From 55bc16cc1916ceac26167b236b76cd55dbce6498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 14 Aug 2023 15:21:33 +0200 Subject: [PATCH 001/644] fix: use update instead of replace in DR (#2006) --- .../dependent/kubernetes/KubernetesDependentResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 45951237be..20e83f02bf 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -153,7 +153,7 @@ public R update(R actual, R target, P primary, Context

context) { .forceConflicts().serverSideApply(); } else { var updatedActual = updaterMatcher.updateResource(actual, target, context); - updatedResource = prepare(updatedActual, primary, "Updating").replace(); + updatedResource = prepare(updatedActual, primary, "Updating").update(); } log.debug("Resource version after update: {}", updatedResource.getMetadata().getResourceVersion()); From 8234e84c78114da1137236c5954c9767cb69e8c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Aug 2023 04:08:04 +0000 Subject: [PATCH 002/644] chore(deps): bump io.micrometer:micrometer-core from 1.11.2 to 1.11.3 Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.11.2 to 1.11.3. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.11.2...v1.11.3) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 14c93ad071..7f8083001d 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 3.24.2 4.2.0 2.7.3 - 1.11.2 + 1.11.3 4.10.0 3.1.3 0.9.0 From 0c362d572edece5a0bb176a1c7aa08b65ec4dc49 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 16 Aug 2023 06:04:10 +0000 Subject: [PATCH 003/644] Set new SNAPSHOT version into pom files. --- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index ce6139934d..e60982e469 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 9fd5fc0e0b..297fbc8933 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 7cf2552ff9..19f8cb1bc9 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index 4e2036d52e..c09b7f55d9 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index accd3eec06..b91222a044 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index ddd4daeb2c..37be3a3117 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 7f8083001d..871db6ce44 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index f68fc47e70..c57b293b38 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 6f1297cc9d..cbb3dba1ac 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 2a48835b5d..280af7689d 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 7d494be81f..c9c0e1b056 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index f4b389bb4b..326b3b89f4 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.2-SNAPSHOT + 4.4.3-SNAPSHOT sample-webpage-operator From 1691cf0b3e5df80749467aaa1a904221b2211ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 17 Aug 2023 11:55:42 +0200 Subject: [PATCH 004/644] docs: remove ConfigurationServiceProvider obsolete usage (#2022) --- docs/documentation/configuration.md | 23 +++++++---------------- docs/documentation/faq.md | 3 +-- docs/documentation/features.md | 2 +- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/docs/documentation/configuration.md b/docs/documentation/configuration.md index 52ce725ad7..44d233de4a 100644 --- a/docs/documentation/configuration.md +++ b/docs/documentation/configuration.md @@ -7,7 +7,7 @@ permalink: /docs/configuration # Configuration options -The Java Operator SDK (JOSDK for short) provides several abstractions that work great out of the +The Java Operator SDK (JOSDK) provides several abstractions that work great out of the box. However, while we strive to cover the most common cases with the default behavior, we also recognize that that default behavior is not always what any given user might want for their operator. Numerous configuration options are therefore provided to help people tailor the @@ -23,29 +23,20 @@ Configuration options act at several levels, depending on which behavior you wis ## Operator-level configuration Configuration that impacts the whole operator is performed via the `ConfigurationService` class. -An instance is provided by the `ConfigurationServiceProvider.instance()` method. This is the -normal way for user-code to retrieve the current `ConfigurationService` instance. Sensible -defaults are provided but you can change the default behavior by overriding the current -configuration using `ConfigurationServiceProvider.overrideCurrent` method, providing a -`ConfigurationServiceOverrider` `Consumer` that will apply the modifications you wish to perform -on the configuration. +`ConfigurationService` is an abstract class, and the implementation can be different based +on which flavor of the framework is used. For example Quarkus Operator SDK replaces the +default implementation. Configurations are initialized with sensible defaults, but can +be changed during initialization. For instance, if you wish to not validate that the CRDs are present on your cluster when the operator starts and configure leader election, you would do something similar to: ```java -ConfigurationServiceProvider.overrideCurrent(o -> o.checkingCRDAndValidateLocalModel(false) +Operator operator = new Operator( override -> override + .checkingCRDAndValidateLocalModel(false) .withLeaderElectionConfiguration(new LeaderElectionConfiguration("bar", "barNS"))); ``` -Note that you can also obtain the same result by passing the `ConfigurationServiceOverrider` -`Consumer` instance to the `Operator` constructor: - -```java -new Operator(o -> o.checkingCRDAndValidateLocalModel(false) - .withLeaderElectionConfiguration(new LeaderElectionConfiguration("bar","barNS"))); -``` - ## Reconciler-level configuration While reconcilers are typically configured using the `@ControllerConfiguration` annotation, it diff --git a/docs/documentation/faq.md b/docs/documentation/faq.md index 9a291df329..bbe09dc633 100644 --- a/docs/documentation/faq.md +++ b/docs/documentation/faq.md @@ -73,10 +73,9 @@ Furthermore, you may not be able to list CRDs at startup which is required when is `true` (`false` by default). To disable, set it to `false` at [Operator-level configuration](./configuration.md#operator-level-configuration): ```java -ConfigurationServiceProvider.overrideCurrent(o -> o.checkingCRDAndValidateLocalModel(false)); +Operator operator = new Operator( override -> override.checkingCRDAndValidateLocalModel(false)); ``` - ### Q: How to fix `sun.security.provider.certpath.SunCertPathBuilderException` on Rancher Desktop and k3d/k3s Kubernetes It's a common issue when using k3d and the fabric8 client tries to connect to the cluster an exception is thrown: diff --git a/docs/documentation/features.md b/docs/documentation/features.md index e94cdcdb81..bce21a61aa 100644 --- a/docs/documentation/features.md +++ b/docs/documentation/features.md @@ -769,7 +769,7 @@ follows: ```java Metrics metrics= …; -ConfigurationServiceProvider.overrideCurrent(overrider->overrider.withMetrics(metrics)); +Operator operator = new Operator(client, o -> o.withMetrics()); ``` ### Micrometer implementation From 995087d9248d64455fc6bb1ebf569751484653d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Aug 2023 08:12:04 +0200 Subject: [PATCH 005/644] chore(deps-dev): bump org.mockito:mockito-core from 5.4.0 to 5.5.0 (#2025) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.4.0 to 5.5.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.4.0...v5.5.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 871db6ce44..f3b5432432 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 6.7.2 1.7.36 2.20.0 - 5.4.0 + 5.5.0 3.13.0 0.19 1.13.0 From 574eeedd32ee1a8b481bb84311cbf8547d9a6d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 23 Aug 2023 12:55:30 +0200 Subject: [PATCH 006/644] improve: add test for startup with no right and no stop config (#2024) --- .../operator/InformerErrorHandlerStartIT.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerErrorHandlerStartIT.java diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerErrorHandlerStartIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerErrorHandlerStartIT.java new file mode 100644 index 0000000000..b1edf3e108 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerErrorHandlerStartIT.java @@ -0,0 +1,47 @@ +package io.javaoperatorsdk.operator; + +import java.time.Duration; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.client.ConfigBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; + +class InformerErrorHandlerStartIT { + /** + * Test showcases that the operator starts even if there is no access right for some resource. + */ + @Test + @Timeout(5) + void operatorStart() { + KubernetesClient client = new KubernetesClientBuilder() + .withConfig(new ConfigBuilder() + .withImpersonateUsername("user-with-no-rights") + .build()) + .build(); + + Operator operator = new Operator(o -> o + .withKubernetesClient(client) + .withStopOnInformerErrorDuringStartup(false) + .withCacheSyncTimeout(Duration.ofSeconds(2))); + operator.register(new ConfigMapReconciler()); + operator.start(); + } + + @ControllerConfiguration + public static class ConfigMapReconciler implements Reconciler { + @Override + public UpdateControl reconcile(ConfigMap resource, Context context) + throws Exception { + return UpdateControl.noUpdate(); + } + } + +} From a97371106b6d7f687c70e64fb2207402ed4087b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 24 Aug 2023 13:24:52 +0200 Subject: [PATCH 007/644] improve: dependent resource can be re-initialized (#2026) --- .../source/informer/InformerEventSource.java | 2 +- .../operator/DependentReInitializationIT.java | 39 +++++++++++++++++++ .../ConfigMapDependentResource.java | 29 ++++++++++++++ ...pendentReInitializationCustomResource.java | 14 +++++++ .../DependentReInitializationReconciler.java | 38 ++++++++++++++++++ 5 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentReInitializationIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/ConfigMapDependentResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/DependentReInitializationCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/DependentReInitializationReconciler.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index 8cca524464..73927851e7 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -365,7 +365,7 @@ public void setConfigurationService(ConfigurationService configurationService) { super.setConfigurationService(configurationService); cache.addIndexers(indexerBuffer); - indexerBuffer = null; + indexerBuffer = new HashMap<>(); } public void addIndexers(Map>> indexers) { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentReInitializationIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentReInitializationIT.java new file mode 100644 index 0000000000..19edc1af61 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentReInitializationIT.java @@ -0,0 +1,39 @@ +package io.javaoperatorsdk.operator; + +import org.junit.jupiter.api.Test; + +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.dependentreinitialization.ConfigMapDependentResource; +import io.javaoperatorsdk.operator.sample.dependentreinitialization.DependentReInitializationCustomResource; +import io.javaoperatorsdk.operator.sample.dependentreinitialization.DependentReInitializationReconciler; + +class DependentReInitializationIT { + + /** + * In case dependent resource is managed by CDI (like in Quarkus) can be handy that the instance + * is reused in tests. + */ + @Test + void dependentCanDeReInitialized() { + var client = new KubernetesClientBuilder().build(); + LocallyRunOperatorExtension.applyCrd(DependentReInitializationCustomResource.class, client); + + var dependent = new ConfigMapDependentResource(); + + startEndStopOperator(client, dependent); + startEndStopOperator(client, dependent); + } + + private static void startEndStopOperator(KubernetesClient client, + ConfigMapDependentResource dependent) { + Operator o1 = new Operator(o -> o + .withCloseClientOnStop(false) + .withKubernetesClient(client)); + o1.register(new DependentReInitializationReconciler(dependent, client)); + o1.start(); + o1.stop(); + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/ConfigMapDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/ConfigMapDependentResource.java new file mode 100644 index 0000000000..a102060c10 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/ConfigMapDependentResource.java @@ -0,0 +1,29 @@ +package io.javaoperatorsdk.operator.sample.dependentreinitialization; + +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; + +public class ConfigMapDependentResource + extends CRUDKubernetesDependentResource { + + public ConfigMapDependentResource() { + super(ConfigMap.class); + } + + @Override + protected ConfigMap desired(DependentReInitializationCustomResource primary, + Context context) { + return new ConfigMapBuilder() + .withMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()) + .withData(Map.of("key", "val")) + .build(); + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/DependentReInitializationCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/DependentReInitializationCustomResource.java new file mode 100644 index 0000000000..ce30463965 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/DependentReInitializationCustomResource.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.sample.dependentreinitialization; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +public class DependentReInitializationCustomResource + extends CustomResource + implements Namespaced { + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/DependentReInitializationReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/DependentReInitializationReconciler.java new file mode 100644 index 0000000000..e247ddb6df --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/DependentReInitializationReconciler.java @@ -0,0 +1,38 @@ +package io.javaoperatorsdk.operator.sample.dependentreinitialization; + +import java.util.Map; + +import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; + +@ControllerConfiguration +public class DependentReInitializationReconciler + implements Reconciler, + EventSourceInitializer { + + private final ConfigMapDependentResource configMapDependentResource; + + public DependentReInitializationReconciler(ConfigMapDependentResource dependentResource, + KubernetesClient client) { + this.configMapDependentResource = dependentResource; + this.configMapDependentResource.setKubernetesClient(client); + } + + @Override + public UpdateControl reconcile( + DependentReInitializationCustomResource resource, + Context context) throws Exception { + configMapDependentResource.reconcile(resource, context); + return UpdateControl.noUpdate(); + } + + @Override + public Map prepareEventSources( + EventSourceContext context) { + return EventSourceInitializer.nameEventSourcesFromDependentResource(context, + configMapDependentResource); + } + + +} From fe1a693cfdaf0534f513d126337c93ad93d32b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 24 Aug 2023 15:14:02 +0200 Subject: [PATCH 008/644] docs: remove dependent resources disclaimer (#2031) --- docs/documentation/dependent-resources.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/documentation/dependent-resources.md b/docs/documentation/dependent-resources.md index 92a5014e90..b23e19f006 100644 --- a/docs/documentation/dependent-resources.md +++ b/docs/documentation/dependent-resources.md @@ -7,11 +7,6 @@ permalink: /docs/dependent-resources # Dependent Resources -DISCLAIMER: The Dependent Resource support is a relatively new feature, while we strove to cover -what we anticipate will be the most common use cases, the implementation is not simple and might -still evolve. As a result, some APIs could be a subject of change in the future. However, -non-backwards compatible changes are expected to be trivial to migrate to. - ## Motivations and Goals Most operators need to deal with secondary resources when trying to realize the desired state From 28aa1647a386861a6a60fb6dc49eeba0c7deaaac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 28 Aug 2023 17:00:43 +0200 Subject: [PATCH 009/644] improve: logging if no primary found for resource id (#2036) --- .../operator/processing/event/EventProcessor.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java index cef5e0ac45..833e10816d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java @@ -146,7 +146,12 @@ private void submitReconciliationExecution(ResourceState state) { controllerUnderExecution, maybeLatest.isPresent()); if (maybeLatest.isEmpty()) { - log.debug("no custom resource found in cache for resource id: {}", resourceID); + // there can be multiple reasons why the primary resource is not present, one is that the + // informer is currently disconnected from k8s api server, but will eventually receive the + // resource. Other is that simply there is no primary resource present for an event, this + // might indicate issue with the implementation, but could happen also naturally, thus + // this is not necessarily a problem. + log.debug("no primary resource found in cache with resource id: {}", resourceID); } } } finally { From c97cf0272fb2cbb68e1bf66cc830a27a67e60165 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Sat, 26 Aug 2023 15:29:28 +0200 Subject: [PATCH 010/644] refactor: reduce redundancy by removing duplicate configuration recording --- .../ControllerResourceEventSource.java | 16 ++--------- .../source/informer/InformerEventSource.java | 28 +++++++++---------- .../source/informer/InformerManager.java | 21 ++++++-------- .../informer/ManagedInformerEventSource.java | 15 +++++----- .../event/EventSourceManagerTest.java | 14 ++-------- 5 files changed, 35 insertions(+), 59 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java index 648febad30..da2e517376 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java @@ -1,10 +1,7 @@ package io.javaoperatorsdk.operator.processing.event.source.controller; -import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,12 +18,8 @@ import io.javaoperatorsdk.operator.processing.event.source.informer.ManagedInformerEventSource; import static io.javaoperatorsdk.operator.ReconcilerUtils.handleKubernetesClientException; -import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getName; -import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getUID; -import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getVersion; -import static io.javaoperatorsdk.operator.processing.event.source.controller.InternalEventFilters.onUpdateFinalizerNeededAndApplied; -import static io.javaoperatorsdk.operator.processing.event.source.controller.InternalEventFilters.onUpdateGenerationAware; -import static io.javaoperatorsdk.operator.processing.event.source.controller.InternalEventFilters.onUpdateMarkedForDeletion; +import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.*; +import static io.javaoperatorsdk.operator.processing.event.source.controller.InternalEventFilters.*; public class ControllerResourceEventSource extends ManagedInformerEventSource> @@ -137,9 +130,4 @@ public void setOnDeleteFilter(OnDeleteFilter onDeleteFilter) { throw new IllegalStateException( "onDeleteFilter is not supported for controller resource event source"); } - - @Override - public void addIndexers(Map>> indexers) { - manager().addIndexers(indexers); - } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index 73927851e7..a9a07f2332 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -1,10 +1,6 @@ package io.javaoperatorsdk.operator.processing.event.source.informer; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -76,7 +72,6 @@ public class InformerEventSource private static final Logger log = LoggerFactory.getLogger(InformerEventSource.class); - private final InformerConfiguration configuration; // always called from a synchronized method private final EventRecorder eventRecorder = new EventRecorder<>(); // we need direct control for the indexer to propagate the just update resource also to the index @@ -91,8 +86,6 @@ public InformerEventSource( public InformerEventSource(InformerConfiguration configuration, KubernetesClient client) { super(client.resources(configuration.getResourceClass()), configuration); - this.configuration = configuration; - // If there is a primary to secondary mapper there is no need for primary to secondary index. primaryToSecondaryMapper = configuration.getPrimaryToSecondaryMapper(); @@ -193,7 +186,7 @@ private boolean temporaryCacheHasResourceWithSameVersionAs(R resource) { private void propagateEvent(R object) { var primaryResourceIdSet = - configuration.getSecondaryToPrimaryMapper().toPrimaryResourceIDs(object); + configuration().getSecondaryToPrimaryMapper().toPrimaryResourceIDs(object); if (primaryResourceIdSet.isEmpty()) { return; } @@ -217,8 +210,7 @@ public Set getSecondaryResources(P primary) { Set secondaryIDs; if (useSecondaryToPrimaryIndex()) { var primaryResourceID = ResourceID.fromResource(primary); - secondaryIDs = - primaryToSecondaryIndex.getSecondaryResources(primaryResourceID); + secondaryIDs = primaryToSecondaryIndex.getSecondaryResources(primaryResourceID); log.debug( "Using PrimaryToSecondaryIndex to find secondary resources for primary: {}. Found secondary ids: {} ", primaryResourceID, secondaryIDs); @@ -232,8 +224,16 @@ public Set getSecondaryResources(P primary) { .collect(Collectors.toSet()); } + /** + * Returns the configuration object for the informer. + * + * @return the informer configuration object + * + * @deprecated Use {@link #configuration()} instead + */ + @Deprecated(forRemoval = true) public InformerConfiguration getConfiguration() { - return configuration; + return configuration(); } @Override @@ -334,7 +334,7 @@ public synchronized void cleanupOnCreateOrUpdateEventFiltering(ResourceID resour @Override public boolean allowsNamespaceChanges() { - return getConfiguration().followControllerNamespaceChanges(); + return configuration().followControllerNamespaceChanges(); } @@ -364,7 +364,7 @@ private boolean acceptedByDeleteFilters(R resource, boolean b) { public void setConfigurationService(ConfigurationService configurationService) { super.setConfigurationService(configurationService); - cache.addIndexers(indexerBuffer); + super.addIndexers(indexerBuffer); indexerBuffer = new HashMap<>(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java index 88f1e51942..e68cd3ab25 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java @@ -1,11 +1,6 @@ package io.javaoperatorsdk.operator.processing.event.source.informer; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; @@ -23,7 +18,6 @@ import io.fabric8.kubernetes.client.informers.ResourceEventHandler; import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.ReconcilerUtils; -import io.javaoperatorsdk.operator.api.config.Cloner; import io.javaoperatorsdk.operator.api.config.ConfigurationService; import io.javaoperatorsdk.operator.api.config.ResourceConfiguration; import io.javaoperatorsdk.operator.health.InformerHealthIndicator; @@ -40,19 +34,21 @@ public class InformerManager> sources = new ConcurrentHashMap<>(); - private Cloner cloner; private final C configuration; private final MixedOperation, Resource> client; private final ResourceEventHandler eventHandler; private final Map>> indexers = new HashMap<>(); - private final ConfigurationService configurationService; + private ConfigurationService configurationService; - public InformerManager(MixedOperation, Resource> client, - C configuration, ConfigurationService configurationService, + InformerManager(MixedOperation, Resource> client, + C configuration, ResourceEventHandler eventHandler) { this.client = client; this.configuration = configuration; this.eventHandler = eventHandler; + } + + void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } @@ -74,7 +70,6 @@ private void initSources() { if (!sources.isEmpty()) { throw new IllegalStateException("Some sources already initialized."); } - cloner = configurationService.getResourceCloner(); final var targetNamespaces = configuration.getEffectiveNamespaces(configurationService); if (ResourceConfiguration.allNamespacesWatched(targetNamespaces)) { var source = createEventSourceForNamespace(WATCH_ALL_NAMESPACES); @@ -175,7 +170,7 @@ public Stream list(String namespace, Predicate predicate) { public Optional get(ResourceID resourceID) { return getSource(resourceID.getNamespace().orElse(WATCH_ALL_NAMESPACES)) .flatMap(source -> source.get(resourceID)) - .map(cloner::clone); + .map(r -> configurationService.getResourceCloner().clone(r)); } @Override diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java index 92a317096c..02df5c2ee5 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java @@ -36,10 +36,9 @@ public abstract class ManagedInformerEventSource, Configurable { private static final Logger log = LoggerFactory.getLogger(ManagedInformerEventSource.class); + private final InformerManager cache; protected TemporaryResourceCache temporaryResourceCache; - protected InformerManager cache; - protected C configuration; protected MixedOperation, Resource> client; protected ManagedInformerEventSource( @@ -47,7 +46,7 @@ protected ManagedInformerEventSource( super(configuration.getResourceClass()); this.client = client; temporaryResourceCache = new TemporaryResourceCache<>(this); - this.configuration = configuration; + this.cache = new InformerManager<>(client, configuration, this); } @Override @@ -128,7 +127,9 @@ void setTemporalResourceCache(TemporaryResourceCache temporaryResourceCache) this.temporaryResourceCache = temporaryResourceCache; } - public abstract void addIndexers(Map>> indexers); + public void addIndexers(Map>> indexers) { + cache.addIndexers(indexers); + } public List byIndex(String indexName, String indexKey) { return manager().byIndex(indexName, indexKey); @@ -156,7 +157,7 @@ public Status getStatus() { @Override public ResourceConfiguration getInformerConfiguration() { - return configuration; + return configuration(); } @Override @@ -167,11 +168,11 @@ public C configuration() { @Override public String toString() { return getClass().getSimpleName() + "{" + - "resourceClass: " + configuration.getResourceClass().getSimpleName() + + "resourceClass: " + configuration().getResourceClass().getSimpleName() + "}"; } public void setConfigurationService(ConfigurationService configurationService) { - cache = new InformerManager<>(client, configuration, configurationService, this); + cache.setConfigurationService(configurationService); } } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventSourceManagerTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventSourceManagerTest.java index 65d2ec7413..b56d79e6ed 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventSourceManagerTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventSourceManagerTest.java @@ -23,16 +23,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; @SuppressWarnings({"rawtypes", "unchecked"}) class EventSourceManagerTest { @@ -166,7 +158,7 @@ void changesNamespacesOnControllerAndInformerEventSources() { when(informerConfigurationMock.followControllerNamespaceChanges()).thenReturn(true); InformerEventSource informerEventSource = mock(InformerEventSource.class); when(informerEventSource.resourceType()).thenReturn(TestCustomResource.class); - when(informerEventSource.getConfiguration()).thenReturn(informerConfigurationMock); + when(informerEventSource.configuration()).thenReturn(informerConfigurationMock); when(informerEventSource.allowsNamespaceChanges()).thenCallRealMethod(); manager.registerEventSource("ies", informerEventSource); From 4983b30f1edf1e6ca4b54e174386ea82f01cbfbf Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Mon, 4 Sep 2023 10:31:06 +0200 Subject: [PATCH 011/644] chore: upgrade k8s versions for CI (#1657) Signed-off-by: Chris Laprun --- .github/workflows/e2e-test.yml | 4 ++-- .github/workflows/integration-tests.yml | 2 +- .github/workflows/pr.yml | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index b5d85c914b..57fb0b6f46 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -32,8 +32,8 @@ jobs: - name: Setup Minikube-Kubernetes uses: manusa/actions-setup-minikube@v2.7.2 with: - minikube version: v1.28.0 - kubernetes version: v1.25.5 + minikube version: v1.31.2 + kubernetes version: v1.28.1 github token: ${{ secrets.GITHUB_TOKEN }} driver: docker diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index ef1ecf1633..5bbe4c643d 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -36,7 +36,7 @@ jobs: - name: Set up Minikube uses: manusa/actions-setup-minikube@v2.7.2 with: - minikube version: 'v1.28.0' + minikube version: v1.31.2 kubernetes version: ${{ inputs.kube-version }} driver: 'docker' github token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index f2f714c804..21d467e4f6 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -35,12 +35,12 @@ jobs: strategy: matrix: java: [ 11, 17 ] - kubernetes: [ 'v1.23.15', 'v1.24.9', 'v1.25.5' ] + kubernetes: [ 'v1.25.13', 'v1.26.8', 'v1.27.5', 'v1.28.1' ] uses: ./.github/workflows/integration-tests.yml with: java-version: ${{ matrix.java }} kube-version: ${{ matrix.kubernetes }} - + httpclient-tests: strategy: matrix: @@ -48,7 +48,7 @@ jobs: uses: ./.github/workflows/integration-tests.yml with: java-version: 17 - kube-version: 'v1.25.5' + kube-version: 'v1.28.1' http-client: ${{ matrix.httpclient }} experimental: true From 2aa8dfe7399f918b58d24606822758e164c8c54e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:22:49 +0200 Subject: [PATCH 012/644] chore(deps): bump actions/checkout from 3 to 4 (#2044) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/e2e-test.yml | 2 +- .github/workflows/integration-tests.yml | 2 +- .github/workflows/pr.yml | 4 ++-- .github/workflows/release-project-in-dir.yml | 4 ++-- .github/workflows/snapshot-releases.yml | 4 ++-- .github/workflows/sonar.yml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 57fb0b6f46..1195f7c05e 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Minikube-Kubernetes uses: manusa/actions-setup-minikube@v2.7.2 diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 5bbe4c643d..db542e341c 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Output test information run: echo "Running ITs with ${{ inputs.http-client }}, ${{ inputs.kube-version }}, ${{ inputs.java-version }}" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Java and Maven uses: actions/setup-java@v3 with: diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 21d467e4f6..e9b20ab449 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -17,7 +17,7 @@ jobs: check_format_and_unit_tests: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Java and Maven uses: actions/setup-java@v3 with: @@ -58,7 +58,7 @@ jobs: matrix: java: [ 11, 17 ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Java and Maven uses: actions/setup-java@v3 with: diff --git a/.github/workflows/release-project-in-dir.yml b/.github/workflows/release-project-in-dir.yml index 931398948d..fa8bcc453d 100644 --- a/.github/workflows/release-project-in-dir.yml +++ b/.github/workflows/release-project-in-dir.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout "${{inputs.version_branch}}" branch - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: "${{inputs.version_branch}}" @@ -54,7 +54,7 @@ jobs: if: "!contains(github.event.release.tag_name, 'RC')" # not sure we should keep this the RC part steps: - name: Checkout "${{inputs.version_branch}}" branch - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: "${{inputs.version_branch}}" diff --git a/.github/workflows/snapshot-releases.yml b/.github/workflows/snapshot-releases.yml index b549d2dca4..71cf119b25 100644 --- a/.github/workflows/snapshot-releases.yml +++ b/.github/workflows/snapshot-releases.yml @@ -16,7 +16,7 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Java and Maven uses: actions/setup-java@v3 with: @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest needs: test steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Java and Maven uses: actions/setup-java@v3 with: diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index e89f3c3de9..27f98a337c 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest if: ${{ ( github.event_name == 'push' ) || ( github.event_name == 'pull_request' && github.event.pull_request.head.repo.owner.login == 'java-operator-sdk' ) }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Java and Maven uses: actions/setup-java@v3 with: From ddd7c42711c6d7f42cc951fdc7a70f916a41326b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Fri, 8 Sep 2023 15:47:01 +0200 Subject: [PATCH 013/644] fix: processor issue with cleanup resources (#2049) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: processor issue with cleanup resources if leader election not running delete event was not cleaning up state Signed-off-by: Attila Mészáros * revert small change Signed-off-by: Attila Mészáros --------- Signed-off-by: Attila Mészáros --- .../operator/processing/event/EventProcessor.java | 3 +++ .../processing/event/EventProcessorTest.java | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java index 833e10816d..14c7cf6d1e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java @@ -97,6 +97,9 @@ public synchronized void handleEvent(Event event) { metrics.receivedEvent(event, metricsMetadata); handleEventMarking(event, state); if (!this.running) { + if (state.deleteEventPresent()) { + cleanupForDeletedEvent(state.getId()); + } // events are received and marked, but will be processed when started, see start() method. log.debug("Skipping event: {} because the event processor is not started", event); return; diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventProcessorTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventProcessorTest.java index 880b4a8e14..9d538713c1 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventProcessorTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventProcessorTest.java @@ -452,6 +452,21 @@ void executionOfReconciliationShouldNotStartIfProcessorStopped() throws Interrup .handleExecution(any()); } + @Test + void cleansUpForDeleteEventEvenIfProcessorNotStarted() { + ResourceID resourceID = new ResourceID("test1", "default"); + + eventProcessor = + spy(new EventProcessor(controllerConfiguration(null, rateLimiterMock), + reconciliationDispatcherMock, + eventSourceManagerMock, null)); + + eventProcessor.handleEvent(prepareCREvent(resourceID)); + eventProcessor.handleEvent(new ResourceEvent(ResourceAction.DELETED, resourceID, null)); + eventProcessor.handleEvent(prepareCREvent(resourceID)); + // no exception thrown + } + private ResourceID eventAlreadyUnderProcessing() { when(reconciliationDispatcherMock.handleExecution(any())) .then( From 85e65ed065b7789045470042b9543693be01a2cd Mon Sep 17 00:00:00 2001 From: Donnerbart Date: Mon, 11 Sep 2023 08:48:50 +0200 Subject: [PATCH 014/644] improve: re-use ignoreList in GenericKubernetesResourceMatcher (#2050) Signed-off-by: David Sondermann --- .../GenericKubernetesResourceMatcher.java | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java index 36935e08a0..3109880063 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java @@ -192,22 +192,17 @@ public static Result match(R d } } - final var matched = matchSpec(actualResource, desired, specEquality, context, ignoredPaths); + final var matched = matchSpec(actualResource, desired, specEquality, context, ignoreList); return Result.computed(matched, desired); } private static boolean matchSpec(R actual, R desired, boolean equality, - Context context, - String[] ignoredPaths) { - + Context context, List ignoreList) { final var kubernetesSerialization = context.getClient().getKubernetesSerialization(); var desiredNode = kubernetesSerialization.convertValue(desired, JsonNode.class); var actualNode = kubernetesSerialization.convertValue(actual, JsonNode.class); var wholeDiffJsonPatch = JsonDiff.asJson(desiredNode, actualNode); - final List ignoreList = - ignoredPaths != null && ignoredPaths.length > 0 ? Arrays.asList(ignoredPaths) - : Collections.emptyList(); // reflection will be replaced by this: // https://github.com/fabric8io/kubernetes-client/issues/3816 var specDiffJsonPatch = getDiffsImpactingPathsWithPrefixes(wholeDiffJsonPatch, SPEC); @@ -218,15 +213,10 @@ private static boolean matchSpec(R actual, R desired, bo return false; } if (!equality && !ignoreList.isEmpty()) { - if (!allDiffsOnIgnoreList(specDiffJsonPatch, ignoreList)) { - return false; - } + return allDiffsOnIgnoreList(specDiffJsonPatch, ignoreList); } else { - if (!allDiffsAreAddOps(specDiffJsonPatch)) { - return false; - } + return allDiffsAreAddOps(specDiffJsonPatch); } - return true; } private static boolean allDiffsOnIgnoreList(List metadataJSonDiffs, @@ -241,7 +231,6 @@ private static Optional R desired, R actualResource, boolean labelsAndAnnotationsEquality, Context

context) { - if (labelsAndAnnotationsEquality) { final var desiredMetadata = desired.getMetadata(); final var actualMetadata = actualResource.getMetadata(); From a3fb3ad9ef84ad60e456ac2b3714b070b37e055b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 11 Sep 2023 09:15:40 +0000 Subject: [PATCH 015/644] Set new SNAPSHOT version into pom files. --- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index e60982e469..f5d75f2321 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.3-SNAPSHOT + 4.4.4-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 297fbc8933..9372c9700d 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.3-SNAPSHOT + 4.4.4-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 19f8cb1bc9..867679800f 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.4.3-SNAPSHOT + 4.4.4-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index c09b7f55d9..d62d84ceaa 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.4.3-SNAPSHOT + 4.4.4-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index b91222a044..8e48eac880 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.3-SNAPSHOT + 4.4.4-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index 37be3a3117..9b89e9a52d 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.3-SNAPSHOT + 4.4.4-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index f3b5432432..ea4d157085 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.4.3-SNAPSHOT + 4.4.4-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index c57b293b38..0cf0452a2a 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.3-SNAPSHOT + 4.4.4-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index cbb3dba1ac..71eddaf328 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.3-SNAPSHOT + 4.4.4-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 280af7689d..61807ada45 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.4.3-SNAPSHOT + 4.4.4-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index c9c0e1b056..8eae54d73e 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.3-SNAPSHOT + 4.4.4-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 326b3b89f4..59109cc13e 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.3-SNAPSHOT + 4.4.4-SNAPSHOT sample-webpage-operator From b3c88fcea7fd55616ef5b91c49155c27a34d5916 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:59:44 +0200 Subject: [PATCH 016/644] chore(deps): bump io.micrometer:micrometer-core from 1.11.3 to 1.11.4 (#2052) Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.11.3 to 1.11.4. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.11.3...v1.11.4) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ea4d157085..4f8ce2b5ea 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 3.24.2 4.2.0 2.7.3 - 1.11.3 + 1.11.4 4.10.0 3.1.3 0.9.0 From 8af00f2a804618367aad107db3c6d9c600aeaab2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Sep 2023 07:01:45 +0200 Subject: [PATCH 017/644] chore(deps): bump manusa/actions-setup-minikube from 2.7.2 to 2.9.0 (#2055) --- .github/workflows/e2e-test.yml | 2 +- .github/workflows/integration-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 1195f7c05e..79d31d2f50 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -30,7 +30,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Minikube-Kubernetes - uses: manusa/actions-setup-minikube@v2.7.2 + uses: manusa/actions-setup-minikube@v2.9.0 with: minikube version: v1.31.2 kubernetes version: v1.28.1 diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index db542e341c..a66ade82a9 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -34,7 +34,7 @@ jobs: java-version: ${{ inputs.java-version }} cache: 'maven' - name: Set up Minikube - uses: manusa/actions-setup-minikube@v2.7.2 + uses: manusa/actions-setup-minikube@v2.9.0 with: minikube version: v1.31.2 kubernetes version: ${{ inputs.kube-version }} From d58f9e1af396f14e230ad2f14de00c1330c65a77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 08:23:11 +0200 Subject: [PATCH 018/644] chore(deps): bump org.apache.maven.plugins:maven-javadoc-plugin (#2058) Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.5.0 to 3.6.0. - [Release notes](https://github.com/apache/maven-javadoc-plugin/releases) - [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.5.0...maven-javadoc-plugin-3.6.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-javadoc-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- operator-framework-bom/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 867679800f..f65cc8f119 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -63,7 +63,7 @@ 1.6.13 3.1.0 3.3.0 - 3.5.0 + 3.6.0 diff --git a/pom.xml b/pom.xml index 4f8ce2b5ea..32a8134f6d 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 2.11 3.11.0 3.1.2 - 3.5.0 + 3.6.0 3.3.1 3.3.0 3.3.0 From 3e692e3b533030b069c955b09833ee85890e9167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 19 Sep 2023 10:30:13 +0200 Subject: [PATCH 019/644] fix: informer config builder (#2062) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../KubernetesDependentResourceConfig.java | 27 ++++--- ...ernetesDependentResourceConfigBuilder.java | 72 +++++++++++++++++++ .../ControllerConfigurationOverriderTest.java | 6 +- .../WebPageDependentsWorkflowReconciler.java | 6 +- ...WebPageStandaloneDependentsReconciler.java | 10 ++- 5 files changed, 100 insertions(+), 21 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java index 4047b25a13..509dae6d0f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java @@ -13,20 +13,21 @@ public class KubernetesDependentResourceConfig { - private Set namespaces = Constants.SAME_AS_CONTROLLER_NAMESPACES_SET; - private String labelSelector = NO_VALUE_SET; - private boolean namespacesWereConfigured = false; + private Set namespaces; + private String labelSelector; + private boolean namespacesWereConfigured; private ResourceDiscriminator resourceDiscriminator; - private OnAddFilter onAddFilter; + private final OnAddFilter onAddFilter; + private final OnUpdateFilter onUpdateFilter; + private final OnDeleteFilter onDeleteFilter; + private final GenericFilter genericFilter; - private OnUpdateFilter onUpdateFilter; - - private OnDeleteFilter onDeleteFilter; - - private GenericFilter genericFilter; - - public KubernetesDependentResourceConfig() {} + public KubernetesDependentResourceConfig() { + this(Constants.SAME_AS_CONTROLLER_NAMESPACES_SET, NO_VALUE_SET, true, + null, null, + null, null, null); + } public KubernetesDependentResourceConfig(Set namespaces, String labelSelector, boolean configuredNS, ResourceDiscriminator resourceDiscriminator, @@ -43,11 +44,15 @@ public KubernetesDependentResourceConfig(Set namespaces, String labelSel this.resourceDiscriminator = resourceDiscriminator; } + // use builder instead + @Deprecated(forRemoval = true) public KubernetesDependentResourceConfig(Set namespaces, String labelSelector) { this(namespaces, labelSelector, true, null, null, null, null, null); } + // use builder instead + @Deprecated(forRemoval = true) public KubernetesDependentResourceConfig setLabelSelector(String labelSelector) { this.labelSelector = labelSelector; return this; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java new file mode 100644 index 0000000000..a408d78915 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java @@ -0,0 +1,72 @@ +package io.javaoperatorsdk.operator.processing.dependent.kubernetes; + +import java.util.Set; + +import io.javaoperatorsdk.operator.api.reconciler.Constants; +import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator; +import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter; +import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter; +import io.javaoperatorsdk.operator.processing.event.source.filter.OnDeleteFilter; +import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter; + +public final class KubernetesDependentResourceConfigBuilder { + + private Set namespaces = Constants.SAME_AS_CONTROLLER_NAMESPACES_SET; + private String labelSelector; + private ResourceDiscriminator resourceDiscriminator; + private OnAddFilter onAddFilter; + private OnUpdateFilter onUpdateFilter; + private OnDeleteFilter onDeleteFilter; + private GenericFilter genericFilter; + + public KubernetesDependentResourceConfigBuilder() {} + + public static KubernetesDependentResourceConfigBuilder aKubernetesDependentResourceConfig() { + return new KubernetesDependentResourceConfigBuilder<>(); + } + + public KubernetesDependentResourceConfigBuilder withNamespaces(Set namespaces) { + this.namespaces = namespaces; + return this; + } + + public KubernetesDependentResourceConfigBuilder withLabelSelector(String labelSelector) { + this.labelSelector = labelSelector; + return this; + } + + public KubernetesDependentResourceConfigBuilder withResourceDiscriminator( + ResourceDiscriminator resourceDiscriminator) { + this.resourceDiscriminator = resourceDiscriminator; + return this; + } + + public KubernetesDependentResourceConfigBuilder withOnAddFilter(OnAddFilter onAddFilter) { + this.onAddFilter = onAddFilter; + return this; + } + + public KubernetesDependentResourceConfigBuilder withOnUpdateFilter( + OnUpdateFilter onUpdateFilter) { + this.onUpdateFilter = onUpdateFilter; + return this; + } + + public KubernetesDependentResourceConfigBuilder withOnDeleteFilter( + OnDeleteFilter onDeleteFilter) { + this.onDeleteFilter = onDeleteFilter; + return this; + } + + public KubernetesDependentResourceConfigBuilder withGenericFilter( + GenericFilter genericFilter) { + this.genericFilter = genericFilter; + return this; + } + + public KubernetesDependentResourceConfig build() { + return new KubernetesDependentResourceConfig<>(namespaces, labelSelector, false, + resourceDiscriminator, onAddFilter, + onUpdateFilter, onDeleteFilter, genericFilter); + } +} diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java index 71be6a2cd4..eae4c22ac6 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java @@ -20,6 +20,7 @@ import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfig; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfigBuilder; import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -327,7 +328,10 @@ void replaceNamedDependentResourceConfigShouldWork() { final var overridden = ControllerConfigurationOverrider.override(configuration) .replacingNamedDependentResourceConfig( DependentResource.defaultNameFor(ReadOnlyDependent.class), - new KubernetesDependentResourceConfig(Set.of(overriddenNS), labelSelector)) + new KubernetesDependentResourceConfigBuilder<>() + .withNamespaces(Set.of(overriddenNS)) + .withLabelSelector(labelSelector) + .build()) .build(); dependents = overridden.getDependentResources(); dependentSpec = dependents.stream().filter(dr -> dr.getName().equals(dependentResourceName)) diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java index 1aaf6d19db..d21e89a172 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java @@ -17,7 +17,7 @@ import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; -import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfig; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfigBuilder; import io.javaoperatorsdk.operator.processing.dependent.workflow.Workflow; import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowBuilder; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @@ -91,8 +91,8 @@ private void initDependentResources(KubernetesClient client) { Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR).forEach(dr -> { dr.setKubernetesClient(client); - dr.configureWith(new KubernetesDependentResourceConfig() - .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR)); + dr.configureWith(new KubernetesDependentResourceConfigBuilder() + .withLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR).build()); }); } diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java index 3230259c1d..c1b3030c9b 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java @@ -13,7 +13,7 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; -import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfig; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfigBuilder; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.sample.customresource.WebPage; import io.javaoperatorsdk.operator.sample.dependentresource.ConfigMapDependentResource; @@ -79,21 +79,19 @@ public ErrorStatusUpdateControl updateErrorStatus( return handleError(resource, e); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "rawtypes"}) private void createDependentResources(KubernetesClient client) { this.configMapDR = new ConfigMapDependentResource(); this.deploymentDR = new DeploymentDependentResource(); this.serviceDR = new ServiceDependentResource(); this.ingressDR = new IngressDependentResource(); - Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR).forEach(dr -> { dr.setKubernetesClient(client); - dr.configureWith(new KubernetesDependentResourceConfig() - .setLabelSelector(SELECTOR + "=true")); + dr.configureWith(new KubernetesDependentResourceConfigBuilder() + .withLabelSelector(SELECTOR + "=true").build()); }); } - } From 609a55a229748fc08d1538907639d962107abc47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 19 Sep 2023 12:07:56 +0200 Subject: [PATCH 020/644] fix: leader election stop not called (#2059) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../io/javaoperatorsdk/operator/LeaderElectionManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java index 1509d87f2a..e36d35530a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java @@ -67,7 +67,9 @@ private void init(LeaderElectionConfiguration config) { config.getRenewDeadline(), config.getRetryPeriod(), leaderCallbacks(), - true, + // this is required to be false to receive stop event in all cases, thus stopLeading + // is called always when leadership is lost/cancelled + false, config.getLeaseName())) .build(); } From 6238ef21d6761fb99731fd4903c077ad10258b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 19 Sep 2023 17:48:50 +0200 Subject: [PATCH 021/644] fix: remove comment that not holds anymore (#2066) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../java/io/javaoperatorsdk/operator/LeaderElectionManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java index e36d35530a..f40f8c2ba1 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java @@ -56,7 +56,6 @@ private void init(LeaderElectionConfiguration config) { throw new IllegalArgumentException(message); } final var lock = new LeaseLock(leaseNamespace, config.getLeaseName(), identity); - // releaseOnCancel is not used in the underlying implementation leaderElector = new LeaderElectorBuilder( configurationService.getKubernetesClient(), configurationService.getExecutorServiceManager().cachingExecutorService()) From 481cb90a5ced6dd2096c3881aed1e59e59c0cd32 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Thu, 21 Sep 2023 10:21:59 +0200 Subject: [PATCH 022/644] chore: update Kubernetes versions to latest (#2067) Signed-off-by: Chris Laprun --- .github/workflows/e2e-test.yml | 2 +- .github/workflows/pr.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 79d31d2f50..189d25a072 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -33,7 +33,7 @@ jobs: uses: manusa/actions-setup-minikube@v2.9.0 with: minikube version: v1.31.2 - kubernetes version: v1.28.1 + kubernetes version: v1.28.2 github token: ${{ secrets.GITHUB_TOKEN }} driver: docker diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index e9b20ab449..44281a2b4b 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -35,7 +35,7 @@ jobs: strategy: matrix: java: [ 11, 17 ] - kubernetes: [ 'v1.25.13', 'v1.26.8', 'v1.27.5', 'v1.28.1' ] + kubernetes: [ 'v1.25.14', 'v1.26.9', 'v1.27.6', 'v1.28.2' ] uses: ./.github/workflows/integration-tests.yml with: java-version: ${{ matrix.java }} @@ -48,7 +48,7 @@ jobs: uses: ./.github/workflows/integration-tests.yml with: java-version: 17 - kube-version: 'v1.28.1' + kube-version: 'v1.28.2' http-client: ${{ matrix.httpclient }} experimental: true From 6a93ce43b3ec470d593f613223aa9a59d03b320b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 21 Sep 2023 10:24:58 +0200 Subject: [PATCH 023/644] fix: snapshot version update (#2068) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index f5d75f2321..b415011178 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.4-SNAPSHOT + 4.4.5-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 9372c9700d..5ca14df2e3 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.4-SNAPSHOT + 4.4.5-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index f65cc8f119..7f2e71f95f 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.4.4-SNAPSHOT + 4.4.5-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index d62d84ceaa..c8e4c4488f 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.4.4-SNAPSHOT + 4.4.5-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 8e48eac880..106c4f899a 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.4-SNAPSHOT + 4.4.5-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index 9b89e9a52d..1aa7332003 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.4-SNAPSHOT + 4.4.5-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 32a8134f6d..9ef762e1cc 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.4.4-SNAPSHOT + 4.4.5-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 0cf0452a2a..bf79116d40 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.4-SNAPSHOT + 4.4.5-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 71eddaf328..4123a5533e 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.4-SNAPSHOT + 4.4.5-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 61807ada45..32eeab41b9 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.4.4-SNAPSHOT + 4.4.5-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 8eae54d73e..d6e7fb5bc7 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.4-SNAPSHOT + 4.4.5-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 59109cc13e..e2341cc549 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.4-SNAPSHOT + 4.4.5-SNAPSHOT sample-webpage-operator From a6a57afd0079f4b64fed42292ef1298e3d7d5187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 21 Sep 2023 10:25:15 +0200 Subject: [PATCH 024/644] docs: webpage sample docs improvement (#2069) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- sample-operators/webpage/README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sample-operators/webpage/README.md b/sample-operators/webpage/README.md index afbabf4abe..7718d0f2f3 100644 --- a/sample-operators/webpage/README.md +++ b/sample-operators/webpage/README.md @@ -1,7 +1,7 @@ -# WebServer Operator +# WebPage Operator This is a simple example of how a Custom Resource backed by an Operator can serve as -an abstraction layer. This Operator will use a webserver resource, which mainly contains a +an abstraction layer. This Operator will use a WebPage resource, which mainly contains a static webpage definition and creates an NGINX Deployment backed by a ConfigMap which holds the HTML. @@ -23,6 +23,16 @@ spec: ``` + +### Different Flavors + +Sample contains three implementation, that are showcasing the different approaches possible with the framework, +the resulting behavior is almost identical behavior at the end: + +- [Low level API](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java) +- [Using managed dependent resources](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageManagedDependentsReconciler.java) +- [Using standalone Dependent Resources](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java) + ### Try The quickest way to try the operator is to run it on your local machine, while it connects to a local or remote From 7b30fb2d386a67efb6cbd27ead3e41bed06621ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Oct 2023 10:50:50 +0200 Subject: [PATCH 025/644] chore(deps): bump com.google.cloud.tools:jib-maven-plugin (#2072) Bumps [com.google.cloud.tools:jib-maven-plugin](https://github.com/GoogleContainerTools/jib) from 3.3.2 to 3.4.0. - [Release notes](https://github.com/GoogleContainerTools/jib/releases) - [Commits](https://github.com/GoogleContainerTools/jib/commits) --- updated-dependencies: - dependency-name: com.google.cloud.tools:jib-maven-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index bf79116d40..110c058b33 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -18,7 +18,7 @@ 11 11 - 3.3.2 + 3.4.0 diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 4123a5533e..2f648f00b1 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -18,7 +18,7 @@ 11 11 - 3.3.2 + 3.4.0 diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index d6e7fb5bc7..12f89dce66 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -18,7 +18,7 @@ 11 11 - 3.3.2 + 3.4.0 diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index e2341cc549..5b99b7c7fc 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -18,7 +18,7 @@ 11 11 - 3.3.2 + 3.4.0 From dc4b7574e80198cf774fce08cd1125383bbe1b12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:26:50 +0200 Subject: [PATCH 026/644] chore(deps-dev): bump org.mockito:mockito-core from 5.5.0 to 5.6.0 (#2081) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.5.0 to 5.6.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.5.0...v5.6.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9ef762e1cc..f5bab12f6e 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 6.7.2 1.7.36 2.20.0 - 5.5.0 + 5.6.0 3.13.0 0.19 1.13.0 From 97019077b4acb3a452498624f458172536588eca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Oct 2023 09:32:11 +0200 Subject: [PATCH 027/644] chore(deps): bump io.micrometer:micrometer-core from 1.11.4 to 1.11.5 (#2086) Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.11.4 to 1.11.5. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.11.4...v1.11.5) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f5bab12f6e..22cf2d64f6 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 3.24.2 4.2.0 2.7.3 - 1.11.4 + 1.11.5 4.10.0 3.1.3 0.9.0 From 0ea50c1f615e309f3eac7efb86d6ffcf728fcbc1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:58:35 +0200 Subject: [PATCH 028/644] chore(deps): bump log4j.version from 2.20.0 to 2.21.0 (#2093) Bumps `log4j.version` from 2.20.0 to 2.21.0. Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.20.0 to 2.21.0 Updates `org.apache.logging.log4j:log4j2-core` from 2.20.0 to 2.21.0 Updates `org.apache.logging.log4j:log4j-core` from 2.20.0 to 2.21.0 --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-slf4j-impl dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.apache.logging.log4j:log4j2-core dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 22cf2d64f6..2d1c3a1591 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ 5.9.2 6.7.2 1.7.36 - 2.20.0 + 2.21.0 5.6.0 3.13.0 0.19 From df23ab6f810d17457735a962cbcc2f7c00625a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 8 Aug 2023 09:34:00 +0200 Subject: [PATCH 029/644] feat: create resource only if not exists (#2001) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: csviri Signed-off-by: Attila Mészáros --- .../kubernetes/KubernetesDependent.java | 9 ++- .../KubernetesDependentConverter.java | 12 +++- .../KubernetesDependentResource.java | 7 ++- .../KubernetesDependentResourceConfig.java | 19 +++++-- ...eateOnlyIfNotExistingDependentWithSSA.java | 57 +++++++++++++++++++ .../ConfigMapDependentResource.java | 30 ++++++++++ ...xistingDependentWithSSACustomResource.java | 13 +++++ ...NotExistingDependentWithSSAReconciler.java | 32 +++++++++++ 8 files changed, 170 insertions(+), 9 deletions(-) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/CreateOnlyIfNotExistingDependentWithSSA.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createonlyifnotexistsdependentwithssa/ConfigMapDependentResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createonlyifnotexistsdependentwithssa/CreateOnlyIfNotExistingDependentWithSSACustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createonlyifnotexistsdependentwithssa/CreateOnlyIfNotExistingDependentWithSSAReconciler.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java index 868ae30dbc..c3f7be408a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java @@ -7,7 +7,10 @@ import io.javaoperatorsdk.operator.api.reconciler.Constants; import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator; -import io.javaoperatorsdk.operator.processing.event.source.filter.*; +import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter; +import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter; +import io.javaoperatorsdk.operator.processing.event.source.filter.OnDeleteFilter; +import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_VALUE_SET; @@ -69,4 +72,8 @@ Class resourceDiscriminator() default ResourceDiscriminator.class; + /** + * Creates the resource only if did not exist before, this applies only if SSA is used. + */ + boolean createResourceOnlyIfNotExistingWithSSA() default KubernetesDependentResourceConfig.DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java index a9a60f8e0a..6ab07a9462 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java @@ -14,6 +14,8 @@ import io.javaoperatorsdk.operator.processing.event.source.filter.OnDeleteFilter; import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter; +import static io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfig.DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA; + public class KubernetesDependentConverter implements ConfigurationConverter, KubernetesDependentResource> { @@ -25,6 +27,8 @@ public KubernetesDependentResourceConfig configFrom(KubernetesDependent confi var namespaces = parentConfiguration.getNamespaces(); var configuredNS = false; String labelSelector = null; + var createResourceOnlyIfNotExistingWithSSA = + DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA; OnAddFilter onAddFilter = null; OnUpdateFilter onUpdateFilter = null; OnDeleteFilter onDeleteFilter = null; @@ -39,9 +43,8 @@ public KubernetesDependentResourceConfig configFrom(KubernetesDependent confi final var fromAnnotation = configAnnotation.labelSelector(); labelSelector = Constants.NO_VALUE_SET.equals(fromAnnotation) ? null : fromAnnotation; - final var context = - Utils.contextFor(parentConfiguration, originatingClass, - configAnnotation.annotationType()); + final var context = Utils.contextFor(parentConfiguration, originatingClass, + configAnnotation.annotationType()); onAddFilter = Utils.instantiate(configAnnotation.onAddFilter(), OnAddFilter.class, context); onUpdateFilter = Utils.instantiate(configAnnotation.onUpdateFilter(), OnUpdateFilter.class, context); @@ -53,9 +56,12 @@ public KubernetesDependentResourceConfig configFrom(KubernetesDependent confi resourceDiscriminator = Utils.instantiate(configAnnotation.resourceDiscriminator(), ResourceDiscriminator.class, context); + createResourceOnlyIfNotExistingWithSSA = + configAnnotation.createResourceOnlyIfNotExistingWithSSA(); } return new KubernetesDependentResourceConfig(namespaces, labelSelector, configuredNS, + createResourceOnlyIfNotExistingWithSSA, resourceDiscriminator, onAddFilter, onUpdateFilter, onDeleteFilter, genericFilter); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 20e83f02bf..8d32892e10 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -130,7 +130,12 @@ protected R handleUpdate(R actual, R desired, P primary, Context

context) { public R create(R target, P primary, Context

context) { if (useSSA(context)) { // setting resource version for SSA so only created if it doesn't exist already - target.getMetadata().setResourceVersion("1"); + var createIfNotExisting = kubernetesDependentResourceConfig == null + ? KubernetesDependentResourceConfig.DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA + : kubernetesDependentResourceConfig.createResourceOnlyIfNotExistingWithSSA(); + if (createIfNotExisting) { + target.getMetadata().setResourceVersion("1"); + } } final var resource = prepare(target, primary, "Creating"); return useSSA(context) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java index 509dae6d0f..c28a1ef1db 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java @@ -13,9 +13,12 @@ public class KubernetesDependentResourceConfig { + public static final boolean DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA = true; + private Set namespaces; private String labelSelector; private boolean namespacesWereConfigured; + private boolean createResourceOnlyIfNotExistingWithSSA; private ResourceDiscriminator resourceDiscriminator; private final OnAddFilter onAddFilter; @@ -24,19 +27,23 @@ public class KubernetesDependentResourceConfig { private final GenericFilter genericFilter; public KubernetesDependentResourceConfig() { - this(Constants.SAME_AS_CONTROLLER_NAMESPACES_SET, NO_VALUE_SET, true, + this(Constants.SAME_AS_CONTROLLER_NAMESPACES_SET, NO_VALUE_SET, true,false, null, null, null, null, null); } - public KubernetesDependentResourceConfig(Set namespaces, String labelSelector, - boolean configuredNS, ResourceDiscriminator resourceDiscriminator, + public KubernetesDependentResourceConfig(Set namespaces, + String labelSelector, + boolean configuredNS, + boolean createResourceOnlyIfNotExistingWithSSA, + ResourceDiscriminator resourceDiscriminator, OnAddFilter onAddFilter, OnUpdateFilter onUpdateFilter, OnDeleteFilter onDeleteFilter, GenericFilter genericFilter) { this.namespaces = namespaces; this.labelSelector = labelSelector; this.namespacesWereConfigured = configuredNS; + this.createResourceOnlyIfNotExistingWithSSA = createResourceOnlyIfNotExistingWithSSA; this.onAddFilter = onAddFilter; this.onUpdateFilter = onUpdateFilter; this.onDeleteFilter = onDeleteFilter; @@ -47,7 +54,8 @@ public KubernetesDependentResourceConfig(Set namespaces, String labelSel // use builder instead @Deprecated(forRemoval = true) public KubernetesDependentResourceConfig(Set namespaces, String labelSelector) { - this(namespaces, labelSelector, true, null, null, null, + this(namespaces, labelSelector, true, DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA, + null, null, null, null, null); } @@ -75,6 +83,9 @@ public OnAddFilter onAddFilter() { return onAddFilter; } + public boolean createResourceOnlyIfNotExistingWithSSA() { + return createResourceOnlyIfNotExistingWithSSA; + } public OnUpdateFilter onUpdateFilter() { return onUpdateFilter; diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/CreateOnlyIfNotExistingDependentWithSSA.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/CreateOnlyIfNotExistingDependentWithSSA.java new file mode 100644 index 0000000000..8a347f632e --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/CreateOnlyIfNotExistingDependentWithSSA.java @@ -0,0 +1,57 @@ +package io.javaoperatorsdk.operator; + +import java.time.Duration; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.createonlyifnotexistsdependentwithssa.CreateOnlyIfNotExistingDependentWithSSACustomResource; +import io.javaoperatorsdk.operator.sample.createonlyifnotexistsdependentwithssa.CreateOnlyIfNotExistingDependentWithSSAReconciler; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +class CreateOnlyIfNotExistingDependentWithSSA { + + public static final String TEST_RESOURCE_NAME = "test1"; + public static final String KEY = "key"; + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(new CreateOnlyIfNotExistingDependentWithSSAReconciler()) + .build(); + + + @Test + void createsResourceOnlyIfNotExisting() { + var cm = new ConfigMapBuilder().withMetadata(new ObjectMetaBuilder() + .withName(TEST_RESOURCE_NAME) + .build()) + .withData(Map.of(KEY, "val")) + .build(); + + extension.create(cm); + extension.create(testResource()); + + await().pollDelay(Duration.ofMillis(200)).untilAsserted(() -> { + var currentCM = extension.get(ConfigMap.class, TEST_RESOURCE_NAME); + assertThat(currentCM.getData()).containsKey(KEY); + }); + } + + CreateOnlyIfNotExistingDependentWithSSACustomResource testResource() { + var res = new CreateOnlyIfNotExistingDependentWithSSACustomResource(); + res.setMetadata(new ObjectMetaBuilder() + .withName(TEST_RESOURCE_NAME) + .build()); + + return res; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createonlyifnotexistsdependentwithssa/ConfigMapDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createonlyifnotexistsdependentwithssa/ConfigMapDependentResource.java new file mode 100644 index 0000000000..d6947c2834 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createonlyifnotexistsdependentwithssa/ConfigMapDependentResource.java @@ -0,0 +1,30 @@ +package io.javaoperatorsdk.operator.sample.createonlyifnotexistsdependentwithssa; + +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; + +public class ConfigMapDependentResource extends + CRUDKubernetesDependentResource { + + public ConfigMapDependentResource() { + super(ConfigMap.class); + } + + @Override + protected ConfigMap desired(CreateOnlyIfNotExistingDependentWithSSACustomResource primary, + Context context) { + ConfigMap configMap = new ConfigMap(); + configMap.setMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()); + configMap.setData(Map.of("drkey", "v")); + return configMap; + } +} + + diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createonlyifnotexistsdependentwithssa/CreateOnlyIfNotExistingDependentWithSSACustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createonlyifnotexistsdependentwithssa/CreateOnlyIfNotExistingDependentWithSSACustomResource.java new file mode 100644 index 0000000000..23f06c365f --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createonlyifnotexistsdependentwithssa/CreateOnlyIfNotExistingDependentWithSSACustomResource.java @@ -0,0 +1,13 @@ +package io.javaoperatorsdk.operator.sample.createonlyifnotexistsdependentwithssa; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +public class CreateOnlyIfNotExistingDependentWithSSACustomResource + extends CustomResource + implements Namespaced { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createonlyifnotexistsdependentwithssa/CreateOnlyIfNotExistingDependentWithSSAReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createonlyifnotexistsdependentwithssa/CreateOnlyIfNotExistingDependentWithSSAReconciler.java new file mode 100644 index 0000000000..884b5a859d --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createonlyifnotexistsdependentwithssa/CreateOnlyIfNotExistingDependentWithSSAReconciler.java @@ -0,0 +1,32 @@ +package io.javaoperatorsdk.operator.sample.createonlyifnotexistsdependentwithssa; + +import java.util.concurrent.atomic.AtomicInteger; + +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; + +@ControllerConfiguration(dependents = { + @Dependent(type = ConfigMapDependentResource.class)}) +public class CreateOnlyIfNotExistingDependentWithSSAReconciler + implements Reconciler { + + private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + + @Override + public UpdateControl reconcile( + CreateOnlyIfNotExistingDependentWithSSACustomResource resource, + Context context) { + numberOfExecutions.addAndGet(1); + return UpdateControl.noUpdate(); + } + + public int getNumberOfExecutions() { + return numberOfExecutions.get(); + } + + + +} From 1f61f07153ab4bd885cc5d00729fbd2941d8bc75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 14 Aug 2023 12:07:21 +0200 Subject: [PATCH 030/644] feat: leader election callbacks (#2015) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: csviri Signed-off-by: Attila Mészáros --- .../operator/LeaderElectionManager.java | 19 ++++-- .../config/LeaderElectionConfiguration.java | 20 ++++-- .../LeaderElectionConfigurationBuilder.java | 61 +++++++++++++++++++ 3 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/LeaderElectionConfigurationBuilder.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java index f40f8c2ba1..b916fdcc10 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/LeaderElectionManager.java @@ -65,7 +65,7 @@ private void init(LeaderElectionConfiguration config) { config.getLeaseDuration(), config.getRenewDeadline(), config.getRetryPeriod(), - leaderCallbacks(), + leaderCallbacks(config), // this is required to be false to receive stop event in all cases, thus stopLeading // is called always when leadership is lost/cancelled false, @@ -75,11 +75,20 @@ private void init(LeaderElectionConfiguration config) { - private LeaderCallbacks leaderCallbacks() { + private LeaderCallbacks leaderCallbacks(LeaderElectionConfiguration config) { return new LeaderCallbacks( - this::startLeading, - this::stopLeading, - leader -> log.info("New leader with identity: {}", leader)); + () -> { + config.getLeaderCallbacks().ifPresent(LeaderCallbacks::onStartLeading); + LeaderElectionManager.this.startLeading(); + }, + () -> { + config.getLeaderCallbacks().ifPresent(LeaderCallbacks::onStopLeading); + LeaderElectionManager.this.stopLeading(); + }, + leader -> { + config.getLeaderCallbacks().ifPresent(cb -> cb.onNewLeader(leader)); + log.info("New leader with identity: {}", leader); + }); } private void startLeading() { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/LeaderElectionConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/LeaderElectionConfiguration.java index 5a2c322657..0ab72ff165 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/LeaderElectionConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/LeaderElectionConfiguration.java @@ -3,6 +3,8 @@ import java.time.Duration; import java.util.Optional; +import io.fabric8.kubernetes.client.extended.leaderelection.LeaderCallbacks; + public class LeaderElectionConfiguration { public static final Duration LEASE_DURATION_DEFAULT_VALUE = Duration.ofSeconds(15); @@ -17,13 +19,15 @@ public class LeaderElectionConfiguration { private final Duration renewDeadline; private final Duration retryPeriod; + private final LeaderCallbacks leaderCallbacks; + public LeaderElectionConfiguration(String leaseName, String leaseNamespace, String identity) { this( leaseName, leaseNamespace, LEASE_DURATION_DEFAULT_VALUE, RENEW_DEADLINE_DEFAULT_VALUE, - RETRY_PERIOD_DEFAULT_VALUE, identity); + RETRY_PERIOD_DEFAULT_VALUE, identity, null); } public LeaderElectionConfiguration(String leaseName, String leaseNamespace) { @@ -32,7 +36,7 @@ public LeaderElectionConfiguration(String leaseName, String leaseNamespace) { leaseNamespace, LEASE_DURATION_DEFAULT_VALUE, RENEW_DEADLINE_DEFAULT_VALUE, - RETRY_PERIOD_DEFAULT_VALUE, null); + RETRY_PERIOD_DEFAULT_VALUE, null, null); } public LeaderElectionConfiguration(String leaseName) { @@ -41,7 +45,7 @@ public LeaderElectionConfiguration(String leaseName) { null, LEASE_DURATION_DEFAULT_VALUE, RENEW_DEADLINE_DEFAULT_VALUE, - RETRY_PERIOD_DEFAULT_VALUE, null); + RETRY_PERIOD_DEFAULT_VALUE, null, null); } public LeaderElectionConfiguration( @@ -50,7 +54,7 @@ public LeaderElectionConfiguration( Duration leaseDuration, Duration renewDeadline, Duration retryPeriod) { - this(leaseName, leaseNamespace, leaseDuration, renewDeadline, retryPeriod, null); + this(leaseName, leaseNamespace, leaseDuration, renewDeadline, retryPeriod, null, null); } public LeaderElectionConfiguration( @@ -59,13 +63,15 @@ public LeaderElectionConfiguration( Duration leaseDuration, Duration renewDeadline, Duration retryPeriod, - String identity) { + String identity, + LeaderCallbacks leaderCallbacks) { this.leaseName = leaseName; this.leaseNamespace = leaseNamespace; this.leaseDuration = leaseDuration; this.renewDeadline = renewDeadline; this.retryPeriod = retryPeriod; this.identity = identity; + this.leaderCallbacks = leaderCallbacks; } public Optional getLeaseNamespace() { @@ -91,4 +97,8 @@ public Duration getRetryPeriod() { public Optional getIdentity() { return Optional.ofNullable(identity); } + + public Optional getLeaderCallbacks() { + return Optional.ofNullable(leaderCallbacks); + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/LeaderElectionConfigurationBuilder.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/LeaderElectionConfigurationBuilder.java new file mode 100644 index 0000000000..4b21dd9d2d --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/LeaderElectionConfigurationBuilder.java @@ -0,0 +1,61 @@ +package io.javaoperatorsdk.operator.api.config; + +import java.time.Duration; + +import io.fabric8.kubernetes.client.extended.leaderelection.LeaderCallbacks; + +import static io.javaoperatorsdk.operator.api.config.LeaderElectionConfiguration.*; + +public final class LeaderElectionConfigurationBuilder { + + private String leaseName; + private String leaseNamespace; + private String identity; + private Duration leaseDuration = LEASE_DURATION_DEFAULT_VALUE; + private Duration renewDeadline = RENEW_DEADLINE_DEFAULT_VALUE; + private Duration retryPeriod = RETRY_PERIOD_DEFAULT_VALUE; + private LeaderCallbacks leaderCallbacks; + + private LeaderElectionConfigurationBuilder(String leaseName) { + this.leaseName = leaseName; + } + + public static LeaderElectionConfigurationBuilder aLeaderElectionConfiguration(String leaseName) { + return new LeaderElectionConfigurationBuilder(leaseName); + } + + public LeaderElectionConfigurationBuilder withLeaseNamespace(String leaseNamespace) { + this.leaseNamespace = leaseNamespace; + return this; + } + + public LeaderElectionConfigurationBuilder withIdentity(String identity) { + this.identity = identity; + return this; + } + + public LeaderElectionConfigurationBuilder withLeaseDuration(Duration leaseDuration) { + this.leaseDuration = leaseDuration; + return this; + } + + public LeaderElectionConfigurationBuilder withRenewDeadline(Duration renewDeadline) { + this.renewDeadline = renewDeadline; + return this; + } + + public LeaderElectionConfigurationBuilder withRetryPeriod(Duration retryPeriod) { + this.retryPeriod = retryPeriod; + return this; + } + + public LeaderElectionConfigurationBuilder withLeaderCallbacks(LeaderCallbacks leaderCallbacks) { + this.leaderCallbacks = leaderCallbacks; + return this; + } + + public LeaderElectionConfiguration build() { + return new LeaderElectionConfiguration(leaseName, leaseNamespace, leaseDuration, renewDeadline, + retryPeriod, identity, leaderCallbacks); + } +} From 5ef7d56a7dd6ab9067d4293a433a1f733636d0a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 14 Aug 2023 14:17:29 +0200 Subject: [PATCH 031/644] discriminator improvements (#2013) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: csviri Signed-off-by: Attila Mészáros --- .../api/reconciler/IndexDiscriminator.java | 50 +++++++++++++++++++ .../ResourceIDMatcherDiscriminator.java | 26 ++++++++-- .../IndexDiscriminator.java | 41 --------------- .../IndexDiscriminatorTestReconciler.java | 4 +- .../TestIndexDiscriminator.java | 14 ++++++ 5 files changed, 89 insertions(+), 46 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/IndexDiscriminator.java delete mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/IndexDiscriminator.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/TestIndexDiscriminator.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/IndexDiscriminator.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/IndexDiscriminator.java new file mode 100644 index 0000000000..7a27397b26 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/IndexDiscriminator.java @@ -0,0 +1,50 @@ +package io.javaoperatorsdk.operator.api.reconciler; + +import java.util.Optional; +import java.util.function.Function; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; + +/** + * Uses a custom index of {@link InformerEventSource} to access the target resource. The index needs + * to be explicitly created when the event source is defined. This approach improves the performance + * to access the resource. + */ +public class IndexDiscriminator + implements ResourceDiscriminator { + + private final String indexName; + private final String eventSourceName; + private final Function keyMapper; + + public IndexDiscriminator(String indexName, Function keyMapper) { + this(indexName, null, keyMapper); + } + + public IndexDiscriminator(String indexName, String eventSourceName, + Function keyMapper) { + this.indexName = indexName; + this.eventSourceName = eventSourceName; + this.keyMapper = keyMapper; + } + + @Override + public Optional distinguish(Class resource, + P primary, + Context

context) { + + InformerEventSource eventSource = + (InformerEventSource) context + .eventSourceRetriever() + .getResourceEventSourceFor(resource, eventSourceName); + var resources = eventSource.byIndex(indexName, keyMapper.apply(primary)); + if (resources.isEmpty()) { + return Optional.empty(); + } else if (resources.size() > 1) { + throw new IllegalStateException("More than one resource found"); + } else { + return Optional.of(resources.get(0)); + } + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceIDMatcherDiscriminator.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceIDMatcherDiscriminator.java index d23459e271..da773fc210 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceIDMatcherDiscriminator.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceIDMatcherDiscriminator.java @@ -5,21 +5,41 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.Cache; public class ResourceIDMatcherDiscriminator implements ResourceDiscriminator { + + private final String eventSourceName; private final Function mapper; public ResourceIDMatcherDiscriminator(Function mapper) { + this(null, mapper); + } + + public ResourceIDMatcherDiscriminator(String eventSourceName, Function mapper) { + this.eventSourceName = eventSourceName; this.mapper = mapper; } + @SuppressWarnings("unchecked") @Override public Optional distinguish(Class resource, P primary, Context

context) { var resourceID = mapper.apply(primary); - return context.getSecondaryResourcesAsStream(resource) - .filter(resourceID::isSameResource) - .findFirst(); + if (eventSourceName != null) { + return ((Cache) context.eventSourceRetriever().getResourceEventSourceFor(resource, + eventSourceName)) + .get(resourceID); + } else { + var eventSources = context.eventSourceRetriever().getResourceEventSourcesFor(resource); + if (eventSources.size() == 1) { + return ((Cache) eventSources.get(0)).get(resourceID); + } else { + return context.getSecondaryResourcesAsStream(resource) + .filter(resourceID::isSameResource) + .findFirst(); + } + } } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/IndexDiscriminator.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/IndexDiscriminator.java deleted file mode 100644 index eb6e193479..0000000000 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/IndexDiscriminator.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.javaoperatorsdk.operator.sample.indexdiscriminator; - -import java.util.Optional; - -import io.fabric8.kubernetes.api.model.ConfigMap; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator; -import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; - -import static io.javaoperatorsdk.operator.sample.indexdiscriminator.IndexDiscriminatorTestReconciler.configMapKeyFromPrimary; - -public class IndexDiscriminator - implements ResourceDiscriminator { - - private final String indexName; - private final String nameSuffix; - - public IndexDiscriminator(String indexName, String nameSuffix) { - this.indexName = indexName; - this.nameSuffix = nameSuffix; - } - - @Override - public Optional distinguish(Class resource, - IndexDiscriminatorTestCustomResource primary, - Context context) { - - InformerEventSource eventSource = - (InformerEventSource) context - .eventSourceRetriever() - .getResourceEventSourceFor(ConfigMap.class); - var resources = eventSource.byIndex(indexName, configMapKeyFromPrimary(primary, nameSuffix)); - if (resources.isEmpty()) { - return Optional.empty(); - } else if (resources.size() > 1) { - throw new IllegalStateException("more than one resource"); - } else { - return Optional.of(resources.get(0)); - } - } -} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/IndexDiscriminatorTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/IndexDiscriminatorTestReconciler.java index 0b0af2a1cc..b988c93491 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/IndexDiscriminatorTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/IndexDiscriminatorTestReconciler.java @@ -81,10 +81,10 @@ public Map prepareEventSources( firstDependentResourceConfigMap .setResourceDiscriminator( - new IndexDiscriminator(CONFIG_MAP_INDEX_1, FIRST_CONFIG_MAP_SUFFIX_1)); + new TestIndexDiscriminator(CONFIG_MAP_INDEX_1, FIRST_CONFIG_MAP_SUFFIX_1)); secondDependentResourceConfigMap .setResourceDiscriminator( - new IndexDiscriminator(CONFIG_MAP_INDEX_2, FIRST_CONFIG_MAP_SUFFIX_2)); + new TestIndexDiscriminator(CONFIG_MAP_INDEX_2, FIRST_CONFIG_MAP_SUFFIX_2)); return EventSourceInitializer.nameEventSources(eventSource); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/TestIndexDiscriminator.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/TestIndexDiscriminator.java new file mode 100644 index 0000000000..a56e44ced8 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/TestIndexDiscriminator.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.sample.indexdiscriminator; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.javaoperatorsdk.operator.api.reconciler.IndexDiscriminator; + +import static io.javaoperatorsdk.operator.sample.indexdiscriminator.IndexDiscriminatorTestReconciler.configMapKeyFromPrimary; + +public class TestIndexDiscriminator + extends IndexDiscriminator { + + public TestIndexDiscriminator(String indexName, String nameSuffix) { + super(indexName, p -> configMapKeyFromPrimary(p, nameSuffix)); + } +} From da5a800e496d01e62776d407783bdd3ca78ff6f8 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Wed, 16 Aug 2023 11:50:43 +0200 Subject: [PATCH 032/644] chore: switch version to 4.5.0-SNAPSHOT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: csviri Signed-off-by: Attila Mészáros --- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index b415011178..a1b3e68470 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.5-SNAPSHOT + 4.5.0-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 5ca14df2e3..a418291dcc 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.5-SNAPSHOT + 4.5.0-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 7f2e71f95f..d3036a6079 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.4.5-SNAPSHOT + 4.5.0-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index c8e4c4488f..792c3c464b 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.4.5-SNAPSHOT + 4.5.0-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 106c4f899a..de852a1dab 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.5-SNAPSHOT + 4.5.0-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index 1aa7332003..2b74b5e91f 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.4.5-SNAPSHOT + 4.5.0-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 2d1c3a1591..49a4f12375 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.4.5-SNAPSHOT + 4.5.0-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 110c058b33..8f9256c8c3 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.5-SNAPSHOT + 4.5.0-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 2f648f00b1..289d03796e 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.5-SNAPSHOT + 4.5.0-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 32eeab41b9..61e1322f65 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.4.5-SNAPSHOT + 4.5.0-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 12f89dce66..3e92c93dca 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.5-SNAPSHOT + 4.5.0-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 5b99b7c7fc..12f2052b3d 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.4.5-SNAPSHOT + 4.5.0-SNAPSHOT sample-webpage-operator From f3f87ab912887fd738c13dae7e78e51aefaa191d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 22 Aug 2023 17:13:19 +0200 Subject: [PATCH 033/644] feat: re-schedule from error handler (#2023) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: csviri Signed-off-by: Attila Mészáros --- .../operator/api/reconciler/BaseControl.java | 2 +- .../reconciler/ErrorStatusUpdateControl.java | 17 +++++++++++++++-- .../event/ReconciliationDispatcher.java | 8 ++++++-- .../event/ReconciliationDispatcherTest.java | 18 ++++++++++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/BaseControl.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/BaseControl.java index ac51bb7263..a5cdb85257 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/BaseControl.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/BaseControl.java @@ -9,7 +9,7 @@ public abstract class BaseControl> { private Long scheduleDelay = null; public T rescheduleAfter(long delay) { - this.scheduleDelay = delay; + rescheduleAfter(Duration.ofMillis(delay)); return (T) this; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusUpdateControl.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusUpdateControl.java index 6d317161f7..48c0e32946 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusUpdateControl.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusUpdateControl.java @@ -1,16 +1,17 @@ package io.javaoperatorsdk.operator.api.reconciler; +import java.time.Duration; import java.util.Optional; import io.fabric8.kubernetes.api.model.HasMetadata; -public class ErrorStatusUpdateControl

{ +public class ErrorStatusUpdateControl

+ extends BaseControl> { private final P resource; private final boolean patch; private boolean noRetry = false; - public static ErrorStatusUpdateControl patchStatus(T resource) { return new ErrorStatusUpdateControl<>(resource, true); } @@ -49,4 +50,16 @@ public boolean isNoRetry() { public boolean isPatch() { return patch; } + + /** + * If re-scheduled using this method, it is not considered as retry, it effectively cancels retry. + * + * @param delay for next execution + * @return ErrorStatusUpdateControl + */ + @Override + public ErrorStatusUpdateControl

rescheduleAfter(Duration delay) { + withNoRetry(); + return super.rescheduleAfter(delay); + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java index 78f42e3bed..9a110a7ba8 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java @@ -201,13 +201,17 @@ public boolean isLastAttempt() { .updateStatus(errorStatusUpdateControl.getResource().orElseThrow()); } if (errorStatusUpdateControl.isNoRetry()) { + PostExecutionControl

postExecutionControl; if (updatedResource != null) { - return errorStatusUpdateControl.isPatch() + postExecutionControl = errorStatusUpdateControl.isPatch() ? PostExecutionControl.customResourceStatusPatched(updatedResource) : PostExecutionControl.customResourceUpdated(updatedResource); } else { - return PostExecutionControl.defaultDispatch(); + postExecutionControl = PostExecutionControl.defaultDispatch(); } + errorStatusUpdateControl.getScheduleDelay() + .ifPresent(postExecutionControl::withReSchedule); + return postExecutionControl; } } catch (RuntimeException ex) { log.error("Error during error status handling.", ex); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java index 9b113625df..c6aacb9071 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java @@ -673,6 +673,24 @@ void retriesAddingFinalizer() { verify(customResourceFacade, times(2)).updateResource(any()); } + @Test + void reSchedulesFromErrorHandler() { + var delay = 1000L; + testCustomResource.addFinalizer(DEFAULT_FINALIZER); + reconciler.reconcile = (r, c) -> { + throw new IllegalStateException("Error Status Test"); + }; + reconciler.errorHandler = + (r, ri, e) -> ErrorStatusUpdateControl.noStatusUpdate() + .rescheduleAfter(delay); + + var res = reconciliationDispatcher.handleExecution( + new ExecutionScope(null).setResource(testCustomResource)); + + assertThat(res.getReScheduleDelay()).contains(delay); + assertThat(res.getRuntimeException()).isEmpty(); + } + private ObservedGenCustomResource createObservedGenCustomResource() { ObservedGenCustomResource observedGenCustomResource = new ObservedGenCustomResource(); observedGenCustomResource.setMetadata(new ObjectMeta()); From f8137f2658e95963366e05d8ba76c3b0cb8f774e Mon Sep 17 00:00:00 2001 From: Steven Hawkins Date: Wed, 23 Aug 2023 07:39:24 -0400 Subject: [PATCH 034/644] changes to simplify the recording mechanism (#2012) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Attila Mészáros Co-authored-by: Chris Laprun Signed-off-by: csviri Signed-off-by: Attila Mészáros --- .../dependent/DependentResource.java | 2 +- .../dependent/RecentOperationEventFilter.java | 11 -- ...actEventSourceHolderDependentResource.java | 7 +- .../KubernetesDependentResource.java | 98 +++++------ .../event/source/informer/EventRecorder.java | 72 --------- .../source/informer/InformerEventSource.java | 153 ++++++------------ .../informer/ManagedInformerEventSource.java | 3 +- .../informer/TemporaryResourceCache.java | 49 +++--- .../source/informer/EventRecorderTest.java | 81 ---------- .../informer/InformerEventSourceTest.java | 128 +++------------ .../informer/TemporaryResourceCacheTest.java | 4 +- ...CreateUpdateEventFilterTestReconciler.java | 68 ++++---- ...DependentPrimaryIndexerTestReconciler.java | 4 +- 13 files changed, 183 insertions(+), 497 deletions(-) delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationEventFilter.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/EventRecorder.java delete mode 100644 operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/EventRecorderTest.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java index affeb96bbf..8230dc4cf9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java @@ -44,7 +44,7 @@ public interface DependentResource { * @param eventSourceContext context of event source initialization * @return an optional event source */ - default Optional> eventSource( + default Optional> eventSource( EventSourceContext

eventSourceContext) { return Optional.empty(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationEventFilter.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationEventFilter.java deleted file mode 100644 index d48343e57c..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/RecentOperationEventFilter.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.javaoperatorsdk.operator.api.reconciler.dependent; - -import io.javaoperatorsdk.operator.processing.event.ResourceID; - -public interface RecentOperationEventFilter extends RecentOperationCacheFiller { - - void prepareForCreateOrUpdateEventFiltering(ResourceID resourceID, R resource); - - void cleanupOnCreateOrUpdateEventFiltering(ResourceID resourceID); - -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java index 972b61cd94..04aa5631cf 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java @@ -34,7 +34,7 @@ protected AbstractEventSourceHolderDependentResource(Class resourceType) { this.resourceType = resourceType; } - public Optional> eventSource(EventSourceContext

context) { + public Optional eventSource(EventSourceContext

context) { // some sub-classes (e.g. KubernetesDependentResource) can have their event source created // before this method is called in the managed case, so only create the event source if it // hasn't already been set. @@ -67,9 +67,8 @@ public void resolveEventSource(EventSourceRetriever

eventSourceRetriever) { * @param context for event sources * @return event source instance */ - @SuppressWarnings("unchecked") public T initEventSource(EventSourceContext

context) { - return (T) eventSource(context).orElseThrow(); + return eventSource(context).orElseThrow(); } @Override @@ -96,7 +95,7 @@ protected void applyFilters() { this.eventSource.setGenericFilter(genericFilter); } - public Optional> eventSource() { + public Optional eventSource() { return Optional.ofNullable(eventSource); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 8d32892e10..5fedd0899d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -1,6 +1,6 @@ package io.javaoperatorsdk.operator.processing.dependent.kubernetes; -import java.util.HashMap; +import java.util.Map; import java.util.Optional; import java.util.Set; @@ -8,7 +8,6 @@ import org.slf4j.LoggerFactory; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.Resource; import io.javaoperatorsdk.operator.OperatorException; @@ -103,29 +102,6 @@ public void configureWith(InformerEventSource informerEventSource) { setEventSource(informerEventSource); } - - protected R handleCreate(R desired, P primary, Context

context) { - ResourceID resourceID = ResourceID.fromResource(desired); - try { - prepareEventFiltering(desired, resourceID); - return super.handleCreate(desired, primary, context); - } catch (RuntimeException e) { - cleanupAfterEventFiltering(resourceID); - throw e; - } - } - - protected R handleUpdate(R actual, R desired, P primary, Context

context) { - ResourceID resourceID = ResourceID.fromResource(desired); - try { - prepareEventFiltering(desired, resourceID); - return super.handleUpdate(actual, desired, primary, context); - } catch (RuntimeException e) { - cleanupAfterEventFiltering(resourceID); - throw e; - } - } - @SuppressWarnings("unused") public R create(R target, P primary, Context

context) { if (useSSA(context)) { @@ -137,6 +113,7 @@ public R create(R target, P primary, Context

context) { target.getMetadata().setResourceVersion("1"); } } + addMetadata(false, null, target, primary); final var resource = prepare(target, primary, "Creating"); return useSSA(context) ? resource @@ -152,6 +129,7 @@ public R update(R actual, R target, P primary, Context

context) { actual.getMetadata().getResourceVersion()); } R updatedResource; + addMetadata(false, actual, target, primary); if (useSSA(context)) { updatedResource = prepare(target, primary, "Updating") .fieldManager(context.getControllerConfiguration().fieldManager()) @@ -165,31 +143,50 @@ public R update(R actual, R target, P primary, Context

context) { return updatedResource; } + @Override public Result match(R actualResource, P primary, Context

context) { final var desired = desired(primary, context); + return match(actualResource, desired, primary, updaterMatcher, context); + } + + @SuppressWarnings({"unused", "unchecked"}) + public Result match(R actualResource, R desired, P primary, Context

context) { + return match(actualResource, desired, primary, + (ResourceUpdaterMatcher) GenericResourceUpdaterMatcher + .updaterMatcherFor(actualResource.getClass()), + context); + } + + public Result match(R actualResource, R desired, P primary, ResourceUpdaterMatcher matcher, + Context

context) { final boolean matches; + addMetadata(true, actualResource, desired, primary); if (useSSA(context)) { - addReferenceHandlingMetadata(desired, primary); matches = SSABasedGenericKubernetesResourceMatcher.getInstance() .matches(actualResource, desired, context); } else { - matches = updaterMatcher.matches(actualResource, desired, context); + matches = matcher.matches(actualResource, desired, context); } return Result.computed(matches, desired); } - @SuppressWarnings("unused") - public Result match(R actualResource, R desired, P primary, Context

context) { - if (useSSA(context)) { - addReferenceHandlingMetadata(desired, primary); - var matches = SSABasedGenericKubernetesResourceMatcher.getInstance() - .matches(actualResource, desired, context); - return Result.computed(matches, desired); - } else { - return GenericKubernetesResourceMatcher - .match(desired, actualResource, true, - false, false, context); + protected void addMetadata(boolean forMatch, R actualResource, final R target, P primary) { + if (forMatch) { // keep the current + String actual = actualResource.getMetadata().getAnnotations() + .get(InformerEventSource.PREVIOUS_ANNOTATION_KEY); + Map annotations = target.getMetadata().getAnnotations(); + if (actual != null) { + annotations.put(InformerEventSource.PREVIOUS_ANNOTATION_KEY, actual); + } else { + annotations.remove(InformerEventSource.PREVIOUS_ANNOTATION_KEY); + } + } else { // set a new one + eventSource().orElseThrow().addPreviousAnnotation( + Optional.ofNullable(actualResource).map(r -> r.getMetadata().getResourceVersion()) + .orElse(null), + target); } + addReferenceHandlingMetadata(target, primary); } private boolean useSSA(Context

context) { @@ -197,6 +194,7 @@ private boolean useSSA(Context

context) { .ssaBasedCreateUpdateMatchForDependentResources(); } + @Override protected void handleDelete(P primary, R secondary, Context

context) { if (secondary != null) { client.resource(secondary).delete(); @@ -214,13 +212,7 @@ protected Resource prepare(R desired, P primary, String actionName) { desired.getClass(), ResourceID.fromResource(desired)); - addReferenceHandlingMetadata(desired, primary); - - if (desired instanceof Namespaced) { - return client.resource(desired).inNamespace(desired.getMetadata().getNamespace()); - } else { - return client.resource(desired); - } + return client.resource(desired); } protected void addReferenceHandlingMetadata(R desired, P primary) { @@ -254,7 +246,7 @@ protected InformerEventSource createEventSource(EventSourceContext

cont "Using default configuration for {} KubernetesDependentResource, call configureWith to provide configuration", resourceType().getSimpleName()); } - return (InformerEventSource) eventSource().orElseThrow(); + return eventSource().orElseThrow(); } private boolean useDefaultAnnotationsToIdentifyPrimary() { @@ -263,10 +255,6 @@ private boolean useDefaultAnnotationsToIdentifyPrimary() { private void addDefaultSecondaryToPrimaryMapperAnnotations(R desired, P primary) { var annotations = desired.getMetadata().getAnnotations(); - if (annotations == null) { - annotations = new HashMap<>(); - desired.getMetadata().setAnnotations(annotations); - } annotations.put(Mappers.DEFAULT_ANNOTATION_FOR_NAME, primary.getMetadata().getName()); var primaryNamespaces = primary.getMetadata().getNamespace(); if (primaryNamespaces != null) { @@ -294,16 +282,6 @@ protected R desired(P primary, Context

context) { return super.desired(primary, context); } - private void prepareEventFiltering(R desired, ResourceID resourceID) { - ((InformerEventSource) eventSource().orElseThrow()) - .prepareForCreateOrUpdateEventFiltering(resourceID, desired); - } - - private void cleanupAfterEventFiltering(ResourceID resourceID) { - ((InformerEventSource) eventSource().orElseThrow()) - .cleanupOnCreateOrUpdateEventFiltering(resourceID); - } - @Override public Optional> configuration() { return Optional.ofNullable(kubernetesDependentResourceConfig); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/EventRecorder.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/EventRecorder.java deleted file mode 100644 index 5d23d870aa..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/EventRecorder.java +++ /dev/null @@ -1,72 +0,0 @@ -package io.javaoperatorsdk.operator.processing.event.source.informer; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.processing.event.ResourceID; - -public class EventRecorder { - - private final Map> resourceEvents = new HashMap<>(); - - public void startEventRecording(ResourceID resourceID) { - resourceEvents.putIfAbsent(resourceID, new ArrayList<>(5)); - } - - public boolean isRecordingFor(ResourceID resourceID) { - return resourceEvents.get(resourceID) != null; - } - - public void stopEventRecording(ResourceID resourceID) { - resourceEvents.remove(resourceID); - } - - public void recordEvent(R resource) { - resourceEvents.get(ResourceID.fromResource(resource)).add(resource); - } - - public boolean containsEventWithResourceVersion(ResourceID resourceID, - String resourceVersion) { - List events = resourceEvents.get(resourceID); - if (events == null) { - return false; - } - if (events.isEmpty()) { - return false; - } else { - return events.stream() - .anyMatch(e -> e.getMetadata().getResourceVersion().equals(resourceVersion)); - } - } - - public boolean containsEventWithVersionButItsNotLastOne( - ResourceID resourceID, String resourceVersion) { - List resources = resourceEvents.get(resourceID); - if (resources == null) { - throw new IllegalStateException( - "Null events list, this is probably a result of invalid usage of the " + - "InformerEventSource. Resource ID: " + resourceID); - } - if (resources.isEmpty()) { - throw new IllegalStateException("No events for resource id: " + resourceID); - } - return !resources - .get(resources.size() - 1) - .getMetadata() - .getResourceVersion() - .equals(resourceVersion); - } - - public R getLastEvent(ResourceID resourceID) { - List resources = resourceEvents.get(resourceID); - if (resources == null) { - throw new IllegalStateException( - "Null events list, this is probably a result of invalid usage of the " + - "InformerEventSource. Resource ID: " + resourceID); - } - return resources.get(resources.size() - 1); - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index a9a07f2332..3b407b42ea 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -14,7 +14,6 @@ import io.javaoperatorsdk.operator.api.config.ConfigurationService; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationEventFilter; import io.javaoperatorsdk.operator.processing.event.Event; import io.javaoperatorsdk.operator.processing.event.EventHandler; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -68,16 +67,18 @@ */ public class InformerEventSource extends ManagedInformerEventSource> - implements ResourceEventHandler, RecentOperationEventFilter { + implements ResourceEventHandler { + + public static String PREVIOUS_ANNOTATION_KEY = "javaoperatorsdk.io/previous"; private static final Logger log = LoggerFactory.getLogger(InformerEventSource.class); - // always called from a synchronized method - private final EventRecorder eventRecorder = new EventRecorder<>(); + private final InformerConfiguration configuration; // we need direct control for the indexer to propagate the just update resource also to the index private final PrimaryToSecondaryIndex primaryToSecondaryIndex; private final PrimaryToSecondaryMapper

primaryToSecondaryMapper; private Map>> indexerBuffer = new HashMap<>(); + private final String id = UUID.randomUUID().toString(); public InformerEventSource( InformerConfiguration configuration, EventSourceContext

context) { @@ -147,12 +148,8 @@ public void onDelete(R resource, boolean b) { private synchronized void onAddOrUpdate(Operation operation, R newObject, R oldObject, Runnable superOnOp) { var resourceID = ResourceID.fromResource(newObject); - if (eventRecorder.isRecordingFor(resourceID)) { - log.debug("Recording event for: {}", resourceID); - eventRecorder.recordEvent(newObject); - return; - } - if (temporaryCacheHasResourceWithSameVersionAs(newObject)) { + + if (canSkipEvent(newObject, oldObject, resourceID)) { log.debug( "Skipping event propagation for {}, since was a result of a reconcile action. Resource ID: {}", operation, @@ -172,16 +169,33 @@ private synchronized void onAddOrUpdate(Operation operation, R newObject, R oldO } } - private boolean temporaryCacheHasResourceWithSameVersionAs(R resource) { - var resourceID = ResourceID.fromResource(resource); + private boolean canSkipEvent(R newObject, R oldObject, ResourceID resourceID) { var res = temporaryResourceCache.getResourceFromCache(resourceID); - return res.map(r -> { - boolean resVersionsEqual = r.getMetadata().getResourceVersion() - .equals(resource.getMetadata().getResourceVersion()); - log.debug("Resource found in temporal cache for id: {} resource versions equal: {}", - resourceID, resVersionsEqual); - return resVersionsEqual; - }).orElse(false); + if (res.isEmpty()) { + return isEventKnownFromAnnotation(newObject, oldObject); + } + boolean resVersionsEqual = newObject.getMetadata().getResourceVersion() + .equals(res.get().getMetadata().getResourceVersion()); + log.debug("Resource found in temporal cache for id: {} resource versions equal: {}", + resourceID, resVersionsEqual); + return resVersionsEqual; + } + + private boolean isEventKnownFromAnnotation(R newObject, R oldObject) { + String previous = newObject.getMetadata().getAnnotations().get(PREVIOUS_ANNOTATION_KEY); + boolean known = false; + if (previous != null) { + String[] parts = previous.split(","); + if (id.equals(parts[0])) { + if (oldObject == null && parts.length == 1) { + known = true; + } else if (oldObject != null && parts.length == 2 + && oldObject.getMetadata().getResourceVersion().equals(parts[1])) { + known = true; + } + } + } + return known; } private void propagateEvent(R object) { @@ -239,99 +253,24 @@ public InformerConfiguration getConfiguration() { @Override public synchronized void handleRecentResourceUpdate(ResourceID resourceID, R resource, R previousVersionOfResource) { - handleRecentCreateOrUpdate(Operation.UPDATE, resource, previousVersionOfResource, - () -> super.handleRecentResourceUpdate(resourceID, resource, previousVersionOfResource)); + handleRecentCreateOrUpdate(Operation.UPDATE, resource, previousVersionOfResource); } @Override public synchronized void handleRecentResourceCreate(ResourceID resourceID, R resource) { - handleRecentCreateOrUpdate(Operation.ADD, resource, null, - () -> super.handleRecentResourceCreate(resourceID, resource)); + handleRecentCreateOrUpdate(Operation.ADD, resource, null); } - private void handleRecentCreateOrUpdate(Operation operation, R resource, R oldResource, - Runnable runnable) { - primaryToSecondaryIndex.onAddOrUpdate(resource); - if (eventRecorder.isRecordingFor(ResourceID.fromResource(resource))) { - handleRecentResourceOperationAndStopEventRecording(operation, resource, oldResource); - } else { - runnable.run(); - } - } - - /** - * There can be the following cases: - *

- * - * @param newResource just created or updated resource - */ - private void handleRecentResourceOperationAndStopEventRecording(Operation operation, - R newResource, R oldResource) { - ResourceID resourceID = ResourceID.fromResource(newResource); - try { - if (!eventRecorder.containsEventWithResourceVersion( - resourceID, newResource.getMetadata().getResourceVersion())) { - log.debug( - "Did not found event in buffer with target version and resource id: {}", resourceID); - temporaryResourceCache.unconditionallyCacheResource(newResource); - } else { - // if the resource is not added to the temp cache, it is cleared, since - // the cache is cleared by subsequent events after updates, but if those did not receive - // the temp cache is still filled at this point with an old resource - log.debug("Cleaning temporary cache for resource id: {}", resourceID); - temporaryResourceCache.removeResourceFromCache(newResource); - if (eventRecorder.containsEventWithVersionButItsNotLastOne( - resourceID, newResource.getMetadata().getResourceVersion())) { - R lastEvent = eventRecorder.getLastEvent(resourceID); - - log.debug( - "Found events in event buffer but the target event is not last for id: {}. Propagating event.", - resourceID); - if (eventAcceptedByFilter(operation, newResource, oldResource)) { - propagateEvent(lastEvent); - } - } - } - } finally { - log.debug("Stopping event recording for: {}", resourceID); - eventRecorder.stopEventRecording(resourceID); - } + private void handleRecentCreateOrUpdate(Operation operation, R newResource, R oldResource) { + primaryToSecondaryIndex.onAddOrUpdate(newResource); + temporaryResourceCache.putResource(newResource, Optional.ofNullable(oldResource) + .map(r -> r.getMetadata().getResourceVersion()).orElse(null)); } private boolean useSecondaryToPrimaryIndex() { return this.primaryToSecondaryMapper == null; } - @Override - public synchronized void prepareForCreateOrUpdateEventFiltering(ResourceID resourceID, - R resource) { - log.debug("Starting event recording for: {}", resourceID); - eventRecorder.startEventRecording(resourceID); - } - - /** - * Mean to be called to clean up in case of an exception from the client. Usually in a catch - * block. - * - * @param resourceID to cleanup - */ - @Override - public synchronized void cleanupOnCreateOrUpdateEventFiltering(ResourceID resourceID) { - log.debug("Stopping event recording for: {}", resourceID); - eventRecorder.stopEventRecording(resourceID); - } - @Override public boolean allowsNamespaceChanges() { return configuration().followControllerNamespaceChanges(); @@ -361,6 +300,7 @@ private boolean acceptedByDeleteFilters(R resource, boolean b) { // Since this event source instance is created by the user, the ConfigurationService is actually // injected after it is registered. Some of the subcomponents are initialized at that time here. + @Override public void setConfigurationService(ConfigurationService configurationService) { super.setConfigurationService(configurationService); @@ -368,6 +308,7 @@ public void setConfigurationService(ConfigurationService configurationService) { indexerBuffer = new HashMap<>(); } + @Override public void addIndexers(Map>> indexers) { if (indexerBuffer == null) { throw new OperatorException("Cannot add indexers after InformerEventSource started."); @@ -375,4 +316,16 @@ public void addIndexers(Map>> indexers) { indexerBuffer.putAll(indexers); } + /** + * Add an annotation to the resource so that the subsequent will be omitted + * + * @param resourceVersion null if there is no prior version + * @param target mutable resource that will be returned + */ + public R addPreviousAnnotation(String resourceVersion, R target) { + target.getMetadata().getAnnotations().put(PREVIOUS_ANNOTATION_KEY, + id + Optional.ofNullable(resourceVersion).map(rv -> "," + rv).orElse("")); + return target; + } + } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java index 02df5c2ee5..6ec6cd7f6e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java @@ -90,7 +90,7 @@ public void stop() { @Override public void handleRecentResourceUpdate(ResourceID resourceID, R resource, R previousVersionOfResource) { - temporaryResourceCache.putUpdatedResource(resource, + temporaryResourceCache.putResource(resource, previousVersionOfResource.getMetadata().getResourceVersion()); } @@ -131,6 +131,7 @@ public void addIndexers(Map>> indexers) { cache.addIndexers(indexers); } + @Override public List byIndex(String indexName, String indexKey) { return manager().byIndex(indexName, indexKey); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java index 8c3d56c008..233b409f3f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java @@ -41,40 +41,37 @@ public TemporaryResourceCache(ManagedInformerEventSource managedInforme this.managedInformerEventSource = managedInformerEventSource; } - public synchronized void removeResourceFromCache(T resource) { - cache.remove(ResourceID.fromResource(resource)); - } - - public synchronized void unconditionallyCacheResource(T newResource) { - putToCache(newResource, null); + public synchronized Optional removeResourceFromCache(T resource) { + return Optional.ofNullable(cache.remove(ResourceID.fromResource(resource))); } public synchronized void putAddedResource(T newResource) { - ResourceID resourceID = ResourceID.fromResource(newResource); - if (managedInformerEventSource.get(resourceID).isEmpty()) { - log.debug("Putting resource to cache with ID: {}", resourceID); - putToCache(newResource, resourceID); - } else { - log.debug("Won't put resource into cache found already informer cache: {}", resourceID); - } + putResource(newResource, null); } - public synchronized void putUpdatedResource(T newResource, String previousResourceVersion) { + /** + * put the item into the cache if the previousResourceVersion matches the current state. If not + * the currently cached item is removed. + * + * @param previousResourceVersion null indicates an add + */ + public synchronized void putResource(T newResource, String previousResourceVersion) { var resourceId = ResourceID.fromResource(newResource); - var informerCacheResource = managedInformerEventSource.get(resourceId); - if (informerCacheResource.isEmpty()) { - log.debug("No cached value present for resource: {}", newResource); - return; - } - // if this is not true that means the cache was already updated - if (informerCacheResource.get().getMetadata().getResourceVersion() - .equals(previousResourceVersion)) { - log.debug("Putting resource to temporal cache with id: {}", resourceId); + var cachedResource = getResourceFromCache(resourceId) + .orElse(managedInformerEventSource.get(resourceId).orElse(null)); + + if ((previousResourceVersion == null && cachedResource == null) + || (cachedResource != null && previousResourceVersion != null + && cachedResource.getMetadata().getResourceVersion() + .equals(previousResourceVersion))) { + log.debug( + "Temporarily moving ahead to target version {} for resource id: {}", + newResource.getMetadata().getResourceVersion(), resourceId); putToCache(newResource, resourceId); } else { - // if something is in cache it's surely obsolete now - log.debug("Trying to remove an obsolete resource from cache for id: {}", resourceId); - cache.remove(resourceId); + if (cache.remove(resourceId) != null) { + log.debug("Removed an obsolete resource from cache for id: {}", resourceId); + } } } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/EventRecorderTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/EventRecorderTest.java deleted file mode 100644 index 556ad089ff..0000000000 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/EventRecorderTest.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.javaoperatorsdk.operator.processing.event.source.informer; - -import org.junit.jupiter.api.Test; - -import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.api.model.ObjectMeta; -import io.javaoperatorsdk.operator.processing.event.ResourceID; - -import static org.assertj.core.api.Assertions.assertThat; - -class EventRecorderTest { - - public static final String RESOURCE_VERSION = "0"; - public static final String RESOURCE_VERSION1 = "1"; - - EventRecorder eventRecorder = new EventRecorder<>(); - - ConfigMap testConfigMap = testConfigMap(RESOURCE_VERSION); - ConfigMap testConfigMap2 = testConfigMap(RESOURCE_VERSION1); - - ResourceID id = ResourceID.fromResource(testConfigMap); - - @Test - void recordsEvents() { - - assertThat(eventRecorder.isRecordingFor(id)).isFalse(); - - eventRecorder.startEventRecording(id); - assertThat(eventRecorder.isRecordingFor(id)).isTrue(); - - eventRecorder.recordEvent(testConfigMap); - - eventRecorder.stopEventRecording(id); - assertThat(eventRecorder.isRecordingFor(id)).isFalse(); - } - - @Test - void getsLastRecorded() { - eventRecorder.startEventRecording(id); - - eventRecorder.recordEvent(testConfigMap); - eventRecorder.recordEvent(testConfigMap2); - - assertThat(eventRecorder.getLastEvent(id)).isEqualTo(testConfigMap2); - } - - @Test - void checksContainsWithResourceVersion() { - eventRecorder.startEventRecording(id); - - eventRecorder.recordEvent(testConfigMap); - eventRecorder.recordEvent(testConfigMap2); - - assertThat(eventRecorder.containsEventWithResourceVersion(id, RESOURCE_VERSION)).isTrue(); - assertThat(eventRecorder.containsEventWithResourceVersion(id, RESOURCE_VERSION1)).isTrue(); - assertThat(eventRecorder.containsEventWithResourceVersion(id, "xxx")).isFalse(); - } - - @Test - void checkLastItemVersion() { - eventRecorder.startEventRecording(id); - - eventRecorder.recordEvent(testConfigMap); - eventRecorder.recordEvent(testConfigMap2); - - assertThat(eventRecorder.containsEventWithVersionButItsNotLastOne(id, RESOURCE_VERSION)) - .isTrue(); - assertThat(eventRecorder.containsEventWithVersionButItsNotLastOne(id, RESOURCE_VERSION1)) - .isFalse(); - } - - ConfigMap testConfigMap(String resourceVersion) { - ConfigMap configMap = new ConfigMap(); - configMap.setMetadata(new ObjectMeta()); - configMap.getMetadata().setName("test"); - configMap.getMetadata().setResourceVersion(resourceVersion); - - return configMap; - } - -} diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java index 69e26f0b35..7acecc7099 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java @@ -8,6 +8,7 @@ import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.MockKubernetesClient; import io.javaoperatorsdk.operator.OperatorException; @@ -36,7 +37,6 @@ class InformerEventSourceTest { private static final String PREV_RESOURCE_VERSION = "0"; private static final String DEFAULT_RESOURCE_VERSION = "1"; - private static final String NEXT_RESOURCE_VERSION = "2"; private InformerEventSource informerEventSource; private final KubernetesClient clientMock = MockKubernetesClient.client(Deployment.class); @@ -78,126 +78,48 @@ void skipsEventPropagationIfResourceWithSameVersionInResourceCache() { } @Test - void propagateEventAndRemoveResourceFromTempCacheIfResourceVersionMismatch() { - Deployment cachedDeployment = testDeployment(); - cachedDeployment.getMetadata().setResourceVersion(PREV_RESOURCE_VERSION); - when(temporaryResourceCacheMock.getResourceFromCache(any())) - .thenReturn(Optional.of(cachedDeployment)); - - - informerEventSource.onUpdate(cachedDeployment, testDeployment()); + void skipsAddEventPropagationViaAnnotation() { + informerEventSource.onAdd(informerEventSource.addPreviousAnnotation(null, testDeployment())); - verify(eventHandlerMock, times(1)).handleEvent(any()); - verify(temporaryResourceCacheMock, times(1)).removeResourceFromCache(any()); + verify(eventHandlerMock, never()).handleEvent(any()); } @Test - void notPropagatesEventIfAfterUpdateReceivedJustTheRelatedEvent() { - var testDeployment = testDeployment(); - var prevTestDeployment = testDeployment(); - prevTestDeployment.getMetadata().setResourceVersion(PREV_RESOURCE_VERSION); - + void skipsUpdateEventPropagationViaAnnotation() { + informerEventSource.onUpdate(testDeployment(), + informerEventSource.addPreviousAnnotation("1", testDeployment())); - informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment), - testDeployment); - informerEventSource.onUpdate(prevTestDeployment, testDeployment); - informerEventSource.handleRecentResourceUpdate(ResourceID.fromResource(testDeployment), - testDeployment, prevTestDeployment); - - verify(eventHandlerMock, times(0)).handleEvent(any()); - verify(temporaryResourceCacheMock, times(0)).unconditionallyCacheResource(any()); + verify(eventHandlerMock, never()).handleEvent(any()); } - @Test - void notPropagatesEventIfAfterCreateReceivedJustTheRelatedEvent() { - var testDeployment = testDeployment(); - - informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment), - testDeployment); - informerEventSource.onAdd(testDeployment); - informerEventSource.handleRecentResourceCreate(ResourceID.fromResource(testDeployment), - testDeployment); - - verify(eventHandlerMock, times(0)).handleEvent(any()); - verify(temporaryResourceCacheMock, times(0)).unconditionallyCacheResource(any()); + void processEventPropagationWithoutAnnotation() { + informerEventSource.onUpdate(testDeployment(), testDeployment()); + + verify(eventHandlerMock, times(1)).handleEvent(any()); } @Test - void propagatesEventIfNewEventReceivedAfterTheCurrentTargetEvent() { - var testDeployment = testDeployment(); - var prevTestDeployment = testDeployment(); - prevTestDeployment.getMetadata().setResourceVersion(PREV_RESOURCE_VERSION); - var nextTestDeployment = testDeployment(); - nextTestDeployment.getMetadata().setResourceVersion(NEXT_RESOURCE_VERSION); - - informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment), - testDeployment); - informerEventSource.onUpdate(prevTestDeployment, testDeployment); - informerEventSource.onUpdate(testDeployment, nextTestDeployment); - informerEventSource.handleRecentResourceUpdate(ResourceID.fromResource(testDeployment), - testDeployment, prevTestDeployment); + void processEventPropagationWithIncorrectAnnotation() { + informerEventSource.onAdd(new DeploymentBuilder(testDeployment()).editMetadata() + .addToAnnotations(InformerEventSource.PREVIOUS_ANNOTATION_KEY, "invalid") + .endMetadata().build()); verify(eventHandlerMock, times(1)).handleEvent(any()); - verify(temporaryResourceCacheMock, times(0)).unconditionallyCacheResource(any()); } @Test - void notPropagatesEventIfMoreReceivedButTheLastIsTheUpdated() { - var testDeployment = testDeployment(); - var prevTestDeployment = testDeployment(); - prevTestDeployment.getMetadata().setResourceVersion(PREV_RESOURCE_VERSION); - var prevPrevTestDeployment = testDeployment(); - prevPrevTestDeployment.getMetadata().setResourceVersion("-1"); - - informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment), - testDeployment); - informerEventSource.onUpdate(prevPrevTestDeployment, prevTestDeployment); - informerEventSource.onUpdate(prevTestDeployment, testDeployment); - informerEventSource.handleRecentResourceUpdate(ResourceID.fromResource(testDeployment), - testDeployment, prevTestDeployment); - - verify(eventHandlerMock, times(0)).handleEvent(any()); - verify(temporaryResourceCacheMock, times(0)).unconditionallyCacheResource(any()); - } + void propagateEventAndRemoveResourceFromTempCacheIfResourceVersionMismatch() { + Deployment cachedDeployment = testDeployment(); + cachedDeployment.getMetadata().setResourceVersion(PREV_RESOURCE_VERSION); + when(temporaryResourceCacheMock.getResourceFromCache(any())) + .thenReturn(Optional.of(cachedDeployment)); - @Test - void putsResourceOnTempCacheIfNoEventRecorded() { - var testDeployment = testDeployment(); - var prevTestDeployment = testDeployment(); - prevTestDeployment.getMetadata().setResourceVersion(PREV_RESOURCE_VERSION); - - informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment), - testDeployment); - informerEventSource.handleRecentResourceUpdate(ResourceID.fromResource(testDeployment), - testDeployment, prevTestDeployment); - - verify(eventHandlerMock, times(0)).handleEvent(any()); - verify(temporaryResourceCacheMock, times(1)).unconditionallyCacheResource(any()); - } - @Test - void putsResourceOnTempCacheIfNoEventRecordedWithSameResourceVersion() { - var testDeployment = testDeployment(); - var prevTestDeployment = testDeployment(); - prevTestDeployment.getMetadata().setResourceVersion(PREV_RESOURCE_VERSION); - var prevPrevTestDeployment = testDeployment(); - prevPrevTestDeployment.getMetadata().setResourceVersion("-1"); - - informerEventSource - .prepareForCreateOrUpdateEventFiltering(ResourceID.fromResource(testDeployment), - testDeployment); - informerEventSource.onUpdate(prevPrevTestDeployment, prevTestDeployment); - informerEventSource.handleRecentResourceUpdate(ResourceID.fromResource(testDeployment), - testDeployment, prevTestDeployment); - - verify(eventHandlerMock, times(0)).handleEvent(any()); - verify(temporaryResourceCacheMock, times(1)).unconditionallyCacheResource(any()); + informerEventSource.onUpdate(cachedDeployment, testDeployment()); + + verify(eventHandlerMock, times(1)).handleEvent(any()); + verify(temporaryResourceCacheMock, times(1)).removeResourceFromCache(any()); } @Test diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCacheTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCacheTest.java index f848e26cec..4d5bdf0dfd 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCacheTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCacheTest.java @@ -30,7 +30,7 @@ void updateAddsTheResourceIntoCacheIfTheInformerHasThePreviousResourceVersion() prevTestResource.getMetadata().setResourceVersion("0"); when(informerEventSource.get(any())).thenReturn(Optional.of(prevTestResource)); - temporaryResourceCache.putUpdatedResource(testResource, "0"); + temporaryResourceCache.putResource(testResource, "0"); var cached = temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource)); assertThat(cached).isPresent(); @@ -43,7 +43,7 @@ void updateNotAddsTheResourceIntoCacheIfTheInformerHasOtherVersion() { informerCachedResource.getMetadata().setResourceVersion("x"); when(informerEventSource.get(any())).thenReturn(Optional.of(informerCachedResource)); - temporaryResourceCache.putUpdatedResource(testResource, "0"); + temporaryResourceCache.putResource(testResource, "0"); var cached = temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource)); assertThat(cached).isNotPresent(); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java index ef2ddfc4ec..6c38b2dd09 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java @@ -16,7 +16,7 @@ import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.junit.KubernetesClientAware; -import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; @@ -26,10 +26,35 @@ public class CreateUpdateEventFilterTestReconciler EventSourceInitializer, KubernetesClientAware { + private static final class DirectConfigMapDependentResource + extends + CRUDKubernetesDependentResource { + + private ConfigMap desired; + + private DirectConfigMapDependentResource(Class resourceType) { + super(resourceType); + } + + @Override + protected ConfigMap desired(CreateUpdateEventFilterTestCustomResource primary, + Context context) { + return desired; + } + + @Override + public void setEventSource( + io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource eventSource) { + super.setEventSource(eventSource); + } + } + public static final String CONFIG_MAP_TEST_DATA_KEY = "key"; private KubernetesClient client; private final AtomicInteger numberOfExecutions = new AtomicInteger(0); private InformerEventSource informerEventSource; + private DirectConfigMapDependentResource configMapDR = + new DirectConfigMapDependentResource(ConfigMap.class); @Override public UpdateControl reconcile( @@ -44,43 +69,14 @@ public UpdateControl reconcile( .withName(resource.getMetadata().getName()) .get(); if (configMap == null) { - var configMapToCreate = createConfigMap(resource); - final var resourceID = ResourceID.fromResource(configMapToCreate); - try { - informerEventSource.prepareForCreateOrUpdateEventFiltering(resourceID, configMapToCreate); - configMap = - client - .configMaps() - .inNamespace(resource.getMetadata().getNamespace()) - .resource(configMapToCreate) - .create(); - informerEventSource.handleRecentResourceCreate(resourceID, configMap); - } catch (RuntimeException e) { - informerEventSource - .cleanupOnCreateOrUpdateEventFiltering(resourceID); - throw e; - } + configMapDR.desired = createConfigMap(resource); + configMapDR.reconcile(resource, context); } else { - ResourceID resourceID = ResourceID.fromResource(configMap); if (!Objects.equals( configMap.getData().get(CONFIG_MAP_TEST_DATA_KEY), resource.getSpec().getValue())) { configMap.getData().put(CONFIG_MAP_TEST_DATA_KEY, resource.getSpec().getValue()); - try { - informerEventSource - .prepareForCreateOrUpdateEventFiltering(resourceID, configMap); - var newConfigMap = - client - .configMaps() - .inNamespace(resource.getMetadata().getNamespace()) - .resource(configMap) - .replace(); - informerEventSource.handleRecentResourceUpdate(resourceID, - newConfigMap, configMap); - } catch (RuntimeException e) { - informerEventSource - .cleanupOnCreateOrUpdateEventFiltering(resourceID); - throw e; - } + configMapDR.desired = configMap; + configMapDR.reconcile(resource, context); } } return UpdateControl.noUpdate(); @@ -109,6 +105,10 @@ public Map prepareEventSources( .build(); informerEventSource = new InformerEventSource<>(informerConfiguration, client); + + this.configMapDR.setKubernetesClient(context.getClient()); + this.configMapDR.setEventSource(informerEventSource); + return EventSourceInitializer.nameEventSources(informerEventSource); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/primaryindexer/DependentPrimaryIndexerTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/primaryindexer/DependentPrimaryIndexerTestReconciler.java index 6d79d4ee56..e123500c42 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/primaryindexer/DependentPrimaryIndexerTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/primaryindexer/DependentPrimaryIndexerTestReconciler.java @@ -12,8 +12,8 @@ import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.IndexerResourceCache; -import io.javaoperatorsdk.operator.processing.event.source.ResourceEventSource; import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; +import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; @ControllerConfiguration(dependents = @Dependent( type = DependentPrimaryIndexerTestReconciler.ReadOnlyConfigMapDependent.class)) @@ -39,7 +39,7 @@ public Set toPrimaryResourceIDs(ConfigMap dependentResource) { } @Override - public Optional> eventSource( + public Optional> eventSource( EventSourceContext context) { cache = context.getPrimaryCache(); cache.addIndexer(CONFIG_MAP_RELATION_INDEXER, indexer); From 182b98c647097fa71aefddf195fca8130084dbc3 Mon Sep 17 00:00:00 2001 From: Steven Hawkins Date: Mon, 28 Aug 2023 04:22:28 -0400 Subject: [PATCH 035/644] generalization of the update matcher (#2014) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: create resource only if not exists (#2001) * feat: leader election callbacks (#2015) * discriminator improvements (#2013) * generalization of the update matcher * consolidating the diffs also adding a test that removes a field not present in the desired --------- Co-authored-by: Attila Mészáros Signed-off-by: csviri Signed-off-by: Attila Mészáros --- .../GenericKubernetesResourceMatcher.java | 111 ++++-------------- ...sterRoleBindingResourceUpdaterMatcher.java | 23 ---- .../ClusterRoleResourceUpdaterMatcher.java | 22 ---- .../ConfigMapResourceUpdaterMatcher.java | 24 ---- .../EndpointSliceResourceUpdateMatcher.java | 25 ---- .../EndpointsResourceUpdaterMatcher.java | 20 ---- .../GenericResourceUpdaterMatcher.java | 49 +++----- .../RoleBindingResourceUpdaterMatcher.java | 23 ---- .../RoleResourceUpdaterMatcher.java | 19 --- .../SecretResourceUpdaterMatcher.java | 25 ---- .../ServiceAccountResourceUpdaterMatcher.java | 25 ---- .../GenericKubernetesResourceMatcherTest.java | 10 ++ .../GenericResourceUpdaterMatcherTest.java | 20 +++- 13 files changed, 70 insertions(+), 326 deletions(-) delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ClusterRoleBindingResourceUpdaterMatcher.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ClusterRoleResourceUpdaterMatcher.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ConfigMapResourceUpdaterMatcher.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/EndpointSliceResourceUpdateMatcher.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/EndpointsResourceUpdaterMatcher.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/RoleBindingResourceUpdaterMatcher.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/RoleResourceUpdaterMatcher.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/SecretResourceUpdaterMatcher.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ServiceAccountResourceUpdaterMatcher.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java index 3109880063..98198bf39a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java @@ -1,11 +1,8 @@ package io.javaoperatorsdk.operator.processing.dependent.kubernetes; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Objects; -import java.util.Optional; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.HasMetadata; @@ -20,8 +17,10 @@ public class GenericKubernetesResourceMatcher { private static final String SPEC = "/spec"; + private static final String METADATA = "/metadata"; private static final String ADD = "add"; private static final String OP = "op"; + private static final List IGNORED_FIELDS = List.of("/apiVersion", "/kind", "/status"); public static final String METADATA_LABELS = "/metadata/labels"; public static final String METADATA_ANNOTATIONS = "/metadata/annotations"; @@ -184,76 +183,39 @@ public static Result match(R d "Equality should be false in case of ignore list provided"); } - if (considerMetadata) { - Optional> res = - matchMetadata(desired, actualResource, labelsAndAnnotationsEquality, context); - if (res.isPresent()) { - return res.orElseThrow(); - } - } - - final var matched = matchSpec(actualResource, desired, specEquality, context, ignoreList); - return Result.computed(matched, desired); - } - - private static boolean matchSpec(R actual, R desired, boolean equality, - Context context, List ignoreList) { final var kubernetesSerialization = context.getClient().getKubernetesSerialization(); var desiredNode = kubernetesSerialization.convertValue(desired, JsonNode.class); - var actualNode = kubernetesSerialization.convertValue(actual, JsonNode.class); + var actualNode = kubernetesSerialization.convertValue(actualResource, JsonNode.class); var wholeDiffJsonPatch = JsonDiff.asJson(desiredNode, actualNode); - // reflection will be replaced by this: - // https://github.com/fabric8io/kubernetes-client/issues/3816 - var specDiffJsonPatch = getDiffsImpactingPathsWithPrefixes(wholeDiffJsonPatch, SPEC); - // In case of equality is set to true, no diffs are allowed, so we return early if diffs exist - // On contrary (if equality is false), "add" is allowed for cases when for some - // resources Kubernetes fills-in values into spec. - if (equality && !specDiffJsonPatch.isEmpty()) { - return false; - } - if (!equality && !ignoreList.isEmpty()) { - return allDiffsOnIgnoreList(specDiffJsonPatch, ignoreList); - } else { - return allDiffsAreAddOps(specDiffJsonPatch); + boolean matched = true; + for (int i = 0; i < wholeDiffJsonPatch.size() && matched; i++) { + var node = wholeDiffJsonPatch.get(i); + if (nodeIsChildOf(node, List.of(SPEC))) { + matched = match(specEquality, node, ignoreList); + } else if (nodeIsChildOf(node, List.of(METADATA))) { + // conditionally consider labels and annotations + if (considerMetadata + && nodeIsChildOf(node, List.of(METADATA_LABELS, METADATA_ANNOTATIONS))) { + matched = match(labelsAndAnnotationsEquality, node, Collections.emptyList()); + } + } else if (!nodeIsChildOf(node, IGNORED_FIELDS)) { + matched = match(true, node, ignoreList); + } } + + return Result.computed(matched, desired); } - private static boolean allDiffsOnIgnoreList(List metadataJSonDiffs, - List ignoreList) { - if (metadataJSonDiffs.isEmpty()) { + private static boolean match(boolean equality, JsonNode diff, + final List ignoreList) { + if (equality) { return false; } - return metadataJSonDiffs.stream().allMatch(n -> nodeIsChildOf(n, ignoreList)); - } - - private static Optional> matchMetadata( - R desired, - R actualResource, - boolean labelsAndAnnotationsEquality, Context

context) { - if (labelsAndAnnotationsEquality) { - final var desiredMetadata = desired.getMetadata(); - final var actualMetadata = actualResource.getMetadata(); - - final var matched = - Objects.equals(desiredMetadata.getAnnotations(), actualMetadata.getAnnotations()) && - Objects.equals(desiredMetadata.getLabels(), actualMetadata.getLabels()); - if (!matched) { - return Optional.of(Result.computed(false, desired)); - } - } else { - final var objectMapper = context.getClient().getKubernetesSerialization(); - var desiredNode = objectMapper.convertValue(desired, JsonNode.class); - var actualNode = objectMapper.convertValue(actualResource, JsonNode.class); - var wholeDiffJsonPatch = JsonDiff.asJson(desiredNode, actualNode); - var metadataJSonDiffs = getDiffsImpactingPathsWithPrefixes(wholeDiffJsonPatch, - METADATA_LABELS, - METADATA_ANNOTATIONS); - if (!allDiffsAreAddOps(metadataJSonDiffs)) { - return Optional.of(Result.computed(false, desired)); - } + if (!ignoreList.isEmpty()) { + return nodeIsChildOf(diff, ignoreList); } - return Optional.empty(); + return ADD.equals(diff.get(OP).asText()); } static boolean nodeIsChildOf(JsonNode n, List prefixes) { @@ -265,29 +227,6 @@ static String getPath(JsonNode n) { return n.get(PATH).asText(); } - static boolean allDiffsAreAddOps(List metadataJSonDiffs) { - if (metadataJSonDiffs.isEmpty()) { - return true; - } - return metadataJSonDiffs.stream().allMatch(n -> ADD.equals(n.get(OP).asText())); - } - - public static List getDiffsImpactingPathsWithPrefixes(JsonNode diffJsonPatch, - String... prefixes) { - if (prefixes != null && prefixes.length > 0) { - var res = new ArrayList(); - var prefixList = Arrays.asList(prefixes); - for (int i = 0; i < diffJsonPatch.size(); i++) { - var node = diffJsonPatch.get(i); - if (nodeIsChildOf(node, prefixList)) { - res.add(node); - } - } - return res; - } - return Collections.emptyList(); - } - @Deprecated(forRemoval = true) public static Result match( KubernetesDependentResource dependentResource, R actualResource, P primary, diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ClusterRoleBindingResourceUpdaterMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ClusterRoleBindingResourceUpdaterMatcher.java deleted file mode 100644 index f6f6d1ef54..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ClusterRoleBindingResourceUpdaterMatcher.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher; - -import java.util.Objects; - -import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding; -import io.javaoperatorsdk.operator.api.reconciler.Context; - -public class ClusterRoleBindingResourceUpdaterMatcher - extends GenericResourceUpdaterMatcher { - - @Override - protected void updateClonedActual(ClusterRoleBinding actual, ClusterRoleBinding desired) { - actual.setRoleRef(desired.getRoleRef()); - actual.setSubjects(desired.getSubjects()); - } - - @Override - public boolean matches(ClusterRoleBinding actual, ClusterRoleBinding desired, - Context context) { - return Objects.equals(actual.getRoleRef(), desired.getRoleRef()) && - Objects.equals(actual.getSubjects(), desired.getSubjects()); - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ClusterRoleResourceUpdaterMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ClusterRoleResourceUpdaterMatcher.java deleted file mode 100644 index da7997c040..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ClusterRoleResourceUpdaterMatcher.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher; - -import java.util.Objects; - -import io.fabric8.kubernetes.api.model.rbac.ClusterRole; -import io.javaoperatorsdk.operator.api.reconciler.Context; - -public class ClusterRoleResourceUpdaterMatcher - extends GenericResourceUpdaterMatcher { - - @Override - protected void updateClonedActual(ClusterRole actual, ClusterRole desired) { - actual.setAggregationRule(desired.getAggregationRule()); - actual.setRules(desired.getRules()); - } - - @Override - public boolean matches(ClusterRole actual, ClusterRole desired, Context context) { - return Objects.equals(actual.getRules(), desired.getRules()) && - Objects.equals(actual.getAggregationRule(), desired.getAggregationRule()); - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ConfigMapResourceUpdaterMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ConfigMapResourceUpdaterMatcher.java deleted file mode 100644 index 7f89d45ff5..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ConfigMapResourceUpdaterMatcher.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher; - -import java.util.Objects; - -import io.fabric8.kubernetes.api.model.ConfigMap; -import io.javaoperatorsdk.operator.api.reconciler.Context; - -public class ConfigMapResourceUpdaterMatcher - extends GenericResourceUpdaterMatcher { - - @Override - protected void updateClonedActual(ConfigMap actual, ConfigMap desired) { - actual.setData(desired.getData()); - actual.setBinaryData((desired.getBinaryData())); - actual.setImmutable(desired.getImmutable()); - } - - @Override - public boolean matches(ConfigMap actual, ConfigMap desired, Context context) { - return Objects.equals(actual.getImmutable(), desired.getImmutable()) && - Objects.equals(actual.getData(), desired.getData()) && - Objects.equals(actual.getBinaryData(), desired.getBinaryData()); - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/EndpointSliceResourceUpdateMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/EndpointSliceResourceUpdateMatcher.java deleted file mode 100644 index dc83c86dbf..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/EndpointSliceResourceUpdateMatcher.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher; - -import java.util.Objects; - -import io.fabric8.kubernetes.api.model.discovery.v1.EndpointSlice; -import io.javaoperatorsdk.operator.api.reconciler.Context; - -public class EndpointSliceResourceUpdateMatcher - extends GenericResourceUpdaterMatcher { - - @Override - protected void updateClonedActual(EndpointSlice actual, EndpointSlice desired) { - actual.setEndpoints(desired.getEndpoints()); - actual.setAddressType(desired.getAddressType()); - actual.setPorts(desired.getPorts()); - } - - @Override - public boolean matches(EndpointSlice actual, EndpointSlice desired, Context context) { - return Objects.equals(actual.getEndpoints(), desired.getEndpoints()) && - Objects.equals(actual.getAddressType(), desired.getAddressType()) && - Objects.equals(actual.getPorts(), desired.getPorts()); - } - -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/EndpointsResourceUpdaterMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/EndpointsResourceUpdaterMatcher.java deleted file mode 100644 index 3dcfabde28..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/EndpointsResourceUpdaterMatcher.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher; - -import java.util.Objects; - -import io.fabric8.kubernetes.api.model.Endpoints; -import io.javaoperatorsdk.operator.api.reconciler.Context; - -public class EndpointsResourceUpdaterMatcher extends GenericResourceUpdaterMatcher { - - @Override - protected void updateClonedActual(Endpoints actual, Endpoints desired) { - actual.setSubsets(desired.getSubsets()); - } - - @Override - public boolean matches(Endpoints actual, Endpoints desired, Context context) { - return Objects.equals(actual.getSubsets(), desired.getSubsets()); - } - -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/GenericResourceUpdaterMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/GenericResourceUpdaterMatcher.java index cd9fbe2b16..2a5bae03b9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/GenericResourceUpdaterMatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/GenericResourceUpdaterMatcher.java @@ -2,13 +2,8 @@ import java.util.Map; -import io.fabric8.kubernetes.api.model.*; -import io.fabric8.kubernetes.api.model.discovery.v1.EndpointSlice; -import io.fabric8.kubernetes.api.model.rbac.ClusterRole; -import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding; -import io.fabric8.kubernetes.api.model.rbac.Role; -import io.fabric8.kubernetes.api.model.rbac.RoleBinding; -import io.javaoperatorsdk.operator.ReconcilerUtils; +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.client.utils.KubernetesSerialization; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.GenericKubernetesResourceMatcher; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.ResourceUpdaterMatcher; @@ -16,34 +11,31 @@ public class GenericResourceUpdaterMatcher implements ResourceUpdaterMatcher { + private static final String METADATA = "metadata"; private static final ResourceUpdaterMatcher INSTANCE = new GenericResourceUpdaterMatcher<>(); - @SuppressWarnings("rawtypes") - private static final Map processors = Map.of( - Secret.class, new SecretResourceUpdaterMatcher(), - ConfigMap.class, new ConfigMapResourceUpdaterMatcher(), - ServiceAccount.class, new ServiceAccountResourceUpdaterMatcher(), - Role.class, new RoleResourceUpdaterMatcher(), - ClusterRole.class, new ClusterRoleResourceUpdaterMatcher(), - RoleBinding.class, new RoleBindingResourceUpdaterMatcher(), - ClusterRoleBinding.class, new ClusterRoleBindingResourceUpdaterMatcher(), - Endpoints.class, new EndpointsResourceUpdaterMatcher(), - EndpointSlice.class, new EndpointSliceResourceUpdateMatcher()); - protected GenericResourceUpdaterMatcher() {} @SuppressWarnings("unchecked") public static ResourceUpdaterMatcher updaterMatcherFor( Class resourceType) { - final var processor = processors.get(resourceType); - return processor != null ? processor : (ResourceUpdaterMatcher) INSTANCE; + return (ResourceUpdaterMatcher) INSTANCE; } + @SuppressWarnings("unchecked") + @Override public R updateResource(R actual, R desired, Context context) { - var clonedActual = context.getControllerConfiguration().getConfigurationService() - .getResourceCloner().clone(actual); + KubernetesSerialization kubernetesSerialization = + context.getClient().getKubernetesSerialization(); + Map actualMap = kubernetesSerialization.convertValue(actual, Map.class); + Map desiredMap = kubernetesSerialization.convertValue(desired, Map.class); + // replace all top level fields from actual with desired, but merge metadata separately + var metadata = actualMap.remove(METADATA); + actualMap.replaceAll((k, v) -> desiredMap.get(k)); + actualMap.putAll(desiredMap); + actualMap.put(METADATA, metadata); + var clonedActual = (R) kubernetesSerialization.convertValue(actualMap, desired.getClass()); updateLabelsAndAnnotation(clonedActual, desired); - updateClonedActual(clonedActual, desired); return clonedActual; } @@ -53,15 +45,6 @@ public boolean matches(R actual, R desired, Context context) { false, false, context).matched(); } - protected void updateClonedActual(R actual, R desired) { - updateSpec(actual, desired); - } - - public static void updateSpec(K actual, K desired) { - var desiredSpec = ReconcilerUtils.getSpec(desired); - ReconcilerUtils.setSpec(actual, desiredSpec); - } - public static void updateLabelsAndAnnotation(K actual, K desired) { actual.getMetadata().getLabels().putAll(desired.getMetadata().getLabels()); actual.getMetadata().getAnnotations().putAll(desired.getMetadata().getAnnotations()); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/RoleBindingResourceUpdaterMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/RoleBindingResourceUpdaterMatcher.java deleted file mode 100644 index c6a87cdae3..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/RoleBindingResourceUpdaterMatcher.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher; - -import java.util.Objects; - -import io.fabric8.kubernetes.api.model.rbac.RoleBinding; -import io.javaoperatorsdk.operator.api.reconciler.Context; - -public class RoleBindingResourceUpdaterMatcher - extends GenericResourceUpdaterMatcher { - - @Override - protected void updateClonedActual(RoleBinding actual, RoleBinding desired) { - actual.setRoleRef(desired.getRoleRef()); - actual.setSubjects(desired.getSubjects()); - } - - @Override - public boolean matches(RoleBinding actual, RoleBinding desired, - Context context) { - return Objects.equals(actual.getRoleRef(), desired.getRoleRef()) && - Objects.equals(actual.getSubjects(), desired.getSubjects()); - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/RoleResourceUpdaterMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/RoleResourceUpdaterMatcher.java deleted file mode 100644 index f02d946db8..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/RoleResourceUpdaterMatcher.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher; - -import java.util.Objects; - -import io.fabric8.kubernetes.api.model.rbac.Role; -import io.javaoperatorsdk.operator.api.reconciler.Context; - -public class RoleResourceUpdaterMatcher extends GenericResourceUpdaterMatcher { - - @Override - protected void updateClonedActual(Role actual, Role desired) { - actual.setRules(desired.getRules()); - } - - @Override - public boolean matches(Role actual, Role desired, Context context) { - return Objects.equals(actual.getRules(), desired.getRules()); - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/SecretResourceUpdaterMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/SecretResourceUpdaterMatcher.java deleted file mode 100644 index 14e8696704..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/SecretResourceUpdaterMatcher.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher; - -import java.util.Objects; - -import io.fabric8.kubernetes.api.model.Secret; -import io.javaoperatorsdk.operator.api.reconciler.Context; - -public class SecretResourceUpdaterMatcher extends GenericResourceUpdaterMatcher { - - @Override - protected void updateClonedActual(Secret actual, Secret desired) { - actual.setData(desired.getData()); - actual.setStringData(desired.getStringData()); - actual.setImmutable(desired.getImmutable()); - actual.setType(desired.getType()); - } - - @Override - public boolean matches(Secret actual, Secret desired, Context context) { - return Objects.equals(actual.getImmutable(), desired.getImmutable()) && - Objects.equals(actual.getType(), desired.getType()) && - Objects.equals(actual.getData(), desired.getData()) && - Objects.equals(actual.getStringData(), desired.getStringData()); - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ServiceAccountResourceUpdaterMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ServiceAccountResourceUpdaterMatcher.java deleted file mode 100644 index f3d625c778..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/ServiceAccountResourceUpdaterMatcher.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher; - -import java.util.Objects; - -import io.fabric8.kubernetes.api.model.ServiceAccount; -import io.javaoperatorsdk.operator.api.reconciler.Context; - -public class ServiceAccountResourceUpdaterMatcher - extends GenericResourceUpdaterMatcher { - - @Override - protected void updateClonedActual(ServiceAccount actual, ServiceAccount desired) { - actual.setAutomountServiceAccountToken(desired.getAutomountServiceAccountToken()); - actual.setImagePullSecrets(desired.getImagePullSecrets()); - actual.setSecrets(desired.getSecrets()); - } - - @Override - public boolean matches(ServiceAccount actual, ServiceAccount desired, Context context) { - return Objects.equals(actual.getAutomountServiceAccountToken(), - desired.getAutomountServiceAccountToken()) && - Objects.equals(actual.getImagePullSecrets(), desired.getImagePullSecrets()) && - Objects.equals(actual.getSecrets(), desired.getSecrets()); - } -} diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java index 41bafe00e4..b1ff214f3b 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java @@ -10,6 +10,7 @@ import io.fabric8.kubernetes.api.model.ServiceAccountBuilder; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; +import io.fabric8.kubernetes.api.model.apps.DeploymentStatusBuilder; import io.javaoperatorsdk.operator.MockKubernetesClient; import io.javaoperatorsdk.operator.ReconcilerUtils; import io.javaoperatorsdk.operator.api.reconciler.Context; @@ -79,6 +80,15 @@ void doesNotMatchChangedValues() { .isFalse(); } + @Test + void ignoreStatus() { + actual = createDeployment(); + actual.setStatus(new DeploymentStatusBuilder().withReadyReplicas(1).build()); + assertThat(matcher.match(actual, null, context).matched()) + .withFailMessage("Should ignore status in actual") + .isTrue(); + } + @Test void doesNotMatchChangedValuesWhenNoIgnoredPathsAreProvided() { actual = createDeployment(); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericResourceUpdaterMatcherTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericResourceUpdaterMatcherTest.java index c1d9b4a5a5..44f3fb51ea 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericResourceUpdaterMatcherTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericResourceUpdaterMatcherTest.java @@ -2,6 +2,7 @@ import java.util.HashMap; import java.util.List; +import java.util.Map; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -33,7 +34,7 @@ static void setUp() { final var client = MockKubernetesClient.client(HasMetadata.class); when(configService.getKubernetesClient()).thenReturn(client); when(configService.getResourceCloner()).thenCallRealMethod(); - + when(context.getClient()).thenReturn(client); when(context.getControllerConfiguration()).thenReturn(controllerConfiguration); } @@ -99,6 +100,23 @@ void checkSecret() { assertThat(secret.getData()).containsOnlyKeys("foo"); } + @Test + void checkSeviceAccount() { + var processor = GenericResourceUpdaterMatcher.updaterMatcherFor(ServiceAccount.class); + var desired = new ServiceAccountBuilder() + .withMetadata(new ObjectMetaBuilder().addToLabels("new", "label").build()) + .build(); + var actual = new ServiceAccountBuilder() + .withMetadata(new ObjectMetaBuilder().addToLabels("a", "label").build()) + .withImagePullSecrets(new LocalObjectReferenceBuilder().withName("secret").build()) + .build(); + + final var serviceAccount = processor.updateResource(actual, desired, context); + assertThat(serviceAccount.getMetadata().getLabels()) + .isEqualTo(Map.of("a", "label", "new", "label")); + assertThat(serviceAccount.getImagePullSecrets()).isNullOrEmpty(); + } + Deployment createDeployment() { return ReconcilerUtils.loadYaml( Deployment.class, GenericResourceUpdaterMatcherTest.class, "nginx-deployment.yaml"); From 16871cfaef972eb8e7da267c1325abb7f392ead2 Mon Sep 17 00:00:00 2001 From: csviri Date: Mon, 4 Sep 2023 10:22:23 +0200 Subject: [PATCH 036/644] fix: rebase issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: csviri Signed-off-by: Attila Mészáros --- .../processing/event/source/informer/InformerEventSource.java | 1 - 1 file changed, 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index 3b407b42ea..d154ad201b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -73,7 +73,6 @@ public class InformerEventSource private static final Logger log = LoggerFactory.getLogger(InformerEventSource.class); - private final InformerConfiguration configuration; // we need direct control for the indexer to propagate the just update resource also to the index private final PrimaryToSecondaryIndex primaryToSecondaryIndex; private final PrimaryToSecondaryMapper

primaryToSecondaryMapper; From 6b9248f5af39b8795d18155fb8d2d7dfbcb3508f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Fri, 8 Sep 2023 10:51:08 +0200 Subject: [PATCH 037/644] feat: configurable SSA per Dependent Resource (#2045) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../kubernetes/BooleanWithUndefined.java | 19 +++++++++++++++++++ .../kubernetes/KubernetesDependent.java | 14 +++++++++++++- .../KubernetesDependentConverter.java | 4 +++- .../KubernetesDependentResource.java | 7 +++++-- .../KubernetesDependentResourceConfig.java | 10 +++++++++- 5 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/BooleanWithUndefined.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/BooleanWithUndefined.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/BooleanWithUndefined.java new file mode 100644 index 0000000000..fcf7553a4a --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/BooleanWithUndefined.java @@ -0,0 +1,19 @@ +package io.javaoperatorsdk.operator.processing.dependent.kubernetes; + +/** + * A replacement for {@link Boolean}, which can't be used in annotations. + */ +public enum BooleanWithUndefined { + TRUE, FALSE, UNDEFINED; + + Boolean asBoolean() { + switch (this) { + case TRUE: + return Boolean.TRUE; + case FALSE: + return Boolean.FALSE; + default: + return null; + } + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java index c3f7be408a..eb4c9cf9b0 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java @@ -25,7 +25,7 @@ * namespace is specified then the controller will monitor the namespaces configured for the * controller. * - * @return the list of namespaces this controller monitors + * @return the array of namespaces this controller monitors */ String[] namespaces() default {Constants.SAME_AS_CONTROLLER}; @@ -76,4 +76,16 @@ * Creates the resource only if did not exist before, this applies only if SSA is used. */ boolean createResourceOnlyIfNotExistingWithSSA() default KubernetesDependentResourceConfig.DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA; + + /** + * Determines whether to use SSA (Server-Side Apply) for this dependent. If SSA is used, the + * dependent resource will only be created if it did not exist before. Default value is + * {@link BooleanWithUndefined#UNDEFINED}, which specifies that the behavior with respect to SSA + * is inherited from the global configuration. + * + * @return {@code true} if SSA is enabled, {@code false} if SSA is disabled, + * {@link BooleanWithUndefined#UNDEFINED} if the SSA behavior should be inherited from the + * global configuration + */ + BooleanWithUndefined useSSA() default BooleanWithUndefined.UNDEFINED; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java index 6ab07a9462..7a434aecf1 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentConverter.java @@ -34,6 +34,7 @@ public KubernetesDependentResourceConfig configFrom(KubernetesDependent confi OnDeleteFilter onDeleteFilter = null; GenericFilter genericFilter = null; ResourceDiscriminator resourceDiscriminator = null; + Boolean useSSA = null; if (configAnnotation != null) { if (!Arrays.equals(KubernetesDependent.DEFAULT_NAMESPACES, configAnnotation.namespaces())) { namespaces = Set.of(configAnnotation.namespaces()); @@ -58,10 +59,11 @@ public KubernetesDependentResourceConfig configFrom(KubernetesDependent confi context); createResourceOnlyIfNotExistingWithSSA = configAnnotation.createResourceOnlyIfNotExistingWithSSA(); + useSSA = configAnnotation.useSSA().asBoolean(); } return new KubernetesDependentResourceConfig(namespaces, labelSelector, configuredNS, createResourceOnlyIfNotExistingWithSSA, - resourceDiscriminator, onAddFilter, onUpdateFilter, onDeleteFilter, genericFilter); + resourceDiscriminator, useSSA, onAddFilter, onUpdateFilter, onDeleteFilter, genericFilter); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 5fedd0899d..7fadcc6940 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -190,8 +190,10 @@ protected void addMetadata(boolean forMatch, R actualResource, final R target, P } private boolean useSSA(Context

context) { - return context.getControllerConfiguration().getConfigurationService() - .ssaBasedCreateUpdateMatchForDependentResources(); + Optional useSSAConfig = + configuration().flatMap(KubernetesDependentResourceConfig::useSSA); + return useSSAConfig.orElse(context.getControllerConfiguration().getConfigurationService() + .ssaBasedCreateUpdateMatchForDependentResources()); } @Override @@ -206,6 +208,7 @@ public void deleteTargetResource(P primary, R resource, String key, Context

c client.resource(resource).delete(); } + @SuppressWarnings("unused") protected Resource prepare(R desired, P primary, String actionName) { log.debug("{} target resource with type: {}, with id: {}", actionName, diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java index c28a1ef1db..ac291f5202 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java @@ -1,5 +1,6 @@ package io.javaoperatorsdk.operator.processing.dependent.kubernetes; +import java.util.Optional; import java.util.Set; import io.javaoperatorsdk.operator.api.reconciler.Constants; @@ -20,6 +21,7 @@ public class KubernetesDependentResourceConfig { private boolean namespacesWereConfigured; private boolean createResourceOnlyIfNotExistingWithSSA; private ResourceDiscriminator resourceDiscriminator; + private Boolean useSSA; private final OnAddFilter onAddFilter; private final OnUpdateFilter onUpdateFilter; @@ -37,6 +39,7 @@ public KubernetesDependentResourceConfig(Set namespaces, boolean configuredNS, boolean createResourceOnlyIfNotExistingWithSSA, ResourceDiscriminator resourceDiscriminator, + Boolean useSSA, OnAddFilter onAddFilter, OnUpdateFilter onUpdateFilter, OnDeleteFilter onDeleteFilter, GenericFilter genericFilter) { @@ -49,6 +52,7 @@ public KubernetesDependentResourceConfig(Set namespaces, this.onDeleteFilter = onDeleteFilter; this.genericFilter = genericFilter; this.resourceDiscriminator = resourceDiscriminator; + this.useSSA = useSSA; } // use builder instead @@ -56,7 +60,7 @@ public KubernetesDependentResourceConfig(Set namespaces, public KubernetesDependentResourceConfig(Set namespaces, String labelSelector) { this(namespaces, labelSelector, true, DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA, null, null, null, - null, null); + null, null, null); } // use builder instead @@ -110,4 +114,8 @@ protected void setNamespaces(Set namespaces) { this.namespaces = namespaces; } } + + public Optional useSSA() { + return Optional.ofNullable(useSSA); + } } From e7c6082b86ac326ed8e9d984d3df2d4d6060d359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 12 Sep 2023 12:16:09 +0200 Subject: [PATCH 038/644] feat: builder for kubernetes dependent configuration (#2054) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../KubernetesDependentResourceConfig.java | 13 +++++++------ .../KubernetesDependentResourceConfigBuilder.java | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java index ac291f5202..9b3838831d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java @@ -18,10 +18,10 @@ public class KubernetesDependentResourceConfig { private Set namespaces; private String labelSelector; - private boolean namespacesWereConfigured; - private boolean createResourceOnlyIfNotExistingWithSSA; - private ResourceDiscriminator resourceDiscriminator; - private Boolean useSSA; + private final boolean namespacesWereConfigured; + private final boolean createResourceOnlyIfNotExistingWithSSA; + private final ResourceDiscriminator resourceDiscriminator; + private final Boolean useSSA; private final OnAddFilter onAddFilter; private final OnUpdateFilter onUpdateFilter; @@ -29,8 +29,9 @@ public class KubernetesDependentResourceConfig { private final GenericFilter genericFilter; public KubernetesDependentResourceConfig() { - this(Constants.SAME_AS_CONTROLLER_NAMESPACES_SET, NO_VALUE_SET, true,false, - null, null, + this(Constants.SAME_AS_CONTROLLER_NAMESPACES_SET, NO_VALUE_SET, true, + DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA, + null, null, null, null, null, null); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java index a408d78915..a9834753cd 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java @@ -13,7 +13,9 @@ public final class KubernetesDependentResourceConfigBuilder { private Set namespaces = Constants.SAME_AS_CONTROLLER_NAMESPACES_SET; private String labelSelector; + private boolean createResourceOnlyIfNotExistingWithSSA; private ResourceDiscriminator resourceDiscriminator; + private Boolean useSSA; private OnAddFilter onAddFilter; private OnUpdateFilter onUpdateFilter; private OnDeleteFilter onDeleteFilter; @@ -35,12 +37,23 @@ public KubernetesDependentResourceConfigBuilder withLabelSelector(String labe return this; } + public KubernetesDependentResourceConfigBuilder withCreateResourceOnlyIfNotExistingWithSSA( + boolean createResourceOnlyIfNotExistingWithSSA) { + this.createResourceOnlyIfNotExistingWithSSA = createResourceOnlyIfNotExistingWithSSA; + return this; + } + public KubernetesDependentResourceConfigBuilder withResourceDiscriminator( ResourceDiscriminator resourceDiscriminator) { this.resourceDiscriminator = resourceDiscriminator; return this; } + public KubernetesDependentResourceConfigBuilder withUseSSA(Boolean useSSA) { + this.useSSA = useSSA; + return this; + } + public KubernetesDependentResourceConfigBuilder withOnAddFilter(OnAddFilter onAddFilter) { this.onAddFilter = onAddFilter; return this; @@ -66,7 +79,7 @@ public KubernetesDependentResourceConfigBuilder withGenericFilter( public KubernetesDependentResourceConfig build() { return new KubernetesDependentResourceConfig<>(namespaces, labelSelector, false, - resourceDiscriminator, onAddFilter, + createResourceOnlyIfNotExistingWithSSA, resourceDiscriminator, useSSA, onAddFilter, onUpdateFilter, onDeleteFilter, genericFilter); } } From 50f844b0fca8875859c906e00d1b5aa0266b3303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 12 Sep 2023 17:00:28 +0200 Subject: [PATCH 039/644] feat: sanitization of resources for matching (#2042) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../api/config/ConfigurationService.java | 21 ++++++- .../config/ConfigurationServiceOverrider.java | 14 +++++ .../kubernetes/DesiredResourceSanitizer.java | 47 +++++++++++++++ .../KubernetesDependentResource.java | 30 +++++++--- ...ernetesDependentResourceConfigBuilder.java | 3 +- ...BasedGenericKubernetesResourceMatcher.java | 11 +--- .../operator/DependentSSAMigrationIT.java | 8 +-- .../StatefulSetDesiredSanitizerIT.java | 57 +++++++++++++++++++ .../dependentssa/DependentSSAReconciler.java | 45 ++++++++++++++- .../dependentssa/SSAConfigMapDependent.java | 4 +- .../ServiceDependentResource.java | 4 +- .../ServiceDependentResource.java | 8 +-- ...efulSetDesiredSanitizerCustomResource.java | 14 +++++ ...lSetDesiredSanitizerDependentResource.java | 43 ++++++++++++++ ...StatefulSetDesiredSanitizerReconciler.java | 20 +++++++ .../StatefulSetDesiredSanitizerSpec.java | 15 +++++ .../statefulset.yaml | 35 ++++++++++++ .../ConfigMapDependentResource.java | 4 +- 18 files changed, 346 insertions(+), 37 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/StatefulSetDesiredSanitizerIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerDependentResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerSpec.java create mode 100644 operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/statefulset.yaml diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java index 2422f6ef74..86efb457c5 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java @@ -9,7 +9,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.ConfigBuilder; import io.fabric8.kubernetes.client.CustomResource; @@ -19,6 +21,7 @@ import io.javaoperatorsdk.operator.api.monitoring.Metrics; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceFactory; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; import io.javaoperatorsdk.operator.processing.dependent.workflow.ManagedWorkflowFactory; import static io.javaoperatorsdk.operator.api.config.ExecutorServiceManager.newThreadPoolExecutor; @@ -335,7 +338,7 @@ default ExecutorServiceManager getExecutorServiceManager() { * resources are created/updated and match was change to use * Server-Side * Apply (SSA) by default. - * + *

* SSA based create/update can be still used with the legacy matching, just overriding the match * method of Kubernetes Dependent Resource. * @@ -345,4 +348,20 @@ default boolean ssaBasedCreateUpdateMatchForDependentResources() { return true; } + /** + * Returns the set of default resources for which Server-Side Apply (SSA) will not be used, even + * if it is the default behavior for dependent resources as specified by + * {@link #ssaBasedCreateUpdateMatchForDependentResources()}. The exception to this is in the case + * where the use of SSA is explicitly enabled on the dependent resource directly using + * {@link KubernetesDependent#useSSA()}. + *

+ * By default, SSA is disabled for {@link ConfigMap} and {@link Secret} resources. + * + * @return The set of resource types for which SSA will not be used + * @since 4.4.0 + */ + default Set> defaultNonSSAResource() { + return Set.of(ConfigMap.class, Secret.class); + } + } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java index ebac41f640..15418aed5e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java @@ -9,6 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.monitoring.Metrics; @@ -35,6 +36,7 @@ public class ConfigurationServiceOverrider { private Duration cacheSyncTimeout; private ResourceClassResolver resourceClassResolver; private Boolean ssaBasedCreateUpdateMatchForDependentResources; + private Set> defaultNonSSAResource; ConfigurationServiceOverrider(ConfigurationService original) { this.original = original; @@ -150,6 +152,12 @@ public ConfigurationServiceOverrider withSSABasedCreateUpdateMatchForDependentRe return this; } + public ConfigurationServiceOverrider withDefaultNonSSAResource( + Set> defaultNonSSAResource) { + this.defaultNonSSAResource = defaultNonSSAResource; + return this; + } + public ConfigurationService build() { return new BaseConfigurationService(original.getVersion(), cloner, client) { @Override @@ -256,6 +264,12 @@ public boolean ssaBasedCreateUpdateMatchForDependentResources() { ? ssaBasedCreateUpdateMatchForDependentResources : super.ssaBasedCreateUpdateMatchForDependentResources(); } + + @Override + public Set> defaultNonSSAResource() { + return defaultNonSSAResource != null ? defaultNonSSAResource + : super.defaultNonSSAResource(); + } }; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java new file mode 100644 index 0000000000..45b781af7a --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java @@ -0,0 +1,47 @@ +package io.javaoperatorsdk.operator.processing.dependent.kubernetes; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaimStatus; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.apps.StatefulSet; +import io.javaoperatorsdk.operator.api.reconciler.Context; + +public class DesiredResourceSanitizer { + + private DesiredResourceSanitizer() {} + + public static void sanitizeDesired(R desired, R actual, P primary, + Context

context, boolean useSSA) { + if (useSSA) { + if (desired instanceof StatefulSet) { + fillDefaultsOnVolumeClaimTemplate((StatefulSet) desired); + } + if (desired instanceof Secret) { + checkIfStringDataUsed((Secret) desired); + } + } + } + + private static void checkIfStringDataUsed(Secret secret) { + if (secret.getStringData() != null && !secret.getStringData().isEmpty()) { + throw new IllegalStateException( + "There is a known issue using StringData with SSA. Use data instead."); + } + } + + private static void fillDefaultsOnVolumeClaimTemplate(StatefulSet statefulSet) { + if (!statefulSet.getSpec().getVolumeClaimTemplates().isEmpty()) { + statefulSet.getSpec().getVolumeClaimTemplates().forEach(t -> { + if (t.getSpec().getVolumeMode() == null) { + t.getSpec().setVolumeMode("Filesystem"); + } + if (t.getStatus() == null) { + t.setStatus(new PersistentVolumeClaimStatus()); + } + if (t.getStatus().getPhase() == null) { + t.getStatus().setPhase("pending"); + } + }); + } + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 7fadcc6940..22ec5a48f9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -103,18 +103,19 @@ public void configureWith(InformerEventSource informerEventSource) { } @SuppressWarnings("unused") - public R create(R target, P primary, Context

context) { + public R create(R desired, P primary, Context

context) { if (useSSA(context)) { // setting resource version for SSA so only created if it doesn't exist already var createIfNotExisting = kubernetesDependentResourceConfig == null ? KubernetesDependentResourceConfig.DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA : kubernetesDependentResourceConfig.createResourceOnlyIfNotExistingWithSSA(); if (createIfNotExisting) { - target.getMetadata().setResourceVersion("1"); + desired.getMetadata().setResourceVersion("1"); } } - addMetadata(false, null, target, primary); - final var resource = prepare(target, primary, "Creating"); + addMetadata(false, null, desired, primary); + sanitizeDesired(desired, null, primary, context); + final var resource = prepare(desired, primary, "Creating"); return useSSA(context) ? resource .fieldManager(context.getControllerConfiguration().fieldManager()) @@ -123,19 +124,20 @@ public R create(R target, P primary, Context

context) { : resource.create(); } - public R update(R actual, R target, P primary, Context

context) { + public R update(R actual, R desired, P primary, Context

context) { if (log.isDebugEnabled()) { log.debug("Updating actual resource: {} version: {}", ResourceID.fromResource(actual), actual.getMetadata().getResourceVersion()); } R updatedResource; - addMetadata(false, actual, target, primary); + addMetadata(false, actual, desired, primary); + sanitizeDesired(desired, actual, primary, context); if (useSSA(context)) { - updatedResource = prepare(target, primary, "Updating") + updatedResource = prepare(desired, primary, "Updating") .fieldManager(context.getControllerConfiguration().fieldManager()) .forceConflicts().serverSideApply(); } else { - var updatedActual = updaterMatcher.updateResource(actual, target, context); + var updatedActual = updaterMatcher.updateResource(actual, desired, context); updatedResource = prepare(updatedActual, primary, "Updating").update(); } log.debug("Resource version after update: {}", @@ -146,6 +148,7 @@ public R update(R actual, R target, P primary, Context

context) { @Override public Result match(R actualResource, P primary, Context

context) { final var desired = desired(primary, context); + sanitizeDesired(desired, actualResource, primary, context); return match(actualResource, desired, primary, updaterMatcher, context); } @@ -189,9 +192,18 @@ protected void addMetadata(boolean forMatch, R actualResource, final R target, P addReferenceHandlingMetadata(target, primary); } - private boolean useSSA(Context

context) { + protected void sanitizeDesired(R desired, R actual, P primary, Context

context) { + DesiredResourceSanitizer.sanitizeDesired(desired, actual, primary, context, useSSA(context)); + } + + protected boolean useSSA(Context

context) { Optional useSSAConfig = configuration().flatMap(KubernetesDependentResourceConfig::useSSA); + var configService = context.getControllerConfiguration().getConfigurationService(); + // don't use SSA for certain resources by default, only if explicitly overriden + if (useSSAConfig.isEmpty() && configService.defaultNonSSAResource().contains(resourceType())) { + return false; + } return useSSAConfig.orElse(context.getControllerConfiguration().getConfigurationService() .ssaBasedCreateUpdateMatchForDependentResources()); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java index a9834753cd..a18d8b8a41 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java @@ -78,7 +78,8 @@ public KubernetesDependentResourceConfigBuilder withGenericFilter( } public KubernetesDependentResourceConfig build() { - return new KubernetesDependentResourceConfig<>(namespaces, labelSelector, false, + return new KubernetesDependentResourceConfig<>(namespaces, labelSelector, + namespaces != Constants.SAME_AS_CONTROLLER_NAMESPACES_SET, createResourceOnlyIfNotExistingWithSSA, resourceDiscriminator, useSSA, onAddFilter, onUpdateFilter, onDeleteFilter, genericFilter); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java index f4718b45c3..442119a822 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java @@ -1,14 +1,7 @@ package io.javaoperatorsdk.operator.processing.dependent.kubernetes; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; import java.util.stream.Collectors; import org.slf4j.Logger; @@ -159,7 +152,7 @@ private static void fillResultsAndTraverseFurther(Map result, Object managedFieldValue) { var emptyMapValue = new HashMap(); result.put(keyInActual, emptyMapValue); - var actualMapValue = actualMap.get(keyInActual); + var actualMapValue = actualMap.getOrDefault(keyInActual, Collections.emptyMap()); log.debug("key: {} actual map value: {} managedFieldValue: {}", keyInActual, actualMapValue, managedFieldValue); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java index 7e226eca38..0eabc07c97 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java @@ -144,9 +144,10 @@ private DependnetSSACustomResource reconcileWithLegacyOperator(Operator legacyOp private Operator createOperator(KubernetesClient client, boolean legacyDependentHandling, String fieldManager) { Operator operator = new Operator(client, - o -> o.withSSABasedCreateUpdateMatchForDependentResources(!legacyDependentHandling) - .withCloseClientOnStop(false)); - operator.register(new DependentSSAReconciler(), o -> { + o -> o.withCloseClientOnStop(false)); + var reconciler = new DependentSSAReconciler(!legacyDependentHandling); + reconciler.setKubernetesClient(client); + operator.register(reconciler, o -> { o.settingNamespace(namespace); if (fieldManager != null) { o.withFieldManager(fieldManager); @@ -155,7 +156,6 @@ private Operator createOperator(KubernetesClient client, boolean legacyDependent return operator; } - public DependnetSSACustomResource testResource() { DependnetSSACustomResource resource = new DependnetSSACustomResource(); resource.setMetadata(new ObjectMetaBuilder() diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/StatefulSetDesiredSanitizerIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/StatefulSetDesiredSanitizerIT.java new file mode 100644 index 0000000000..5313fb7dfb --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/StatefulSetDesiredSanitizerIT.java @@ -0,0 +1,57 @@ +package io.javaoperatorsdk.operator; + +import java.time.Duration; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.apps.StatefulSet; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer.StatefulSetDesiredSanitizerCustomResource; +import io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer.StatefulSetDesiredSanitizerDependentResource; +import io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer.StatefulSetDesiredSanitizerReconciler; +import io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer.StatefulSetDesiredSanitizerSpec; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class StatefulSetDesiredSanitizerIT { + + public static final String TEST_1 = "test1"; + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(new StatefulSetDesiredSanitizerReconciler()) + .build(); + + @Test + void testSSAMatcher() { + var resource = extension.create(testResource()); + + await().pollDelay(Duration.ofMillis(200)).untilAsserted(() -> { + var statefulSet = extension.get(StatefulSet.class, TEST_1); + assertThat(statefulSet).isNotNull(); + }); + // make sure reconciliation happens at least once more + resource.getSpec().setValue("changed value"); + extension.replace(resource); + + await().untilAsserted( + () -> assertThat(StatefulSetDesiredSanitizerDependentResource.nonMatchedAtLeastOnce) + .isFalse()); + } + + StatefulSetDesiredSanitizerCustomResource testResource() { + var res = new StatefulSetDesiredSanitizerCustomResource(); + res.setMetadata(new ObjectMetaBuilder() + .withName(TEST_1) + .build()); + res.setSpec(new StatefulSetDesiredSanitizerSpec()); + res.getSpec().setValue("initial value"); + + return res; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java index d5c48256f7..f84dfe4597 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java @@ -1,21 +1,43 @@ package io.javaoperatorsdk.operator.sample.dependentssa; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; +import io.javaoperatorsdk.operator.junit.KubernetesClientAware; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfigBuilder; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; -@ControllerConfiguration(dependents = {@Dependent(type = SSAConfigMapDependent.class)}) +@ControllerConfiguration public class DependentSSAReconciler - implements Reconciler, TestExecutionInfoProvider { + implements Reconciler, TestExecutionInfoProvider, + KubernetesClientAware, + EventSourceInitializer { private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + private SSAConfigMapDependent ssaConfigMapDependent = new SSAConfigMapDependent(); + private KubernetesClient kubernetesClient; + + public DependentSSAReconciler() { + this(true); + } + + public DependentSSAReconciler(boolean useSSA) { + ssaConfigMapDependent.configureWith(new KubernetesDependentResourceConfigBuilder() + .withUseSSA(useSSA) + .build()); + } + @Override public UpdateControl reconcile( DependnetSSACustomResource resource, Context context) { + + ssaConfigMapDependent.reconcile(resource, context); numberOfExecutions.addAndGet(1); return UpdateControl.noUpdate(); } @@ -24,4 +46,21 @@ public int getNumberOfExecutions() { return numberOfExecutions.get(); } + @Override + public KubernetesClient getKubernetesClient() { + return kubernetesClient; + } + + @Override + public void setKubernetesClient(KubernetesClient kubernetesClient) { + this.kubernetesClient = kubernetesClient; + ssaConfigMapDependent.setKubernetesClient(kubernetesClient); + } + + @Override + public Map prepareEventSources( + EventSourceContext context) { + return EventSourceInitializer.nameEventSourcesFromDependentResource(context, + ssaConfigMapDependent); + } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java index 70f0ddcf15..806eccd717 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java @@ -33,10 +33,10 @@ protected ConfigMap desired(DependnetSSACustomResource primary, } @Override - public ConfigMap update(ConfigMap actual, ConfigMap target, + public ConfigMap update(ConfigMap actual, ConfigMap desired, DependnetSSACustomResource primary, Context context) { NUMBER_OF_UPDATES.incrementAndGet(); - return super.update(actual, target, primary, context); + return super.update(actual, desired, primary, context); } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/servicestrictmatcher/ServiceDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/servicestrictmatcher/ServiceDependentResource.java index 1079642b33..deddf20263 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/servicestrictmatcher/ServiceDependentResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/servicestrictmatcher/ServiceDependentResource.java @@ -53,10 +53,10 @@ public Matcher.Result match(Service actualResource, } @Override - public Service update(Service actual, Service target, + public Service update(Service actual, Service desired, ServiceStrictMatcherTestCustomResource primary, Context context) { updated.addAndGet(1); - return super.update(actual, target, primary, context); + return super.update(actual, desired, primary, context); } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java index 5230404ceb..a1f5f6faf0 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java @@ -45,17 +45,17 @@ public Result match(Service actualResource, SSALegacyMatcherCustomResou // override just to check the exec count @Override - public Service update(Service actual, Service target, SSALegacyMatcherCustomResource primary, + public Service update(Service actual, Service desired, SSALegacyMatcherCustomResource primary, Context context) { createUpdateCount.addAndGet(1); - return super.update(actual, target, primary, context); + return super.update(actual, desired, primary, context); } // override just to check the exec count @Override - public Service create(Service target, SSALegacyMatcherCustomResource primary, + public Service create(Service desired, SSALegacyMatcherCustomResource primary, Context context) { createUpdateCount.addAndGet(1); - return super.create(target, primary, context); + return super.create(desired, primary, context); } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerCustomResource.java new file mode 100644 index 0000000000..bf35304da0 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerCustomResource.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +public class StatefulSetDesiredSanitizerCustomResource + extends CustomResource + implements Namespaced { + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerDependentResource.java new file mode 100644 index 0000000000..12525c4c8d --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerDependentResource.java @@ -0,0 +1,43 @@ +package io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.apps.StatefulSet; +import io.javaoperatorsdk.operator.ReconcilerUtils; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; + +public class StatefulSetDesiredSanitizerDependentResource + extends + CRUDKubernetesDependentResource { + + public static volatile Boolean nonMatchedAtLeastOnce; + + public StatefulSetDesiredSanitizerDependentResource() { + super(StatefulSet.class); + } + + @Override + protected StatefulSet desired(StatefulSetDesiredSanitizerCustomResource primary, + Context context) { + var template = + ReconcilerUtils.loadYaml(StatefulSet.class, getClass(), "statefulset.yaml"); + template.setMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()); + return template; + } + + @Override + public Result match(StatefulSet actualResource, + StatefulSetDesiredSanitizerCustomResource primary, + Context context) { + var res = super.match(actualResource, primary, context); + if (!res.matched()) { + nonMatchedAtLeastOnce = true; + } else if (nonMatchedAtLeastOnce == null) { + nonMatchedAtLeastOnce = false; + } + return res; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerReconciler.java new file mode 100644 index 0000000000..c884619227 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerReconciler.java @@ -0,0 +1,20 @@ +package io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer; + +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; + +@ControllerConfiguration( + dependents = {@Dependent(type = StatefulSetDesiredSanitizerDependentResource.class)}) +public class StatefulSetDesiredSanitizerReconciler + implements Reconciler { + + @Override + public UpdateControl reconcile( + StatefulSetDesiredSanitizerCustomResource resource, + Context context) throws Exception { + return UpdateControl.noUpdate(); + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerSpec.java new file mode 100644 index 0000000000..3cca134108 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerSpec.java @@ -0,0 +1,15 @@ +package io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer; + +public class StatefulSetDesiredSanitizerSpec { + + private String value; + + public String getValue() { + return value; + } + + public StatefulSetDesiredSanitizerSpec setValue(String value) { + this.value = value; + return this; + } +} diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/statefulset.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/statefulset.yaml new file mode 100644 index 0000000000..f40fbeb607 --- /dev/null +++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/statefulset.yaml @@ -0,0 +1,35 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: "" +spec: + selector: + matchLabels: + app: nginx # has to match .spec.template.metadata.labels + serviceName: "nginx" + replicas: 1 + minReadySeconds: 10 # by default is 0 + template: + metadata: + labels: + app: nginx # has to match .spec.selector.matchLabels + spec: + terminationGracePeriodSeconds: 10 + containers: + - name: nginx + image: registry.k8s.io/nginx-slim:0.8 + ports: + - containerPort: 80 + name: web + volumeMounts: + - name: www + mountPath: /usr/share/nginx/html + volumeClaimTemplates: + - metadata: + name: www + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "my-storage-class" + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java index cc7b15146b..ea1731041f 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java @@ -47,9 +47,9 @@ protected ConfigMap desired(WebPage webPage, Context context) { } @Override - public ConfigMap update(ConfigMap actual, ConfigMap target, WebPage primary, + public ConfigMap update(ConfigMap actual, ConfigMap desired, WebPage primary, Context context) { - var res = super.update(actual, target, primary, context); + var res = super.update(actual, desired, primary, context); var ns = actual.getMetadata().getNamespace(); log.info("Restarting pods because HTML has changed in {}", ns); From 21121da09e4f97fe2d59d8092dd5f6781233baa8 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Thu, 14 Sep 2023 16:07:09 +0200 Subject: [PATCH 040/644] feat: make primary cache accessible from Context (#2053) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: make primary cache accessible from Context Signed-off-by: Chris Laprun * refactor: introduce IndexedResourceCache interface Signed-off-by: Chris Laprun * refactor: move read-only cache interfaces to api package Signed-off-by: Chris Laprun --------- Signed-off-by: Chris Laprun Signed-off-by: Attila Mészáros --- .../javaoperatorsdk/operator/api/reconciler/Context.java | 9 +++++++++ .../operator/api/reconciler/DefaultContext.java | 5 +++++ .../operator/api/reconciler/IndexedResourceCache.java | 9 +++++++++ .../event/source => api/reconciler}/ResourceCache.java | 3 ++- .../processing/event/source/IndexerResourceCache.java | 6 ++---- 5 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/IndexedResourceCache.java rename operator-framework-core/src/main/java/io/javaoperatorsdk/operator/{processing/event/source => api/reconciler}/ResourceCache.java (76%) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java index 5043ed675c..e157ed5fd7 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java @@ -10,6 +10,7 @@ import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedDependentResourceContext; import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever; +import io.javaoperatorsdk.operator.processing.event.source.IndexerResourceCache; public interface Context

{ @@ -43,4 +44,12 @@ Optional getSecondaryResource(Class expectedType, * ExecutorService initialized by framework for workflows. Used for workflow standalone mode. */ ExecutorService getWorkflowExecutorService(); + + /** + * Retrieves the primary resource cache. + * + * @return the {@link IndexerResourceCache} associated with the associated {@link Reconciler} for + * this context + */ + IndexedResourceCache

getPrimaryCache(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java index d6e5cb91ea..2b0f20ef33 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java @@ -40,6 +40,11 @@ public Set getSecondaryResources(Class expectedType) { return getSecondaryResourcesAsStream(expectedType).collect(Collectors.toSet()); } + @Override + public IndexedResourceCache

getPrimaryCache() { + return controller.getEventSourceManager().getControllerResourceEventSource(); + } + @Override public Stream getSecondaryResourcesAsStream(Class expectedType) { return controller.getEventSourceManager().getResourceEventSourcesFor(expectedType).stream() diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/IndexedResourceCache.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/IndexedResourceCache.java new file mode 100644 index 0000000000..29ac9c073a --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/IndexedResourceCache.java @@ -0,0 +1,9 @@ +package io.javaoperatorsdk.operator.api.reconciler; + +import java.util.List; + +import io.fabric8.kubernetes.api.model.HasMetadata; + +public interface IndexedResourceCache extends ResourceCache { + List byIndex(String indexName, String indexKey); +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ResourceCache.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceCache.java similarity index 76% rename from operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ResourceCache.java rename to operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceCache.java index b0b9e88746..130bd23e8d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ResourceCache.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceCache.java @@ -1,9 +1,10 @@ -package io.javaoperatorsdk.operator.processing.event.source; +package io.javaoperatorsdk.operator.api.reconciler; import java.util.function.Predicate; import java.util.stream.Stream; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.processing.event.source.Cache; @SuppressWarnings("unchecked") public interface ResourceCache extends Cache { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/IndexerResourceCache.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/IndexerResourceCache.java index e52833d00a..3938d8219b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/IndexerResourceCache.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/IndexerResourceCache.java @@ -5,15 +5,13 @@ import java.util.function.Function; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.IndexedResourceCache; -public interface IndexerResourceCache extends ResourceCache { +public interface IndexerResourceCache extends IndexedResourceCache { void addIndexers(Map>> indexers); default void addIndexer(String name, Function> indexer) { addIndexers(Map.of(name, indexer)); } - - List byIndex(String indexName, String indexKey); - } From 32c1cabe29c93353c42695392ce7d9fb7cabed5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 18 Sep 2023 15:46:22 +0200 Subject: [PATCH 041/644] fix: remove pod delete web page dependent test (#2061) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../ConfigMapDependentResource.java | 24 ------------------- .../sample/WebPageOperatorAbstractTest.java | 3 ++- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java index ea1731041f..8641aa343b 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java @@ -3,9 +3,6 @@ import java.util.HashMap; import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; @@ -15,7 +12,6 @@ import io.javaoperatorsdk.operator.sample.customresource.WebPage; import static io.javaoperatorsdk.operator.sample.Utils.configMapName; -import static io.javaoperatorsdk.operator.sample.Utils.deploymentName; import static io.javaoperatorsdk.operator.sample.WebPageManagedDependentsReconciler.SELECTOR; // this annotation only activates when using managed dependents and is not otherwise needed @@ -23,8 +19,6 @@ public class ConfigMapDependentResource extends CRUDKubernetesDependentResource { - private static final Logger log = LoggerFactory.getLogger(ConfigMapDependentResource.class); - public ConfigMapDependentResource() { super(ConfigMap.class); } @@ -45,22 +39,4 @@ protected ConfigMap desired(WebPage webPage, Context context) { .withData(data) .build(); } - - @Override - public ConfigMap update(ConfigMap actual, ConfigMap desired, WebPage primary, - Context context) { - var res = super.update(actual, desired, primary, context); - var ns = actual.getMetadata().getNamespace(); - log.info("Restarting pods because HTML has changed in {}", - ns); - // not that this is not necessary, eventually mounted config map would be updated, just this way - // is much faster; what is handy for demo purposes. - // https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#mounted-configmaps-are-updated-automatically - getKubernetesClient() - .pods() - .inNamespace(ns) - .withLabel("app", deploymentName(primary)) - .delete(); - return res; - } } diff --git a/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorAbstractTest.java b/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorAbstractTest.java index 24945a58b3..d1445e34ba 100644 --- a/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorAbstractTest.java +++ b/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorAbstractTest.java @@ -36,6 +36,7 @@ public abstract class WebPageOperatorAbstractTest { public static final String TITLE1 = "Hello Operator World"; public static final String TITLE2 = "Hello Operator World Title 2"; public static final int WAIT_SECONDS = 20; + public static final int LONG_WAIT_SECONDS = 120; public static final Duration POLL_INTERVAL = Duration.ofSeconds(1); boolean isLocal() { @@ -68,7 +69,7 @@ void testAddingWebPage() { // update part: changing title operator().replace(createWebPage(TITLE2)); - await().atMost(Duration.ofSeconds(WAIT_SECONDS)) + await().atMost(Duration.ofSeconds(LONG_WAIT_SECONDS)) .pollInterval(POLL_INTERVAL) .untilAsserted(() -> { String page = httpGetForWebPage(webPage); From 28f841af0d22610c49f31ecf882a8d49b260fe18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 18 Sep 2023 17:00:02 +0200 Subject: [PATCH 042/644] fix: logging recursive matching on trace level (#2060) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../kubernetes/SSABasedGenericKubernetesResourceMatcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java index 442119a822..37a5fa9dd2 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java @@ -153,7 +153,7 @@ private static void fillResultsAndTraverseFurther(Map result, var emptyMapValue = new HashMap(); result.put(keyInActual, emptyMapValue); var actualMapValue = actualMap.getOrDefault(keyInActual, Collections.emptyMap()); - log.debug("key: {} actual map value: {} managedFieldValue: {}", keyInActual, + log.trace("key: {} actual map value: {} managedFieldValue: {}", keyInActual, actualMapValue, managedFieldValue); keepOnlyManagedFields(emptyMapValue, (Map) actualMapValue, From 66556b4084d4b7e4b6a9f79b296d25d8a9409111 Mon Sep 17 00:00:00 2001 From: Steven Hawkins Date: Fri, 22 Sep 2023 03:14:38 -0400 Subject: [PATCH 043/644] eventing refinements mentioned on #2012 (#2034) * refinements mentioned on #2012 provides two options - to control if the annotation is used (to omit events that come too quickly) - to parse the resource version (to keep the cache up-to-date and omit events if they come too slowly) Signed-off-by: Steven Hawkins --- .../api/config/ConfigurationService.java | 27 ++++++++ .../config/ConfigurationServiceOverrider.java | 28 ++++++++ .../informer/InformerConfiguration.java | 4 ++ .../KubernetesDependentResource.java | 18 +++-- .../ControllerResourceEventSource.java | 4 +- .../source/informer/InformerEventSource.java | 14 +++- .../informer/ManagedInformerEventSource.java | 12 ++-- .../informer/TemporaryResourceCache.java | 66 ++++++++++++++++--- .../informer/InformerEventSourceTest.java | 2 +- .../informer/TemporaryResourceCacheTest.java | 41 ++++++++++-- ...pdateInformerEventSourceEventFilterIT.java | 44 +++++-------- .../PreviousAnnotationDisabledIT.java | 38 +++++++++++ 12 files changed, 238 insertions(+), 60 deletions(-) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/PreviousAnnotationDisabledIT.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java index 86efb457c5..53bfc75df9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java @@ -364,4 +364,31 @@ default Set> defaultNonSSAResource() { return Set.of(ConfigMap.class, Secret.class); } + /** + * If a javaoperatorsdk.io/previous annotation should be used so that the operator sdk can detect + * events from its own updates of dependent resources and then filter them. + *

+ * Disable this if you want to react to your own dependent resource updates + * + * @since 4.5.0 + */ + default boolean previousAnnotationForDependentResourcesEventFiltering() { + return true; + } + + /** + * If the event logic should parse the resourceVersion to determine the ordering of dependent + * resource events. This is typically not needed. + *

+ * Disabled by default as Kubernetes does not support, and discourages, this interpretation of + * resourceVersions. Enable only if your api server event processing seems to lag the operator + * logic and you want to further minimize the the amount of work done / updates issued by the + * operator. + * + * @since 4.5.0 + */ + default boolean parseResourceVersionsForEventFilteringAndCaching() { + return false; + } + } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java index 15418aed5e..2a2f6964c1 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java @@ -37,6 +37,8 @@ public class ConfigurationServiceOverrider { private ResourceClassResolver resourceClassResolver; private Boolean ssaBasedCreateUpdateMatchForDependentResources; private Set> defaultNonSSAResource; + private Boolean previousAnnotationForDependentResources; + private Boolean parseResourceVersions; ConfigurationServiceOverrider(ConfigurationService original) { this.original = original; @@ -158,6 +160,18 @@ public ConfigurationServiceOverrider withDefaultNonSSAResource( return this; } + public ConfigurationServiceOverrider withPreviousAnnotationForDependentResources( + boolean value) { + this.previousAnnotationForDependentResources = value; + return this; + } + + public ConfigurationServiceOverrider wihtParseResourceVersions( + boolean value) { + this.parseResourceVersions = value; + return this; + } + public ConfigurationService build() { return new BaseConfigurationService(original.getVersion(), cloner, client) { @Override @@ -270,6 +284,20 @@ public Set> defaultNonSSAResource() { return defaultNonSSAResource != null ? defaultNonSSAResource : super.defaultNonSSAResource(); } + + @Override + public boolean previousAnnotationForDependentResourcesEventFiltering() { + return previousAnnotationForDependentResources != null + ? previousAnnotationForDependentResources + : super.previousAnnotationForDependentResourcesEventFiltering(); + } + + @Override + public boolean parseResourceVersionsForEventFilteringAndCaching() { + return parseResourceVersions != null + ? parseResourceVersions + : super.parseResourceVersionsForEventFilteringAndCaching(); + } }; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java index 1f40677ee7..4b0007c96e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java @@ -62,6 +62,7 @@ public SecondaryToPrimaryMapper getSecondaryToPrimaryMapper() { return secondaryToPrimaryMapper; } + @Override public Optional> onDeleteFilter() { return Optional.ofNullable(onDeleteFilter); } @@ -95,12 +96,15 @@ public

PrimaryToSecondaryMapper

getPrimaryToSecondary */ SecondaryToPrimaryMapper getSecondaryToPrimaryMapper(); + @Override Optional> onAddFilter(); + @Override Optional> onUpdateFilter(); Optional> onDeleteFilter(); + @Override Optional> genericFilter();

PrimaryToSecondaryMapper

getPrimaryToSecondaryMapper(); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 22ec5a48f9..f81f98f12c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -113,7 +113,7 @@ public R create(R desired, P primary, Context

context) { desired.getMetadata().setResourceVersion("1"); } } - addMetadata(false, null, desired, primary); + addMetadata(false, null, desired, primary, context); sanitizeDesired(desired, null, primary, context); final var resource = prepare(desired, primary, "Creating"); return useSSA(context) @@ -130,7 +130,7 @@ public R update(R actual, R desired, P primary, Context

context) { actual.getMetadata().getResourceVersion()); } R updatedResource; - addMetadata(false, actual, desired, primary); + addMetadata(false, actual, desired, primary, context); sanitizeDesired(desired, actual, primary, context); if (useSSA(context)) { updatedResource = prepare(desired, primary, "Updating") @@ -163,7 +163,7 @@ public Result match(R actualResource, R desired, P primary, Context

contex public Result match(R actualResource, R desired, P primary, ResourceUpdaterMatcher matcher, Context

context) { final boolean matches; - addMetadata(true, actualResource, desired, primary); + addMetadata(true, actualResource, desired, primary, context); if (useSSA(context)) { matches = SSABasedGenericKubernetesResourceMatcher.getInstance() .matches(actualResource, desired, context); @@ -173,8 +173,9 @@ public Result match(R actualResource, R desired, P primary, ResourceUpdaterMa return Result.computed(matches, desired); } - protected void addMetadata(boolean forMatch, R actualResource, final R target, P primary) { - if (forMatch) { // keep the current + protected void addMetadata(boolean forMatch, R actualResource, final R target, P primary, + Context

context) { + if (forMatch) { // keep the current previous annotation String actual = actualResource.getMetadata().getAnnotations() .get(InformerEventSource.PREVIOUS_ANNOTATION_KEY); Map annotations = target.getMetadata().getAnnotations(); @@ -183,7 +184,7 @@ protected void addMetadata(boolean forMatch, R actualResource, final R target, P } else { annotations.remove(InformerEventSource.PREVIOUS_ANNOTATION_KEY); } - } else { // set a new one + } else if (usePreviousAnnotation(context)) { // set a new one eventSource().orElseThrow().addPreviousAnnotation( Optional.ofNullable(actualResource).map(r -> r.getMetadata().getResourceVersion()) .orElse(null), @@ -208,6 +209,11 @@ protected boolean useSSA(Context

context) { .ssaBasedCreateUpdateMatchForDependentResources()); } + private boolean usePreviousAnnotation(Context

context) { + return context.getControllerConfiguration().getConfigurationService() + .previousAnnotationForDependentResourcesEventFiltering(); + } + @Override protected void handleDelete(P primary, R secondary, Context

context) { if (secondary != null) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java index da2e517376..f7b51bd572 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java @@ -32,12 +32,12 @@ public class ControllerResourceEventSource @SuppressWarnings({"unchecked", "rawtypes"}) public ControllerResourceEventSource(Controller controller) { - super(controller.getCRClient(), controller.getConfiguration()); + super(controller.getCRClient(), controller.getConfiguration(), false); this.controller = controller; final var config = controller.getConfiguration(); OnUpdateFilter internalOnUpdateFilter = - (OnUpdateFilter) onUpdateFinalizerNeededAndApplied(controller.useFinalizer(), + onUpdateFinalizerNeededAndApplied(controller.useFinalizer(), config.getFinalizerName()) .or(onUpdateGenerationAware(config.isGenerationAware())) .or(onUpdateMarkedForDeletion()); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index d154ad201b..968ccc27b9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -81,12 +81,18 @@ public class InformerEventSource public InformerEventSource( InformerConfiguration configuration, EventSourceContext

context) { - this(configuration, context.getClient()); + this(configuration, context.getClient(), + context.getControllerConfiguration().getConfigurationService() + .parseResourceVersionsForEventFilteringAndCaching()); } public InformerEventSource(InformerConfiguration configuration, KubernetesClient client) { - super(client.resources(configuration.getResourceClass()), configuration); + this(configuration, client, false); + } + public InformerEventSource(InformerConfiguration configuration, KubernetesClient client, + boolean parseResourceVersions) { + super(client.resources(configuration.getResourceClass()), configuration, parseResourceVersions); // If there is a primary to secondary mapper there is no need for primary to secondary index. primaryToSecondaryMapper = configuration.getPrimaryToSecondaryMapper(); if (primaryToSecondaryMapper == null) { @@ -169,6 +175,9 @@ private synchronized void onAddOrUpdate(Operation operation, R newObject, R oldO } private boolean canSkipEvent(R newObject, R oldObject, ResourceID resourceID) { + if (temporaryResourceCache.isKnownResourceVersion(newObject)) { + return true; + } var res = temporaryResourceCache.getResourceFromCache(resourceID); if (res.isEmpty()) { return isEventKnownFromAnnotation(newObject, oldObject); @@ -275,7 +284,6 @@ public boolean allowsNamespaceChanges() { return configuration().followControllerNamespaceChanges(); } - private boolean eventAcceptedByFilter(Operation operation, R newObject, R oldObject) { if (genericFilter != null && !genericFilter.accept(newObject)) { return false; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java index 6ec6cd7f6e..5dff2be51b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java @@ -42,26 +42,27 @@ public abstract class ManagedInformerEventSource, Resource> client; protected ManagedInformerEventSource( - MixedOperation, Resource> client, C configuration) { + MixedOperation, Resource> client, C configuration, + boolean parseResourceVersions) { super(configuration.getResourceClass()); this.client = client; - temporaryResourceCache = new TemporaryResourceCache<>(this); + temporaryResourceCache = new TemporaryResourceCache<>(this, parseResourceVersions); this.cache = new InformerManager<>(client, configuration, this); } @Override public void onAdd(R resource) { - temporaryResourceCache.removeResourceFromCache(resource); + temporaryResourceCache.onEvent(resource, false); } @Override public void onUpdate(R oldObj, R newObj) { - temporaryResourceCache.removeResourceFromCache(newObj); + temporaryResourceCache.onEvent(newObj, false); } @Override public void onDelete(R obj, boolean deletedFinalStateUnknown) { - temporaryResourceCache.removeResourceFromCache(obj); + temporaryResourceCache.onEvent(obj, deletedFinalStateUnknown); } protected InformerManager manager() { @@ -127,6 +128,7 @@ void setTemporalResourceCache(TemporaryResourceCache temporaryResourceCache) this.temporaryResourceCache = temporaryResourceCache; } + @Override public void addIndexers(Map>> indexers) { cache.addIndexers(indexers); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java index 233b409f3f..fd9a8ad565 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java @@ -1,13 +1,17 @@ package io.javaoperatorsdk.operator.processing.event.source.informer; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -33,16 +37,33 @@ public class TemporaryResourceCache { private static final Logger log = LoggerFactory.getLogger(TemporaryResourceCache.class); + private static final int MAX_RESOURCE_VERSIONS = 256; private final Map cache = new ConcurrentHashMap<>(); private final ManagedInformerEventSource managedInformerEventSource; + private final boolean parseResourceVersions; + private final Set knownResourceVersions; - public TemporaryResourceCache(ManagedInformerEventSource managedInformerEventSource) { + public TemporaryResourceCache(ManagedInformerEventSource managedInformerEventSource, + boolean parseResourceVersions) { this.managedInformerEventSource = managedInformerEventSource; + this.parseResourceVersions = parseResourceVersions; + if (parseResourceVersions) { + knownResourceVersions = Collections.newSetFromMap(new LinkedHashMap() { + @Override + protected boolean removeEldestEntry(java.util.Map.Entry eldest) { + return size() >= MAX_RESOURCE_VERSIONS; + } + }); + } else { + knownResourceVersions = null; + } } - public synchronized Optional removeResourceFromCache(T resource) { - return Optional.ofNullable(cache.remove(ResourceID.fromResource(resource))); + public synchronized void onEvent(T resource, boolean unknownState) { + cache.computeIfPresent(ResourceID.fromResource(resource), + (id, cached) -> (unknownState || !isLaterResourceVersion(id, cached, resource)) ? null + : cached); } public synchronized void putAddedResource(T newResource) { @@ -56,23 +77,50 @@ public synchronized void putAddedResource(T newResource) { * @param previousResourceVersion null indicates an add */ public synchronized void putResource(T newResource, String previousResourceVersion) { + if (knownResourceVersions != null) { + knownResourceVersions.add(newResource.getMetadata().getResourceVersion()); + } var resourceId = ResourceID.fromResource(newResource); var cachedResource = getResourceFromCache(resourceId) .orElse(managedInformerEventSource.get(resourceId).orElse(null)); if ((previousResourceVersion == null && cachedResource == null) - || (cachedResource != null && previousResourceVersion != null - && cachedResource.getMetadata().getResourceVersion() - .equals(previousResourceVersion))) { + || (cachedResource != null + && (cachedResource.getMetadata().getResourceVersion().equals(previousResourceVersion)) + || isLaterResourceVersion(resourceId, newResource, cachedResource))) { log.debug( "Temporarily moving ahead to target version {} for resource id: {}", newResource.getMetadata().getResourceVersion(), resourceId); putToCache(newResource, resourceId); - } else { - if (cache.remove(resourceId) != null) { - log.debug("Removed an obsolete resource from cache for id: {}", resourceId); + } else if (cache.remove(resourceId) != null) { + log.debug("Removed an obsolete resource from cache for id: {}", resourceId); + } + } + + public boolean isKnownResourceVersion(T resource) { + return knownResourceVersions != null + && knownResourceVersions.contains(resource.getMetadata().getResourceVersion()); + } + + /** + * @return true if {@link InformerConfiguration#parseResourceVersions()} is enabled and the + * resourceVersion of newResource is numerically greater than cachedResource, otherwise + * false + */ + private boolean isLaterResourceVersion(ResourceID resourceId, T newResource, T cachedResource) { + try { + if (parseResourceVersions + && Long.parseLong(newResource.getMetadata().getResourceVersion()) > Long + .parseLong(cachedResource.getMetadata().getResourceVersion())) { + return true; } + } catch (NumberFormatException e) { + log.debug( + "Could not compare resourceVersions {} and {} for {}", + newResource.getMetadata().getResourceVersion(), + cachedResource.getMetadata().getResourceVersion(), resourceId); } + return false; } private void putToCache(T resource, ResourceID resourceID) { diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java index 7acecc7099..0881cccaf2 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java @@ -119,7 +119,7 @@ void propagateEventAndRemoveResourceFromTempCacheIfResourceVersionMismatch() { informerEventSource.onUpdate(cachedDeployment, testDeployment()); verify(eventHandlerMock, times(1)).handleEvent(any()); - verify(temporaryResourceCacheMock, times(1)).removeResourceFromCache(any()); + verify(temporaryResourceCacheMock, times(1)).onEvent(testDeployment(), false); } @Test diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCacheTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCacheTest.java index 4d5bdf0dfd..d641736739 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCacheTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCacheTest.java @@ -3,9 +3,11 @@ import java.util.Map; import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -16,12 +18,16 @@ class TemporaryResourceCacheTest { - public static final String RESOURCE_VERSION = "1"; + public static final String RESOURCE_VERSION = "2"; @SuppressWarnings("unchecked") - private final InformerEventSource informerEventSource = - mock(InformerEventSource.class); - private final TemporaryResourceCache temporaryResourceCache = - new TemporaryResourceCache<>(informerEventSource); + private InformerEventSource informerEventSource; + private TemporaryResourceCache temporaryResourceCache; + + @BeforeEach + void setup() { + informerEventSource = mock(InformerEventSource.class); + temporaryResourceCache = new TemporaryResourceCache<>(informerEventSource, false); + } @Test void updateAddsTheResourceIntoCacheIfTheInformerHasThePreviousResourceVersion() { @@ -75,7 +81,30 @@ void addOperationNotAddsTheResourceIfInformerCacheNotEmpty() { void removesResourceFromCache() { ConfigMap testResource = propagateTestResourceToCache(); - temporaryResourceCache.removeResourceFromCache(testResource()); + temporaryResourceCache.onEvent(testResource(), false); + + assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource))) + .isNotPresent(); + } + + @Test + void resourceVersionParsing() { + this.temporaryResourceCache = new TemporaryResourceCache<>(informerEventSource, true); + + assertThat(temporaryResourceCache.isKnownResourceVersion(testResource())).isFalse(); + + ConfigMap testResource = propagateTestResourceToCache(); + + // an event with a newer version will not remove + temporaryResourceCache.onEvent(new ConfigMapBuilder(testResource).editMetadata() + .withResourceVersion("1").endMetadata().build(), false); + + assertThat(temporaryResourceCache.isKnownResourceVersion(testResource)).isTrue(); + assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource))) + .isPresent(); + + // anything else will remove + temporaryResourceCache.onEvent(testResource(), false); assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource))) .isNotPresent(); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/CreateUpdateInformerEventSourceEventFilterIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/CreateUpdateInformerEventSourceEventFilterIT.java index f319509c47..8a68c9a2b3 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/CreateUpdateInformerEventSourceEventFilterIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/CreateUpdateInformerEventSourceEventFilterIT.java @@ -26,28 +26,12 @@ class CreateUpdateInformerEventSourceEventFilterIT { @Test void updateEventNotReceivedAfterCreateOrUpdate() { - CreateUpdateEventFilterTestCustomResource resource = prepareTestResource(); + CreateUpdateEventFilterTestCustomResource resource = + CreateUpdateInformerEventSourceEventFilterIT.prepareTestResource(); var createdResource = operator.create(resource); - await() - .atMost(Duration.ofSeconds(1)) - .until(() -> { - var cm = operator.get(ConfigMap.class, createdResource.getMetadata().getName()); - if (cm == null) { - return false; - } - return cm.getData() - .get(CONFIG_MAP_TEST_DATA_KEY) - .equals(createdResource.getSpec().getValue()); - }); - - assertThat( - ((CreateUpdateEventFilterTestReconciler) operator.getFirstReconciler()) - .getNumberOfExecutions()) - .isEqualTo(1); // this should be 1 usually but sometimes event is received - // faster than added resource added to the cache - + assertData(operator, createdResource, 1, 1); CreateUpdateEventFilterTestCustomResource actualCreatedResource = operator.get(CreateUpdateEventFilterTestCustomResource.class, @@ -55,26 +39,30 @@ void updateEventNotReceivedAfterCreateOrUpdate() { actualCreatedResource.getSpec().setValue("2"); operator.replace(actualCreatedResource); + assertData(operator, actualCreatedResource, 2, 2); + } - await().atMost(Duration.ofSeconds(1)) + static void assertData(LocallyRunOperatorExtension operator, + CreateUpdateEventFilterTestCustomResource resource, int minExecutions, int maxExecutions) { + await() + .atMost(Duration.ofSeconds(1)) .until(() -> { - var cm = operator.get(ConfigMap.class, createdResource.getMetadata().getName()); + var cm = operator.get(ConfigMap.class, resource.getMetadata().getName()); if (cm == null) { return false; } return cm.getData() .get(CONFIG_MAP_TEST_DATA_KEY) - .equals(actualCreatedResource.getSpec().getValue()); + .equals(resource.getSpec().getValue()); }); - assertThat( - ((CreateUpdateEventFilterTestReconciler) operator.getFirstReconciler()) - .getNumberOfExecutions()) - // same as for previous assert (usually this should be 2) - .isEqualTo(2); + int numberOfExecutions = ((CreateUpdateEventFilterTestReconciler) operator.getFirstReconciler()) + .getNumberOfExecutions(); + assertThat(numberOfExecutions).isGreaterThanOrEqualTo(minExecutions); + assertThat(numberOfExecutions).isLessThanOrEqualTo(maxExecutions); } - private CreateUpdateEventFilterTestCustomResource prepareTestResource() { + static CreateUpdateEventFilterTestCustomResource prepareTestResource() { CreateUpdateEventFilterTestCustomResource resource = new CreateUpdateEventFilterTestCustomResource(); resource.setMetadata(new ObjectMeta()); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/PreviousAnnotationDisabledIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/PreviousAnnotationDisabledIT.java new file mode 100644 index 0000000000..c636737d0a --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/PreviousAnnotationDisabledIT.java @@ -0,0 +1,38 @@ +package io.javaoperatorsdk.operator; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.createupdateeventfilter.CreateUpdateEventFilterTestCustomResource; +import io.javaoperatorsdk.operator.sample.createupdateeventfilter.CreateUpdateEventFilterTestReconciler; + +class PreviousAnnotationDisabledIT { + + @RegisterExtension + LocallyRunOperatorExtension operator = + LocallyRunOperatorExtension.builder() + .withReconciler(new CreateUpdateEventFilterTestReconciler()) + .withConfigurationService( + overrider -> overrider.withPreviousAnnotationForDependentResources(false)) + .build(); + + @Test + void updateEventReceivedAfterCreateOrUpdate() { + CreateUpdateEventFilterTestCustomResource resource = + CreateUpdateInformerEventSourceEventFilterIT.prepareTestResource(); + var createdResource = + operator.create(resource); + + CreateUpdateInformerEventSourceEventFilterIT.assertData(operator, createdResource, 1, 2); + + CreateUpdateEventFilterTestCustomResource actualCreatedResource = + operator.get(CreateUpdateEventFilterTestCustomResource.class, + resource.getMetadata().getName()); + actualCreatedResource.getSpec().setValue("2"); + operator.replace(actualCreatedResource); + + CreateUpdateInformerEventSourceEventFilterIT.assertData(operator, actualCreatedResource, 2, 4); + } + +} From ed7e13df1f2573c781249b57e0cefcd603d2dca2 Mon Sep 17 00:00:00 2001 From: Steven Hawkins Date: Fri, 22 Sep 2023 09:27:53 -0400 Subject: [PATCH 044/644] various refinements to ssa logic (#2028) - localizes sanitation to ssa matcher - further ensures values won't be logged Signed-off-by: Steven Hawkins --- docs/documentation/dependent-resources.md | 2 + .../kubernetes/DesiredResourceSanitizer.java | 47 -------------- .../KubernetesDependentResource.java | 15 ++--- ...BasedGenericKubernetesResourceMatcher.java | 64 ++++++++++++------- 4 files changed, 51 insertions(+), 77 deletions(-) delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java diff --git a/docs/documentation/dependent-resources.md b/docs/documentation/dependent-resources.md index b23e19f006..06149cf8ba 100644 --- a/docs/documentation/dependent-resources.md +++ b/docs/documentation/dependent-resources.md @@ -370,6 +370,8 @@ server. To bypass the matching feature completely, simply override the `match` m return `false`, thus telling JOSDK that the actual state never matches the desired one, making it always update the resources using SSA. +WARNING: Older versions of Kubernetes before 1.25 would create an additional resource version for every SSA update performed with certain resources - even though there were no actual changes in the stored resource - leading to infinite reconciliations. This behavior was seen with Secrets using `stringData`, Ingresses using empty string fields, and StatefulSets using volume claim templates. The operator framework has added built-in handling for the StatefulSet issue. If you encounter this issue on an older Kubernetes version, consider changing your desired state, turning off SSA for that resource, or even upgrading your Kubernetes version. If you encounter it on a newer Kubernetes version, please log an issue with the JOSDK and with upstream Kubernetes. + ## Telling JOSDK how to find which secondary resources are associated with a given primary resource [`KubernetesDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java deleted file mode 100644 index 45b781af7a..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent.kubernetes; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.api.model.PersistentVolumeClaimStatus; -import io.fabric8.kubernetes.api.model.Secret; -import io.fabric8.kubernetes.api.model.apps.StatefulSet; -import io.javaoperatorsdk.operator.api.reconciler.Context; - -public class DesiredResourceSanitizer { - - private DesiredResourceSanitizer() {} - - public static void sanitizeDesired(R desired, R actual, P primary, - Context

context, boolean useSSA) { - if (useSSA) { - if (desired instanceof StatefulSet) { - fillDefaultsOnVolumeClaimTemplate((StatefulSet) desired); - } - if (desired instanceof Secret) { - checkIfStringDataUsed((Secret) desired); - } - } - } - - private static void checkIfStringDataUsed(Secret secret) { - if (secret.getStringData() != null && !secret.getStringData().isEmpty()) { - throw new IllegalStateException( - "There is a known issue using StringData with SSA. Use data instead."); - } - } - - private static void fillDefaultsOnVolumeClaimTemplate(StatefulSet statefulSet) { - if (!statefulSet.getSpec().getVolumeClaimTemplates().isEmpty()) { - statefulSet.getSpec().getVolumeClaimTemplates().forEach(t -> { - if (t.getSpec().getVolumeMode() == null) { - t.getSpec().setVolumeMode("Filesystem"); - } - if (t.getStatus() == null) { - t.setStatus(new PersistentVolumeClaimStatus()); - } - if (t.getStatus().getPhase() == null) { - t.getStatus().setPhase("pending"); - } - }); - } - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index f81f98f12c..174cf10619 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -43,11 +43,14 @@ public abstract class KubernetesDependentResource kubernetesDependentResourceConfig; + private boolean usingCustomResourceUpdateMatcher; + @SuppressWarnings("unchecked") public KubernetesDependentResource(Class resourceType) { super(resourceType); - updaterMatcher = this instanceof ResourceUpdaterMatcher + usingCustomResourceUpdateMatcher = this instanceof ResourceUpdaterMatcher; + updaterMatcher = usingCustomResourceUpdateMatcher ? (ResourceUpdaterMatcher) this : GenericResourceUpdaterMatcher.updaterMatcherFor(resourceType); } @@ -114,7 +117,6 @@ public R create(R desired, P primary, Context

context) { } } addMetadata(false, null, desired, primary, context); - sanitizeDesired(desired, null, primary, context); final var resource = prepare(desired, primary, "Creating"); return useSSA(context) ? resource @@ -131,7 +133,6 @@ public R update(R actual, R desired, P primary, Context

context) { } R updatedResource; addMetadata(false, actual, desired, primary, context); - sanitizeDesired(desired, actual, primary, context); if (useSSA(context)) { updatedResource = prepare(desired, primary, "Updating") .fieldManager(context.getControllerConfiguration().fieldManager()) @@ -148,7 +149,6 @@ public R update(R actual, R desired, P primary, Context

context) { @Override public Result match(R actualResource, P primary, Context

context) { final var desired = desired(primary, context); - sanitizeDesired(desired, actualResource, primary, context); return match(actualResource, desired, primary, updaterMatcher, context); } @@ -193,11 +193,10 @@ protected void addMetadata(boolean forMatch, R actualResource, final R target, P addReferenceHandlingMetadata(target, primary); } - protected void sanitizeDesired(R desired, R actual, P primary, Context

context) { - DesiredResourceSanitizer.sanitizeDesired(desired, actual, primary, context, useSSA(context)); - } - protected boolean useSSA(Context

context) { + if (usingCustomResourceUpdateMatcher) { + return false; + } Optional useSSAConfig = configuration().flatMap(KubernetesDependentResourceConfig::useSSA); var configService = context.getControllerConfiguration().getConfigurationService(); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java index 37a5fa9dd2..d699ff2822 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java @@ -7,8 +7,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.ManagedFieldsEntry; +import io.fabric8.kubernetes.api.model.apps.StatefulSet; import io.fabric8.kubernetes.client.utils.KubernetesSerialization; import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.api.reconciler.Context; @@ -74,6 +76,9 @@ public boolean matches(R actual, R desired, Context context) { var objectMapper = context.getClient().getKubernetesSerialization(); var actualMap = objectMapper.convertValue(actual, Map.class); + + sanitizeState(actual, desired, actualMap); + var desiredMap = objectMapper.convertValue(desired, Map.class); if (LoggingUtils.isNotSensitiveResource(desired)) { log.trace("Original actual: \n {} \n original desired: \n {} ", actual, desiredMap); @@ -92,6 +97,35 @@ public boolean matches(R actual, R desired, Context context) { return prunedActual.equals(desiredMap); } + /** + * Correct for known issue with SSA + */ + @SuppressWarnings("unchecked") + private void sanitizeState(R actual, R desired, Map actualMap) { + if (desired instanceof StatefulSet) { + StatefulSet desiredStatefulSet = (StatefulSet) desired; + StatefulSet actualStatefulSet = (StatefulSet) actual; + int claims = desiredStatefulSet.getSpec().getVolumeClaimTemplates().size(); + if (claims == actualStatefulSet.getSpec().getVolumeClaimTemplates().size()) { + for (int i = 0; i < claims; i++) { + if (desiredStatefulSet.getSpec().getVolumeClaimTemplates().get(i).getSpec() + .getVolumeMode() == null) { + Optional + .ofNullable(GenericKubernetesResource.get(actualMap, "spec", "volumeClaimTemplates", + i, "spec")) + .map(Map.class::cast).ifPresent(m -> m.remove("volumeMode")); + } + if (desiredStatefulSet.getSpec().getVolumeClaimTemplates().get(i).getStatus() == null) { + Optional + .ofNullable( + GenericKubernetesResource.get(actualMap, "spec", "volumeClaimTemplates", i)) + .map(Map.class::cast).ifPresent(m -> m.remove("status")); + } + } + } + } + } + @SuppressWarnings("unchecked") private static void removeIrrelevantValues(Map desiredMap) { var metadata = (Map) desiredMap.get(METADATA_KEY); @@ -153,8 +187,7 @@ private static void fillResultsAndTraverseFurther(Map result, var emptyMapValue = new HashMap(); result.put(keyInActual, emptyMapValue); var actualMapValue = actualMap.getOrDefault(keyInActual, Collections.emptyMap()); - log.trace("key: {} actual map value: {} managedFieldValue: {}", keyInActual, - actualMapValue, managedFieldValue); + log.debug("key: {} actual map value: managedFieldValue: {}", keyInActual, managedFieldValue); keepOnlyManagedFields(emptyMapValue, (Map) actualMapValue, (Map) managedFields.get(key), objectMapper); @@ -282,29 +315,16 @@ private static java.util.Map.Entry> selectListEntry } if (possibleTargets.isEmpty()) { throw new IllegalStateException( - "Cannot find list element for key:" + key + ", in map: " + values); + "Cannot find list element for key:" + key + ", in map: " + + values.stream().map(Map::keySet).collect(Collectors.toList())); } if (possibleTargets.size() > 1) { throw new IllegalStateException( - "More targets found in list element for key:" + key + ", in map: " + values); + "More targets found in list element for key:" + key + ", in map: " + + values.stream().map(Map::keySet).collect(Collectors.toList())); } final var finalIndex = index; - return new Map.Entry<>() { - @Override - public Integer getKey() { - return finalIndex; - } - - @Override - public Map getValue() { - return possibleTargets.get(0); - } - - @Override - public Map setValue(Map stringObjectMap) { - throw new IllegalStateException("should not be called"); - } - }; + return new AbstractMap.SimpleEntry<>(finalIndex, possibleTargets.get(0)); } @@ -318,14 +338,14 @@ private Optional checkIfFieldManagerExists(R actual, String .collect(Collectors.toList()); if (targetManagedFields.isEmpty()) { log.debug("No field manager exists for resource {} with name: {} and operation Apply ", - actual, actual.getMetadata().getName()); + actual.getKind(), actual.getMetadata().getName()); return Optional.empty(); } // this should not happen in theory if (targetManagedFields.size() > 1) { throw new OperatorException( "More than one field manager exists with name: " + fieldManager + "in resource: " + - actual + " with name: " + actual.getMetadata().getName()); + actual.getKind() + " with name: " + actual.getMetadata().getName()); } return Optional.of(targetManagedFields.get(0)); } From 395f1757e510cab344b9a714170934559bbe492e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 4 Oct 2023 16:26:30 +0200 Subject: [PATCH 045/644] feat: customize mapping annotation in kubernetes dependent resource (#2075) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../KubernetesDependentResource.java | 23 +++--- .../source/SecondaryToPrimaryMapper.java | 2 +- .../DependentCustomMappingAnnotationIT.java | 72 +++++++++++++++++++ ...stomMappingConfigMapDependentResource.java | 52 ++++++++++++++ .../DependentCustomMappingCustomResource.java | 14 ++++ .../DependentCustomMappingReconciler.java | 20 ++++++ .../DependentCustomMappingSpec.java | 15 ++++ ...DependentPrimaryIndexerTestReconciler.java | 4 +- .../dependent/SecretDependentResource.java | 6 +- 9 files changed, 193 insertions(+), 15 deletions(-) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentCustomMappingAnnotationIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/CustomMappingConfigMapDependentResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/DependentCustomMappingCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/DependentCustomMappingReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/DependentCustomMappingSpec.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 174cf10619..912d876aba 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -88,7 +88,7 @@ private SecondaryToPrimaryMapper getSecondaryToPrimaryMapper() { return (SecondaryToPrimaryMapper) this; } else if (garbageCollected) { return Mappers.fromOwnerReference(); - } else if (useDefaultAnnotationsToIdentifyPrimary()) { + } else if (useNonOwnerRefBasedSecondaryToPrimaryMapping()) { return Mappers.fromDefaultAnnotations(); } else { throw new OperatorException("Provide a SecondaryToPrimaryMapper to associate " + @@ -238,8 +238,8 @@ protected Resource prepare(R desired, P primary, String actionName) { protected void addReferenceHandlingMetadata(R desired, P primary) { if (addOwnerReference()) { desired.addOwnerReference(primary); - } else if (useDefaultAnnotationsToIdentifyPrimary()) { - addDefaultSecondaryToPrimaryMapperAnnotations(desired, primary); + } else if (useNonOwnerRefBasedSecondaryToPrimaryMapping()) { + addSecondaryToPrimaryMapperAnnotations(desired, primary); } } @@ -269,17 +269,22 @@ protected InformerEventSource createEventSource(EventSourceContext

cont return eventSource().orElseThrow(); } - private boolean useDefaultAnnotationsToIdentifyPrimary() { - return !(this instanceof SecondaryToPrimaryMapper) && !garbageCollected && isCreatable(); + private boolean useNonOwnerRefBasedSecondaryToPrimaryMapping() { + return !garbageCollected && isCreatable(); } - private void addDefaultSecondaryToPrimaryMapperAnnotations(R desired, P primary) { + protected void addSecondaryToPrimaryMapperAnnotations(R desired, P primary) { + addSecondaryToPrimaryMapperAnnotations(desired, primary, Mappers.DEFAULT_ANNOTATION_FOR_NAME, + Mappers.DEFAULT_ANNOTATION_FOR_NAMESPACE); + } + + protected void addSecondaryToPrimaryMapperAnnotations(R desired, P primary, String nameKey, + String namespaceKey) { var annotations = desired.getMetadata().getAnnotations(); - annotations.put(Mappers.DEFAULT_ANNOTATION_FOR_NAME, primary.getMetadata().getName()); + annotations.put(nameKey, primary.getMetadata().getName()); var primaryNamespaces = primary.getMetadata().getNamespace(); if (primaryNamespaces != null) { - annotations.put( - Mappers.DEFAULT_ANNOTATION_FOR_NAMESPACE, primary.getMetadata().getNamespace()); + annotations.put(namespaceKey, primary.getMetadata().getNamespace()); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/SecondaryToPrimaryMapper.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/SecondaryToPrimaryMapper.java index 45573542c2..7b8853b4ae 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/SecondaryToPrimaryMapper.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/SecondaryToPrimaryMapper.java @@ -6,5 +6,5 @@ @FunctionalInterface public interface SecondaryToPrimaryMapper { - Set toPrimaryResourceIDs(R dependentResource); + Set toPrimaryResourceIDs(R resource); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentCustomMappingAnnotationIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentCustomMappingAnnotationIT.java new file mode 100644 index 0000000000..8a7d168b26 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentCustomMappingAnnotationIT.java @@ -0,0 +1,72 @@ +package io.javaoperatorsdk.operator; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.dependentcustommappingannotation.CustomMappingConfigMapDependentResource; +import io.javaoperatorsdk.operator.sample.dependentcustommappingannotation.DependentCustomMappingCustomResource; +import io.javaoperatorsdk.operator.sample.dependentcustommappingannotation.DependentCustomMappingReconciler; +import io.javaoperatorsdk.operator.sample.dependentcustommappingannotation.DependentCustomMappingSpec; + +import static io.javaoperatorsdk.operator.sample.dependentcustommappingannotation.CustomMappingConfigMapDependentResource.CUSTOM_NAMESPACE_KEY; +import static io.javaoperatorsdk.operator.sample.dependentcustommappingannotation.CustomMappingConfigMapDependentResource.CUSTOM_NAME_KEY; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +class DependentCustomMappingAnnotationIT { + + public static final String INITIAL_VALUE = "initial value"; + public static final String CHANGED_VALUE = "changed value"; + public static final String TEST_RESOURCE_NAME = "test1"; + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(DependentCustomMappingReconciler.class) + .build(); + + + @Test + void testCustomMappingAnnotationForDependent() { + var cr = extension.create(testResource()); + assertConfigMapData(INITIAL_VALUE); + + cr.getSpec().setValue(CHANGED_VALUE); + cr = extension.replace(cr); + assertConfigMapData(CHANGED_VALUE); + + extension.delete(cr); + + await().untilAsserted(() -> { + var resource = extension.get(ConfigMap.class, TEST_RESOURCE_NAME); + assertThat(resource).isNull(); + }); + } + + private void assertConfigMapData(String val) { + await().untilAsserted(() -> { + var resource = extension.get(ConfigMap.class, TEST_RESOURCE_NAME); + assertThat(resource).isNotNull(); + assertThat(resource.getMetadata().getAnnotations()) + .containsKey(CUSTOM_NAME_KEY) + .containsKey(CUSTOM_NAMESPACE_KEY); + assertThat(resource.getData()).containsEntry(CustomMappingConfigMapDependentResource.KEY, + val); + }); + } + + + DependentCustomMappingCustomResource testResource() { + var dr = new DependentCustomMappingCustomResource(); + dr.setMetadata(new ObjectMetaBuilder().withName(TEST_RESOURCE_NAME).build()); + dr.setSpec(new DependentCustomMappingSpec()); + dr.getSpec().setValue(INITIAL_VALUE); + + return dr; + } + + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/CustomMappingConfigMapDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/CustomMappingConfigMapDependentResource.java new file mode 100644 index 0000000000..123d360068 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/CustomMappingConfigMapDependentResource.java @@ -0,0 +1,52 @@ +package io.javaoperatorsdk.operator.sample.dependentcustommappingannotation; + +import java.util.Map; +import java.util.Set; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDNoGCKubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; +import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; + +public class CustomMappingConfigMapDependentResource + extends CRUDNoGCKubernetesDependentResource + implements SecondaryToPrimaryMapper { + + public static final String CUSTOM_NAME_KEY = "customNameKey"; + public static final String CUSTOM_NAMESPACE_KEY = "customNamespaceKey"; + public static final String KEY = "key"; + + private SecondaryToPrimaryMapper mapper = + Mappers.fromAnnotation(CUSTOM_NAME_KEY, CUSTOM_NAMESPACE_KEY); + + public CustomMappingConfigMapDependentResource() { + super(ConfigMap.class); + } + + @Override + protected ConfigMap desired(DependentCustomMappingCustomResource primary, + Context context) { + return new ConfigMapBuilder() + .withMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()) + .withData(Map.of(KEY, primary.getSpec().getValue())) + .build(); + } + + @Override + public Set toPrimaryResourceIDs(ConfigMap resource) { + return mapper.toPrimaryResourceIDs(resource); + } + + @Override + protected void addSecondaryToPrimaryMapperAnnotations(ConfigMap desired, + DependentCustomMappingCustomResource primary) { + addSecondaryToPrimaryMapperAnnotations(desired, primary, CUSTOM_NAME_KEY, CUSTOM_NAMESPACE_KEY); + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/DependentCustomMappingCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/DependentCustomMappingCustomResource.java new file mode 100644 index 0000000000..47776ed1e7 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/DependentCustomMappingCustomResource.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.sample.dependentcustommappingannotation; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +public class DependentCustomMappingCustomResource + extends CustomResource + implements Namespaced { + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/DependentCustomMappingReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/DependentCustomMappingReconciler.java new file mode 100644 index 0000000000..8c14f829ff --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/DependentCustomMappingReconciler.java @@ -0,0 +1,20 @@ +package io.javaoperatorsdk.operator.sample.dependentcustommappingannotation; + +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; + +@ControllerConfiguration( + dependents = {@Dependent(type = CustomMappingConfigMapDependentResource.class)}) +public class DependentCustomMappingReconciler + implements Reconciler { + + @Override + public UpdateControl reconcile( + DependentCustomMappingCustomResource resource, + Context context) throws Exception { + + return UpdateControl.noUpdate(); + } + + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/DependentCustomMappingSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/DependentCustomMappingSpec.java new file mode 100644 index 0000000000..bc5b92901f --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentcustommappingannotation/DependentCustomMappingSpec.java @@ -0,0 +1,15 @@ +package io.javaoperatorsdk.operator.sample.dependentcustommappingannotation; + +public class DependentCustomMappingSpec { + + private String value; + + public String getValue() { + return value; + } + + public DependentCustomMappingSpec setValue(String value) { + this.value = value; + return this; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/primaryindexer/DependentPrimaryIndexerTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/primaryindexer/DependentPrimaryIndexerTestReconciler.java index e123500c42..89b2a43700 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/primaryindexer/DependentPrimaryIndexerTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/primaryindexer/DependentPrimaryIndexerTestReconciler.java @@ -31,8 +31,8 @@ public ReadOnlyConfigMapDependent() { } @Override - public Set toPrimaryResourceIDs(ConfigMap dependentResource) { - return cache.byIndex(CONFIG_MAP_RELATION_INDEXER, dependentResource.getMetadata().getName()) + public Set toPrimaryResourceIDs(ConfigMap resource) { + return cache.byIndex(CONFIG_MAP_RELATION_INDEXER, resource.getMetadata().getName()) .stream() .map(ResourceID::fromResource) .collect(Collectors.toSet()); diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java index 1aa2ad62e5..edaa5707ee 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java @@ -61,9 +61,9 @@ public Result match(Secret actual, MySQLSchema primary, Context toPrimaryResourceIDs(Secret dependentResource) { - String name = dependentResource.getMetadata().getName(); + public Set toPrimaryResourceIDs(Secret resource) { + String name = resource.getMetadata().getName(); return Set.of(new ResourceID(name.substring(0, name.length() - SECRET_SUFFIX.length()), - dependentResource.getMetadata().getNamespace())); + resource.getMetadata().getNamespace())); } } From 22237a03135be4954fe55fa0cdd4353e69206e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 5 Oct 2023 11:46:03 +0200 Subject: [PATCH 046/644] 4.5 release notes (#2077) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros Signed-off-by: Chris Laprun Co-authored-by: Chris Laprun --- docs/_data/sidebar.yml | 4 +++- docs/documentation/v4-5-migration.md | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 docs/documentation/v4-5-migration.md diff --git a/docs/_data/sidebar.yml b/docs/_data/sidebar.yml index d2572f5734..8c083a6cc1 100644 --- a/docs/_data/sidebar.yml +++ b/docs/_data/sidebar.yml @@ -30,4 +30,6 @@ - title: Migrating from v4.2 to v4.3 url: /docs/v4-3-migration - title: Migrating from v4.3 to v4.4 - url: /docs/v4-4-migration \ No newline at end of file + url: /docs/v4-4-migration + - title: Migrating from v4.4 to v4.5 + url: /docs/v4-5-migration \ No newline at end of file diff --git a/docs/documentation/v4-5-migration.md b/docs/documentation/v4-5-migration.md new file mode 100644 index 0000000000..0ff08eef13 --- /dev/null +++ b/docs/documentation/v4-5-migration.md @@ -0,0 +1,26 @@ +--- +title: Migrating from v4.4 to v4.5 +description: Migrating from v4.4 to v4.5 +layout: docs +permalink: /docs/v4-5-migration +--- + +# Migrating from v4.4 to v4.5 + +Version 4.5 introduces improvements related to event handling for Dependent Resources, more precisely the +[caching and event handling](https://javaoperatorsdk.io/docs/dependent-resources#caching-and-event-handling-in-kubernetesdependentresource) +features. As a result the Kubernetes resources managed using +[KubernetesDependentResource](https://github.com/java-operator-sdk/java-operator-sdk/blob/73b1d8db926a24502c3a70da34f6bcac4f66b4eb/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java#L72-L72) +or its subclasses, will add an annotation recording the resource's version whenever JOSDK updates or creates such +resources. This can be turned off using a +[feature flag](https://github.com/java-operator-sdk/java-operator-sdk/blob/73b1d8db926a24502c3a70da34f6bcac4f66b4eb/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L375-L375) +if causes some issues in your use case. + +Using this feature, JOSDK now tracks versions of cached resources. It also uses, by default, that information to prevent +unneeded reconciliations that could occur when, depending on the timing of operations, an outdated resource would happen +to be in the cache. This relies on the fact that versions (as recorded by the `metadata.resourceVersion` field) are +currently implemented as monotonically increasing integers (though they should be considered as opaque and their +interpretation discouraged). Note that, while this helps preventing unneeded reconciliations, things would eventually +reach consistency even in the absence of this feature. Also, if this interpreting of the resource versions causes +issues, you can turn the feature off using the +[following feature flag](https://github.com/java-operator-sdk/java-operator-sdk/blob/73b1d8db926a24502c3a70da34f6bcac4f66b4eb/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L390-L390). From 7af5730cb3f423d3074c428a33eeee6839cc5d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 12 Oct 2023 13:57:45 +0200 Subject: [PATCH 047/644] Pure Java Project Generator (#2083) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/pr.yml | 2 +- bootstrapper-maven-plugin/pom.xml | 95 +++++++++++++ .../operator/bootstrapper/Versions.java | 10 ++ .../boostrapper/Bootstrapper.java | 134 ++++++++++++++++++ .../boostrapper/BootstrapperMojo.java | 25 ++++ .../src/main/resources/log4j2.xml | 16 +++ .../src/main/resources/static/.gitignore | 41 ++++++ .../src/main/resources/static/README.md | 3 + .../templates/ConfigMapDependentResource.java | 34 +++++ .../resources/templates/CustomResource.java | 11 ++ .../main/resources/templates/Reconciler.java | 28 ++++ .../src/main/resources/templates/Runner.java | 18 +++ .../src/main/resources/templates/Spec.java | 14 ++ .../src/main/resources/templates/Status.java | 7 + .../templates/k8s/test-resource.yaml | 6 + .../src/main/resources/templates/log4j2.xml | 16 +++ .../src/main/resources/templates/pom.xml | 92 ++++++++++++ .../bootstrapper/BootstrapperTest.java | 50 +++++++ operator-framework/pom.xml | 9 +- pom.xml | 21 ++- 20 files changed, 624 insertions(+), 8 deletions(-) create mode 100644 bootstrapper-maven-plugin/pom.xml create mode 100644 bootstrapper-maven-plugin/src/main/java-templates/io/javaoperatorsdk/operator/bootstrapper/Versions.java create mode 100644 bootstrapper-maven-plugin/src/main/java/io/javaoperatorsdk/boostrapper/Bootstrapper.java create mode 100644 bootstrapper-maven-plugin/src/main/java/io/javaoperatorsdk/boostrapper/BootstrapperMojo.java create mode 100644 bootstrapper-maven-plugin/src/main/resources/log4j2.xml create mode 100644 bootstrapper-maven-plugin/src/main/resources/static/.gitignore create mode 100644 bootstrapper-maven-plugin/src/main/resources/static/README.md create mode 100644 bootstrapper-maven-plugin/src/main/resources/templates/ConfigMapDependentResource.java create mode 100644 bootstrapper-maven-plugin/src/main/resources/templates/CustomResource.java create mode 100644 bootstrapper-maven-plugin/src/main/resources/templates/Reconciler.java create mode 100644 bootstrapper-maven-plugin/src/main/resources/templates/Runner.java create mode 100644 bootstrapper-maven-plugin/src/main/resources/templates/Spec.java create mode 100644 bootstrapper-maven-plugin/src/main/resources/templates/Status.java create mode 100644 bootstrapper-maven-plugin/src/main/resources/templates/k8s/test-resource.yaml create mode 100644 bootstrapper-maven-plugin/src/main/resources/templates/log4j2.xml create mode 100644 bootstrapper-maven-plugin/src/main/resources/templates/pom.xml create mode 100644 bootstrapper-maven-plugin/src/test/java/io/javaoperatorsdk/bootstrapper/BootstrapperTest.java diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 44281a2b4b..47fd168516 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -29,7 +29,7 @@ jobs: ./mvnw ${MAVEN_ARGS} formatter:validate -Dconfigfile=$PWD/contributing/eclipse-google-style.xml -pl '!operator-framework-bom' --file pom.xml ./mvnw ${MAVEN_ARGS} impsort:check -pl '!operator-framework-bom' --file pom.xml - name: Run unit tests - run: ./mvnw ${MAVEN_ARGS} -B test --file pom.xml + run: ./mvnw ${MAVEN_ARGS} clean install --file pom.xml integration_tests: strategy: diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml new file mode 100644 index 0000000000..42de1fd6c5 --- /dev/null +++ b/bootstrapper-maven-plugin/pom.xml @@ -0,0 +1,95 @@ + + 4.0.0 + + + java-operator-sdk + io.javaoperatorsdk + 4.5.0-SNAPSHOT + + + bootstrapper + maven-plugin + Operator SDK - Bootstrapper Maven Plugin + Operator SDK - Bootstrapper Maven Plugin + + + 3.9.0 + 3.9.5 + + + + + org.apache.maven + maven-plugin-api + ${maven-plugin-api.version} + provided + + + org.apache.maven.plugin-tools + maven-plugin-annotations + ${maven-plugin-annotations.version} + provided + + + org.slf4j + slf4j-api + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core + test + + + org.junit.jupiter + junit-jupiter-api + + + org.junit.jupiter + junit-jupiter-engine + + + commons-io + commons-io + 2.14.0 + + + com.github.spullara.mustache.java + compiler + + + org.assertj + assertj-core + test + + + + + + + org.apache.maven.plugins + maven-plugin-plugin + 3.9.0 + + + org.codehaus.mojo + templating-maven-plugin + 1.0.0 + + + filtering-java-templates + + filter-sources + + + + + + + + diff --git a/bootstrapper-maven-plugin/src/main/java-templates/io/javaoperatorsdk/operator/bootstrapper/Versions.java b/bootstrapper-maven-plugin/src/main/java-templates/io/javaoperatorsdk/operator/bootstrapper/Versions.java new file mode 100644 index 0000000000..1656ee28f7 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/java-templates/io/javaoperatorsdk/operator/bootstrapper/Versions.java @@ -0,0 +1,10 @@ +package io.javaoperatorsdk.bootstrapper; + +public final class Versions { + + private Versions() {} + + public static final String JOSDK = "${project.version}"; + public static final String KUBERNETES_CLIENT = "${fabric8-client.version}"; + +} diff --git a/bootstrapper-maven-plugin/src/main/java/io/javaoperatorsdk/boostrapper/Bootstrapper.java b/bootstrapper-maven-plugin/src/main/java/io/javaoperatorsdk/boostrapper/Bootstrapper.java new file mode 100644 index 0000000000..56f6f00f5a --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/java/io/javaoperatorsdk/boostrapper/Bootstrapper.java @@ -0,0 +1,134 @@ +package io.javaoperatorsdk.boostrapper; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.javaoperatorsdk.bootstrapper.Versions; + +import com.github.mustachejava.DefaultMustacheFactory; +import com.github.mustachejava.MustacheFactory; + +public class Bootstrapper { + + private static final Logger log = LoggerFactory.getLogger(Bootstrapper.class); + + private MustacheFactory mustacheFactory = new DefaultMustacheFactory(); + + private static final List TOP_LEVEL_STATIC_FILES = + List.of(".gitignore", "README.md"); + private static final List JAVA_FILES = + List.of("CustomResource.java", "Reconciler.java", + "Spec.java", "Status.java"); + + public void create(File targetDir, String groupId, String artifactId) { + try { + log.info("Generating project to: {}", targetDir.getPath()); + var projectDir = new File(targetDir, artifactId); + FileUtils.forceMkdir(projectDir); + addStaticFiles(projectDir); + addTemplatedFiles(projectDir, groupId, artifactId); + addJavaFiles(projectDir, groupId, artifactId); + addResourceFiles(projectDir, groupId, artifactId); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void addResourceFiles(File projectDir, String groupId, String artifactId) { + try { + var target = new File(projectDir, "src/main/resources"); + FileUtils.forceMkdir(target); + addTemplatedFile(target, "log4j2.xml", groupId, artifactId, target, null); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void addJavaFiles(File projectDir, String groupId, String artifactId) { + try { + var packages = groupId.replace(".", File.separator); + var targetDir = new File(projectDir, "src/main/java/" + packages); + FileUtils.forceMkdir(targetDir); + var classFileNamePrefix = artifactClassId(artifactId); + JAVA_FILES.forEach(f -> addTemplatedFile(projectDir, f, groupId, artifactId, targetDir, + classFileNamePrefix + f)); + + addTemplatedFile(projectDir, "Runner.java", groupId, artifactId, targetDir, null); + addTemplatedFile(projectDir, "ConfigMapDependentResource.java", groupId, artifactId, + targetDir, null); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + + private void addTemplatedFiles(File projectDir, String groupId, String artifactId) { + addTemplatedFile(projectDir, "pom.xml", groupId, artifactId); + addTemplatedFile(projectDir, "k8s/test-resource.yaml", groupId, artifactId); + } + + private void addTemplatedFile(File projectDir, String fileName, String groupId, + String artifactId) { + addTemplatedFile(projectDir, fileName, groupId, artifactId, null, null); + } + + private void addTemplatedFile(File projectDir, String fileName, String groupId, String artifactId, + File targetDir, String targetFileName) { + try { + var values = Map.of("groupId", groupId, "artifactId", artifactId, + "artifactClassId", artifactClassId(artifactId), + "josdkVersion", Versions.JOSDK, + "fabric8Version", Versions.KUBERNETES_CLIENT); + + var mustache = mustacheFactory.compile("templates/" + fileName); + var targetFile = new File(targetDir == null ? projectDir : targetDir, + targetFileName == null ? fileName : targetFileName); + FileUtils.forceMkdir(targetFile.getParentFile()); + var writer = new FileWriter(targetFile); + mustache.execute(writer, values); + writer.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void addStaticFiles(File projectDir) { + TOP_LEVEL_STATIC_FILES.forEach(f -> addStaticFile(projectDir, f)); + } + + private void addStaticFile(File targetDir, String fileName) { + addStaticFile(targetDir, fileName, null); + } + + private void addStaticFile(File targetDir, String fileName, String subDir) { + String sourcePath = subDir == null ? "/static/" : "/static/" + subDir; + String path = sourcePath + fileName; + try (var is = Bootstrapper.class.getResourceAsStream(path)) { + targetDir = subDir == null ? targetDir : new File(targetDir, subDir); + if (subDir != null) { + FileUtils.forceMkdir(targetDir); + } + FileUtils.copyInputStreamToFile(is, new File(targetDir, fileName)); + } catch (IOException e) { + throw new RuntimeException("File path: " + path, e); + } + + } + + public static String artifactClassId(String artifactId) { + var parts = artifactId.split("-"); + return Arrays.stream(parts).map(p -> p.substring(0, 1) + .toUpperCase() + p.substring(1)) + .collect(Collectors.joining("")); + } + +} diff --git a/bootstrapper-maven-plugin/src/main/java/io/javaoperatorsdk/boostrapper/BootstrapperMojo.java b/bootstrapper-maven-plugin/src/main/java/io/javaoperatorsdk/boostrapper/BootstrapperMojo.java new file mode 100644 index 0000000000..0d87a152e2 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/java/io/javaoperatorsdk/boostrapper/BootstrapperMojo.java @@ -0,0 +1,25 @@ +package io.javaoperatorsdk.boostrapper; + +import java.io.File; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; + +@Mojo(name = "create", requiresProject = false) +public class BootstrapperMojo + extends AbstractMojo { + + @Parameter(defaultValue = "${projectGroupId}") + protected String projectGroupId; + + @Parameter(defaultValue = "${projectArtifactId}") + protected String projectArtifactId; + + public void execute() + throws MojoExecutionException { + String userDir = System.getProperty("user.dir"); + new Bootstrapper().create(new File(userDir), projectGroupId, projectArtifactId); + } +} diff --git a/bootstrapper-maven-plugin/src/main/resources/log4j2.xml b/bootstrapper-maven-plugin/src/main/resources/log4j2.xml new file mode 100644 index 0000000000..124aef7838 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/log4j2.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/bootstrapper-maven-plugin/src/main/resources/static/.gitignore b/bootstrapper-maven-plugin/src/main/resources/static/.gitignore new file mode 100644 index 0000000000..9a6a0350f2 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/static/.gitignore @@ -0,0 +1,41 @@ +#Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +release.properties +.flattened-pom.xml + +# Eclipse +.project +.classpath +.settings/ +bin/ + +# IntelliJ +.idea +*.ipr +*.iml +*.iws + +# NetBeans +nb-configuration.xml + +# Visual Studio Code +.vscode +.factorypath + +# OSX +.DS_Store + +# Vim +*.swp +*.swo + +# patch +*.orig +*.rej + +# Local environment +.env + diff --git a/bootstrapper-maven-plugin/src/main/resources/static/README.md b/bootstrapper-maven-plugin/src/main/resources/static/README.md new file mode 100644 index 0000000000..7746a9a5d2 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/static/README.md @@ -0,0 +1,3 @@ +# Generated Project Skeleton + +A simple operator that copies the value in a spec to a ConfigMap. \ No newline at end of file diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/ConfigMapDependentResource.java b/bootstrapper-maven-plugin/src/main/resources/templates/ConfigMapDependentResource.java new file mode 100644 index 0000000000..ed28771081 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/templates/ConfigMapDependentResource.java @@ -0,0 +1,34 @@ +package {{groupId}}; + +import java.util.HashMap; +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; +import {{groupId}}.{{artifactClassId}}CustomResource; + +@KubernetesDependent +public class ConfigMapDependentResource + extends CRUDKubernetesDependentResource { + + public ConfigMapDependentResource() { + super(ConfigMap.class); + } + + @Override + protected ConfigMap desired({{artifactClassId}}CustomResource primary, + Context<{{artifactClassId}}CustomResource> context) { + return new ConfigMapBuilder() + .withMetadata( + new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()) + .withData(Map.of("data", primary.getSpec().getValue())) + .build(); + } +} \ No newline at end of file diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/CustomResource.java b/bootstrapper-maven-plugin/src/main/resources/templates/CustomResource.java new file mode 100644 index 0000000000..e17dcc0450 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/templates/CustomResource.java @@ -0,0 +1,11 @@ +package {{groupId}}; + +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("{{groupId}}") +@Version("v1") +public class {{artifactClassId}}CustomResource extends CustomResource<{{artifactClassId}}Spec,{{artifactClassId}}Status> implements Namespaced { +} diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/Reconciler.java b/bootstrapper-maven-plugin/src/main/resources/templates/Reconciler.java new file mode 100644 index 0000000000..03ac06f882 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/templates/Reconciler.java @@ -0,0 +1,28 @@ +package {{groupId}}; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; +import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; + +import java.util.Map; +import java.util.Optional; + +@ControllerConfiguration(dependents = {@Dependent(type = ConfigMapDependentResource.class)}) +public class {{artifactClassId}}Reconciler implements Reconciler<{{artifactClassId}}CustomResource> { + + public UpdateControl<{{artifactClassId}}CustomResource> reconcile({{artifactClassId}}CustomResource primary, + Context<{{artifactClassId}}CustomResource> context) { + + return UpdateControl.noUpdate(); + } +} diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/Runner.java b/bootstrapper-maven-plugin/src/main/resources/templates/Runner.java new file mode 100644 index 0000000000..41be6d6976 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/templates/Runner.java @@ -0,0 +1,18 @@ +package {{groupId}}; + +import io.javaoperatorsdk.operator.Operator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class Runner { + + private static final Logger log = LoggerFactory.getLogger(Runner.class); + + public static void main(String[] args) { + Operator operator = new Operator(); + operator.register(new {{artifactClassId}}Reconciler()); + operator.start(); + log.info("Operator started."); + } +} diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/Spec.java b/bootstrapper-maven-plugin/src/main/resources/templates/Spec.java new file mode 100644 index 0000000000..13d82dad51 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/templates/Spec.java @@ -0,0 +1,14 @@ +package {{groupId}}; + +public class {{artifactClassId}}Spec { + + private String value; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/Status.java b/bootstrapper-maven-plugin/src/main/resources/templates/Status.java new file mode 100644 index 0000000000..4c37b99947 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/templates/Status.java @@ -0,0 +1,7 @@ +package {{groupId}}; + +import io.javaoperatorsdk.operator.api.ObservedGenerationAwareStatus; + +public class {{artifactClassId}}Status extends ObservedGenerationAwareStatus { + +} diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/k8s/test-resource.yaml b/bootstrapper-maven-plugin/src/main/resources/templates/k8s/test-resource.yaml new file mode 100644 index 0000000000..ec7987512e --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/templates/k8s/test-resource.yaml @@ -0,0 +1,6 @@ +apiVersion: {{groupId}}/v1 +kind: {{artifactClassId}}CustomResource +metadata: + name: test1 +spec: + value: test \ No newline at end of file diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/log4j2.xml b/bootstrapper-maven-plugin/src/main/resources/templates/log4j2.xml new file mode 100644 index 0000000000..9fde311940 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/templates/log4j2.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/pom.xml b/bootstrapper-maven-plugin/src/main/resources/templates/pom.xml new file mode 100644 index 0000000000..4bdacf1f03 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/templates/pom.xml @@ -0,0 +1,92 @@ + + + 4.0.0 + + {{groupId}} + {{artifactId}} + 0.1.0-SNAPSHOT + sample-webpage-operator + jar + + + 11 + ${java.version} + ${java.version} + {{josdkVersion}} + 1.7.36 + 5.9.2 + 2.20.0 + {{fabric8Version}} + + + + + + io.javaoperatorsdk + operator-framework-bom + ${josdk.version} + pom + import + + + + + + + io.javaoperatorsdk + operator-framework + ${josdk.version} + + + io.fabric8 + crd-generator-apt + ${fabric8-client.version} + provided + + + io.javaoperatorsdk + operator-framework-junit-5 + ${josdk.version} + test + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.apache.logging.log4j + log4j-slf4j-impl + ${log4j.version} + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + org.junit.jupiter + junit-jupiter-api + test + ${junit.version} + + + org.junit.jupiter + junit-jupiter-engine + test + ${junit.version} + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + + + + \ No newline at end of file diff --git a/bootstrapper-maven-plugin/src/test/java/io/javaoperatorsdk/bootstrapper/BootstrapperTest.java b/bootstrapper-maven-plugin/src/test/java/io/javaoperatorsdk/bootstrapper/BootstrapperTest.java new file mode 100644 index 0000000000..b0a97d76c0 --- /dev/null +++ b/bootstrapper-maven-plugin/src/test/java/io/javaoperatorsdk/bootstrapper/BootstrapperTest.java @@ -0,0 +1,50 @@ +package io.javaoperatorsdk.bootstrapper; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; + +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.javaoperatorsdk.boostrapper.Bootstrapper; + +import static org.assertj.core.api.Assertions.assertThat; + +class BootstrapperTest { + + private static final Logger log = LoggerFactory.getLogger(BootstrapperTest.class); + + Bootstrapper bootstrapper = new Bootstrapper(); + + @Test + void copiesFilesToTarget() { + bootstrapper.create(new File("target"), "io.sample", "test-project"); + + var targetDir = new File("target", "test-project"); + assertThat(targetDir.list()).contains("pom.xml"); + assertProjectCompiles(); + } + + private void assertProjectCompiles() { + try { + var process = Runtime.getRuntime() + .exec("mvn clean install -f target/test-project/pom.xml"); + + BufferedReader stdOut = new BufferedReader(new InputStreamReader(process.getInputStream())); + + log.info("Maven output:"); + String logLine; + while ((logLine = stdOut.readLine()) != null) { + log.info(logLine); + } + var res = process.waitFor(); + log.info("exit code: {}", res); + assertThat(res).isZero(); + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index 2b74b5e91f..f4f2f498b3 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -25,15 +25,15 @@ org.apache.commons commons-lang3 - - org.slf4j - slf4j-api - com.squareup javapoet compile + + org.slf4j + slf4j-api + org.junit.jupiter junit-jupiter-api @@ -72,7 +72,6 @@ org.apache.logging.log4j log4j-core - ${log4j.version} test diff --git a/pom.xml b/pom.xml index 49a4f12375..1f2918946a 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,8 @@ 4.10.0 3.1.3 0.9.0 + 0.9.10 + 2.14.0 2.11 3.11.0 @@ -85,6 +87,7 @@ micrometer-support sample-operators caffeine-bounded-cache-support + bootstrapper-maven-plugin @@ -140,7 +143,11 @@ awaitility ${awaitility.version} - + + commons-io + commons-io + ${commons.io.version} + org.assertj assertj-core @@ -162,12 +169,22 @@ log4j-slf4j-impl ${log4j.version} + + org.apache.logging.log4j + log4j-core + ${log4j.version} + test + org.apache.logging.log4j log4j2-core ${log4j.version} - + + com.github.spullara.mustache.java + compiler + ${mustache.version} + io.javaoperatorsdk operator-framework-core From 0ed29a0d22a13977b61012d2635b5e62fb91256f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 12 Oct 2023 15:36:04 +0200 Subject: [PATCH 048/644] docs: getting started update with mvn plugin (#2090) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- docs/documentation/getting-started.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/documentation/getting-started.md b/docs/documentation/getting-started.md index a67f58a318..705a23215d 100644 --- a/docs/documentation/getting-started.md +++ b/docs/documentation/getting-started.md @@ -25,6 +25,14 @@ You can also refer to the [Writing Kubernetes operators using JOSDK blog series](https://developers.redhat.com/articles/2022/02/15/write-kubernetes-java-java-operator-sdk) . +## Generating Project Skeleton + +Project includes a maven plugin to generate a skeleton project: + +```shell +mvn io.javaoperatorsdk:bootstrapper:[version]:create -DprojectGroupId=org.acme -DprojectArtifactId=getting-started +``` + ## Getting Started The easiest way to get started with SDK is to start From cb18124ce8a9838441e917fa562f753dbe984c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 12 Oct 2023 21:36:34 +0200 Subject: [PATCH 049/644] fix: snapshot build (#2089) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/snapshot-releases.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/snapshot-releases.yml b/.github/workflows/snapshot-releases.yml index 71cf119b25..2df39ceba0 100644 --- a/.github/workflows/snapshot-releases.yml +++ b/.github/workflows/snapshot-releases.yml @@ -23,8 +23,8 @@ jobs: distribution: temurin java-version: 11 cache: 'maven' - - name: Run unit tests - run: ./mvnw ${MAVEN_ARGS} -B test --file pom.xml + - name: Build and test project + run: ./mvnw ${MAVEN_ARGS} clean install --file pom.xml release-snapshot: runs-on: ubuntu-latest needs: test From ec48decaf0242c3034d51a1e25d671f7fd27aac3 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Tue, 17 Oct 2023 13:59:15 +0200 Subject: [PATCH 050/644] refactor: remove now unneeded KubernetesClientAware (#2084) --- .../cache/sample/AbstractTestReconciler.java | 34 ++++++----------- .../managed/KubernetesClientAware.java | 6 +++ .../AbstractExternalDependentResource.java | 23 ++---------- .../DependentResourceWithExplicitState.java | 3 +- .../KubernetesDependentResource.java | 33 +++++------------ .../informer/ManagedInformerEventSource.java | 1 - .../operator/junit/KubernetesClientAware.java | 6 +++ .../junit/LocallyRunOperatorExtension.java | 4 -- .../operator/DependentReInitializationIT.java | 2 +- .../operator/DependentSSAMigrationIT.java | 5 +-- .../operator/OperatorRestartIT.java | 15 +++----- ...ConfigMapDeleterBulkDependentResource.java | 2 +- .../StandaloneBulkDependentReconciler.java | 16 +------- .../ChangeNamespaceTestReconciler.java | 17 +-------- ...ClusterScopedCustomResourceReconciler.java | 17 +-------- ...CreateUpdateEventFilterTestReconciler.java | 30 ++------------- .../DependentReInitializationReconciler.java | 5 +-- .../dependentssa/DependentSSAReconciler.java | 15 -------- .../ExternalStateReconciler.java | 37 +++++-------------- .../sample/filter/FilterTestReconciler.java | 18 +-------- .../IndexDiscriminatorTestReconciler.java | 18 +-------- ...endentGarbageCollectionTestReconciler.java | 14 +------ .../MultipleDependentResourceReconciler.java | 18 +-------- ...ultipleSecondaryEventSourceReconciler.java | 16 +------- ...ourcePollingEventSourceTestReconciler.java | 17 +-------- .../sample/simple/TestReconciler.java | 20 ++-------- .../StandaloneDependentTestReconciler.java | 26 +------------ .../ConfigMapDependentResource.java | 2 +- .../WebPageDependentsWorkflowReconciler.java | 14 +------ ...WebPageStandaloneDependentsReconciler.java | 1 - 30 files changed, 80 insertions(+), 355 deletions(-) diff --git a/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/AbstractTestReconciler.java b/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/AbstractTestReconciler.java index 835fcef91a..b6e3ba2c8f 100644 --- a/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/AbstractTestReconciler.java +++ b/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/AbstractTestReconciler.java @@ -6,14 +6,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.fabric8.kubernetes.api.model.*; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.client.CustomResource; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.cache.BoundedItemStore; import io.javaoperatorsdk.operator.processing.event.source.cache.CaffeineBoundedItemStores; @@ -27,38 +28,35 @@ import com.github.benmanes.caffeine.cache.Caffeine; public abstract class AbstractTestReconciler

> - implements KubernetesClientAware, Reconciler

, - EventSourceInitializer

{ + implements Reconciler

, EventSourceInitializer

{ private static final Logger log = LoggerFactory.getLogger(BoundedCacheClusterScopeTestReconciler.class); public static final String DATA_KEY = "dataKey"; - protected KubernetesClient client; - @Override public UpdateControl

reconcile( P resource, Context

context) { var maybeConfigMap = context.getSecondaryResource(ConfigMap.class); maybeConfigMap.ifPresentOrElse( - cm -> updateConfigMapIfNeeded(cm, resource), - () -> createConfigMap(resource)); + cm -> updateConfigMapIfNeeded(cm, resource, context), + () -> createConfigMap(resource, context)); ensureStatus(resource); log.info("Reconciled: {}", resource.getMetadata().getName()); return UpdateControl.patchStatus(resource); } - protected void updateConfigMapIfNeeded(ConfigMap cm, P resource) { + protected void updateConfigMapIfNeeded(ConfigMap cm, P resource, Context

context) { var data = cm.getData().get(DATA_KEY); if (data == null || data.equals(resource.getSpec().getData())) { cm.setData(Map.of(DATA_KEY, resource.getSpec().getData())); - client.configMaps().resource(cm).replace(); + context.getClient().configMaps().resource(cm).replace(); } } - protected void createConfigMap(P resource) { + protected void createConfigMap(P resource, Context

context) { var cm = new ConfigMapBuilder() .withMetadata(new ObjectMetaBuilder() .withName(resource.getMetadata().getName()) @@ -67,17 +65,7 @@ protected void createConfigMap(P resource) { .withData(Map.of(DATA_KEY, resource.getSpec().getData())) .build(); cm.addOwnerReference(resource); - client.configMaps().resource(cm).create(); - } - - @Override - public KubernetesClient getKubernetesClient() { - return client; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.client = kubernetesClient; + context.getClient().configMaps().resource(cm).create(); } @Override diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/KubernetesClientAware.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/KubernetesClientAware.java index 2a28813c35..d6c743f22b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/KubernetesClientAware.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/KubernetesClientAware.java @@ -1,7 +1,13 @@ package io.javaoperatorsdk.operator.api.reconciler.dependent.managed; import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.api.reconciler.Context; +/** + * @deprecated It shouldn't be needed to pass a {@link KubernetesClient} instance anymore as the + * client should be accessed via {@link Context#getClient()} instead. + */ +@Deprecated(since = "4.5.0", forRemoval = true) public interface KubernetesClientAware { void setKubernetesClient(KubernetesClient kubernetesClient); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java index 18e6f41a92..4fb4c9bcd6 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java @@ -1,7 +1,6 @@ package io.javaoperatorsdk.operator.processing.dependent; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller; import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever; @@ -18,7 +17,6 @@ public abstract class AbstractExternalDependentResource externalStateEventSource; - private KubernetesClient kubernetesClient; @SuppressWarnings("unchecked") protected AbstractExternalDependentResource(Class resourceType) { @@ -65,14 +63,13 @@ public void delete(P primary, Context

context) { @SuppressWarnings({"unchecked", "unused"}) private void handleExplicitStateDelete(P primary, R secondary, Context

context) { var res = dependentResourceWithExplicitState.stateResource(primary, secondary); - dependentResourceWithExplicitState.getKubernetesClient().resource(res).delete(); + context.getClient().resource(res).delete(); } @SuppressWarnings({"rawtypes", "unchecked", "unused"}) protected void handleExplicitStateCreation(P primary, R created, Context

context) { var resource = dependentResourceWithExplicitState.stateResource(primary, created); - var stateResource = - dependentResourceWithExplicitState.getKubernetesClient().resource(resource).create(); + var stateResource = context.getClient().resource(resource).create(); if (externalStateEventSource != null) { ((RecentOperationCacheFiller) externalStateEventSource) .handleRecentResourceCreate(ResourceID.fromResource(primary), stateResource); @@ -84,7 +81,7 @@ protected void handleExplicitStateCreation(P primary, R created, Context

cont public void deleteTargetResource(P primary, R resource, String key, Context

context) { if (isDependentResourceWithExplicitState) { - getKubernetesClient() + context.getClient() .resource(dependentResourceWithExplicitState.stateResource(primary, resource)) .delete(); } @@ -100,18 +97,4 @@ public void handleDeleteTargetResource(P primary, R resource, String key, protected InformerEventSource getExternalStateEventSource() { return externalStateEventSource; } - - /** - * It's here just to manage the explicit state resource in case the dependent resource implements - * {@link RecentOperationCacheFiller}. - * - * @return kubernetes client. - */ - public KubernetesClient getKubernetesClient() { - return kubernetesClient; - } - - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.kubernetesClient = kubernetesClient; - } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceWithExplicitState.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceWithExplicitState.java index 284b215679..05206731db 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceWithExplicitState.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceWithExplicitState.java @@ -4,7 +4,6 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.dependent.Deleter; -import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.KubernetesClientAware; /** * Handles external resources where in order to address the resource additional information or @@ -14,7 +13,7 @@ * for a resource that extends {@link AbstractExternalDependentResource}. */ public interface DependentResourceWithExplicitState - extends Creator, Deleter

, KubernetesClientAware { + extends Creator, Deleter

{ /** * Only needs to be implemented if multiple event sources are present for the target resource diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 912d876aba..b587c72327 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -8,7 +8,6 @@ import org.slf4j.LoggerFactory; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.Resource; import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.api.config.dependent.Configured; @@ -19,7 +18,6 @@ import io.javaoperatorsdk.operator.api.reconciler.Ignore; import io.javaoperatorsdk.operator.api.reconciler.dependent.GarbageCollected; import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.DependentResourceConfigurator; -import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.dependent.AbstractEventSourceHolderDependentResource; import io.javaoperatorsdk.operator.processing.dependent.Matcher.Result; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher.GenericResourceUpdaterMatcher; @@ -33,17 +31,14 @@ converter = KubernetesDependentConverter.class) public abstract class KubernetesDependentResource extends AbstractEventSourceHolderDependentResource> - implements KubernetesClientAware, - DependentResourceConfigurator> { + implements DependentResourceConfigurator> { private static final Logger log = LoggerFactory.getLogger(KubernetesDependentResource.class); - - protected KubernetesClient client; private final ResourceUpdaterMatcher updaterMatcher; private final boolean garbageCollected = this instanceof GarbageCollected; private KubernetesDependentResourceConfig kubernetesDependentResourceConfig; - private boolean usingCustomResourceUpdateMatcher; + private final boolean usingCustomResourceUpdateMatcher; @SuppressWarnings("unchecked") public KubernetesDependentResource(Class resourceType) { @@ -117,7 +112,7 @@ public R create(R desired, P primary, Context

context) { } } addMetadata(false, null, desired, primary, context); - final var resource = prepare(desired, primary, "Creating"); + final var resource = prepare(context, desired, primary, "Creating"); return useSSA(context) ? resource .fieldManager(context.getControllerConfiguration().fieldManager()) @@ -134,12 +129,12 @@ public R update(R actual, R desired, P primary, Context

context) { R updatedResource; addMetadata(false, actual, desired, primary, context); if (useSSA(context)) { - updatedResource = prepare(desired, primary, "Updating") + updatedResource = prepare(context, desired, primary, "Updating") .fieldManager(context.getControllerConfiguration().fieldManager()) .forceConflicts().serverSideApply(); } else { var updatedActual = updaterMatcher.updateResource(actual, desired, context); - updatedResource = prepare(updatedActual, primary, "Updating").update(); + updatedResource = prepare(context, updatedActual, primary, "Updating").update(); } log.debug("Resource version after update: {}", updatedResource.getMetadata().getResourceVersion()); @@ -216,23 +211,23 @@ private boolean usePreviousAnnotation(Context

context) { @Override protected void handleDelete(P primary, R secondary, Context

context) { if (secondary != null) { - client.resource(secondary).delete(); + context.getClient().resource(secondary).delete(); } } @SuppressWarnings("unused") public void deleteTargetResource(P primary, R resource, String key, Context

context) { - client.resource(resource).delete(); + context.getClient().resource(resource).delete(); } @SuppressWarnings("unused") - protected Resource prepare(R desired, P primary, String actionName) { + protected Resource prepare(Context

context, R desired, P primary, String actionName) { log.debug("{} target resource with type: {}, with id: {}", actionName, desired.getClass(), ResourceID.fromResource(desired)); - return client.resource(desired); + return context.getClient().resource(desired); } protected void addReferenceHandlingMetadata(R desired, P primary) { @@ -292,16 +287,6 @@ protected boolean addOwnerReference() { return garbageCollected; } - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.client = kubernetesClient; - } - - @Override - public KubernetesClient getKubernetesClient() { - return client; - } - @Override protected R desired(P primary, Context

context) { return super.desired(primary, context); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java index 5dff2be51b..d030e7a8f4 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java @@ -37,7 +37,6 @@ public abstract class ManagedInformerEventSource cache; - protected TemporaryResourceCache temporaryResourceCache; protected MixedOperation, Resource> client; diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/KubernetesClientAware.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/KubernetesClientAware.java index 8a1a702074..8e94e71b53 100644 --- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/KubernetesClientAware.java +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/KubernetesClientAware.java @@ -1,7 +1,13 @@ package io.javaoperatorsdk.operator.junit; import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.api.reconciler.Context; +/** + * @deprecated It shouldn't be needed to pass a {@link KubernetesClient} instance to the reconciler + * anymore as the client should be accessed via {@link Context#getClient()} instead. + */ +@Deprecated(since = "4.5.0", forRemoval = true) public interface KubernetesClientAware extends HasKubernetesClient { void setKubernetesClient(KubernetesClient kubernetesClient); } diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java index 6b276b43d9..7f7cb64b28 100644 --- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java @@ -152,10 +152,6 @@ protected void before(ExtensionContext context) { applyCrd(config.getResourceTypeName()); } - if (ref.reconciler instanceof KubernetesClientAware) { - ((KubernetesClientAware) ref.reconciler).setKubernetesClient(kubernetesClient); - } - var registeredController = this.operator.register(ref.reconciler, oconfig.build()); registeredControllers.put(ref.reconciler, registeredController); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentReInitializationIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentReInitializationIT.java index 19edc1af61..73b7bd20d9 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentReInitializationIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentReInitializationIT.java @@ -31,7 +31,7 @@ private static void startEndStopOperator(KubernetesClient client, Operator o1 = new Operator(o -> o .withCloseClientOnStop(false) .withKubernetesClient(client)); - o1.register(new DependentReInitializationReconciler(dependent, client)); + o1.register(new DependentReInitializationReconciler(dependent)); o1.start(); o1.stop(); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java index 0eabc07c97..c4217bff25 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java @@ -143,10 +143,9 @@ private DependnetSSACustomResource reconcileWithLegacyOperator(Operator legacyOp private Operator createOperator(KubernetesClient client, boolean legacyDependentHandling, String fieldManager) { - Operator operator = new Operator(client, - o -> o.withCloseClientOnStop(false)); + Operator operator = + new Operator(o -> o.withKubernetesClient(client).withCloseClientOnStop(false)); var reconciler = new DependentSSAReconciler(!legacyDependentHandling); - reconciler.setKubernetesClient(client); operator.register(reconciler, o -> { o.settingNamespace(namespace); if (fieldManager != null) { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/OperatorRestartIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/OperatorRestartIT.java index 45b88a126b..9f506cc927 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/OperatorRestartIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/OperatorRestartIT.java @@ -1,14 +1,8 @@ package io.javaoperatorsdk.operator; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; -import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; import io.javaoperatorsdk.operator.sample.restart.RestartTestCustomResource; import io.javaoperatorsdk.operator.sample.restart.RestartTestReconciler; @@ -17,14 +11,15 @@ import static org.awaitility.Awaitility.await; class OperatorRestartIT { - private final static KubernetesClient client = new KubernetesClientBuilder().build(); + private final static Operator operator = new Operator(o -> o.withCloseClientOnStop(false)); private final static RestartTestReconciler reconciler = new RestartTestReconciler(); private static int reconcileNumberBeforeStop = 0; @BeforeAll static void registerReconciler() { - LocallyRunOperatorExtension.applyCrd(RestartTestCustomResource.class, client); + LocallyRunOperatorExtension.applyCrd(RestartTestCustomResource.class, + operator.getKubernetesClient()); operator.register(reconciler); } @@ -41,7 +36,7 @@ void stopOperator() { @Test @Order(1) void createResource() { - client.resource(testCustomResource()).createOrReplace(); + operator.getKubernetesClient().resource(testCustomResource()).createOrReplace(); await().untilAsserted(() -> assertThat(reconciler.getNumberOfExecutions()).isGreaterThan(0)); reconcileNumberBeforeStop = reconciler.getNumberOfExecutions(); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/bulkdependent/ConfigMapDeleterBulkDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/bulkdependent/ConfigMapDeleterBulkDependentResource.java index 28bb358d5a..29a9af89e7 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/bulkdependent/ConfigMapDeleterBulkDependentResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/bulkdependent/ConfigMapDeleterBulkDependentResource.java @@ -55,7 +55,7 @@ public ConfigMap desired(BulkDependentTestCustomResource primary, String key, .withLabels(Map.of(LABEL_KEY, LABEL_VALUE)) .build()); configMap.setData( - Map.of("number", "" + key, ADDITIONAL_DATA_KEY, primary.getSpec().getAdditionalData())); + Map.of("number", key, ADDITIONAL_DATA_KEY, primary.getSpec().getAdditionalData())); return configMap; } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/bulkdependent/StandaloneBulkDependentReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/bulkdependent/StandaloneBulkDependentReconciler.java index ad799116a0..6af93232b4 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/bulkdependent/StandaloneBulkDependentReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/bulkdependent/StandaloneBulkDependentReconciler.java @@ -3,21 +3,18 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; @ControllerConfiguration public class StandaloneBulkDependentReconciler implements Reconciler, TestExecutionInfoProvider, - EventSourceInitializer, KubernetesClientAware { + EventSourceInitializer { private final AtomicInteger numberOfExecutions = new AtomicInteger(0); private final ConfigMapDeleterBulkDependentResource dependent; - private KubernetesClient kubernetesClient; public StandaloneBulkDependentReconciler() { dependent = new CRUDConfigMapBulkDependentResource(); @@ -44,15 +41,4 @@ public Map prepareEventSources( return EventSourceInitializer .nameEventSources(dependent.initEventSource(context)); } - - @Override - public KubernetesClient getKubernetesClient() { - return kubernetesClient; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.kubernetesClient = kubernetesClient; - dependent.setKubernetesClient(kubernetesClient); - } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/changenamespace/ChangeNamespaceTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/changenamespace/ChangeNamespaceTestReconciler.java index f891eac525..7d51f311e1 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/changenamespace/ChangeNamespaceTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/changenamespace/ChangeNamespaceTestReconciler.java @@ -5,10 +5,8 @@ import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; @@ -16,11 +14,10 @@ @ControllerConfiguration public class ChangeNamespaceTestReconciler implements Reconciler, - EventSourceInitializer, KubernetesClientAware { + EventSourceInitializer { private final ConcurrentHashMap numberOfResourceReconciliations = new ConcurrentHashMap<>(); - private KubernetesClient client; @Override public Map prepareEventSources( @@ -40,7 +37,7 @@ public UpdateControl reconcile( var actualConfigMap = context.getSecondaryResource(ConfigMap.class); if (actualConfigMap.isEmpty()) { - client.configMaps().inNamespace(primary.getMetadata().getNamespace()) + context.getClient().configMaps().inNamespace(primary.getMetadata().getNamespace()) .resource(configMap(primary)) .create(); } @@ -73,14 +70,4 @@ private ConfigMap configMap(ChangeNamespaceTestCustomResource primary) { configMap.addOwnerReference(primary); return configMap; } - - @Override - public KubernetesClient getKubernetesClient() { - return client; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.client = kubernetesClient; - } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/clusterscopedresource/ClusterScopedCustomResourceReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/clusterscopedresource/ClusterScopedCustomResourceReconciler.java index 9d4a4fbd74..a6f5e00c96 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/clusterscopedresource/ClusterScopedCustomResourceReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/clusterscopedresource/ClusterScopedCustomResourceReconciler.java @@ -5,10 +5,8 @@ import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; @@ -16,21 +14,20 @@ @ControllerConfiguration public class ClusterScopedCustomResourceReconciler implements Reconciler, - KubernetesClientAware, EventSourceInitializer { + EventSourceInitializer { public static final String DATA_KEY = "data-key"; public static final String TEST_LABEL_VALUE = "clusterscopecrtest"; public static final String TEST_LABEL_KEY = "test"; - private KubernetesClient client; - @Override public UpdateControl reconcile( ClusterScopedCustomResource resource, Context context) { var optionalConfigMap = context.getSecondaryResource(ConfigMap.class); + final var client = context.getClient(); optionalConfigMap.ifPresentOrElse(cm -> { if (!resource.getSpec().getData().equals(cm.getData().get(DATA_KEY))) { client.configMaps().resource(desired(resource)).replace(); @@ -55,16 +52,6 @@ private ConfigMap desired(ClusterScopedCustomResource resource) { return cm; } - @Override - public KubernetesClient getKubernetesClient() { - return client; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.client = kubernetesClient; - } - @Override public Map prepareEventSources( EventSourceContext context) { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java index 6c38b2dd09..ab0369d998 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java @@ -7,15 +7,8 @@ import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ObjectMeta; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; -import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; +import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; @@ -23,8 +16,7 @@ @ControllerConfiguration public class CreateUpdateEventFilterTestReconciler implements Reconciler, - EventSourceInitializer, - KubernetesClientAware { + EventSourceInitializer { private static final class DirectConfigMapDependentResource extends @@ -50,7 +42,6 @@ public void setEventSource( } public static final String CONFIG_MAP_TEST_DATA_KEY = "key"; - private KubernetesClient client; private final AtomicInteger numberOfExecutions = new AtomicInteger(0); private InformerEventSource informerEventSource; private DirectConfigMapDependentResource configMapDR = @@ -63,7 +54,7 @@ public UpdateControl reconcile( numberOfExecutions.incrementAndGet(); ConfigMap configMap = - client + context.getClient() .configMaps() .inNamespace(resource.getMetadata().getNamespace()) .withName(resource.getMetadata().getName()) @@ -103,25 +94,12 @@ public Map prepareEventSources( InformerConfiguration.from(ConfigMap.class) .withLabelSelector("integrationtest = " + this.getClass().getSimpleName()) .build(); - informerEventSource = - new InformerEventSource<>(informerConfiguration, client); - - this.configMapDR.setKubernetesClient(context.getClient()); + informerEventSource = new InformerEventSource<>(informerConfiguration, context.getClient()); this.configMapDR.setEventSource(informerEventSource); return EventSourceInitializer.nameEventSources(informerEventSource); } - @Override - public KubernetesClient getKubernetesClient() { - return client; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.client = kubernetesClient; - } - public int getNumberOfExecutions() { return numberOfExecutions.get(); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/DependentReInitializationReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/DependentReInitializationReconciler.java index e247ddb6df..a8e6a48e6b 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/DependentReInitializationReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentreinitialization/DependentReInitializationReconciler.java @@ -2,7 +2,6 @@ import java.util.Map; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @@ -13,10 +12,8 @@ public class DependentReInitializationReconciler private final ConfigMapDependentResource configMapDependentResource; - public DependentReInitializationReconciler(ConfigMapDependentResource dependentResource, - KubernetesClient client) { + public DependentReInitializationReconciler(ConfigMapDependentResource dependentResource) { this.configMapDependentResource = dependentResource; - this.configMapDependentResource.setKubernetesClient(client); } @Override diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java index f84dfe4597..f1c11dea6d 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java @@ -4,9 +4,7 @@ import java.util.concurrent.atomic.AtomicInteger; import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfigBuilder; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; @@ -14,13 +12,11 @@ @ControllerConfiguration public class DependentSSAReconciler implements Reconciler, TestExecutionInfoProvider, - KubernetesClientAware, EventSourceInitializer { private final AtomicInteger numberOfExecutions = new AtomicInteger(0); private SSAConfigMapDependent ssaConfigMapDependent = new SSAConfigMapDependent(); - private KubernetesClient kubernetesClient; public DependentSSAReconciler() { this(true); @@ -46,17 +42,6 @@ public int getNumberOfExecutions() { return numberOfExecutions.get(); } - @Override - public KubernetesClient getKubernetesClient() { - return kubernetesClient; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.kubernetesClient = kubernetesClient; - ssaConfigMapDependent.setKubernetesClient(kubernetesClient); - } - @Override public Map prepareEventSources( EventSourceContext context) { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/externalstate/ExternalStateReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/externalstate/ExternalStateReconciler.java index 804906e3c1..66c53c3971 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/externalstate/ExternalStateReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/externalstate/ExternalStateReconciler.java @@ -9,17 +9,8 @@ import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.Cleaner; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.DeleteControl; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; -import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; +import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.EventSourceStartPriority; @@ -32,14 +23,13 @@ @ControllerConfiguration() public class ExternalStateReconciler implements Reconciler, Cleaner, - EventSourceInitializer, KubernetesClientAware, + EventSourceInitializer, TestExecutionInfoProvider { public static final String ID_KEY = "id"; private final AtomicInteger numberOfExecutions = new AtomicInteger(0); private final ExternalIDGenServiceMock externalService = ExternalIDGenServiceMock.getInstance(); - private KubernetesClient client; InformerEventSource configMapEventSource; PerResourcePollingEventSource externalResourceEventSource; @@ -52,11 +42,11 @@ public UpdateControl reconcile( var externalResource = context.getSecondaryResource(ExternalResource.class); externalResource.ifPresentOrElse(r -> { if (!r.getData().equals(resource.getSpec().getData())) { - updateExternalResource(resource, r); + updateExternalResource(resource, r, context); } }, () -> { if (externalResource.isEmpty()) { - createExternalResource(resource); + createExternalResource(resource, context); } }); @@ -65,14 +55,15 @@ public UpdateControl reconcile( } private void updateExternalResource(ExternalStateCustomResource resource, - ExternalResource externalResource) { + ExternalResource externalResource, Context context) { var newResource = new ExternalResource(externalResource.getId(), resource.getSpec().getData()); externalService.update(newResource); externalResourceEventSource.handleRecentResourceUpdate(ResourceID.fromResource(resource), newResource, externalResource); } - private void createExternalResource(ExternalStateCustomResource resource) { + private void createExternalResource(ExternalStateCustomResource resource, + Context context) { var createdResource = externalService.create(new ExternalResource(resource.getSpec().getData())); var configMap = new ConfigMapBuilder() @@ -83,7 +74,7 @@ private void createExternalResource(ExternalStateCustomResource resource) { .withData(Map.of(ID_KEY, createdResource.getId())) .build(); configMap.addOwnerReference(resource); - client.configMaps().resource(configMap).create(); + context.getClient().configMaps().resource(configMap).create(); var primaryID = ResourceID.fromResource(resource); // Making sure that the created resources are in the cache for the next reconciliation. @@ -98,7 +89,7 @@ public DeleteControl cleanup(ExternalStateCustomResource resource, Context context) { var externalResource = context.getSecondaryResource(ExternalResource.class); externalResource.ifPresent(er -> externalService.delete(er.getId())); - client.configMaps().inNamespace(resource.getMetadata().getNamespace()) + context.getClient().configMaps().inNamespace(resource.getMetadata().getNamespace()) .withName(resource.getMetadata().getName()).delete(); return DeleteControl.defaultDelete(); } @@ -128,14 +119,4 @@ public Map prepareEventSources( return EventSourceInitializer.nameEventSources(configMapEventSource, externalResourceEventSource); } - - @Override - public KubernetesClient getKubernetesClient() { - return client; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.client = kubernetesClient; - } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/filter/FilterTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/filter/FilterTestReconciler.java index 776f857bc8..ab5c9b7400 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/filter/FilterTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/filter/FilterTestReconciler.java @@ -5,32 +5,28 @@ import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; @ControllerConfiguration(onUpdateFilter = UpdateFilter.class) public class FilterTestReconciler implements Reconciler, - EventSourceInitializer, - KubernetesClientAware { + EventSourceInitializer { public static final String CONFIG_MAP_FILTER_VALUE = "config_map_skip_this"; public static final String CUSTOM_RESOURCE_FILTER_VALUE = "custom_resource_skip_this"; public static final String CM_VALUE_KEY = "value"; private final AtomicInteger numberOfExecutions = new AtomicInteger(0); - private KubernetesClient client; @Override public UpdateControl reconcile( FilterTestCustomResource resource, Context context) { numberOfExecutions.addAndGet(1); - client.configMaps().inNamespace(resource.getMetadata().getNamespace()) + context.getClient().configMaps().inNamespace(resource.getMetadata().getNamespace()) .resource(createConfigMap(resource)) .createOrReplace(); return UpdateControl.noUpdate(); @@ -65,14 +61,4 @@ public Map prepareEventSources( return EventSourceInitializer.nameEventSources(configMapES); } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.client = kubernetesClient; - } - - @Override - public KubernetesClient getKubernetesClient() { - return client; - } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/IndexDiscriminatorTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/IndexDiscriminatorTestReconciler.java index b988c93491..4acda2feee 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/IndexDiscriminatorTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/indexdiscriminator/IndexDiscriminatorTestReconciler.java @@ -6,10 +6,8 @@ import java.util.concurrent.atomic.AtomicInteger; import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; @@ -18,8 +16,7 @@ public class IndexDiscriminatorTestReconciler implements Reconciler, Cleaner, - TestExecutionInfoProvider, EventSourceInitializer, - KubernetesClientAware { + TestExecutionInfoProvider, EventSourceInitializer { public static final String FIRST_CONFIG_MAP_SUFFIX_1 = "-1"; public static final String FIRST_CONFIG_MAP_SUFFIX_2 = "-2"; @@ -30,7 +27,6 @@ public class IndexDiscriminatorTestReconciler private final IndexDiscriminatorTestDRConfigMap firstDependentResourceConfigMap; private final IndexDiscriminatorTestDRConfigMap secondDependentResourceConfigMap; - private KubernetesClient client; public IndexDiscriminatorTestReconciler() { firstDependentResourceConfigMap = @@ -88,18 +84,6 @@ public Map prepareEventSources( return EventSourceInitializer.nameEventSources(eventSource); } - @Override - public KubernetesClient getKubernetesClient() { - return client; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.client = kubernetesClient; - firstDependentResourceConfigMap.setKubernetesClient(kubernetesClient); - secondDependentResourceConfigMap.setKubernetesClient(kubernetesClient); - } - public static String configMapKey(ConfigMap configMap) { return configMap.getMetadata().getName() + "#" + configMap.getMetadata().getNamespace(); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/kubernetesdependentgarbagecollection/DependentGarbageCollectionTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/kubernetesdependentgarbagecollection/DependentGarbageCollectionTestReconciler.java index c20d573a03..fcb2192539 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/kubernetesdependentgarbagecollection/DependentGarbageCollectionTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/kubernetesdependentgarbagecollection/DependentGarbageCollectionTestReconciler.java @@ -8,7 +8,6 @@ import io.fabric8.kubernetes.client.KubernetesClientException; import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.api.reconciler.dependent.GarbageCollected; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.dependent.Creator; import io.javaoperatorsdk.operator.processing.dependent.Updater; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; @@ -18,7 +17,7 @@ public class DependentGarbageCollectionTestReconciler implements Reconciler, EventSourceInitializer, - KubernetesClientAware, ErrorStatusHandler { + ErrorStatusHandler { private KubernetesClient kubernetesClient; private volatile boolean errorOccurred = false; @@ -50,17 +49,6 @@ public UpdateControl reconcile( return UpdateControl.noUpdate(); } - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.kubernetesClient = kubernetesClient; - configMapDependent.setKubernetesClient(kubernetesClient); - } - - @Override - public KubernetesClient getKubernetesClient() { - return this.kubernetesClient; - } - @Override public ErrorStatusUpdateControl updateErrorStatus( DependentGarbageCollectionTestCustomResource resource, diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipledependentresource/MultipleDependentResourceReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipledependentresource/MultipleDependentResourceReconciler.java index 49f5ee64c1..2dc7f6490f 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipledependentresource/MultipleDependentResourceReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipledependentresource/MultipleDependentResourceReconciler.java @@ -4,10 +4,8 @@ import java.util.concurrent.atomic.AtomicInteger; import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; @@ -16,8 +14,7 @@ @ControllerConfiguration public class MultipleDependentResourceReconciler implements Reconciler, - TestExecutionInfoProvider, EventSourceInitializer, - KubernetesClientAware { + TestExecutionInfoProvider, EventSourceInitializer { public static final int FIRST_CONFIG_MAP_ID = 1; public static final int SECOND_CONFIG_MAP_ID = 2; @@ -25,7 +22,6 @@ public class MultipleDependentResourceReconciler private final MultipleDependentResourceConfigMap firstDependentResourceConfigMap; private final MultipleDependentResourceConfigMap secondDependentResourceConfigMap; - private KubernetesClient client; public MultipleDependentResourceReconciler() { firstDependentResourceConfigMap = new MultipleDependentResourceConfigMap(FIRST_CONFIG_MAP_ID); @@ -70,16 +66,4 @@ public Map prepareEventSources( return EventSourceInitializer.nameEventSources(eventSource); } - - @Override - public KubernetesClient getKubernetesClient() { - return client; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.client = kubernetesClient; - firstDependentResourceConfigMap.setKubernetesClient(kubernetesClient); - secondDependentResourceConfigMap.setKubernetesClient(kubernetesClient); - } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java index e3cc6e8c63..8f4ed834aa 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java @@ -7,10 +7,8 @@ import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ObjectMeta; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; @@ -19,10 +17,9 @@ @ControllerConfiguration public class MultipleSecondaryEventSourceReconciler implements Reconciler, TestExecutionInfoProvider, - EventSourceInitializer, KubernetesClientAware { + EventSourceInitializer { private final AtomicInteger numberOfExecutions = new AtomicInteger(0); - private KubernetesClient client; @Override public UpdateControl reconcile( @@ -30,6 +27,7 @@ public UpdateControl reconcile( Context context) { numberOfExecutions.addAndGet(1); + final var client = context.getClient(); if (client.configMaps().inNamespace(resource.getMetadata().getNamespace()) .withName(getName1(resource)).get() == null) { client.configMaps().inNamespace(resource.getMetadata().getNamespace()) @@ -94,14 +92,4 @@ ConfigMap configMap(String name, MultipleSecondaryEventSourceCustomResource reso configMap.addOwnerReference(resource); return configMap; } - - @Override - public KubernetesClient getKubernetesClient() { - return client; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.client = kubernetesClient; - } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/perresourceeventsource/PerResourcePollingEventSourceTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/perresourceeventsource/PerResourcePollingEventSourceTestReconciler.java index f8cb3ffa44..81d8773986 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/perresourceeventsource/PerResourcePollingEventSourceTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/perresourceeventsource/PerResourcePollingEventSourceTestReconciler.java @@ -6,24 +6,19 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource; @ControllerConfiguration public class PerResourcePollingEventSourceTestReconciler implements Reconciler, - EventSourceInitializer, - KubernetesClientAware { + EventSourceInitializer { public static final int POLL_PERIOD = 100; private final Map numberOfExecutions = new ConcurrentHashMap<>(); private final Map numberOfFetchExecutions = new ConcurrentHashMap<>(); - private KubernetesClient client; - @Override public UpdateControl reconcile( PerResourceEventSourceCustomResource resource, @@ -46,16 +41,6 @@ public Map prepareEventSources( return EventSourceInitializer.nameEventSources(eventSource); } - @Override - public KubernetesClient getKubernetesClient() { - return client; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.client = kubernetesClient; - } - public int getNumberOfExecutions(String name) { var num = numberOfExecutions.get(name); return num == null ? 0 : num; diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/simple/TestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/simple/TestReconciler.java index df24cbe38e..fea06bba93 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/simple/TestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/simple/TestReconciler.java @@ -10,17 +10,14 @@ import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.ReconcilerUtils; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; @ControllerConfiguration(generationAwareEventProcessing = false) public class TestReconciler implements Reconciler, Cleaner, - TestExecutionInfoProvider, - KubernetesClientAware { + TestExecutionInfoProvider { private static final Logger log = LoggerFactory.getLogger(TestReconciler.class); @@ -29,7 +26,6 @@ public class TestReconciler private final AtomicInteger numberOfExecutions = new AtomicInteger(0); private final AtomicInteger numberOfCleanupExecutions = new AtomicInteger(0); - private KubernetesClient kubernetesClient; private volatile boolean updateStatus; private volatile boolean patchStatus; @@ -51,22 +47,12 @@ public void setUpdateStatus(boolean updateStatus) { this.updateStatus = updateStatus; } - @Override - public KubernetesClient getKubernetesClient() { - return kubernetesClient; - } - - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.kubernetesClient = kubernetesClient; - } - @Override public DeleteControl cleanup( TestCustomResource resource, Context context) { numberOfCleanupExecutions.incrementAndGet(); - var statusDetail = kubernetesClient + var statusDetail = context.getClient() .configMaps() .inNamespace(resource.getMetadata().getNamespace()) .withName(resource.getSpec().getConfigMapName()) @@ -93,7 +79,7 @@ public UpdateControl reconcile( if (!resource.getMetadata().getFinalizers().contains(FINALIZER_NAME)) { throw new IllegalStateException("Finalizer is not present."); } - + final var kubernetesClient = context.getClient(); ConfigMap existingConfigMap = kubernetesClient .configMaps() diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java index 4b20bdccb3..77fcf0b85d 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java @@ -4,19 +4,10 @@ import java.util.Optional; import io.fabric8.kubernetes.api.model.apps.Deployment; -import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientException; import io.javaoperatorsdk.operator.ReconcilerUtils; import io.javaoperatorsdk.operator.StandaloneDependentResourceIT; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler; -import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; -import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; -import io.javaoperatorsdk.operator.junit.KubernetesClientAware; +import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @@ -24,9 +15,7 @@ public class StandaloneDependentTestReconciler implements Reconciler, EventSourceInitializer, - KubernetesClientAware, ErrorStatusHandler { - - private KubernetesClient kubernetesClient; + ErrorStatusHandler { private volatile boolean errorOccurred = false; DeploymentDependentResource deploymentDependent; @@ -59,17 +48,6 @@ public UpdateControl reconcile( return UpdateControl.noUpdate(); } - @Override - public void setKubernetesClient(KubernetesClient kubernetesClient) { - this.kubernetesClient = kubernetesClient; - deploymentDependent.setKubernetesClient(kubernetesClient); - } - - @Override - public KubernetesClient getKubernetesClient() { - return this.kubernetesClient; - } - @Override public ErrorStatusUpdateControl updateErrorStatus( StandaloneDependentTestCustomResource resource, diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowallfeature/ConfigMapDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowallfeature/ConfigMapDependentResource.java index 0620d6a753..04876b7959 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowallfeature/ConfigMapDependentResource.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowallfeature/ConfigMapDependentResource.java @@ -52,7 +52,7 @@ public void delete(WorkflowAllFeatureCustomResource primary, optionalConfigMap.ifPresent((configMap -> { if (configMap.getMetadata().getAnnotations() != null && configMap.getMetadata().getAnnotations().get(READY_TO_DELETE_ANNOTATION) != null) { - client.resource(configMap).delete(); + context.getClient().resource(configMap).delete(); } })); } diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java index d21e89a172..8494af5402 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageDependentsWorkflowReconciler.java @@ -8,14 +8,7 @@ import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.networking.v1.Ingress; import io.fabric8.kubernetes.client.KubernetesClient; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler; -import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; -import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; +import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfigBuilder; import io.javaoperatorsdk.operator.processing.dependent.workflow.Workflow; @@ -24,9 +17,7 @@ import io.javaoperatorsdk.operator.sample.customresource.WebPage; import io.javaoperatorsdk.operator.sample.dependentresource.*; -import static io.javaoperatorsdk.operator.sample.Utils.createStatus; -import static io.javaoperatorsdk.operator.sample.Utils.handleError; -import static io.javaoperatorsdk.operator.sample.Utils.simulateErrorIfRequested; +import static io.javaoperatorsdk.operator.sample.Utils.*; /** * Shows how to implement reconciler using standalone dependent resources. @@ -90,7 +81,6 @@ private void initDependentResources(KubernetesClient client) { this.ingressDR = new IngressDependentResource(); Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR).forEach(dr -> { - dr.setKubernetesClient(client); dr.configureWith(new KubernetesDependentResourceConfigBuilder() .withLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR).build()); }); diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java index c1b3030c9b..34a208f72e 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java @@ -87,7 +87,6 @@ private void createDependentResources(KubernetesClient client) { this.ingressDR = new IngressDependentResource(); Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR).forEach(dr -> { - dr.setKubernetesClient(client); dr.configureWith(new KubernetesDependentResourceConfigBuilder() .withLabelSelector(SELECTOR + "=true").build()); }); From dccdd63c69b43da39407d312d1d7d06fc7d3dc3a Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 18 Oct 2023 11:44:42 +0000 Subject: [PATCH 051/644] Set new SNAPSHOT version into pom files. --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 42de1fd6c5..dc441e98bf 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index a1b3e68470..8212ac544b 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index a418291dcc..a0778ff869 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index d3036a6079..1f1640dccd 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index 792c3c464b..c9cceaad48 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index de852a1dab..d749b40dee 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index f4f2f498b3..ca4c534636 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 1f2918946a..96b87b903e 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 8f9256c8c3..2dd21b35e3 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 289d03796e..5cf095cf97 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 61e1322f65..48e3853883 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 3e92c93dca..c513e4d5e0 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 12f2052b3d..310df7edc3 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.5.0-SNAPSHOT + 4.5.1-SNAPSHOT sample-webpage-operator From d9118600007a38971d0cd9ad42a9b8aad1ed9911 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 09:08:57 +0200 Subject: [PATCH 052/644] chore(deps): bump io.github.git-commit-id:git-commit-id-maven-plugin (#2098) Bumps [io.github.git-commit-id:git-commit-id-maven-plugin](https://github.com/git-commit-id/git-commit-id-maven-plugin) from 6.0.0 to 7.0.0. - [Release notes](https://github.com/git-commit-id/git-commit-id-maven-plugin/releases) - [Commits](https://github.com/git-commit-id/git-commit-id-maven-plugin/compare/v6.0.0...v7.0.0) --- updated-dependencies: - dependency-name: io.github.git-commit-id:git-commit-id-maven-plugin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 96b87b903e..8f2e8d0fe2 100644 --- a/pom.xml +++ b/pom.xml @@ -73,7 +73,7 @@ 1.6.13 3.0.0 3.1.1 - 6.0.0 + 7.0.0 2.23.0 1.0 1.9.0 From edc1e58b1f7618bdaec8c575a503543bdb154d36 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 09:09:12 +0200 Subject: [PATCH 053/644] chore(deps): bump org.apache.maven.plugins:maven-plugin-plugin (#2097) Bumps [org.apache.maven.plugins:maven-plugin-plugin](https://github.com/apache/maven-plugin-tools) from 3.9.0 to 3.10.1. - [Release notes](https://github.com/apache/maven-plugin-tools/releases) - [Commits](https://github.com/apache/maven-plugin-tools/compare/maven-plugin-tools-3.9.0...maven-plugin-tools-3.10.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-plugin-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bootstrapper-maven-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index dc441e98bf..df8188b3df 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -74,7 +74,7 @@ org.apache.maven.plugins maven-plugin-plugin - 3.9.0 + 3.10.1 org.codehaus.mojo From 624d505d876a88802c09e17b7fddc76db7d63ef4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 09:09:25 +0200 Subject: [PATCH 054/644] chore(deps): bump org.apache.maven.plugin-tools:maven-plugin-annotations (#2096) Bumps [org.apache.maven.plugin-tools:maven-plugin-annotations](https://github.com/apache/maven-plugin-tools) from 3.9.0 to 3.10.1. - [Release notes](https://github.com/apache/maven-plugin-tools/releases) - [Commits](https://github.com/apache/maven-plugin-tools/compare/maven-plugin-tools-3.9.0...maven-plugin-tools-3.10.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugin-tools:maven-plugin-annotations dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bootstrapper-maven-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index df8188b3df..6d9961f482 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -14,7 +14,7 @@ Operator SDK - Bootstrapper Maven Plugin - 3.9.0 + 3.10.1 3.9.5 From 6e239615d10c172152c917c52c6c81dd7b93c117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 23 Oct 2023 10:19:56 +0200 Subject: [PATCH 055/644] fix: sonar run/build (#2099) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/sonar.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 27f98a337c..20f8d22c87 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -40,5 +40,5 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: mvn -B org.jacoco:jacoco-maven-plugin:prepare-agent verify org.jacoco:jacoco-maven-plugin:report org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=java-operator-sdk_java-operator-sdk + run: mvn -B org.jacoco:jacoco-maven-plugin:prepare-agent clean install verify org.jacoco:jacoco-maven-plugin:report org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=java-operator-sdk_java-operator-sdk From f0d13a7072f1360ddda1b8dad32bcde9fa29d0ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 09:17:36 +0200 Subject: [PATCH 056/644] chore(deps): bump org.apache.maven.plugins:maven-surefire-plugin (#2101) Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.1.2 to 3.2.1. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.1.2...surefire-3.2.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8f2e8d0fe2..f8de9f3855 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 2.11 3.11.0 - 3.1.2 + 3.2.1 3.6.0 3.3.1 3.3.0 From 44af34e785dbc9f46c70cc9894238988aaf64716 Mon Sep 17 00:00:00 2001 From: Jakub Cechacek Date: Tue, 24 Oct 2023 10:32:59 +0200 Subject: [PATCH 057/644] docs: added Debezium Operator to the list (#2102) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fa957ef739..d850c4551d 100644 --- a/README.md +++ b/README.md @@ -76,3 +76,4 @@ project, as shown below: - [Strimzi Schema Registry Operator](https://github.com/shangyuantech/strimzi-registry-ksql-operator): A Schema Registry Operator based on JOSDK for running the Confluent Schema Registry with a Strimzi-based Kafka cluster. - [Airflow Dag Operator](https://github.com/cdmikechen/airflow-dag-operator): Use JOSDK(Quarkus Extension) to replace Airflow Git Sync strategy. The main idea of the project is to start a synchronization container on each airflow pod to synchronize the DAG/files into the DAG folder. - [Glasskube Operator](https://github.com/glasskube/operator): simplifies the deployment, maintenance and upgrade of popular open source business tools. It is written in Kotlin and uses the JOSDK and fabric8 Kubernetes client with Kotlin-based DSL. +- [Debezium Operator](https://github.com/debezium/debezium-operator): Debezium Operator adds Change-Data-Capture capabilities to your Kubernetes or Openshift cluster by providing an easy way to run and manage [Debezium Server](https://debezium.io/documentation/reference/stable/operations/debezium-server.html) instances. From 42f8d60c73ada6980e9917a1fb8fcbe7c4a5aaed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 10:12:15 +0200 Subject: [PATCH 058/644] chore(deps): bump log4j.version from 2.21.0 to 2.21.1 (#2108) Bumps `log4j.version` from 2.21.0 to 2.21.1. Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.21.0 to 2.21.1 Updates `org.apache.logging.log4j:log4j-core` from 2.21.0 to 2.21.1 Updates `org.apache.logging.log4j:log4j2-core` from 2.21.0 to 2.21.1 --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-slf4j-impl dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.logging.log4j:log4j2-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f8de9f3855..fb9c1257f7 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ 5.9.2 6.7.2 1.7.36 - 2.21.0 + 2.21.1 5.6.0 3.13.0 0.19 From ddc61b23d34be6a5e7514f6b3dfaecb67af8f62f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Oct 2023 08:35:13 +0200 Subject: [PATCH 059/644] chore(deps): bump commons-io:commons-io from 2.14.0 to 2.15.0 (#2109) Bumps commons-io:commons-io from 2.14.0 to 2.15.0. --- updated-dependencies: - dependency-name: commons-io:commons-io dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bootstrapper-maven-plugin/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 6d9961f482..fd13755391 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -56,7 +56,7 @@ commons-io commons-io - 2.14.0 + 2.15.0 com.github.spullara.mustache.java diff --git a/pom.xml b/pom.xml index fb9c1257f7..b10089a0c9 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 3.1.3 0.9.0 0.9.10 - 2.14.0 + 2.15.0 2.11 3.11.0 From 36e796ae43b8255d0446a6efe9d34bcad72b5cb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Oct 2023 09:52:45 +0200 Subject: [PATCH 060/644] chore(deps): bump org.apache.maven.plugins:maven-clean-plugin (#2110) Bumps [org.apache.maven.plugins:maven-clean-plugin](https://github.com/apache/maven-clean-plugin) from 3.3.1 to 3.3.2. - [Release notes](https://github.com/apache/maven-clean-plugin/releases) - [Commits](https://github.com/apache/maven-clean-plugin/compare/maven-clean-plugin-3.3.1...maven-clean-plugin-3.3.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-clean-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b10089a0c9..c08abd6e3b 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ 3.3.1 3.3.0 3.3.0 - 3.3.1 + 3.3.2 3.1.0 1.6.13 3.0.0 From eef287ef12f3d9a378187bd83d7c3dc5dbadf469 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 03:47:44 +0000 Subject: [PATCH 061/644] chore(deps-dev): bump org.mockito:mockito-core from 5.6.0 to 5.7.0 Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.6.0 to 5.7.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.6.0...v5.7.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c08abd6e3b..a40a5c7693 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 6.7.2 1.7.36 2.21.1 - 5.6.0 + 5.7.0 3.13.0 0.19 1.13.0 From 518c36fda8577be3ee09cb42b44357465f53e9c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Nov 2023 03:23:13 +0000 Subject: [PATCH 062/644] chore(deps): bump org.apache.maven.plugins:maven-surefire-plugin Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.2.1 to 3.2.2. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.2.1...surefire-3.2.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a40a5c7693..ec648f61ff 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 2.11 3.11.0 - 3.2.1 + 3.2.2 3.6.0 3.3.1 3.3.0 From 2f5ae017b17d6d0fb6a09e5c8f7f2c3495bdf085 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Nov 2023 07:53:16 +0000 Subject: [PATCH 063/644] chore(deps): bump org.apache.maven.plugins:maven-javadoc-plugin Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.0 to 3.6.2. - [Release notes](https://github.com/apache/maven-javadoc-plugin/releases) - [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.0...maven-javadoc-plugin-3.6.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-javadoc-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- operator-framework-bom/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 1f1640dccd..11737c9a00 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -63,7 +63,7 @@ 1.6.13 3.1.0 3.3.0 - 3.6.0 + 3.6.2 diff --git a/pom.xml b/pom.xml index ec648f61ff..88334768e1 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 2.11 3.11.0 3.2.2 - 3.6.0 + 3.6.2 3.3.1 3.3.0 3.3.0 From 147e661c673955451a329a89992cad67b3b0e4cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Nov 2023 21:08:56 +0100 Subject: [PATCH 064/644] chore(deps): bump org.apache.maven.plugin-tools:maven-plugin-annotations (#2118) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [org.apache.maven.plugin-tools:maven-plugin-annotations](https://github.com/apache/maven-plugin-tools) from 3.10.1 to 3.10.2. - [Release notes](https://github.com/apache/maven-plugin-tools/releases) - [Commits](https://github.com/apache/maven-plugin-tools/compare/maven-plugin-tools-3.10.1...maven-plugin-tools-3.10.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugin-tools:maven-plugin-annotations dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Attila Mészáros --- bootstrapper-maven-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index fd13755391..98a1624d5b 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -14,7 +14,7 @@ Operator SDK - Bootstrapper Maven Plugin - 3.10.1 + 3.10.2 3.9.5 From 4cc151e71a4f46db12acb643b2ff962eb249c7b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Nov 2023 03:22:59 +0000 Subject: [PATCH 065/644] chore(deps): bump org.apache.maven.plugins:maven-plugin-plugin Bumps [org.apache.maven.plugins:maven-plugin-plugin](https://github.com/apache/maven-plugin-tools) from 3.10.1 to 3.10.2. - [Release notes](https://github.com/apache/maven-plugin-tools/releases) - [Commits](https://github.com/apache/maven-plugin-tools/compare/maven-plugin-tools-3.10.1...maven-plugin-tools-3.10.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-plugin-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- bootstrapper-maven-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 98a1624d5b..4e61c8c8e2 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -74,7 +74,7 @@ org.apache.maven.plugins maven-plugin-plugin - 3.10.1 + 3.10.2 org.codehaus.mojo From d763fcb4074ae4299a6c16fee16a91f8ffbd9b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 14 Nov 2023 09:34:42 +0100 Subject: [PATCH 066/644] improve: matcher for config maps (#2121) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../GenericKubernetesResourceMatcher.java | 34 ++++++------ .../GenericKubernetesResourceMatcherTest.java | 52 ++++++++++++------- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java index 98198bf39a..c71da5d5ad 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java @@ -73,26 +73,26 @@ public Result match(R actualResource, P primary, Context

context) { * @param labelsAndAnnotationsEquality if true labels and annotation match exactly in the actual * and desired state if false, additional elements are allowed in actual annotations. * Considered only if considerLabelsAndAnnotations is true. - * @param specEquality if {@code false}, the algorithm checks if the properties in the desired - * resource spec are same as in the actual resource spec. The reason is that admission - * controllers and default Kubernetes controllers might add default values to some - * properties which are not set in the desired resources' spec and comparing it with simple - * equality check would mean that such resource will not match (while conceptually should). - * However, there is an issue with this for example if desired spec contains a list of - * values and a value is removed, this still will match the actual state from previous - * reconciliation. Setting this parameter to {@code true}, will match the resources only if - * all properties and values are equal. This could be implemented also by overriding equals - * method of spec, should be done as an optimization - this implementation does not require - * that. + * @param valuesEquality if {@code false}, the algorithm checks if the properties in the desired + * resource spec (or other non metadata value) are same as in the actual resource spec. The + * reason is that admission controllers and default Kubernetes controllers might add + * default values to some properties which are not set in the desired resources' spec and + * comparing it with simple equality check would mean that such resource will not match + * (while conceptually should). However, there is an issue with this for example if desired + * spec contains a list of values and a value is removed, this still will match the actual + * state from previous reconciliation. Setting this parameter to {@code true}, will match + * the resources only if all properties and values are equal. This could be implemented + * also by overriding equals method of spec, should be done as an optimization - this + * implementation does not require that. * @param resource * @return results of matching */ public static Result match(R desired, R actualResource, boolean considerLabelsAndAnnotations, boolean labelsAndAnnotationsEquality, - boolean specEquality, Context

context) { + boolean valuesEquality, Context

context) { return match(desired, actualResource, considerLabelsAndAnnotations, - labelsAndAnnotationsEquality, specEquality, context, EMPTY_ARRAY); + labelsAndAnnotationsEquality, valuesEquality, context, EMPTY_ARRAY); } /** @@ -171,14 +171,14 @@ public static Result match( public static Result match(R desired, R actualResource, - boolean considerMetadata, boolean labelsAndAnnotationsEquality, boolean specEquality, + boolean considerMetadata, boolean labelsAndAnnotationsEquality, boolean valuesEquality, Context

context, String... ignoredPaths) { final List ignoreList = ignoredPaths != null && ignoredPaths.length > 0 ? Arrays.asList(ignoredPaths) : Collections.emptyList(); - if (specEquality && !ignoreList.isEmpty()) { + if (valuesEquality && !ignoreList.isEmpty()) { throw new IllegalArgumentException( "Equality should be false in case of ignore list provided"); } @@ -192,7 +192,7 @@ public static Result match(R d for (int i = 0; i < wholeDiffJsonPatch.size() && matched; i++) { var node = wholeDiffJsonPatch.get(i); if (nodeIsChildOf(node, List.of(SPEC))) { - matched = match(specEquality, node, ignoreList); + matched = match(valuesEquality, node, ignoreList); } else if (nodeIsChildOf(node, List.of(METADATA))) { // conditionally consider labels and annotations if (considerMetadata @@ -200,7 +200,7 @@ && nodeIsChildOf(node, List.of(METADATA_LABELS, METADATA_ANNOTATIONS))) { matched = match(labelsAndAnnotationsEquality, node, Collections.emptyList()); } } else if (!nodeIsChildOf(node, IGNORED_FIELDS)) { - matched = match(true, node, ignoreList); + matched = match(valuesEquality, node, ignoreList); } } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java index b1ff214f3b..a2eea9279c 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java @@ -1,13 +1,12 @@ package io.javaoperatorsdk.operator.processing.dependent.kubernetes; +import java.util.Map; import java.util.Optional; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.api.model.ServiceAccount; -import io.fabric8.kubernetes.api.model.ServiceAccountBuilder; +import io.fabric8.kubernetes.api.model.*; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.fabric8.kubernetes.api.model.apps.DeploymentStatusBuilder; @@ -17,6 +16,7 @@ import io.javaoperatorsdk.operator.processing.dependent.Matcher; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher.GenericResourceUpdaterMatcher; +import static io.javaoperatorsdk.operator.processing.dependent.kubernetes.GenericKubernetesResourceMatcher.match; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -55,9 +55,8 @@ void matchesAdditiveOnlyChanges() { @Test void matchesWithStrongSpecEquality() { actual.getSpec().getTemplate().getMetadata().getLabels().put("new-key", "val"); - assertThat(GenericKubernetesResourceMatcher - .match(dependentResource, actual, null, context, true, true, - true) + assertThat(match(dependentResource, actual, null, context, true, true, + true) .matched()) .withFailMessage("Adding values should fail matching when strong equality is required") .isFalse(); @@ -93,8 +92,7 @@ void ignoreStatus() { void doesNotMatchChangedValuesWhenNoIgnoredPathsAreProvided() { actual = createDeployment(); actual.getSpec().setReplicas(2); - assertThat(GenericKubernetesResourceMatcher - .match(dependentResource, actual, null, context, true).matched()) + assertThat(match(dependentResource, actual, null, context, true).matched()) .withFailMessage( "Should not have matched because values have changed and no ignored path is provided") .isFalse(); @@ -104,8 +102,7 @@ void doesNotMatchChangedValuesWhenNoIgnoredPathsAreProvided() { void doesNotAttemptToMatchIgnoredPaths() { actual = createDeployment(); actual.getSpec().setReplicas(2); - assertThat(GenericKubernetesResourceMatcher - .match(dependentResource, actual, null, context, false, "/spec/replicas").matched()) + assertThat(match(dependentResource, actual, null, context, false, "/spec/replicas").matched()) .withFailMessage("Should not have compared ignored paths") .isTrue(); } @@ -114,8 +111,7 @@ void doesNotAttemptToMatchIgnoredPaths() { void ignoresWholeSubPath() { actual = createDeployment(); actual.getSpec().getTemplate().getMetadata().getLabels().put("additional-key", "val"); - assertThat(GenericKubernetesResourceMatcher - .match(dependentResource, actual, null, context, false, "/spec/template").matched()) + assertThat(match(dependentResource, actual, null, context, false, "/spec/template").matched()) .withFailMessage("Should match when only changes impact ignored sub-paths") .isTrue(); } @@ -127,18 +123,15 @@ void matchesMetadata() { .addToAnnotations("test", "value") .endMetadata() .build(); - assertThat(GenericKubernetesResourceMatcher - .match(dependentResource, actual, null, context, false).matched()) + assertThat(match(dependentResource, actual, null, context, false).matched()) .withFailMessage("Annotations shouldn't matter when metadata is not considered") .isTrue(); - assertThat(GenericKubernetesResourceMatcher - .match(dependentResource, actual, null, context, true, true, true).matched()) + assertThat(match(dependentResource, actual, null, context, true, true, true).matched()) .withFailMessage("Annotations should matter when metadata is considered") .isFalse(); - assertThat(GenericKubernetesResourceMatcher - .match(dependentResource, actual, null, context, true, false).matched()) + assertThat(match(dependentResource, actual, null, context, true, false).matched()) .withFailMessage( "Should match when strong equality is not considered and only additive changes are made") .isTrue(); @@ -155,7 +148,28 @@ void checkServiceAccount() { .build(); final var matcher = GenericResourceUpdaterMatcher.updaterMatcherFor(ServiceAccount.class); - assertThat(matcher.matches(actual, desired, context)).isFalse(); + assertThat(matcher.matches(actual, desired, context)).isTrue(); + } + + @Test + void matchConfigMap() { + var desired = createConfigMap(); + var actual = createConfigMap(); + actual.getData().put("key2", "val2"); + + var match = GenericKubernetesResourceMatcher.match(desired, actual, true, + true, false, context); + assertThat(match.matched()).isTrue(); + } + + ConfigMap createConfigMap() { + return new ConfigMapBuilder() + .withMetadata(new ObjectMetaBuilder() + .withName("tes1") + .withNamespace("default") + .build()) + .withData(Map.of("key1", "val1")) + .build(); } Deployment createDeployment() { From dc5be9cdb15763280bc32fa83c72617ed8d0ed09 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Tue, 14 Nov 2023 10:43:25 +0100 Subject: [PATCH 067/644] chore: update to Fabric8 client 6.9.2 (#2111) * chore: update to Fabric8 client 6.9.1 Signed-off-by: Chris Laprun * chore: update to Fabric8 client 6.9.2 Signed-off-by: Chris Laprun --------- Signed-off-by: Chris Laprun --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 88334768e1..b511c0d973 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ okhttp 5.9.2 - 6.7.2 + 6.9.2 1.7.36 2.21.1 5.7.0 From 76958c5dc77e74e6fa8ffcf8f4795ebbc2c19ee9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 17:13:01 +0100 Subject: [PATCH 068/644] chore(deps): bump io.micrometer:micrometer-core from 1.11.5 to 1.12.0 (#2122) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.11.5 to 1.12.0. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.11.5...v1.12.0) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Attila Mészáros --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b511c0d973..5c4d2b4256 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 3.24.2 4.2.0 2.7.3 - 1.11.5 + 1.12.0 4.10.0 3.1.3 0.9.0 From 4426544fbc84f95690627090d16adc5a184cf5c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 23 Oct 2023 13:47:16 +0200 Subject: [PATCH 069/644] add logging to help identify issue with failing e2e test (#2095) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: csviri Signed-off-by: Attila Mészáros --- .../source/informer/InformerEventSource.java | 1 + .../operator/sample/WebPageReconciler.java | 9 +++++++-- .../ConfigMapDependentResource.java | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index 968ccc27b9..f900e602ce 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -123,6 +123,7 @@ public void onAdd(R newResource) { @Override public void onUpdate(R oldObject, R newObject) { + log.debug("On updated with old: {} \n new: {}", oldObject, newObject); if (log.isDebugEnabled()) { log.debug( "On update event received for resource id: {} type: {} version: {} old version: {} ", diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java index 2680e18010..18021402a5 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java @@ -106,8 +106,9 @@ public UpdateControl reconcile(WebPage webPage, Context contex "Creating or updating ConfigMap {} in {}", desiredHtmlConfigMap.getMetadata().getName(), ns); - kubernetesClient.configMaps().inNamespace(ns).resource(desiredHtmlConfigMap) + var res = kubernetesClient.configMaps().inNamespace(ns).resource(desiredHtmlConfigMap) .createOrReplace(); + log.debug("Updated config map: {}", res); } var existingDeployment = context.getSecondaryResource(Deployment.class).orElse(null); @@ -181,10 +182,14 @@ private boolean match(Service desiredService, Service service) { } private boolean match(ConfigMap desiredHtmlConfigMap, ConfigMap existingConfigMap) { + log.debug("Actual config map: {}, desired configMap: {}", existingConfigMap, + desiredHtmlConfigMap); if (existingConfigMap == null) { return false; } else { - return desiredHtmlConfigMap.getData().equals(existingConfigMap.getData()); + var matched = desiredHtmlConfigMap.getData().equals(existingConfigMap.getData()); + log.debug("Matched config map: {}", matched); + return matched; } } diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java index 8641aa343b..a94cc82376 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java @@ -3,6 +3,9 @@ import java.util.HashMap; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; @@ -19,12 +22,15 @@ public class ConfigMapDependentResource extends CRUDKubernetesDependentResource { + private static final Logger log = LoggerFactory.getLogger(ConfigMapDependentResource.class); + public ConfigMapDependentResource() { super(ConfigMap.class); } @Override protected ConfigMap desired(WebPage webPage, Context context) { + log.debug("Web page spec: {}", webPage.getSpec().getHtml()); Map data = new HashMap<>(); data.put("index.html", webPage.getSpec().getHtml()); Map labels = new HashMap<>(); @@ -39,4 +45,15 @@ protected ConfigMap desired(WebPage webPage, Context context) { .withData(data) .build(); } + + @Override + public Result match(ConfigMap actualResource, WebPage primary, + Context context) { + var matched = super.match(actualResource, primary, context); + log.debug("Match for config map {} res: {}", actualResource.getMetadata().getName(), + matched.matched()); + return matched; + } + + } From 595547d154d8b218e09eb97a0dad7795b8761358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 24 Oct 2023 21:40:53 +0200 Subject: [PATCH 070/644] chore: version for 4.6.0-SNAPSHOT (#2103) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 4e61c8c8e2..441a995069 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index 8212ac544b..aee3ec8ecb 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index a0778ff869..1063998850 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 11737c9a00..96acc6498d 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index c9cceaad48..c13545e695 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index d749b40dee..bd572d0ab4 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index ca4c534636..d5b8a5371b 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 5c4d2b4256..2e9ecbc0f2 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 2dd21b35e3..32970da779 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 5cf095cf97..c4bc7b7247 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 48e3853883..be54f5ab48 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index c513e4d5e0..b488b73dfd 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 310df7edc3..048358c633 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.5.1-SNAPSHOT + 4.6.0-SNAPSHOT sample-webpage-operator From 7db15039d2363d2d0ab5290b38fedb872741f6e0 Mon Sep 17 00:00:00 2001 From: BramMeerten Date: Mon, 13 Nov 2023 18:19:22 +0100 Subject: [PATCH 071/644] feat: Make @Configured, @GradualRetry and @RateLimited Inherited (#2091) (#2092) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bram Meerten Co-authored-by: Attila Mészáros Signed-off-by: Attila Mészáros --- .../processing/event/rate/RateLimited.java | 2 + .../processing/retry/GradualRetry.java | 2 + .../config/BaseConfigurationServiceTest.java | 47 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/rate/RateLimited.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/rate/RateLimited.java index 7f425b73d9..66ab6849ed 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/rate/RateLimited.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/rate/RateLimited.java @@ -1,11 +1,13 @@ package io.javaoperatorsdk.operator.processing.event.rate; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.concurrent.TimeUnit; +@Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface RateLimited { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/retry/GradualRetry.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/retry/GradualRetry.java index 66f6372b32..f5033fc7aa 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/retry/GradualRetry.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/retry/GradualRetry.java @@ -1,10 +1,12 @@ package io.javaoperatorsdk.operator.processing.retry; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +@Inherited @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface GradualRetry { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/BaseConfigurationServiceTest.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/BaseConfigurationServiceTest.java index 339d2a02b4..e107623347 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/BaseConfigurationServiceTest.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/config/BaseConfigurationServiceTest.java @@ -190,6 +190,24 @@ void configuringRateAndRetryViaAnnotationsShouldWork() { assertEquals(Duration.ofSeconds(3), rateLimiter.getRefreshPeriod()); } + @Test + void configuringRateLimitAndGradualRetryViaSuperClassShouldWork() { + var config = configFor(new GradualRetryAndRateLimitedOnSuperClass()); + final var retry = config.getRetry(); + final var testRetry = assertInstanceOf(GenericRetry.class, retry); + assertEquals( + BaseClassWithGradualRetryAndRateLimited.RETRY_MAX_ATTEMPTS, + testRetry.getMaxAttempts()); + + final var rateLimiter = assertInstanceOf(LinearRateLimiter.class, config.getRateLimiter()); + assertEquals( + BaseClassWithGradualRetryAndRateLimited.RATE_LIMITED_MAX_RECONCILIATIONS, + rateLimiter.getLimitForPeriod()); + assertEquals( + Duration.ofSeconds(BaseClassWithGradualRetryAndRateLimited.RATE_LIMITED_WITHIN_SECONDS), + rateLimiter.getRefreshPeriod()); + } + @Test void checkingRetryingGraduallyWorks() { var config = configFor(new CheckRetryingGraduallyConfiguration()); @@ -250,6 +268,7 @@ public UpdateControl reconcile(ConfigMap resource, Context @ControllerConfiguration( dependents = @Dependent(type = ReadOnlyDependent.class, name = NamedDepReconciler.NAME)) private static class NamedDepReconciler implements Reconciler { + private static final String NAME = "foo"; @Override @@ -325,6 +344,7 @@ public UpdateControl reconcile(ConfigMap resource, Context } public static class TestRetry implements Retry, AnnotationConfigurable { + private int value; public TestRetry() {} @@ -347,6 +367,7 @@ public void initFrom(TestRetryConfiguration configuration) { @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) private @interface TestRetryConfiguration { + int value() default 42; } @@ -382,7 +403,30 @@ public UpdateControl reconcile(ConfigMap resource, Context } } + @ControllerConfiguration + private static class GradualRetryAndRateLimitedOnSuperClass + extends BaseClassWithGradualRetryAndRateLimited + implements Reconciler { + + @Override + public UpdateControl reconcile(ConfigMap resource, Context context) { + return null; + } + } + + @RateLimited( + maxReconciliations = BaseClassWithGradualRetryAndRateLimited.RATE_LIMITED_MAX_RECONCILIATIONS, + within = BaseClassWithGradualRetryAndRateLimited.RATE_LIMITED_WITHIN_SECONDS) + @GradualRetry(maxAttempts = BaseClassWithGradualRetryAndRateLimited.RETRY_MAX_ATTEMPTS) + private static class BaseClassWithGradualRetryAndRateLimited { + + public static final int RATE_LIMITED_MAX_RECONCILIATIONS = 7; + public static final int RATE_LIMITED_WITHIN_SECONDS = 3; + public static final int RETRY_MAX_ATTEMPTS = 3; + } + private static class ControllerConfigurationOnSuperClass extends BaseClass { + } @ControllerConfiguration @@ -443,10 +487,12 @@ private static class ChildCustomAnnotatedDep extends CustomAnnotatedDep { @Retention(RetentionPolicy.RUNTIME) private @interface CustomAnnotation { + int value(); } private static class CustomConfig { + private final int value; private CustomConfig(int value) { @@ -460,6 +506,7 @@ public int getValue() { private static class CustomConfigConverter implements ConfigurationConverter { + static final int CONVERTER_PROVIDED_DEFAULT = 7; @Override From dcbf7d60331efbc73b5c8e0ea603523ca5ef2e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 20 Nov 2023 12:49:06 +0100 Subject: [PATCH 072/644] feat: activation condition (#2105) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- docs/documentation/workflows.md | 28 ++- .../api/config/BaseConfigurationService.java | 1 + .../dependent/DependentResourceSpec.java | 10 +- .../api/reconciler/dependent/Dependent.java | 20 +++ .../operator/processing/Controller.java | 12 +- .../workflow/AbstractWorkflowExecutor.java | 5 +- .../workflow/DefaultManagedWorkflow.java | 1 + .../dependent/workflow/DefaultWorkflow.java | 11 ++ .../workflow/DependentResourceNode.java | 14 +- .../dependent/workflow/Workflow.java | 5 + .../dependent/workflow/WorkflowBuilder.java | 5 + .../workflow/WorkflowCleanupExecutor.java | 13 +- .../workflow/WorkflowReconcileExecutor.java | 78 ++++++-- .../processing/event/EventSourceManager.java | 23 +++ .../event/EventSourceRetriever.java | 47 +++++ .../processing/event/EventSources.java | 7 +- .../source/informer/InformerEventSource.java | 23 --- .../informer/ManagedInformerEventSource.java | 29 +-- .../AbstractWorkflowExecutorTest.java | 4 +- .../workflow/ManagedWorkflowTestUtils.java | 2 +- .../workflow/WorkflowCleanupExecutorTest.java | 103 ++++++++++- .../WorkflowReconcileExecutorTest.java | 166 +++++++++++++----- .../ControllerResourceEventSourceTest.java | 2 +- .../informer/InformerEventSourceTest.java | 7 +- operator-framework/pom.xml | 6 + .../WorkflowActivationConditionIT.java | 50 ++++++ .../WorkflowMultipleActivationIT.java | 137 +++++++++++++++ .../ConfigMapDependentResource.java | 30 ++++ .../IsOpenShiftCondition.java | 18 ++ .../RouteDependentResource.java | 27 +++ ...flowActivationConditionCustomResource.java | 17 ++ ...WorkflowActivationConditionReconciler.java | 21 +++ .../WorkflowActivationConditionSpec.java | 14 ++ .../ActivationCondition.java | 20 +++ .../ConfigMapDependentResource.java | 31 ++++ .../SecretDependentResource.java | 31 ++++ ...kflowMultipleActivationCustomResource.java | 17 ++ .../WorkflowMultipleActivationReconciler.java | 34 ++++ .../WorkflowMultipleActivationSpec.java | 14 ++ 39 files changed, 961 insertions(+), 122 deletions(-) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/WorkflowActivationConditionIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/WorkflowMultipleActivationIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/ConfigMapDependentResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/IsOpenShiftCondition.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/RouteDependentResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/WorkflowActivationConditionCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/WorkflowActivationConditionReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/WorkflowActivationConditionSpec.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/ActivationCondition.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/ConfigMapDependentResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/SecretDependentResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/WorkflowMultipleActivationCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/WorkflowMultipleActivationReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/WorkflowMultipleActivationSpec.java diff --git a/docs/documentation/workflows.md b/docs/documentation/workflows.md index c676207855..fed30afb25 100644 --- a/docs/documentation/workflows.md +++ b/docs/documentation/workflows.md @@ -35,6 +35,14 @@ reconciliation process. proceeding until the condition checking whether the DR is ready holds true - **Delete postcondition** - is a condition on a given DR to check if the reconciliation of dependents can proceed after the DR is supposed to have been deleted +- **Activation condition** - is a special condition meant to specify under which condition the DR is used in the + workflow. A typical use-case for this feature is to only activate some dependents depending on the presence of + optional resources / features on the target cluster. Without this activation condition, JOSDK would attempt to + register an informer for these optional resources, which would cause an error in the case where the resource is + missing. With this activation condition, you can now conditionally register informers depending on whether the + condition holds or not. This is a very useful feature when your operator needs to handle different flavors of the + platform (e.g. OpenShift vs plain Kubernetes) and/or change its behavior based on the availability of optional + resources / features (e.g. CertManager, a specific Ingress controller, etc.). ## Defining Workflows @@ -66,6 +74,7 @@ will only consider the `ConfigMap` deleted until that post-condition becomes `tr @Dependent(type = ConfigMapDependentResource.class, reconcilePrecondition = ConfigMapReconcileCondition.class, deletePostcondition = ConfigMapDeletePostCondition.class, + activationCondition = ConfigMapActivationCondition.class, dependsOn = DEPLOYMENT_NAME) }) public class SampleWorkflowReconciler implements Reconciler, @@ -165,7 +174,7 @@ executed if a resource is marked for deletion. ## Common Principles - **As complete as possible execution** - when a workflow is reconciled, it tries to reconcile as - many resources as possible. Thus if an error happens or a ready condition is not met for a + many resources as possible. Thus, if an error happens or a ready condition is not met for a resources, all the other independent resources will be still reconciled. This is the opposite to a fail-fast approach. The assumption is that eventually in this way the overall state will converge faster towards the desired state than would be the case if the reconciliation was @@ -186,13 +195,13 @@ demonstrated using examples: `depends-on` relations. 2. Root nodes, i.e. nodes in the graph that do not depend on other nodes are reconciled first, in a parallel manner. -2. A DR is reconciled if it does not depend on any other DRs, or *ALL* the DRs it depends on are - reconciled and ready. If a DR defines a reconcile pre-condition, then this condition must - become `true` before the DR is reconciled. -2. A DR is considered *ready* if it got successfully reconciled and any ready post-condition it +3. A DR is reconciled if it does not depend on any other DRs, or *ALL* the DRs it depends on are + reconciled and ready. If a DR defines a reconcile pre-condition and/or an activation condition, + then these condition must become `true` before the DR is reconciled. +4. A DR is considered *ready* if it got successfully reconciled and any ready post-condition it might define is `true`. -3. If a DR's reconcile pre-condition is not met, this DR is deleted. All of the DRs that depend - on the dependent resource being considered are also recursively deleted. This implies that +5. If a DR's reconcile pre-condition is not met, this DR is deleted. All the DRs that depend + on the dependent resource are also recursively deleted. This implies that DRs are deleted in reverse order compared the one in which they are reconciled. The reason for this behavior is (Will make a more detailed blog post about the design decision, much deeper than the reference documentation) @@ -202,7 +211,10 @@ demonstrated using examples: idempotency (i.e. with the same input state, we should have the same output state), from this follows that if the condition doesn't hold `true` anymore, the associated resource needs to be deleted because the resource shouldn't exist/have been created. -4. For a DR to be deleted by a workflow, it needs to implement the `Deleter` interface, in which +6. If a DR's activation condition is not met, it won't be reconciled or deleted. If other DR's depend on it, those will + be recursively deleted in a way similar to reconcile pre-conditions. Event sources for a dependent resource with + activation condition are registered/de-registered dynamically, thus during the reconciliation. +7. For a DR to be deleted by a workflow, it needs to implement the `Deleter` interface, in which case its `delete` method will be called, unless it also implements the `GarbageCollected` interface. If a DR doesn't implement `Deleter` it is considered as automatically deleted. If a delete post-condition exists for this DR, it needs to become `true` for the workflow to diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/BaseConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/BaseConfigurationService.java index ae836f2a72..d908f52ebe 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/BaseConfigurationService.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/BaseConfigurationService.java @@ -230,6 +230,7 @@ private static List dependentResources( Utils.instantiate(dependent.readyPostcondition(), Condition.class, context), Utils.instantiate(dependent.reconcilePrecondition(), Condition.class, context), Utils.instantiate(dependent.deletePostcondition(), Condition.class, context), + Utils.instantiate(dependent.activationCondition(), Condition.class, context), eventSourceName); specsMap.put(dependentName, spec); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceSpec.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceSpec.java index 58fd9ace4b..1fcd0709fb 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceSpec.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceSpec.java @@ -22,18 +22,21 @@ public class DependentResourceSpec { private final Condition deletePostCondition; + private final Condition activationCondition; + private final String useEventSourceWithName; public DependentResourceSpec(Class> dependentResourceClass, String name, Set dependsOn, Condition readyCondition, Condition reconcileCondition, Condition deletePostCondition, - String useEventSourceWithName) { + Condition activationCondition, String useEventSourceWithName) { this.dependentResourceClass = dependentResourceClass; this.name = name; this.dependsOn = dependsOn; this.readyCondition = readyCondition; this.reconcileCondition = reconcileCondition; this.deletePostCondition = deletePostCondition; + this.activationCondition = activationCondition; this.useEventSourceWithName = useEventSourceWithName; } @@ -87,6 +90,11 @@ public Condition getDeletePostCondition() { return deletePostCondition; } + @SuppressWarnings("rawtypes") + public Condition getActivationCondition() { + return activationCondition; + } + public Optional getUseEventSourceWithName() { return Optional.ofNullable(useEventSourceWithName); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Dependent.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Dependent.java index 78e9ee4581..754e2c85be 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Dependent.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Dependent.java @@ -50,6 +50,26 @@ */ Class deletePostcondition() default Condition.class; + /** + *

+ * A condition that needs to become true for the dependent to even be considered as part of the + * workflow. This is useful for dependents that represent optional resources on the cluster and + * might not be present. In this case, a reconcile pre-condition is not enough because in that + * situation, the associated informer will still be registered. With this activation condition, + * the associated event source will only be registered if the condition is met. Otherwise, this + * behaves like a reconcile pre-condition in the sense that dependents, that depend on this one, + * will only get created if the condition is met and will get deleted if the condition becomes + * false. + *

+ *

+ * As other conditions, this gets evaluated at the beginning of every reconciliation, which means + * that it allows to react to optional resources becoming available on the cluster as the operator + * runs. More specifically, this means that the associated event source can get dynamically + * registered or de-registered during reconciliation. + *

+ */ + Class activationCondition() default Condition.class; + /** * The list of named dependents that need to be reconciled before this one can be. * diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java index e8d15671bf..70069148c3 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java @@ -76,6 +76,7 @@ public class Controller

private final GroupVersionKind associatedGVK; private final EventProcessor

eventProcessor; private final ControllerHealthInfo controllerHealthInfo; + private final EventSourceContext

eventSourceContext; public Controller(Reconciler

reconciler, ControllerConfiguration

configuration, @@ -98,9 +99,9 @@ public Controller(Reconciler

reconciler, eventProcessor = new EventProcessor<>(eventSourceManager, configurationService); eventSourceManager.postProcessDefaultEventSourcesAfterProcessorInitializer(); controllerHealthInfo = new ControllerHealthInfo(eventSourceManager); - final var context = new EventSourceContext<>( + eventSourceContext = new EventSourceContext<>( eventSourceManager.getControllerResourceEventSource(), configuration, kubernetesClient); - initAndRegisterEventSources(context); + initAndRegisterEventSources(eventSourceContext); configurationService.getMetrics().controllerRegistered(this); } @@ -236,7 +237,8 @@ public void initAndRegisterEventSources(EventSourceContext

context) { } // register created event sources - final var dependentResourcesByName = managedWorkflow.getDependentResourcesByName(); + final var dependentResourcesByName = + managedWorkflow.getDependentResourcesByNameWithoutActivationCondition(); final var size = dependentResourcesByName.size(); if (size > 0) { dependentResourcesByName.forEach((key, dependentResource) -> { @@ -440,4 +442,8 @@ public EventProcessor

getEventProcessor() { public ExecutorServiceManager getExecutorServiceManager() { return getConfiguration().getConfigurationService().getExecutorServiceManager(); } + + public EventSourceContext

eventSourceContext() { + return eventSourceContext; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java index 595341add7..6aab0f1f39 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java @@ -46,12 +46,15 @@ public AbstractWorkflowExecutor(Workflow

workflow, P primary, Context

cont protected synchronized void waitForScheduledExecutionsToRun() { while (true) { try { - this.wait(); + // in case when workflow just contains non-activated dependents, + // it needs to be checked first if there are already no executions + // scheduled at the beginning. if (noMoreExecutionsScheduled()) { break; } else { logger().warn("Notified but still resources under execution. This should not happen."); } + this.wait(); } catch (InterruptedException e) { if (noMoreExecutionsScheduled()) { logger().debug("interrupted, no more executions for: {}", primaryID); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultManagedWorkflow.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultManagedWorkflow.java index e5b89f6c80..13d51b1759 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultManagedWorkflow.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultManagedWorkflow.java @@ -81,6 +81,7 @@ public Workflow

resolve(KubernetesClient client, spec.getReconcileCondition(), spec.getDeletePostCondition(), spec.getReadyCondition(), + spec.getActivationCondition(), resolve(spec, client, configuration)); alreadyResolved.put(node.getName(), node); spec.getDependsOn() diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultWorkflow.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultWorkflow.java index b2b8716470..d31f42419d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultWorkflow.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultWorkflow.java @@ -147,4 +147,15 @@ public Map getDependentResourcesByName() { .forEach((name, node) -> resources.put(name, node.getDependentResource())); return resources; } + + public Map getDependentResourcesByNameWithoutActivationCondition() { + final var resources = new HashMap(dependentResourceNodes.size()); + dependentResourceNodes + .forEach((name, node) -> { + if (node.getActivationCondition().isEmpty()) { + resources.put(name, node.getDependentResource()); + } + }); + return resources; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DependentResourceNode.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DependentResourceNode.java index 1b12970f48..39a9ba6fe5 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DependentResourceNode.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DependentResourceNode.java @@ -16,19 +16,21 @@ public class DependentResourceNode { private Condition reconcilePrecondition; private Condition deletePostcondition; private Condition readyPostcondition; + private Condition activationCondition; private final DependentResource dependentResource; DependentResourceNode(DependentResource dependentResource) { - this(getNameFor(dependentResource), null, null, null, dependentResource); + this(getNameFor(dependentResource), null, null, null, null, dependentResource); } public DependentResourceNode(String name, Condition reconcilePrecondition, Condition deletePostcondition, Condition readyPostcondition, - DependentResource dependentResource) { + Condition activationCondition, DependentResource dependentResource) { this.name = name; this.reconcilePrecondition = reconcilePrecondition; this.deletePostcondition = deletePostcondition; this.readyPostcondition = readyPostcondition; + this.activationCondition = activationCondition; this.dependentResource = dependentResource; } @@ -63,6 +65,10 @@ public Optional> getDeletePostcondition() { return Optional.ofNullable(deletePostcondition); } + public Optional> getActivationCondition() { + return Optional.ofNullable(activationCondition); + } + void setReconcilePrecondition(Condition reconcilePrecondition) { this.reconcilePrecondition = reconcilePrecondition; } @@ -71,6 +77,10 @@ void setDeletePostcondition(Condition cleanupCondition) { this.deletePostcondition = cleanupCondition; } + void setActivationCondition(Condition activationCondition) { + this.activationCondition = activationCondition; + } + public Optional> getReadyPostcondition() { return Optional.ofNullable(readyPostcondition); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/Workflow.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/Workflow.java index c06f17b7d8..839844256e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/Workflow.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/Workflow.java @@ -42,4 +42,9 @@ default boolean isEmpty() { default Map getDependentResourcesByName() { return Collections.emptyMap(); } + + @SuppressWarnings("rawtypes") + default Map getDependentResourcesByNameWithoutActivationCondition() { + return Collections.emptyMap(); + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowBuilder.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowBuilder.java index 0eb176f3aa..a7729859a8 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowBuilder.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowBuilder.java @@ -58,6 +58,11 @@ public WorkflowBuilder

withDeletePostcondition(Condition deletePostcondition) return this; } + public WorkflowBuilder

withActivationCondition(Condition activationCondition) { + currentNode.setActivationCondition(activationCondition); + return this; + } + DependentResourceNode getNodeByDependentResource(DependentResource dependentResource) { // first check by name final var node = diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutor.java index 5426eff1aa..74ae47100e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutor.java @@ -68,11 +68,20 @@ protected void doRun(DependentResourceNode dependentResourceNode, DependentResource dependentResource) { var deletePostCondition = dependentResourceNode.getDeletePostcondition(); - if (dependentResource.isDeletable()) { + var active = + isConditionMet(dependentResourceNode.getActivationCondition(), dependentResource); + + if (dependentResource.isDeletable() && active) { ((Deleter

) dependentResource).delete(primary, context); deleteCalled.add(dependentResourceNode); } - boolean deletePostConditionMet = isConditionMet(deletePostCondition, dependentResource); + + boolean deletePostConditionMet; + if (active) { + deletePostConditionMet = isConditionMet(deletePostCondition, dependentResource); + } else { + deletePostConditionMet = true; + } if (deletePostConditionMet) { markAsVisited(dependentResourceNode); handleDependentCleaned(dependentResourceNode); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java index b1ef16c7b0..27b5ad45da 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java @@ -62,15 +62,40 @@ private synchronized void handleReconcile(DependentResourceNode depend return; } - boolean reconcileConditionMet = isConditionMet(dependentResourceNode.getReconcilePrecondition(), + boolean activationConditionMet = isConditionMet(dependentResourceNode.getActivationCondition(), dependentResourceNode.getDependentResource()); - if (!reconcileConditionMet) { - handleReconcileConditionNotMet(dependentResourceNode); + registerOrDeregisterEventSourceBasedOnActivation(activationConditionMet, dependentResourceNode); + + boolean reconcileConditionMet = true; + if (activationConditionMet) { + reconcileConditionMet = isConditionMet(dependentResourceNode.getReconcilePrecondition(), + dependentResourceNode.getDependentResource()); + } + if (!reconcileConditionMet || !activationConditionMet) { + handleReconcileOrActivationConditionNotMet(dependentResourceNode, activationConditionMet); } else { submit(dependentResourceNode, new NodeReconcileExecutor<>(dependentResourceNode), RECONCILE); } } + private void registerOrDeregisterEventSourceBasedOnActivation(boolean activationConditionMet, + DependentResourceNode dependentResourceNode) { + if (dependentResourceNode.getActivationCondition().isPresent()) { + if (activationConditionMet) { + var eventSource = + dependentResourceNode.getDependentResource().eventSource(context.eventSourceRetriever() + .eventSourceContexForDynamicRegistration()); + var es = eventSource.orElseThrow(); + context.eventSourceRetriever() + .dynamicallyRegisterEventSource(dependentResourceNode.getName(), es); + + } else { + context.eventSourceRetriever() + .dynamicallyDeRegisterEventSource(dependentResourceNode.getName()); + } + } + } + private synchronized void handleDelete(DependentResourceNode dependentResourceNode) { log.debug("Submitting for delete: {}", dependentResourceNode); @@ -83,7 +108,8 @@ private synchronized void handleDelete(DependentResourceNode dependentResourceNo return; } - submit(dependentResourceNode, new NodeDeleteExecutor<>(dependentResourceNode), DELETE); + submit(dependentResourceNode, + new NodeDeleteExecutor<>(dependentResourceNode), DELETE); } private boolean allDependentsDeletedAlready(DependentResourceNode dependentResourceNode) { @@ -141,13 +167,17 @@ protected void doRun(DependentResourceNode dependentResourceNode, DependentResource dependentResource) { var deletePostCondition = dependentResourceNode.getDeletePostcondition(); - // GarbageCollected status is irrelevant here, as this method is only called when a - // precondition does not hold, - // a deleter should be deleted even if it is otherwise garbage collected - if (dependentResource instanceof Deleter) { - ((Deleter

) dependentResource).delete(primary, context); + boolean deletePostConditionMet = true; + if (isConditionMet(dependentResourceNode.getActivationCondition(), dependentResource)) { + // GarbageCollected status is irrelevant here, as this method is only called when a + // precondition does not hold, + // a deleter should be deleted even if it is otherwise garbage collected + if (dependentResource instanceof Deleter) { + ((Deleter

) dependentResource).delete(primary, context); + } + deletePostConditionMet = isConditionMet(deletePostCondition, dependentResource); } - boolean deletePostConditionMet = isConditionMet(deletePostCondition, dependentResource); + if (deletePostConditionMet) { markAsVisited(dependentResourceNode); handleDependentDeleted(dependentResourceNode); @@ -180,20 +210,34 @@ private synchronized void handleDependentsReconcile( } - private void handleReconcileConditionNotMet(DependentResourceNode dependentResourceNode) { + private void handleReconcileOrActivationConditionNotMet( + DependentResourceNode dependentResourceNode, + boolean activationConditionMet) { Set bottomNodes = new HashSet<>(); - markDependentsForDelete(dependentResourceNode, bottomNodes); + markDependentsForDelete(dependentResourceNode, bottomNodes, activationConditionMet); bottomNodes.forEach(this::handleDelete); } private void markDependentsForDelete(DependentResourceNode dependentResourceNode, - Set bottomNodes) { - markedForDelete.add(dependentResourceNode); + Set bottomNodes, boolean activationConditionMet) { + // this is a check so the activation condition is not evaluated twice, + // so if the activation condition was false, this node is not meant to be deleted. var dependents = dependentResourceNode.getParents(); - if (dependents.isEmpty()) { - bottomNodes.add(dependentResourceNode); + if (activationConditionMet) { + markedForDelete.add(dependentResourceNode); + if (dependents.isEmpty()) { + bottomNodes.add(dependentResourceNode); + } else { + dependents.forEach(d -> markDependentsForDelete(d, bottomNodes, true)); + } } else { - dependents.forEach(d -> markDependentsForDelete(d, bottomNodes)); + // this is for an edge case when there is only one resource but that is not active + markAsVisited(dependentResourceNode); + if (dependents.isEmpty()) { + handleNodeExecutionFinish(dependentResourceNode); + } else { + dependents.forEach(d -> markDependentsForDelete(d, bottomNodes, true)); + } } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java index 29785eda01..824c24e276 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java @@ -17,6 +17,7 @@ import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.api.config.ExecutorServiceManager; import io.javaoperatorsdk.operator.api.config.NamespaceChangeable; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; import io.javaoperatorsdk.operator.processing.Controller; import io.javaoperatorsdk.operator.processing.LifecycleAware; @@ -231,6 +232,28 @@ public List> getResourceEventSourcesFor(Class d return eventSources.getEventSources(dependentType); } + @Override + public synchronized void dynamicallyRegisterEventSource(String name, EventSource eventSource) { + if (eventSources.existing(name, eventSource) != null) { + return; + } + registerEventSource(name, eventSource); + eventSource.start(); + } + + @Override + public synchronized void dynamicallyDeRegisterEventSource(String name) { + EventSource es = eventSources.remove(name); + if (es != null) { + es.stop(); + } + } + + @Override + public EventSourceContext

eventSourceContexForDynamicRegistration() { + return controller.eventSourceContext(); + } + /** * @deprecated Use {@link #getResourceEventSourceFor(Class)} instead * diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceRetriever.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceRetriever.java index a37f35531f..67f149f5cd 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceRetriever.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceRetriever.java @@ -3,6 +3,8 @@ import java.util.List; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.ResourceEventSource; public interface EventSourceRetriever

{ @@ -15,4 +17,49 @@ default ResourceEventSource getResourceEventSourceFor(Class depende List> getResourceEventSourcesFor(Class dependentType); + /** + * Registers (and starts) the specified {@link EventSource} dynamically during the reconciliation. + * If an EventSource is already registered with the specified name, the registration will be + * ignored. It is the user's responsibility to handle the naming correctly, thus to not try to + * register different event source with same name that is already registered. + *

+ * This is only needed when your operator needs to adapt dynamically based on optional resources + * that may or may not be present on the target cluster. Even in this situation, it should be + * possible to make these decisions at when the "regular" EventSources are registered so this + * method should not typically be called directly but rather by the framework to support + * activation conditions of dependents, for example. + *

+ *

+ * This method will block until the event source is synced, if needed (as is the case for + * {@link io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource}). + *

+ *

+ * Should multiple reconciliations happen concurrently, only one EventSource with the specified + * name will ever be registered. + *

+ * + * @param name of the event source + * @param eventSource to register + */ + void dynamicallyRegisterEventSource(String name, EventSource eventSource); + + /** + * De-registers (and stops) the {@link EventSource} associated with the specified name. If no such + * source exists, this method will do nothing. + *

+ * This method will block until the event source is de-registered and stopped. If multiple + * reconciliations happen concurrently, all will be blocked until the event source is + * de-registered. + *

+ *

+ * This method is meant only to be used for dynamically registered event sources and should not be + * typically called directly. + *

+ * + * @param name of the event source + */ + void dynamicallyDeRegisterEventSource(String name); + + EventSourceContext

eventSourceContexForDynamicRegistration(); + } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSources.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSources.java index 63c94b1b6a..b53b92e122 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSources.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSources.java @@ -75,7 +75,7 @@ public void clear() { sources.clear(); } - private NamedEventSource existing(String name, EventSource source) { + public NamedEventSource existing(String name, EventSource source) { final var eventSources = sources.get(keyFor(source)); if (eventSources == null || eventSources.isEmpty()) { return null; @@ -183,4 +183,9 @@ public List> getEventSources(Class dependentTyp .map(es -> (ResourceEventSource) es) .collect(Collectors.toList()); } + + public EventSource remove(String name) { + var optionalMap = sources.values().stream().filter(m -> m.containsKey(name)).findFirst(); + return optionalMap.map(m -> m.remove(name)).orElse(null); + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index f900e602ce..a9bc2d308a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -1,7 +1,6 @@ package io.javaoperatorsdk.operator.processing.event.source.informer; import java.util.*; -import java.util.function.Function; import java.util.stream.Collectors; import org.slf4j.Logger; @@ -10,8 +9,6 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.informers.ResourceEventHandler; -import io.javaoperatorsdk.operator.OperatorException; -import io.javaoperatorsdk.operator.api.config.ConfigurationService; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.processing.event.Event; @@ -76,7 +73,6 @@ public class InformerEventSource // we need direct control for the indexer to propagate the just update resource also to the index private final PrimaryToSecondaryIndex primaryToSecondaryIndex; private final PrimaryToSecondaryMapper

primaryToSecondaryMapper; - private Map>> indexerBuffer = new HashMap<>(); private final String id = UUID.randomUUID().toString(); public InformerEventSource( @@ -305,25 +301,6 @@ private boolean acceptedByDeleteFilters(R resource, boolean b) { (genericFilter == null || genericFilter.accept(resource)); } - - // Since this event source instance is created by the user, the ConfigurationService is actually - // injected after it is registered. Some of the subcomponents are initialized at that time here. - @Override - public void setConfigurationService(ConfigurationService configurationService) { - super.setConfigurationService(configurationService); - - super.addIndexers(indexerBuffer); - indexerBuffer = new HashMap<>(); - } - - @Override - public void addIndexers(Map>> indexers) { - if (indexerBuffer == null) { - throw new OperatorException("Cannot add indexers after InformerEventSource started."); - } - indexerBuffer.putAll(indexers); - } - /** * Add an annotation to the resource so that the subsequent will be omitted * diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java index d030e7a8f4..7a1a6ba310 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java @@ -1,9 +1,6 @@ package io.javaoperatorsdk.operator.processing.event.source.informer; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; @@ -16,6 +13,7 @@ import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.kubernetes.client.informers.ResourceEventHandler; +import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.api.config.ConfigurationService; import io.javaoperatorsdk.operator.api.config.NamespaceChangeable; import io.javaoperatorsdk.operator.api.config.ResourceConfiguration; @@ -36,7 +34,11 @@ public abstract class ManagedInformerEventSource, Configurable { private static final Logger log = LoggerFactory.getLogger(ManagedInformerEventSource.class); - private final InformerManager cache; + private InformerManager cache; + private boolean parseResourceVersions; + private ConfigurationService configurationService; + private C configuration; + private Map>> indexers = new HashMap<>(); protected TemporaryResourceCache temporaryResourceCache; protected MixedOperation, Resource> client; @@ -44,9 +46,9 @@ protected ManagedInformerEventSource( MixedOperation, Resource> client, C configuration, boolean parseResourceVersions) { super(configuration.getResourceClass()); + this.parseResourceVersions = parseResourceVersions; this.client = client; - temporaryResourceCache = new TemporaryResourceCache<>(this, parseResourceVersions); - this.cache = new InformerManager<>(client, configuration, this); + this.configuration = configuration; } @Override @@ -77,6 +79,10 @@ public void changeNamespaces(Set namespaces) { @Override public void start() { + temporaryResourceCache = new TemporaryResourceCache<>(this, parseResourceVersions); + this.cache = new InformerManager<>(client, configuration, this); + cache.setConfigurationService(configurationService); + cache.addIndexers(indexers); manager().start(); super.start(); } @@ -129,7 +135,10 @@ void setTemporalResourceCache(TemporaryResourceCache temporaryResourceCache) @Override public void addIndexers(Map>> indexers) { - cache.addIndexers(indexers); + if (isRunning()) { + throw new OperatorException("Cannot add indexers after InformerEventSource started."); + } + this.indexers.putAll(indexers); } @Override @@ -164,7 +173,7 @@ public ResourceConfiguration getInformerConfiguration() { @Override public C configuration() { - return manager().configuration(); + return configuration; } @Override @@ -175,6 +184,6 @@ public String toString() { } public void setConfigurationService(ConfigurationService configurationService) { - cache.setConfigurationService(configurationService); + this.configurationService = configurationService; } } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutorTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutorTest.java index e8b26184c4..6cfdb3dc63 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutorTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutorTest.java @@ -25,9 +25,9 @@ public class AbstractWorkflowExecutorTest { protected GarbageCollectedDeleter gcDeleter = new GarbageCollectedDeleter("GC_DELETER"); @SuppressWarnings("rawtypes") - protected final Condition noMetDeletePostCondition = (primary, secondary, context) -> false; + protected final Condition notMetCondition = (primary, secondary, context) -> false; @SuppressWarnings("rawtypes") - protected final Condition metDeletePostCondition = (primary, secondary, context) -> true; + protected final Condition metCondition = (primary, secondary, context) -> true; protected List executionHistory = Collections.synchronizedList(new ArrayList<>()); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/ManagedWorkflowTestUtils.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/ManagedWorkflowTestUtils.java index 25c0ad139b..b314b5b112 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/ManagedWorkflowTestUtils.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/ManagedWorkflowTestUtils.java @@ -21,7 +21,7 @@ public class ManagedWorkflowTestUtils { @SuppressWarnings("unchecked") public static DependentResourceSpec createDRS(String name, String... dependOns) { return new DependentResourceSpec(EmptyTestDependentResource.class, name, Set.of(dependOns), - null, null, null, null); + null, null, null, null, null); } public static DependentResourceSpec createDRSWithTraits(String name, diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutorTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutorTest.java index 64fdc6e6f7..3b34dcf458 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutorTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutorTest.java @@ -21,6 +21,7 @@ class WorkflowCleanupExecutorTest extends AbstractWorkflowExecutorTest { protected TestDeleterDependent dd1 = new TestDeleterDependent("DR_DELETER_1"); protected TestDeleterDependent dd2 = new TestDeleterDependent("DR_DELETER_2"); protected TestDeleterDependent dd3 = new TestDeleterDependent("DR_DELETER_3"); + protected TestDeleterDependent dd4 = new TestDeleterDependent("DR_DELETER_4"); @SuppressWarnings("unchecked") Context mockContext = mock(Context.class); @@ -76,7 +77,7 @@ void dontDeleteIfDependentErrored() { void cleanupConditionTrivialCase() { var workflow = new WorkflowBuilder() .addDependentResource(dd1) - .addDependentResource(dd2).dependsOn(dd1).withDeletePostcondition(noMetDeletePostCondition) + .addDependentResource(dd2).dependsOn(dd1).withDeletePostcondition(notMetCondition) .build(); var res = workflow.cleanup(new TestCustomResource(), mockContext); @@ -91,7 +92,7 @@ void cleanupConditionTrivialCase() { void cleanupConditionMet() { var workflow = new WorkflowBuilder() .addDependentResource(dd1) - .addDependentResource(dd2).dependsOn(dd1).withDeletePostcondition(metDeletePostCondition) + .addDependentResource(dd2).dependsOn(dd1).withDeletePostcondition(metCondition) .build(); var res = workflow.cleanup(new TestCustomResource(), mockContext); @@ -105,12 +106,10 @@ void cleanupConditionMet() { @Test void cleanupConditionDiamondWorkflow() { - TestDeleterDependent dd4 = new TestDeleterDependent("DR_DELETER_4"); - var workflow = new WorkflowBuilder() .addDependentResource(dd1) .addDependentResource(dd2).dependsOn(dd1) - .addDependentResource(dd3).dependsOn(dd1).withDeletePostcondition(noMetDeletePostCondition) + .addDependentResource(dd3).dependsOn(dd1).withDeletePostcondition(notMetCondition) .addDependentResource(dd4).dependsOn(dd2, dd3) .build(); @@ -141,4 +140,98 @@ void dontDeleteIfGarbageCollected() { Assertions.assertThat(res.getDeleteCalledOnDependents()).isEmpty(); } + @Test + void ifDependentActiveDependentNormallyDeleted() { + var workflow = new WorkflowBuilder() + .addDependentResource(dd1) + .addDependentResource(dd2).dependsOn(dd1) + .addDependentResource(dd3).dependsOn(dd1) + .withActivationCondition(metCondition) + .addDependentResource(dd4).dependsOn(dd2, dd3) + .build(); + + var res = workflow.cleanup(new TestCustomResource(), mockContext); + + assertThat(executionHistory) + .reconciledInOrder(dd4, dd2, dd1) + .reconciledInOrder(dd4, dd3, dd1); + + Assertions.assertThat(res.getDeleteCalledOnDependents()).containsExactlyInAnyOrder(dd4, dd3, + dd2, dd1); + } + + @Test + void ifDependentActiveDeletePostConditionIsChecked() { + var workflow = new WorkflowBuilder() + .addDependentResource(dd1) + .addDependentResource(dd2).dependsOn(dd1) + .addDependentResource(dd3).dependsOn(dd1) + .withDeletePostcondition(notMetCondition) + .withActivationCondition(metCondition) + .addDependentResource(dd4).dependsOn(dd2, dd3) + .build(); + + var res = workflow.cleanup(new TestCustomResource(), mockContext); + + assertThat(executionHistory) + .reconciledInOrder(dd4, dd2) + .reconciledInOrder(dd4, dd3) + .notReconciled(dr1); + + Assertions.assertThat(res.getDeleteCalledOnDependents()).containsExactlyInAnyOrder(dd4, dd3, + dd2); + Assertions.assertThat(res.getErroredDependents()).isEmpty(); + Assertions.assertThat(res.getPostConditionNotMetDependents()).containsExactlyInAnyOrder(dd3); + } + + @Test + void ifDependentInactiveDeleteIsNotCalled() { + var workflow = new WorkflowBuilder() + .addDependentResource(dd1) + .addDependentResource(dd2).dependsOn(dd1) + .addDependentResource(dd3).dependsOn(dd1) + .withActivationCondition(notMetCondition) + .addDependentResource(dd4).dependsOn(dd2, dd3) + .build(); + + var res = workflow.cleanup(new TestCustomResource(), mockContext); + + assertThat(executionHistory) + .reconciledInOrder(dd4, dd2, dd1); + + Assertions.assertThat(res.getDeleteCalledOnDependents()).containsExactlyInAnyOrder(dd4, + dd2, dd1); + } + + @Test + void ifDependentInactiveDeletePostConditionNotChecked() { + var workflow = new WorkflowBuilder() + .addDependentResource(dd1) + .addDependentResource(dd2).dependsOn(dd1) + .addDependentResource(dd3).dependsOn(dd1) + .withDeletePostcondition(notMetCondition) + .withActivationCondition(notMetCondition) + .addDependentResource(dd4).dependsOn(dd2, dd3) + .build(); + + var res = workflow.cleanup(new TestCustomResource(), mockContext); + + assertThat(executionHistory) + .reconciledInOrder(dd4, dd2, dd1); + + Assertions.assertThat(res.getPostConditionNotMetDependents()).isEmpty(); + } + + @Test + void singleInactiveDependent() { + var workflow = new WorkflowBuilder() + .addDependentResource(dd1) + .withActivationCondition(notMetCondition) + .build(); + + workflow.cleanup(new TestCustomResource(), mockContext); + + assertThat(executionHistory).notReconciled(dd1); + } + } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutorTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutorTest.java index b3c4ea35e9..099d5fad2b 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutorTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutorTest.java @@ -9,33 +9,27 @@ import io.javaoperatorsdk.operator.AggregatedOperatorException; import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever; import io.javaoperatorsdk.operator.sample.simple.TestCustomResource; import static io.javaoperatorsdk.operator.processing.dependent.workflow.ExecutionAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; @SuppressWarnings("rawtypes") class WorkflowReconcileExecutorTest extends AbstractWorkflowExecutorTest { - - - private final Condition met_reconcile_condition = (primary, secondary, context) -> true; - private final Condition not_met_reconcile_condition = (primary, secondary, context) -> false; - - private final Condition metReadyCondition = - (primary, secondary, context) -> true; - private final Condition notMetReadyCondition = - (primary, secondary, context) -> false; - @SuppressWarnings("unchecked") Context mockContext = mock(Context.class); ExecutorService executorService = Executors.newCachedThreadPool(); + TestDependent dr3 = new TestDependent("DR_3"); + TestDependent dr4 = new TestDependent("DR_4"); + @BeforeEach void setup() { when(mockContext.getWorkflowExecutorService()).thenReturn(executorService); + when(mockContext.eventSourceRetriever()).thenReturn(mock(EventSourceRetriever.class)); } @Test @@ -70,7 +64,6 @@ void reconciliationWithSimpleDependsOn() { @Test void reconciliationWithTwoTheDependsOns() { - TestDependent dr3 = new TestDependent("DR_3"); var workflow = new WorkflowBuilder() .addDependentResource(dr1) @@ -90,9 +83,6 @@ void reconciliationWithTwoTheDependsOns() { @Test void diamondShareWorkflowReconcile() { - TestDependent dr3 = new TestDependent("DR_3"); - TestDependent dr4 = new TestDependent("DR_4"); - var workflow = new WorkflowBuilder() .addDependentResource(dr1) .addDependentResource(dr2).dependsOn(dr1) @@ -152,7 +142,6 @@ void dependentsOnErroredResourceNotReconciled() { @Test void oneBranchErrorsOtherCompletes() { - TestDependent dr3 = new TestDependent("DR_3"); var workflow = new WorkflowBuilder() .addDependentResource(dr1) @@ -194,9 +183,9 @@ void onlyOneDependsOnErroredResourceNotReconciled() { @Test void simpleReconcileCondition() { var workflow = new WorkflowBuilder() - .addDependentResource(dr1).withReconcilePrecondition(not_met_reconcile_condition) - .addDependentResource(dr2).withReconcilePrecondition(met_reconcile_condition) - .addDependentResource(drDeleter).withReconcilePrecondition(not_met_reconcile_condition) + .addDependentResource(dr1).withReconcilePrecondition(notMetCondition) + .addDependentResource(dr2).withReconcilePrecondition(metCondition) + .addDependentResource(drDeleter).withReconcilePrecondition(notMetCondition) .build(); var res = workflow.reconcile(new TestCustomResource(), mockContext); @@ -213,7 +202,7 @@ void triangleOnceConditionNotMet() { var workflow = new WorkflowBuilder() .addDependentResource(dr1) .addDependentResource(dr2).dependsOn(dr1) - .addDependentResource(drDeleter).withReconcilePrecondition(not_met_reconcile_condition) + .addDependentResource(drDeleter).withReconcilePrecondition(notMetCondition) .dependsOn(dr1) .build(); @@ -232,11 +221,11 @@ void reconcileConditionTransitiveDelete() { var workflow = new WorkflowBuilder() .addDependentResource(dr1) .addDependentResource(dr2).dependsOn(dr1) - .withReconcilePrecondition(not_met_reconcile_condition) + .withReconcilePrecondition(notMetCondition) .addDependentResource(drDeleter).dependsOn(dr2) - .withReconcilePrecondition(met_reconcile_condition) + .withReconcilePrecondition(metCondition) .addDependentResource(drDeleter2).dependsOn(drDeleter) - .withReconcilePrecondition(met_reconcile_condition) + .withReconcilePrecondition(metCondition) .build(); var res = workflow.reconcile(new TestCustomResource(), mockContext); @@ -257,9 +246,9 @@ void reconcileConditionAlsoErrorDependsOn() { var workflow = new WorkflowBuilder() .addDependentResource(drError) - .addDependentResource(drDeleter).withReconcilePrecondition(not_met_reconcile_condition) + .addDependentResource(drDeleter).withReconcilePrecondition(notMetCondition) .addDependentResource(drDeleter2).dependsOn(drError, drDeleter) - .withReconcilePrecondition(met_reconcile_condition) + .withReconcilePrecondition(metCondition) .withThrowExceptionFurther(false) .build(); @@ -280,7 +269,7 @@ void reconcileConditionAlsoErrorDependsOn() { void oneDependsOnConditionNotMet() { var workflow = new WorkflowBuilder() .addDependentResource(dr1) - .addDependentResource(dr2).withReconcilePrecondition(not_met_reconcile_condition) + .addDependentResource(dr2).withReconcilePrecondition(notMetCondition) .addDependentResource(drDeleter).dependsOn(dr1, dr2) .build(); @@ -300,7 +289,7 @@ void deletedIfReconcileConditionNotMet() { var workflow = new WorkflowBuilder() .addDependentResource(dr1) .addDependentResource(drDeleter).dependsOn(dr1) - .withReconcilePrecondition(not_met_reconcile_condition) + .withReconcilePrecondition(notMetCondition) .addDependentResource(drDeleter2).dependsOn(dr1, drDeleter) .build(); @@ -323,7 +312,7 @@ void deleteDoneInReverseOrder() { var workflow = new WorkflowBuilder() .addDependentResource(dr1) - .addDependentResource(drDeleter).withReconcilePrecondition(not_met_reconcile_condition) + .addDependentResource(drDeleter).withReconcilePrecondition(notMetCondition) .dependsOn(dr1) .addDependentResource(drDeleter2).dependsOn(drDeleter) .addDependentResource(drDeleter3).dependsOn(drDeleter) @@ -349,10 +338,10 @@ void diamondDeleteWithPostConditionInMiddle() { TestDeleterDependent drDeleter4 = new TestDeleterDependent("DR_DELETER_4"); var workflow = new WorkflowBuilder() - .addDependentResource(drDeleter).withReconcilePrecondition(not_met_reconcile_condition) + .addDependentResource(drDeleter).withReconcilePrecondition(notMetCondition) .addDependentResource(drDeleter2).dependsOn(drDeleter) .addDependentResource(drDeleter3).dependsOn(drDeleter) - .withDeletePostcondition(noMetDeletePostCondition) + .withDeletePostcondition(this.notMetCondition) .addDependentResource(drDeleter4).dependsOn(drDeleter3, drDeleter2) .build(); @@ -373,7 +362,7 @@ void diamondDeleteErrorInMiddle() { TestDeleterDependent drDeleter3 = new TestDeleterDependent("DR_DELETER_3"); var workflow = new WorkflowBuilder() - .addDependentResource(drDeleter).withReconcilePrecondition(not_met_reconcile_condition) + .addDependentResource(drDeleter).withReconcilePrecondition(notMetCondition) .addDependentResource(drDeleter2).dependsOn(drDeleter) .addDependentResource(errorDD).dependsOn(drDeleter) .addDependentResource(drDeleter3).dependsOn(errorDD, drDeleter2) @@ -394,7 +383,7 @@ void diamondDeleteErrorInMiddle() { @Test void readyConditionTrivialCase() { var workflow = new WorkflowBuilder() - .addDependentResource(dr1).withReadyPostcondition(metReadyCondition) + .addDependentResource(dr1).withReadyPostcondition(metCondition) .addDependentResource(dr2).dependsOn(dr1) .build(); @@ -410,7 +399,7 @@ void readyConditionTrivialCase() { @Test void readyConditionNotMetTrivialCase() { var workflow = new WorkflowBuilder() - .addDependentResource(dr1).withReadyPostcondition(notMetReadyCondition) + .addDependentResource(dr1).withReadyPostcondition(notMetCondition) .addDependentResource(dr2).dependsOn(dr1) .build(); @@ -426,10 +415,9 @@ void readyConditionNotMetTrivialCase() { @Test void readyConditionNotMetInOneParent() { - TestDependent dr3 = new TestDependent("DR_3"); var workflow = new WorkflowBuilder() - .addDependentResource(dr1).withReadyPostcondition(notMetReadyCondition) + .addDependentResource(dr1).withReadyPostcondition(notMetCondition) .addDependentResource(dr2) .addDependentResource(dr3).dependsOn(dr1, dr2) .build(); @@ -444,12 +432,9 @@ void readyConditionNotMetInOneParent() { @Test void diamondShareWithReadyCondition() { - TestDependent dr3 = new TestDependent("DR_3"); - TestDependent dr4 = new TestDependent("DR_4"); - var workflow = new WorkflowBuilder() .addDependentResource(dr1) - .addDependentResource(dr2).dependsOn(dr1).withReadyPostcondition(notMetReadyCondition) + .addDependentResource(dr2).dependsOn(dr1).withReadyPostcondition(notMetCondition) .addDependentResource(dr3).dependsOn(dr1) .addDependentResource(dr4).dependsOn(dr2, dr3) .build(); @@ -469,7 +454,7 @@ void diamondShareWithReadyCondition() { @Test void garbageCollectedResourceIsDeletedIfReconcilePreconditionDoesNotHold() { var workflow = new WorkflowBuilder() - .addDependentResource(gcDeleter).withReconcilePrecondition(not_met_reconcile_condition) + .addDependentResource(gcDeleter).withReconcilePrecondition(notMetCondition) .build(); var res = workflow.reconcile(new TestCustomResource(), mockContext); @@ -481,7 +466,7 @@ void garbageCollectedResourceIsDeletedIfReconcilePreconditionDoesNotHold() { @Test void garbageCollectedDeepResourceIsDeletedIfReconcilePreconditionDoesNotHold() { var workflow = new WorkflowBuilder() - .addDependentResource(dr1).withReconcilePrecondition(not_met_reconcile_condition) + .addDependentResource(dr1).withReconcilePrecondition(notMetCondition) .addDependentResource(gcDeleter).dependsOn(dr1) .build(); @@ -491,4 +476,101 @@ void garbageCollectedDeepResourceIsDeletedIfReconcilePreconditionDoesNotHold() { assertThat(executionHistory).deleted(gcDeleter); } + @Test + void notReconciledIfActivationConditionNotMet() { + var workflow = new WorkflowBuilder() + .addDependentResource(dr1) + .withActivationCondition(notMetCondition) + .addDependentResource(dr2) + .build(); + var res = workflow.reconcile(new TestCustomResource(), mockContext); + + assertThat(executionHistory).reconciled(dr2).notReconciled(dr1); + Assertions.assertThat(res.getErroredDependents()).isEmpty(); + Assertions.assertThat(res.getReconciledDependents()).contains(dr2); + } + + @Test + void dependentsOnANonActiveDependentNotReconciled() { + var workflow = new WorkflowBuilder() + .addDependentResource(dr1) + .withActivationCondition(notMetCondition) + .addDependentResource(dr2) + .addDependentResource(dr3).dependsOn(dr1) + .build(); + var res = workflow.reconcile(new TestCustomResource(), mockContext); + + assertThat(executionHistory).reconciled(dr2).notReconciled(dr1, dr3); + Assertions.assertThat(res.getErroredDependents()).isEmpty(); + Assertions.assertThat(res.getReconciledDependents()).contains(dr2); + } + + @Test + void readyConditionNotCheckedOnNonActiveDependent() { + var workflow = new WorkflowBuilder() + .addDependentResource(dr1) + .withActivationCondition(notMetCondition) + .withReadyPostcondition(notMetCondition) + .addDependentResource(dr2) + .addDependentResource(dr3).dependsOn(dr1) + .build(); + + var res = workflow.reconcile(new TestCustomResource(), mockContext); + + Assertions.assertThat(res.getNotReadyDependents()).isEmpty(); + } + + @Test + void reconcilePreconditionNotCheckedOnNonActiveDependent() { + var precondition = mock(Condition.class); + + var workflow = new WorkflowBuilder() + .addDependentResource(dr1) + .withActivationCondition(notMetCondition) + .withReconcilePrecondition(precondition) + .build(); + + workflow.reconcile(new TestCustomResource(), mockContext); + + verify(precondition, never()).isMet(any(), any(), any()); + } + + @Test + void deletesDependentsOfNonActiveDependentButNotTheNonActive() { + TestDeleterDependent drDeleter2 = new TestDeleterDependent("DR_DELETER_2"); + TestDeleterDependent drDeleter3 = new TestDeleterDependent("DR_DELETER_2"); + + var workflow = new WorkflowBuilder() + .addDependentResource(dr1).withActivationCondition(notMetCondition) + .addDependentResource(drDeleter).dependsOn(dr1) + .addDependentResource(drDeleter2).dependsOn(drDeleter) + .withActivationCondition(notMetCondition) + .addDependentResource(drDeleter3).dependsOn(drDeleter2) + .build(); + + var res = workflow.reconcile(new TestCustomResource(), mockContext); + + Assertions.assertThat(res.getReconciledDependents()).isEmpty(); + assertThat(executionHistory).deleted(drDeleter, drDeleter3) + .notReconciled(dr1, + drDeleter2); + } + + @Test + void activationConditionOnlyCalledOnceOnDeleteDependents() { + TestDeleterDependent drDeleter2 = new TestDeleterDependent("DR_DELETER_2"); + var condition = mock(Condition.class); + when(condition.isMet(any(), any(), any())).thenReturn(false); + + var workflow = new WorkflowBuilder() + .addDependentResource(drDeleter).withActivationCondition(condition) + .addDependentResource(drDeleter2).dependsOn(drDeleter) + .build(); + + workflow.reconcile(new TestCustomResource(), mockContext); + + assertThat(executionHistory).deleted(drDeleter2); + verify(condition, times(1)).isMet(any(), any(), any()); + } + } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSourceTest.java index 87ec3f9eba..64f0993139 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSourceTest.java @@ -37,7 +37,7 @@ class ControllerResourceEventSourceTest extends @BeforeEach public void setup() { - setUpSource(new ControllerResourceEventSource<>(testController), false, + setUpSource(new ControllerResourceEventSource<>(testController), true, new BaseConfigurationService()); } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java index 0881cccaf2..ce3c52076d 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java @@ -55,15 +55,16 @@ void setup() { when(informerConfiguration.getResourceClass()).thenReturn(Deployment.class); informerEventSource = new InformerEventSource<>(informerConfiguration, clientMock); - informerEventSource.setTemporalResourceCache(temporaryResourceCacheMock); - informerEventSource.setEventHandler(eventHandlerMock); - + informerEventSource.setEventHandler(eventHandlerMock); + informerEventSource.setConfigurationService(new BaseConfigurationService()); SecondaryToPrimaryMapper secondaryToPrimaryMapper = mock(SecondaryToPrimaryMapper.class); when(informerConfiguration.getSecondaryToPrimaryMapper()) .thenReturn(secondaryToPrimaryMapper); when(secondaryToPrimaryMapper.toPrimaryResourceIDs(any())) .thenReturn(Set.of(ResourceID.fromResource(testDeployment()))); + informerEventSource.start(); + informerEventSource.setTemporalResourceCache(temporaryResourceCacheMock); } @Test diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index d5b8a5371b..943acc11d2 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -64,6 +64,12 @@ crd-generator-apt test + + + io.fabric8 + openshift-client-api + test + org.apache.logging.log4j log4j-slf4j-impl diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/WorkflowActivationConditionIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/WorkflowActivationConditionIT.java new file mode 100644 index 0000000000..38a11e0438 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/WorkflowActivationConditionIT.java @@ -0,0 +1,50 @@ +package io.javaoperatorsdk.operator; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.workflowactivationcondition.WorkflowActivationConditionCustomResource; +import io.javaoperatorsdk.operator.sample.workflowactivationcondition.WorkflowActivationConditionReconciler; +import io.javaoperatorsdk.operator.sample.workflowactivationcondition.WorkflowActivationConditionSpec; + +import static io.javaoperatorsdk.operator.sample.workflowactivationcondition.ConfigMapDependentResource.DATA_KEY; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class WorkflowActivationConditionIT { + + public static final String TEST_RESOURCE_NAME = "test1"; + public static final String TEST_DATA = "test data"; + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(WorkflowActivationConditionReconciler.class) + .build(); + + // Without activation condition this would fail / there would be errors. + @Test + void reconciledOnVanillaKubernetesDespiteRouteInWorkflow() { + extension.create(testResource()); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, TEST_RESOURCE_NAME); + assertThat(cm).isNotNull(); + assertThat(cm.getData()).containsEntry(DATA_KEY, TEST_DATA); + }); + } + + private WorkflowActivationConditionCustomResource testResource() { + var res = new WorkflowActivationConditionCustomResource(); + res.setMetadata(new ObjectMetaBuilder() + .withName(TEST_RESOURCE_NAME) + .build()); + res.setSpec(new WorkflowActivationConditionSpec()); + res.getSpec().setValue(TEST_DATA); + return res; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/WorkflowMultipleActivationIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/WorkflowMultipleActivationIT.java new file mode 100644 index 0000000000..a7f93935ee --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/WorkflowMultipleActivationIT.java @@ -0,0 +1,137 @@ +package io.javaoperatorsdk.operator; + +import java.time.Duration; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.Secret; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.workflowmultipleactivation.*; + +import static io.javaoperatorsdk.operator.sample.workflowactivationcondition.ConfigMapDependentResource.DATA_KEY; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class WorkflowMultipleActivationIT { + + public static final String INITIAL_DATA = "initial data"; + public static final String TEST_RESOURCE1 = "test1"; + public static final String TEST_RESOURCE2 = "test2"; + public static final String CHANGED_VALUE = "changed value"; + public static final int POLL_DELAY = 300; + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(WorkflowMultipleActivationReconciler.class) + .build(); + + @Test + void deactivatingAndReactivatingDependent() { + ActivationCondition.MET = true; + var cr1 = extension.create(testResource()); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, TEST_RESOURCE1); + var secret = extension.get(Secret.class, TEST_RESOURCE1); + assertThat(cm).isNotNull(); + assertThat(secret).isNotNull(); + assertThat(cm.getData()).containsEntry(DATA_KEY, INITIAL_DATA); + }); + + extension.delete(cr1); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, TEST_RESOURCE1); + assertThat(cm).isNull(); + }); + + ActivationCondition.MET = false; + cr1 = extension.create(testResource()); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, TEST_RESOURCE1); + var secret = extension.get(Secret.class, TEST_RESOURCE1); + assertThat(cm).isNull(); + assertThat(secret).isNotNull(); + }); + + ActivationCondition.MET = true; + cr1.getSpec().setValue(CHANGED_VALUE); + extension.replace(cr1); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, TEST_RESOURCE1); + assertThat(cm).isNotNull(); + assertThat(cm.getData()).containsEntry(DATA_KEY, CHANGED_VALUE); + }); + + ActivationCondition.MET = false; + cr1.getSpec().setValue(INITIAL_DATA); + extension.replace(cr1); + + await().pollDelay(Duration.ofMillis(POLL_DELAY)).untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, TEST_RESOURCE1); + assertThat(cm).isNotNull(); + // data not changed + assertThat(cm.getData()).containsEntry(DATA_KEY, CHANGED_VALUE); + }); + + var numOfReconciliation = + extension.getReconcilerOfType(WorkflowMultipleActivationReconciler.class) + .getNumberOfReconciliationExecution(); + var actualCM = extension.get(ConfigMap.class, TEST_RESOURCE1); + actualCM.getData().put("data2", "additionaldata"); + extension.replace(actualCM); + await().pollDelay(Duration.ofMillis(POLL_DELAY)).untilAsserted(() -> { + // change in config map does not induce reconciliation if inactive (thus informer is not + // present) + assertThat(extension.getReconcilerOfType(WorkflowMultipleActivationReconciler.class) + .getNumberOfReconciliationExecution()).isEqualTo(numOfReconciliation); + }); + + extension.delete(cr1); + await().pollDelay(Duration.ofMillis(POLL_DELAY)).untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, TEST_RESOURCE1); + assertThat(cm).isNotNull(); + }); + } + + WorkflowMultipleActivationCustomResource testResource(String name) { + var res = new WorkflowMultipleActivationCustomResource(); + res.setMetadata(new ObjectMetaBuilder() + .withName(name) + .build()); + res.setSpec(new WorkflowMultipleActivationSpec()); + res.getSpec().setValue(INITIAL_DATA); + return res; + } + + WorkflowMultipleActivationCustomResource testResource() { + return testResource(TEST_RESOURCE1); + } + + WorkflowMultipleActivationCustomResource testResource2() { + return testResource(TEST_RESOURCE2); + } + + @Test + void simpleConcurrencyTest() { + ActivationCondition.MET = true; + extension.create(testResource()); + extension.create(testResource2()); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, TEST_RESOURCE1); + var cm2 = extension.get(ConfigMap.class, TEST_RESOURCE2); + assertThat(cm).isNotNull(); + assertThat(cm2).isNotNull(); + assertThat(cm.getData()).containsEntry(DATA_KEY, INITIAL_DATA); + assertThat(cm2.getData()).containsEntry(DATA_KEY, INITIAL_DATA); + }); + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/ConfigMapDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/ConfigMapDependentResource.java new file mode 100644 index 0000000000..7433c31c73 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/ConfigMapDependentResource.java @@ -0,0 +1,30 @@ +package io.javaoperatorsdk.operator.sample.workflowactivationcondition; + +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; + +public class ConfigMapDependentResource + extends CRUDKubernetesDependentResource { + + public static final String DATA_KEY = "data"; + + public ConfigMapDependentResource() { + super(ConfigMap.class); + } + + @Override + protected ConfigMap desired(WorkflowActivationConditionCustomResource primary, + Context context) { + ConfigMap configMap = new ConfigMap(); + configMap.setMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()); + configMap.setData(Map.of(DATA_KEY, primary.getSpec().getValue())); + return configMap; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/IsOpenShiftCondition.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/IsOpenShiftCondition.java new file mode 100644 index 0000000000..79434409b8 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/IsOpenShiftCondition.java @@ -0,0 +1,18 @@ +package io.javaoperatorsdk.operator.sample.workflowactivationcondition; + +import io.fabric8.openshift.api.model.Route; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition; + +public class IsOpenShiftCondition + implements Condition { + @Override + public boolean isMet( + DependentResource dependentResource, + WorkflowActivationConditionCustomResource primary, + Context context) { + // we are testing if the reconciliation still works on Kubernetes, so this always false; + return false; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/RouteDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/RouteDependentResource.java new file mode 100644 index 0000000000..de5d52f76a --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/RouteDependentResource.java @@ -0,0 +1,27 @@ +package io.javaoperatorsdk.operator.sample.workflowactivationcondition; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.openshift.api.model.Route; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; + +public class RouteDependentResource + extends CRUDKubernetesDependentResource { + + public RouteDependentResource() { + super(Route.class); + } + + @Override + protected Route desired(WorkflowActivationConditionCustomResource primary, + Context context) { + // basically does not matter since this should not be called + Route route = new Route(); + route.setMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()); + + return route; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/WorkflowActivationConditionCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/WorkflowActivationConditionCustomResource.java new file mode 100644 index 0000000000..63d4bc343c --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/WorkflowActivationConditionCustomResource.java @@ -0,0 +1,17 @@ +package io.javaoperatorsdk.operator.sample.workflowactivationcondition; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("wac") +public class WorkflowActivationConditionCustomResource + extends CustomResource + implements Namespaced { + + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/WorkflowActivationConditionReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/WorkflowActivationConditionReconciler.java new file mode 100644 index 0000000000..33db3043ba --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/WorkflowActivationConditionReconciler.java @@ -0,0 +1,21 @@ +package io.javaoperatorsdk.operator.sample.workflowactivationcondition; + +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; + +@ControllerConfiguration(dependents = { + @Dependent(type = ConfigMapDependentResource.class), + @Dependent(type = RouteDependentResource.class, + activationCondition = IsOpenShiftCondition.class) +}) +public class WorkflowActivationConditionReconciler + implements Reconciler { + + @Override + public UpdateControl reconcile( + WorkflowActivationConditionCustomResource resource, + Context context) { + + return UpdateControl.noUpdate(); + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/WorkflowActivationConditionSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/WorkflowActivationConditionSpec.java new file mode 100644 index 0000000000..826fe04958 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcondition/WorkflowActivationConditionSpec.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.sample.workflowactivationcondition; + +public class WorkflowActivationConditionSpec { + + private String value; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/ActivationCondition.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/ActivationCondition.java new file mode 100644 index 0000000000..c8be8467df --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/ActivationCondition.java @@ -0,0 +1,20 @@ +package io.javaoperatorsdk.operator.sample.workflowmultipleactivation; + +import io.fabric8.openshift.api.model.Route; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition; + +public class ActivationCondition + implements Condition { + + public static volatile boolean MET = true; + + @Override + public boolean isMet( + DependentResource dependentResource, + WorkflowMultipleActivationCustomResource primary, + Context context) { + return MET; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/ConfigMapDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/ConfigMapDependentResource.java new file mode 100644 index 0000000000..e245cb222d --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/ConfigMapDependentResource.java @@ -0,0 +1,31 @@ +package io.javaoperatorsdk.operator.sample.workflowmultipleactivation; + +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDNoGCKubernetesDependentResource; + +public class ConfigMapDependentResource + extends + CRUDNoGCKubernetesDependentResource { + + public static final String DATA_KEY = "data"; + + public ConfigMapDependentResource() { + super(ConfigMap.class); + } + + @Override + protected ConfigMap desired(WorkflowMultipleActivationCustomResource primary, + Context context) { + ConfigMap configMap = new ConfigMap(); + configMap.setMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()); + configMap.setData(Map.of(DATA_KEY, primary.getSpec().getValue())); + return configMap; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/SecretDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/SecretDependentResource.java new file mode 100644 index 0000000000..decd5a346d --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/SecretDependentResource.java @@ -0,0 +1,31 @@ +package io.javaoperatorsdk.operator.sample.workflowmultipleactivation; + +import java.util.Base64; +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.Secret; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; + +public class SecretDependentResource + extends CRUDKubernetesDependentResource { + + public SecretDependentResource() { + super(Secret.class); + } + + @Override + protected Secret desired(WorkflowMultipleActivationCustomResource primary, + Context context) { + // basically does not matter since this should not be called + Secret secret = new Secret(); + secret.setMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()); + secret.setData(Map.of("data", + Base64.getEncoder().encodeToString(primary.getSpec().getValue().getBytes()))); + return secret; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/WorkflowMultipleActivationCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/WorkflowMultipleActivationCustomResource.java new file mode 100644 index 0000000000..9c642e9635 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/WorkflowMultipleActivationCustomResource.java @@ -0,0 +1,17 @@ +package io.javaoperatorsdk.operator.sample.workflowmultipleactivation; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("mwac") +public class WorkflowMultipleActivationCustomResource + extends CustomResource + implements Namespaced { + + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/WorkflowMultipleActivationReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/WorkflowMultipleActivationReconciler.java new file mode 100644 index 0000000000..8277e7f8e7 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/WorkflowMultipleActivationReconciler.java @@ -0,0 +1,34 @@ +package io.javaoperatorsdk.operator.sample.workflowmultipleactivation; + +import java.util.concurrent.atomic.AtomicInteger; + +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; + +@ControllerConfiguration(dependents = { + @Dependent(type = ConfigMapDependentResource.class, + activationCondition = ActivationCondition.class), + @Dependent(type = SecretDependentResource.class) +}) +public class WorkflowMultipleActivationReconciler + implements Reconciler { + + private final AtomicInteger numberOfReconciliationExecution = new AtomicInteger(0); + + @Override + public UpdateControl reconcile( + WorkflowMultipleActivationCustomResource resource, + Context context) { + + numberOfReconciliationExecution.incrementAndGet(); + + return UpdateControl.noUpdate(); + } + + public int getNumberOfReconciliationExecution() { + return numberOfReconciliationExecution.get(); + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/WorkflowMultipleActivationSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/WorkflowMultipleActivationSpec.java new file mode 100644 index 0000000000..b342bb331f --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowmultipleactivation/WorkflowMultipleActivationSpec.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.sample.workflowmultipleactivation; + +public class WorkflowMultipleActivationSpec { + + private String value; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} From dcebe80a83c740b8022d7f8c589df3f4dc49b44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 20 Nov 2023 15:34:25 +0100 Subject: [PATCH 073/644] improve: webpage e2e test and deprecated api usage (#2124) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/sample/WebPageReconciler.java | 12 +++++++----- .../operator/sample/WebPageOperatorAbstractTest.java | 7 ++++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java index 18021402a5..fba64bb45d 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java @@ -16,6 +16,7 @@ import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.networking.v1.Ingress; import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.Replaceable; import io.javaoperatorsdk.operator.ReconcilerUtils; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; @@ -107,7 +108,7 @@ public UpdateControl reconcile(WebPage webPage, Context contex desiredHtmlConfigMap.getMetadata().getName(), ns); var res = kubernetesClient.configMaps().inNamespace(ns).resource(desiredHtmlConfigMap) - .createOrReplace(); + .createOr(Replaceable::update); log.debug("Updated config map: {}", res); } @@ -118,7 +119,7 @@ public UpdateControl reconcile(WebPage webPage, Context contex desiredDeployment.getMetadata().getName(), ns); kubernetesClient.apps().deployments().inNamespace(ns).resource(desiredDeployment) - .createOrReplace(); + .createOr(Replaceable::update); } var existingService = context.getSecondaryResource(Service.class).orElse(null); @@ -127,14 +128,15 @@ public UpdateControl reconcile(WebPage webPage, Context contex "Creating or updating Deployment {} in {}", desiredDeployment.getMetadata().getName(), ns); - kubernetesClient.services().inNamespace(ns).resource(desiredService).createOrReplace(); + kubernetesClient.services().inNamespace(ns).resource(desiredService) + .createOr(Replaceable::update); } var existingIngress = context.getSecondaryResource(Ingress.class); if (Boolean.TRUE.equals(webPage.getSpec().getExposed())) { var desiredIngress = makeDesiredIngress(webPage); if (existingIngress.isEmpty() || !match(desiredIngress, existingIngress.get())) { - kubernetesClient.resource(desiredIngress).inNamespace(ns).createOrReplace(); + kubernetesClient.resource(desiredIngress).inNamespace(ns).createOr(Replaceable::update); } } else existingIngress.ifPresent( @@ -150,7 +152,7 @@ public UpdateControl reconcile(WebPage webPage, Context contex kubernetesClient.pods().inNamespace(ns).withLabel("app", deploymentName(webPage)).delete(); } webPage.setStatus(createStatus(desiredHtmlConfigMap.getMetadata().getName())); - return UpdateControl.updateStatus(webPage); + return UpdateControl.patchStatus(webPage); } private boolean match(Ingress desiredIngress, Ingress existingIngress) { diff --git a/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorAbstractTest.java b/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorAbstractTest.java index d1445e34ba..040b3b2f8f 100644 --- a/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorAbstractTest.java +++ b/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorAbstractTest.java @@ -12,6 +12,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.KubernetesClient; @@ -23,6 +24,7 @@ import static io.javaoperatorsdk.operator.sample.Utils.deploymentName; import static io.javaoperatorsdk.operator.sample.Utils.serviceName; +import static io.javaoperatorsdk.operator.sample.WebPageReconciler.INDEX_HTML; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; @@ -72,7 +74,10 @@ void testAddingWebPage() { await().atMost(Duration.ofSeconds(LONG_WAIT_SECONDS)) .pollInterval(POLL_INTERVAL) .untilAsserted(() -> { - String page = httpGetForWebPage(webPage); + String page = operator().get(ConfigMap.class, Utils.configMapName(webPage)).getData() + .get(INDEX_HTML); + // not using portforward here since there were issues with GitHub actions + // String page = httpGetForWebPage(webPage); assertThat(page).isNotNull().contains(TITLE2); }); From c7571531a83364710d1d1d9706b7d0bff235fd21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 20 Nov 2023 16:09:41 +0100 Subject: [PATCH 074/644] Revert "add logging to help identify issue with failing e2e test (#2095)" (#2125) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 1e5e03e5094ea84234c45119514bf45e05043bbc. Signed-off-by: Attila Mészáros --- .../source/informer/InformerEventSource.java | 1 - .../operator/sample/WebPageReconciler.java | 7 +------ .../ConfigMapDependentResource.java | 17 ----------------- 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index a9bc2d308a..dfaec7c19e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -119,7 +119,6 @@ public void onAdd(R newResource) { @Override public void onUpdate(R oldObject, R newObject) { - log.debug("On updated with old: {} \n new: {}", oldObject, newObject); if (log.isDebugEnabled()) { log.debug( "On update event received for resource id: {} type: {} version: {} old version: {} ", diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java index fba64bb45d..af938a7833 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java @@ -109,7 +109,6 @@ public UpdateControl reconcile(WebPage webPage, Context contex ns); var res = kubernetesClient.configMaps().inNamespace(ns).resource(desiredHtmlConfigMap) .createOr(Replaceable::update); - log.debug("Updated config map: {}", res); } var existingDeployment = context.getSecondaryResource(Deployment.class).orElse(null); @@ -184,14 +183,10 @@ private boolean match(Service desiredService, Service service) { } private boolean match(ConfigMap desiredHtmlConfigMap, ConfigMap existingConfigMap) { - log.debug("Actual config map: {}, desired configMap: {}", existingConfigMap, - desiredHtmlConfigMap); if (existingConfigMap == null) { return false; } else { - var matched = desiredHtmlConfigMap.getData().equals(existingConfigMap.getData()); - log.debug("Matched config map: {}", matched); - return matched; + return desiredHtmlConfigMap.getData().equals(existingConfigMap.getData()); } } diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java index a94cc82376..8641aa343b 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java @@ -3,9 +3,6 @@ import java.util.HashMap; import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; @@ -22,15 +19,12 @@ public class ConfigMapDependentResource extends CRUDKubernetesDependentResource { - private static final Logger log = LoggerFactory.getLogger(ConfigMapDependentResource.class); - public ConfigMapDependentResource() { super(ConfigMap.class); } @Override protected ConfigMap desired(WebPage webPage, Context context) { - log.debug("Web page spec: {}", webPage.getSpec().getHtml()); Map data = new HashMap<>(); data.put("index.html", webPage.getSpec().getHtml()); Map labels = new HashMap<>(); @@ -45,15 +39,4 @@ protected ConfigMap desired(WebPage webPage, Context context) { .withData(data) .build(); } - - @Override - public Result match(ConfigMap actualResource, WebPage primary, - Context context) { - var matched = super.match(actualResource, primary, context); - log.debug("Match for config map {} res: {}", actualResource.getMetadata().getName(), - matched.matched()); - return matched; - } - - } From 19d0318efa1318315c7d3ffed5a0896a398cba8f Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 20 Nov 2023 16:00:35 +0000 Subject: [PATCH 075/644] Set new SNAPSHOT version into pom files. --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 441a995069..eb0283bced 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index aee3ec8ecb..fb5e2c98a1 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 1063998850..3e640e3e7f 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 96acc6498d..0ada2a081e 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index c13545e695..92396da92a 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index bd572d0ab4..a80d03d69e 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index 943acc11d2..ff38d5fc66 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 2e9ecbc0f2..2387b6cc40 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 32970da779..6933b2bc78 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index c4bc7b7247..c69c388299 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index be54f5ab48..f7b1b4dfcb 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index b488b73dfd..b94068525a 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 048358c633..8cbac1f178 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.0-SNAPSHOT + 4.6.1-SNAPSHOT sample-webpage-operator From 48cd523a3829a695ad7127b8878098f9e7f2d956 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Nov 2023 09:11:52 +0100 Subject: [PATCH 076/644] chore(deps): bump log4j.version from 2.21.1 to 2.22.0 (#2129) Bumps `log4j.version` from 2.21.1 to 2.22.0. Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.21.1 to 2.22.0 Updates `org.apache.logging.log4j:log4j-core` from 2.21.1 to 2.22.0 Updates `org.apache.logging.log4j:log4j2-core` from 2.21.1 to 2.22.0 --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-slf4j-impl dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.apache.logging.log4j:log4j2-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2387b6cc40..8e2f23d84d 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ 5.9.2 6.9.2 1.7.36 - 2.21.1 + 2.22.0 5.7.0 3.13.0 0.19 From 0b4bbd69ac5d6240a17da6b284468a6b0c8a3e15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Nov 2023 08:46:55 +0100 Subject: [PATCH 077/644] chore(deps): bump org.apache.commons:commons-lang3 from 3.13.0 to 3.14.0 (#2131) Bumps org.apache.commons:commons-lang3 from 3.13.0 to 3.14.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-lang3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8e2f23d84d..ca2935ae6a 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ 1.7.36 2.22.0 5.7.0 - 3.13.0 + 3.14.0 0.19 1.13.0 3.24.2 From dae6421a8ab86bd1d85f48df5cfba47d2acc7c04 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 10:17:11 +0100 Subject: [PATCH 078/644] chore(deps): bump commons-io:commons-io from 2.15.0 to 2.15.1 (#2134) Bumps commons-io:commons-io from 2.15.0 to 2.15.1. --- updated-dependencies: - dependency-name: commons-io:commons-io dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bootstrapper-maven-plugin/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index eb0283bced..bc345bef7f 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -56,7 +56,7 @@ commons-io commons-io - 2.15.0 + 2.15.1 com.github.spullara.mustache.java diff --git a/pom.xml b/pom.xml index ca2935ae6a..2ee7a888d9 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 3.1.3 0.9.0 0.9.10 - 2.15.0 + 2.15.1 2.11 3.11.0 From 94e68d1237c3182397a9372c91fb6ac3a90a28e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 10:18:20 +0100 Subject: [PATCH 079/644] chore(deps): bump actions/setup-java from 3 to 4 (#2133) Bumps [actions/setup-java](https://github.com/actions/setup-java) from 3 to 4. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-java dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/e2e-test.yml | 2 +- .github/workflows/integration-tests.yml | 2 +- .github/workflows/pr.yml | 4 ++-- .github/workflows/release-project-in-dir.yml | 4 ++-- .github/workflows/snapshot-releases.yml | 4 ++-- .github/workflows/sonar.yml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 189d25a072..f14823f4fa 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -38,7 +38,7 @@ jobs: driver: docker - name: Set up Java and Maven - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 17 distribution: temurin diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index a66ade82a9..3eb4e9ef5f 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -28,7 +28,7 @@ jobs: run: echo "Running ITs with ${{ inputs.http-client }}, ${{ inputs.kube-version }}, ${{ inputs.java-version }}" - uses: actions/checkout@v4 - name: Set up Java and Maven - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin java-version: ${{ inputs.java-version }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 47fd168516..19a217b222 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -19,7 +19,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Java and Maven - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin java-version: 17 @@ -60,7 +60,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Java and Maven - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin java-version: ${{ matrix.java }} diff --git a/.github/workflows/release-project-in-dir.yml b/.github/workflows/release-project-in-dir.yml index fa8bcc453d..b271f05f02 100644 --- a/.github/workflows/release-project-in-dir.yml +++ b/.github/workflows/release-project-in-dir.yml @@ -24,7 +24,7 @@ jobs: ref: "${{inputs.version_branch}}" - name: Set up Java and Maven - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 11 distribution: temurin @@ -59,7 +59,7 @@ jobs: ref: "${{inputs.version_branch}}" - name: Set up Java and Maven - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 11 distribution: temurin diff --git a/.github/workflows/snapshot-releases.yml b/.github/workflows/snapshot-releases.yml index 2df39ceba0..e5aff55e62 100644 --- a/.github/workflows/snapshot-releases.yml +++ b/.github/workflows/snapshot-releases.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Java and Maven - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin java-version: 11 @@ -31,7 +31,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Java and Maven - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin java-version: 11 diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 20f8d22c87..783f250669 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Java and Maven - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: temurin java-version: 17 From fd324218227760cb1e9f583dabb32bd78face23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 30 Nov 2023 11:29:59 +0100 Subject: [PATCH 080/644] improve: make sure there is no infinite recursion by default for external service (#2130) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../processing/dependent/AbstractDependentResource.java | 4 +--- .../dependent/AbstractExternalDependentResource.java | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java index 897664e08a..ea1e020bfb 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java @@ -85,9 +85,7 @@ protected ReconcileResult reconcile(P primary, R actualResource, Context

c return ReconcileResult.noOperation(actualResource); } - public Result match(R resource, P primary, Context

context) { - return updater.match(resource, primary, context); - } + public abstract Result match(R resource, P primary, Context

context); @Override public Optional getSecondaryResource(P primary, Context

context) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java index 4fb4c9bcd6..ef825ef71f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java @@ -76,6 +76,11 @@ protected void handleExplicitStateCreation(P primary, R created, Context

cont } } + @Override + public Matcher.Result match(R resource, P primary, Context

context) { + var desired = desired(primary, context); + return Matcher.Result.computed(resource.equals(desired), desired); + } @SuppressWarnings("unchecked") public void deleteTargetResource(P primary, R resource, String key, From ad45e02801d80e222529c8f569302bfb3829fe22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 08:12:27 +0100 Subject: [PATCH 081/644] chore(deps): bump org.apache.maven.plugins:maven-javadoc-plugin (#2137) Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.2 to 3.6.3. - [Release notes](https://github.com/apache/maven-javadoc-plugin/releases) - [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.2...maven-javadoc-plugin-3.6.3) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-javadoc-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- operator-framework-bom/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 0ada2a081e..e54776b161 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -63,7 +63,7 @@ 1.6.13 3.1.0 3.3.0 - 3.6.2 + 3.6.3 diff --git a/pom.xml b/pom.xml index 2ee7a888d9..41ac233c7e 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 2.11 3.11.0 3.2.2 - 3.6.2 + 3.6.3 3.3.1 3.3.0 3.3.0 From 1b97faa3a3fe9ddd58836a63924194681307af52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 08:14:18 +0100 Subject: [PATCH 082/644] chore(deps): bump org.apache.maven:maven-plugin-api from 3.9.5 to 3.9.6 (#2138) Bumps [org.apache.maven:maven-plugin-api](https://github.com/apache/maven) from 3.9.5 to 3.9.6. - [Release notes](https://github.com/apache/maven/releases) - [Commits](https://github.com/apache/maven/compare/maven-3.9.5...maven-3.9.6) --- updated-dependencies: - dependency-name: org.apache.maven:maven-plugin-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bootstrapper-maven-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index bc345bef7f..a077bb82ad 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -15,7 +15,7 @@ 3.10.2 - 3.9.5 + 3.9.6 From 557bedfe0123ffeff0ccba9223a35f0305a463f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 08:29:37 +0100 Subject: [PATCH 083/644] chore(deps-dev): bump org.mockito:mockito-core from 5.7.0 to 5.8.0 (#2139) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.7.0 to 5.8.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.7.0...v5.8.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 41ac233c7e..2298aeb4e0 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 6.9.2 1.7.36 2.22.0 - 5.7.0 + 5.8.0 3.14.0 0.19 1.13.0 From ce44b1964ddb1d8e8cbda511fd2da4841ee3444d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 08:35:46 +0100 Subject: [PATCH 084/644] chore(deps): bump org.awaitility:awaitility from 4.1.1 to 4.2.0 (#2143) Bumps [org.awaitility:awaitility](https://github.com/awaitility/awaitility) from 4.1.1 to 4.2.0. - [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt) - [Commits](https://github.com/awaitility/awaitility/compare/awaitility-4.1.1...awaitility-4.2.0) --- updated-dependencies: - dependency-name: org.awaitility:awaitility dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- sample-operators/tomcat-operator/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index b94068525a..ffb17e2cda 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -75,7 +75,7 @@ org.awaitility awaitility - 4.1.1 + 4.2.0 test From 29a6c22275f9181877ca0360f619a22679b7e25c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 08:37:00 +0100 Subject: [PATCH 085/644] chore(deps): bump okhttp.version from 4.10.0 to 4.12.0 (#2142) Bumps `okhttp.version` from 4.10.0 to 4.12.0. Updates `com.squareup.okhttp3:okhttp` from 4.10.0 to 4.12.0 - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.10.0...parent-4.12.0) Updates `com.squareup.okhttp3:logging-interceptor` from 4.10.0 to 4.12.0 - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.10.0...parent-4.12.0) Updates `com.squareup.okhttp3:mockwebserver` from 4.10.0 to 4.12.0 - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.10.0...parent-4.12.0) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.squareup.okhttp3:logging-interceptor dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.squareup.okhttp3:mockwebserver dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2298aeb4e0..740048811f 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ 4.2.0 2.7.3 1.12.0 - 4.10.0 + 4.12.0 3.1.3 0.9.0 0.9.10 From 35425fb1aa5870c3985b314e1c08d907ac1e7b9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 08:37:16 +0100 Subject: [PATCH 086/644] chore(deps): bump org.takes:takes from 1.21.1 to 1.24.4 (#2140) Bumps [org.takes:takes](https://github.com/yegor256/takes) from 1.21.1 to 1.24.4. - [Release notes](https://github.com/yegor256/takes/releases) - [Commits](https://github.com/yegor256/takes/compare/1.21.1...1.24.4) --- updated-dependencies: - dependency-name: org.takes:takes dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- sample-operators/leader-election/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 6933b2bc78..af8589be61 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -45,7 +45,7 @@ org.takes takes - 1.21.1 + 1.24.4 org.awaitility From ec6dffbc55e0637c5fdf7e6652fc3f9d485c04d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 09:00:36 +0100 Subject: [PATCH 087/644] chore(deps): bump com.github.ben-manes.caffeine:caffeine (#2141) Bumps [com.github.ben-manes.caffeine:caffeine](https://github.com/ben-manes/caffeine) from 3.1.3 to 3.1.8. - [Release notes](https://github.com/ben-manes/caffeine/releases) - [Commits](https://github.com/ben-manes/caffeine/compare/v3.1.3...v3.1.8) --- updated-dependencies: - dependency-name: com.github.ben-manes.caffeine:caffeine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 740048811f..8d193cafcb 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ 2.7.3 1.12.0 4.12.0 - 3.1.3 + 3.1.8 0.9.0 0.9.10 2.15.1 From 66149757d8b4396e4f3bc6d72d54c9363c02748b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 08:47:05 +0100 Subject: [PATCH 088/644] chore(deps): bump org.junit:junit-bom from 5.9.2 to 5.10.1 (#2150) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.9.2 to 5.10.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.2...r5.10.1) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8d193cafcb..5ef9ba60a9 100644 --- a/pom.xml +++ b/pom.xml @@ -43,7 +43,7 @@ https://sonarcloud.io okhttp - 5.9.2 + 5.10.1 6.9.2 1.7.36 2.22.0 From 2487729a5f9b3f161e85fa68a39ab9ab5817b1ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 08:47:18 +0100 Subject: [PATCH 089/644] chore(deps): bump com.github.spullara.mustache.java:compiler (#2149) Bumps [com.github.spullara.mustache.java:compiler](https://github.com/spullara/mustache.java) from 0.9.10 to 0.9.11. - [Commits](https://github.com/spullara/mustache.java/compare/0.9.10...mustache.java-0.9.11) --- updated-dependencies: - dependency-name: com.github.spullara.mustache.java:compiler dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5ef9ba60a9..0643bd0a42 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ 4.12.0 3.1.8 0.9.0 - 0.9.10 + 0.9.11 2.15.1 2.11 From 933612d2410b2a458876c63db995d077a686bb61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 08:47:34 +0100 Subject: [PATCH 090/644] chore(deps): bump org.codehaus.mojo:templating-maven-plugin (#2148) Bumps [org.codehaus.mojo:templating-maven-plugin](https://github.com/mojohaus/templating-maven-plugin) from 1.0.0 to 3.0.0. - [Release notes](https://github.com/mojohaus/templating-maven-plugin/releases) - [Commits](https://github.com/mojohaus/templating-maven-plugin/compare/templating-maven-plugin-1.0.0...3.0.0) --- updated-dependencies: - dependency-name: org.codehaus.mojo:templating-maven-plugin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bootstrapper-maven-plugin/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index a077bb82ad..f797a7d56f 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -79,7 +79,7 @@ org.codehaus.mojo templating-maven-plugin - 1.0.0 + 3.0.0 filtering-java-templates diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index 92396da92a..b4afcf0d33 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -50,7 +50,7 @@ org.codehaus.mojo templating-maven-plugin - 1.0.0 + 3.0.0 filtering-java-templates From bb32222e6b347f54f6470d9d0749d6bcb00a4adf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 08:47:46 +0100 Subject: [PATCH 091/644] chore(deps-dev): bump com.google.testing.compile:compile-testing (#2147) Bumps [com.google.testing.compile:compile-testing](https://github.com/google/compile-testing) from 0.19 to 0.21.0. - [Release notes](https://github.com/google/compile-testing/releases) - [Commits](https://github.com/google/compile-testing/compare/compile-testing-0.19...v0.21.0) --- updated-dependencies: - dependency-name: com.google.testing.compile:compile-testing dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0643bd0a42..16b399d445 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ 2.22.0 5.8.0 3.14.0 - 0.19 + 0.21.0 1.13.0 3.24.2 4.2.0 From da8bba9985f4460cbdaa39fda1f49c8101c197e3 Mon Sep 17 00:00:00 2001 From: Steven Hawkins Date: Thu, 7 Dec 2023 06:32:25 -0500 Subject: [PATCH 092/644] fix: preserve the original itemstore (#2154) closes: #2152 Signed-off-by: Steven Hawkins --- .../ControllerConfigurationOverrider.java | 1 + .../ControllerConfigurationOverriderTest.java | 23 ++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java index 88a28480bd..328d912109 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java @@ -58,6 +58,7 @@ private ControllerConfigurationOverrider(ControllerConfiguration original) { this.name = original.getName(); this.fieldManager = original.fieldManager(); this.informerListLimit = original.getInformerListLimit().orElse(null); + this.itemStore = original.getItemStore().orElse(null); } public ControllerConfigurationOverrider withFinalizer(String finalizer) { diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java index eae4c22ac6..1c86886d89 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverriderTest.java @@ -7,6 +7,9 @@ import org.junit.jupiter.api.Test; import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.client.informers.cache.BasicItemStore; +import io.fabric8.kubernetes.client.informers.cache.Cache; import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfigurationResolver; import io.javaoperatorsdk.operator.api.reconciler.Constants; import io.javaoperatorsdk.operator.api.reconciler.Context; @@ -130,7 +133,15 @@ private io.javaoperatorsdk.operator.api.config.ControllerConfiguration create return configurationService.configFor(reconciler); } - @ControllerConfiguration(namespaces = "foo") + private static class MyItemStore extends BasicItemStore { + + public MyItemStore() { + super(Cache::metaNamespaceKeyFunc); + } + + } + + @ControllerConfiguration(namespaces = "foo", itemStore = MyItemStore.class) private static class WatchCurrentReconciler implements Reconciler { @Override @@ -187,6 +198,16 @@ void overridingNamespacesShouldWork() { assertFalse(configuration.watchCurrentNamespace()); } + @Test + void itemStorePreserved() { + var configuration = createConfiguration(new WatchCurrentReconciler()); + + configuration = ControllerConfigurationOverrider.override(configuration) + .build(); + + assertNotNull(configuration.getItemStore().orElse(null)); + } + @Test void configuredDependentShouldNotChangeOnParentOverrideEvenWhenInitialConfigIsSame() { var configuration = createConfiguration(new OverriddenNSOnDepReconciler()); From 4969493db4496e56851c646a9347d6ea422ae8fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Dec 2023 08:28:23 +0100 Subject: [PATCH 093/644] chore(deps): bump actions/stale from 8 to 9 (#2155) Bumps [actions/stale](https://github.com/actions/stale) from 8 to 9. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v8...v9) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale-issues-and-prs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale-issues-and-prs.yml b/.github/workflows/stale-issues-and-prs.yml index 5564f60d22..db295a49b6 100644 --- a/.github/workflows/stale-issues-and-prs.yml +++ b/.github/workflows/stale-issues-and-prs.yml @@ -8,7 +8,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v8 + - uses: actions/stale@v9 with: days-before-issue-stale: 60 days-before-pr-stale: 60 From 5f05c70f24f7835e279abfb82e5ae5cccd584109 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 08:41:09 +0100 Subject: [PATCH 094/644] chore(deps): bump io.micrometer:micrometer-core from 1.12.0 to 1.12.1 (#2156) Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.12.0 to 1.12.1. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.12.0...v1.12.1) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 16b399d445..6ca4f9684f 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 3.24.2 4.2.0 2.7.3 - 1.12.0 + 1.12.1 4.12.0 3.1.8 0.9.0 From c761ffa75f5759f6a919ff4f791bcdc4f139cba8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 08:55:58 +0100 Subject: [PATCH 095/644] chore(deps): bump org.apache.maven.plugins:maven-surefire-plugin (#2160) Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.2.2 to 3.2.3. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.2.2...surefire-3.2.3) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6ca4f9684f..e447116c50 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 2.11 3.11.0 - 3.2.2 + 3.2.3 3.6.3 3.3.1 3.3.0 From 5a9cdbdfa540273a5fff10d319eb6cb5527e1cdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 14 Dec 2023 17:03:30 +0100 Subject: [PATCH 096/644] improve: api for dynamic registration of event sources (#2162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes also a typo Signed-off-by: Attila Mészáros --- .../workflow/WorkflowReconcileExecutor.java | 2 +- .../processing/event/EventSourceManager.java | 20 +++++++++---------- .../event/EventSourceRetriever.java | 9 ++++++--- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java index 27b5ad45da..33aad99811 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java @@ -84,7 +84,7 @@ private void registerOrDeregisterEventSourceBasedOnActivation(boolean activa if (activationConditionMet) { var eventSource = dependentResourceNode.getDependentResource().eventSource(context.eventSourceRetriever() - .eventSourceContexForDynamicRegistration()); + .eventSourceContextForDynamicRegistration()); var es = eventSource.orElseThrow(); context.eventSourceRetriever() .dynamicallyRegisterEventSource(dependentResourceNode.getName(), es); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java index 824c24e276..5ae700cedc 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java @@ -1,10 +1,6 @@ package io.javaoperatorsdk.operator.processing.event; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -233,24 +229,28 @@ public List> getResourceEventSourcesFor(Class d } @Override - public synchronized void dynamicallyRegisterEventSource(String name, EventSource eventSource) { - if (eventSources.existing(name, eventSource) != null) { - return; + public synchronized EventSource dynamicallyRegisterEventSource(String name, + EventSource eventSource) { + var es = eventSources.existing(name, eventSource); + if (es != null) { + return es; } registerEventSource(name, eventSource); eventSource.start(); + return eventSource; } @Override - public synchronized void dynamicallyDeRegisterEventSource(String name) { + public synchronized Optional dynamicallyDeRegisterEventSource(String name) { EventSource es = eventSources.remove(name); if (es != null) { es.stop(); } + return Optional.ofNullable(es); } @Override - public EventSourceContext

eventSourceContexForDynamicRegistration() { + public EventSourceContext

eventSourceContextForDynamicRegistration() { return controller.eventSourceContext(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceRetriever.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceRetriever.java index 67f149f5cd..a8e7e24f81 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceRetriever.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceRetriever.java @@ -1,6 +1,7 @@ package io.javaoperatorsdk.operator.processing.event; import java.util.List; +import java.util.Optional; import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; @@ -40,8 +41,9 @@ default ResourceEventSource getResourceEventSourceFor(Class depende * * @param name of the event source * @param eventSource to register + * @return the actual event source registered. Might not be the same as the parameter. */ - void dynamicallyRegisterEventSource(String name, EventSource eventSource); + EventSource dynamicallyRegisterEventSource(String name, EventSource eventSource); /** * De-registers (and stops) the {@link EventSource} associated with the specified name. If no such @@ -57,9 +59,10 @@ default ResourceEventSource getResourceEventSourceFor(Class depende *

* * @param name of the event source + * @return the actual event source deregistered if there is one. */ - void dynamicallyDeRegisterEventSource(String name); + Optional dynamicallyDeRegisterEventSource(String name); - EventSourceContext

eventSourceContexForDynamicRegistration(); + EventSourceContext

eventSourceContextForDynamicRegistration(); } From 0b2ec1b62304e206adef7d97491d15634c24c81f Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 14 Dec 2023 16:56:46 +0000 Subject: [PATCH 097/644] Set new SNAPSHOT version into pom files. --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index f797a7d56f..2ba35a5d2e 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index fb5e2c98a1..2ac26e16dc 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 3e640e3e7f..3e92098646 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index e54776b161..9c08334519 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index b4afcf0d33..732a126da2 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index a80d03d69e..38c7a5b436 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index ff38d5fc66..4fad02a464 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index e447116c50..946529026c 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index af8589be61..e98d7ced0e 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index c69c388299..fffc71c54a 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index f7b1b4dfcb..8630639daa 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index ffb17e2cda..082ae4fba9 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 8cbac1f178..845ea520ef 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.1-SNAPSHOT + 4.6.2-SNAPSHOT sample-webpage-operator From 876fa56c3bb72da7363e2547d5dc17b6ada6f9b3 Mon Sep 17 00:00:00 2001 From: Lan Date: Mon, 18 Dec 2023 02:58:29 +0800 Subject: [PATCH 098/644] CI with kubernetes v1.29.0 (#2164) Signed-off-by: Lan Liang --- .github/workflows/pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 19a217b222..686647b46d 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -35,7 +35,7 @@ jobs: strategy: matrix: java: [ 11, 17 ] - kubernetes: [ 'v1.25.14', 'v1.26.9', 'v1.27.6', 'v1.28.2' ] + kubernetes: [ 'v1.25.14', 'v1.26.9', 'v1.27.6', 'v1.28.2', 'v1.29.0' ] uses: ./.github/workflows/integration-tests.yml with: java-version: ${{ matrix.java }} From 166cb13016e837862298cbd0072568779fb673ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 08:27:24 +0100 Subject: [PATCH 099/644] chore(deps): bump org.apache.maven.plugins:maven-compiler-plugin (#2168) Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.11.0 to 3.12.0. - [Release notes](https://github.com/apache/maven-compiler-plugin/releases) - [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.11.0...maven-compiler-plugin-3.12.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-compiler-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 946529026c..be8c45234d 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 2.15.1 2.11 - 3.11.0 + 3.12.0 3.2.3 3.6.3 3.3.1 diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index e98d7ced0e..1ed237df6a 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -81,7 +81,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.0 diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index fffc71c54a..0d0ad4216a 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -108,7 +108,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.0 diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 082ae4fba9..86af580266 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -110,7 +110,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.0 diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 845ea520ef..bb65c15568 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -81,7 +81,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.0 From 16066ea738a33a9577bf84bc07a82a9a2e01582a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 19 Dec 2023 11:25:20 +0100 Subject: [PATCH 100/644] fix: misleading warning message on workflow execution (#2170) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../dependent/workflow/AbstractWorkflowExecutor.java | 11 +++++++---- .../operator/DependentOperationEventFilterIT.java | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java index 6aab0f1f39..c546570e34 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java @@ -44,17 +44,20 @@ public AbstractWorkflowExecutor(Workflow

workflow, P primary, Context

cont protected abstract Logger logger(); protected synchronized void waitForScheduledExecutionsToRun() { + // in case when workflow just contains non-activated dependents, + // it needs to be checked first if there are already no executions + // scheduled at the beginning. + if (noMoreExecutionsScheduled()) { + return; + } while (true) { try { - // in case when workflow just contains non-activated dependents, - // it needs to be checked first if there are already no executions - // scheduled at the beginning. + this.wait(); if (noMoreExecutionsScheduled()) { break; } else { logger().warn("Notified but still resources under execution. This should not happen."); } - this.wait(); } catch (InterruptedException e) { if (noMoreExecutionsScheduled()) { logger().debug("interrupted, no more executions for: {}", primaryID); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentOperationEventFilterIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentOperationEventFilterIT.java index 1d0c091e16..eb354bf96d 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentOperationEventFilterIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentOperationEventFilterIT.java @@ -25,6 +25,7 @@ class DependentOperationEventFilterIT { @RegisterExtension LocallyRunOperatorExtension operator = LocallyRunOperatorExtension.builder() + .withNamespaceDeleteTimeout(2) .withReconciler(new DependentOperationEventFilterCustomResourceTestReconciler()) .build(); From 50a6b2d3546bdd30440116a3584e833e903042b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Dec 2023 15:34:54 +0100 Subject: [PATCH 101/644] chore(deps): bump org.apache.maven.plugins:maven-compiler-plugin (#2176) Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.12.0 to 3.12.1. - [Release notes](https://github.com/apache/maven-compiler-plugin/releases) - [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.12.0...maven-compiler-plugin-3.12.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-compiler-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index be8c45234d..6bd5570db4 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 2.15.1 2.11 - 3.12.0 + 3.12.1 3.2.3 3.6.3 3.3.1 diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 1ed237df6a..0244b3244d 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -81,7 +81,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.0 + 3.12.1 diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 0d0ad4216a..214c1e55b5 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -108,7 +108,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.0 + 3.12.1 diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 86af580266..f29120500d 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -110,7 +110,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.0 + 3.12.1 diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index bb65c15568..2340439ca1 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -81,7 +81,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.0 + 3.12.1 From 45b1f039cd10d0898a7ae54b2a5fbc6a5c7ce526 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Dec 2023 12:06:59 +0100 Subject: [PATCH 102/644] chore(deps): bump log4j.version from 2.22.0 to 2.22.1 (#2177) Bumps `log4j.version` from 2.22.0 to 2.22.1. Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.22.0 to 2.22.1 Updates `org.apache.logging.log4j:log4j-core` from 2.22.0 to 2.22.1 Updates `org.apache.logging.log4j:log4j2-core` from 2.22.0 to 2.22.1 --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-slf4j-impl dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.logging.log4j:log4j2-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6bd5570db4..2f41b09886 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ 5.10.1 6.9.2 1.7.36 - 2.22.0 + 2.22.1 5.8.0 3.14.0 0.21.0 From 0e3886bf005633b75be4b45e75b0cad0e62787ae Mon Sep 17 00:00:00 2001 From: Ramesh Malla Date: Fri, 29 Dec 2023 19:15:52 +0100 Subject: [PATCH 103/644] feat: make ConfigurationServiceOverrider accept dependent resource factory (#2175) * feat:Made ConfigurationServiceOverrider to accept dependent resource factory Signed-off-by: Ramesh Malla * Code refactor Signed-off-by: Ramesh Malla * Format code Signed-off-by: Ramesh Malla --------- Signed-off-by: Ramesh Malla Co-authored-by: Ramesh Malla --- .../api/config/ConfigurationServiceOverrider.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java index 2a2f6964c1..5879383464 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java @@ -12,6 +12,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.monitoring.Metrics; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceFactory; @SuppressWarnings("unused") public class ConfigurationServiceOverrider { @@ -39,6 +40,7 @@ public class ConfigurationServiceOverrider { private Set> defaultNonSSAResource; private Boolean previousAnnotationForDependentResources; private Boolean parseResourceVersions; + private DependentResourceFactory dependentResourceFactory; ConfigurationServiceOverrider(ConfigurationService original) { this.original = original; @@ -77,6 +79,12 @@ public ConfigurationServiceOverrider withMinConcurrentWorkflowExecutorThreads(in return this; } + public ConfigurationServiceOverrider withDependentResourceFactory( + DependentResourceFactory dependentResourceFactory) { + this.dependentResourceFactory = dependentResourceFactory; + return this; + } + public ConfigurationServiceOverrider withResourceCloner(Cloner cloner) { this.cloner = cloner; return this; @@ -184,6 +192,12 @@ public boolean checkCRDAndValidateLocalModel() { return checkCR != null ? checkCR : original.checkCRDAndValidateLocalModel(); } + @Override + public DependentResourceFactory dependentResourceFactory() { + return dependentResourceFactory != null ? dependentResourceFactory + : DependentResourceFactory.DEFAULT; + } + @Override public int concurrentReconciliationThreads() { return Utils.ensureValid( From 3a89e8e1c48add6398efe9cd0cf798f01caa48e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 15:17:11 +0100 Subject: [PATCH 104/644] chore(deps): bump org.assertj:assertj-core from 3.24.2 to 3.25.0 (#2179) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2f41b09886..4dc2d2f823 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ 3.14.0 0.21.0 1.13.0 - 3.24.2 + 3.25.0 4.2.0 2.7.3 1.12.1 From b8c885e7e2df090f9fcc75ea5075b6bc20db1f44 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 09:02:47 +0100 Subject: [PATCH 105/644] chore(deps): bump manusa/actions-setup-minikube from 2.9.0 to 2.10.0 (#2181) Bumps [manusa/actions-setup-minikube](https://github.com/manusa/actions-setup-minikube) from 2.9.0 to 2.10.0. - [Release notes](https://github.com/manusa/actions-setup-minikube/releases) - [Commits](https://github.com/manusa/actions-setup-minikube/compare/v2.9.0...v2.10.0) --- updated-dependencies: - dependency-name: manusa/actions-setup-minikube dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/e2e-test.yml | 2 +- .github/workflows/integration-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index f14823f4fa..be3732c42c 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -30,7 +30,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Minikube-Kubernetes - uses: manusa/actions-setup-minikube@v2.9.0 + uses: manusa/actions-setup-minikube@v2.10.0 with: minikube version: v1.31.2 kubernetes version: v1.28.2 diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 3eb4e9ef5f..fbac44faa9 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -34,7 +34,7 @@ jobs: java-version: ${{ inputs.java-version }} cache: 'maven' - name: Set up Minikube - uses: manusa/actions-setup-minikube@v2.9.0 + uses: manusa/actions-setup-minikube@v2.10.0 with: minikube version: v1.31.2 kubernetes version: ${{ inputs.kube-version }} From f105ff168ef28c97812d227e90d86c4a44e9579b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jan 2024 09:03:23 +0100 Subject: [PATCH 106/644] chore(deps): bump org.assertj:assertj-core from 3.25.0 to 3.25.1 (#2180) Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.0 to 3.25.1. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.0...assertj-build-3.25.1) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4dc2d2f823..32ad5c1429 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ 3.14.0 0.21.0 1.13.0 - 3.25.0 + 3.25.1 4.2.0 2.7.3 1.12.1 From 706ba26d450a39a72cbf0a72c16ef5bd62399df9 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 5 Jan 2024 15:09:37 +0000 Subject: [PATCH 107/644] Set new SNAPSHOT version into pom files. --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 2ba35a5d2e..a24c2844a3 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index 2ac26e16dc..f43c9044e4 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 3e92098646..000c6bb08d 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 9c08334519..d2844d0022 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index 732a126da2..b4e81c5857 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 38c7a5b436..21be322999 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index 4fad02a464..3eaf842ab5 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 32ad5c1429..c4ac25c569 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 0244b3244d..60bb410ceb 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 214c1e55b5..f4562e5fc8 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 8630639daa..6749d5b887 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index f29120500d..bca29f4bf0 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 2340439ca1..ba73f69d37 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.2-SNAPSHOT + 4.6.3-SNAPSHOT sample-webpage-operator From 3f232dd7a94b201be6e2badb855574edb04484ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jan 2024 08:53:50 +0100 Subject: [PATCH 108/644] chore(deps): bump org.apache.maven.plugins:maven-surefire-plugin (#2192) Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.2.3 to 3.2.5. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.2.3...surefire-3.2.5) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c4ac25c569..9b7bfbe744 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 2.11 3.12.1 - 3.2.3 + 3.2.5 3.6.3 3.3.1 3.3.0 From fefb840fe25cf72910cad041e0e69f12ea1c4fff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jan 2024 08:54:35 +0100 Subject: [PATCH 109/644] chore(deps): bump io.micrometer:micrometer-core from 1.12.1 to 1.12.2 (#2191) Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.12.1 to 1.12.2. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.12.1...v1.12.2) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9b7bfbe744..54732fe0a1 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 3.25.1 4.2.0 2.7.3 - 1.12.1 + 1.12.2 4.12.0 3.1.8 0.9.0 From 2d0a99ea5d2c8525c04cc33ee5064363facad572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 22 Nov 2023 13:18:40 +0100 Subject: [PATCH 110/644] chore: change version to 4.7.0-SNAPSHOT (#2132) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 4 ++-- sample-operators/mysql-schema/pom.xml | 4 ++-- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 4 ++-- sample-operators/webpage/pom.xml | 4 ++-- 13 files changed, 17 insertions(+), 17 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index a24c2844a3..b82bcc11f4 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index f43c9044e4..a63c5889fe 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 000c6bb08d..6f6669999a 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index d2844d0022..75ead60afa 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index b4e81c5857..dc054d587a 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 21be322999..9366485f25 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index 3eaf842ab5..430cc508b2 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 54732fe0a1..0e8b9a4459 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 60bb410ceb..ea18538d30 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT sample-leader-election @@ -81,7 +81,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.11.0 diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index f4562e5fc8..7dba03f3d9 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT sample-mysql-schema-operator @@ -108,7 +108,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.11.0 diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 6749d5b887..56c7834d03 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index bca29f4bf0..89e243ba0a 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT sample-tomcat-operator @@ -110,7 +110,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.11.0 diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index ba73f69d37..e0becee1a5 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.6.3-SNAPSHOT + 4.7.0-SNAPSHOT sample-webpage-operator @@ -81,7 +81,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.11.0 From 7a4386884679dc1158e7ac931077c2e5549885df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 13 Dec 2023 22:31:21 +0100 Subject: [PATCH 111/644] feat: generic kubernetes resource usage (#2136) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- docs/documentation/dependent-resources.md | 10 +++ .../micrometer/MicrometerMetrics.java | 6 +- .../config/DefaultResourceConfiguration.java | 7 +- .../api/config/ExecutorServiceManager.java | 2 +- .../informer/InformerConfiguration.java | 42 +++++++++- .../operator/processing/GroupVersionKind.java | 63 ++++++++++++++- .../GenericKubernetesDependentResource.java | 25 ++++++ .../KubernetesDependentResource.java | 6 +- .../source/informer/InformerEventSource.java | 7 +- .../source/informer/InformerWrapper.java | 4 + .../informer/ManagedInformerEventSource.java | 10 +-- .../processing/GroupVersionKindTest.java | 21 +++++ .../GenericKubernetesDependentManagedIT.java | 36 +++++++++ ...enericKubernetesDependentStandaloneIT.java | 35 +++++++++ .../GenericKubernetesDependentTestBase.java | 52 +++++++++++++ .../GenericKubernetesResourceHandlingIT.java | 36 +++++++++ .../GenericKubernetesDependentSpec.java | 15 ++++ .../ConfigMapGenericKubernetesDependent.java | 46 +++++++++++ ...ernetesDependentManagedCustomResource.java | 16 ++++ ...cKubernetesDependentManagedReconciler.java | 19 +++++ .../ConfigMapGenericKubernetesDependent.java | 46 +++++++++++ ...etesDependentStandaloneCustomResource.java | 16 ++++ ...bernetesDependentStandaloneReconciler.java | 33 ++++++++ ...ernetesResourceHandlingCustomResource.java | 16 ++++ ...cKubernetesResourceHandlingReconciler.java | 77 +++++++++++++++++++ .../src/test/resources/configmap.yaml | 6 ++ 26 files changed, 632 insertions(+), 20 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesDependentResource.java create mode 100644 operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/GroupVersionKindTest.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesDependentManagedIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesDependentStandaloneIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesDependentTestBase.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesResourceHandlingIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/GenericKubernetesDependentSpec.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentresourcemanaged/ConfigMapGenericKubernetesDependent.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentresourcemanaged/GenericKubernetesDependentManagedCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentresourcemanaged/GenericKubernetesDependentManagedReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentstandalone/ConfigMapGenericKubernetesDependent.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentstandalone/GenericKubernetesDependentStandaloneCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentstandalone/GenericKubernetesDependentStandaloneReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesresourcehandling/GenericKubernetesResourceHandlingCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesresourcehandling/GenericKubernetesResourceHandlingReconciler.java create mode 100644 operator-framework/src/test/resources/configmap.yaml diff --git a/docs/documentation/dependent-resources.md b/docs/documentation/dependent-resources.md index 06149cf8ba..7678e997e6 100644 --- a/docs/documentation/dependent-resources.md +++ b/docs/documentation/dependent-resources.md @@ -483,6 +483,16 @@ also be created, one per dependent resource. See [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/ExternalStateBulkIT.java) as a sample. + +## GenericKubernetesResource based Dependent Resources + +In rare circumstances resource handling where there is no class representation or just typeless handling might be needed. +Fabric8 Client provides [GenericKubernetesResource](https://github.com/fabric8io/kubernetes-client/blob/main/doc/CHEATSHEET.md#resource-typeless-api) +to support that. + +For dependent resource this is supported by [GenericKubernetesDependentResource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesDependentResource.java#L8-L8) +. See samples [here](https://github.com/java-operator-sdk/java-operator-sdk/tree/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource). + ## Other Dependent Resource Features ### Caching and Event Handling in [KubernetesDependentResource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java) diff --git a/micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetrics.java b/micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetrics.java index 61ff1562ee..b819bd0ca3 100644 --- a/micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetrics.java +++ b/micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetrics.java @@ -291,9 +291,9 @@ private static String getScope(ResourceID resourceID) { } private static void addGVKTags(GroupVersionKind gvk, List tags, boolean prefixed) { - addTagOmittingOnEmptyValue(GROUP, gvk.group, tags, prefixed); - addTag(VERSION, gvk.version, tags, prefixed); - addTag(KIND, gvk.kind, tags, prefixed); + addTagOmittingOnEmptyValue(GROUP, gvk.getGroup(), tags, prefixed); + addTag(VERSION, gvk.getVersion(), tags, prefixed); + addTag(KIND, gvk.getKind(), tags, prefixed); } private void incrementCounter(ResourceID id, String counterName, Map metadata, diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java index 87d8a6cd80..f8ee9f4e84 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultResourceConfiguration.java @@ -3,6 +3,7 @@ import java.util.Optional; import java.util.Set; +import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.informers.cache.ItemStore; import io.javaoperatorsdk.operator.ReconcilerUtils; @@ -28,7 +29,11 @@ protected DefaultResourceConfiguration(Class resourceClass, OnUpdateFilter onUpdateFilter, GenericFilter genericFilter, ItemStore itemStore, Long informerListLimit) { this.resourceClass = resourceClass; - this.resourceTypeName = ReconcilerUtils.getResourceTypeName(resourceClass); + this.resourceTypeName = resourceClass.isAssignableFrom(GenericKubernetesResource.class) + // in general this is irrelevant now for secondary resources it is used just by controller + // where GenericKubernetesResource now does not apply + ? GenericKubernetesResource.class.getSimpleName() + : ReconcilerUtils.getResourceTypeName(resourceClass); this.onAddFilter = onAddFilter; this.onUpdateFilter = onUpdateFilter; this.genericFilter = genericFilter; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ExecutorServiceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ExecutorServiceManager.java index 4685fb1d57..62f345426c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ExecutorServiceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ExecutorServiceManager.java @@ -78,7 +78,7 @@ public static void executeAndWaitForAllToComplete(Stream stream, // to find out any exceptions f.get(); } catch (ExecutionException e) { - throw new OperatorException(e.getCause()); + throw new OperatorException(e); } catch (InterruptedException e) { log.warn("Interrupted.", e); Thread.currentThread().interrupt(); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java index 4b0007c96e..bca39b189c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java @@ -4,12 +4,14 @@ import java.util.Optional; import java.util.Set; +import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.informers.cache.ItemStore; import io.javaoperatorsdk.operator.api.config.DefaultResourceConfiguration; import io.javaoperatorsdk.operator.api.config.ResourceConfiguration; import io.javaoperatorsdk.operator.api.config.Utils; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.processing.GroupVersionKind; import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper; import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter; @@ -30,9 +32,11 @@ class DefaultInformerConfiguration extends private final SecondaryToPrimaryMapper secondaryToPrimaryMapper; private final boolean followControllerNamespaceChanges; private final OnDeleteFilter onDeleteFilter; + private final GroupVersionKind groupVersionKind; protected DefaultInformerConfiguration(String labelSelector, Class resourceClass, + GroupVersionKind groupVersionKind, PrimaryToSecondaryMapper primaryToSecondaryMapper, SecondaryToPrimaryMapper secondaryToPrimaryMapper, Set namespaces, boolean followControllerNamespaceChanges, @@ -44,7 +48,7 @@ protected DefaultInformerConfiguration(String labelSelector, super(resourceClass, namespaces, labelSelector, onAddFilter, onUpdateFilter, genericFilter, itemStore, informerListLimit); this.followControllerNamespaceChanges = followControllerNamespaceChanges; - + this.groupVersionKind = groupVersionKind; this.primaryToSecondaryMapper = primaryToSecondaryMapper; this.secondaryToPrimaryMapper = Objects.requireNonNullElse(secondaryToPrimaryMapper, @@ -72,6 +76,10 @@ public Optional> onDeleteFilter() { public

PrimaryToSecondaryMapper

getPrimaryToSecondaryMapper() { return (PrimaryToSecondaryMapper

) primaryToSecondaryMapper; } + + public Optional getGroupVersionKind() { + return Optional.ofNullable(groupVersionKind); + } } /** @@ -109,14 +117,17 @@ public

PrimaryToSecondaryMapper

getPrimaryToSecondary

PrimaryToSecondaryMapper

getPrimaryToSecondaryMapper(); + Optional getGroupVersionKind(); + @SuppressWarnings("unused") class InformerConfigurationBuilder { + private final Class resourceClass; + private final GroupVersionKind groupVersionKind; private PrimaryToSecondaryMapper primaryToSecondaryMapper; private SecondaryToPrimaryMapper secondaryToPrimaryMapper; private Set namespaces; private String labelSelector; - private final Class resourceClass; private OnAddFilter onAddFilter; private OnUpdateFilter onUpdateFilter; private OnDeleteFilter onDeleteFilter; @@ -127,6 +138,13 @@ class InformerConfigurationBuilder { private InformerConfigurationBuilder(Class resourceClass) { this.resourceClass = resourceClass; + this.groupVersionKind = null; + } + + @SuppressWarnings("unchecked") + private InformerConfigurationBuilder(GroupVersionKind groupVersionKind) { + this.resourceClass = (Class) GenericKubernetesResource.class; + this.groupVersionKind = groupVersionKind; } public

InformerConfigurationBuilder withPrimaryToSecondaryMapper( @@ -244,7 +262,7 @@ public InformerConfigurationBuilder withInformerListLimit(Long informerListLi } public InformerConfiguration build() { - return new DefaultInformerConfiguration<>(labelSelector, resourceClass, + return new DefaultInformerConfiguration<>(labelSelector, resourceClass, groupVersionKind, primaryToSecondaryMapper, secondaryToPrimaryMapper, namespaces, inheritControllerNamespacesOnChange, onAddFilter, onUpdateFilter, @@ -257,6 +275,14 @@ static InformerConfigurationBuilder from( return new InformerConfigurationBuilder<>(resourceClass); } + /** + * * For the case when want to use {@link GenericKubernetesResource} + */ + static InformerConfigurationBuilder from( + GroupVersionKind groupVersionKind) { + return new InformerConfigurationBuilder<>(groupVersionKind); + } + /** * Creates a configuration builder that inherits namespaces from the controller and follows * namespaces changes. @@ -272,6 +298,16 @@ static InformerConfigurationBuilder from( .withNamespacesInheritedFromController(eventSourceContext); } + /** + * * For the case when want to use {@link GenericKubernetesResource} + */ + @SuppressWarnings("unchecked") + static InformerConfigurationBuilder from( + GroupVersionKind groupVersionKind, EventSourceContext eventSourceContext) { + return new InformerConfigurationBuilder(groupVersionKind) + .withNamespacesInheritedFromController(eventSourceContext); + } + @SuppressWarnings("unchecked") @Override default Class getResourceClass() { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/GroupVersionKind.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/GroupVersionKind.java index 1a8a4b595d..9e5cbea14d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/GroupVersionKind.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/GroupVersionKind.java @@ -1,13 +1,27 @@ package io.javaoperatorsdk.operator.processing; +import java.util.Objects; + import io.fabric8.kubernetes.api.model.HasMetadata; public class GroupVersionKind { - public final String group; - public final String version; - public final String kind; + private final String group; + private final String version; + private final String kind; - GroupVersionKind(String group, String version, String kind) { + public GroupVersionKind(String apiVersion, String kind) { + this.kind = kind; + String[] groupAndVersion = apiVersion.split("/"); + if (groupAndVersion.length == 1) { + this.group = null; + this.version = groupAndVersion[0]; + } else { + this.group = groupAndVersion[0]; + this.version = groupAndVersion[1]; + } + } + + public GroupVersionKind(String group, String version, String kind) { this.group = group; this.version = version; this.kind = kind; @@ -17,4 +31,45 @@ public static GroupVersionKind gvkFor(Class resourceClass return new GroupVersionKind(HasMetadata.getGroup(resourceClass), HasMetadata.getVersion(resourceClass), HasMetadata.getKind(resourceClass)); } + + public String getGroup() { + return group; + } + + public String getVersion() { + return version; + } + + public String getKind() { + return kind; + } + + public String apiVersion() { + return group == null || group.isBlank() ? version : group + "/" + version; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + GroupVersionKind that = (GroupVersionKind) o; + return Objects.equals(group, that.group) && Objects.equals(version, that.version) + && Objects.equals(kind, that.kind); + } + + @Override + public int hashCode() { + return Objects.hash(group, version, kind); + } + + @Override + public String toString() { + return "GroupVersionKind{" + + "group='" + group + '\'' + + ", version='" + version + '\'' + + ", kind='" + kind + '\'' + + '}'; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesDependentResource.java new file mode 100644 index 0000000000..98f2346577 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesDependentResource.java @@ -0,0 +1,25 @@ +package io.javaoperatorsdk.operator.processing.dependent.kubernetes; + +import io.fabric8.kubernetes.api.model.GenericKubernetesResource; +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; +import io.javaoperatorsdk.operator.processing.GroupVersionKind; + +public class GenericKubernetesDependentResource

+ extends KubernetesDependentResource { + + private GroupVersionKind groupVersionKind; + + public GenericKubernetesDependentResource(GroupVersionKind groupVersionKind) { + super(GenericKubernetesResource.class); + this.groupVersionKind = groupVersionKind; + } + + protected InformerConfiguration.InformerConfigurationBuilder informerConfigurationBuilder() { + return InformerConfiguration.from(groupVersionKind); + } + + public GroupVersionKind getGroupVersionKind() { + return groupVersionKind; + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index b587c72327..a4305df502 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -67,14 +67,18 @@ private void configureWith(String labelSelector, Set namespaces, namespaces = context.getControllerConfiguration().getNamespaces(); } - var ic = InformerConfiguration.from(resourceType()) + var ic = informerConfigurationBuilder() .withLabelSelector(labelSelector) .withSecondaryToPrimaryMapper(getSecondaryToPrimaryMapper()) .withNamespaces(namespaces, inheritNamespacesOnChange) .build(); configureWith(new InformerEventSource<>(ic, context)); + } + // just to seamlessly handle GenericKubernetesDependentResource + protected InformerConfiguration.InformerConfigurationBuilder informerConfigurationBuilder() { + return InformerConfiguration.from(resourceType()); } @SuppressWarnings("unchecked") diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index dfaec7c19e..81d31f7407 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -8,6 +8,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.informers.ResourceEventHandler; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; @@ -88,7 +89,11 @@ public InformerEventSource(InformerConfiguration configuration, KubernetesCli public InformerEventSource(InformerConfiguration configuration, KubernetesClient client, boolean parseResourceVersions) { - super(client.resources(configuration.getResourceClass()), configuration, parseResourceVersions); + super( + configuration.getGroupVersionKind() + .map(gvk -> client.genericKubernetesResources(gvk.apiVersion(), gvk.getKind())) + .orElseGet(() -> (MixedOperation) client.resources(configuration.getResourceClass())), + configuration, parseResourceVersions); // If there is a primary to secondary mapper there is no need for primary to secondary index. primaryToSecondaryMapper = configuration.getPrimaryToSecondaryMapper(); if (primaryToSecondaryMapper == null) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java index 639eac1a59..28cf33a041 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java @@ -13,6 +13,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.informers.ExceptionHandler; import io.fabric8.kubernetes.client.informers.ResourceEventHandler; @@ -113,6 +114,9 @@ public void start() throws OperatorException { private String versionedFullResourceName() { final var apiTypeClass = informer.getApiTypeClass(); + if (apiTypeClass.isAssignableFrom(GenericKubernetesResource.class)) { + return GenericKubernetesResource.class.getSimpleName(); + } return ReconcilerUtils.getResourceTypeNameWithVersion(apiTypeClass); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java index 7a1a6ba310..64d402ada5 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java @@ -9,9 +9,7 @@ import org.slf4j.LoggerFactory; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.api.model.KubernetesResourceList; import io.fabric8.kubernetes.client.dsl.MixedOperation; -import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.kubernetes.client.informers.ResourceEventHandler; import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.api.config.ConfigurationService; @@ -35,15 +33,15 @@ public abstract class ManagedInformerEventSource cache; - private boolean parseResourceVersions; + private final boolean parseResourceVersions; private ConfigurationService configurationService; - private C configuration; + private final C configuration; private Map>> indexers = new HashMap<>(); protected TemporaryResourceCache temporaryResourceCache; - protected MixedOperation, Resource> client; + protected MixedOperation client; protected ManagedInformerEventSource( - MixedOperation, Resource> client, C configuration, + MixedOperation client, C configuration, boolean parseResourceVersions) { super(configuration.getResourceClass()); this.parseResourceVersions = parseResourceVersions; diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/GroupVersionKindTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/GroupVersionKindTest.java new file mode 100644 index 0000000000..ad69cae800 --- /dev/null +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/GroupVersionKindTest.java @@ -0,0 +1,21 @@ +package io.javaoperatorsdk.operator.processing; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class GroupVersionKindTest { + + @Test + void testInitFromApiVersion() { + var gvk = new GroupVersionKind("v1", "ConfigMap"); + assertThat(gvk.getGroup()).isNull(); + assertThat(gvk.getVersion()).isEqualTo("v1"); + + gvk = new GroupVersionKind("apps/v1", "Deployment"); + assertThat(gvk.getGroup()).isEqualTo("apps"); + assertThat(gvk.getVersion()).isEqualTo("v1"); + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesDependentManagedIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesDependentManagedIT.java new file mode 100644 index 0000000000..f06185d402 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesDependentManagedIT.java @@ -0,0 +1,36 @@ +package io.javaoperatorsdk.operator; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.GenericKubernetesDependentSpec; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesdependentresourcemanaged.GenericKubernetesDependentManagedCustomResource; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesdependentresourcemanaged.GenericKubernetesDependentManagedReconciler; + +public class GenericKubernetesDependentManagedIT + extends GenericKubernetesDependentTestBase { + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(new GenericKubernetesDependentManagedReconciler()) + .build(); + + @Override + public LocallyRunOperatorExtension extension() { + return extension; + } + + @Override + GenericKubernetesDependentManagedCustomResource testResource(String name, String data) { + var resource = new GenericKubernetesDependentManagedCustomResource(); + resource.setMetadata(new ObjectMetaBuilder() + .withName(name) + .build()); + resource.setSpec(new GenericKubernetesDependentSpec()); + resource.getSpec().setValue(INITIAL_DATA); + return resource; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesDependentStandaloneIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesDependentStandaloneIT.java new file mode 100644 index 0000000000..708d2f119c --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesDependentStandaloneIT.java @@ -0,0 +1,35 @@ +package io.javaoperatorsdk.operator; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.GenericKubernetesDependentSpec; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesdependentstandalone.GenericKubernetesDependentStandaloneCustomResource; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesdependentstandalone.GenericKubernetesDependentStandaloneReconciler; + +public class GenericKubernetesDependentStandaloneIT + extends GenericKubernetesDependentTestBase { + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(new GenericKubernetesDependentStandaloneReconciler()) + .build(); + + @Override + public LocallyRunOperatorExtension extension() { + return extension; + } + + @Override + GenericKubernetesDependentStandaloneCustomResource testResource(String name, String data) { + var resource = new GenericKubernetesDependentStandaloneCustomResource(); + resource.setMetadata(new ObjectMetaBuilder() + .withName(name) + .build()); + resource.setSpec(new GenericKubernetesDependentSpec()); + resource.getSpec().setValue(INITIAL_DATA); + return resource; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesDependentTestBase.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesDependentTestBase.java new file mode 100644 index 0000000000..fea23b7796 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesDependentTestBase.java @@ -0,0 +1,52 @@ +package io.javaoperatorsdk.operator; + +import java.time.Duration; + +import org.junit.jupiter.api.Test; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.client.CustomResource; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.GenericKubernetesDependentSpec; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesdependentstandalone.ConfigMapGenericKubernetesDependent; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public abstract class GenericKubernetesDependentTestBase> { + + public static final String INITIAL_DATA = "Initial data"; + public static final String CHANGED_DATA = "Changed data"; + public static final String TEST_RESOURCE_NAME = "test1"; + + @Test + void testReconciliation() { + var resource = extension().create(testResource(TEST_RESOURCE_NAME, INITIAL_DATA)); + + await().untilAsserted(() -> { + var cm = extension().get(ConfigMap.class, TEST_RESOURCE_NAME); + assertThat(cm).isNotNull(); + assertThat(cm.getData()).containsEntry(ConfigMapGenericKubernetesDependent.KEY, INITIAL_DATA); + }); + + resource.getSpec().setValue(CHANGED_DATA); + resource = extension().replace(resource); + + await().untilAsserted(() -> { + var cm = extension().get(ConfigMap.class, TEST_RESOURCE_NAME); + assertThat(cm.getData()).containsEntry(ConfigMapGenericKubernetesDependent.KEY, CHANGED_DATA); + }); + + extension().delete(resource); + + await().timeout(Duration.ofSeconds(30)).untilAsserted(() -> { + var cm = extension().get(ConfigMap.class, TEST_RESOURCE_NAME); + assertThat(cm).isNull(); + }); + } + + public abstract LocallyRunOperatorExtension extension(); + + abstract R testResource(String name, String data); + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesResourceHandlingIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesResourceHandlingIT.java new file mode 100644 index 0000000000..b3ee935553 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/GenericKubernetesResourceHandlingIT.java @@ -0,0 +1,36 @@ +package io.javaoperatorsdk.operator; + +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.GenericKubernetesDependentSpec; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesresourcehandling.GenericKubernetesResourceHandlingCustomResource; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesresourcehandling.GenericKubernetesResourceHandlingReconciler; + +public class GenericKubernetesResourceHandlingIT + extends GenericKubernetesDependentTestBase { + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(new GenericKubernetesResourceHandlingReconciler()) + .build(); + + @Override + public LocallyRunOperatorExtension extension() { + return extension; + } + + @Override + GenericKubernetesResourceHandlingCustomResource testResource(String name, String data) { + var resource = new GenericKubernetesResourceHandlingCustomResource(); + resource.setMetadata(new ObjectMetaBuilder() + .withName(name) + .build()); + resource.setSpec(new GenericKubernetesDependentSpec()); + resource.getSpec().setValue(INITIAL_DATA); + return resource; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/GenericKubernetesDependentSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/GenericKubernetesDependentSpec.java new file mode 100644 index 0000000000..050e0cf520 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/GenericKubernetesDependentSpec.java @@ -0,0 +1,15 @@ +package io.javaoperatorsdk.operator.sample.generickubernetesresource; + +public class GenericKubernetesDependentSpec { + + private String value; + + public String getValue() { + return value; + } + + public GenericKubernetesDependentSpec setValue(String value) { + this.value = value; + return this; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentresourcemanaged/ConfigMapGenericKubernetesDependent.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentresourcemanaged/ConfigMapGenericKubernetesDependent.java new file mode 100644 index 0000000000..d5ab470cfb --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentresourcemanaged/ConfigMapGenericKubernetesDependent.java @@ -0,0 +1,46 @@ +package io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesdependentresourcemanaged; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import io.fabric8.kubernetes.api.model.GenericKubernetesResource; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.GarbageCollected; +import io.javaoperatorsdk.operator.processing.GroupVersionKind; +import io.javaoperatorsdk.operator.processing.dependent.Creator; +import io.javaoperatorsdk.operator.processing.dependent.Updater; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.GenericKubernetesDependentResource; + +public class ConfigMapGenericKubernetesDependent extends + GenericKubernetesDependentResource + implements + Creator, + Updater, + GarbageCollected { + + public static final String VERSION = "v1"; + public static final String KIND = "ConfigMap"; + public static final String KEY = "key"; + + public ConfigMapGenericKubernetesDependent() { + super(new GroupVersionKind("", VERSION, KIND)); + } + + @Override + protected GenericKubernetesResource desired( + GenericKubernetesDependentManagedCustomResource primary, + Context context) { + + try (InputStream is = this.getClass().getResourceAsStream("/configmap.yaml")) { + var res = context.getClient().genericKubernetesResources(VERSION, KIND).load(is).item(); + res.getMetadata().setName(primary.getMetadata().getName()); + res.getMetadata().setNamespace(primary.getMetadata().getNamespace()); + Map data = (Map) res.getAdditionalProperties().get("data"); + data.put(KEY, primary.getSpec().getValue()); + return res; + } catch (IOException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentresourcemanaged/GenericKubernetesDependentManagedCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentresourcemanaged/GenericKubernetesDependentManagedCustomResource.java new file mode 100644 index 0000000000..d7c44ddab3 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentresourcemanaged/GenericKubernetesDependentManagedCustomResource.java @@ -0,0 +1,16 @@ +package io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesdependentresourcemanaged; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.GenericKubernetesDependentSpec; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("gkdm") +public class GenericKubernetesDependentManagedCustomResource + extends CustomResource + implements Namespaced { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentresourcemanaged/GenericKubernetesDependentManagedReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentresourcemanaged/GenericKubernetesDependentManagedReconciler.java new file mode 100644 index 0000000000..64651ec23e --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentresourcemanaged/GenericKubernetesDependentManagedReconciler.java @@ -0,0 +1,19 @@ +package io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesdependentresourcemanaged; + +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; + +@ControllerConfiguration( + dependents = {@Dependent(type = ConfigMapGenericKubernetesDependent.class)}) +public class GenericKubernetesDependentManagedReconciler + implements Reconciler { + + @Override + public UpdateControl reconcile( + GenericKubernetesDependentManagedCustomResource resource, + Context context) { + + return UpdateControl.noUpdate(); + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentstandalone/ConfigMapGenericKubernetesDependent.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentstandalone/ConfigMapGenericKubernetesDependent.java new file mode 100644 index 0000000000..4efc968ef0 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentstandalone/ConfigMapGenericKubernetesDependent.java @@ -0,0 +1,46 @@ +package io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesdependentstandalone; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import io.fabric8.kubernetes.api.model.GenericKubernetesResource; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.GarbageCollected; +import io.javaoperatorsdk.operator.processing.GroupVersionKind; +import io.javaoperatorsdk.operator.processing.dependent.Creator; +import io.javaoperatorsdk.operator.processing.dependent.Updater; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.GenericKubernetesDependentResource; + +public class ConfigMapGenericKubernetesDependent extends + GenericKubernetesDependentResource + implements + Creator, + Updater, + GarbageCollected { + + public static final String VERSION = "v1"; + public static final String KIND = "ConfigMap"; + public static final String KEY = "key"; + + public ConfigMapGenericKubernetesDependent() { + super(new GroupVersionKind("", VERSION, KIND)); + } + + @Override + protected GenericKubernetesResource desired( + GenericKubernetesDependentStandaloneCustomResource primary, + Context context) { + + try (InputStream is = this.getClass().getResourceAsStream("/configmap.yaml")) { + var res = context.getClient().genericKubernetesResources(VERSION, KIND).load(is).item(); + res.getMetadata().setName(primary.getMetadata().getName()); + res.getMetadata().setNamespace(primary.getMetadata().getNamespace()); + Map data = (Map) res.getAdditionalProperties().get("data"); + data.put(KEY, primary.getSpec().getValue()); + return res; + } catch (IOException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentstandalone/GenericKubernetesDependentStandaloneCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentstandalone/GenericKubernetesDependentStandaloneCustomResource.java new file mode 100644 index 0000000000..38eaf804e4 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentstandalone/GenericKubernetesDependentStandaloneCustomResource.java @@ -0,0 +1,16 @@ +package io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesdependentstandalone; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.GenericKubernetesDependentSpec; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("gkd") +public class GenericKubernetesDependentStandaloneCustomResource + extends CustomResource + implements Namespaced { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentstandalone/GenericKubernetesDependentStandaloneReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentstandalone/GenericKubernetesDependentStandaloneReconciler.java new file mode 100644 index 0000000000..1969ad8f2a --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesdependentstandalone/GenericKubernetesDependentStandaloneReconciler.java @@ -0,0 +1,33 @@ +package io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesdependentstandalone; + +import java.util.Map; + +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; + +@ControllerConfiguration +public class GenericKubernetesDependentStandaloneReconciler + implements Reconciler, + EventSourceInitializer { + + private final ConfigMapGenericKubernetesDependent dependent = + new ConfigMapGenericKubernetesDependent(); + + public GenericKubernetesDependentStandaloneReconciler() {} + + @Override + public UpdateControl reconcile( + GenericKubernetesDependentStandaloneCustomResource resource, + Context context) { + + dependent.reconcile(resource, context); + + return UpdateControl.noUpdate(); + } + + @Override + public Map prepareEventSources( + EventSourceContext context) { + return EventSourceInitializer.nameEventSources(dependent.eventSource(context).orElseThrow()); + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesresourcehandling/GenericKubernetesResourceHandlingCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesresourcehandling/GenericKubernetesResourceHandlingCustomResource.java new file mode 100644 index 0000000000..47b3a14a5a --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesresourcehandling/GenericKubernetesResourceHandlingCustomResource.java @@ -0,0 +1,16 @@ +package io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesresourcehandling; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; +import io.javaoperatorsdk.operator.sample.generickubernetesresource.GenericKubernetesDependentSpec; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("gkrr") +public class GenericKubernetesResourceHandlingCustomResource + extends CustomResource + implements Namespaced { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesresourcehandling/GenericKubernetesResourceHandlingReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesresourcehandling/GenericKubernetesResourceHandlingReconciler.java new file mode 100644 index 0000000000..45be0281f6 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource/generickubernetesresourcehandling/GenericKubernetesResourceHandlingReconciler.java @@ -0,0 +1,77 @@ +package io.javaoperatorsdk.operator.sample.generickubernetesresource.generickubernetesresourcehandling; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import io.fabric8.kubernetes.api.model.GenericKubernetesResource; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.processing.GroupVersionKind; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; +import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; + +@ControllerConfiguration +public class GenericKubernetesResourceHandlingReconciler + implements Reconciler, + EventSourceInitializer { + + + public static final String VERSION = "v1"; + public static final String KIND = "ConfigMap"; + public static final String KEY = "key"; + + @Override + public UpdateControl reconcile( + GenericKubernetesResourceHandlingCustomResource primary, + Context context) { + + var secondary = context.getSecondaryResource(GenericKubernetesResource.class); + + secondary.ifPresentOrElse(r -> { + var desired = desiredConfigMap(primary, context); + if (!matches(r, desired)) { + context.getClient().genericKubernetesResources(VERSION, KIND).resource(desired).update(); + } + }, () -> context.getClient().genericKubernetesResources(VERSION, KIND) + .resource(desiredConfigMap(primary, context)).create()); + + return UpdateControl.noUpdate(); + } + + @SuppressWarnings("unchecked") + private boolean matches(GenericKubernetesResource actual, GenericKubernetesResource desired) { + var actualData = (HashMap) actual.getAdditionalProperties().get("data"); + var desiredData = (HashMap) desired.getAdditionalProperties().get("data"); + return actualData.equals(desiredData); + } + + GenericKubernetesResource desiredConfigMap( + GenericKubernetesResourceHandlingCustomResource primary, + Context context) { + try (InputStream is = this.getClass().getResourceAsStream("/configmap.yaml")) { + var res = context.getClient().genericKubernetesResources(VERSION, KIND).load(is).item(); + res.getMetadata().setName(primary.getMetadata().getName()); + res.getMetadata().setNamespace(primary.getMetadata().getNamespace()); + Map data = (Map) res.getAdditionalProperties().get("data"); + data.put(KEY, primary.getSpec().getValue()); + res.addOwnerReference(primary); + return res; + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + + @Override + public Map prepareEventSources( + EventSourceContext context) { + + var informerEventSource = new InformerEventSource<>(InformerConfiguration.from( + new GroupVersionKind("", VERSION, KIND), context).build(), + context); + + return EventSourceInitializer.nameEventSources(informerEventSource); + } +} diff --git a/operator-framework/src/test/resources/configmap.yaml b/operator-framework/src/test/resources/configmap.yaml new file mode 100644 index 0000000000..3245e257ab --- /dev/null +++ b/operator-framework/src/test/resources/configmap.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "" +data: + key: "" \ No newline at end of file From 28c3eb1db8ad8e7fd14bad4c2690a950da9eec1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 14 Dec 2023 14:46:57 +0100 Subject: [PATCH 112/644] feat: generate integration test in bootstrapper (#2146) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../boostrapper/Bootstrapper.java | 4 ++ .../templates/ConfigMapDependentResource.java | 4 +- .../templates/ReconcilerIntegrationTest.java | 60 +++++++++++++++++++ .../src/main/resources/templates/pom.xml | 6 ++ .../bootstrapper/BootstrapperTest.java | 2 +- 5 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 bootstrapper-maven-plugin/src/main/resources/templates/ReconcilerIntegrationTest.java diff --git a/bootstrapper-maven-plugin/src/main/java/io/javaoperatorsdk/boostrapper/Bootstrapper.java b/bootstrapper-maven-plugin/src/main/java/io/javaoperatorsdk/boostrapper/Bootstrapper.java index 56f6f00f5a..b0dba64c17 100644 --- a/bootstrapper-maven-plugin/src/main/java/io/javaoperatorsdk/boostrapper/Bootstrapper.java +++ b/bootstrapper-maven-plugin/src/main/java/io/javaoperatorsdk/boostrapper/Bootstrapper.java @@ -57,6 +57,7 @@ private void addJavaFiles(File projectDir, String groupId, String artifactId) { try { var packages = groupId.replace(".", File.separator); var targetDir = new File(projectDir, "src/main/java/" + packages); + var targetTestDir = new File(projectDir, "src/test/java/" + packages); FileUtils.forceMkdir(targetDir); var classFileNamePrefix = artifactClassId(artifactId); JAVA_FILES.forEach(f -> addTemplatedFile(projectDir, f, groupId, artifactId, targetDir, @@ -65,6 +66,9 @@ private void addJavaFiles(File projectDir, String groupId, String artifactId) { addTemplatedFile(projectDir, "Runner.java", groupId, artifactId, targetDir, null); addTemplatedFile(projectDir, "ConfigMapDependentResource.java", groupId, artifactId, targetDir, null); + addTemplatedFile(projectDir, "ReconcilerIntegrationTest.java", groupId, + artifactId, + targetTestDir, artifactClassId(artifactId) + "ReconcilerIntegrationTest.java"); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/ConfigMapDependentResource.java b/bootstrapper-maven-plugin/src/main/resources/templates/ConfigMapDependentResource.java index ed28771081..a8d43c60db 100644 --- a/bootstrapper-maven-plugin/src/main/resources/templates/ConfigMapDependentResource.java +++ b/bootstrapper-maven-plugin/src/main/resources/templates/ConfigMapDependentResource.java @@ -15,6 +15,8 @@ public class ConfigMapDependentResource extends CRUDKubernetesDependentResource { + public static final String KEY = "key"; + public ConfigMapDependentResource() { super(ConfigMap.class); } @@ -28,7 +30,7 @@ protected ConfigMap desired({{artifactClassId}}CustomResource primary, .withName(primary.getMetadata().getName()) .withNamespace(primary.getMetadata().getNamespace()) .build()) - .withData(Map.of("data", primary.getSpec().getValue())) + .withData(Map.of(KEY, primary.getSpec().getValue())) .build(); } } \ No newline at end of file diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/ReconcilerIntegrationTest.java b/bootstrapper-maven-plugin/src/main/resources/templates/ReconcilerIntegrationTest.java new file mode 100644 index 0000000000..865fe9c594 --- /dev/null +++ b/bootstrapper-maven-plugin/src/main/resources/templates/ReconcilerIntegrationTest.java @@ -0,0 +1,60 @@ +package {{groupId}}; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static {{groupId}}.ConfigMapDependentResource.KEY; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +class {{artifactClassId}}ReconcilerIntegrationTest { + + public static final String RESOURCE_NAME = "test1"; + public static final String INITIAL_VALUE = "initial value"; + public static final String CHANGED_VALUE = "changed value"; + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler({{artifactClassId}}Reconciler.class) + .build(); + + @Test + void testCRUDOperations() { + var cr = extension.create(testResource()); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, RESOURCE_NAME); + assertThat(cm).isNotNull(); + assertThat(cm.getData()).containsEntry(KEY, INITIAL_VALUE); + }); + + cr.getSpec().setValue(CHANGED_VALUE); + cr = extension.replace(cr); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, RESOURCE_NAME); + assertThat(cm.getData()).containsEntry(KEY, CHANGED_VALUE); + }); + + extension.delete(cr); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, RESOURCE_NAME); + assertThat(cm).isNull(); + }); + } + + {{artifactClassId}}CustomResource testResource() { + var resource = new {{artifactClassId}}CustomResource(); + resource.setMetadata(new ObjectMetaBuilder() + .withName(RESOURCE_NAME) + .build()); + resource.setSpec(new {{artifactClassId}}Spec()); + resource.getSpec().setValue(INITIAL_VALUE); + return resource; + } +} diff --git a/bootstrapper-maven-plugin/src/main/resources/templates/pom.xml b/bootstrapper-maven-plugin/src/main/resources/templates/pom.xml index 4bdacf1f03..d2ffb66b46 100644 --- a/bootstrapper-maven-plugin/src/main/resources/templates/pom.xml +++ b/bootstrapper-maven-plugin/src/main/resources/templates/pom.xml @@ -39,6 +39,12 @@ operator-framework ${josdk.version} + + io.javaoperatorsdk + operator-framework-junit-5 + ${josdk.version} + test + io.fabric8 crd-generator-apt diff --git a/bootstrapper-maven-plugin/src/test/java/io/javaoperatorsdk/bootstrapper/BootstrapperTest.java b/bootstrapper-maven-plugin/src/test/java/io/javaoperatorsdk/bootstrapper/BootstrapperTest.java index b0a97d76c0..1245799480 100644 --- a/bootstrapper-maven-plugin/src/test/java/io/javaoperatorsdk/bootstrapper/BootstrapperTest.java +++ b/bootstrapper-maven-plugin/src/test/java/io/javaoperatorsdk/bootstrapper/BootstrapperTest.java @@ -31,7 +31,7 @@ void copiesFilesToTarget() { private void assertProjectCompiles() { try { var process = Runtime.getRuntime() - .exec("mvn clean install -f target/test-project/pom.xml"); + .exec("mvn clean install -f target/test-project/pom.xml -DskipTests"); BufferedReader stdOut = new BufferedReader(new InputStreamReader(process.getInputStream())); From d078a2069ef52939d392b11043c05872b36fe27d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 18 Dec 2023 14:22:16 +0100 Subject: [PATCH 113/644] improve: name for dependent explicitly (#2165) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../dependent/workflow/DependentResourceNode.java | 4 ++++ .../dependent/workflow/WorkflowBuilder.java | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DependentResourceNode.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DependentResourceNode.java index 39a9ba6fe5..4c82ee19f3 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DependentResourceNode.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DependentResourceNode.java @@ -19,6 +19,10 @@ public class DependentResourceNode { private Condition activationCondition; private final DependentResource dependentResource; + DependentResourceNode(String name, DependentResource dependentResource) { + this(name, null, null, null, null, dependentResource); + } + DependentResourceNode(DependentResource dependentResource) { this(getNameFor(dependentResource), null, null, null, null, dependentResource); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowBuilder.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowBuilder.java index a7729859a8..d65e21659c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowBuilder.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowBuilder.java @@ -21,10 +21,15 @@ public class WorkflowBuilder

{ private boolean isCleaner = false; public WorkflowBuilder

addDependentResource(DependentResource dependentResource) { - currentNode = new DependentResourceNode<>(dependentResource); + return addDependentResource(dependentResource, null); + } + + public WorkflowBuilder

addDependentResource(DependentResource dependentResource, String name) { + currentNode = name == null ? new DependentResourceNode<>(dependentResource) + : new DependentResourceNode<>(name, dependentResource); isCleaner = isCleaner || dependentResource.isDeletable(); - final var name = currentNode.getName(); - dependentResourceNodes.put(name, currentNode); + final var actualName = currentNode.getName(); + dependentResourceNodes.put(actualName, currentNode); return this; } From e740d6652deb097221295a5a8981aa1788c78122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 21 Dec 2023 10:38:18 +0100 Subject: [PATCH 114/644] improve: better namespace naming for junit extension and custom patterns (#2171) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- operator-framework-junit5/pom.xml | 5 ++ .../junit/AbstractOperatorExtension.java | 45 +++++++++------ .../ClusterDeployedOperatorExtension.java | 11 +++- .../junit/DefaultNamespaceNameSupplier.java | 49 ++++++++++++++++ .../DefaultPerClassNamespaceNameSupplier.java | 32 +++++++++++ .../junit/LocallyRunOperatorExtension.java | 11 +++- .../DefaultNamespaceNameSupplierTest.java | 56 +++++++++++++++++++ ...aultPerClassNamespaceNameSupplierTest.java | 44 +++++++++++++++ .../junit/NamespaceNamingTestUtils.java | 53 ++++++++++++++++++ 9 files changed, 282 insertions(+), 24 deletions(-) create mode 100644 operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/DefaultNamespaceNameSupplier.java create mode 100644 operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/DefaultPerClassNamespaceNameSupplier.java create mode 100644 operator-framework-junit5/src/test/java/io/javaoperatorsdk/operator/junit/DefaultNamespaceNameSupplierTest.java create mode 100644 operator-framework-junit5/src/test/java/io/javaoperatorsdk/operator/junit/DefaultPerClassNamespaceNameSupplierTest.java create mode 100644 operator-framework-junit5/src/test/java/io/javaoperatorsdk/operator/junit/NamespaceNamingTestUtils.java diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 9366485f25..4bbd35e145 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -39,6 +39,11 @@ org.awaitility awaitility + + org.mockito + mockito-core + test + \ No newline at end of file diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/AbstractOperatorExtension.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/AbstractOperatorExtension.java index 9a86bdfbbf..1ce14b73ed 100644 --- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/AbstractOperatorExtension.java +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/AbstractOperatorExtension.java @@ -4,10 +4,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Locale; -import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import java.util.function.Function; import org.awaitility.Awaitility; import org.junit.jupiter.api.extension.AfterAllCallback; @@ -23,7 +22,6 @@ import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; import io.fabric8.kubernetes.client.utils.Utils; import io.javaoperatorsdk.operator.api.config.ConfigurationServiceOverrider; @@ -34,6 +32,7 @@ public abstract class AbstractOperatorExtension implements HasKubernetesClient, AfterEachCallback { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractOperatorExtension.class); + public static final int MAX_NAMESPACE_NAME_LENGTH = 63; public static final int CRD_READY_WAIT = 2000; public static final int DEFAULT_NAMESPACE_DELETE_TIMEOUT = 90; @@ -44,6 +43,8 @@ public abstract class AbstractOperatorExtension implements HasKubernetesClient, protected final boolean preserveNamespaceOnError; protected final boolean waitForNamespaceDeletion; protected final int namespaceDeleteTimeout = DEFAULT_NAMESPACE_DELETE_TIMEOUT; + protected final Function namespaceNameSupplier; + protected final Function perClassNamespaceNameSupplier; protected String namespace; @@ -53,7 +54,9 @@ protected AbstractOperatorExtension( boolean oneNamespacePerClass, boolean preserveNamespaceOnError, boolean waitForNamespaceDeletion, - KubernetesClient kubernetesClient) { + KubernetesClient kubernetesClient, + Function namespaceNameSupplier, + Function perClassNamespaceNameSupplier) { this.kubernetesClient = kubernetesClient != null ? kubernetesClient : new KubernetesClientBuilder().build(); this.infrastructure = infrastructure; @@ -61,6 +64,8 @@ protected AbstractOperatorExtension( this.oneNamespacePerClass = oneNamespacePerClass; this.preserveNamespaceOnError = preserveNamespaceOnError; this.waitForNamespaceDeletion = waitForNamespaceDeletion; + this.namespaceNameSupplier = namespaceNameSupplier; + this.perClassNamespaceNameSupplier = perClassNamespaceNameSupplier; } @@ -132,26 +137,14 @@ public boolean delete(Class type, T resource) { protected void beforeAllImpl(ExtensionContext context) { if (oneNamespacePerClass) { - namespace = context.getRequiredTestClass().getSimpleName(); - namespace += "-"; - namespace += UUID.randomUUID(); - namespace = KubernetesResourceUtil.sanitizeName(namespace).toLowerCase(Locale.US); - namespace = namespace.substring(0, Math.min(namespace.length(), 63)); - + namespace = perClassNamespaceNameSupplier.apply(context); before(context); } } protected void beforeEachImpl(ExtensionContext context) { if (!oneNamespacePerClass) { - namespace = context.getRequiredTestClass().getSimpleName(); - namespace += "-"; - namespace += context.getRequiredTestMethod().getName(); - namespace += "-"; - namespace += UUID.randomUUID(); - namespace = KubernetesResourceUtil.sanitizeName(namespace).toLowerCase(Locale.US); - namespace = namespace.substring(0, Math.min(namespace.length(), 63)); - + namespace = namespaceNameSupplier.apply(context); before(context); } } @@ -219,6 +212,10 @@ public static abstract class AbstractBuilder> { protected boolean oneNamespacePerClass; protected int namespaceDeleteTimeout; protected Consumer configurationServiceOverrider; + protected Function namespaceNameSupplier = + new DefaultNamespaceNameSupplier(); + protected Function perClassNamespaceNameSupplier = + new DefaultPerClassNamespaceNameSupplier(); protected AbstractBuilder() { this.infrastructure = new ArrayList<>(); @@ -280,5 +277,17 @@ public T withNamespaceDeleteTimeout(int timeout) { this.namespaceDeleteTimeout = timeout; return (T) this; } + + public AbstractBuilder withNamespaceNameSupplier( + Function namespaceNameSupplier) { + this.namespaceNameSupplier = namespaceNameSupplier; + return this; + } + + public AbstractBuilder withPerClassNamespaceNameSupplier( + Function perClassNamespaceNameSupplier) { + this.perClassNamespaceNameSupplier = perClassNamespaceNameSupplier; + return this; + } } } diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/ClusterDeployedOperatorExtension.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/ClusterDeployedOperatorExtension.java index ec1bff4064..b2ec773fcc 100644 --- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/ClusterDeployedOperatorExtension.java +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/ClusterDeployedOperatorExtension.java @@ -11,6 +11,7 @@ import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import java.util.function.Function; import org.junit.jupiter.api.extension.ExtensionContext; import org.slf4j.Logger; @@ -37,11 +38,13 @@ private ClusterDeployedOperatorExtension( boolean preserveNamespaceOnError, boolean waitForNamespaceDeletion, boolean oneNamespacePerClass, - KubernetesClient kubernetesClient) { + KubernetesClient kubernetesClient, + Function namespaceNameSupplier, + Function perClassNamespaceNameSupplier) { super(infrastructure, infrastructureTimeout, oneNamespacePerClass, preserveNamespaceOnError, waitForNamespaceDeletion, - kubernetesClient); + kubernetesClient, namespaceNameSupplier, perClassNamespaceNameSupplier); this.operatorDeployment = operatorDeployment; this.operatorDeploymentTimeout = operatorDeploymentTimeout; } @@ -152,7 +155,9 @@ public ClusterDeployedOperatorExtension build() { preserveNamespaceOnError, waitForNamespaceDeletion, oneNamespacePerClass, - kubernetesClient != null ? kubernetesClient : new KubernetesClientBuilder().build()); + kubernetesClient != null ? kubernetesClient : new KubernetesClientBuilder().build(), + namespaceNameSupplier, + perClassNamespaceNameSupplier); } } } diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/DefaultNamespaceNameSupplier.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/DefaultNamespaceNameSupplier.java new file mode 100644 index 0000000000..3041ed0f31 --- /dev/null +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/DefaultNamespaceNameSupplier.java @@ -0,0 +1,49 @@ +package io.javaoperatorsdk.operator.junit; + +import java.util.Locale; +import java.util.UUID; +import java.util.function.Function; + +import org.junit.jupiter.api.extension.ExtensionContext; + +import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; + +import static io.javaoperatorsdk.operator.junit.AbstractOperatorExtension.MAX_NAMESPACE_NAME_LENGTH; + +public class DefaultNamespaceNameSupplier implements Function { + + public static final int RANDOM_SUFFIX_LENGTH = 5; + public static final int DELIMITERS_LENGTH = 2; + + public static final int MAX_NAME_LENGTH_TOGETHER = + MAX_NAMESPACE_NAME_LENGTH - DELIMITERS_LENGTH - RANDOM_SUFFIX_LENGTH; + public static final int PART_RESERVED_NAME_LENGTH = MAX_NAME_LENGTH_TOGETHER / 2; + + public static final String DELIMITER = "-"; + + @Override + public String apply(ExtensionContext context) { + String classPart = context.getRequiredTestClass().getSimpleName(); + String methodPart = context.getRequiredTestMethod().getName(); + if (classPart.length() + methodPart.length() + DELIMITERS_LENGTH + + RANDOM_SUFFIX_LENGTH > MAX_NAMESPACE_NAME_LENGTH) { + if (classPart.length() > PART_RESERVED_NAME_LENGTH) { + int classPartMaxLength = + methodPart.length() > PART_RESERVED_NAME_LENGTH ? PART_RESERVED_NAME_LENGTH + : MAX_NAME_LENGTH_TOGETHER - methodPart.length(); + classPart = classPart.substring(0, Math.min(classPartMaxLength, classPart.length())); + } + if (methodPart.length() > PART_RESERVED_NAME_LENGTH) { + int methodPartMaxLength = + classPart.length() > PART_RESERVED_NAME_LENGTH ? PART_RESERVED_NAME_LENGTH + : MAX_NAME_LENGTH_TOGETHER - classPart.length(); + methodPart = methodPart.substring(0, Math.min(methodPartMaxLength, methodPart.length())); + } + } + + String namespace = classPart + DELIMITER + methodPart + DELIMITER + UUID.randomUUID().toString() + .substring(0, RANDOM_SUFFIX_LENGTH); + namespace = KubernetesResourceUtil.sanitizeName(namespace).toLowerCase(Locale.US); + return namespace; + } +} diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/DefaultPerClassNamespaceNameSupplier.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/DefaultPerClassNamespaceNameSupplier.java new file mode 100644 index 0000000000..b184a3fc3d --- /dev/null +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/DefaultPerClassNamespaceNameSupplier.java @@ -0,0 +1,32 @@ +package io.javaoperatorsdk.operator.junit; + +import java.util.Locale; +import java.util.UUID; +import java.util.function.Function; + +import org.junit.jupiter.api.extension.ExtensionContext; + +import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; + +import static io.javaoperatorsdk.operator.junit.AbstractOperatorExtension.MAX_NAMESPACE_NAME_LENGTH; +import static io.javaoperatorsdk.operator.junit.DefaultNamespaceNameSupplier.DELIMITER; +import static io.javaoperatorsdk.operator.junit.DefaultNamespaceNameSupplier.RANDOM_SUFFIX_LENGTH; + +public class DefaultPerClassNamespaceNameSupplier implements Function { + + public static final int MAX_CLASS_NAME_LENGTH = + MAX_NAMESPACE_NAME_LENGTH - RANDOM_SUFFIX_LENGTH - 1; + + @Override + public String apply(ExtensionContext context) { + String className = context.getRequiredTestClass().getSimpleName(); + String namespace = + className.length() > MAX_CLASS_NAME_LENGTH ? className.substring(0, MAX_CLASS_NAME_LENGTH) + : className; + namespace += DELIMITER; + namespace += UUID.randomUUID().toString().substring(0, RANDOM_SUFFIX_LENGTH); + namespace = KubernetesResourceUtil.sanitizeName(namespace).toLowerCase(Locale.US); + namespace = namespace.substring(0, Math.min(namespace.length(), MAX_NAMESPACE_NAME_LENGTH)); + return namespace; + } +} diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java index 7f7cb64b28..61916f14bc 100644 --- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -53,14 +54,18 @@ private LocallyRunOperatorExtension( boolean waitForNamespaceDeletion, boolean oneNamespacePerClass, KubernetesClient kubernetesClient, - Consumer configurationServiceOverrider) { + Consumer configurationServiceOverrider, + Function namespaceNameSupplier, + Function perClassNamespaceNameSupplier) { super( infrastructure, infrastructureTimeout, oneNamespacePerClass, preserveNamespaceOnError, waitForNamespaceDeletion, - kubernetesClient); + kubernetesClient, + namespaceNameSupplier, + perClassNamespaceNameSupplier); this.reconcilers = reconcilers; this.portForwards = portForwards; this.localPortForwards = new ArrayList<>(portForwards.size()); @@ -285,7 +290,7 @@ public LocallyRunOperatorExtension build() { waitForNamespaceDeletion, oneNamespacePerClass, kubernetesClient, - configurationServiceOverrider); + configurationServiceOverrider, namespaceNameSupplier, perClassNamespaceNameSupplier); } } diff --git a/operator-framework-junit5/src/test/java/io/javaoperatorsdk/operator/junit/DefaultNamespaceNameSupplierTest.java b/operator-framework-junit5/src/test/java/io/javaoperatorsdk/operator/junit/DefaultNamespaceNameSupplierTest.java new file mode 100644 index 0000000000..cd1dce1a51 --- /dev/null +++ b/operator-framework-junit5/src/test/java/io/javaoperatorsdk/operator/junit/DefaultNamespaceNameSupplierTest.java @@ -0,0 +1,56 @@ +package io.javaoperatorsdk.operator.junit; + +import org.junit.jupiter.api.Test; + +import static io.javaoperatorsdk.operator.junit.AbstractOperatorExtension.MAX_NAMESPACE_NAME_LENGTH; +import static io.javaoperatorsdk.operator.junit.DefaultNamespaceNameSupplier.*; +import static io.javaoperatorsdk.operator.junit.NamespaceNamingTestUtils.*; +import static org.assertj.core.api.Assertions.assertThat; + +class DefaultNamespaceNameSupplierTest { + + + DefaultNamespaceNameSupplier supplier = new DefaultNamespaceNameSupplier(); + + @Test + void trivialCase() { + String ns = supplier.apply(mockExtensionContext(SHORT_CLASS_NAME, SHORT_METHOD_NAME)); + + assertThat(ns).startsWith(SHORT_CLASS_NAME + DELIMITER + SHORT_METHOD_NAME + DELIMITER); + shortEnoughAndEndsWithRandomString(ns); + } + + @Test + void classPartLongerCase() { + String ns = supplier.apply(mockExtensionContext(LONG_CLASS_NAME, SHORT_METHOD_NAME)); + + assertThat(ns).startsWith(LONG_CLASS_NAME + DELIMITER + SHORT_METHOD_NAME + DELIMITER); + shortEnoughAndEndsWithRandomString(ns); + } + + @Test + void methodPartLonger() { + String ns = supplier.apply(mockExtensionContext(SHORT_CLASS_NAME, LONG_METHOD_NAME)); + + assertThat(ns).startsWith(SHORT_CLASS_NAME + DELIMITER + LONG_METHOD_NAME + DELIMITER); + shortEnoughAndEndsWithRandomString(ns); + } + + @Test + void methodPartAndClassPartLonger() { + String ns = supplier.apply(mockExtensionContext(LONG_CLASS_NAME, LONG_METHOD_NAME)); + + assertThat(ns).startsWith(LONG_CLASS_NAME.substring(0, PART_RESERVED_NAME_LENGTH) + DELIMITER + + LONG_METHOD_NAME.substring(0, PART_RESERVED_NAME_LENGTH) + + DELIMITER); + shortEnoughAndEndsWithRandomString(ns); + } + + + private static void shortEnoughAndEndsWithRandomString(String ns) { + assertThat(ns.length()).isLessThanOrEqualTo(MAX_NAMESPACE_NAME_LENGTH); + assertThat(ns.split("-")[2]).hasSize(RANDOM_SUFFIX_LENGTH); + } + + +} diff --git a/operator-framework-junit5/src/test/java/io/javaoperatorsdk/operator/junit/DefaultPerClassNamespaceNameSupplierTest.java b/operator-framework-junit5/src/test/java/io/javaoperatorsdk/operator/junit/DefaultPerClassNamespaceNameSupplierTest.java new file mode 100644 index 0000000000..40e240cbd1 --- /dev/null +++ b/operator-framework-junit5/src/test/java/io/javaoperatorsdk/operator/junit/DefaultPerClassNamespaceNameSupplierTest.java @@ -0,0 +1,44 @@ +package io.javaoperatorsdk.operator.junit; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; + +import static io.javaoperatorsdk.operator.junit.AbstractOperatorExtension.MAX_NAMESPACE_NAME_LENGTH; +import static io.javaoperatorsdk.operator.junit.DefaultNamespaceNameSupplier.DELIMITER; +import static io.javaoperatorsdk.operator.junit.DefaultNamespaceNameSupplier.RANDOM_SUFFIX_LENGTH; +import static io.javaoperatorsdk.operator.junit.DefaultPerClassNamespaceNameSupplier.MAX_CLASS_NAME_LENGTH; +import static io.javaoperatorsdk.operator.junit.NamespaceNamingTestUtils.SHORT_CLASS_NAME; +import static io.javaoperatorsdk.operator.junit.NamespaceNamingTestUtils.VERY_LONG_CLASS_NAME; +import static org.assertj.core.api.Assertions.assertThat; + +class DefaultPerClassNamespaceNameSupplierTest { + + DefaultPerClassNamespaceNameSupplier supplier = new DefaultPerClassNamespaceNameSupplier(); + + @Test + void shortClassCase() { + var ns = supplier.apply(mockExtensionContext(SHORT_CLASS_NAME)); + + assertThat(ns).startsWith(SHORT_CLASS_NAME + DELIMITER); + shortEnoughAndEndsWithRandomString(ns); + } + + @Test + void longClassCase() { + var ns = supplier.apply(mockExtensionContext(VERY_LONG_CLASS_NAME)); + + assertThat(ns).startsWith(VERY_LONG_CLASS_NAME.substring(0, MAX_CLASS_NAME_LENGTH) + DELIMITER); + shortEnoughAndEndsWithRandomString(ns); + assertThat(ns).hasSize(MAX_NAMESPACE_NAME_LENGTH); + } + + public static ExtensionContext mockExtensionContext(String className) { + return NamespaceNamingTestUtils.mockExtensionContext(className, null); + } + + private static void shortEnoughAndEndsWithRandomString(String ns) { + assertThat(ns.length()).isLessThanOrEqualTo(MAX_NAMESPACE_NAME_LENGTH); + assertThat(ns.split("-")[1]).hasSize(RANDOM_SUFFIX_LENGTH); + } + +} diff --git a/operator-framework-junit5/src/test/java/io/javaoperatorsdk/operator/junit/NamespaceNamingTestUtils.java b/operator-framework-junit5/src/test/java/io/javaoperatorsdk/operator/junit/NamespaceNamingTestUtils.java new file mode 100644 index 0000000000..0443d0e983 --- /dev/null +++ b/operator-framework-junit5/src/test/java/io/javaoperatorsdk/operator/junit/NamespaceNamingTestUtils.java @@ -0,0 +1,53 @@ +package io.javaoperatorsdk.operator.junit; + +import java.lang.reflect.Method; + +import org.junit.jupiter.api.extension.ExtensionContext; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class NamespaceNamingTestUtils { + + public static final String SHORT_CLASS_NAME = Method.class.getSimpleName().toLowerCase(); + public static final String SHORT_METHOD_NAME = "short"; + public static final String LONG_METHOD_NAME = "longmethodnametotestifistruncatedcorrectly"; + public static final String LONG_CLASS_NAME = VeryLongClassNameForSakeOfThisTestIfItWorks.class + .getSimpleName().toLowerCase(); + // longer then 63 + public static final String VERY_LONG_CLASS_NAME = + VeryVeryVeryVeryVeryVeryLongClassNameForSakeOfThisTestIfItWorks.class + .getSimpleName().toLowerCase(); + + public static ExtensionContext mockExtensionContext(String className, String methodName) { + ExtensionContext extensionContext = mock(ExtensionContext.class); + Method method = mock(Method.class); + + Class clazz; + if (className.equals(SHORT_CLASS_NAME)) { + clazz = Method.class; + } else if (className.equals(LONG_CLASS_NAME)) { + clazz = VeryLongClassNameForSakeOfThisTestIfItWorks.class; + } else if (className.equals(VERY_LONG_CLASS_NAME)) { + clazz = VeryVeryVeryVeryVeryVeryLongClassNameForSakeOfThisTestIfItWorks.class; + } else { + throw new IllegalArgumentException(); + } + + when(method.getName()).thenReturn(methodName); + when(extensionContext.getRequiredTestMethod()).thenReturn(method); + when(extensionContext.getRequiredTestClass()).thenReturn(clazz); + + return extensionContext; + } + + + public static class VeryVeryVeryVeryVeryVeryLongClassNameForSakeOfThisTestIfItWorks { + + } + + public static class VeryLongClassNameForSakeOfThisTestIfItWorks { + + } + +} From ab89e692cd509f8a062a2a3e5d3f211d6820d90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 8 Jan 2024 16:31:32 +0100 Subject: [PATCH 115/644] feat: extending event source context with workflow support (#2185) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit also change webpage sample use workflow builder Signed-off-by: Attila Mészáros --- .../reconciler/EventSourceInitializer.java | 28 +++++++-- .../operator/sample/WebPageOperator.java | 2 +- .../operator/sample/WebPageReconciler.java | 2 +- ...WebPageStandaloneDependentsReconciler.java | 60 ++++++++----------- ...eratorStandaloneDependentResourcesE2E.java | 2 +- 5 files changed, 50 insertions(+), 44 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java index 2c94840d38..09c1687e1e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java @@ -1,12 +1,10 @@ package io.javaoperatorsdk.operator.api.reconciler; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; +import java.util.*; import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.processing.dependent.workflow.Workflow; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.ResourceEventSource; @@ -43,12 +41,30 @@ static Map nameEventSources(EventSource... eventSources) { return eventSourceMap; } - @SuppressWarnings("unchecked,rawtypes") + @SuppressWarnings("unchecked") + static Map eventSourcesFromWorkflow( + EventSourceContext context, + Workflow workflow) { + Map result = new HashMap<>(); + for (var e : workflow.getDependentResourcesByNameWithoutActivationCondition().entrySet()) { + var eventSource = e.getValue().eventSource(context); + eventSource.ifPresent(es -> result.put(e.getKey(), (EventSource) es)); + } + return result; + } + + @SuppressWarnings("rawtypes") static Map nameEventSourcesFromDependentResource( EventSourceContext context, DependentResource... dependentResources) { + return nameEventSourcesFromDependentResource(context, Arrays.asList(dependentResources)); + } + + @SuppressWarnings("unchecked,rawtypes") + static Map nameEventSourcesFromDependentResource( + EventSourceContext context, Collection dependentResources) { if (dependentResources != null) { - Map eventSourceMap = new HashMap<>(dependentResources.length); + Map eventSourceMap = new HashMap<>(dependentResources.size()); for (DependentResource dependentResource : dependentResources) { Optional es = dependentResource.eventSource(context); es.ifPresent(e -> eventSourceMap.put(generateNameFor(e), e)); diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageOperator.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageOperator.java index 28a0b4e84f..e3ab63dc54 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageOperator.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageOperator.java @@ -37,7 +37,7 @@ public static void main(String[] args) throws IOException { .equals(reconcilerEnvVar)) { operator.register(new WebPageManagedDependentsReconciler()); } else { - operator.register(new WebPageStandaloneDependentsReconciler(client)); + operator.register(new WebPageStandaloneDependentsReconciler()); } operator.start(); diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java index af938a7833..4be2da11c7 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java @@ -107,7 +107,7 @@ public UpdateControl reconcile(WebPage webPage, Context contex "Creating or updating ConfigMap {} in {}", desiredHtmlConfigMap.getMetadata().getName(), ns); - var res = kubernetesClient.configMaps().inNamespace(ns).resource(desiredHtmlConfigMap) + kubernetesClient.configMaps().inNamespace(ns).resource(desiredHtmlConfigMap) .createOr(Replaceable::update); } diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java index 34a208f72e..1799d72cea 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java @@ -7,19 +7,13 @@ import org.slf4j.LoggerFactory; import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.api.model.Service; -import io.fabric8.kubernetes.api.model.apps.Deployment; -import io.fabric8.kubernetes.api.model.networking.v1.Ingress; -import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfigBuilder; +import io.javaoperatorsdk.operator.processing.dependent.workflow.Workflow; +import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowBuilder; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.sample.customresource.WebPage; -import io.javaoperatorsdk.operator.sample.dependentresource.ConfigMapDependentResource; -import io.javaoperatorsdk.operator.sample.dependentresource.DeploymentDependentResource; -import io.javaoperatorsdk.operator.sample.dependentresource.IngressDependentResource; -import io.javaoperatorsdk.operator.sample.dependentresource.ServiceDependentResource; +import io.javaoperatorsdk.operator.sample.dependentresource.*; import static io.javaoperatorsdk.operator.sample.Utils.*; import static io.javaoperatorsdk.operator.sample.WebPageManagedDependentsReconciler.SELECTOR; @@ -34,19 +28,15 @@ public class WebPageStandaloneDependentsReconciler private static final Logger log = LoggerFactory.getLogger(WebPageStandaloneDependentsReconciler.class); - private KubernetesDependentResource configMapDR; - private KubernetesDependentResource deploymentDR; - private KubernetesDependentResource serviceDR; - private KubernetesDependentResource ingressDR; + private Workflow workflow; - public WebPageStandaloneDependentsReconciler(KubernetesClient kubernetesClient) { - createDependentResources(kubernetesClient); + public WebPageStandaloneDependentsReconciler() { + workflow = createDependentResourcesAndWorkflow(); } @Override public Map prepareEventSources(EventSourceContext context) { - return EventSourceInitializer.nameEventSourcesFromDependentResource(context, configMapDR, - deploymentDR, serviceDR, ingressDR); + return EventSourceInitializer.eventSourcesFromWorkflow(context, workflow); } @Override @@ -58,14 +48,7 @@ public UpdateControl reconcile(WebPage webPage, Context contex return UpdateControl.patchStatus(setInvalidHtmlErrorMessage(webPage)); } - Arrays.asList(configMapDR, deploymentDR, serviceDR) - .forEach(dr -> dr.reconcile(webPage, context)); - - if (Boolean.TRUE.equals(webPage.getSpec().getExposed())) { - ingressDR.reconcile(webPage, context); - } else { - ingressDR.delete(webPage, context); - } + workflow.reconcile(webPage, context); webPage.setStatus( createStatus( @@ -80,16 +63,23 @@ public ErrorStatusUpdateControl updateErrorStatus( } @SuppressWarnings({"unchecked", "rawtypes"}) - private void createDependentResources(KubernetesClient client) { - this.configMapDR = new ConfigMapDependentResource(); - this.deploymentDR = new DeploymentDependentResource(); - this.serviceDR = new ServiceDependentResource(); - this.ingressDR = new IngressDependentResource(); - - Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR).forEach(dr -> { - dr.configureWith(new KubernetesDependentResourceConfigBuilder() - .withLabelSelector(SELECTOR + "=true").build()); - }); + private Workflow createDependentResourcesAndWorkflow() { + var configMapDR = new ConfigMapDependentResource(); + var deploymentDR = new DeploymentDependentResource(); + var serviceDR = new ServiceDependentResource(); + var ingressDR = new IngressDependentResource(); + + Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR) + .forEach(dr -> dr.configureWith(new KubernetesDependentResourceConfigBuilder() + .withLabelSelector(SELECTOR + "=true").build())); + + return new WorkflowBuilder() + .addDependentResource(configMapDR) + .addDependentResource(deploymentDR) + .addDependentResource(serviceDR) + .addDependentResource(ingressDR) + .withReconcilePrecondition(new ExposedIngressCondition()) + .build(); } diff --git a/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorStandaloneDependentResourcesE2E.java b/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorStandaloneDependentResourcesE2E.java index e1e9e65f96..7786473257 100644 --- a/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorStandaloneDependentResourcesE2E.java +++ b/sample-operators/webpage/src/test/java/io/javaoperatorsdk/operator/sample/WebPageOperatorStandaloneDependentResourcesE2E.java @@ -18,7 +18,7 @@ public WebPageOperatorStandaloneDependentResourcesE2E() throws FileNotFoundExcep isLocal() ? LocallyRunOperatorExtension.builder() .waitForNamespaceDeletion(false) - .withReconciler(new WebPageStandaloneDependentsReconciler(client)) + .withReconciler(new WebPageStandaloneDependentsReconciler()) .build() : ClusterDeployedOperatorExtension.builder() .waitForNamespaceDeletion(false) From 39818f8494c73cc49780ac8bc7870769de15465a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 9 Jan 2024 16:23:35 +0100 Subject: [PATCH 116/644] feat: add default delete condition to managed dependent resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- docs/documentation/workflows.md | 22 ++++++ .../workflow/DefaultManagedWorkflow.java | 2 +- .../KubernetesResourceDeletedCondition.java | 27 +++++++ .../ManagedDependentDeleteConditionIT.java | 71 +++++++++++++++++++ .../ConfigMapDependent.java | 29 ++++++++ ...tDefaultDeleteConditionCustomResource.java | 15 ++++ ...ndentDefaultDeleteConditionReconciler.java | 31 ++++++++ .../SecretDependent.java | 33 +++++++++ 8 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/KubernetesResourceDeletedCondition.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/ManagedDependentDeleteConditionIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ConfigMapDependent.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ManagedDependentDefaultDeleteConditionCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ManagedDependentDefaultDeleteConditionReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/SecretDependent.java diff --git a/docs/documentation/workflows.md b/docs/documentation/workflows.md index fed30afb25..27cd2f4274 100644 --- a/docs/documentation/workflows.md +++ b/docs/documentation/workflows.md @@ -312,6 +312,28 @@ containing all the related exceptions. The exceptions can be handled by [`ErrorStatusHandler`](https://github.com/java-operator-sdk/java-operator-sdk/blob/14620657fcacc8254bb96b4293eded84c20ba685/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusHandler.java) +## Waiting for the actual deletion of Kubernetes Dependent Resources + +Let's consider a case when a Kubernetes Dependent Resources (KDR) depends on another resource, on cleanup +the resources will be deleted in reverse order, thus the KDR will be deleted first. +However, the workflow implementation currently simply asks the Kubernetes API server to delete the resource. This is, +however, an asynchronous process, meaning that the deletion might not occur immediately, in particular if the resource +uses finalizers that block the deletion or if the deletion itself takes some time. From the SDK's perspective, though, +the deletion has been requested and it moves on to other tasks without waiting for the resource to be actually deleted +from the server (which might never occur if it uses finalizers which are not removed). +In situations like these, if your logic depends on resources being actually removed from the cluster before a +cleanup workflow can proceed correctly, you need to block the workflow progression using a delete post-condition that +checks that the resource is actually removed or that it, at least, doesn't have any finalizers any longer. JOSDK +provides such a delete post-condition implementation in the form of +[`KubernetesResourceDeletedCondition`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/KubernetesResourceDeletedCondition.java) + +Also, check usage in an [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ManagedDependentDefaultDeleteConditionReconciler.java). + +In such cases the Kubernetes Dependent Resource should extend `CRUDNoGCKubernetesDependentResource` +and NOT `CRUDKubernetesDependentResource` since otherwise the Kubernetes Garbage Collector would delete the resources. +In other words if a Kubernetes Dependent Resource depends on another dependent resource, it should not implement +`GargageCollected` interface, otherwise the deletion order won't be guaranteed. + ## Notes and Caveats - Delete is almost always called on every resource during the cleanup. However, it might be the case diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultManagedWorkflow.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultManagedWorkflow.java index 13d51b1759..27400230df 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultManagedWorkflow.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/DefaultManagedWorkflow.java @@ -85,7 +85,7 @@ public Workflow

resolve(KubernetesClient client, resolve(spec, client, configuration)); alreadyResolved.put(node.getName(), node); spec.getDependsOn() - .forEach(depend -> node.addDependsOnRelation(alreadyResolved.get((String) depend))); + .forEach(depend -> node.addDependsOnRelation(alreadyResolved.get(depend))); } final var bottom = diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/KubernetesResourceDeletedCondition.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/KubernetesResourceDeletedCondition.java new file mode 100644 index 0000000000..28342f2d17 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/KubernetesResourceDeletedCondition.java @@ -0,0 +1,27 @@ +package io.javaoperatorsdk.operator.processing.dependent.workflow; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; + +/** + * A condition implementation meant to be used as a delete post-condition on Kubernetes dependent + * resources to prevent the workflow from proceeding until the associated resource is actually + * deleted from the server (or, at least, doesn't have any finalizers anymore). This is needed in + * cases where a cleaning process depends on resources being actually removed from the server + * because, by default, workflows simply request the deletion but do NOT wait for the resources to + * be actually deleted. + */ +public class KubernetesResourceDeletedCondition implements Condition { + + @Override + public boolean isMet(DependentResource dependentResource, + HasMetadata primary, Context context) { + var optionalResource = dependentResource.getSecondaryResource(primary, context); + if (optionalResource.isEmpty()) { + return true; + } else { + return optionalResource.orElseThrow().getMetadata().getFinalizers().isEmpty(); + } + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ManagedDependentDeleteConditionIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ManagedDependentDeleteConditionIT.java new file mode 100644 index 0000000000..b2ef89f0f9 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ManagedDependentDeleteConditionIT.java @@ -0,0 +1,71 @@ +package io.javaoperatorsdk.operator; + +import java.time.Duration; +import java.util.Set; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.Secret; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.manageddependentdeletecondition.ManagedDependentDefaultDeleteConditionCustomResource; +import io.javaoperatorsdk.operator.sample.manageddependentdeletecondition.ManagedDependentDefaultDeleteConditionReconciler; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class ManagedDependentDeleteConditionIT { + + public static final String RESOURCE_NAME = "test1"; + public static final String CUSTOM_FINALIZER = "test/customfinalizer"; + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withConfigurationService(o -> o.withDefaultNonSSAResource(Set.of())) + .withReconciler(new ManagedDependentDefaultDeleteConditionReconciler()).build(); + + + @Test + void resourceNotDeletedUntilDependentDeleted() { + var resource = new ManagedDependentDefaultDeleteConditionCustomResource(); + resource.setMetadata(new ObjectMetaBuilder() + .withName(RESOURCE_NAME) + .build()); + resource = extension.create(resource); + + await().timeout(Duration.ofSeconds(300)).untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, RESOURCE_NAME); + var sec = extension.get(Secret.class, RESOURCE_NAME); + assertThat(cm).isNotNull(); + assertThat(sec).isNotNull(); + }); + + var secret = extension.get(Secret.class, RESOURCE_NAME); + secret.getMetadata().getFinalizers().add(CUSTOM_FINALIZER); + secret = extension.replace(secret); + + extension.delete(resource); + + // both resources are present until the finalizer removed + await().pollDelay(Duration.ofMillis(250)).untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, RESOURCE_NAME); + var sec = extension.get(Secret.class, RESOURCE_NAME); + assertThat(cm).isNotNull(); + assertThat(sec).isNotNull(); + }); + + secret.getMetadata().getFinalizers().clear(); + extension.replace(secret); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, RESOURCE_NAME); + var sec = extension.get(Secret.class, RESOURCE_NAME); + assertThat(cm).isNull(); + assertThat(sec).isNull(); + }); + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ConfigMapDependent.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ConfigMapDependent.java new file mode 100644 index 0000000000..63791417f6 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ConfigMapDependent.java @@ -0,0 +1,29 @@ +package io.javaoperatorsdk.operator.sample.manageddependentdeletecondition; + +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDNoGCKubernetesDependentResource; + +public class ConfigMapDependent extends + CRUDNoGCKubernetesDependentResource { + + public ConfigMapDependent() { + super(ConfigMap.class); + } + + @Override + protected ConfigMap desired(ManagedDependentDefaultDeleteConditionCustomResource primary, + Context context) { + + return new ConfigMapBuilder() + .withNewMetadata() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .endMetadata() + .withData(Map.of("key", "val")) + .build(); + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ManagedDependentDefaultDeleteConditionCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ManagedDependentDefaultDeleteConditionCustomResource.java new file mode 100644 index 0000000000..0922e8977e --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ManagedDependentDefaultDeleteConditionCustomResource.java @@ -0,0 +1,15 @@ +package io.javaoperatorsdk.operator.sample.manageddependentdeletecondition; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("mdcc") +public class ManagedDependentDefaultDeleteConditionCustomResource + extends CustomResource + implements Namespaced { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ManagedDependentDefaultDeleteConditionReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ManagedDependentDefaultDeleteConditionReconciler.java new file mode 100644 index 0000000000..8ef1035e9b --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ManagedDependentDefaultDeleteConditionReconciler.java @@ -0,0 +1,31 @@ +package io.javaoperatorsdk.operator.sample.manageddependentdeletecondition; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; +import io.javaoperatorsdk.operator.processing.dependent.workflow.KubernetesResourceDeletedCondition; + +@ControllerConfiguration(dependents = { + @Dependent(name = "ConfigMap", type = ConfigMapDependent.class), + @Dependent(type = SecretDependent.class, dependsOn = "ConfigMap", + deletePostcondition = KubernetesResourceDeletedCondition.class) +}) +public class ManagedDependentDefaultDeleteConditionReconciler + implements Reconciler { + + private static final Logger log = + LoggerFactory.getLogger(ManagedDependentDefaultDeleteConditionReconciler.class); + + @Override + public UpdateControl reconcile( + ManagedDependentDefaultDeleteConditionCustomResource resource, + Context context) { + + log.debug("Reconciled: {}", resource); + + return UpdateControl.noUpdate(); + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/SecretDependent.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/SecretDependent.java new file mode 100644 index 0000000000..d1af07a2a5 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/SecretDependent.java @@ -0,0 +1,33 @@ +package io.javaoperatorsdk.operator.sample.manageddependentdeletecondition; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.Map; + +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDNoGCKubernetesDependentResource; + +public class SecretDependent + extends + CRUDNoGCKubernetesDependentResource { + + public SecretDependent() { + super(Secret.class); + } + + @Override + protected Secret desired(ManagedDependentDefaultDeleteConditionCustomResource primary, + Context context) { + + return new SecretBuilder() + .withNewMetadata() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .endMetadata() + .withData(Map.of("key", + new String(Base64.getEncoder().encode("val".getBytes(StandardCharsets.UTF_16))))) + .build(); + } +} From cd0fe64bbe59648de453bc58adb993d6fad0389e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 9 Jan 2024 16:34:07 +0100 Subject: [PATCH 117/644] feat: throw exception on problematic owner ference adding in dependent resources (#2190) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/ReconcilerUtils.java | 27 ++++++++++ .../KubernetesDependentResource.java | 2 + .../operator/ReconcilerUtilsTest.java | 54 +++++++++++++++---- 3 files changed, 73 insertions(+), 10 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java index a30c335fb0..fec5c4e61e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java @@ -6,12 +6,15 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.Locale; +import java.util.Objects; import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; import io.fabric8.kubernetes.api.builder.Builder; +import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.client.CustomResource; import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.utils.Serialization; @@ -71,6 +74,30 @@ public static String getNameFor(Class reconcilerClass) { return getDefaultNameFor(reconcilerClass); } + public static void checkIfCanAddOwnerReference(HasMetadata owner, HasMetadata resource) { + if (owner instanceof GenericKubernetesResource + || resource instanceof GenericKubernetesResource) { + return; + } + if (owner instanceof Namespaced) { + if (!(resource instanceof Namespaced)) { + throw new OperatorException( + "Cannot add owner reference from a cluster scoped to a namespace scoped resource." + + resourcesIdentifierDescription(owner, resource)); + } else if (!Objects.equals(owner.getMetadata().getNamespace(), + resource.getMetadata().getNamespace())) { + throw new OperatorException( + "Cannot add owner reference between two resource in different namespaces." + + resourcesIdentifierDescription(owner, resource)); + } + } + } + + private static String resourcesIdentifierDescription(HasMetadata owner, HasMetadata resource) { + return " Owner name: " + owner.getMetadata().getName() + " Kind: " + owner.getKind() + + ", Resource name: " + resource.getMetadata().getName() + " Kind: " + resource.getKind(); + } + public static String getNameFor(Reconciler reconciler) { return getNameFor(reconciler.getClass()); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index a4305df502..36bf342aff 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -10,6 +10,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.dsl.Resource; import io.javaoperatorsdk.operator.OperatorException; +import io.javaoperatorsdk.operator.ReconcilerUtils; import io.javaoperatorsdk.operator.api.config.dependent.Configured; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Constants; @@ -236,6 +237,7 @@ protected Resource prepare(Context

context, R desired, P primary, String a protected void addReferenceHandlingMetadata(R desired, P primary) { if (addOwnerReference()) { + ReconcilerUtils.checkIfCanAddOwnerReference(primary, desired); desired.addOwnerReference(primary); } else if (useNonOwnerRefBasedSecondaryToPrimaryMapping()) { addSecondaryToPrimaryMapperAnnotations(desired, primary); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java index 2b4d89ae06..827bf7916a 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ReconcilerUtilsTest.java @@ -4,16 +4,12 @@ import org.junit.jupiter.api.Test; -import io.fabric8.kubernetes.api.model.ContainerBuilder; -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.api.model.Namespace; -import io.fabric8.kubernetes.api.model.Namespaced; -import io.fabric8.kubernetes.api.model.Pod; -import io.fabric8.kubernetes.api.model.PodSpec; -import io.fabric8.kubernetes.api.model.PodTemplateSpec; +import io.fabric8.kubernetes.api.model.*; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.fabric8.kubernetes.api.model.apps.DeploymentSpec; +import io.fabric8.kubernetes.api.model.rbac.ClusterRole; +import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder; import io.fabric8.kubernetes.client.CustomResource; import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.http.HttpRequest; @@ -29,9 +25,7 @@ import static io.javaoperatorsdk.operator.ReconcilerUtils.handleKubernetesClientException; import static io.javaoperatorsdk.operator.ReconcilerUtils.isFinalizerValid; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -155,6 +149,46 @@ void handleKubernetesExceptionShouldThrowMissingCRDExceptionWhenAppropriate() { HasMetadata.getFullResourceName(Tomcat.class))); } + + @Test + void checksIfOwnerReferenceCanBeAdded() { + assertThrows(OperatorException.class, + () -> ReconcilerUtils.checkIfCanAddOwnerReference(namespacedResource(), + namespacedResourceFromOtherNamespace())); + + assertThrows(OperatorException.class, + () -> ReconcilerUtils.checkIfCanAddOwnerReference(namespacedResource(), + clusterScopedResource())); + + assertDoesNotThrow(() -> { + ReconcilerUtils.checkIfCanAddOwnerReference(clusterScopedResource(), clusterScopedResource()); + ReconcilerUtils.checkIfCanAddOwnerReference(namespacedResource(), namespacedResource()); + }); + } + + private ClusterRole clusterScopedResource() { + return new ClusterRoleBuilder() + .withMetadata(new ObjectMetaBuilder() + .build()) + .build(); + } + + private ConfigMap namespacedResource() { + return new ConfigMapBuilder() + .withMetadata(new ObjectMetaBuilder() + .withNamespace("testns1") + .build()) + .build(); + } + + private ConfigMap namespacedResourceFromOtherNamespace() { + return new ConfigMapBuilder() + .withMetadata(new ObjectMetaBuilder() + .withNamespace("testns2") + .build()) + .build(); + } + @Group("tomcatoperator.io") @Version("v1") @ShortNames("tc") From 5e6a62ae6bbc8e54ff07f87847aca4605680046a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 9 Jan 2024 21:50:53 +0100 Subject: [PATCH 118/644] improve: thread-safe idempotent dynamic informer event source start (#2174) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../processing/event/EventSourceManager.java | 15 ++-- .../event/EventSourceRetriever.java | 1 + .../ControllerResourceEventSource.java | 2 +- .../informer/ManagedInformerEventSource.java | 10 ++- ...namicGenericEventSourceRegistrationIT.java | 62 +++++++++++++ ...EventSourceRegistrationCustomResource.java | 16 ++++ ...ericEventSourceRegistrationReconciler.java | 90 +++++++++++++++++++ 7 files changed, 188 insertions(+), 8 deletions(-) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/DynamicGenericEventSourceRegistrationIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dynamicgenericeventsourceregistration/DynamicGenericEventSourceRegistrationCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dynamicgenericeventsourceregistration/DynamicGenericEventSourceRegistrationReconciler.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java index 5ae700cedc..f9304b6ca6 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java @@ -229,13 +229,18 @@ public List> getResourceEventSourcesFor(Class d } @Override - public synchronized EventSource dynamicallyRegisterEventSource(String name, + public EventSource dynamicallyRegisterEventSource(String name, EventSource eventSource) { - var es = eventSources.existing(name, eventSource); - if (es != null) { - return es; + synchronized (this) { + var actual = eventSources.existing(name, eventSource); + if (actual != null) { + eventSource = actual; + } else { + registerEventSource(name, eventSource); + } } - registerEventSource(name, eventSource); + // The start itself is blocking thus blocking only the threads which are attempt to start the + // actual event source. Think of this as a form of lock striping. eventSource.start(); return eventSource; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceRetriever.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceRetriever.java index a8e7e24f81..7ed2777998 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceRetriever.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceRetriever.java @@ -45,6 +45,7 @@ default ResourceEventSource getResourceEventSourceFor(Class depende */ EventSource dynamicallyRegisterEventSource(String name, EventSource eventSource); + /** * De-registers (and stops) the {@link EventSource} associated with the specified name. If no such * source exists, this method will do nothing. diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java index f7b51bd572..5aa05f146c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java @@ -55,7 +55,7 @@ public ControllerResourceEventSource(Controller controller) { } @Override - public void start() { + public synchronized void start() { try { super.start(); } catch (KubernetesClientException e) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java index 64d402ada5..ec72da0529 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java @@ -76,7 +76,10 @@ public void changeNamespaces(Set namespaces) { } @Override - public void start() { + public synchronized void start() { + if (isRunning()) { + return; + } temporaryResourceCache = new TemporaryResourceCache<>(this, parseResourceVersions); this.cache = new InformerManager<>(client, configuration, this); cache.setConfigurationService(configurationService); @@ -86,7 +89,10 @@ public void start() { } @Override - public void stop() { + public synchronized void stop() { + if (!isRunning()) { + return; + } super.stop(); manager().stop(); } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DynamicGenericEventSourceRegistrationIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DynamicGenericEventSourceRegistrationIT.java new file mode 100644 index 0000000000..308630a365 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DynamicGenericEventSourceRegistrationIT.java @@ -0,0 +1,62 @@ +package io.javaoperatorsdk.operator; + +import java.time.Duration; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.Secret; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.dynamicgenericeventsourceregistration.DynamicGenericEventSourceRegistrationCustomResource; +import io.javaoperatorsdk.operator.sample.dynamicgenericeventsourceregistration.DynamicGenericEventSourceRegistrationReconciler; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +class DynamicGenericEventSourceRegistrationIT { + + public static final String TEST_RESOURCE_NAME = "test1"; + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(DynamicGenericEventSourceRegistrationReconciler.class) + .build(); + + @Test + void registersEventSourcesDynamically() { + var reconciler = + extension.getReconcilerOfType(DynamicGenericEventSourceRegistrationReconciler.class); + extension.create(testResource()); + + await().pollDelay(Duration.ofMillis(150)).untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, TEST_RESOURCE_NAME); + var secret = extension.get(Secret.class, TEST_RESOURCE_NAME); + assertThat(cm).isNotNull(); + assertThat(secret).isNotNull(); + }); + var executions = reconciler.getNumberOfExecutions(); + assertThat(reconciler.getNumberOfEventSources()).isEqualTo(2); + assertThat(executions).isLessThanOrEqualTo(3); + + var cm = extension.get(ConfigMap.class, TEST_RESOURCE_NAME); + cm.getData().put("key2", "val2"); + + extension.replace(cm); // triggers the reconciliation + + await().untilAsserted(() -> { + assertThat(reconciler.getNumberOfExecutions() - executions).isEqualTo(2); + }); + assertThat(reconciler.getNumberOfEventSources()).isEqualTo(2); + } + + + DynamicGenericEventSourceRegistrationCustomResource testResource() { + var res = new DynamicGenericEventSourceRegistrationCustomResource(); + res.setMetadata(new ObjectMetaBuilder() + .withName(TEST_RESOURCE_NAME) + .build()); + return res; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dynamicgenericeventsourceregistration/DynamicGenericEventSourceRegistrationCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dynamicgenericeventsourceregistration/DynamicGenericEventSourceRegistrationCustomResource.java new file mode 100644 index 0000000000..fd82d7bf71 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dynamicgenericeventsourceregistration/DynamicGenericEventSourceRegistrationCustomResource.java @@ -0,0 +1,16 @@ +package io.javaoperatorsdk.operator.sample.dynamicgenericeventsourceregistration; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("dger") +public class DynamicGenericEventSourceRegistrationCustomResource + extends CustomResource + implements Namespaced { + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dynamicgenericeventsourceregistration/DynamicGenericEventSourceRegistrationReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dynamicgenericeventsourceregistration/DynamicGenericEventSourceRegistrationReconciler.java new file mode 100644 index 0000000000..53dc3578bb --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dynamicgenericeventsourceregistration/DynamicGenericEventSourceRegistrationReconciler.java @@ -0,0 +1,90 @@ +package io.javaoperatorsdk.operator.sample.dynamicgenericeventsourceregistration; + +import java.util.Base64; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import io.fabric8.kubernetes.api.model.*; +import io.fabric8.kubernetes.client.dsl.NonDeletingOperation; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; +import io.javaoperatorsdk.operator.processing.GroupVersionKind; +import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; + +@ControllerConfiguration +public class DynamicGenericEventSourceRegistrationReconciler + implements Reconciler { + + private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + private final AtomicInteger numberOfEventSources = new AtomicInteger(); + + @Override + public UpdateControl reconcile( + DynamicGenericEventSourceRegistrationCustomResource primary, + Context context) { + + numberOfExecutions.addAndGet(1); + + context.eventSourceRetriever().dynamicallyRegisterEventSource(ConfigMap.class.getSimpleName(), + genericInformerFor(ConfigMap.class, context)); + context.eventSourceRetriever().dynamicallyRegisterEventSource(Secret.class.getSimpleName(), + genericInformerFor(Secret.class, context)); + + context.getClient().resource(secret(primary)).createOr(NonDeletingOperation::update); + context.getClient().resource(configMap(primary)).createOr(NonDeletingOperation::update); + + numberOfEventSources.set(context.eventSourceRetriever() + .getResourceEventSourcesFor(GenericKubernetesResource.class).size()); + + return UpdateControl.noUpdate(); + } + + private Secret secret(DynamicGenericEventSourceRegistrationCustomResource primary) { + var secret = new SecretBuilder() + .withMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()) + .withData(Map.of("key", Base64.getEncoder().encodeToString("val".getBytes()))) + .build(); + secret.addOwnerReference(primary); + return secret; + } + + private ConfigMap configMap(DynamicGenericEventSourceRegistrationCustomResource primary) { + var cm = new ConfigMapBuilder() + .withMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()) + .withData(Map.of("key", "val")) + .build(); + cm.addOwnerReference(primary); + return cm; + } + + private GroupVersionKind gvkFor(Class clazz) { + return new GroupVersionKind(HasMetadata.getApiVersion(clazz), HasMetadata.getKind(clazz)); + } + + private InformerEventSource genericInformerFor( + Class clazz, + Context context) { + + return new InformerEventSource<>( + InformerConfiguration.from(gvkFor(clazz), + context.eventSourceRetriever().eventSourceContextForDynamicRegistration()).build(), + context.eventSourceRetriever().eventSourceContextForDynamicRegistration()); + } + + public int getNumberOfExecutions() { + return numberOfExecutions.get(); + } + + public int getNumberOfEventSources() { + return numberOfEventSources.get(); + } +} From fb9e07363d1b7ff1fc02ec6e04c17df5eb357bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 10 Jan 2024 08:56:09 +0100 Subject: [PATCH 119/644] improve: dependent resources notify all owners by default (#2161) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../KubernetesDependentResource.java | 2 +- .../operator/processing/event/ResourceID.java | 10 ++- .../event/source/informer/Mappers.java | 7 ++ .../MultiOwnerDependentTriggeringIT.java | 82 +++++++++++++++++++ .../MultipleOwnerDependentConfigMap.java | 55 +++++++++++++ .../MultipleOwnerDependentCustomResource.java | 16 ++++ .../MultipleOwnerDependentReconciler.java | 37 +++++++++ .../MultipleOwnerDependentSpec.java | 15 ++++ 8 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/MultiOwnerDependentTriggeringIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentConfigMap.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentSpec.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 36bf342aff..b804b88a30 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -87,7 +87,7 @@ private SecondaryToPrimaryMapper getSecondaryToPrimaryMapper() { if (this instanceof SecondaryToPrimaryMapper) { return (SecondaryToPrimaryMapper) this; } else if (garbageCollected) { - return Mappers.fromOwnerReference(); + return Mappers.fromOwnerReferences(false); } else if (useNonOwnerRefBasedSecondaryToPrimaryMapping()) { return Mappers.fromDefaultAnnotations(); } else { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceID.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceID.java index a6bf6dd4e8..39374cb433 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceID.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceID.java @@ -5,6 +5,7 @@ import java.util.Optional; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.OwnerReference; public class ResourceID implements Serializable { @@ -21,13 +22,18 @@ public static Optional fromFirstOwnerReference(HasMetadata resource, boolean clusterScoped) { var ownerReferences = resource.getMetadata().getOwnerReferences(); if (!ownerReferences.isEmpty()) { - return Optional.of(new ResourceID(ownerReferences.get(0).getName(), - clusterScoped ? null : resource.getMetadata().getNamespace())); + return Optional.of(fromOwnerReference(resource, ownerReferences.get(0), clusterScoped)); } else { return Optional.empty(); } } + public static ResourceID fromOwnerReference(HasMetadata resource, OwnerReference ownerReference, + boolean clusterScoped) { + return new ResourceID(ownerReference.getName(), + clusterScoped ? null : resource.getMetadata().getNamespace()); + } + private final String name; private final String namespace; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/Mappers.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/Mappers.java index 23a79b8f62..65f9c86cb8 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/Mappers.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/Mappers.java @@ -57,6 +57,13 @@ public static SecondaryToPrimaryMapper fromOwnerRefer .orElseGet(Collections::emptySet); } + public static SecondaryToPrimaryMapper fromOwnerReferences( + boolean clusterScope) { + return resource -> resource.getMetadata().getOwnerReferences().stream() + .map(or -> ResourceID.fromOwnerReference(resource, or, clusterScope)) + .collect(Collectors.toSet()); + } + private static SecondaryToPrimaryMapper fromMetadata( String nameKey, String namespaceKey, boolean isLabel) { return resource -> { diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultiOwnerDependentTriggeringIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultiOwnerDependentTriggeringIT.java new file mode 100644 index 0000000000..7f6f917c55 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultiOwnerDependentTriggeringIT.java @@ -0,0 +1,82 @@ +package io.javaoperatorsdk.operator; + +import java.util.Set; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.multipleupdateondependent.MultipleOwnerDependentConfigMap; +import io.javaoperatorsdk.operator.sample.multipleupdateondependent.MultipleOwnerDependentCustomResource; +import io.javaoperatorsdk.operator.sample.multipleupdateondependent.MultipleOwnerDependentReconciler; +import io.javaoperatorsdk.operator.sample.multipleupdateondependent.MultipleOwnerDependentSpec; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +class MultiOwnerDependentTriggeringIT { + + public static final String VALUE_1 = "value1"; + public static final String VALUE_2 = "value2"; + public static final String NEW_VALUE_1 = "newValue1"; + public static final String NEW_VALUE_2 = "newValue2"; + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withConfigurationService(o -> o.withDefaultNonSSAResource(Set.of())) + .withReconciler(MultipleOwnerDependentReconciler.class) + .build(); + + + @Test + void multiOwnerTriggeringAndManagement() { + var res1 = extension.create(testResource("res1", VALUE_1)); + var res2 = extension.create(testResource("res2", VALUE_2)); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, MultipleOwnerDependentConfigMap.RESOURCE_NAME); + + assertThat(cm).isNotNull(); + assertThat(cm.getData()) + .containsEntry(VALUE_1, VALUE_1) + .containsEntry(VALUE_2, VALUE_2); + assertThat(cm.getMetadata().getOwnerReferences()).hasSize(2); + }); + + res1.getSpec().setValue(NEW_VALUE_1); + extension.replace(res1); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, MultipleOwnerDependentConfigMap.RESOURCE_NAME); + assertThat(cm.getData()) + .containsEntry(NEW_VALUE_1, NEW_VALUE_1) + // note that it will still contain the old value too + .containsEntry(VALUE_1, VALUE_1); + assertThat(cm.getMetadata().getOwnerReferences()).hasSize(2); + }); + + res2.getSpec().setValue(NEW_VALUE_2); + extension.replace(res2); + + await().untilAsserted(() -> { + var cm = extension.get(ConfigMap.class, MultipleOwnerDependentConfigMap.RESOURCE_NAME); + assertThat(cm.getData()).containsEntry(NEW_VALUE_2, NEW_VALUE_2); + assertThat(cm.getMetadata().getOwnerReferences()).hasSize(2); + }); + } + + MultipleOwnerDependentCustomResource testResource(String name, String value) { + var res = new MultipleOwnerDependentCustomResource(); + res.setMetadata(new ObjectMetaBuilder() + .withName(name) + .build()); + res.setSpec(new MultipleOwnerDependentSpec()); + res.getSpec().setValue(value); + + return res; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentConfigMap.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentConfigMap.java new file mode 100644 index 0000000000..698cec88af --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentConfigMap.java @@ -0,0 +1,55 @@ +package io.javaoperatorsdk.operator.sample.multipleupdateondependent; + +import java.util.HashMap; +import java.util.List; +import java.util.Optional; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.BooleanWithUndefined; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; + +@KubernetesDependent(useSSA = BooleanWithUndefined.TRUE) +public class MultipleOwnerDependentConfigMap + extends + CRUDKubernetesDependentResource { + + public static final String RESOURCE_NAME = "test1"; + + public MultipleOwnerDependentConfigMap() { + super(ConfigMap.class); + } + + @Override + protected ConfigMap desired(MultipleOwnerDependentCustomResource primary, + Context context) { + + var cm = getSecondaryResource(primary, context); + + var data = cm.map(ConfigMap::getData).orElse(new HashMap<>()); + data.put(primary.getSpec().getValue(), primary.getSpec().getValue()); + + return new ConfigMapBuilder() + .withNewMetadata() + .withName(RESOURCE_NAME) + .withNamespace(primary.getMetadata().getNamespace()) + .withOwnerReferences(cm.map(c -> c.getMetadata().getOwnerReferences()).orElse(List.of())) + .endMetadata() + .withData(data) + .build(); + } + + // need to change this since owner reference is present only for the creator primary resource. + @Override + public Optional getSecondaryResource(MultipleOwnerDependentCustomResource primary, + Context context) { + InformerEventSource ies = + (InformerEventSource) context + .eventSourceRetriever().getResourceEventSourceFor(ConfigMap.class); + return ies.get(new ResourceID(RESOURCE_NAME, primary.getMetadata().getNamespace())); + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentCustomResource.java new file mode 100644 index 0000000000..85b8be124c --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentCustomResource.java @@ -0,0 +1,16 @@ +package io.javaoperatorsdk.operator.sample.multipleupdateondependent; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("mod") +public class MultipleOwnerDependentCustomResource + extends CustomResource + implements Namespaced { + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentReconciler.java new file mode 100644 index 0000000000..c1f1262414 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentReconciler.java @@ -0,0 +1,37 @@ +package io.javaoperatorsdk.operator.sample.multipleupdateondependent; + +import java.util.concurrent.atomic.AtomicInteger; + +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; +import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; + +@ControllerConfiguration(dependents = { + @Dependent(type = MultipleOwnerDependentConfigMap.class) +}) +public class MultipleOwnerDependentReconciler + implements Reconciler, + TestExecutionInfoProvider { + + private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + + public MultipleOwnerDependentReconciler() {} + + @Override + public UpdateControl reconcile( + MultipleOwnerDependentCustomResource resource, + Context context) { + numberOfExecutions.getAndIncrement(); + + return UpdateControl.noUpdate(); + } + + + public int getNumberOfExecutions() { + return numberOfExecutions.get(); + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentSpec.java new file mode 100644 index 0000000000..cda4377cdc --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multipleupdateondependent/MultipleOwnerDependentSpec.java @@ -0,0 +1,15 @@ +package io.javaoperatorsdk.operator.sample.multipleupdateondependent; + +public class MultipleOwnerDependentSpec { + + private String value; + + public String getValue() { + return value; + } + + public MultipleOwnerDependentSpec setValue(String value) { + this.value = value; + return this; + } +} From 87275f9404c2f13ff821db35d7c29683cfd3417d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 10 Jan 2024 10:57:38 +0100 Subject: [PATCH 120/644] improve: eventing on cleanup in case status is changed after marked for deletion (#2153) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../controller/InternalEventFilters.java | 6 +- .../controller/InternalEventFiltersTest.java | 3 +- .../UpdateStatusInCleanupAndRescheduleIT.java | 55 +++++++++++++++++ ...sInCleanupAndRescheduleCustomResource.java | 17 ++++++ ...tusInCleanupAndRescheduleCustomStatus.java | 16 +++++ ...tatusInCleanupAndRescheduleReconciler.java | 60 +++++++++++++++++++ 6 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/UpdateStatusInCleanupAndRescheduleIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/updatestatusincleanupandreschedule/UpdateStatusInCleanupAndRescheduleCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/updatestatusincleanupandreschedule/UpdateStatusInCleanupAndRescheduleCustomStatus.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/updatestatusincleanupandreschedule/UpdateStatusInCleanupAndRescheduleReconciler.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/InternalEventFilters.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/InternalEventFilters.java index 1f6ecc4540..b7c4249411 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/InternalEventFilters.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/InternalEventFilters.java @@ -8,7 +8,11 @@ public class InternalEventFilters { private InternalEventFilters() {} static OnUpdateFilter onUpdateMarkedForDeletion() { - return (newResource, oldResource) -> newResource.isMarkedForDeletion(); + // the old resource is checked since in corner cases users might still want to update the status + // for a resource that is marked for deletion + + return (newResource, oldResource) -> !oldResource.isMarkedForDeletion() + && newResource.isMarkedForDeletion(); } static OnUpdateFilter onUpdateGenerationAware( diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/InternalEventFiltersTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/InternalEventFiltersTest.java index 4a5caa74f0..829e1620a7 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/InternalEventFiltersTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/controller/InternalEventFiltersTest.java @@ -17,8 +17,9 @@ class InternalEventFiltersTest { @Test void onUpdateMarkedForDeletion() { + var oldRes = TestUtils.testCustomResource(); var res = markForDeletion(TestUtils.testCustomResource()); - assertThat(InternalEventFilters.onUpdateMarkedForDeletion().accept(res, res)).isTrue(); + assertThat(InternalEventFilters.onUpdateMarkedForDeletion().accept(res, oldRes)).isTrue(); } @Test diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/UpdateStatusInCleanupAndRescheduleIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/UpdateStatusInCleanupAndRescheduleIT.java new file mode 100644 index 0000000000..798ea4eac5 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/UpdateStatusInCleanupAndRescheduleIT.java @@ -0,0 +1,55 @@ +package io.javaoperatorsdk.operator; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.updatestatusincleanupandreschedule.UpdateStatusInCleanupAndRescheduleCustomResource; +import io.javaoperatorsdk.operator.sample.updatestatusincleanupandreschedule.UpdateStatusInCleanupAndRescheduleReconciler; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class UpdateStatusInCleanupAndRescheduleIT { + + public static final String TEST_RESOURCE = "test1"; + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(UpdateStatusInCleanupAndRescheduleReconciler.class) + .build(); + + + @Test + void testRescheduleAfterPatch() { + var res = extension.create(testResource()); + + await().untilAsserted(() -> { + var resource = + extension.get(UpdateStatusInCleanupAndRescheduleCustomResource.class, TEST_RESOURCE); + assertThat(resource.getMetadata().getFinalizers()).isNotEmpty(); + }); + + extension.delete(res); + + await().untilAsserted(() -> { + var resource = + extension.get(UpdateStatusInCleanupAndRescheduleCustomResource.class, TEST_RESOURCE); + assertThat(resource).isNull(); + }); + + assertThat(extension.getReconcilerOfType(UpdateStatusInCleanupAndRescheduleReconciler.class) + .getRescheduleDelayWorked()) + .isTrue(); + } + + UpdateStatusInCleanupAndRescheduleCustomResource testResource() { + var resource = new UpdateStatusInCleanupAndRescheduleCustomResource(); + resource.setMetadata(new ObjectMetaBuilder() + .withName(TEST_RESOURCE) + .build()); + return resource; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/updatestatusincleanupandreschedule/UpdateStatusInCleanupAndRescheduleCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/updatestatusincleanupandreschedule/UpdateStatusInCleanupAndRescheduleCustomResource.java new file mode 100644 index 0000000000..9c6365e5d0 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/updatestatusincleanupandreschedule/UpdateStatusInCleanupAndRescheduleCustomResource.java @@ -0,0 +1,17 @@ +package io.javaoperatorsdk.operator.sample.updatestatusincleanupandreschedule; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("usc") +public class UpdateStatusInCleanupAndRescheduleCustomResource + extends + CustomResource + implements Namespaced { + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/updatestatusincleanupandreschedule/UpdateStatusInCleanupAndRescheduleCustomStatus.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/updatestatusincleanupandreschedule/UpdateStatusInCleanupAndRescheduleCustomStatus.java new file mode 100644 index 0000000000..17e4067a44 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/updatestatusincleanupandreschedule/UpdateStatusInCleanupAndRescheduleCustomStatus.java @@ -0,0 +1,16 @@ +package io.javaoperatorsdk.operator.sample.updatestatusincleanupandreschedule; + +public class UpdateStatusInCleanupAndRescheduleCustomStatus { + + private Integer cleanupAttempt; + + public Integer getCleanupAttempt() { + return cleanupAttempt; + } + + public UpdateStatusInCleanupAndRescheduleCustomStatus setCleanupAttempt(Integer cleanupAttempt) { + this.cleanupAttempt = cleanupAttempt; + return this; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/updatestatusincleanupandreschedule/UpdateStatusInCleanupAndRescheduleReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/updatestatusincleanupandreschedule/UpdateStatusInCleanupAndRescheduleReconciler.java new file mode 100644 index 0000000000..9fcceca851 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/updatestatusincleanupandreschedule/UpdateStatusInCleanupAndRescheduleReconciler.java @@ -0,0 +1,60 @@ +package io.javaoperatorsdk.operator.sample.updatestatusincleanupandreschedule; + +import java.time.LocalTime; +import java.time.temporal.ChronoUnit; + +import io.javaoperatorsdk.operator.api.reconciler.*; + +@ControllerConfiguration +public class UpdateStatusInCleanupAndRescheduleReconciler + implements Reconciler, + Cleaner { + + public static final Integer DELAY = 150; + + private LocalTime lastCleanupExecution; + + public Boolean rescheduleDelayWorked; + + @Override + public UpdateControl reconcile( + UpdateStatusInCleanupAndRescheduleCustomResource resource, + Context context) { + + return UpdateControl.noUpdate(); + } + + @Override + public DeleteControl cleanup(UpdateStatusInCleanupAndRescheduleCustomResource resource, + Context context) { + + var status = resource.getStatus(); + if (status == null) { + resource.setStatus(new UpdateStatusInCleanupAndRescheduleCustomStatus()); + resource.getStatus().setCleanupAttempt(1); + lastCleanupExecution = LocalTime.now(); + } else { + var currentAttempt = resource.getStatus().getCleanupAttempt(); + resource.getStatus().setCleanupAttempt(currentAttempt + 1); + if (!Boolean.FALSE.equals(rescheduleDelayWorked)) { + var diff = ChronoUnit.MILLIS.between(lastCleanupExecution, LocalTime.now()); + if (diff < DELAY) { + rescheduleDelayWorked = false; + } else { + rescheduleDelayWorked = true; + } + } + } + var res = context.getClient().resource(resource).updateStatus(); + + if (resource.getStatus().getCleanupAttempt() > 5) { + return DeleteControl.defaultDelete(); + } else { + return DeleteControl.noFinalizerRemoval().rescheduleAfter(DELAY); + } + } + + public Boolean getRescheduleDelayWorked() { + return rescheduleDelayWorked; + } +} From af7706452752dadcecaccf549640066c795311d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 10 Jan 2024 15:33:51 +0100 Subject: [PATCH 121/644] chore: fabric8 client v6.10.0 (#2193) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0e8b9a4459..6af732f2c6 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ okhttp 5.10.1 - 6.9.2 + 6.10.0 1.7.36 2.22.1 5.8.0 From 553957759348fc930913f2dac428eb330230baec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 09:20:09 +0100 Subject: [PATCH 122/644] chore(deps): bump org.apache.maven.plugins:maven-compiler-plugin (#2195) Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.11.0 to 3.12.1. - [Release notes](https://github.com/apache/maven-compiler-plugin/releases) - [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.11.0...maven-compiler-plugin-3.12.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-compiler-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index ea18538d30..d4349cd388 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -81,7 +81,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 7dba03f3d9..61f0abf4d7 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -108,7 +108,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 89e243ba0a..05fcfbbabf 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -110,7 +110,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index e0becee1a5..2aae0570cb 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -81,7 +81,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.12.1 From 81a1fc3f00c9d9a67f9c3eb841be664b7fdfb099 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 09:20:31 +0100 Subject: [PATCH 123/644] chore(deps): bump org.apache.maven.plugin-tools:maven-plugin-annotations (#2196) Bumps [org.apache.maven.plugin-tools:maven-plugin-annotations](https://github.com/apache/maven-plugin-tools) from 3.10.2 to 3.11.0. - [Release notes](https://github.com/apache/maven-plugin-tools/releases) - [Commits](https://github.com/apache/maven-plugin-tools/compare/maven-plugin-tools-3.10.2...maven-plugin-tools-3.11.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugin-tools:maven-plugin-annotations dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bootstrapper-maven-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index b82bcc11f4..7d1da5d97e 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -14,7 +14,7 @@ Operator SDK - Bootstrapper Maven Plugin - 3.10.2 + 3.11.0 3.9.6 From 040c06afb8c0315164ee574a49bc2d795bebea78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 09:57:44 +0100 Subject: [PATCH 124/644] chore(deps): bump org.mockito:mockito-core from 5.8.0 to 5.9.0 (#2199) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.8.0 to 5.9.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.8.0...v5.9.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6af732f2c6..064f19c8b4 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 6.10.0 1.7.36 2.22.1 - 5.8.0 + 5.9.0 3.14.0 0.21.0 1.13.0 From 3496e9be606065531f62da41a636dabc6cbafbb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 18 Jan 2024 10:23:44 +0100 Subject: [PATCH 125/644] chore: jenvtest to 0.9.6 (#2201) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 064f19c8b4..e7993ded00 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.12.2 4.12.0 3.1.8 - 0.9.0 + 0.9.6 0.9.11 2.15.1 From 24784f2d662c26353b22f6551b9a0b21f6779c58 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 10:48:55 +0100 Subject: [PATCH 126/644] chore(deps): bump actions/cache from 3 to 4 (#2202) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Attila Mészáros --- .github/workflows/sonar.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 783f250669..b7a96edef6 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -31,7 +31,7 @@ jobs: java-version: 17 cache: 'maven' - name: Cache SonarCloud packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar From 280e4b56a317e8c93c240e1c1a460a882051c640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 18 Jan 2024 14:47:37 +0100 Subject: [PATCH 127/644] chore: bootstrapper maven-plugin-plugin version (#2204) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes also missing goal prefix Signed-off-by: Attila Mészáros --- bootstrapper-maven-plugin/pom.xml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 7d1da5d97e..c27fcb5e3d 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -16,6 +16,8 @@ 3.11.0 3.9.6 + 3.0.0 + 3.11.0 @@ -74,12 +76,15 @@ org.apache.maven.plugins maven-plugin-plugin - 3.10.2 + ${maven-plugin-plugin.version} + + josdk-bootstrapper + org.codehaus.mojo templating-maven-plugin - 3.0.0 + ${templating-maven-plugin.version} filtering-java-templates From 8165e6d1b1fe7e65e970fcd82f14897f38296b7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Jan 2024 08:10:10 +0100 Subject: [PATCH 128/644] chore(deps): bump org.assertj:assertj-core from 3.25.1 to 3.25.2 (#2216) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e7993ded00..5f7e4b8a0c 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ 3.14.0 0.21.0 1.13.0 - 3.25.1 + 3.25.2 4.2.0 2.7.3 1.12.2 From f4b9744426de42e6d44b6dfbe6598768fecf0f0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Jan 2024 08:53:14 +0100 Subject: [PATCH 129/644] chore(deps): bump org.mockito:mockito-core from 5.9.0 to 5.10.0 (#2215) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.9.0 to 5.10.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.9.0...v5.10.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f7e4b8a0c..509fb7b726 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 6.10.0 1.7.36 2.22.1 - 5.9.0 + 5.10.0 3.14.0 0.21.0 1.13.0 From 988cf176816249b4ef02f32847ea4c05d69eddfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 25 Jan 2024 10:12:12 +0100 Subject: [PATCH 130/644] chore: set version in pom to 4.7.1-SNAPSHOT (#2217) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index c27fcb5e3d..c6cc1e8f68 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index a63c5889fe..c1cd13611c 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 6f6669999a..9588adcb78 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 75ead60afa..54ed34e1ce 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index dc054d587a..c3cba42ad2 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 4bbd35e145..61a3a66f31 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index 430cc508b2..eac361a75b 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 509fb7b726..f2065f507d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index d4349cd388..b2340fad30 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 61f0abf4d7..a8b9cb5261 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 56c7834d03..e789be46d7 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 05fcfbbabf..2c4e2e73b5 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 2aae0570cb..5ac137df45 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.0-SNAPSHOT + 4.7.1-SNAPSHOT sample-webpage-operator From 51a8fe509cd72d47bd94c35282f5f149e9d45cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 25 Jan 2024 13:54:00 +0100 Subject: [PATCH 131/644] fix: dynamic event source registration should not return named event source (#2219) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/processing/event/EventSourceManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java index f9304b6ca6..bd299b464a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java @@ -234,7 +234,7 @@ public EventSource dynamicallyRegisterEventSource(String name, synchronized (this) { var actual = eventSources.existing(name, eventSource); if (actual != null) { - eventSource = actual; + eventSource = actual.eventSource(); } else { registerEventSource(name, eventSource); } From 236698752758d8b9a7b64fa22009ee9fbe14028b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 29 Jan 2024 09:22:14 +0100 Subject: [PATCH 132/644] docs: note on activation condition (#2220) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- docs/documentation/workflows.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/documentation/workflows.md b/docs/documentation/workflows.md index 27cd2f4274..7190f8e8e3 100644 --- a/docs/documentation/workflows.md +++ b/docs/documentation/workflows.md @@ -43,6 +43,10 @@ reconciliation process. condition holds or not. This is a very useful feature when your operator needs to handle different flavors of the platform (e.g. OpenShift vs plain Kubernetes) and/or change its behavior based on the availability of optional resources / features (e.g. CertManager, a specific Ingress controller, etc.). + + Activation condition is semi-experimental at the moment, and it has its limitations. + For example event sources cannot be shared between multiple managed dependent resources which use activation condition. + The intention is to further improve and explore the possibilities with this approach. ## Defining Workflows From 7d17e4c814d32a0f2d25b2a57164495a327f77e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 29 Jan 2024 15:04:11 +0100 Subject: [PATCH 133/644] fix: possible issue with concurrency for activation dynamic event source registration (#2222) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../AbstractEventSourceHolderDependentResource.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java index 04aa5631cf..6562afd09f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java @@ -34,13 +34,22 @@ protected AbstractEventSourceHolderDependentResource(Class resourceType) { this.resourceType = resourceType; } - public Optional eventSource(EventSourceContext

context) { + /** + * Method is synchronized since when used in case of dynamic registration (thus for activation + * conditions) can be called concurrently to create the target event source. In that case only one + * instance should be created, since this also sets the event source, and dynamic registration + * will just start one with the same name. So if this would not be synchronized it could happen + * that multiple event sources would be created and only one started and registered. Note that + * this method does not start the event source, so no blocking IO is involved. + */ + public synchronized Optional eventSource(EventSourceContext

context) { // some sub-classes (e.g. KubernetesDependentResource) can have their event source created // before this method is called in the managed case, so only create the event source if it // hasn't already been set. // The filters are applied automatically only if event source is created automatically. So if an // event source // is shared between dependent resources this does not override the existing filters. + if (eventSource == null && eventSourceNameToUse == null) { setEventSource(createEventSource(context)); applyFilters(); From fa43abacb153b03adb2b280afc17765f26deabf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 29 Jan 2024 15:28:44 +0100 Subject: [PATCH 134/644] fix: cleanup of resources with activation condition (#2223) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../workflow/AbstractWorkflowExecutor.java | 19 +++++ .../workflow/WorkflowCleanupExecutor.java | 1 + .../workflow/WorkflowReconcileExecutor.java | 18 ----- .../AbstractWorkflowExecutorTest.java | 4 +- .../workflow/WorkflowCleanupExecutorTest.java | 18 +++++ .../operator/WorkflowActivationCleanupIT.java | 79 +++++++++++++++++++ .../ConfigMapDependentResource.java | 31 ++++++++ .../TestActivcationCondition.java | 18 +++++ ...rkflowActivationCleanupCustomResource.java | 17 ++++ .../WorkflowActivationCleanupReconciler.java | 27 +++++++ .../WorkflowActivationCleanupSpec.java | 14 ++++ 11 files changed, 227 insertions(+), 19 deletions(-) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/WorkflowActivationCleanupIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/ConfigMapDependentResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/TestActivcationCondition.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/WorkflowActivationCleanupCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/WorkflowActivationCleanupReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/WorkflowActivationCleanupSpec.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java index c546570e34..56e5e17d07 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutor.java @@ -128,4 +128,23 @@ protected void submit(DependentResourceNode dependentResourceNode, logger().debug("Submitted to {}: {} primaryID: {}", operation, dependentResourceNode, primaryID); } + + protected void registerOrDeregisterEventSourceBasedOnActivation( + boolean activationConditionMet, + DependentResourceNode dependentResourceNode) { + if (dependentResourceNode.getActivationCondition().isPresent()) { + if (activationConditionMet) { + var eventSource = + dependentResourceNode.getDependentResource().eventSource(context.eventSourceRetriever() + .eventSourceContextForDynamicRegistration()); + var es = eventSource.orElseThrow(); + context.eventSourceRetriever() + .dynamicallyRegisterEventSource(dependentResourceNode.getName(), es); + + } else { + context.eventSourceRetriever() + .dynamicallyDeRegisterEventSource(dependentResourceNode.getName()); + } + } + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutor.java index 74ae47100e..dda4db6729 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutor.java @@ -70,6 +70,7 @@ protected void doRun(DependentResourceNode dependentResourceNode, var active = isConditionMet(dependentResourceNode.getActivationCondition(), dependentResource); + registerOrDeregisterEventSourceBasedOnActivation(active, dependentResourceNode); if (dependentResource.isDeletable() && active) { ((Deleter

) dependentResource).delete(primary, context); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java index 33aad99811..2da0bd7525 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowReconcileExecutor.java @@ -78,24 +78,6 @@ private synchronized void handleReconcile(DependentResourceNode depend } } - private void registerOrDeregisterEventSourceBasedOnActivation(boolean activationConditionMet, - DependentResourceNode dependentResourceNode) { - if (dependentResourceNode.getActivationCondition().isPresent()) { - if (activationConditionMet) { - var eventSource = - dependentResourceNode.getDependentResource().eventSource(context.eventSourceRetriever() - .eventSourceContextForDynamicRegistration()); - var es = eventSource.orElseThrow(); - context.eventSourceRetriever() - .dynamicallyRegisterEventSource(dependentResourceNode.getName(), es); - - } else { - context.eventSourceRetriever() - .dynamicallyDeRegisterEventSource(dependentResourceNode.getName()); - } - } - } - private synchronized void handleDelete(DependentResourceNode dependentResourceNode) { log.debug("Submitting for delete: {}", dependentResourceNode); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutorTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutorTest.java index 6cfdb3dc63..941c3fa434 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutorTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/AbstractWorkflowExecutorTest.java @@ -11,6 +11,7 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; import io.javaoperatorsdk.operator.api.reconciler.dependent.GarbageCollected; import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult; +import io.javaoperatorsdk.operator.processing.dependent.Creator; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; import io.javaoperatorsdk.operator.sample.simple.TestCustomResource; @@ -55,7 +56,8 @@ public String toString() { } } - public class TestDeleterDependent extends TestDependent implements Deleter { + public class TestDeleterDependent extends TestDependent + implements Creator, Deleter { public TestDeleterDependent(String name) { super(name); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutorTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutorTest.java index 3b34dcf458..ed6ba5f80c 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutorTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowCleanupExecutorTest.java @@ -7,8 +7,14 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import io.fabric8.kubernetes.api.model.ConfigMap; import io.javaoperatorsdk.operator.AggregatedOperatorException; +import io.javaoperatorsdk.operator.MockKubernetesClient; +import io.javaoperatorsdk.operator.api.config.ConfigurationService; +import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever; import io.javaoperatorsdk.operator.sample.simple.TestCustomResource; import static io.javaoperatorsdk.operator.processing.dependent.workflow.ExecutionAssert.assertThat; @@ -29,7 +35,19 @@ class WorkflowCleanupExecutorTest extends AbstractWorkflowExecutorTest { @BeforeEach void setup() { + var eventSourceContextMock = mock(EventSourceContext.class); + var eventSourceRetrieverMock = mock(EventSourceRetriever.class); + var mockControllerConfig = mock(ControllerConfiguration.class); + when(eventSourceRetrieverMock.eventSourceContextForDynamicRegistration()) + .thenReturn(eventSourceContextMock); + var client = MockKubernetesClient.client(ConfigMap.class); + when(eventSourceContextMock.getClient()).thenReturn(client); + when(eventSourceContextMock.getControllerConfiguration()).thenReturn(mockControllerConfig); + when(mockControllerConfig.getConfigurationService()) + .thenReturn(mock(ConfigurationService.class)); + when(mockContext.getWorkflowExecutorService()).thenReturn(executorService); + when(mockContext.eventSourceRetriever()).thenReturn(eventSourceRetrieverMock); } @Test diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/WorkflowActivationCleanupIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/WorkflowActivationCleanupIT.java new file mode 100644 index 0000000000..fe1b72cc5a --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/WorkflowActivationCleanupIT.java @@ -0,0 +1,79 @@ +package io.javaoperatorsdk.operator; + +import org.junit.jupiter.api.*; + +import io.fabric8.kubernetes.api.model.Namespace; +import io.fabric8.kubernetes.api.model.NamespaceBuilder; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientBuilder; +import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.workflowactivationcleanup.WorkflowActivationCleanupCustomResource; +import io.javaoperatorsdk.operator.sample.workflowactivationcleanup.WorkflowActivationCleanupReconciler; +import io.javaoperatorsdk.operator.sample.workflowactivationcleanup.WorkflowActivationCleanupSpec; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class WorkflowActivationCleanupIT { + + private final KubernetesClient client = new KubernetesClientBuilder().build(); + private Operator operator; + + private String testNamespace; + + @BeforeEach + void beforeEach(TestInfo testInfo) { + LocallyRunOperatorExtension.applyCrd(WorkflowActivationCleanupCustomResource.class, + client); + + testInfo.getTestMethod() + .ifPresent(method -> testNamespace = KubernetesResourceUtil.sanitizeName(method.getName())); + client.namespaces().resource(testNamespace(testNamespace)).create(); + operator = new Operator(o -> o.withCloseClientOnStop(false)); + operator.register(new WorkflowActivationCleanupReconciler(), + o -> o.settingNamespaces(testNamespace)); + } + + @AfterEach + void stopOperator() { + client.namespaces().withName(testNamespace).delete(); + await().untilAsserted(() -> { + var ns = client.namespaces().withName(testNamespace).get(); + assertThat(ns).isNull(); + }); + operator.stop(); + } + + @Test + void testCleanupOnMarkedResourceOnOperatorStartup() { + var resource = client.resource(testResourceWithFinalizer()).create(); + client.resource(resource).delete(); + operator.start(); + + await().untilAsserted(() -> { + var res = client.resource(resource).get(); + assertThat(res).isNull(); + }); + } + + private WorkflowActivationCleanupCustomResource testResourceWithFinalizer() { + var resource = new WorkflowActivationCleanupCustomResource(); + resource.setMetadata(new ObjectMetaBuilder() + .withName("test1") + .withFinalizers("workflowactivationcleanupcustomresources.sample.javaoperatorsdk/finalizer") + .withNamespace(testNamespace) + .build()); + resource.setSpec(new WorkflowActivationCleanupSpec()); + resource.getSpec().setValue("val1"); + return resource; + } + + private Namespace testNamespace(String name) { + return new NamespaceBuilder().withMetadata(new ObjectMetaBuilder() + .withName(name) + .build()).build(); + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/ConfigMapDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/ConfigMapDependentResource.java new file mode 100644 index 0000000000..241bff64ce --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/ConfigMapDependentResource.java @@ -0,0 +1,31 @@ +package io.javaoperatorsdk.operator.sample.workflowactivationcleanup; + +import java.util.Map; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDNoGCKubernetesDependentResource; + +public class ConfigMapDependentResource + extends + CRUDNoGCKubernetesDependentResource { + + public static final String DATA_KEY = "data"; + + public ConfigMapDependentResource() { + super(ConfigMap.class); + } + + @Override + protected ConfigMap desired(WorkflowActivationCleanupCustomResource primary, + Context context) { + ConfigMap configMap = new ConfigMap(); + configMap.setMetadata(new ObjectMetaBuilder() + .withName(primary.getMetadata().getName()) + .withNamespace(primary.getMetadata().getNamespace()) + .build()); + configMap.setData(Map.of(DATA_KEY, primary.getSpec().getValue())); + return configMap; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/TestActivcationCondition.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/TestActivcationCondition.java new file mode 100644 index 0000000000..ff215b7d72 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/TestActivcationCondition.java @@ -0,0 +1,18 @@ +package io.javaoperatorsdk.operator.sample.workflowactivationcleanup; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition; + +public class TestActivcationCondition + implements Condition { + + @Override + public boolean isMet( + DependentResource dependentResource, + WorkflowActivationCleanupCustomResource primary, + Context context) { + return true; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/WorkflowActivationCleanupCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/WorkflowActivationCleanupCustomResource.java new file mode 100644 index 0000000000..f73b484d86 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/WorkflowActivationCleanupCustomResource.java @@ -0,0 +1,17 @@ +package io.javaoperatorsdk.operator.sample.workflowactivationcleanup; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("wacc") +public class WorkflowActivationCleanupCustomResource + extends CustomResource + implements Namespaced { + + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/WorkflowActivationCleanupReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/WorkflowActivationCleanupReconciler.java new file mode 100644 index 0000000000..3f2fba15c5 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/WorkflowActivationCleanupReconciler.java @@ -0,0 +1,27 @@ +package io.javaoperatorsdk.operator.sample.workflowactivationcleanup; + +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; + +@ControllerConfiguration(dependents = { + @Dependent(type = ConfigMapDependentResource.class, + activationCondition = TestActivcationCondition.class), +}) +public class WorkflowActivationCleanupReconciler + implements Reconciler, + Cleaner { + + @Override + public UpdateControl reconcile( + WorkflowActivationCleanupCustomResource resource, + Context context) { + + return UpdateControl.noUpdate(); + } + + @Override + public DeleteControl cleanup(WorkflowActivationCleanupCustomResource resource, + Context context) { + return DeleteControl.defaultDelete(); + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/WorkflowActivationCleanupSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/WorkflowActivationCleanupSpec.java new file mode 100644 index 0000000000..23ea4cda3e --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowactivationcleanup/WorkflowActivationCleanupSpec.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.sample.workflowactivationcleanup; + +public class WorkflowActivationCleanupSpec { + + private String value; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} From 8342b918e7fa4e57fd4a66441bd19623b865b6c1 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 29 Jan 2024 15:10:49 +0000 Subject: [PATCH 135/644] Set new SNAPSHOT version into pom files. --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index c6cc1e8f68..2ccc24e23d 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index c1cd13611c..dac6530fea 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 9588adcb78..5e2d38702e 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 54ed34e1ce..a1ff5a4c5d 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index c3cba42ad2..00a502a6d2 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 61a3a66f31..152cd353e6 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index eac361a75b..25cd05b4c5 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index f2065f507d..302d0d337e 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index b2340fad30..e6d6893ab0 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index a8b9cb5261..f4d65ccf01 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index e789be46d7..a0553af8b4 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 2c4e2e73b5..6fb7bae9e1 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 5ac137df45..2fba19290a 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.1-SNAPSHOT + 4.7.2-SNAPSHOT sample-webpage-operator From 1fc9e3ebac7533be444abe1dcf12f396b8fcc0b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Fri, 2 Feb 2024 17:13:04 +0100 Subject: [PATCH 136/644] chore: k8s version for PR (#2231) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 686647b46d..e1116df546 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -35,7 +35,7 @@ jobs: strategy: matrix: java: [ 11, 17 ] - kubernetes: [ 'v1.25.14', 'v1.26.9', 'v1.27.6', 'v1.28.2', 'v1.29.0' ] + kubernetes: [ 'v1.26.13', 'v1.27.10', 'v1.28.6', 'v1.29.1' ] uses: ./.github/workflows/integration-tests.yml with: java-version: ${{ matrix.java }} From ff0493c8387642d8b5f6d841d29e22156731ce32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 08:37:48 +0100 Subject: [PATCH 137/644] chore(deps): bump org.assertj:assertj-core from 3.25.2 to 3.25.3 (#2232) Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.25.2 to 3.25.3. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.25.2...assertj-build-3.25.3) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 302d0d337e..7910b43abe 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ 3.14.0 0.21.0 1.13.0 - 3.25.2 + 3.25.3 4.2.0 2.7.3 1.12.2 From 4f70aa99f5be80eef5259abbd5b910a4aa3c731f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 5 Feb 2024 10:03:17 +0100 Subject: [PATCH 138/644] feat: logging of conflic errors (#2230) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../processing/event/EventProcessor.java | 35 ++++++++++++++++++- .../event/ReconciliationDispatcher.java | 1 - 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java index 14c7cf6d1e..e94f5f3a7e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java @@ -1,5 +1,6 @@ package io.javaoperatorsdk.operator.processing.event; +import java.net.HttpURLConnection; import java.time.Duration; import java.util.HashMap; import java.util.Map; @@ -10,6 +11,7 @@ import org.slf4j.LoggerFactory; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.client.KubernetesClientException; import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.api.config.ConfigurationService; import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; @@ -224,6 +226,7 @@ synchronized void eventProcessingFinished( postExecutionControl); unsetUnderExecution(resourceID); + logErrorIfNoRetryConfigured(executionScope, postExecutionControl); // If a delete event present at this phase, it was received during reconciliation. // So we either removed the finalizer during reconciliation or we don't use finalizers. // Either way we don't want to retry. @@ -261,6 +264,17 @@ synchronized void eventProcessingFinished( } } + /** + * In case retry is configured more complex error logging takes place, see handleRetryOnException + */ + private void logErrorIfNoRetryConfigured(ExecutionScope

executionScope, + PostExecutionControl

postExecutionControl) { + if (!isRetryConfigured() && postExecutionControl.exceptionDuringExecution()) { + log.error("Error during event processing {}", executionScope, + postExecutionControl.getRuntimeException().orElseThrow()); + } + } + private void reScheduleExecutionIfInstructed( PostExecutionControl

postExecutionControl, P customResource) { @@ -302,6 +316,7 @@ private void handleRetryOnException( boolean eventPresent = state.eventPresent(); state.markEventReceived(); + retryAwareErrorLogging(state.getRetry(), eventPresent, exception, executionScope); if (eventPresent) { log.debug("New events exists for for resource id: {}", resourceID); submitReconciliationExecution(state); @@ -319,11 +334,29 @@ private void handleRetryOnException( retryEventSource().scheduleOnce(resourceID, delay); }, () -> { - log.error("Exhausted retries for {}", executionScope); + log.error("Exhausted retries for scope {}.", executionScope); scheduleExecutionForMaxReconciliationInterval(executionScope.getResource()); }); } + private void retryAwareErrorLogging(RetryExecution retry, boolean eventPresent, + Exception exception, + ExecutionScope

executionScope) { + if (!eventPresent && !retry.isLastAttempt() && exception instanceof KubernetesClientException) { + KubernetesClientException ex = (KubernetesClientException) exception; + if (ex.getCode() == HttpURLConnection.HTTP_CONFLICT) { + log.debug("Full client conflict error during event processing {}", executionScope, + exception); + log.warn( + "Resource Kubernetes Resource Creator/Update Conflict during reconciliation. Message: {} Resource name: {}", + ex.getMessage(), ex.getFullResourceName()); + return; + } + } + log.error("Error during event processing {}", executionScope, + exception); + } + private void cleanupOnSuccessfulExecution(ExecutionScope

executionScope) { log.debug( "Cleanup for successful execution for resource: {}", getName(executionScope.getResource())); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java index 9a110a7ba8..a03ab8b399 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java @@ -63,7 +63,6 @@ public PostExecutionControl

handleExecution(ExecutionScope

executionScope) try { return handleDispatch(executionScope); } catch (Exception e) { - log.error("Error during event processing {} failed.", executionScope, e); return PostExecutionControl.exceptionDuringExecution(e); } } From 515589a37eaac85f2b0014a53a805462b472e54c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 6 Feb 2024 10:56:05 +0100 Subject: [PATCH 139/644] docs: improve read-only dependent (#2234) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros Signed-off-by: Chris Laprun Co-authored-by: Chris Laprun --- docs/documentation/dependent-resources.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/documentation/dependent-resources.md b/docs/documentation/dependent-resources.md index 7678e997e6..61e18fd3f2 100644 --- a/docs/documentation/dependent-resources.md +++ b/docs/documentation/dependent-resources.md @@ -370,7 +370,13 @@ server. To bypass the matching feature completely, simply override the `match` m return `false`, thus telling JOSDK that the actual state never matches the desired one, making it always update the resources using SSA. -WARNING: Older versions of Kubernetes before 1.25 would create an additional resource version for every SSA update performed with certain resources - even though there were no actual changes in the stored resource - leading to infinite reconciliations. This behavior was seen with Secrets using `stringData`, Ingresses using empty string fields, and StatefulSets using volume claim templates. The operator framework has added built-in handling for the StatefulSet issue. If you encounter this issue on an older Kubernetes version, consider changing your desired state, turning off SSA for that resource, or even upgrading your Kubernetes version. If you encounter it on a newer Kubernetes version, please log an issue with the JOSDK and with upstream Kubernetes. +WARNING: Older versions of Kubernetes before 1.25 would create an additional resource version for every SSA update +performed with certain resources - even though there were no actual changes in the stored resource - leading to infinite +reconciliations. This behavior was seen with Secrets using `stringData`, Ingresses using empty string fields, and +StatefulSets using volume claim templates. The operator framework has added built-in handling for the StatefulSet issue. +If you encounter this issue on an older Kubernetes version, consider changing your desired state, turning off SSA for +that resource, or even upgrading your Kubernetes version. If you encounter it on a newer Kubernetes version, please log +an issue with the JOSDK and with upstream Kubernetes. ## Telling JOSDK how to find which secondary resources are associated with a given primary resource @@ -544,5 +550,7 @@ several benefits: - if dependents are already used in a controller, it makes sense to unify the handling of all secondary resources as dependents from a code organization perspective - dependent resources can also interact with the workflow feature, thus allowing the read-only - resource to participate in conditions, in particular to decide whether or not the primary - resource needs/can be reconciled using reconcile pre-conditions \ No newline at end of file + resource to participate in conditions, in particular to decide whether the primary + resource needs/can be reconciled using reconcile pre-conditions, block the progression of the workflow altogether with + ready post-conditions or have other dependents depend on them, in essence, read-only dependents can participate in + workflows just as any other dependents. \ No newline at end of file From 3c080a00f3de5be7dceda779fc8c4eddeed7294c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 6 Feb 2024 12:18:30 +0100 Subject: [PATCH 140/644] fix: multiple dependents of same type exceptions (#2226) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros Signed-off-by: Chris Laprun Co-authored-by: Chris Laprun --- .../dependent/workflow/WorkflowResult.java | 20 +++++- .../workflow/WorkflowResultTest.java | 65 +++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResultTest.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResult.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResult.java index ba9e0f5755..77fc2dcbfe 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResult.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResult.java @@ -1,8 +1,8 @@ package io.javaoperatorsdk.operator.processing.dependent.workflow; +import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; -import java.util.stream.Collectors; import io.javaoperatorsdk.operator.AggregatedOperatorException; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; @@ -10,6 +10,7 @@ @SuppressWarnings("rawtypes") class WorkflowResult { + private static final String NUMBER_DELIMITER = "_"; private final Map erroredDependents; WorkflowResult(Map erroredDependents) { @@ -36,9 +37,22 @@ public boolean erroredDependentsExist() { public void throwAggregateExceptionIfErrorsPresent() { if (erroredDependentsExist()) { + Map exceptionMap = new HashMap<>(); + Map numberOfClasses = new HashMap<>(); + + for (Entry entry : erroredDependents.entrySet()) { + String name = entry.getKey().getClass().getName(); + var num = numberOfClasses.getOrDefault(name, 0); + if (num > 0) { + exceptionMap.put(name + NUMBER_DELIMITER + num, entry.getValue()); + } else { + exceptionMap.put(name, entry.getValue()); + } + numberOfClasses.put(name, num + 1); + } + throw new AggregatedOperatorException("Exception(s) during workflow execution.", - erroredDependents.entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey().getClass().getName(), Entry::getValue))); + exceptionMap); } } } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResultTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResultTest.java new file mode 100644 index 0000000000..48cf3fa75a --- /dev/null +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/WorkflowResultTest.java @@ -0,0 +1,65 @@ +package io.javaoperatorsdk.operator.processing.dependent.workflow; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.AggregatedOperatorException; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult; + +import static org.assertj.core.api.Assertions.assertThat; + +class WorkflowResultTest { + + @Test + void throwsExceptionWithoutNumberingIfAllDifferentClass() { + var res = new WorkflowResult(Map.of(new DependentA(), new RuntimeException(), + new DependentB(), new RuntimeException())); + try { + res.throwAggregateExceptionIfErrorsPresent(); + } catch (AggregatedOperatorException e) { + assertThat(e.getAggregatedExceptions()).containsOnlyKeys(DependentA.class.getName(), + DependentB.class.getName()); + } + } + + @Test + void numbersDependentClassNamesIfMoreOfSameType() { + var res = new WorkflowResult(Map.of(new DependentA(), new RuntimeException(), + new DependentA(), new RuntimeException())); + try { + res.throwAggregateExceptionIfErrorsPresent(); + } catch (AggregatedOperatorException e) { + assertThat(e.getAggregatedExceptions()).hasSize(2); + } + } + + @SuppressWarnings("rawtypes") + static class DependentA implements DependentResource { + @Override + public ReconcileResult reconcile(HasMetadata primary, Context context) { + return null; + } + + @Override + public Class resourceType() { + return null; + } + } + + @SuppressWarnings("rawtypes") + static class DependentB implements DependentResource { + @Override + public ReconcileResult reconcile(HasMetadata primary, Context context) { + return null; + } + + @Override + public Class resourceType() { + return null; + } + } +} From 32b8b926c36fa1272d269807fd3d33bc2cfa55b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 6 Feb 2024 12:19:20 +0100 Subject: [PATCH 141/644] feat: different reconciler same type (#2229) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros Signed-off-by: Chris Laprun Co-authored-by: Chris Laprun --- .../operator/ControllerManager.java | 21 +++---- .../operator/ControllerManagerTest.java | 58 ++++++------------ .../sample/simple/DuplicateCRController.java | 16 ----- .../MultipleReconcilerSameTypeIT.java | 61 +++++++++++++++++++ ...tipleReconcilerSameTypeCustomResource.java | 15 +++++ ...MultipleReconcilerSameTypeReconciler1.java | 29 +++++++++ ...MultipleReconcilerSameTypeReconciler2.java | 32 ++++++++++ .../MultipleReconcilerSameTypeStatus.java | 14 +++++ 8 files changed, 177 insertions(+), 69 deletions(-) delete mode 100644 operator-framework-core/src/test/java/io/javaoperatorsdk/operator/sample/simple/DuplicateCRController.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleReconcilerSameTypeIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeReconciler1.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeReconciler2.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeStatus.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ControllerManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ControllerManager.java index 5504e543f5..e90070d3c2 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ControllerManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ControllerManager.java @@ -17,6 +17,8 @@ */ class ControllerManager { + public static final String CANNOT_REGISTER_MULTIPLE_CONTROLLERS_WITH_SAME_NAME_MESSAGE = + "Cannot register multiple controllers with same name: "; private static final Logger log = LoggerFactory.getLogger(ControllerManager.class); @SuppressWarnings("rawtypes") @@ -62,25 +64,20 @@ public synchronized void startEventProcessing() { }, c -> "Event processor starter for: " + c.getConfiguration().getName()); } - @SuppressWarnings({"unchecked", "rawtypes"}) + @SuppressWarnings("rawtypes") synchronized void add(Controller controller) { final var configuration = controller.getConfiguration(); - final var resourceTypeName = ReconcilerUtils - .getResourceTypeNameWithVersion(configuration.getResourceClass()); - final var existing = controllers.get(resourceTypeName); - if (existing != null) { - throw new OperatorException("Cannot register controller '" + configuration.getName() - + "': another controller named '" + existing.getConfiguration().getName() - + "' is already registered for resource '" + resourceTypeName + "'"); + final var name = configuration.getName(); + if (controllers.containsKey(name)) { + throw new OperatorException( + CANNOT_REGISTER_MULTIPLE_CONTROLLERS_WITH_SAME_NAME_MESSAGE + name); } - controllers.put(resourceTypeName, controller); + controllers.put(name, controller); } @SuppressWarnings("rawtypes") synchronized Optional get(String name) { - return controllers().stream() - .filter(c -> name.equals(c.getConfiguration().getName())) - .findFirst(); + return Optional.ofNullable(controllers.get(name)); } @SuppressWarnings("rawtypes") diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ControllerManagerTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ControllerManagerTest.java index 7b80aeed8b..c8c4cb5008 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ControllerManagerTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/ControllerManagerTest.java @@ -8,66 +8,42 @@ import io.javaoperatorsdk.operator.api.config.ResolvedControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.processing.Controller; -import io.javaoperatorsdk.operator.sample.simple.DuplicateCRController; import io.javaoperatorsdk.operator.sample.simple.TestCustomReconciler; -import io.javaoperatorsdk.operator.sample.simple.TestCustomReconcilerOtherV1; import io.javaoperatorsdk.operator.sample.simple.TestCustomResource; -import io.javaoperatorsdk.operator.sample.simple.TestCustomResourceOtherV1; +import static io.javaoperatorsdk.operator.ControllerManager.CANNOT_REGISTER_MULTIPLE_CONTROLLERS_WITH_SAME_NAME_MESSAGE; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; class ControllerManagerTest { @Test - void shouldNotAddMultipleControllersForSameCustomResource() { - final var registered = new TestControllerConfiguration<>(new TestCustomReconciler(null), - TestCustomResource.class); - final var duplicated = - new TestControllerConfiguration<>(new DuplicateCRController(), TestCustomResource.class); - - checkException(registered, duplicated); - } - - @Test - void addingMultipleControllersForCustomResourcesWithSameVersionsShouldNotWork() { - final var registered = new TestControllerConfiguration<>(new TestCustomReconciler(null), - TestCustomResource.class); - final var duplicated = new TestControllerConfiguration<>(new TestCustomReconcilerOtherV1(), - TestCustomResourceOtherV1.class); - - checkException(registered, duplicated); - } - - private void checkException( - TestControllerConfiguration registered, - TestControllerConfiguration duplicated) { - + void addingReconcilerWithSameNameShouldNotWork() { + final var controllerConfiguration = + new TestControllerConfiguration<>(new TestCustomReconciler(null), + TestCustomResource.class); + var controller = new Controller<>(controllerConfiguration.reconciler, controllerConfiguration, + MockKubernetesClient.client(controllerConfiguration.getResourceClass())); ConfigurationService configurationService = new BaseConfigurationService(); + final var controllerManager = + new ControllerManager(configurationService.getExecutorServiceManager()); + controllerManager.add(controller); - final var exception = assertThrows(OperatorException.class, () -> { - final var controllerManager = - new ControllerManager(configurationService.getExecutorServiceManager()); - controllerManager.add(new Controller<>(registered.controller, registered, - MockKubernetesClient.client(registered.getResourceClass()))); - controllerManager.add(new Controller<>(duplicated.controller, duplicated, - MockKubernetesClient.client(duplicated.getResourceClass()))); + var ex = assertThrows(OperatorException.class, () -> { + controllerManager.add(controller); }); - final var msg = exception.getMessage(); assertTrue( - msg.contains("Cannot register controller '" + duplicated.getName() + "'") - && msg.contains(registered.getName()) - && msg.contains(registered.getResourceTypeName())); + ex.getMessage().contains(CANNOT_REGISTER_MULTIPLE_CONTROLLERS_WITH_SAME_NAME_MESSAGE)); } private static class TestControllerConfiguration extends ResolvedControllerConfiguration { - private final Reconciler controller; + private final Reconciler reconciler; - public TestControllerConfiguration(Reconciler controller, Class crClass) { - super(crClass, getControllerName(controller), controller.getClass(), + public TestControllerConfiguration(Reconciler reconciler, Class crClass) { + super(crClass, getControllerName(reconciler), reconciler.getClass(), new BaseConfigurationService()); - this.controller = controller; + this.reconciler = reconciler; } static String getControllerName( diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/sample/simple/DuplicateCRController.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/sample/simple/DuplicateCRController.java deleted file mode 100644 index 6b5b6ab08d..0000000000 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/sample/simple/DuplicateCRController.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.javaoperatorsdk.operator.sample.simple; - -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; - -@ControllerConfiguration -public class DuplicateCRController implements Reconciler { - - @Override - public UpdateControl reconcile(TestCustomResource resource, - Context context) { - return UpdateControl.noUpdate(); - } -} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleReconcilerSameTypeIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleReconcilerSameTypeIT.java new file mode 100644 index 0000000000..b0be12bd91 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleReconcilerSameTypeIT.java @@ -0,0 +1,61 @@ +package io.javaoperatorsdk.operator; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.multiplereconcilersametype.MultipleReconcilerSameTypeCustomResource; +import io.javaoperatorsdk.operator.sample.multiplereconcilersametype.MultipleReconcilerSameTypeReconciler1; +import io.javaoperatorsdk.operator.sample.multiplereconcilersametype.MultipleReconcilerSameTypeReconciler2; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class MultipleReconcilerSameTypeIT { + + public static final String TEST_RESOURCE_1 = "test1"; + public static final String TEST_RESOURCE_2 = "test2"; + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withReconciler(MultipleReconcilerSameTypeReconciler1.class) + .withReconciler(MultipleReconcilerSameTypeReconciler2.class) + .build(); + + + @Test + void multipleReconcilersBasedOnLeaderElection() { + extension.create(testResource(TEST_RESOURCE_1, true)); + extension.create(testResource(TEST_RESOURCE_2, false)); + + + await().untilAsserted(() -> { + assertThat(extension.getReconcilerOfType(MultipleReconcilerSameTypeReconciler1.class) + .getNumberOfExecutions()).isEqualTo(1); + assertThat(extension.getReconcilerOfType(MultipleReconcilerSameTypeReconciler2.class) + .getNumberOfExecutions()).isEqualTo(1); + + var res1 = extension.get(MultipleReconcilerSameTypeCustomResource.class, TEST_RESOURCE_1); + var res2 = extension.get(MultipleReconcilerSameTypeCustomResource.class, TEST_RESOURCE_2); + assertThat(res1).isNotNull(); + assertThat(res2).isNotNull(); + assertThat(res1.getStatus().getReconciledBy()) + .isEqualTo(MultipleReconcilerSameTypeReconciler1.class.getSimpleName()); + assertThat(res2.getStatus().getReconciledBy()) + .isEqualTo(MultipleReconcilerSameTypeReconciler2.class.getSimpleName()); + }); + } + + MultipleReconcilerSameTypeCustomResource testResource(String name, boolean type1) { + var res = new MultipleReconcilerSameTypeCustomResource(); + res.setMetadata(new ObjectMetaBuilder() + .withName(name) + .build()); + if (type1) { + res.getMetadata().getLabels().put("reconciler", "1"); + } + return res; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeCustomResource.java new file mode 100644 index 0000000000..53c731e5e7 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeCustomResource.java @@ -0,0 +1,15 @@ +package io.javaoperatorsdk.operator.sample.multiplereconcilersametype; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("mrst") +public class MultipleReconcilerSameTypeCustomResource + extends CustomResource + implements Namespaced { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeReconciler1.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeReconciler1.java new file mode 100644 index 0000000000..e32a6ad7e2 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeReconciler1.java @@ -0,0 +1,29 @@ +package io.javaoperatorsdk.operator.sample.multiplereconcilersametype; + +import java.util.concurrent.atomic.AtomicInteger; + +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; + +@ControllerConfiguration(labelSelector = "reconciler = 1") +public class MultipleReconcilerSameTypeReconciler1 + implements Reconciler, TestExecutionInfoProvider { + + private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + + @Override + public UpdateControl reconcile( + MultipleReconcilerSameTypeCustomResource resource, + Context context) { + numberOfExecutions.addAndGet(1); + + resource.setStatus(new MultipleReconcilerSameTypeStatus()); + resource.getStatus().setReconciledBy(getClass().getSimpleName()); + return UpdateControl.patchStatus(resource); + } + + public int getNumberOfExecutions() { + return numberOfExecutions.get(); + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeReconciler2.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeReconciler2.java new file mode 100644 index 0000000000..73b082f3b0 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeReconciler2.java @@ -0,0 +1,32 @@ +package io.javaoperatorsdk.operator.sample.multiplereconcilersametype; + +import java.util.concurrent.atomic.AtomicInteger; + +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; +import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; + +@ControllerConfiguration(labelSelector = "reconciler != 1") +public class MultipleReconcilerSameTypeReconciler2 + implements Reconciler, TestExecutionInfoProvider { + + private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + + @Override + public UpdateControl reconcile( + MultipleReconcilerSameTypeCustomResource resource, + Context context) { + numberOfExecutions.addAndGet(1); + + resource.setStatus(new MultipleReconcilerSameTypeStatus()); + resource.getStatus().setReconciledBy(getClass().getSimpleName()); + return UpdateControl.patchStatus(resource); + } + + public int getNumberOfExecutions() { + return numberOfExecutions.get(); + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeStatus.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeStatus.java new file mode 100644 index 0000000000..9335d89752 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplereconcilersametype/MultipleReconcilerSameTypeStatus.java @@ -0,0 +1,14 @@ +package io.javaoperatorsdk.operator.sample.multiplereconcilersametype; + +public class MultipleReconcilerSameTypeStatus { + + private String reconciledBy; + + public String getReconciledBy() { + return reconciledBy; + } + + public void setReconciledBy(String reconciledBy) { + this.reconciledBy = reconciledBy; + } +} From 1cc1d2a19cc605627819f3b38e1c4457a5cc7627 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 6 Feb 2024 14:36:56 +0000 Subject: [PATCH 142/644] Set new SNAPSHOT version into pom files. --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 2ccc24e23d..09f0ba1023 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index dac6530fea..d2f5dbad49 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 5e2d38702e..e692171367 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index a1ff5a4c5d..df08a2220b 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index 00a502a6d2..48367effbe 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 152cd353e6..599a211beb 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index 25cd05b4c5..c5213a5cad 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 7910b43abe..e2797bcaac 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index e6d6893ab0..f60b446c8a 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index f4d65ccf01..faa3b897eb 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index a0553af8b4..1870f4f80a 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 6fb7bae9e1..24b9a1a676 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 2fba19290a..0c06724bb7 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.2-SNAPSHOT + 4.7.3-SNAPSHOT sample-webpage-operator From 69711cf346d75331a61616bcfe2fd7015c93434b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 07:48:23 +0100 Subject: [PATCH 143/644] chore(deps): bump io.micrometer:micrometer-core from 1.12.2 to 1.12.3 (#2239) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e2797bcaac..b7c69fa689 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 3.25.3 4.2.0 2.7.3 - 1.12.2 + 1.12.3 4.12.0 3.1.8 0.9.6 From 6cab68b53829befa4755742fe0155878f5964bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 21 Feb 2024 11:19:02 +0100 Subject: [PATCH 144/644] chore: self version to 4.8.1-SNAPSHOT (#2247) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 09f0ba1023..54eff9484f 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index d2f5dbad49..dcb293e86d 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index e692171367..0ecfd38d9c 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index df08a2220b..4367d104d2 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index 48367effbe..9f29d69e28 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 599a211beb..d7ca656556 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index c5213a5cad..e1cad88810 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index b7c69fa689..dbadd8187a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index f60b446c8a..1bca200332 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index faa3b897eb..c52faa9b08 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 1870f4f80a..e383d1e038 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 24b9a1a676..d42b6d04ac 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 0c06724bb7..37ed1d2ae6 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.7.3-SNAPSHOT + 4.8.1-SNAPSHOT sample-webpage-operator From 3c453059510fd444bf0cca0aa8932b65b9ee488e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 15:42:15 +0100 Subject: [PATCH 145/644] chore(deps): bump log4j.version from 2.22.1 to 2.23.0 (#2248) Bumps `log4j.version` from 2.22.1 to 2.23.0. Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.22.1 to 2.23.0 Updates `org.apache.logging.log4j:log4j-core` from 2.22.1 to 2.23.0 Updates `org.apache.logging.log4j:log4j2-core` from 2.22.1 to 2.23.0 --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-slf4j-impl dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.apache.logging.log4j:log4j2-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dbadd8187a..19b07908ee 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ 5.10.1 6.10.0 1.7.36 - 2.22.1 + 2.23.0 5.10.0 3.14.0 0.21.0 From 37eb90bffc777c2e15fa3d08c2489363b5a6cafe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 27 Feb 2024 15:42:38 +0100 Subject: [PATCH 146/644] chore: minikube 1.32.0 and target kubernetes version bump (#2244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/e2e-test.yml | 4 ++-- .github/workflows/integration-tests.yml | 2 +- .github/workflows/pr.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index be3732c42c..5e0a629bbc 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -32,8 +32,8 @@ jobs: - name: Setup Minikube-Kubernetes uses: manusa/actions-setup-minikube@v2.10.0 with: - minikube version: v1.31.2 - kubernetes version: v1.28.2 + minikube version: v1.32.0 + kubernetes version: v1.29.1 github token: ${{ secrets.GITHUB_TOKEN }} driver: docker diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index fbac44faa9..5d3fadc762 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -36,7 +36,7 @@ jobs: - name: Set up Minikube uses: manusa/actions-setup-minikube@v2.10.0 with: - minikube version: v1.31.2 + minikube version: v1.32.0 kubernetes version: ${{ inputs.kube-version }} driver: 'docker' github token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index e1116df546..8206b0d43a 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -48,7 +48,7 @@ jobs: uses: ./.github/workflows/integration-tests.yml with: java-version: 17 - kube-version: 'v1.28.2' + kube-version: 'v1.29.1' http-client: ${{ matrix.httpclient }} experimental: true From c47a551f0f34689268aa2c08392d17ce483c11ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 27 Feb 2024 16:17:26 +0100 Subject: [PATCH 147/644] improve: primary to secondary index edge case for dynamic mapper changes (#2246) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../informer/DefaultPrimaryToSecondaryIndex.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/DefaultPrimaryToSecondaryIndex.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/DefaultPrimaryToSecondaryIndex.java index 113deef767..a1a5a96d36 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/DefaultPrimaryToSecondaryIndex.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/DefaultPrimaryToSecondaryIndex.java @@ -33,9 +33,14 @@ public synchronized void onDelete(R resource) { primaryResources.forEach( primaryResource -> { var secondaryResources = index.get(primaryResource); - secondaryResources.remove(ResourceID.fromResource(resource)); - if (secondaryResources.isEmpty()) { - index.remove(primaryResource); + // this can be null in just very special cases, like when the secondaryToPrimaryMapper is + // changing dynamically. Like if a list of ResourceIDs mapped dynamically extended in the + // mapper between the onAddOrUpdate and onDelete is called. + if (secondaryResources != null) { + secondaryResources.remove(ResourceID.fromResource(resource)); + if (secondaryResources.isEmpty()) { + index.remove(primaryResource); + } } }); } From 6a46dae620658dbdf12835dbec4df34469a46e81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Feb 2024 08:35:57 +0100 Subject: [PATCH 148/644] chore(deps): bump com.google.cloud.tools:jib-maven-plugin (#2254) Bumps [com.google.cloud.tools:jib-maven-plugin](https://github.com/GoogleContainerTools/jib) from 3.4.0 to 3.4.1. - [Release notes](https://github.com/GoogleContainerTools/jib/releases) - [Commits](https://github.com/GoogleContainerTools/jib/commits) --- updated-dependencies: - dependency-name: com.google.cloud.tools:jib-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 1bca200332..648417c8fb 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -18,7 +18,7 @@ 11 11 - 3.4.0 + 3.4.1 diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index c52faa9b08..a9b43df1e1 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -18,7 +18,7 @@ 11 11 - 3.4.0 + 3.4.1 diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index d42b6d04ac..2311d22d57 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -18,7 +18,7 @@ 11 11 - 3.4.0 + 3.4.1 diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 37ed1d2ae6..4ba8eb8991 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -18,7 +18,7 @@ 11 11 - 3.4.0 + 3.4.1 From 6d24455a4ee181cb1994cc4a89d4cf08fcdcc34c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 08:42:14 +0100 Subject: [PATCH 149/644] chore(deps): bump org.mockito:mockito-core from 5.10.0 to 5.11.0 (#2258) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.10.0 to 5.11.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.10.0...v5.11.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 19b07908ee..1657201469 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 6.10.0 1.7.36 2.23.0 - 5.10.0 + 5.11.0 3.14.0 0.21.0 1.13.0 From 3a6e333ce3713de41ddd93d09ce96239f92c07ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 5 Mar 2024 08:28:13 +0100 Subject: [PATCH 150/644] improve: logging for tracing issues with events (#2260) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros Co-authored-by: Chris Laprun --- .../event/ReconciliationDispatcher.java | 23 +++++++++++-------- .../ControllerResourceEventSource.java | 11 ++++++--- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java index a03ab8b399..cd1d601487 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java @@ -285,11 +285,12 @@ private void updatePostExecutionControlWithReschedule( private PostExecutionControl

handleCleanup(P resource, Context

context) { - log.debug( - "Executing delete for resource: {} with version: {}", - getName(resource), - getVersion(resource)); - + if (log.isDebugEnabled()) { + log.debug( + "Executing delete for resource: {} with version: {}", + ResourceID.fromResource(resource), + getVersion(resource)); + } DeleteControl deleteControl = controller.cleanup(resource, context); final var useFinalizer = controller.useFinalizer(); if (useFinalizer) { @@ -345,7 +346,7 @@ ControllerConfiguration

configuration() { public P conflictRetryingUpdate(P resource, Function modificationFunction) { if (log.isDebugEnabled()) { - log.debug("Removing finalizer on resource: {}", ResourceID.fromResource(resource)); + log.debug("Conflict retrying update for: {}", ResourceID.fromResource(resource)); } int retryIndex = 0; while (true) { @@ -393,10 +394,12 @@ public R getResource(String namespace, String name) { } public R updateResource(R resource) { - log.debug( - "Trying to replace resource {}, version: {}", - getName(resource), - resource.getMetadata().getResourceVersion()); + if (log.isDebugEnabled()) { + log.debug( + "Trying to replace resource {}, version: {}", + ResourceID.fromResource(resource), + resource.getMetadata().getResourceVersion()); + } return resource(resource).lockResourceVersion(resource.getMetadata().getResourceVersion()) .update(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java index 5aa05f146c..c1ac2d3352 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java @@ -66,7 +66,12 @@ public synchronized void start() { public void eventReceived(ResourceAction action, T resource, T oldResource) { try { - log.debug("Event received for resource: {}", getName(resource)); + if (log.isDebugEnabled()) { + log.debug("Event received for resource: {} version: {} uuid: {} action: {}", + ResourceID.fromResource(resource), + getVersion(resource), resource.getMetadata().getUid(), action); + log.trace("Event Old resource: {},\n new resource: {}", oldResource, resource); + } MDCUtils.addResourceInfo(resource); controller.getEventSourceManager().broadcastOnResourceEvent(action, resource, oldResource); if ((legacyFilters == null || @@ -75,8 +80,8 @@ && isAcceptedByFilters(action, resource, oldResource)) { getEventHandler().handleEvent( new ResourceEvent(action, ResourceID.fromResource(resource), resource)); } else { - log.debug("Skipping event handling resource {} with version: {}", getUID(resource), - getVersion(resource)); + log.debug("Skipping event handling resource {}", + ResourceID.fromResource(resource)); } } finally { MDCUtils.removeResourceInfo(); From ed1aed5289b15d3bd14e8d21c5a57f91c99ea250 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 08:28:33 +0100 Subject: [PATCH 151/644] chore(deps): bump io.github.git-commit-id:git-commit-id-maven-plugin (#2261) Bumps [io.github.git-commit-id:git-commit-id-maven-plugin](https://github.com/git-commit-id/git-commit-id-maven-plugin) from 7.0.0 to 8.0.0. - [Release notes](https://github.com/git-commit-id/git-commit-id-maven-plugin/releases) - [Commits](https://github.com/git-commit-id/git-commit-id-maven-plugin/compare/v7.0.0...v8.0.0) --- updated-dependencies: - dependency-name: io.github.git-commit-id:git-commit-id-maven-plugin dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1657201469..c23fb0b3c6 100644 --- a/pom.xml +++ b/pom.xml @@ -73,7 +73,7 @@ 1.6.13 3.0.0 3.1.1 - 7.0.0 + 8.0.0 2.23.0 1.0 1.9.0 From b880791ed105b50a333257695fcade71f4c984d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Montalv=C3=A3o=20Marques?= <9379664+gonmmarques@users.noreply.github.com> Date: Tue, 5 Mar 2024 15:16:14 +0000 Subject: [PATCH 152/644] docs: fix small typos (#2264) --- docs/documentation/features.md | 4 ++-- docs/documentation/glossary.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/documentation/features.md b/docs/documentation/features.md index bce21a61aa..564b5233f5 100644 --- a/docs/documentation/features.md +++ b/docs/documentation/features.md @@ -461,7 +461,7 @@ reschedule reconciliations. There are few interesting points here: -The `CustomResourceEvenSource` event source is a special one, responsible for handling events +The `CustomResourceEventSource` event source is a special one, responsible for handling events pertaining to changes affecting our primary resources. This `EventSource` is always registered for every controller automatically by the SDK. It is important to note that events always relate to a given primary resource. Concurrency is still handled for you, even in the presence of @@ -493,7 +493,7 @@ related [method](https://github.com/java-operator-sdk/java-operator-sdk/blob/mai To register event sources, your `Reconciler` has to implement the [`EventSourceInitializer`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java) -interface and initiliaze a list of event sources to register. One way to see this in action is +interface and initialize a list of event sources to register. One way to see this in action is to look at the [tomcat example](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatReconciler.java) (irrelevant details omitted): diff --git a/docs/documentation/glossary.md b/docs/documentation/glossary.md index e0378d0746..6443774ce1 100644 --- a/docs/documentation/glossary.md +++ b/docs/documentation/glossary.md @@ -13,7 +13,7 @@ permalink: /docs/glossary - **Secondary Resource** - any resource that the controller needs to manage the reach the desired state represented by the primary resource. These resources can be created, updated, deleted or simply read depending on the use case. For example, the `Deployment` controller manages - `ReplicatSet` instances when trying to realize the state represented by the `Deployment`. In + `ReplicaSet` instances when trying to realize the state represented by the `Deployment`. In this scenario, the `Deployment` is the primary resource while `ReplicaSet` is one of the secondary resources managed by the `Deployment` controller. - **Dependent Resource** - a feature of JOSDK, to make it easier to manage secondary resources. A From dc0b4eebb44d30131bd51839421f210c05f22152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 7 Mar 2024 11:26:58 +0100 Subject: [PATCH 153/644] improve: lazy init workflow executor (#2266) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros Signed-off-by: Chris Laprun Co-authored-by: Chris Laprun --- .../api/config/ExecutorServiceManager.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ExecutorServiceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ExecutorServiceManager.java index 62f345426c..3ea05e7e0d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ExecutorServiceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ExecutorServiceManager.java @@ -29,6 +29,7 @@ public class ExecutorServiceManager { private ExecutorService workflowExecutor; private ExecutorService cachingExecutorService; private boolean started; + private ConfigurationService configurationService; ExecutorServiceManager(ConfigurationService configurationService) { start(configurationService); @@ -95,30 +96,38 @@ public ExecutorService reconcileExecutorService() { } public ExecutorService workflowExecutorService() { + lazyInitWorkflowExecutorService(); return workflowExecutor; } + private synchronized void lazyInitWorkflowExecutorService() { + if (workflowExecutor == null) { + workflowExecutor = + new InstrumentedExecutorService(configurationService.getWorkflowExecutorService()); + } + } + public ExecutorService cachingExecutorService() { return cachingExecutorService; } public void start(ConfigurationService configurationService) { if (!started) { + this.configurationService = configurationService; // used to lazy init workflow executor this.cachingExecutorService = Executors.newCachedThreadPool(); this.executor = new InstrumentedExecutorService(configurationService.getExecutorService()); - this.workflowExecutor = - new InstrumentedExecutorService(configurationService.getWorkflowExecutorService()); started = true; } } public void stop(Duration gracefulShutdownTimeout) { try { - var parallelExec = Executors.newFixedThreadPool(3); log.debug("Closing executor"); + var parallelExec = Executors.newFixedThreadPool(3); parallelExec.invokeAll(List.of(shutdown(executor, gracefulShutdownTimeout), shutdown(workflowExecutor, gracefulShutdownTimeout), shutdown(cachingExecutorService, gracefulShutdownTimeout))); + workflowExecutor = null; parallelExec.shutdownNow(); started = false; } catch (InterruptedException e) { @@ -130,6 +139,10 @@ public void stop(Duration gracefulShutdownTimeout) { private static Callable shutdown(ExecutorService executorService, Duration gracefulShutdownTimeout) { return () -> { + // workflow executor can be null + if (executorService == null) { + return null; + } executorService.shutdown(); if (!executorService.awaitTermination(gracefulShutdownTimeout.toMillis(), TimeUnit.MILLISECONDS)) { From ab7c01f982a3d34097e6b66716f0d2e8fa3897c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Sat, 9 Mar 2024 12:59:55 +0100 Subject: [PATCH 154/644] improve: use fixed thread pool explicitly (#2265) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../api/config/ConfigurationService.java | 32 ++++++++++++------- .../config/ConfigurationServiceOverrider.java | 8 +++++ .../api/config/ExecutorServiceManager.java | 10 ------ .../processing/event/EventProcessorTest.java | 1 - 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java index 53bfc75df9..92859421eb 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java @@ -4,6 +4,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.function.Consumer; import org.slf4j.Logger; @@ -24,8 +25,6 @@ import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; import io.javaoperatorsdk.operator.processing.dependent.workflow.ManagedWorkflowFactory; -import static io.javaoperatorsdk.operator.api.config.ExecutorServiceManager.newThreadPoolExecutor; - /** An interface from which to retrieve configuration information. */ public interface ConfigurationService { @@ -127,14 +126,18 @@ default boolean checkCRDAndValidateLocalModel() { return false; } - int DEFAULT_RECONCILIATION_THREADS_NUMBER = 200; + int DEFAULT_RECONCILIATION_THREADS_NUMBER = 50; + /** + * @deprecated Not used anymore in the default implementation + */ + @Deprecated(forRemoval = true) int MIN_DEFAULT_RECONCILIATION_THREADS_NUMBER = 10; /** - * The maximum number of threads the operator can spin out to dispatch reconciliation requests to - * reconcilers + * The number of threads the operator can spin out to dispatch reconciliation requests to + * reconcilers with the default executors * - * @return the maximum number of concurrent reconciliation threads + * @return the number of concurrent reconciliation threads */ default int concurrentReconciliationThreads() { return DEFAULT_RECONCILIATION_THREADS_NUMBER; @@ -143,17 +146,24 @@ default int concurrentReconciliationThreads() { /** * The minimum number of threads the operator starts in the thread pool for reconciliations. * + * @deprecated not used anymore by default executor implementation * @return the minimum number of concurrent reconciliation threads */ + @Deprecated(forRemoval = true) default int minConcurrentReconciliationThreads() { return MIN_DEFAULT_RECONCILIATION_THREADS_NUMBER; } int DEFAULT_WORKFLOW_EXECUTOR_THREAD_NUMBER = DEFAULT_RECONCILIATION_THREADS_NUMBER; + /** + * @deprecated Not used anymore in the default implementation + */ + @Deprecated(forRemoval = true) int MIN_DEFAULT_WORKFLOW_EXECUTOR_THREAD_NUMBER = MIN_DEFAULT_RECONCILIATION_THREADS_NUMBER; /** - * Retrieves the maximum number of threads the operator can spin out to be used in the workflows. + * Number of threads the operator can spin out to be used in the workflows with the default + * executor. * * @return the maximum number of concurrent workflow threads */ @@ -164,8 +174,10 @@ default int concurrentWorkflowExecutorThreads() { /** * The minimum number of threads the operator starts in the thread pool for workflows. * + * @deprecated not used anymore by default executor implementation * @return the minimum number of concurrent workflow threads */ + @Deprecated(forRemoval = true) default int minConcurrentWorkflowExecutorThreads() { return MIN_DEFAULT_WORKFLOW_EXECUTOR_THREAD_NUMBER; } @@ -191,13 +203,11 @@ default Metrics getMetrics() { } default ExecutorService getExecutorService() { - return newThreadPoolExecutor(minConcurrentReconciliationThreads(), - concurrentReconciliationThreads()); + return Executors.newFixedThreadPool(concurrentReconciliationThreads()); } default ExecutorService getWorkflowExecutorService() { - return newThreadPoolExecutor(minConcurrentWorkflowExecutorThreads(), - concurrentWorkflowExecutorThreads()); + return Executors.newFixedThreadPool(concurrentWorkflowExecutorThreads()); } default boolean closeClientOnStop() { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java index 5879383464..12a8a5c699 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java @@ -218,13 +218,21 @@ public int concurrentWorkflowExecutorThreads() { original.concurrentWorkflowExecutorThreads()); } + /** + * @deprecated Not used anymore in the default implementation + */ + @Deprecated(forRemoval = true) @Override public int minConcurrentReconciliationThreads() { return minConcurrentReconciliationThreads != null ? minConcurrentReconciliationThreads : original.minConcurrentReconciliationThreads(); } + /** + * @deprecated Not used anymore in the default implementation + */ @Override + @Deprecated(forRemoval = true) public int minConcurrentWorkflowExecutorThreads() { return minConcurrentWorkflowExecutorThreads != null ? minConcurrentWorkflowExecutorThreads : original.minConcurrentWorkflowExecutorThreads(); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ExecutorServiceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ExecutorServiceManager.java index 3ea05e7e0d..112ab7188a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ExecutorServiceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ExecutorServiceManager.java @@ -8,8 +8,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Function; @@ -35,14 +33,6 @@ public class ExecutorServiceManager { start(configurationService); } - public static ExecutorService newThreadPoolExecutor(int minThreads, int maxThreads) { - minThreads = Utils.ensureValid(minThreads, "minimum number of threads", MIN_THREAD_NUMBER); - maxThreads = Utils.ensureValid(maxThreads, "maximum number of threads", minThreads + 1); - - return new ThreadPoolExecutor(minThreads, maxThreads, 1, TimeUnit.MINUTES, - new LinkedBlockingDeque<>()); - } - /** * Uses cachingExecutorService from this manager. Use this only for tasks, that don't have dynamic * nature, in sense that won't grow with the number of inputs (thus kubernetes resources) diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventProcessorTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventProcessorTest.java index 9d538713c1..93e58a55c6 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventProcessorTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/EventProcessorTest.java @@ -434,7 +434,6 @@ void executionOfReconciliationShouldNotStartIfProcessorStopped() throws Interrup new BaseConfigurationService(), o -> { o.withConcurrentReconciliationThreads(1); - o.withMinConcurrentReconciliationThreads(1); }); eventProcessor = spy(new EventProcessor(controllerConfiguration(null, rateLimiterMock, configurationService), From 15ff8b54480545eac30726b56140c41224b2ad86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 08:34:23 +0100 Subject: [PATCH 155/644] chore(deps): bump log4j.version from 2.23.0 to 2.23.1 (#2276) Bumps `log4j.version` from 2.23.0 to 2.23.1. Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.23.0 to 2.23.1 Updates `org.apache.logging.log4j:log4j-core` from 2.23.0 to 2.23.1 Updates `org.apache.logging.log4j:log4j2-core` from 2.23.0 to 2.23.1 --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-slf4j-impl dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.logging.log4j:log4j2-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c23fb0b3c6..31e02083c1 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ 5.10.1 6.10.0 1.7.36 - 2.23.0 + 2.23.1 5.11.0 3.14.0 0.21.0 From 30cc18a1831a3a38760472d37dc7ae2af2a90119 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 08:35:10 +0100 Subject: [PATCH 156/644] chore(deps): bump io.github.git-commit-id:git-commit-id-maven-plugin (#2277) Bumps [io.github.git-commit-id:git-commit-id-maven-plugin](https://github.com/git-commit-id/git-commit-id-maven-plugin) from 8.0.0 to 8.0.1. - [Release notes](https://github.com/git-commit-id/git-commit-id-maven-plugin/releases) - [Commits](https://github.com/git-commit-id/git-commit-id-maven-plugin/compare/v8.0.0...v8.0.1) --- updated-dependencies: - dependency-name: io.github.git-commit-id:git-commit-id-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 31e02083c1..7a8e99abe6 100644 --- a/pom.xml +++ b/pom.xml @@ -73,7 +73,7 @@ 1.6.13 3.0.0 3.1.1 - 8.0.0 + 8.0.1 2.23.0 1.0 1.9.0 From e4495f846090f31a2e3ed70ada0239f09da53b4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 09:01:28 +0100 Subject: [PATCH 157/644] chore(deps): bump org.apache.maven.plugins:maven-gpg-plugin (#2282) Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.1.0 to 3.2.0. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.1.0...maven-gpg-plugin-3.2.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- operator-framework-bom/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 4367d104d2..a4fb8b6845 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -61,7 +61,7 @@ 1.6.13 - 3.1.0 + 3.2.0 3.3.0 3.6.3 diff --git a/pom.xml b/pom.xml index 7a8e99abe6..6e4f422692 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 3.3.0 3.3.0 3.3.2 - 3.1.0 + 3.2.0 1.6.13 3.0.0 3.1.1 From 7b2d07893b4d7294c2bddb4db67c4cfb73639076 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 09:01:51 +0100 Subject: [PATCH 158/644] chore(deps): bump io.micrometer:micrometer-core from 1.12.3 to 1.12.4 (#2281) Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.12.3 to 1.12.4. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.12.3...v1.12.4) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6e4f422692..7039cd6eed 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 3.25.3 4.2.0 2.7.3 - 1.12.3 + 1.12.4 4.12.0 3.1.8 0.9.6 From 0029b678b1b31c8d1519b372257a0062a1e1a4e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 12 Mar 2024 09:49:36 +0100 Subject: [PATCH 159/644] improve: remote stale check (#2283) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is already done by Openshift CI Signed-off-by: Attila Mészáros --- .github/workflows/stale-issues-and-prs.yml | 32 ---------------------- 1 file changed, 32 deletions(-) delete mode 100644 .github/workflows/stale-issues-and-prs.yml diff --git a/.github/workflows/stale-issues-and-prs.yml b/.github/workflows/stale-issues-and-prs.yml deleted file mode 100644 index db295a49b6..0000000000 --- a/.github/workflows/stale-issues-and-prs.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: 'Close stale issues and PRs' -on: - workflow_dispatch: - schedule: - - cron: '30 1 * * *' - -jobs: - stale: - runs-on: ubuntu-latest - steps: - - uses: actions/stale@v9 - with: - days-before-issue-stale: 60 - days-before-pr-stale: 60 - days-before-issue-close: 14 - days-before-pr-close: 14 - stale-issue-message: > - This issue is stale because it has been open 60 days with no activity. - Remove stale label or comment or this will be closed in 14 days. - close-issue-message: > - This issue was closed because it has been stalled for 14 days with no activity. - stale-pr-message: > - This PR is stale because it has been open 60 days with no activity. - Remove stale label or comment or this will be closed in 14 days. - close-pr-message: > - This PR was closed because it has been stalled for 10 days with no activity. - stale-issue-label: 'stale' - exempt-issue-labels: 'needs-discussion,help wanted,never stale,feature' - stale-pr-label: 'stale' - exempt-pr-labels: 'never stale' - operations-per-run: 500 - ascending: true \ No newline at end of file From 9674154516e891a5abc416a975b8ee6b6664fe9a Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Wed, 13 Mar 2024 12:10:09 +0100 Subject: [PATCH 160/644] fix: date parsing after 8.0.0 release of git-commit-id (#2286) Signed-off-by: Chris Laprun --- .../java/io/javaoperatorsdk/operator/api/config/Utils.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java index 19d8a73689..6971de6476 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java @@ -6,7 +6,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.text.SimpleDateFormat; import java.time.Instant; import java.util.Arrays; import java.util.Date; @@ -57,9 +56,7 @@ public static Version loadFromProperties() { try { String time = properties.getProperty("git.build.time"); if (time != null) { - builtTime = - // RFC 822 date is the default format used by git-commit-id-plugin - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(time); + builtTime = Date.from(Instant.parse(time)); } else { builtTime = Date.from(Instant.EPOCH); } From 9fa2b684cea5a1eb6947afabdcd0a9da5b0ae31e Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 13 Mar 2024 16:21:54 +0000 Subject: [PATCH 161/644] Set new SNAPSHOT version into pom files. --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 54eff9484f..203232a79f 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index dcb293e86d..b3b15ef3c0 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 0ecfd38d9c..9448f4fb34 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index a4fb8b6845..f5b6a7ff9f 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index 9f29d69e28..2f57cdfc88 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index d7ca656556..8e3baddfb9 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index e1cad88810..beabd00dce 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 7039cd6eed..48ff031200 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 648417c8fb..351d31a00c 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index a9b43df1e1..aa27625bd2 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index e383d1e038..62b8b6f8ed 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 2311d22d57..904d030974 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 4ba8eb8991..0dca7ed97e 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.1-SNAPSHOT + 4.8.2-SNAPSHOT sample-webpage-operator From 42334830944bb09c2d405c55f19859f4c6ed59d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 07:36:29 +0100 Subject: [PATCH 162/644] chore(deps): bump org.apache.maven.plugins:maven-gpg-plugin (#2294) Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.0 to 3.2.1. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.0...maven-gpg-plugin-3.2.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- operator-framework-bom/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index f5b6a7ff9f..64d4e47183 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -61,7 +61,7 @@ 1.6.13 - 3.2.0 + 3.2.1 3.3.0 3.6.3 diff --git a/pom.xml b/pom.xml index 48ff031200..ca6720593c 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 3.3.0 3.3.0 3.3.2 - 3.2.0 + 3.2.1 1.6.13 3.0.0 3.1.1 From 0b17878ca5497d97838faa0bb8754ca61b8bd414 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 08:16:47 +0100 Subject: [PATCH 163/644] chore(deps): bump io.github.git-commit-id:git-commit-id-maven-plugin (#2295) Bumps [io.github.git-commit-id:git-commit-id-maven-plugin](https://github.com/git-commit-id/git-commit-id-maven-plugin) from 8.0.1 to 8.0.2. - [Release notes](https://github.com/git-commit-id/git-commit-id-maven-plugin/releases) - [Commits](https://github.com/git-commit-id/git-commit-id-maven-plugin/compare/v8.0.1...v8.0.2) --- updated-dependencies: - dependency-name: io.github.git-commit-id:git-commit-id-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ca6720593c..7f72c869a0 100644 --- a/pom.xml +++ b/pom.xml @@ -73,7 +73,7 @@ 1.6.13 3.0.0 3.1.1 - 8.0.1 + 8.0.2 2.23.0 1.0 1.9.0 From 43b8591d96776e1c7c7ef815d5cb5fb2725ca8e0 Mon Sep 17 00:00:00 2001 From: Steven Hawkins Date: Mon, 25 Mar 2024 04:16:51 -0400 Subject: [PATCH 164/644] fix: ignore server managed fields for SSA matching (#2309) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Steven Hawkins Signed-off-by: Attila Mészáros --- ...BasedGenericKubernetesResourceMatcher.java | 48 ++++++++++--------- ...-managed-fields-additional-controller.yaml | 2 +- .../kubernetes/nginx-deployment.yaml | 1 + 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java index d699ff2822..bcfaa52d1a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java @@ -41,6 +41,10 @@ public class SSABasedGenericKubernetesResourceMatcher { public static final String APPLY_OPERATION = "Apply"; public static final String DOT_KEY = "."; + private static final List IGNORED_METADATA = + Arrays.asList("creationTimestamp", "deletionTimestamp", + "generation", "selfLink", "uid"); + @SuppressWarnings("unchecked") public static SSABasedGenericKubernetesResourceMatcher getInstance() { return INSTANCE; @@ -58,11 +62,10 @@ public static SSABasedGenericKubernetesResourceMatcher context) { - var optionalManagedFieldsEntry = - checkIfFieldManagerExists(actual, context.getControllerConfiguration().fieldManager()); + var optionalManagedFieldsEntry = checkIfFieldManagerExists(actual, + context.getControllerConfiguration().fieldManager()); // If no field is managed by our controller, that means the controller hasn't touched the // resource yet and the resource probably doesn't match the desired state. Not matching here // means that the resource will need to be updated and since this will be done using SSA, the @@ -86,7 +89,8 @@ public boolean matches(R actual, R desired, Context context) { var prunedActual = new HashMap(actualMap.size()); keepOnlyManagedFields(prunedActual, actualMap, - managedFieldsEntry.getFieldsV1().getAdditionalProperties(), objectMapper); + managedFieldsEntry.getFieldsV1().getAdditionalProperties(), + objectMapper); removeIrrelevantValues(desiredMap); @@ -110,9 +114,8 @@ private void sanitizeState(R actual, R desired, Map actualMap) { for (int i = 0; i < claims; i++) { if (desiredStatefulSet.getSpec().getVolumeClaimTemplates().get(i).getSpec() .getVolumeMode() == null) { - Optional - .ofNullable(GenericKubernetesResource.get(actualMap, "spec", "volumeClaimTemplates", - i, "spec")) + Optional.ofNullable( + GenericKubernetesResource.get(actualMap, "spec", "volumeClaimTemplates", i, "spec")) .map(Map.class::cast).ifPresent(m -> m.remove("volumeMode")); } if (desiredStatefulSet.getSpec().getVolumeClaimTemplates().get(i).getStatus() == null) { @@ -131,6 +134,7 @@ private static void removeIrrelevantValues(Map desiredMap) { var metadata = (Map) desiredMap.get(METADATA_KEY); metadata.remove(NAME_KEY); metadata.remove(NAMESPACE_KEY); + IGNORED_METADATA.forEach(metadata::remove); if (metadata.isEmpty()) { desiredMap.remove(METADATA_KEY); } @@ -163,7 +167,8 @@ private static void keepOnlyManagedFields(Map result, } else { // basically if we should traverse further fillResultsAndTraverseFurther(result, actualMap, managedFields, objectMapper, key, - keyInActual, managedFieldValue); + keyInActual, + managedFieldValue); } } else { // this should handle the case when the value is complex in the actual map (not just a @@ -181,8 +186,9 @@ private static void keepOnlyManagedFields(Map result, @SuppressWarnings("unchecked") private static void fillResultsAndTraverseFurther(Map result, - Map actualMap, Map managedFields, - KubernetesSerialization objectMapper, String key, String keyInActual, + Map actualMap, + Map managedFields, KubernetesSerialization objectMapper, String key, + String keyInActual, Object managedFieldValue) { var emptyMapValue = new HashMap(); result.put(keyInActual, emptyMapValue); @@ -223,8 +229,9 @@ private static void handleListKeyEntrySet(Map result, if (DOT_KEY.equals(listEntry.getKey())) { continue; } - var actualListEntry = selectListEntryBasedOnKey(keyWithoutPrefix(listEntry.getKey()), - actualValueList, objectMapper); + var actualListEntry = + selectListEntryBasedOnKey(keyWithoutPrefix(listEntry.getKey()), actualValueList, + objectMapper); targetValuesByIndex.put(actualListEntry.getKey(), actualListEntry.getValue()); managedEntryByIndex.put(actualListEntry.getKey(), (Map) listEntry.getValue()); } @@ -301,8 +308,7 @@ private static boolean isKeyPrefixedSkippingDotKey(Set @SuppressWarnings("unchecked") private static java.util.Map.Entry> selectListEntryBasedOnKey( String key, - List> values, - KubernetesSerialization objectMapper) { + List> values, KubernetesSerialization objectMapper) { Map ids = objectMapper.unmarshal(key, Map.class); List> possibleTargets = new ArrayList<>(1); int index = -1; @@ -314,9 +320,8 @@ private static java.util.Map.Entry> selectListEntry } } if (possibleTargets.isEmpty()) { - throw new IllegalStateException( - "Cannot find list element for key:" + key + ", in map: " - + values.stream().map(Map::keySet).collect(Collectors.toList())); + throw new IllegalStateException("Cannot find list element for key:" + key + ", in map: " + + values.stream().map(Map::keySet).collect(Collectors.toList())); } if (possibleTargets.size() > 1) { throw new IllegalStateException( @@ -327,7 +332,6 @@ private static java.util.Map.Entry> selectListEntry return new AbstractMap.SimpleEntry<>(finalIndex, possibleTargets.get(0)); } - private Optional checkIfFieldManagerExists(R actual, String fieldManager) { var targetManagedFields = actual.getMetadata().getManagedFields().stream() // Only the apply operations are interesting for us since those were created properly be SSA @@ -338,14 +342,14 @@ private Optional checkIfFieldManagerExists(R actual, String .collect(Collectors.toList()); if (targetManagedFields.isEmpty()) { log.debug("No field manager exists for resource {} with name: {} and operation Apply ", - actual.getKind(), actual.getMetadata().getName()); + actual.getKind(), + actual.getMetadata().getName()); return Optional.empty(); } // this should not happen in theory if (targetManagedFields.size() > 1) { - throw new OperatorException( - "More than one field manager exists with name: " + fieldManager + "in resource: " + - actual.getKind() + " with name: " + actual.getMetadata().getName()); + throw new OperatorException("More than one field manager exists with name: " + fieldManager + + "in resource: " + actual.getKind() + " with name: " + actual.getMetadata().getName()); } return Optional.of(targetManagedFields.get(0)); } diff --git a/operator-framework-core/src/test/resources/io/javaoperatorsdk/operator/processing/dependent/kubernetes/deployment-with-managed-fields-additional-controller.yaml b/operator-framework-core/src/test/resources/io/javaoperatorsdk/operator/processing/dependent/kubernetes/deployment-with-managed-fields-additional-controller.yaml index 5e0be88433..d82b5c8933 100644 --- a/operator-framework-core/src/test/resources/io/javaoperatorsdk/operator/processing/dependent/kubernetes/deployment-with-managed-fields-additional-controller.yaml +++ b/operator-framework-core/src/test/resources/io/javaoperatorsdk/operator/processing/dependent/kubernetes/deployment-with-managed-fields-additional-controller.yaml @@ -4,7 +4,7 @@ metadata: annotations: deployment.kubernetes.io/revision: "1" creationTimestamp: "2023-06-01T08:43:47Z" - generation: 1 + generation: 2 managedFields: - apiVersion: apps/v1 fieldsType: FieldsV1 diff --git a/operator-framework-core/src/test/resources/io/javaoperatorsdk/operator/processing/dependent/kubernetes/nginx-deployment.yaml b/operator-framework-core/src/test/resources/io/javaoperatorsdk/operator/processing/dependent/kubernetes/nginx-deployment.yaml index dcf90a8fc7..5478ac1747 100644 --- a/operator-framework-core/src/test/resources/io/javaoperatorsdk/operator/processing/dependent/kubernetes/nginx-deployment.yaml +++ b/operator-framework-core/src/test/resources/io/javaoperatorsdk/operator/processing/dependent/kubernetes/nginx-deployment.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: "test" + generation: 1 spec: progressDeadlineSeconds: 600 revisionHistoryLimit: 10 From 76931153a879fc3f18028f9e74b25be8e25cd540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 25 Mar 2024 22:05:24 +0100 Subject: [PATCH 165/644] chore: bump fabric8 to 6.11.0 (#2315) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7f72c869a0..9c264fd577 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ okhttp 5.10.1 - 6.10.0 + 6.11.0 1.7.36 2.23.1 5.11.0 From 19e6dfd8aad25d3623d5fa938fc8d7cf4e663fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 26 Mar 2024 08:53:50 +0100 Subject: [PATCH 166/644] improve: IT timeout (#2291) (#2316) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 5d3fadc762..d2240a8561 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -22,7 +22,7 @@ jobs: integration_tests: runs-on: ubuntu-latest continue-on-error: ${{ inputs.experimental }} - timeout-minutes: 20 + timeout-minutes: 40 steps: - name: Output test information run: echo "Running ITs with ${{ inputs.http-client }}, ${{ inputs.kube-version }}, ${{ inputs.java-version }}" From e5cb5b8c9042ea1289845fd5a0d5983d94c11eae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Mar 2024 08:47:08 +0100 Subject: [PATCH 167/644] chore(deps): bump org.apache.maven.plugins:maven-gpg-plugin (#2322) --- operator-framework-bom/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 64d4e47183..75a3829046 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -61,7 +61,7 @@ 1.6.13 - 3.2.1 + 3.2.2 3.3.0 3.6.3 diff --git a/pom.xml b/pom.xml index 9c264fd577..3091ddfd75 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 3.3.0 3.3.0 3.3.2 - 3.2.1 + 3.2.2 1.6.13 3.0.0 3.1.1 From 3bfac638c390e085722f0a8a7b5d1c0aa64d8cf8 Mon Sep 17 00:00:00 2001 From: Steven Hawkins Date: Wed, 27 Mar 2024 09:45:12 -0400 Subject: [PATCH 168/644] fix: using tombstones to account for rapid deletion (#2317) closes: #2314 Signed-off-by: Steven Hawkins --- .../informer/ManagedInformerEventSource.java | 6 +- .../informer/TemporaryResourceCache.java | 94 +++++++++++++++---- .../informer/InformerEventSourceTest.java | 2 +- .../informer/TemporaryResourceCacheTest.java | 51 +++++++++- 4 files changed, 125 insertions(+), 28 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java index ec72da0529..7139395e76 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java @@ -51,17 +51,17 @@ protected ManagedInformerEventSource( @Override public void onAdd(R resource) { - temporaryResourceCache.onEvent(resource, false); + temporaryResourceCache.onAddOrUpdateEvent(resource); } @Override public void onUpdate(R oldObj, R newObj) { - temporaryResourceCache.onEvent(newObj, false); + temporaryResourceCache.onAddOrUpdateEvent(newObj); } @Override public void onDelete(R obj, boolean deletedFinalStateUnknown) { - temporaryResourceCache.onEvent(obj, deletedFinalStateUnknown); + temporaryResourceCache.onDeleteEvent(obj, deletedFinalStateUnknown); } protected InformerManager manager() { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java index fd9a8ad565..b905629e69 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCache.java @@ -1,10 +1,8 @@ package io.javaoperatorsdk.operator.processing.event.source.informer; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.slf4j.Logger; @@ -18,8 +16,8 @@ /** *

* Temporal cache is used to solve the problem for {@link KubernetesDependentResource} that is, when - * a create or update is executed the subsequent getResource opeeration might not return the - * up-to-date resource from informer cache, since it is not received yet by webhook. + * a create or update is executed the subsequent getResource operation might not return the + * up-to-date resource from informer cache, since it is not received yet. *

*

* The idea of the solution is, that since an update (for create is simpler) was done successfully, @@ -36,31 +34,78 @@ */ public class TemporaryResourceCache { + static class ExpirationCache { + private final LinkedHashMap cache; + private final int ttlMs; + + public ExpirationCache(int maxEntries, int ttlMs) { + this.ttlMs = ttlMs; + this.cache = new LinkedHashMap<>() { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > maxEntries; + } + }; + } + + public void add(K key) { + clean(); + cache.putIfAbsent(key, System.currentTimeMillis()); + } + + public boolean contains(K key) { + clean(); + return cache.get(key) != null; + } + + void clean() { + if (!cache.isEmpty()) { + long currentTimeMillis = System.currentTimeMillis(); + var iter = cache.entrySet().iterator(); + // the order will already be from oldest to newest, clean a fixed number of entries to + // amortize the cost amongst multiple calls + for (int i = 0; i < 10 && iter.hasNext(); i++) { + var entry = iter.next(); + if (currentTimeMillis - entry.getValue() > ttlMs) { + iter.remove(); + } + } + } + } + } + private static final Logger log = LoggerFactory.getLogger(TemporaryResourceCache.class); - private static final int MAX_RESOURCE_VERSIONS = 256; private final Map cache = new ConcurrentHashMap<>(); + + // keep up to the last million deletions for up to 10 minutes + private final ExpirationCache tombstones = new ExpirationCache<>(1000000, 1200000); private final ManagedInformerEventSource managedInformerEventSource; private final boolean parseResourceVersions; - private final Set knownResourceVersions; + private final ExpirationCache knownResourceVersions; public TemporaryResourceCache(ManagedInformerEventSource managedInformerEventSource, boolean parseResourceVersions) { this.managedInformerEventSource = managedInformerEventSource; this.parseResourceVersions = parseResourceVersions; if (parseResourceVersions) { - knownResourceVersions = Collections.newSetFromMap(new LinkedHashMap() { - @Override - protected boolean removeEldestEntry(java.util.Map.Entry eldest) { - return size() >= MAX_RESOURCE_VERSIONS; - } - }); + // keep up to the 50000 add/updates for up to 5 minutes + knownResourceVersions = new ExpirationCache<>(50000, 600000); } else { knownResourceVersions = null; } } - public synchronized void onEvent(T resource, boolean unknownState) { + public synchronized void onDeleteEvent(T resource, boolean unknownState) { + tombstones.add(resource.getMetadata().getUid()); + onEvent(resource, unknownState); + } + + public synchronized void onAddOrUpdateEvent(T resource) { + onEvent(resource, false); + } + + synchronized void onEvent(T resource, boolean unknownState) { cache.computeIfPresent(ResourceID.fromResource(resource), (id, cached) -> (unknownState || !isLaterResourceVersion(id, cached, resource)) ? null : cached); @@ -84,20 +129,33 @@ public synchronized void putResource(T newResource, String previousResourceVersi var cachedResource = getResourceFromCache(resourceId) .orElse(managedInformerEventSource.get(resourceId).orElse(null)); - if ((previousResourceVersion == null && cachedResource == null) + boolean moveAhead = false; + if (previousResourceVersion == null && cachedResource == null) { + if (tombstones.contains(newResource.getMetadata().getUid())) { + log.debug( + "Won't resurrect uid {} for resource id: {}", + newResource.getMetadata().getUid(), resourceId); + return; + } + // we can skip further checks as this is a simple add and there's no previous entry to + // consider + moveAhead = true; + } + + if (moveAhead || (cachedResource != null && (cachedResource.getMetadata().getResourceVersion().equals(previousResourceVersion)) || isLaterResourceVersion(resourceId, newResource, cachedResource))) { log.debug( "Temporarily moving ahead to target version {} for resource id: {}", newResource.getMetadata().getResourceVersion(), resourceId); - putToCache(newResource, resourceId); + cache.put(resourceId, newResource); } else if (cache.remove(resourceId) != null) { log.debug("Removed an obsolete resource from cache for id: {}", resourceId); } } - public boolean isKnownResourceVersion(T resource) { + public synchronized boolean isKnownResourceVersion(T resource) { return knownResourceVersions != null && knownResourceVersions.contains(resource.getMetadata().getResourceVersion()); } @@ -123,10 +181,6 @@ private boolean isLaterResourceVersion(ResourceID resourceId, T newResource, T c return false; } - private void putToCache(T resource, ResourceID resourceID) { - cache.put(resourceID == null ? ResourceID.fromResource(resource) : resourceID, resource); - } - public synchronized Optional getResourceFromCache(ResourceID resourceID) { return Optional.ofNullable(cache.get(resourceID)); } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java index ce3c52076d..5b8aac89e6 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java @@ -120,7 +120,7 @@ void propagateEventAndRemoveResourceFromTempCacheIfResourceVersionMismatch() { informerEventSource.onUpdate(cachedDeployment, testDeployment()); verify(eventHandlerMock, times(1)).handleEvent(any()); - verify(temporaryResourceCacheMock, times(1)).onEvent(testDeployment(), false); + verify(temporaryResourceCacheMock, times(1)).onAddOrUpdateEvent(testDeployment()); } @Test diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCacheTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCacheTest.java index d641736739..60eb7245a9 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCacheTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/TemporaryResourceCacheTest.java @@ -2,7 +2,9 @@ import java.util.Map; import java.util.Optional; +import java.util.concurrent.TimeUnit; +import org.awaitility.Awaitility; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -10,6 +12,7 @@ import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.informer.TemporaryResourceCache.ExpirationCache; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -81,7 +84,7 @@ void addOperationNotAddsTheResourceIfInformerCacheNotEmpty() { void removesResourceFromCache() { ConfigMap testResource = propagateTestResourceToCache(); - temporaryResourceCache.onEvent(testResource(), false); + temporaryResourceCache.onAddOrUpdateEvent(testResource()); assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource))) .isNotPresent(); @@ -96,20 +99,59 @@ void resourceVersionParsing() { ConfigMap testResource = propagateTestResourceToCache(); // an event with a newer version will not remove - temporaryResourceCache.onEvent(new ConfigMapBuilder(testResource).editMetadata() - .withResourceVersion("1").endMetadata().build(), false); + temporaryResourceCache.onAddOrUpdateEvent(new ConfigMapBuilder(testResource).editMetadata() + .withResourceVersion("1").endMetadata().build()); assertThat(temporaryResourceCache.isKnownResourceVersion(testResource)).isTrue(); assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource))) .isPresent(); // anything else will remove - temporaryResourceCache.onEvent(testResource(), false); + temporaryResourceCache.onAddOrUpdateEvent(testResource()); assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource))) .isNotPresent(); } + @Test + void rapidDeletion() { + var testResource = testResource(); + + temporaryResourceCache.onAddOrUpdateEvent(testResource); + temporaryResourceCache.onDeleteEvent(new ConfigMapBuilder(testResource).editMetadata() + .withResourceVersion("3").endMetadata().build(), false); + temporaryResourceCache.putAddedResource(testResource); + + assertThat(temporaryResourceCache.getResourceFromCache(ResourceID.fromResource(testResource))) + .isEmpty(); + } + + @Test + void expirationCacheMax() { + ExpirationCache cache = new ExpirationCache<>(2, Integer.MAX_VALUE); + + cache.add(1); + cache.add(2); + cache.add(3); + + assertThat(cache.contains(1)).isFalse(); + assertThat(cache.contains(2)).isTrue(); + assertThat(cache.contains(3)).isTrue(); + } + + @Test + void expirationCacheTtl() { + ExpirationCache cache = new ExpirationCache<>(2, 1); + + cache.add(1); + cache.add(2); + + Awaitility.await().atMost(1, TimeUnit.SECONDS).untilAsserted(() -> { + assertThat(cache.contains(1)).isFalse(); + assertThat(cache.contains(2)).isFalse(); + }); + } + private ConfigMap propagateTestResourceToCache() { var testResource = testResource(); when(informerEventSource.get(any())).thenReturn(Optional.empty()); @@ -127,6 +169,7 @@ ConfigMap testResource() { configMap.getMetadata().setName("test"); configMap.getMetadata().setNamespace("default"); configMap.getMetadata().setResourceVersion(RESOURCE_VERSION); + configMap.getMetadata().setUid("test-uid"); return configMap; } From 9ad344341b591e2cb98ff8e075f375f154f16549 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 27 Mar 2024 14:37:07 +0000 Subject: [PATCH 169/644] Set new SNAPSHOT version into pom files. --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 203232a79f..f9a46ae943 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index b3b15ef3c0..6f21000dc6 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 9448f4fb34..3d52fe0997 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 75a3829046..638a16314e 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index 2f57cdfc88..84ada8f79f 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 8e3baddfb9..2036680ba8 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index beabd00dce..5e5bb07ff3 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 3091ddfd75..4de8fdaa43 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 351d31a00c..32eff201c7 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index aa27625bd2..ae63cf3847 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 62b8b6f8ed..43120eb74d 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 904d030974..9616b6ac92 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 0dca7ed97e..7f977d68a6 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.2-SNAPSHOT + 4.8.3-SNAPSHOT sample-webpage-operator From 830f29d86346e5b576beba1e5c2a12daf6d977f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Mar 2024 09:35:47 +0100 Subject: [PATCH 170/644] chore(deps): bump commons-io:commons-io from 2.15.1 to 2.16.0 (#2324) Bumps commons-io:commons-io from 2.15.1 to 2.16.0. --- updated-dependencies: - dependency-name: commons-io:commons-io dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bootstrapper-maven-plugin/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index f9a46ae943..48d170d082 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -58,7 +58,7 @@ commons-io commons-io - 2.15.1 + 2.16.0 com.github.spullara.mustache.java diff --git a/pom.xml b/pom.xml index 4de8fdaa43..32f462f827 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 3.1.8 0.9.6 0.9.11 - 2.15.1 + 2.16.0 2.11 3.12.1 From 6a6ce38331c23062292cc4ace69a59b9620f558f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 09:27:32 +0200 Subject: [PATCH 171/644] chore(deps): bump com.google.cloud.tools:jib-maven-plugin (#2327) Bumps [com.google.cloud.tools:jib-maven-plugin](https://github.com/GoogleContainerTools/jib) from 3.4.1 to 3.4.2. - [Release notes](https://github.com/GoogleContainerTools/jib/releases) - [Commits](https://github.com/GoogleContainerTools/jib/commits) --- updated-dependencies: - dependency-name: com.google.cloud.tools:jib-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 32eff201c7..c1b8d4cb5d 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -18,7 +18,7 @@ 11 11 - 3.4.1 + 3.4.2 diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index ae63cf3847..eca48e5b2c 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -18,7 +18,7 @@ 11 11 - 3.4.1 + 3.4.2 diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 9616b6ac92..b2bc3e5fe3 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -18,7 +18,7 @@ 11 11 - 3.4.1 + 3.4.2 diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 7f977d68a6..5befc0d8a7 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -18,7 +18,7 @@ 11 11 - 3.4.1 + 3.4.2 From 4458c531e3d3b96ec3500d737169dfaf53b10b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 3 Apr 2024 13:22:14 +0200 Subject: [PATCH 172/644] fix: processor concurrency issue on startup (#2328) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --------- Signed-off-by: Attila Mészáros --- .../operator/processing/event/EventProcessor.java | 4 +++- .../processing/event/ReconciliationDispatcher.java | 3 ++- .../operator/processing/event/ResourceState.java | 11 +++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java index e94f5f3a7e..f5d7d5ba83 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java @@ -400,7 +400,8 @@ public synchronized void stop() { } @Override - public void start() throws OperatorException { + public synchronized void start() throws OperatorException { + log.debug("Starting event processor: {}", this); // on restart new executor service is created and needs to be set here executor = controllerConfiguration.getConfigurationService().getExecutorServiceManager() .reconcileExecutorService(); @@ -410,6 +411,7 @@ public void start() throws OperatorException { private void handleAlreadyMarkedEvents() { for (var state : resourceStateManager.resourcesWithEventPresent()) { + log.debug("Handling already marked event on start. State: {}", state); handleMarkedEventForResource(state); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java index cd1d601487..ed3eb38521 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java @@ -71,7 +71,8 @@ private PostExecutionControl

handleDispatch(ExecutionScope

executionScope) throws Exception { P originalResource = executionScope.getResource(); var resourceForExecution = cloneResource(originalResource); - log.debug("Handling dispatch for resource {}", getName(originalResource)); + log.debug("Handling dispatch for resource name: {} namespace: {}", getName(originalResource), + originalResource.getMetadata().getNamespace()); final var markedForDeletion = originalResource.isMarkedForDeletion(); if (markedForDeletion && shouldNotDispatchToCleanupWhenMarkedForDeletion(originalResource)) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceState.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceState.java index 4c3eedf827..d52c1b19ec 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceState.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceState.java @@ -111,4 +111,15 @@ public void unMarkEventReceived() { break; } } + + @Override + public String toString() { + return "ResourceState{" + + "id=" + id + + ", underProcessing=" + underProcessing + + ", retry=" + retry + + ", eventing=" + eventing + + ", rateLimit=" + rateLimit + + '}'; + } } From bf701ad69614ec20037fc884877701806dd160b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 08:03:20 +0200 Subject: [PATCH 173/644] chore(deps): bump org.apache.maven.plugins:maven-plugin-plugin (#2333) --- bootstrapper-maven-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 48d170d082..fc8e7af196 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -17,7 +17,7 @@ 3.11.0 3.9.6 3.0.0 - 3.11.0 + 3.12.0 From e9ce2ee0c3ddd9c65e855db32c63d1aad197cde3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 09:04:00 +0200 Subject: [PATCH 174/644] chore(deps): bump org.apache.maven.plugin-tools:maven-plugin-annotations (#2332) Bumps [org.apache.maven.plugin-tools:maven-plugin-annotations](https://github.com/apache/maven-plugin-tools) from 3.11.0 to 3.12.0. - [Release notes](https://github.com/apache/maven-plugin-tools/releases) - [Commits](https://github.com/apache/maven-plugin-tools/compare/maven-plugin-tools-3.11.0...maven-plugin-tools-3.12.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugin-tools:maven-plugin-annotations dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bootstrapper-maven-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index fc8e7af196..f504b1857d 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -14,7 +14,7 @@ Operator SDK - Bootstrapper Maven Plugin - 3.11.0 + 3.12.0 3.9.6 3.0.0 3.12.0 From 3f442a198b48e9afb6dca9f45c4620ec3925aaf1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 08:49:59 +0200 Subject: [PATCH 175/644] chore(deps): bump org.apache.maven.plugins:maven-source-plugin (#2334) Bumps [org.apache.maven.plugins:maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.3.0 to 3.3.1. - [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.3.0...maven-source-plugin-3.3.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-source-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- operator-framework-bom/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 638a16314e..f6e905b02d 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -62,7 +62,7 @@ 1.6.13 3.2.2 - 3.3.0 + 3.3.1 3.6.3 diff --git a/pom.xml b/pom.xml index 32f462f827..2f31d46cb3 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ 3.2.5 3.6.3 3.3.1 - 3.3.0 + 3.3.1 3.3.0 3.3.2 3.2.2 From c0e81c04465cd4cb76f3d798a8f452c7769355d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 08:41:20 +0200 Subject: [PATCH 176/644] chore(deps): bump io.micrometer:micrometer-core from 1.12.4 to 1.12.5 (#2337) Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.12.4 to 1.12.5. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.12.4...v1.12.5) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2f31d46cb3..ad2c4dbdb8 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 3.25.3 4.2.0 2.7.3 - 1.12.4 + 1.12.5 4.12.0 3.1.8 0.9.6 From 494b48f17333d275985c71270af2847dc2b0a333 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 08:41:43 +0200 Subject: [PATCH 177/644] chore(deps): bump commons-io:commons-io from 2.16.0 to 2.16.1 (#2338) Bumps commons-io:commons-io from 2.16.0 to 2.16.1. --- updated-dependencies: - dependency-name: commons-io:commons-io dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bootstrapper-maven-plugin/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index f504b1857d..893f728315 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -58,7 +58,7 @@ commons-io commons-io - 2.16.0 + 2.16.1 com.github.spullara.mustache.java diff --git a/pom.xml b/pom.xml index ad2c4dbdb8..0191cbd367 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 3.1.8 0.9.6 0.9.11 - 2.16.0 + 2.16.1 2.11 3.12.1 From 9ac6b5c5d22d194754817fc0be28c2fb3762c678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 10 Apr 2024 16:46:47 +0200 Subject: [PATCH 178/644] feat: schedule fabric8 client snapshot build (#2243) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../fabric8-next-version-schedule.yml | 68 +++++++++++++++++++ .github/workflows/integration-tests.yml | 6 ++ 2 files changed, 74 insertions(+) create mode 100644 .github/workflows/fabric8-next-version-schedule.yml diff --git a/.github/workflows/fabric8-next-version-schedule.yml b/.github/workflows/fabric8-next-version-schedule.yml new file mode 100644 index 0000000000..e79374c74f --- /dev/null +++ b/.github/workflows/fabric8-next-version-schedule.yml @@ -0,0 +1,68 @@ +name: Verify Pull Request + +env: + MAVEN_ARGS: -V -ntp -e + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true +on: + schedule: + # Run on end of the day + - cron: '0 0 * * *' + workflow_dispatch: +jobs: + check_format_and_unit_tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: 'fabric8-next-version' + - name: Set up Java and Maven + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 17 + cache: 'maven' + - name: Run unit tests + run: ./mvnw ${MAVEN_ARGS} clean install --file pom.xml + + integration_tests: + strategy: + matrix: + java: [ 11, 17 ] + kubernetes: [ 'v1.26.13', 'v1.27.10', 'v1.28.6', 'v1.29.1' ] + uses: ./.github/workflows/integration-tests.yml + with: + java-version: ${{ matrix.java }} + kube-version: ${{ matrix.kubernetes }} + + httpclient-tests: + strategy: + matrix: + httpclient: [ 'vertx', 'jdk', 'jetty' ] + uses: ./.github/workflows/integration-tests.yml + with: + java-version: 17 + kube-version: 'v1.29.1' + http-client: ${{ matrix.httpclient }} + experimental: true + checkout-ref: 'fabric8-next-version' + + special_integration_tests: + runs-on: ubuntu-latest + strategy: + matrix: + java: [ 11, 17 ] + steps: + - uses: actions/checkout@v4 + with: + ref: 'fabric8-next-version' + - name: Set up Java and Maven + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: ${{ matrix.java }} + cache: 'maven' + - name: Run Special Integration Tests + run: ./mvnw ${MAVEN_ARGS} -B package -P minimal-watch-timeout-dependent-it --file pom.xml \ No newline at end of file diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index d2240a8561..79c77a6c98 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -17,6 +17,10 @@ on: type: boolean required: false default: false + checkout-ref: + type: string + required: false + default: '' jobs: integration_tests: @@ -27,6 +31,8 @@ jobs: - name: Output test information run: echo "Running ITs with ${{ inputs.http-client }}, ${{ inputs.kube-version }}, ${{ inputs.java-version }}" - uses: actions/checkout@v4 + with: + ref: ${{ inputs.checkout-ref }} - name: Set up Java and Maven uses: actions/setup-java@v4 with: From 762292a5e36a3205dff225bfac8d2b55959efd5f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Apr 2024 09:18:03 +0200 Subject: [PATCH 179/644] chore(deps): bump org.apache.maven.plugins:maven-gpg-plugin (#2342) Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.2 to 3.2.3. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.2...maven-gpg-plugin-3.2.3) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- operator-framework-bom/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index f6e905b02d..184a9a58bf 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -61,7 +61,7 @@ 1.6.13 - 3.2.2 + 3.2.3 3.3.1 3.6.3 diff --git a/pom.xml b/pom.xml index 0191cbd367..7f29ad9858 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 3.3.1 3.3.0 3.3.2 - 3.2.2 + 3.2.3 1.6.13 3.0.0 3.1.1 From 6daf2dc828c8a27a94fe26adc72a4f6518e74eaa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 08:37:49 +0200 Subject: [PATCH 180/644] chore(deps): bump org.apache.maven.plugins:maven-jar-plugin (#2348) Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/apache/maven-jar-plugin/releases) - [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.3.0...maven-jar-plugin-3.4.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-jar-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7f29ad9858..17e91a3516 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ 3.6.3 3.3.1 3.3.1 - 3.3.0 + 3.4.0 3.3.2 3.2.3 1.6.13 From 90ea84e31623a5c74decdc9d94a5a364da09287f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 15 Apr 2024 13:10:57 +0200 Subject: [PATCH 181/644] fix: change namespace starts processor on namespace change even if not leader (#2344) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../operator/processing/Controller.java | 14 ++- .../processing/event/EventProcessor.java | 4 + .../LeaderElectionChangeNamespaceIT.java | 98 +++++++++++++++++++ ...ElectionChangeNamespaceCustomResource.java | 15 +++ ...aderElectionChangeNamespaceReconciler.java | 29 ++++++ 5 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/LeaderElectionChangeNamespaceIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/leaderelectionchangenamespace/LeaderElectionChangeNamespaceCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/leaderelectionchangenamespace/LeaderElectionChangeNamespaceReconciler.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java index 70069148c3..bc2d3f9eec 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java @@ -368,7 +368,7 @@ private void validateCRDWithLocalModelIfRequired(Class

resClass, String contr } } - public void changeNamespaces(Set namespaces) { + public synchronized void changeNamespaces(Set namespaces) { if (namespaces.contains(WATCH_CURRENT_NAMESPACE)) { throw new OperatorException("Unexpected value in target namespaces: " + namespaces); } @@ -376,9 +376,17 @@ public void changeNamespaces(Set namespaces) { throw new OperatorException( "Watching all namespaces, but additional specific namespace is present"); } - eventProcessor.stop(); + // if the processor was not running, for example because the controller + // was not leading in a HA setup, we don't want to stop and + // mainly start the processor on namespace change. + boolean eventProcessorWasRunning = eventProcessor.isRunning(); + if (eventProcessorWasRunning) { + eventProcessor.stop(); + } eventSourceManager.changeNamespaces(namespaces); - eventProcessor.start(); + if (eventProcessorWasRunning) { + eventProcessor.start(); + } } public synchronized void startEventProcessing() { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java index f5d7d5ba83..2809efde8a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java @@ -473,4 +473,8 @@ private String controllerName() { public synchronized boolean isUnderProcessing(ResourceID resourceID) { return isControllerUnderExecution(resourceStateManager.getOrCreate(resourceID)); } + + public synchronized boolean isRunning() { + return running; + } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/LeaderElectionChangeNamespaceIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/LeaderElectionChangeNamespaceIT.java new file mode 100644 index 0000000000..1a3a450b90 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/LeaderElectionChangeNamespaceIT.java @@ -0,0 +1,98 @@ +package io.javaoperatorsdk.operator; + +import java.time.Duration; +import java.time.ZonedDateTime; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.coordination.v1.Lease; +import io.fabric8.kubernetes.api.model.coordination.v1.LeaseSpecBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientBuilder; +import io.javaoperatorsdk.operator.api.config.LeaderElectionConfiguration; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.leaderelectionchangenamespace.LeaderElectionChangeNamespaceCustomResource; +import io.javaoperatorsdk.operator.sample.leaderelectionchangenamespace.LeaderElectionChangeNamespaceReconciler; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +public class LeaderElectionChangeNamespaceIT { + + public static final String LEASE_NAME = "nschangelease"; + + @RegisterExtension + LocallyRunOperatorExtension extension = + LocallyRunOperatorExtension.builder() + .withConfigurationService(o -> o.withLeaderElectionConfiguration( + new LeaderElectionConfiguration(LEASE_NAME))) + .withReconciler(new LeaderElectionChangeNamespaceReconciler()) + .build(); + + private static KubernetesClient client = new KubernetesClientBuilder().build(); + + @BeforeAll + static void createLeaseManually() { + client.resource(lease()).create(); + } + + @AfterAll + static void deleteLeaseManually() { + client.resource(lease()).delete(); + } + + @Test + @DisplayName("If operator is not a leader, namespace change should not start processor") + void noReconcileOnChangeNamespace() { + extension.create(testResource()); + + var reconciler = extension.getReconcilerOfType(LeaderElectionChangeNamespaceReconciler.class); + await().pollDelay(Duration.ofSeconds(1)) + .timeout(Duration.ofSeconds(3)) + .untilAsserted(() -> { + assertThat(reconciler.getNumberOfExecutions()).isEqualTo(0); + }); + + extension.getRegisteredControllerForReconcile(LeaderElectionChangeNamespaceReconciler.class) + .changeNamespaces("default", extension.getNamespace()); + + await().pollDelay(Duration.ofSeconds(1)) + .timeout(Duration.ofSeconds(3)) + .untilAsserted(() -> { + assertThat(reconciler.getNumberOfExecutions()).isEqualTo(0); + }); + } + + + LeaderElectionChangeNamespaceCustomResource testResource() { + var resource = new LeaderElectionChangeNamespaceCustomResource(); + resource.setMetadata(new ObjectMetaBuilder() + .withName("test1") + .build()); + return resource; + } + + static Lease lease() { + var lease = new Lease(); + lease.setMetadata(new ObjectMetaBuilder() + .withName(LEASE_NAME) + .withNamespace("default") + .build()); + var time = ZonedDateTime.now(); + lease.setSpec(new LeaseSpecBuilder() + .withAcquireTime(ZonedDateTime.now()) + .withRenewTime(time) + .withAcquireTime(time) + .withHolderIdentity("non-operator-identity") + .withLeaseTransitions(0) + .withLeaseDurationSeconds(30) + .build()); + + return lease; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/leaderelectionchangenamespace/LeaderElectionChangeNamespaceCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/leaderelectionchangenamespace/LeaderElectionChangeNamespaceCustomResource.java new file mode 100644 index 0000000000..8a37720955 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/leaderelectionchangenamespace/LeaderElectionChangeNamespaceCustomResource.java @@ -0,0 +1,15 @@ +package io.javaoperatorsdk.operator.sample.leaderelectionchangenamespace; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("lcn") +public class LeaderElectionChangeNamespaceCustomResource + extends CustomResource + implements Namespaced { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/leaderelectionchangenamespace/LeaderElectionChangeNamespaceReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/leaderelectionchangenamespace/LeaderElectionChangeNamespaceReconciler.java new file mode 100644 index 0000000000..8651a4774e --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/leaderelectionchangenamespace/LeaderElectionChangeNamespaceReconciler.java @@ -0,0 +1,29 @@ +package io.javaoperatorsdk.operator.sample.leaderelectionchangenamespace; + +import java.util.concurrent.atomic.AtomicInteger; + +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; +import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; + +@ControllerConfiguration() +public class LeaderElectionChangeNamespaceReconciler + implements Reconciler, TestExecutionInfoProvider { + + private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + + @Override + public UpdateControl reconcile( + LeaderElectionChangeNamespaceCustomResource resource, + Context context) { + numberOfExecutions.addAndGet(1); + return UpdateControl.noUpdate(); + } + + public int getNumberOfExecutions() { + return numberOfExecutions.get(); + } + +} From 8d100b8222a34278c7bb72ebc14a8450e2aa8bf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 15 Apr 2024 13:28:05 +0200 Subject: [PATCH 182/644] fix: name of fabric8 workflow (#2350) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/fabric8-next-version-schedule.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/fabric8-next-version-schedule.yml b/.github/workflows/fabric8-next-version-schedule.yml index e79374c74f..72a1ba52d3 100644 --- a/.github/workflows/fabric8-next-version-schedule.yml +++ b/.github/workflows/fabric8-next-version-schedule.yml @@ -1,4 +1,4 @@ -name: Verify Pull Request +name: Fabric8 Client Snapshot Build env: MAVEN_ARGS: -V -ntp -e From 6d9bc228cf0f794029b46aba2e057846dffc453b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 15 Apr 2024 14:19:53 +0000 Subject: [PATCH 183/644] Set new SNAPSHOT version into pom files. --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 893f728315..e40fce1cbd 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index 6f21000dc6..8eb2e7d96d 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 3d52fe0997..58cd68083f 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 184a9a58bf..8817e956d2 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index 84ada8f79f..a1dc67359b 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 2036680ba8..f391f0357b 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index 5e5bb07ff3..473971601a 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 17e91a3516..413f160f91 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index c1b8d4cb5d..73582cddeb 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index eca48e5b2c..6572365e73 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 43120eb74d..de9b30045e 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index b2bc3e5fe3..0412120489 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 5befc0d8a7..adf597192a 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.3-SNAPSHOT + 4.8.4-SNAPSHOT sample-webpage-operator From 603895db0cbd7e4004248e85fface334c874d6b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Apr 2024 08:54:03 +0200 Subject: [PATCH 184/644] chore(deps): bump org.apache.maven.plugins:maven-jar-plugin (#2358) Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.4.0 to 3.4.1. - [Release notes](https://github.com/apache/maven-jar-plugin/releases) - [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.4.0...maven-jar-plugin-3.4.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-jar-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 413f160f91..64abf731a5 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ 3.6.3 3.3.1 3.3.1 - 3.4.0 + 3.4.1 3.3.2 3.2.3 1.6.13 From 69c7744004dfcf7843a37b77985976f722696cc4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Apr 2024 08:54:25 +0200 Subject: [PATCH 185/644] chore(deps): bump org.apache.maven.plugins:maven-gpg-plugin (#2357) Bumps [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 3.2.3 to 3.2.4. - [Release notes](https://github.com/apache/maven-gpg-plugin/releases) - [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-3.2.3...maven-gpg-plugin-3.2.4) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-gpg-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- operator-framework-bom/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 8817e956d2..12843e5c2d 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -61,7 +61,7 @@ 1.6.13 - 3.2.3 + 3.2.4 3.3.1 3.6.3 diff --git a/pom.xml b/pom.xml index 64abf731a5..47b7aaf7d8 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 3.3.1 3.4.1 3.3.2 - 3.2.3 + 3.2.4 1.6.13 3.0.0 3.1.1 From 4f342e29d5b87f6314f9cb73e4b75c236d4d0e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 22 Apr 2024 14:38:52 +0200 Subject: [PATCH 186/644] fix: remove invalid log message (#2356) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit it can happen that other controller added finalizer, so the logging is misleading Signed-off-by: Attila Mészáros --- .../operator/processing/event/ReconciliationDispatcher.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java index ed3eb38521..9189cc6822 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java @@ -95,10 +95,6 @@ private PostExecutionControl

handleDispatch(ExecutionScope

executionScope) private boolean shouldNotDispatchToCleanupWhenMarkedForDeletion(P resource) { var alreadyRemovedFinalizer = controller.useFinalizer() && !resource.hasFinalizer(configuration().getFinalizerName()); - if (alreadyRemovedFinalizer) { - log.warn("This should not happen. Marked for deletion & already removed finalizer: {}", - ResourceID.fromResource(resource)); - } return !controller.useFinalizer() || alreadyRemovedFinalizer; } From 3c863793fdd2341d434bdfcfd6216b4023554a7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 23 Apr 2024 09:09:39 +0200 Subject: [PATCH 187/644] docs: minor comment on impl (#2355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../updatermatcher/GenericResourceUpdaterMatcher.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/GenericResourceUpdaterMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/GenericResourceUpdaterMatcher.java index 2a5bae03b9..43d0b2fedf 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/GenericResourceUpdaterMatcher.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/updatermatcher/GenericResourceUpdaterMatcher.java @@ -30,6 +30,8 @@ public R updateResource(R actual, R desired, Context context) { Map actualMap = kubernetesSerialization.convertValue(actual, Map.class); Map desiredMap = kubernetesSerialization.convertValue(desired, Map.class); // replace all top level fields from actual with desired, but merge metadata separately + // note that this ensures that `resourceVersion` is present, therefore optimistic + // locking will happen on server side var metadata = actualMap.remove(METADATA); actualMap.replaceAll((k, v) -> desiredMap.get(k)); actualMap.putAll(desiredMap); From 28a68c3fb80b9bc11f2e0d1ea27da9bc99e08c3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Mon, 29 Apr 2024 08:51:45 +0200 Subject: [PATCH 188/644] docs: remove jenvtest add glue operator reference (#2366) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d850c4551d..fd9a6e2646 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,9 @@ For all features and their usage see the [related section on the website](https: * Quarkus Extension: https://github.com/quarkiverse/quarkus-operator-sdk * Spring Boot Starter: https://github.com/java-operator-sdk/operator-framework-spring-boot-starter -* jenvtest: https://github.com/java-operator-sdk/jenvtest - Support for integration testing against Kubernetes API Server in a lightweight manner +* Kubernetes Glue Operator: https://github.com/csviri/kubernetes-glue-operator + Meta-operator that builds upon to use JOSDK Workflows and Dependent Resources features and + allows to create operators by simply applying a custom resource, thus, is a language independent way. * Kubernetes Webhooks Framework: https://github.com/java-operator-sdk/kubernetes-webooks-framework Framework to implement Admission Controllers and Conversion Hooks. * Operator SDK plugin: https://github.com/operator-framework/java-operator-plugins From 8e9f85deedf764e93be8490a4c084b90420639a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Apr 2024 08:56:51 +0200 Subject: [PATCH 189/644] chore(deps): bump org.apache.maven.plugins:maven-install-plugin (#2369) Bumps [org.apache.maven.plugins:maven-install-plugin](https://github.com/apache/maven-install-plugin) from 3.1.1 to 3.1.2. - [Release notes](https://github.com/apache/maven-install-plugin/releases) - [Commits](https://github.com/apache/maven-install-plugin/compare/maven-install-plugin-3.1.1...maven-install-plugin-3.1.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-install-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 47b7aaf7d8..ac278615dc 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,7 @@ 3.2.4 1.6.13 3.0.0 - 3.1.1 + 3.1.2 8.0.2 2.23.0 1.0 From 39bf6b255e887e027501374621937f11f5cfd084 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 08:59:06 +0200 Subject: [PATCH 190/644] chore(deps): bump org.apache.maven.plugins:maven-plugin-plugin (#2378) Bumps [org.apache.maven.plugins:maven-plugin-plugin](https://github.com/apache/maven-plugin-tools) from 3.12.0 to 3.13.0. - [Release notes](https://github.com/apache/maven-plugin-tools/releases) - [Commits](https://github.com/apache/maven-plugin-tools/compare/maven-plugin-tools-3.12.0...maven-plugin-tools-3.13.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-plugin-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bootstrapper-maven-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index e40fce1cbd..08a3ae05ed 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -17,7 +17,7 @@ 3.12.0 3.9.6 3.0.0 - 3.12.0 + 3.13.0 From 77c3fec4fd4511cef60f4e3f9178fecd15f45e05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 08:59:35 +0200 Subject: [PATCH 191/644] chore(deps): bump org.apache.maven.plugin-tools:maven-plugin-annotations (#2377) Bumps [org.apache.maven.plugin-tools:maven-plugin-annotations](https://github.com/apache/maven-plugin-tools) from 3.12.0 to 3.13.0. - [Release notes](https://github.com/apache/maven-plugin-tools/releases) - [Commits](https://github.com/apache/maven-plugin-tools/compare/maven-plugin-tools-3.12.0...maven-plugin-tools-3.13.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugin-tools:maven-plugin-annotations dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bootstrapper-maven-plugin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 08a3ae05ed..51cb574ecd 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -14,7 +14,7 @@ Operator SDK - Bootstrapper Maven Plugin - 3.12.0 + 3.13.0 3.9.6 3.0.0 3.13.0 From 452cb50f1a883683cc1a6ce965c7e6de69629e3f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 23:14:20 +0200 Subject: [PATCH 192/644] chore(deps): bump manusa/actions-setup-minikube from 2.10.0 to 2.11.0 (#2379) --- .github/workflows/e2e-test.yml | 2 +- .github/workflows/integration-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 5e0a629bbc..49ec92013e 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -30,7 +30,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Minikube-Kubernetes - uses: manusa/actions-setup-minikube@v2.10.0 + uses: manusa/actions-setup-minikube@v2.11.0 with: minikube version: v1.32.0 kubernetes version: v1.29.1 diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 79c77a6c98..df7bf8436e 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -40,7 +40,7 @@ jobs: java-version: ${{ inputs.java-version }} cache: 'maven' - name: Set up Minikube - uses: manusa/actions-setup-minikube@v2.10.0 + uses: manusa/actions-setup-minikube@v2.11.0 with: minikube version: v1.32.0 kubernetes version: ${{ inputs.kube-version }} From ed0276ab039b27d6861f1c80d5485605abe0758f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 09:40:26 +0200 Subject: [PATCH 193/644] chore(deps): bump org.mockito:mockito-core from 5.11.0 to 5.12.0 (#2380) Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.11.0 to 5.12.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.11.0...v5.12.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ac278615dc..6a9af93f16 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 6.11.0 1.7.36 2.23.1 - 5.11.0 + 5.12.0 3.14.0 0.21.0 1.13.0 From 81585c61be73d6c80a705720c1531fb81a1bd2a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 May 2024 08:57:30 +0200 Subject: [PATCH 194/644] chore(deps): bump io.micrometer:micrometer-core from 1.12.5 to 1.13.0 (#2381) Bumps [io.micrometer:micrometer-core](https://github.com/micrometer-metrics/micrometer) from 1.12.5 to 1.13.0. - [Release notes](https://github.com/micrometer-metrics/micrometer/releases) - [Commits](https://github.com/micrometer-metrics/micrometer/compare/v1.12.5...v1.13.0) --- updated-dependencies: - dependency-name: io.micrometer:micrometer-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6a9af93f16..2d4f075821 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ 3.25.3 4.2.0 2.7.3 - 1.12.5 + 1.13.0 4.12.0 3.1.8 0.9.6 From 37ad093b70822fd680f2cd29e6a832243aa87987 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Thu, 16 May 2024 20:28:15 +0200 Subject: [PATCH 195/644] chore: update to Fabric8 client 6.12.1 (#2376) Signed-off-by: Chris Laprun --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2d4f075821..c30d77d781 100644 --- a/pom.xml +++ b/pom.xml @@ -44,7 +44,7 @@ okhttp 5.10.1 - 6.11.0 + 6.12.1 1.7.36 2.23.1 5.12.0 From 73d6c60c0a4994d205f63b5a7131f95d5ac5a06c Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 17 May 2024 08:25:56 +0000 Subject: [PATCH 196/644] Set new SNAPSHOT version into pom files. --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 51cb574ecd..77e00978b0 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index 8eb2e7d96d..cb58a1e00f 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index 58cd68083f..dc3c94ab18 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index 12843e5c2d..c8a4bc391e 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index a1dc67359b..3ff3aeae92 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index f391f0357b..7aa1db8b5d 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index 473971601a..b5fd468d1a 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index c30d77d781..a61a53569f 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 73582cddeb..264a7a8db1 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 6572365e73..4446d020cf 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index de9b30045e..857ba700ee 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 0412120489..0dde4f2722 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index adf597192a..51a4c0d31a 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.4-SNAPSHOT + 4.8.5-SNAPSHOT sample-webpage-operator From 6f898d9d849bc4997d1927f21aaaac178fea8087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Fri, 17 May 2024 12:24:06 +0200 Subject: [PATCH 197/644] chore: bump version to 4.9.1-SNAPSHOT (#2388) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- bootstrapper-maven-plugin/pom.xml | 2 +- caffeine-bounded-cache-support/pom.xml | 2 +- micrometer-support/pom.xml | 2 +- operator-framework-bom/pom.xml | 2 +- operator-framework-core/pom.xml | 2 +- operator-framework-junit5/pom.xml | 2 +- operator-framework/pom.xml | 2 +- pom.xml | 2 +- sample-operators/leader-election/pom.xml | 2 +- sample-operators/mysql-schema/pom.xml | 2 +- sample-operators/pom.xml | 2 +- sample-operators/tomcat-operator/pom.xml | 2 +- sample-operators/webpage/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml index 77e00978b0..a2173e7ce1 100644 --- a/bootstrapper-maven-plugin/pom.xml +++ b/bootstrapper-maven-plugin/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT bootstrapper diff --git a/caffeine-bounded-cache-support/pom.xml b/caffeine-bounded-cache-support/pom.xml index cb58a1e00f..8172959283 100644 --- a/caffeine-bounded-cache-support/pom.xml +++ b/caffeine-bounded-cache-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT 4.0.0 diff --git a/micrometer-support/pom.xml b/micrometer-support/pom.xml index dc3c94ab18..e5666469ff 100644 --- a/micrometer-support/pom.xml +++ b/micrometer-support/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT 4.0.0 diff --git a/operator-framework-bom/pom.xml b/operator-framework-bom/pom.xml index c8a4bc391e..73b941f621 100644 --- a/operator-framework-bom/pom.xml +++ b/operator-framework-bom/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk operator-framework-bom - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT Operator SDK - Bill of Materials pom Java SDK for implementing Kubernetes operators diff --git a/operator-framework-core/pom.xml b/operator-framework-core/pom.xml index 3ff3aeae92..a8cb6beac0 100644 --- a/operator-framework-core/pom.xml +++ b/operator-framework-core/pom.xml @@ -6,7 +6,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT ../pom.xml diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml index 7aa1db8b5d..6e98ab0b48 100644 --- a/operator-framework-junit5/pom.xml +++ b/operator-framework-junit5/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT 4.0.0 diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml index b5fd468d1a..0ed845d02c 100644 --- a/operator-framework/pom.xml +++ b/operator-framework/pom.xml @@ -5,7 +5,7 @@ java-operator-sdk io.javaoperatorsdk - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index a61a53569f..c62b44c8cb 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT Operator SDK for Java Java SDK for implementing Kubernetes operators pom diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml index 264a7a8db1..c7bbcb0cd2 100644 --- a/sample-operators/leader-election/pom.xml +++ b/sample-operators/leader-election/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT sample-leader-election diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml index 4446d020cf..3c3a9107f9 100644 --- a/sample-operators/mysql-schema/pom.xml +++ b/sample-operators/mysql-schema/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT sample-mysql-schema-operator diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml index 857ba700ee..959257cec5 100644 --- a/sample-operators/pom.xml +++ b/sample-operators/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk java-operator-sdk - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT sample-operators diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml index 0dde4f2722..be62027eb1 100644 --- a/sample-operators/tomcat-operator/pom.xml +++ b/sample-operators/tomcat-operator/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT sample-tomcat-operator diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml index 51a4c0d31a..0f43b5b2e6 100644 --- a/sample-operators/webpage/pom.xml +++ b/sample-operators/webpage/pom.xml @@ -7,7 +7,7 @@ io.javaoperatorsdk sample-operators - 4.8.5-SNAPSHOT + 4.9.1-SNAPSHOT sample-webpage-operator From 1bd712e0a42d9bd7a8b166cc767783c5bb3f229e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 21 May 2024 11:33:26 +0200 Subject: [PATCH 198/644] feat: docsy migration (#2352) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- docsy/.gitignore | 5 + docsy/.nvmrc | 1 + docsy/CONTRIBUTING.md | 28 + docsy/Dockerfile | 4 + docsy/LICENSE | 201 ++++ docsy/README.md | 184 ++++ docsy/assets/icons/logo.svg | 18 + docsy/assets/scss/_variables_project.scss | 10 + docsy/config.yaml | 15 + docsy/content/en/_index.md | 73 ++ docsy/content/en/blog/_index.md | 8 + docsy/content/en/blog/news/_index.md | 4 + docsy/content/en/blog/releases/_index.md | 4 + docsy/content/en/community/_index.md | 6 + docsy/content/en/docs/_index.md | 8 + docsy/content/en/docs/architecture/_index.md | 65 ++ docsy/content/en/docs/configuration/_index.md | 68 ++ docsy/content/en/docs/contributing/_index.md | 84 ++ .../en/docs/dependent-resources/_index.md | 552 +++++++++++ docsy/content/en/docs/faq/_index.md | 96 ++ docsy/content/en/docs/features/_index.md | 860 ++++++++++++++++++ .../content/en/docs/getting-started/_index.md | 58 ++ docsy/content/en/docs/glossary/_index.md | 24 + .../en/docs/intro-to-operators/_index.md | 16 + docsy/content/en/docs/migration/_index.md | 4 + .../content/en/docs/migration/v2-migration.md | 60 ++ .../en/docs/migration/v3-1-migration.md | 47 + .../content/en/docs/migration/v3-migration.md | 40 + .../en/docs/migration/v4-3-migration.md | 50 + .../en/docs/migration/v4-4-migration.md | 93 ++ .../en/docs/migration/v4-5-migration.md | 26 + .../docs/patters-and-best-practices/_index.md | 122 +++ docsy/content/en/docs/using-samples/_index.md | 255 ++++++ docsy/content/en/docs/workflows/_index.md | 354 +++++++ docsy/content/en/featured-background.jpg | Bin 0 -> 129070 bytes docsy/content/en/search.md | 4 + docsy/content/fileList.txt | 0 docsy/docker-compose.yaml | 13 + docsy/docsy.work | 5 + docsy/docsy.work.sum | 0 docsy/go.mod | 5 + docsy/go.sum | 5 + docsy/hugo.toml | 199 ++++ docsy/layouts/404.html | 7 + .../_default/_markup/render-heading.html | 1 + docsy/netlify.toml | 12 + docsy/package.json | 42 + docsy/static/favicons/favicon.ico | Bin 0 -> 1150 bytes docsy/static/images/architecture.svg | 4 + docsy/static/images/cncf_logo.png | Bin 0 -> 4783 bytes docsy/static/images/cs-logo.svg | 1 + docsy/static/images/full-logo-white.svg | 20 + docsy/static/images/original_full_logo.png | Bin 0 -> 35366 bytes docsy/static/images/red-hat.webp | Bin 0 -> 15512 bytes .../podspecinspec/SampleCustomResource.java | 13 + .../sample/podspecinspec/SampleSpec.java | 19 + 56 files changed, 3793 insertions(+) create mode 100644 docsy/.gitignore create mode 100644 docsy/.nvmrc create mode 100644 docsy/CONTRIBUTING.md create mode 100644 docsy/Dockerfile create mode 100644 docsy/LICENSE create mode 100644 docsy/README.md create mode 100644 docsy/assets/icons/logo.svg create mode 100644 docsy/assets/scss/_variables_project.scss create mode 100644 docsy/config.yaml create mode 100644 docsy/content/en/_index.md create mode 100644 docsy/content/en/blog/_index.md create mode 100644 docsy/content/en/blog/news/_index.md create mode 100644 docsy/content/en/blog/releases/_index.md create mode 100644 docsy/content/en/community/_index.md create mode 100755 docsy/content/en/docs/_index.md create mode 100644 docsy/content/en/docs/architecture/_index.md create mode 100644 docsy/content/en/docs/configuration/_index.md create mode 100644 docsy/content/en/docs/contributing/_index.md create mode 100644 docsy/content/en/docs/dependent-resources/_index.md create mode 100644 docsy/content/en/docs/faq/_index.md create mode 100644 docsy/content/en/docs/features/_index.md create mode 100644 docsy/content/en/docs/getting-started/_index.md create mode 100644 docsy/content/en/docs/glossary/_index.md create mode 100644 docsy/content/en/docs/intro-to-operators/_index.md create mode 100644 docsy/content/en/docs/migration/_index.md create mode 100644 docsy/content/en/docs/migration/v2-migration.md create mode 100644 docsy/content/en/docs/migration/v3-1-migration.md create mode 100644 docsy/content/en/docs/migration/v3-migration.md create mode 100644 docsy/content/en/docs/migration/v4-3-migration.md create mode 100644 docsy/content/en/docs/migration/v4-4-migration.md create mode 100644 docsy/content/en/docs/migration/v4-5-migration.md create mode 100644 docsy/content/en/docs/patters-and-best-practices/_index.md create mode 100644 docsy/content/en/docs/using-samples/_index.md create mode 100644 docsy/content/en/docs/workflows/_index.md create mode 100644 docsy/content/en/featured-background.jpg create mode 100644 docsy/content/en/search.md create mode 100644 docsy/content/fileList.txt create mode 100644 docsy/docker-compose.yaml create mode 100644 docsy/docsy.work create mode 100644 docsy/docsy.work.sum create mode 100644 docsy/go.mod create mode 100644 docsy/go.sum create mode 100644 docsy/hugo.toml create mode 100644 docsy/layouts/404.html create mode 100644 docsy/layouts/_default/_markup/render-heading.html create mode 100644 docsy/netlify.toml create mode 100644 docsy/package.json create mode 100644 docsy/static/favicons/favicon.ico create mode 100644 docsy/static/images/architecture.svg create mode 100644 docsy/static/images/cncf_logo.png create mode 100644 docsy/static/images/cs-logo.svg create mode 100644 docsy/static/images/full-logo-white.svg create mode 100644 docsy/static/images/original_full_logo.png create mode 100644 docsy/static/images/red-hat.webp create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleSpec.java diff --git a/docsy/.gitignore b/docsy/.gitignore new file mode 100644 index 0000000000..40b67f41a7 --- /dev/null +++ b/docsy/.gitignore @@ -0,0 +1,5 @@ +/public +resources/ +node_modules/ +package-lock.json +.hugo_build.lock \ No newline at end of file diff --git a/docsy/.nvmrc b/docsy/.nvmrc new file mode 100644 index 0000000000..b009dfb9d9 --- /dev/null +++ b/docsy/.nvmrc @@ -0,0 +1 @@ +lts/* diff --git a/docsy/CONTRIBUTING.md b/docsy/CONTRIBUTING.md new file mode 100644 index 0000000000..db177d4ac7 --- /dev/null +++ b/docsy/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# How to Contribute + +We'd love to accept your patches and contributions to this project. There are +just a few small guidelines you need to follow. + +## Contributor License Agreement + +Contributions to this project must be accompanied by a Contributor License +Agreement. You (or your employer) retain the copyright to your contribution; +this simply gives us permission to use and redistribute your contributions as +part of the project. Head over to to see +your current agreements on file or to sign a new one. + +You generally only need to submit a CLA once, so if you've already submitted one +(even if it was for a different project), you probably don't need to do it +again. + +## Code reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. Consult +[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more +information on using pull requests. + +## Community Guidelines + +This project follows +[Google's Open Source Community Guidelines](https://opensource.google.com/conduct/). diff --git a/docsy/Dockerfile b/docsy/Dockerfile new file mode 100644 index 0000000000..232d8f70c4 --- /dev/null +++ b/docsy/Dockerfile @@ -0,0 +1,4 @@ +FROM floryn90/hugo:ext-alpine + +RUN apk add git && \ + git config --global --add safe.directory /src diff --git a/docsy/LICENSE b/docsy/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/docsy/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/docsy/README.md b/docsy/README.md new file mode 100644 index 0000000000..481ce67413 --- /dev/null +++ b/docsy/README.md @@ -0,0 +1,184 @@ +# Docsy Example + +[Docsy][] is a [Hugo theme module][] for technical documentation sites, providing easy +site navigation, structure, and more. This **Docsy Example Project** uses the Docsy +theme component as a hugo module and provides a skeleton documentation structure for you to use. +You can clone/copy this project and edit it with your own content, or use it as an example. + +In this project, the Docsy theme is pulled in as a Hugo module, together with +its dependencies: + +```console +$ hugo mod graph +... +``` + +For Docsy documentation, see [Docsy user guide][]. + +This Docsy Example Project is hosted on [Netlify][] at [example.docsy.dev][]. +You can view deploy logs from the [deploy section of the project's Netlify +dashboard][deploys], or this [alternate dashboard][]. + +This is not an officially supported Google product. This project is currently maintained. + +## Using the Docsy Example Project as a template + +A simple way to get started is to use this project as a template, which gives you a site project that is set up and ready to use. To do this: + +1. Use the dropdown for switching branches/tags to change to the **latest** released tag. + +2. Click **Use this template**. + +3. Select a name for your new project and click **Create repository from template**. + +4. Make your own local working copy of your new repo using git clone, replacing https://github.com/me/example.git with your repo’s web URL: + +```bash +git clone --depth 1 https://github.com/me/example.git +``` + +You can now edit your own versions of the site’s source files. + +If you want to do SCSS edits and want to publish these, you need to install `PostCSS` + +```bash +npm install +``` + +## Running the website locally + +Building and running the site locally requires a recent `extended` version of [Hugo](https://gohugo.io). +You can find out more about how to install Hugo for your environment in our +[Getting started](https://www.docsy.dev/docs/getting-started/#prerequisites-and-installation) guide. + +Once you've made your working copy of the site repo, from the repo root folder, run: + +```bash +hugo server +``` + +## Running a container locally + +You can run docsy-example inside a [Docker](https://docs.docker.com/) +container, the container runs with a volume bound to the `docsy-example` +folder. This approach doesn't require you to install any dependencies other +than [Docker Desktop](https://www.docker.com/products/docker-desktop) on +Windows and Mac, and [Docker Compose](https://docs.docker.com/compose/install/) +on Linux. + +1. Build the docker image + + ```bash + docker-compose build + ``` + +1. Run the built image + + ```bash + docker-compose up + ``` + + > NOTE: You can run both commands at once with `docker-compose up --build`. + +1. Verify that the service is working. + + Open your web browser and type `http://localhost:1313` in your navigation bar, + This opens a local instance of the docsy-example homepage. You can now make + changes to the docsy example and those changes will immediately show up in your + browser after you save. + +### Cleanup + +To stop Docker Compose, on your terminal window, press **Ctrl + C**. + +To remove the produced images run: + +```bash +docker-compose rm +``` +For more information see the [Docker Compose documentation][]. + +## Using a local Docsy clone + +Make sure your installed go version is `1.18` or higher. + +Clone the latest version of the docsy theme into the parent folder of your project. The newly created repo should now reside in a sibling folder of your site's root folder. + +```shell +cd root-of-your-site +git clone --branch v0.7.2 https://github.com/google/docsy.git ../docsy +``` + +Now run: + +```shell +HUGO_MODULE_WORKSPACE=docsy.work hugo server --ignoreVendorPaths "**" +``` + +or, when using npm, prepend `local` to the script you want to invoke, e.g.: + +```shell +npm run local serve +``` + +By using the `HUGO_MODULE_WORKSPACE` directive (either directly or via prefix `local` when using npm), the server now watches all files and directories inside the sibling directory `../docsy` , too. Any changes inside the local `docsy` theme clone are now immediately picked up (hot reload), you can instantly see the effect of your local edits. + +In the command above, we used the environment variable `HUGO_MODULE_WORKSPACE` to tell hugo about the local workspace file `docsy.work`. Alternatively, you can declare the workspace file inside your settings file `hugo.toml`: + +```toml +[module] + workspace = "docsy.work" +``` + +Your project's `hugo.toml` file already contains these lines, the directive for workspace assignment is commented out, however. Remove the two trailing comment characters '//' so that this line takes effect. + +## Troubleshooting + +As you run the website locally, you may run into the following error: + +```console +$ hugo server +WARN 2023/06/27 16:59:06 Module "project" is not compatible with this Hugo version; run "hugo mod graph" for more information. +Start building sites … +hugo v0.101.0-466fa43c16709b4483689930a4f9ac8add5c9f66+extended windows/amd64 BuildDate=2022-06-16T07:09:16Z VendorInfo=gohugoio +Error: Error building site: "C:\Users\foo\path\to\docsy-example\content\en\_index.md:5:1": failed to extract shortcode: template for shortcode "blocks/cover" not found +Built in 27 ms +``` + +This error occurs if you are running an outdated version of Hugo. As of docsy theme version `v0.7.0`, hugo version `0.110.0` or higher is required. +See this [section](https://www.docsy.dev/docs/get-started/docsy-as-module/installation-prerequisites/#install-hugo) of the user guide for instructions on how to install Hugo. + +Or you may be confronted with the following error: + +```console +$ hugo server + +INFO 2021/01/21 21:07:55 Using config file: +Building sites … INFO 2021/01/21 21:07:55 syncing static files to / +Built in 288 ms +Error: Error building site: TOCSS: failed to transform "scss/main.scss" (text/x-scss): resource "scss/scss/main.scss_9fadf33d895a46083cdd64396b57ef68" not found in file cache +``` + +This error occurs if you have not installed the extended version of Hugo. +See this [section](https://www.docsy.dev/docs/get-started/docsy-as-module/installation-prerequisites/#install-hugo) of the user guide for instructions on how to install Hugo. + +Or you may encounter the following error: + +```console +$ hugo server + +Error: failed to download modules: binary with name "go" not found +``` + +This error occurs if you have not installed the `go` programming language on your system. +See this [section](https://www.docsy.dev/docs/get-started/docsy-as-module/installation-prerequisites/#install-go-language) of the user guide for instructions on how to install `go`. + + +[alternate dashboard]: https://app.netlify.com/sites/goldydocs/deploys +[deploys]: https://app.netlify.com/sites/docsy-example/deploys +[Docsy user guide]: https://docsy.dev/docs +[Docsy]: https://github.com/google/docsy +[example.docsy.dev]: https://example.docsy.dev +[Hugo theme module]: https://gohugo.io/hugo-modules/use-modules/#use-a-module-for-a-theme +[Netlify]: https://netlify.com +[Docker Compose documentation]: https://docs.docker.com/compose/gettingstarted/ diff --git a/docsy/assets/icons/logo.svg b/docsy/assets/icons/logo.svg new file mode 100644 index 0000000000..0048fdf4d6 --- /dev/null +++ b/docsy/assets/icons/logo.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/docsy/assets/scss/_variables_project.scss b/docsy/assets/scss/_variables_project.scss new file mode 100644 index 0000000000..35523dc3f4 --- /dev/null +++ b/docsy/assets/scss/_variables_project.scss @@ -0,0 +1,10 @@ +/* + +Add styles or override variables from the theme here. + +*/ + +//$primary: #fc9c62;; +$primary: #da5504; +$secondary: #fc9c62 +//$secondary: white; \ No newline at end of file diff --git a/docsy/config.yaml b/docsy/config.yaml new file mode 100644 index 0000000000..9070e384f0 --- /dev/null +++ b/docsy/config.yaml @@ -0,0 +1,15 @@ +# THIS IS A TEST CONFIG ONLY! +# FOR THE CONFIGURATION OF YOUR SITE USE hugo.yaml. +# +# As of Docsy 0.7.0, Hugo 0.110.0 or later must be used. +# +# The sole purpose of this config file is to detect Hugo-module builds that use +# an older version of Hugo. +# +# DO NOT add any config parameters to this file. You can safely delete this file +# if your project is using the required Hugo version. + +module: + hugoVersion: + extended: true + min: 0.110.0 diff --git a/docsy/content/en/_index.md b/docsy/content/en/_index.md new file mode 100644 index 0000000000..9da4a292d8 --- /dev/null +++ b/docsy/content/en/_index.md @@ -0,0 +1,73 @@ +--- +title: Java Operator SDK Documentation +--- + +{{< blocks/cover title="Welcome to Java Operator SDK Documentation!" image_anchor="top" height="full" >}} + + Learn More + + + Download + +

Implement Kubernetes operators in Java without hassle

+{{< blocks/link-down color="info" >}} +{{< /blocks/cover >}} + + +{{% blocks/lead color="gray" %}} +Whether you want to build applications that operate themselves or provision infrastructure from Java code, Kubernetes Operators are the way to go. +Java Operator SDK is based on the fabric8 Kubernetes client and will make it easy for Java developers to embrace this new way of automation. +{{% /blocks/lead %}} + + +{{% blocks/section color="secondary" type="row" %}} +{{% blocks/feature icon="fab fa-slack" title="Contact us on Slack" url="https://kubernetes.slack.com/archives/CAW0GV7A5" %}} +Feel free to reach out on [Kuberentes Slack](https://kubernetes.slack.com/archives/CAW0GV7A5) + +Ask any question, we are happy to answer! +{{% /blocks/feature %}} + + +{{% blocks/feature icon="fab fa-github" title="Contributions welcome!" url="https://github.com/operator-framework/java-operator-sdk" %}} +We do a [Pull Request](https://github.com/operator-framework/java-operator-sdk/pulls) contributions workflow on **GitHub**. New users are always welcome! +{{% /blocks/feature %}} + + +{{% blocks/feature icon="fab fa-twitter" title="Follow us on Twitter!" url="https://twitter.com/javaoperatorsdk" %}} +For announcement of latest features etc. +{{% /blocks/feature %}} + + +{{% /blocks/section %}} + + +{{% blocks/section %}} + +Sponsored by: +{.h1 .text-center} + + +
Red Hat   &   Container Solutions +{.h1 .text-center} + +{{% /blocks/section %}} + + +{{% blocks/section type="row" %}} + +{{% blocks/feature icon="no_icon" %}} +{{% /blocks/feature %}} + +{{% blocks/feature %}} +Java Operator SDK if member of CNCF as a subproject of Operator Framework +{.h3 .text-center} + +CNCF + +{{% /blocks/feature %}} + +{{% blocks/feature icon="no_icon" %}} +{{% /blocks/feature %}} + +{{% /blocks/section %}} + diff --git a/docsy/content/en/blog/_index.md b/docsy/content/en/blog/_index.md new file mode 100644 index 0000000000..c8219f7994 --- /dev/null +++ b/docsy/content/en/blog/_index.md @@ -0,0 +1,8 @@ +--- +title: Blog +menu: {main: {weight: 30}} +--- + +This is the **blog** section. It has two categories: News and Releases. + +Content is coming soon. diff --git a/docsy/content/en/blog/news/_index.md b/docsy/content/en/blog/news/_index.md new file mode 100644 index 0000000000..c609aa2543 --- /dev/null +++ b/docsy/content/en/blog/news/_index.md @@ -0,0 +1,4 @@ +--- +title: News +weight: 20 +--- diff --git a/docsy/content/en/blog/releases/_index.md b/docsy/content/en/blog/releases/_index.md new file mode 100644 index 0000000000..9143a23148 --- /dev/null +++ b/docsy/content/en/blog/releases/_index.md @@ -0,0 +1,4 @@ +--- +title: Releases +weight: 20 +--- diff --git a/docsy/content/en/community/_index.md b/docsy/content/en/community/_index.md new file mode 100644 index 0000000000..3f237b8a79 --- /dev/null +++ b/docsy/content/en/community/_index.md @@ -0,0 +1,6 @@ +--- +title: Community +menu: {main: {weight: 40}} +--- + + diff --git a/docsy/content/en/docs/_index.md b/docsy/content/en/docs/_index.md new file mode 100755 index 0000000000..76486e22f7 --- /dev/null +++ b/docsy/content/en/docs/_index.md @@ -0,0 +1,8 @@ +--- +title: Documentation +linkTitle: Docs +menu: {main: {weight: 20}} +weight: 20 +--- + + diff --git a/docsy/content/en/docs/architecture/_index.md b/docsy/content/en/docs/architecture/_index.md new file mode 100644 index 0000000000..a29f70c4f6 --- /dev/null +++ b/docsy/content/en/docs/architecture/_index.md @@ -0,0 +1,65 @@ +--- +title: Architecture and Internals +weight: 90 +--- + + +This document gives an overview of the internal structure and components of Java Operator SDK core, +in order to make it easier for developers to understand and contribute to it. This document is +not intended to be a comprehensive reference, rather an introduction to the core concepts and we +hope that the other parts should be fairly easy to understand. We will evolve this document +based on the community's feedback. + +## The Big Picture and Core Components + +![JOSDK architecture](/images/architecture.svg) + +An [Operator](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java) +is a set of +independent [controllers](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java) +. +The `Controller` class, however, is an internal class managed by the framework itself and +usually shouldn't interacted with directly by end users. It +manages all the processing units involved with reconciling a single type of Kubernetes resource. + +Other components include: + +- [Reconciler](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java) + is the primary entry-point for the developers of the framework to implement the reconciliation + logic. +- [EventSource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSource.java) + represents a source of events that might eventually trigger a reconciliation. +- [EventSourceManager](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java) + aggregates all the event sources associated with a controller. Manages the event sources' + lifecycle. +- [ControllerResourceEventSource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java) + is a central event source that watches the resources associated with the controller (also + called primary resources) for changes, propagates events and caches the related state. +- [EventProcessor](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java) + processes the incoming events and makes sure they are executed in a sequential manner, that is + making sure that the events are processed in the order they are received for a given resource, + despite requests being processed concurrently overall. The `EventProcessor` also takes care of + re-scheduling or retrying requests as needed. +- [ReconcilerDispatcher](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java) + is responsible for dispatching requests to the appropriate `Reconciler` method and handling + the reconciliation results, making the instructed Kubernetes API calls. + +## Typical Workflow + +A typical workflows looks like following: + +1. An `EventSource` produces an event, that is propagated to the `EventProcessor`. +2. The resource associated with the event is read from the internal cache. +3. If the resource is not already being processed, a reconciliation request is + submitted to the executor service to be executed in a different thread, encapsulated in a + `ControllerExecution` instance. +4. This, in turns, calls the `ReconcilerDispatcher` which dispatches the call to the appropriate + `Reconciler` method, passing along all the required information. +5. Once the `Reconciler` is done, what happens depends on the result returned by the + `Reconciler`. If needed, the `ReconcilerDispatcher` will make the appropriate calls to the + Kubernetes API server. +6. Once the `Reconciler` is done, the `EventProcessor` is called back to finalize the + execution and update the controller's state. +7. The `EventProcessor` checks if the request needs to be rescheduled or retried and if there are no + subsequent events received for the same resource. +8. When none of this happens, the processing of the event is finished. diff --git a/docsy/content/en/docs/configuration/_index.md b/docsy/content/en/docs/configuration/_index.md new file mode 100644 index 0000000000..11929e3358 --- /dev/null +++ b/docsy/content/en/docs/configuration/_index.md @@ -0,0 +1,68 @@ +--- +title: Configuring JOSDK +layout: docs +permalink: /docs/configuration +--- + +# Configuration options + +The Java Operator SDK (JOSDK) provides several abstractions that work great out of the +box. However, while we strive to cover the most common cases with the default behavior, we also +recognize that that default behavior is not always what any given user might want for their +operator. Numerous configuration options are therefore provided to help people tailor the +framework to their needs. + +Configuration options act at several levels, depending on which behavior you wish to act upon: +- `Operator`-level using `ConfigurationService` +- `Reconciler`-level using `ControllerConfiguration` +- `DependentResouce`-level using the `DependentResourceConfigurator` interface +- `EventSource`-level: some event sources, such as `InformerEventSource`, might need to be + fine-tuned to properly identify which events will trigger the associated reconciler. + +## Operator-level configuration + +Configuration that impacts the whole operator is performed via the `ConfigurationService` class. +`ConfigurationService` is an abstract class, and the implementation can be different based +on which flavor of the framework is used. For example Quarkus Operator SDK replaces the +default implementation. Configurations are initialized with sensible defaults, but can +be changed during initialization. + +For instance, if you wish to not validate that the CRDs are present on your cluster when the +operator starts and configure leader election, you would do something similar to: + +```java +Operator operator = new Operator( override -> override + .checkingCRDAndValidateLocalModel(false) + .withLeaderElectionConfiguration(new LeaderElectionConfiguration("bar", "barNS"))); +``` + +## Reconciler-level configuration + +While reconcilers are typically configured using the `@ControllerConfiguration` annotation, it +is also possible to override the configuration at runtime, when the reconciler is registered +with the operator instance, either by passing it a completely new `ControllerConfiguration` +instance or by preferably overriding some aspects of the current configuration using a +`ControllerConfigurationOverrider` `Consumer`: + +```java +Operator operator; +Reconciler reconciler; +... +operator.register(reconciler, configOverrider -> + configOverrider.withFinalizer("my-nifty-operator/finalizer").withLabelSelector("foo=bar")); +``` + +## DependentResource-level configuration + +`DependentResource` implementations can implement the `DependentResourceConfigurator` interface +to pass information to the implementation. For example, the SDK +provides specific support for the `KubernetesDependentResource`, which can be configured via the +`@KubernetesDependent` annotation. This annotation is, in turn, converted into a +`KubernetesDependentResourceConfig` instance, which is then passed to the `configureWith` method +implementation. + +TODO: still subject to change / uniformization + +## EventSource-level configuration + +TODO diff --git a/docsy/content/en/docs/contributing/_index.md b/docsy/content/en/docs/contributing/_index.md new file mode 100644 index 0000000000..e67c45ebb6 --- /dev/null +++ b/docsy/content/en/docs/contributing/_index.md @@ -0,0 +1,84 @@ +--- +title: Contributing To Java Operator SDK +weight: 100 +--- + +First of all, we'd like to thank you for considering contributing to the project! We really +hope to create a vibrant community around this project but this won't happen without help from +people like you! + +## Code of Conduct + +We are serious about making this a welcoming, happy project. We will not tolerate discrimination, +aggressive or insulting behaviour. + +To this end, the project and everyone participating in it is bound by the [Code of +Conduct]({{baseurl}}/coc). By participating, you are expected to uphold this code. Please report +unacceptable behaviour to any of the project admins. + +## Bugs + +If you find a bug, +please [open an issue](https://github.com/java-operator-sdk/java-operator-sdk/issues)! Do try +to include all the details needed to recreate your problem. This is likely to include: + +- The version of the Operator SDK being used +- The exact platform and version of the platform that you're running on +- The steps taken to cause the bug +- Reproducer code is also very welcome to help us diagnose the issue and fix it quickly + +## Building Features and Documentation + +If you're looking for something to work on, take look at the issue tracker, in particular any items +labelled [good first issue](https://github.com/java-operator-sdk/java-operator-sdk/labels/good%20first%20issue) +. +Please leave a comment on the issue to mention that you have started work, in order to avoid +multiple people working on the same issue. + +If you have an idea for a feature - whether or not you have time to work on it - please also open an +issue describing your feature and label it "enhancement". We can then discuss it as a community and +see what can be done. Please be aware that some features may not align with the project goals and +might therefore be closed. In particular, please don't start work on a new feature without +discussing it first to avoid wasting effort. We do commit to listening to all proposals and will do +our best to work something out! + +Once you've got the go ahead to work on a feature, you can start work. Feel free to communicate with +team via updates on the issue tracker or the [Discord channel](https://discord.gg/DacEhAy) and ask +for feedback, pointers etc. Once you're happy with your code, go ahead and open a Pull Request. + +## Pull Request Process + +First, please format your commit messages so that they follow +the [conventional commit](https://www.conventionalcommits.org/en/v1.0.0/) format. + +On opening a PR, a GitHub action will execute the test suite against the new code. All code is +required to pass the tests, and new code must be accompanied by new tests. + +All PRs have to be reviewed and signed off by another developer before being merged. This review +will likely ask for some changes to the code - please don't be alarmed or upset +at this; it is expected that all PRs will need tweaks and a normal part of the process. + +The PRs are checked to be compliant with the Java Google code style. + +Be aware that all Operator SDK code is released under the [Apache 2.0 licence](LICENSE). + +## Development environment setup + +### Code style + +The SDK modules and samples are formatted to follow the Java Google code style. +On every `compile` the code gets formatted automatically, however, to make things simpler (i.e. +avoid getting a PR rejected simply because of code style issues), you can import one of the +following code style schemes based on the IDE you use: + +- for *Intellij IDEA* + import [contributing/intellij-google-style.xml](contributing/intellij-google-style.xml) +- for *Eclipse* + import [contributing/eclipse-google-style.xml](contributing/eclipse-google-style.xml) + +## Thanks + +These guidelines were based on several sources, including +[Atom](https://github.com/atom/atom/blob/master/CONTRIBUTING.md), [PurpleBooth's +advice](https://gist.github.com/PurpleBooth/b24679402957c63ec426) and the [Contributor +Covenant](https://www.contributor-covenant.org/). diff --git a/docsy/content/en/docs/dependent-resources/_index.md b/docsy/content/en/docs/dependent-resources/_index.md new file mode 100644 index 0000000000..51738869e3 --- /dev/null +++ b/docsy/content/en/docs/dependent-resources/_index.md @@ -0,0 +1,552 @@ +--- +title: Dependent Resources +weight: 60 +--- + +## Motivations and Goals + +Most operators need to deal with secondary resources when trying to realize the desired state +described by the primary resource they are in charge of. For example, the Kubernetes-native +`Deployment` controller needs to manage `ReplicaSet` instances as part of a `Deployment`'s +reconciliation process. In this instance, `ReplicatSet` is considered a secondary resource for +the `Deployment` controller. + +Controllers that deal with secondary resources typically need to perform the following steps, for +each secondary resource: + +
+flowchart TD + +compute[Compute desired secondary resource based on primary state] --> A +A{Secondary resource exists?} +A -- Yes --> match +A -- No --> Create --> Done + +match{Matches desired state?} +match -- Yes --> Done +match -- No --> Update --> Done + +
+ +While these steps are not difficult in and of themselves, there are some subtleties that can lead to +bugs or sub-optimal code if not done right. As this process is pretty much similar for each +dependent resource, it makes sense for the SDK to offer some level of support to remove the +boilerplate code associated with encoding these repetitive actions. It should +be possible to handle common cases (such as dealing with Kubernetes-native secondary resources) in a +semi-declarative way with only a minimal amount of code, JOSDK taking care of wiring everything +accordingly. + +Moreover, in order for your reconciler to get informed of events on these secondary resources, you +need to configure and create event sources and maintain them. JOSDK already makes it rather easy +to deal with these, but dependent resources makes it even simpler. + +Finally, there are also opportunities for the SDK to transparently add features that are even +trickier to get right, such as immediate caching of updated or created resources (so that your +reconciler doesn't need to wait for a cluster roundtrip to continue its work) and associated +event filtering (so that something your reconciler just changed doesn't re-trigger a +reconciliation, for example). + +## Design + +### `DependentResource` vs. `AbstractDependentResource` + +The new +[`DependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java) +interface lies at the core of the design and strives to encapsulate the logic that is required +to reconcile the state of the associated secondary resource based on the state of the primary +one. For most cases, this logic will follow the flow expressed above and JOSDK provides a very +convenient implementation of this logic in the form of the +[`AbstractDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java) +class. If your logic doesn't fit this pattern, though, you can still provide your +own `reconcile` method implementation. While the benefits of using dependent resources are less +obvious in that case, this allows you to separate the logic necessary to deal with each +secondary resource in its own class that can then be tested in isolation via unit tests. You can +also use the declarative support with your own implementations as we shall see later on. + +`AbstractDependentResource` is designed so that classes extending it specify which functionality +they support by implementing trait interfaces. This design has been selected to express the fact +that not all secondary resources are completely under the control of the primary reconciler: +some dependent resources are only ever created or updated for example and we needed a way to let +JOSDK know when that is the case. We therefore provide trait interfaces: `Creator`, +`Updater` and `Deleter` to express that the `DependentResource` implementation will provide custom +functionality to create, update and delete its associated secondary resources, respectively. If +these traits are not implemented then parts of the logic described above is never triggered: if +your implementation doesn't implement `Creator`, for example, `AbstractDependentResource` will +never try to create the associated secondary resource, even if it doesn't exist. It is even +possible to not implement any of these traits and therefore create read-only dependent resources +that will trigger your reconciler whenever a user interacts with them but that are never +modified by your reconciler itself - however note that read-only dependent resources rarely make +sense, as it is usually simpler to register an event source for the target resource. + +All subclasses +of [`AbstractDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractDependentResource.java) +can also implement +the [`Matcher`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/Matcher.java) +interface to customize how the SDK decides whether or not the actual state of the dependent +matches the desired state. This makes it convenient to use these abstract base classes for your +implementation, only customizing the matching logic. Note that in many cases, there is no need +to customize that logic as the SDK already provides convenient default implementations in the +form +of [`DesiredEqualsMatcher`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DesiredEqualsMatcher.java) +and +[`GenericKubernetesResourceMatcher`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java) +implementations, respectively. If you want to provide custom logic, you only need your +`DependentResource` implementation to implement the `Matcher` interface as below, which shows +how to customize the default matching logic for Kubernetes resources to also consider annotations +and labels, which are ignored by default: + +```java +public class MyDependentResource extends KubernetesDependentResource + implements Matcher { + // your implementation + + public Result match(MyDependent actualResource, MyPrimary primary, + Context context) { + return GenericKubernetesResourceMatcher.match(this, actualResource, primary, context, true); + } +} +``` + +### Batteries included: convenient DependentResource implementations! + +JOSDK also offers several other convenient implementations building on top of +`AbstractDependentResource` that you can use as starting points for your own implementations. + +One such implementation is the `KubernetesDependentResource` class that makes it really easy to work +with Kubernetes-native resources. In this case, you usually only need to provide an implementation +for the `desired` method to tell JOSDK what the desired state of your secondary resource should +be based on the specified primary resource state. + +JOSDK takes care of everything else using default implementations that you can override in case you +need more precise control of what's going on. + +We also provide implementations that make it easy to cache +(`AbstractExternalDependentResource`) or poll for changes in external resources +(`PollingDependentResource`, `PerResourcePollingDependentResource`). All the provided +implementations can be found in the `io/javaoperatorsdk/operator/processing/dependent` package of +the `operator-framework-core` module. + +### Sample Kubernetes Dependent Resource + +A typical use case, when a Kubernetes resource is fully managed - Created, Read, Updated and +Deleted (or set to be garbage collected). The following example shows how to create a +`Deployment` dependent resource: + +```java + +@KubernetesDependent(labelSelector = WebPageManagedDependentsReconciler.SELECTOR) +class DeploymentDependentResource extends CRUDKubernetesDependentResource { + + public DeploymentDependentResource() { + super(Deployment.class); + } + + @Override + protected Deployment desired(WebPage webPage, Context context) { + var deploymentName = deploymentName(webPage); + Deployment deployment = loadYaml(Deployment.class, getClass(), "deployment.yaml"); + deployment.getMetadata().setName(deploymentName); + deployment.getMetadata().setNamespace(webPage.getMetadata().getNamespace()); + deployment.getSpec().getSelector().getMatchLabels().put("app", deploymentName); + + deployment.getSpec().getTemplate().getMetadata().getLabels() + .put("app", deploymentName); + deployment.getSpec().getTemplate().getSpec().getVolumes().get(0) + .setConfigMap(new ConfigMapVolumeSourceBuilder().withName(configMapName(webPage)).build()); + return deployment; + } +} +``` + +The only thing that you need to do is to extend the `CRUDKubernetesDependentResource` and +specify the desired state for your secondary resources based on the state of the primary one. In +the example above, we're handling the state of a `Deployment` secondary resource associated with +a `WebPage` custom (primary) resource. + +The `@KubernetesDependent` annotation can be used to further configure **managed** dependent +resource that are extending `KubernetesDependentResource`. + +See the full source +code [here](https://github.com/operator-framework/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/DeploymentDependentResource.java) +. + +## Managed Dependent Resources + +As mentioned previously, one goal of this implementation is to make it possible to declaratively +create and wire dependent resources. You can annotate your reconciler with `@Dependent` +annotations that specify which `DependentResource` implementation it depends upon. +JOSDK will take the appropriate steps to wire everything together and call your +`DependentResource` implementations `reconcile` method before your primary resource is reconciled. +This makes sense in most use cases where the logic associated with the primary resource is +usually limited to status handling based on the state of the secondary resources and the +resources are not dependent on each other. + +See [Workflows](https://javaoperatorsdk.io/docs/workflows) for more details on how the dependent +resources are reconciled. + +This behavior and automated handling is referred to as "managed" because the `DependentResource` +instances are managed by JOSDK, an example of which can be seen below: + +```java + +@ControllerConfiguration( + labelSelector = SELECTOR, + dependents = { + @Dependent(type = ConfigMapDependentResource.class), + @Dependent(type = DeploymentDependentResource.class), + @Dependent(type = ServiceDependentResource.class) + }) +public class WebPageManagedDependentsReconciler + implements Reconciler, ErrorStatusHandler { + + // omitted code + + @Override + public UpdateControl reconcile(WebPage webPage, Context context) { + + final var name = context.getSecondaryResource(ConfigMap.class).orElseThrow() + .getMetadata().getName(); + webPage.setStatus(createStatus(name)); + return UpdateControl.patchStatus(webPage); + } + +} +``` + +See the full source code of +sample [here](https://github.com/operator-framework/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageManagedDependentsReconciler.java) +. + +## Standalone Dependent Resources + +It is also possible to wire dependent resources programmatically. In practice this means that the +developer is responsible for initializing and managing the dependent resources as well as calling +their `reconcile` method. However, this makes it possible for developers to fully customize the +reconciliation process. Standalone dependent resources should be used in cases when the managed use +case does not fit. + +Note that [Workflows](https://javaoperatorsdk.io/docs/workflows) also can be invoked from standalone +resources. + +The following sample is similar to the one above, simply performing additional checks, and +conditionally creating an `Ingress`: + +```java + +@ControllerConfiguration +public class WebPageStandaloneDependentsReconciler + implements Reconciler, ErrorStatusHandler, + EventSourceInitializer { + + private KubernetesDependentResource configMapDR; + private KubernetesDependentResource deploymentDR; + private KubernetesDependentResource serviceDR; + private KubernetesDependentResource ingressDR; + + public WebPageStandaloneDependentsReconciler(KubernetesClient kubernetesClient) { + // 1. + createDependentResources(kubernetesClient); + } + + @Override + public List prepareEventSources(EventSourceContext context) { + // 2. + return List.of( + configMapDR.initEventSource(context), + deploymentDR.initEventSource(context), + serviceDR.initEventSource(context)); + } + + @Override + public UpdateControl reconcile(WebPage webPage, Context context) { + + // 3. + if (!isValidHtml(webPage.getHtml())) { + return UpdateControl.patchStatus(setInvalidHtmlErrorMessage(webPage)); + } + + // 4. + configMapDR.reconcile(webPage, context); + deploymentDR.reconcile(webPage, context); + serviceDR.reconcile(webPage, context); + + // 5. + if (Boolean.TRUE.equals(webPage.getSpec().getExposed())) { + ingressDR.reconcile(webPage, context); + } else { + ingressDR.delete(webPage, context); + } + + // 6. + webPage.setStatus( + createStatus(configMapDR.getResource(webPage).orElseThrow().getMetadata().getName())); + return UpdateControl.patchStatus(webPage); + } + + private void createDependentResources(KubernetesClient client) { + this.configMapDR = new ConfigMapDependentResource(); + this.deploymentDR = new DeploymentDependentResource(); + this.serviceDR = new ServiceDependentResource(); + this.ingressDR = new IngressDependentResource(); + + Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR).forEach(dr -> { + dr.setKubernetesClient(client); + dr.configureWith(new KubernetesDependentResourceConfig() + .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR)); + }); + } + + // omitted code +} +``` + +There are multiple things happening here: + +1. Dependent resources are explicitly created and can be access later by reference. +2. Event sources are produced by the dependent resources, but needs to be explicitly registered in + this case by implementing + the [`EventSourceInitializer`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java) + interface. +3. The input html is validated, and error message is set in case it is invalid. +4. Reconciliation of dependent resources is called explicitly, but here the workflow + customization is fully in the hand of the developer. +5. An `Ingress` is created but only in case `exposed` flag set to true on custom resource. Tries to + delete it if not. +6. Status is set in a different way, this is just an alternative way to show, that the actual state + can be read using the reference. This could be written in a same way as in the managed example. + +See the full source code of +sample [here](https://github.com/operator-framework/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java) +. + +Note also the Workflows feature makes it possible to also support this conditional creation use +case in managed dependent resources. + +## Creating/Updating Kubernetes Resources + +From version 4.4 of the framework the resources are created and updated +using [Server Side Apply](https://kubernetes.io/docs/reference/using-api/server-side-apply/) +, thus the desired state is simply sent using this approach to update the actual resource. + +## Comparing desired and actual state (matching) + +During the reconciliation of a dependent resource, the desired state is matched with the actual +state from the caches. The dependent resource only gets updated on the server if the actual, +observed state differs from the desired one. Comparing these two states is a complex problem +when dealing with Kubernetes resources because a strict equality check is usually not what is +wanted due to the fact that multiple fields might be automatically updated or added by +the platform ( +by [dynamic admission controllers](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) +or validation webhooks, for example). Solving this problem in a generic way is therefore a tricky +proposition. + +JOSDK provides such a generic matching implementation which is used by default: +[SSABasedGenericKubernetesResourceMatcher](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java) +This implementation relies on the managed fields used by the Server Side Apply feature to +compare only the values of the fields that the controller manages. This ensures that only +semantically relevant fields are compared. See javadoc for further details. + +JOSDK versions prior to 4.4 were using a different matching algorithm as implemented in +[GenericKubernetesResourceMatcher](https://github.com/java-operator-sdk/java-operator-sdk/blob/e16559fd41bbb8bef6ce9d1f47bffa212a941b09/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java). + +Since SSA is a complex feature, JOSDK implements a feature flag allowing users to switch between +these implementations. See +in [ConfigurationService](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L332-L358). + +It is, however, important to note that these implementations are default, generic +implementations that the framework can provide expected behavior out of the box. In many +situations, these will work just fine but it is also possible to provide matching algorithms +optimized for specific use cases. This is easily done by simply overriding +the `match(...)` [method](https://github.com/java-operator-sdk/java-operator-sdk/blob/e16559fd41bbb8bef6ce9d1f47bffa212a941b09/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java#L156-L156). + +It is also possible to bypass the matching logic altogether to simply rely on the server-side +apply mechanism if always sending potentially unchanged resources to the cluster is not an issue. +JOSDK's matching mechanism allows to spare some potentially useless calls to the Kubernetes API +server. To bypass the matching feature completely, simply override the `match` method to always +return `false`, thus telling JOSDK that the actual state never matches the desired one, making +it always update the resources using SSA. + +WARNING: Older versions of Kubernetes before 1.25 would create an additional resource version for every SSA update +performed with certain resources - even though there were no actual changes in the stored resource - leading to infinite +reconciliations. This behavior was seen with Secrets using `stringData`, Ingresses using empty string fields, and +StatefulSets using volume claim templates. The operator framework has added built-in handling for the StatefulSet issue. +If you encounter this issue on an older Kubernetes version, consider changing your desired state, turning off SSA for +that resource, or even upgrading your Kubernetes version. If you encounter it on a newer Kubernetes version, please log +an issue with the JOSDK and with upstream Kubernetes. + +## Telling JOSDK how to find which secondary resources are associated with a given primary resource + +[`KubernetesDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java) +automatically maps secondary resource to a primary by owner reference. This behavior can be +customized by implementing +[`SecondaryToPrimaryMapper`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/SecondaryToPrimaryMapper.java) +by the dependent resource. + +See sample in one of the integration +tests [here](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/primaryindexer/DependentPrimaryIndexerTestReconciler.java#L25-L25) +. + +## Multiple Dependent Resources of Same Type + +When dealing with multiple dependent resources of same type, the dependent resource implementation +needs to know which specific resource should be targeted when reconciling a given dependent +resource, since there will be multiple instances of that type which could possibly be used, each +associated with the same primary resource. In order to do this, JOSDK relies on the +[resource discriminator](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceDiscriminator.java) +concept. Resource discriminators uniquely identify the target resource of a dependent resource. +In the managed Kubernetes dependent resources case, the discriminator can be declaratively set +using the `@KubernetesDependent` annotation: + +```java + +@KubernetesDependent(resourceDiscriminator = ConfigMap1Discriminator.class) +public class MultipleManagedDependentResourceConfigMap1 { +//... +} +``` + +Dependent resources usually also provide event sources. When dealing with multiple dependents of +the same type, one needs to decide whether these dependent resources should track the same +resources and therefore share a common event source, or, to the contrary, track completely +separate resources, in which case using separate event sources is advised. + +Dependents can therefore reuse existing, named event sources by referring to their name. In the +declarative case, assuming a `configMapSource` `EventSource` has already been declared, this +would look as follows: + +``` + @Dependent(type = MultipleManagedDependentResourceConfigMap1.class, + useEventSourceWithName = "configMapSource") +``` + +A sample is provided as an integration test both +for [managed](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleManagedDependentSameTypeIT.java) +and +for [standalone](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleDependentResourceIT.java) +cases. + +## Bulk Dependent Resources + +So far, all the cases we've considered were dealing with situations where the number of +dependent resources needed to reconcile the state expressed by the primary resource is known +when writing the code for the operator. There are, however, cases where the number of dependent +resources to be created depends on information found in the primary resource. + +These cases are covered by the "bulk" dependent resources feature. To create such dependent +resources, your implementation should extend `AbstractDependentResource` (at least indirectly) and +implement the +[`BulkDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/BulkDependentResource.java) +interface. + +Various examples are provided +as [integration tests](https://github.com/java-operator-sdk/java-operator-sdk/tree/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/bulkdependent) +. + +To see how bulk dependent resources interact with workflow conditions, please refer to this +[integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/bulkdependent/BulkDependentWithConditionIT.java). + +## External State Tracking Dependent Resources + +It is sometimes necessary for a controller to track external (i.e. non-Kubernetes) state to +properly manage some dependent resources. For example, your controller might need to track the +state of a REST API resource, which, after being created, would be refer to by its identifier. +Such identifier would need to be tracked by your controller to properly retrieve the state of +the associated resource and/or assess if such a resource exists. While there are several ways to +support this use case, we recommend storing such information in a dedicated Kubernetes resources +(usually a `ConfigMap` or a `Secret`), so that it can be manipulated with common Kubernetes +mechanisms. + +This particular use case is supported by the +[`AbstractExternalDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractExternalDependentResource.java) +class that you can extend to suit your needs, as well as implement the +[`DependentResourceWithExplicitState`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceWithExplicitState.java) +interface. Note that most of the JOSDK-provided dependent resource implementations such as +`PollingDependentResource` or `PerResourcePollingDependentResource` already extends +`AbstractExternalDependentResource`, thus supporting external state tracking out of the box. + +See [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/ExternalStateDependentIT.java) +as a sample. + +For a better understanding it might be worth to study +a [sample implementation](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/externalstate/ExternalStateReconciler.java) +without dependent resources. + +Please also refer to the [docs](/docs/patterns-best-practices#managing-state) for managing state in +general. + +## Combining Bulk and External State Tracking Dependent Resources + +Both bulk and external state tracking features can be combined. In that +case, a separate, state-tracking resource will be created for each bulk dependent resource +created. For example, if three bulk dependent resources associated with external state are created, +three associated `ConfigMaps` (assuming `ConfigMaps` are used as a state-tracking resource) will +also be created, one per dependent resource. + +See [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/ExternalStateBulkIT.java) +as a sample. + + +## GenericKubernetesResource based Dependent Resources + +In rare circumstances resource handling where there is no class representation or just typeless handling might be needed. +Fabric8 Client provides [GenericKubernetesResource](https://github.com/fabric8io/kubernetes-client/blob/main/doc/CHEATSHEET.md#resource-typeless-api) +to support that. + +For dependent resource this is supported by [GenericKubernetesDependentResource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesDependentResource.java#L8-L8) +. See samples [here](https://github.com/java-operator-sdk/java-operator-sdk/tree/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource). + +## Other Dependent Resource Features + +### Caching and Event Handling in [KubernetesDependentResource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java) + +1. When a Kubernetes resource is created or updated the related informer (more precisely + the `InformerEventSource`), eventually will receive an event and will cache the up-to-date + resource. Typically, though, there might be a small time window when calling the + `getResource()` of the dependent resource or getting the resource from the `EventSource` + itself won't return the just updated resource, in the case where the associated event hasn't + been received from the Kubernetes API. The `KubernetesDependentResource` implementation, + however, addresses this issue, so you don't have to worry about it by making sure that it or + the related `InformerEventSource` always return the up-to-date resource. + +2. Another feature of `KubernetesDependentResource` is to make sure that if a resource is created or + updated during the reconciliation, this particular change, which normally would trigger the + reconciliation again (since the resource has changed on the server), will, in fact, not + trigger the reconciliation again since we already know the state is as expected. This is a small + optimization. For example if during a reconciliation a `ConfigMap` is updated using dependent + resources, this won't trigger a new reconciliation. Such a reconciliation is indeed not + needed since the change originated from our reconciler. For this system to work properly, + though, it is required that changes are received only by one event source (this is a best + practice in general) - so for example if there are two config map dependents, either + there should be a shared event source between them, or a label selector on the event sources + to select only the relevant events, see + in [related integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/orderedmanageddependent/ConfigMapDependentResource1.java) + . + +## "Read-only" Dependent Resources vs. Event Source + +See Integration test for a read-only +dependent [here](https://github.com/java-operator-sdk/java-operator-sdk/blob/249b41f3c68c4d0e9c77c41eca647a69a24347b0/operator-framework/src/test/java/io/javaoperatorsdk/operator/PrimaryToSecondaryDependentIT.java). + +Some secondary resources only exist as input for the reconciliation process and are never +updated *by a controller* (they might, and actually usually do, get updated by users interacting +with the resources directly, however). This might be the case, for example, of a `ConfigMap`that is +used to configure common characteristics of multiple resources in one convenient place. + +In such situations, one might wonder whether it makes sense to create a dependent resource in +this case or simply use an `EventSource` so that the primary resource gets reconciled whenever a +user changes the resource. Typical dependent resources provide a desired state that the +reconciliation process attempts to match. In the case of so-called read-only dependents, though, +there is no such desired state because the operator / controller will never update the resource +itself, just react to external changes to it. An `EventSource` would achieve the same result. + +Using a dependent resource for that purpose instead of a simple `EventSource`, however, provides +several benefits: + +- dependents can be created declaratively, while an event source would need to be manually created +- if dependents are already used in a controller, it makes sense to unify the handling of all + secondary resources as dependents from a code organization perspective +- dependent resources can also interact with the workflow feature, thus allowing the read-only + resource to participate in conditions, in particular to decide whether the primary + resource needs/can be reconciled using reconcile pre-conditions, block the progression of the workflow altogether with + ready post-conditions or have other dependents depend on them, in essence, read-only dependents can participate in + workflows just as any other dependents. \ No newline at end of file diff --git a/docsy/content/en/docs/faq/_index.md b/docsy/content/en/docs/faq/_index.md new file mode 100644 index 0000000000..79264332ef --- /dev/null +++ b/docsy/content/en/docs/faq/_index.md @@ -0,0 +1,96 @@ +--- +title: FAQ +weight: 80 +--- + +### Q: How can I access the events which triggered the Reconciliation? + +In the v1.* version events were exposed to `Reconciler` (which was called `ResourceController` +then). This included events (Create, Update) of the custom resource, but also events produced by +Event Sources. After long discussions also with developers of golang version (controller-runtime), +we decided to remove access to these events. We already advocated to not use events in the +reconciliation logic, since events can be lost. Instead, reconcile all the resources on every +execution of reconciliation. On first this might sound a little opinionated, but there is a +sound agreement between the developers that this is the way to go. + +Note that this is also consistent with Kubernetes +[level based](https://cloud.redhat.com/blog/kubernetes-operators-best-practices) reconciliation approach. + +### Q: Can I re-schedule a reconciliation, possibly with a specific delay? + +Yes, this can be done +using [`UpdateControl`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/UpdateControl.java) +and [`DeleteControl`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DeleteControl.java) +, see: + +```java + @Override + public UpdateControl reconcile( + EventSourceTestCustomResource resource, Context context) { + ... + return UpdateControl.patchStatus(resource).rescheduleAfter(10, TimeUnit.SECONDS); + } +``` + +without an update: + +```java + @Override + public UpdateControl reconcile( + EventSourceTestCustomResource resource, Context context) { + ... + return UpdateControl.noUpdate().rescheduleAfter(10, TimeUnit.SECONDS); + } +``` + +Although you might consider using `EventSources`, to handle reconciliation triggering in a smarter +way. + +### Q: How can I run an operator without cluster scope rights? + +By default, JOSDK requires access to CRs at cluster scope. You may not be granted such +rights and you will see some error at startup that looks like: + +```plain +io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: https://kubernetes.local.svc/apis/mygroup/v1alpha1/mycr. Message: Forbidden! Configured service account doesn't have access. Service account may have been revoked. mycrs.mygroup is forbidden: User "system:serviceaccount:ns:sa" cannot list resource "mycrs" in API group "mygroup" at the cluster scope. +``` + +To restrict the operator to a set of namespaces, you may override which namespaces are watched by a reconciler +at [Reconciler-level configuration](./configuration.md#reconciler-level-configuration): + +```java +Operator operator; +Reconciler reconciler; +... +operator.register(reconciler, configOverrider -> + configOverrider.settingNamespace("mynamespace")); +``` +Note that configuring the watched namespaces can also be done using the `@ControllerConfiguration` annotation. + +Furthermore, you may not be able to list CRDs at startup which is required when `checkingCRDAndValidateLocalModel` +is `true` (`false` by default). To disable, set it to `false` at [Operator-level configuration](./configuration.md#operator-level-configuration): + +```java +Operator operator = new Operator( override -> override.checkingCRDAndValidateLocalModel(false)); +``` + +### Q: How to fix `sun.security.provider.certpath.SunCertPathBuilderException` on Rancher Desktop and k3d/k3s Kubernetes + +It's a common issue when using k3d and the fabric8 client tries to connect to the cluster an exception is thrown: + +``` +Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target + at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131) + at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:352) + at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:295) +``` + +The cause is that fabric8 kubernetes client does not handle elliptical curve encryption by default. To fix this, add +the following dependency on the classpath: + +```xml + + org.bouncycastle + bcpkix-jdk15on + +``` \ No newline at end of file diff --git a/docsy/content/en/docs/features/_index.md b/docsy/content/en/docs/features/_index.md new file mode 100644 index 0000000000..b1f0ff166f --- /dev/null +++ b/docsy/content/en/docs/features/_index.md @@ -0,0 +1,860 @@ +--- +title: Features +weight: 50 +--- + +The Java Operator SDK (JOSDK) is a high level framework and related tooling aimed at +facilitating the implementation of Kubernetes operators. The features are by default following +the best practices in an opinionated way. However, feature flags and other configuration options +are provided to fine tune or turn off these features. + +## Reconciliation Execution in a Nutshell + +Reconciliation execution is always triggered by an event. Events typically come from a +primary resource, most of the time a custom resource, triggered by changes made to that resource +on the server (e.g. a resource is created, updated or deleted). Reconciler implementations are +associated with a given resource type and listens for such events from the Kubernetes API server +so that they can appropriately react to them. It is, however, possible for secondary sources to +trigger the reconciliation process. This usually occurs via +the [event source](#handling-related-events-with-event-sources) mechanism. + +When an event is received reconciliation is executed, unless a reconciliation is already +underway for this particular resource. In other words, the framework guarantees that no +concurrent reconciliation happens for any given resource. + +Once the reconciliation is done, the framework checks if: + +- an exception was thrown during execution and if yes schedules a retry. +- new events were received during the controller execution, if yes schedule a new reconciliation. +- the reconcilier instructed the SDK to re-schedule a reconciliation at a later date, if yes + schedules a timer event with the specified delay. +- none of the above, the reconciliation is finished. + +In summary, the core of the SDK is implemented as an eventing system, where events trigger +reconciliation requests. + +## Implementing a [`Reconciler`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java) and/or [`Cleaner`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Cleaner.java) + +The lifecycle of a Kubernetes resource can be clearly separated into two phases from the +perspective of an operator depending on whether a resource is created or updated, or on the +other hand if it is marked for deletion. + +This separation-related logic is automatically handled by the framework. The framework will always +call the `reconcile` method, unless the custom resource is +[marked from deletion](https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers/#how-finalizers-work) +. On the other, if the resource is marked from deletion and if the `Reconciler` implements the +`Cleaner` interface, only the `cleanup` method will be called. Implementing the `Cleaner` +interface allows developers to let the SDK know that they are interested in cleaning related +state (e.g. out-of-cluster resources). The SDK will therefore automatically add a finalizer +associated with your `Reconciler` so that the Kubernetes server doesn't delete your resources +before your `Reconciler` gets a chance to clean things up. +See [Finalizer support](#finalizer-support) for more details. + +### Using `UpdateControl` and `DeleteControl` + +These two classes are used to control the outcome or the desired behaviour after the reconciliation. + +The [`UpdateControl`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/UpdateControl.java) +can instruct the framework to update the status sub-resource of the resource +and/or re-schedule a reconciliation with a desired time delay: + +```java + @Override + public UpdateControl reconcile( + EventSourceTestCustomResource resource, Context context) { + ... + return UpdateControl.patchStatus(resource).rescheduleAfter(10, TimeUnit.SECONDS); + } +``` + +without an update: + +```java + @Override + public UpdateControl reconcile( + EventSourceTestCustomResource resource, Context context) { + ... + return UpdateControl.noUpdate().rescheduleAfter(10, TimeUnit.SECONDS); + } +``` + +Note, though, that using `EventSources` should be preferred to rescheduling since the +reconciliation will then be triggered only when needed instead than on a timely basis. + +Those are the typical use cases of resource updates, however in some cases there it can happen that +the controller wants to update the resource itself (for example to add annotations) or not perform +any updates, which is also supported. + +It is also possible to update both the status and the resource with the +`updateResourceAndStatus` method. In this case, the resource is updated first followed by the +status, using two separate requests to the Kubernetes API. + +You should always state your intent using `UpdateControl` and let the SDK deal with the actual +updates instead of performing these updates yourself using the actual Kubernetes client so that +the SDK can update its internal state accordingly. + +Resource updates are protected using optimistic version control, to make sure that other updates +that might have occurred in the mean time on the server are not overwritten. This is ensured by +setting the `resourceVersion` field on the processed resources. + +[`DeleteControl`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DeleteControl.java) +typically instructs the framework to remove the finalizer after the dependent +resource are cleaned up in `cleanup` implementation. + +```java + +public DeleteControl cleanup(MyCustomResource customResource,Context context){ + ... + return DeleteControl.defaultDelete(); + } + +``` + +However, it is possible to instruct the SDK to not remove the finalizer, this allows to clean up +the resources in a more asynchronous way, mostly for cases when there is a long waiting period +after a delete operation is initiated. Note that in this case you might want to either schedule +a timed event to make sure `cleanup` is executed again or use event sources to get notified +about the state changes of the deleted resource. + +### Finalizer Support + +[Kubernetes finalizers](https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers/) +make sure that your `Reconciler` gets a chance to act before a resource is actually deleted +after it's been marked for deletion. Without finalizers, the resource would be deleted directly +by the Kubernetes server. + +Depending on your use case, you might or might not need to use finalizers. In particular, if +your operator doesn't need to clean any state that would not be automatically managed by the +Kubernetes cluster (e.g. external resources), you might not need to use finalizers. You should +use the +Kubernetes [garbage collection](https://kubernetes.io/docs/concepts/architecture/garbage-collection/#owners-dependents) +mechanism as much as possible by setting owner references for your secondary resources so that +the cluster can automatically deleted them for you whenever the associated primary resource is +deleted. Note that setting owner references is the responsibility of the `Reconciler` +implementation, though [dependent resources](https://javaoperatorsdk.io/docs/dependent-resources) +make that process easier. + +If you do need to clean such state, you need to use finalizers so that their +presence will prevent the Kubernetes server from deleting the resource before your operator is +ready to allow it. This allows for clean up to still occur even if your operator was down when +the resources was "deleted" by a user. + +JOSDK makes cleaning resources in this fashion easier by taking care of managing finalizers +automatically for you when needed. The only thing you need to do is let the SDK know that your +operator is interested in cleaning state associated with your primary resources by having it +implement +the [`Cleaner

`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Cleaner.java) +interface. If your `Reconciler` doesn't implement the `Cleaner` interface, the SDK will consider +that you don't need to perform any clean-up when resources are deleted and will therefore not +activate finalizer support. In other words, finalizer support is added only if your `Reconciler` +implements the `Cleaner` interface. + +Finalizers are automatically added by the framework as the first step, thus after a resource +is created, but before the first reconciliation. The finalizer is added via a separate +Kubernetes API call. As a result of this update, the finalizer will then be present on the +resource. The reconciliation can then proceed as normal. + +The finalizer that is automatically added will be also removed after the `cleanup` is executed on +the reconciler. This behavior is customizable as explained +[above](#using-updatecontrol-and-deletecontrol) when we addressed the use of +`DeleteControl`. + +You can specify the name of the finalizer to use for your `Reconciler` using the +[`@ControllerConfiguration`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java) +annotation. If you do not specify a finalizer name, one will be automatically generated for you. + +## Automatic Observed Generation Handling + +Having an `.observedGeneration` value on your resources' status is a best practice to +indicate the last generation of the resource which was successfully reconciled by the controller. +This helps users / administrators diagnose potential issues. + +In order to have this feature working: + +- the **status class** (not the resource itself) must implement the + [`ObservedGenerationAware`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/ObservedGenerationAware.java) + interface. See also + the [`ObservedGenerationAwareStatus`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/ObservedGenerationAwareStatus.java) + convenience implementation that you can extend in your own status class implementations. +- The other condition is that the `CustomResource.getStatus()` method should not return `null`. + So the status should be instantiated when the object is returned using the `UpdateControl`. + +If these conditions are fulfilled and generation awareness is activated, the observed generation +is automatically set by the framework after the `reconcile` method is called. Note that the +observed generation is also updated even when `UpdateControl.noUpdate()` is returned from the +reconciler. See this feature at work in +the [WebPage example](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStatus.java#L5) +. + +```java +public class WebPageStatus extends ObservedGenerationAwareStatus { + + private String htmlConfigMap; + + ... +} +``` + +Initializing status automatically on custom resource could be done by overriding the `initStatus` method +of `CustomResource`. However, this is NOT advised, since breaks the status patching if you use: +`UpdateControl.patchStatus`. See +also [javadocs](https://github.com/java-operator-sdk/java-operator-sdk/blob/3994f5ffc1fb000af81aa198abf72a5f75fd3e97/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/UpdateControl.java#L41-L42) +. + +```java +@Group("sample.javaoperatorsdk") +@Version("v1") +public class WebPage extends CustomResource + implements Namespaced { + + @Override + protected WebPageStatus initStatus() { + return new WebPageStatus(); + } +} +``` + +## Generation Awareness and Event Filtering + +A best practice when an operator starts up is to reconcile all the associated resources because +changes might have occurred to the resources while the operator was not running. + +When this first reconciliation is done successfully, the next reconciliation is triggered if either +dependent resources are changed or the primary resource `.spec` field is changed. If other fields +like `.metadata` are changed on the primary resource, the reconciliation could be skipped. This +behavior is supported out of the box and reconciliation is by default not triggered if +changes to the primary resource do not increase the `.metadata.generation` field. +Note that changes to `.metada.generation` are automatically handled by Kubernetes. + +To turn off this feature, set `generationAwareEventProcessing` to `false` for the `Reconciler`. + +## Support for Well Known (non-custom) Kubernetes Resources + +A Controller can be registered for a non-custom resource, so well known Kubernetes resources like ( +`Ingress`, `Deployment`,...). Note that automatic observed generation handling is not supported +for these resources, though, in this case, the handling of the observed generation is probably +handled by the primary controller. + +See +the [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/deployment/DeploymentReconciler.java) +for reconciling deployments. + +```java +public class DeploymentReconciler + implements Reconciler, TestExecutionInfoProvider { + + @Override + public UpdateControl reconcile( + Deployment resource, Context context) { + ... + } +``` + +## Max Interval Between Reconciliations + +When informers / event sources are properly set up, and the `Reconciler` implementation is +correct, no additional reconciliation triggers should be needed. However, it's +a [common practice](https://github.com/java-operator-sdk/java-operator-sdk/issues/848#issuecomment-1016419966) +to have a failsafe periodic trigger in place, just to make sure resources are nevertheless +reconciled after a certain amount of time. This functionality is in place by default, with a +rather high time interval (currently 10 hours) after which a reconciliation will be +automatically triggered even in the absence of other events. See how to override this using the +standard annotation: + +```java +@ControllerConfiguration(maxReconciliationInterval = @MaxReconciliationInterval( + interval = 50, + timeUnit = TimeUnit.MILLISECONDS)) +``` + +The event is not propagated at a fixed rate, rather it's scheduled after each reconciliation. So the +next reconciliation will occur at most within the specified interval after the last reconciliation. + +This feature can be turned off by setting `maxReconciliationInterval` +to [`Constants.NO_MAX_RECONCILIATION_INTERVAL`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Constants.java#L20-L20) +or any non-positive number. + +The automatic retries are not affected by this feature so a reconciliation will be re-triggered +on error, according to the specified retry policy, regardless of this maximum interval setting. + +## Automatic Retries on Error + +JOSDK will schedule an automatic retry of the reconciliation whenever an exception is thrown by +your `Reconciler`. The retry is behavior is configurable but a default implementation is provided +covering most of the typical use-cases, see +[GenericRetry](https://github.com/java-operator-sdk/java-operator-sdk/blob/master/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/retry/GenericRetry.java) +. + +```java + GenericRetry.defaultLimitedExponentialRetry() + .setInitialInterval(5000) + .setIntervalMultiplier(1.5D) + .setMaxAttempts(5); +``` + +You can also configure the default retry behavior using the `@GradualRetry` annotation. + +It is possible to provide a custom implementation using the `retry` field of the +`@ControllerConfiguration` annotation and specifying the class of your custom implementation. +Note that this class will need to provide an accessible no-arg constructor for automated +instantiation. Additionally, your implementation can be automatically configured from an +annotation that you can provide by having your `Retry` implementation implement the +`AnnotationConfigurable` interface, parameterized with your annotation type. See the +`GenericRetry` implementation for more details. + +Information about the current retry state is accessible from +the [Context](https://github.com/java-operator-sdk/java-operator-sdk/blob/master/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/Context.java) +object. Of note, particularly interesting is the `isLastAttempt` method, which could allow your +`Reconciler` to implement a different behavior based on this status, by setting an error message +in your resource' status, for example, when attempting a last retry. + +Note, though, that reaching the retry limit won't prevent new events to be processed. New +reconciliations will happen for new events as usual. However, if an error also occurs that +would normally trigger a retry, the SDK won't schedule one at this point since the retry limit +is already reached. + +A successful execution resets the retry state. + +### Setting Error Status After Last Retry Attempt + +In order to facilitate error reporting, `Reconciler` can implement the +[ErrorStatusHandler](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusHandler.java) +interface: + +```java +public interface ErrorStatusHandler

{ + + ErrorStatusUpdateControl

updateErrorStatus(P resource, Context

context, Exception e); + +} +``` + +The `updateErrorStatus` method is called in case an exception is thrown from the `Reconciler`. It is +also called even if no retry policy is configured, just after the reconciler execution. +`RetryInfo.getAttemptCount()` is zero after the first reconciliation attempt, since it is not a +result of a retry (regardless of whether a retry policy is configured or not). + +`ErrorStatusUpdateControl` is used to tell the SDK what to do and how to perform the status +update on the primary resource, always performed as a status sub-resource request. Note that +this update request will also produce an event, and will result in a reconciliation if the +controller is not generation aware. + +This feature is only available for the `reconcile` method of the `Reconciler` interface, since +there should not be updates to resource that have been marked for deletion. + +Retry can be skipped in cases of unrecoverable errors: + +```java + ErrorStatusUpdateControl.patchStatus(customResource).withNoRetry(); +``` + +### Correctness and Automatic Retries + +While it is possible to deactivate automatic retries, this is not desirable, unless for very +specific reasons. Errors naturally occur, whether it be transient network errors or conflicts +when a given resource is handled by a `Reconciler` but is modified at the same time by a user in +a different process. Automatic retries handle these cases nicely and will usually result in a +successful reconciliation. + +## Retry and Rescheduling and Event Handling Common Behavior + +Retry, reschedule and standard event processing form a relatively complex system, each of these +functionalities interacting with the others. In the following, we describe the interplay of +these features: + +1. A successful execution resets a retry and the rescheduled executions which were present before + the reconciliation. However, a new rescheduling can be instructed from the reconciliation + outcome (`UpdateControl` or `DeleteControl`). + + For example, if a reconciliation had previously been re-scheduled after some amount of time, but an event triggered + the reconciliation (or cleanup) in the mean time, the scheduled execution would be automatically cancelled, i.e. + re-scheduling a reconciliation does not guarantee that one will occur exactly at that time, it simply guarantees that + one reconciliation will occur at that time at the latest, triggering one if no event from the cluster triggered one. + Of course, it's always possible to re-schedule a new reconciliation at the end of that "automatic" reconciliation. + + Similarly, if a retry was scheduled, any event from the cluster triggering a successful execution in the mean time + would cancel the scheduled retry (because there's now no point in retrying something that already succeeded) + +2. In case an exception happened, a retry is initiated. However, if an event is received + meanwhile, it will be reconciled instantly, and this execution won't count as a retry attempt. +3. If the retry limit is reached (so no more automatic retry would happen), but a new event + received, the reconciliation will still happen, but won't reset the retry, and will still be + marked as the last attempt in the retry info. The point (1) still holds, but in case of an + error, no retry will happen. + +The thing to keep in mind when it comes to retrying or rescheduling is that JOSDK tries to avoid unnecessary work. When +you reschedule an operation, you instruct JOSDK to perform that operation at the latest by the end of the rescheduling +delay. If something occurred on the cluster that triggers that particular operation (reconciliation or cleanup), then +JOSDK considers that there's no point in attempting that operation again at the end of the specified delay since there +is now no point to do so anymore. The same idea also applies to retries. + +## Rate Limiting + +It is possible to rate limit reconciliation on a per-resource basis. The rate limit also takes +precedence over retry/re-schedule configurations: for example, even if a retry was scheduled for +the next second but this request would make the resource go over its rate limit, the next +reconciliation will be postponed according to the rate limiting rules. Note that the +reconciliation is never cancelled, it will just be executed as early as possible based on rate +limitations. + +Rate limiting is by default turned **off**, since correct configuration depends on the reconciler +implementation, in particular, on how long a typical reconciliation takes. +(The parallelism of reconciliation itself can be +limited [`ConfigurationService`](https://github.com/java-operator-sdk/java-operator-sdk/blob/ce4d996ee073ebef5715737995fc3d33f4751275/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L120-L120) +by configuring the `ExecutorService` appropriately.) + +A default rate limiter implementation is provided, see: +[`PeriodRateLimiter`](https://github.com/java-operator-sdk/java-operator-sdk/blob/ce4d996ee073ebef5715737995fc3d33f4751275/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/rate/PeriodRateLimiter.java#L14-L14) +. +Users can override it by implementing their own +[`RateLimiter`](https://github.com/java-operator-sdk/java-operator-sdk/blob/ce4d996ee073ebef5715737995fc3d33f4751275/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/rate/RateLimiter.java) +and specifying this custom implementation using the `rateLimiter` field of the +`@ControllerConfiguration` annotation. Similarly to the `Retry` implementations, +`RateLimiter` implementations must provide an accessible, no-arg constructor for instantiation +purposes and can further be automatically configured from your own, provided annotation provided +your `RateLimiter` implementation also implements the `AnnotationConfigurable` interface, +parameterized by your custom annotation type. + +To configure the default rate limiter use the `@RateLimited` annotation on your +`Reconciler` class. The following configuration limits each resource to reconcile at most twice +within a 3 second interval: + +```java + +@RateLimited(maxReconciliations = 2, within = 3, unit = TimeUnit.SECONDS) +@ControllerConfiguration +public class MyReconciler implements Reconciler { + +} +``` + +Thus, if a given resource was reconciled twice in one second, no further reconciliation for this +resource will happen before two seconds have elapsed. Note that, since rate is limited on a +per-resource basis, other resources can still be reconciled at the same time, as long, of course, +that they stay within their own rate limits. + +## Handling Related Events with Event Sources + +See also +this [blog post](https://csviri.medium.com/java-operator-sdk-introduction-to-event-sources-a1aab5af4b7b) +. + +Event sources are a relatively simple yet powerful and extensible concept to trigger controller +executions, usually based on changes to dependent resources. You typically need an event source +when you want your `Reconciler` to be triggered when something occurs to secondary resources +that might affect the state of your primary resource. This is needed because a given +`Reconciler` will only listen by default to events affecting the primary resource type it is +configured for. Event sources act as listen to events affecting these secondary resources so +that a reconciliation of the associated primary resource can be triggered when needed. Note that +these secondary resources need not be Kubernetes resources. Typically, when dealing with +non-Kubernetes objects or services, we can extend our operator to handle webhooks or websockets +or to react to any event coming from a service we interact with. This allows for very efficient +controller implementations because reconciliations are then only triggered when something occurs +on resources affecting our primary resources thus doing away with the need to periodically +reschedule reconciliations. + +![Event Sources architecture diagram](../assets/images/event-sources.png) + +There are few interesting points here: + +The `CustomResourceEventSource` event source is a special one, responsible for handling events +pertaining to changes affecting our primary resources. This `EventSource` is always registered +for every controller automatically by the SDK. It is important to note that events always relate +to a given primary resource. Concurrency is still handled for you, even in the presence of +`EventSource` implementations, and the SDK still guarantees that there is no concurrent execution of +the controller for any given primary resource (though, of course, concurrent/parallel executions +of events pertaining to other primary resources still occur as expected). + +### Caching and Event Sources + +Kubernetes resources are handled in a declarative manner. The same also holds true for event +sources. For example, if we define an event source to watch for changes of a Kubernetes Deployment +object using an `InformerEventSource`, we always receive the whole associated object from the +Kubernetes API. This object might be needed at any point during our reconciliation process and +it's best to retrieve it from the event source directly when possible instead of fetching it +from the Kubernetes API since the event source guarantees that it will provide the latest +version. Not only that, but many event source implementations also cache resources they handle +so that it's possible to retrieve the latest version of resources without needing to make any +calls to the Kubernetes API, thus allowing for very efficient controller implementations. + +Note after an operator starts, caches are already populated by the time the first reconciliation +is processed for the `InformerEventSource` implementation. However, this does not necessarily +hold true for all event source implementations (`PerResourceEventSource` for example). The SDK +provides methods to handle this situation elegantly, allowing you to check if an object is +cached, retrieving it from a provided supplier if not. See +related [method](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java#L146) +. + +### Registering Event Sources + +To register event sources, your `Reconciler` has to implement the +[`EventSourceInitializer`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java) +interface and initialize a list of event sources to register. One way to see this in action is +to look at the +[tomcat example](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatReconciler.java) +(irrelevant details omitted): + +```java + +@ControllerConfiguration +public class TomcatReconciler implements Reconciler, EventSourceInitializer { + + @Override + public List prepareEventSources(EventSourceContext context) { + var configMapEventSource = + new InformerEventSource<>(InformerConfiguration.from(Deployment.class, context) + .withLabelSelector(SELECTOR) + .withSecondaryToPrimaryMapper( + Mappers.fromAnnotation(ANNOTATION_NAME, ANNOTATION_NAMESPACE) + .build(), context)); + return EventSourceInitializer.nameEventSources(configMapEventSource); + } + ... +} +``` + +In the example above an `InformerEventSource` is configured and registered. +`InformerEventSource` is one of the bundled `EventSource` implementations that JOSDK provides to +cover common use cases. + +### Managing Relation between Primary and Secondary Resources + +Event sources let your operator know when a secondary resource has changed and that your +operator might need to reconcile this new information. However, in order to do so, the SDK needs +to somehow retrieve the primary resource associated with which ever secondary resource triggered +the event. In the `Tomcat` example above, when an event occurs on a tracked `Deployment`, the +SDK needs to be able to identify which `Tomcat` resource is impacted by that change. + +Seasoned Kubernetes users already know one way to track this parent-child kind of relationship: +using owner references. Indeed, that's how the SDK deals with this situation by default as well, +that is, if your controller properly set owner references on your secondary resources, the SDK +will be able to follow that reference back to your primary resource automatically without you +having to worry about it. + +However, owner references cannot always be used as they are restricted to operating within a +single namespace (i.e. you cannot have an owner reference to a resource in a different namespace) +and are, by essence, limited to Kubernetes resources so you're out of luck if your secondary +resources live outside of a cluster. + +This is why JOSDK provides the `SecondayToPrimaryMapper` interface so that you can provide +alternative ways for the SDK to identify which primary resource needs to be reconciled when +something occurs to your secondary resources. We even provide some of these alternatives in the +[Mappers](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/Mappers.java) +class. + +Note that, while a set of `ResourceID` is returned, this set usually consists only of one +element. It is however possible to return multiple values or even no value at all to cover some +rare corner cases. Returning an empty set means that the mapper considered the secondary +resource event as irrelevant and the SDK will thus not trigger a reconciliation of the primary +resource in that situation. + +Adding a `SecondaryToPrimaryMapper` is typically sufficient when there is a one-to-many relationship +between primary and secondary resources. The secondary resources can be mapped to its primary +owner, and this is enough information to also get these secondary resources from the `Context` +object that's passed to your `Reconciler`. + +There are however cases when this isn't sufficient and you need to provide an explicit mapping +between a primary resource and its associated secondary resources using an implementation of the +`PrimaryToSecondaryMapper` interface. This is typically needed when there are many-to-one or +many-to-many relationships between primary and secondary resources, e.g. when the primary resource +is referencing secondary resources. +See [PrimaryToSecondaryIT](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/PrimaryToSecondaryIT.java) +integration test for a sample. + +### Built-in EventSources + +There are multiple event-sources provided out of the box, the following are some more central ones: + +#### `InformerEventSource` + +[InformerEventSource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java) +is probably the most important `EventSource` implementation to know about. When you create an +`InformerEventSource`, JOSDK will automatically create and register a `SharedIndexInformer`, a +fabric8 Kubernetes client class, that will listen for events associated with the resource type +you configured your `InformerEventSource` with. If you want to listen to Kubernetes resource +events, `InformerEventSource` is probably the only thing you need to use. It's highly +configurable so you can tune it to your needs. Take a look at +[InformerConfiguration](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java) +and associated classes for more details but some interesting features we can mention here is the +ability to filter events so that you can only get notified for events you care about. A +particularly interesting feature of the `InformerEventSource`, as opposed to using your own +informer-based listening mechanism is that caches are particularly well optimized preventing +reconciliations from being triggered when not needed and allowing efficient operators to be written. + +#### `PerResourcePollingEventSource` + +[PerResourcePollingEventSource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PerResourcePollingEventSource.java) +is used to poll external APIs, which don't support webhooks or other event notifications. It +extends the abstract +[ExternalResourceCachingEventSource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/ExternalResourceCachingEventSource.java) +to support caching. +See [MySQL Schema sample](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java) +for usage. + +#### `PollingeEventSource` + +[PollingEventSource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java) +is similar to `PerResourceCachingEventSource` except that, contrary to that event source, it +doesn't poll a specific API separately per resource, but periodically and independently of +actually observed primary resources. + +#### Inbound event sources + +[SimpleInboundEventSource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/inbound/SimpleInboundEventSource.java) +and +[CachingInboundEventSource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/inbound/CachingInboundEventSource.java) +are used to handle incoming events from webhooks and messaging systems. + +#### `ControllerResourceEventSource` + +[ControllerResourceEventSource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerResourceEventSource.java) +is a special `EventSource` implementation that you will never have to deal with directly. It is, +however, at the core of the SDK is automatically added for you: this is the main event source +that listens for changes to your primary resources and triggers your `Reconciler` when needed. +It features smart caching and is really optimized to minimize Kubernetes API accesses and avoid +triggering unduly your `Reconciler`. + +More on the philosophy of the non Kubernetes API related event source see in +issue [#729](https://github.com/java-operator-sdk/java-operator-sdk/issues/729). + +## Contextual Info for Logging with MDC + +Logging is enhanced with additional contextual information using +[MDC](http://www.slf4j.org/manual.html#mdc). The following attributes are available in most +parts of reconciliation logic and during the execution of the controller: + +| MDC Key | Value added from primary resource | +|:---------------------------|:----------------------------------| +| `resource.apiVersion` | `.apiVersion` | +| `resource.kind` | `.kind` | +| `resource.name` | `.metadata.name` | +| `resource.namespace` | `.metadata.namespace` | +| `resource.resourceVersion` | `.metadata.resourceVersion` | +| `resource.generation` | `.metadata.generation` | +| `resource.uid` | `.metadata.uid` | + +For more information about MDC see this [link](https://www.baeldung.com/mdc-in-log4j-2-logback). + +## Dynamically Changing Target Namespaces + +A controller can be configured to watch a specific set of namespaces in addition of the +namespace in which it is currently deployed or the whole cluster. The framework supports +dynamically changing the list of these namespaces while the operator is running. +When a reconciler is registered, an instance of +[`RegisteredController`](https://github.com/java-operator-sdk/java-operator-sdk/blob/ec37025a15046d8f409c77616110024bf32c3416/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/RegisteredController.java#L5) +is returned, providing access to the methods allowing users to change watched namespaces as the +operator is running. + +A typical scenario would probably involve extracting the list of target namespaces from a +`ConfigMap` or some other input but this part is out of the scope of the framework since this is +use-case specific. For example, reacting to changes to a `ConfigMap` would probably involve +registering an associated `Informer` and then calling the `changeNamespaces` method on +`RegisteredController`. + +```java + +public static void main(String[]args)throws IOException{ + KubernetesClient client=new DefaultKubernetesClient(); + Operator operator=new Operator(client); + RegisteredController registeredController=operator.register(new WebPageReconciler(client)); + operator.installShutdownHook(); + operator.start(); + + // call registeredController further while operator is running + } + +``` + +If watched namespaces change for a controller, it might be desirable to propagate these changes to +`InformerEventSources` associated with the controller. In order to express this, +`InformerEventSource` implementations interested in following such changes need to be +configured appropriately so that the `followControllerNamespaceChanges` method returns `true`: + +```java + +@ControllerConfiguration +public class MyReconciler + implements Reconciler, EventSourceInitializer { + + @Override + public Map prepareEventSources( + EventSourceContext context) { + + InformerEventSource configMapES = + new InformerEventSource<>(InformerConfiguration.from(ConfigMap.class) + .withNamespacesInheritedFromController(context) + .build(), context); + + return EventSourceInitializer.nameEventSources(configMapES); + } + +} +``` + +As seen in the above code snippet, the informer will have the initial namespaces inherited from +controller, but also will adjust the target namespaces if it changes for the controller. + +See also +the [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/ec37025a15046d8f409c77616110024bf32c3416/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/changenamespace/ChangeNamespaceTestReconciler.java) +for this feature. + +## Leader Election + +Operators are generally deployed with a single running or active instance. However, it is +possible to deploy multiple instances in such a way that only one, called the "leader", processes the +events. This is achieved via a mechanism called "leader election". While all the instances are +running, and even start their event sources to populate the caches, only the leader will process +the events. This means that should the leader change for any reason, for example because it +crashed, the other instances are already warmed up and ready to pick up where the previous +leader left off should one of them become elected leader. + +See sample configuration in +the [E2E test](https://github.com/java-operator-sdk/java-operator-sdk/blob/8865302ac0346ee31f2d7b348997ec2913d5922b/sample-operators/leader-election/src/main/java/io/javaoperatorsdk/operator/sample/LeaderElectionTestOperator.java#L21-L23) +. + +## Runtime Info + +[RuntimeInfo](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/RuntimeInfo.java#L16-L16) +is used mainly to check the actual health of event sources. Based on this information it is easy to implement custom +liveness probes. + +[stopOnInformerErrorDuringStartup](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L168-L168) +setting, where this flag usually needs to be set to false, in order to control the exact liveness properties. + +See also an example implementation in the +[WebPage sample](https://github.com/java-operator-sdk/java-operator-sdk/blob/3e2e7c4c834ef1c409d636156b988125744ca911/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageOperator.java#L38-L43) + +## Automatic Generation of CRDs + +Note that this feature is provided by the +[Fabric8 Kubernetes Client](https://github.com/fabric8io/kubernetes-client), not JOSDK itself. + +To automatically generate CRD manifests from your annotated Custom Resource classes, you only need +to add the following dependencies to your project: + +```xml + + + io.fabric8 + crd-generator-apt + provided + +``` + +The CRD will be generated in `target/classes/META-INF/fabric8` (or +in `target/test-classes/META-INF/fabric8`, if you use the `test` scope) with the CRD name +suffixed by the generated spec version. For example, a CR using the `java-operator-sdk.io` group +with a `mycrs` plural form will result in 2 files: + +- `mycrs.java-operator-sdk.io-v1.yml` +- `mycrs.java-operator-sdk.io-v1beta1.yml` + +**NOTE:** +> Quarkus users using the `quarkus-operator-sdk` extension do not need to add any extra dependency +> to get their CRD generated as this is handled by the extension itself. + +## Metrics + +JOSDK provides built-in support for metrics reporting on what is happening with your reconcilers in the form of +the `Metrics` interface which can be implemented to connect to your metrics provider of choice, JOSDK calling the +methods as it goes about reconciling resources. By default, a no-operation implementation is provided thus providing a +no-cost sane default. A [micrometer](https://micrometer.io)-based implementation is also provided. + +You can use a different implementation by overriding the default one provided by the default `ConfigurationService`, as +follows: + +```java +Metrics metrics= …; +Operator operator = new Operator(client, o -> o.withMetrics()); +``` + +### Micrometer implementation + +The micrometer implementation is typically created using one of the provided factory methods which, depending on which +is used, will return either a ready to use instance or a builder allowing users to customized how the implementation +behaves, in particular when it comes to the granularity of collected metrics. It is, for example, possible to collect +metrics on a per-resource basis via tags that are associated with meters. This is the default, historical behavior but +this will change in a future version of JOSDK because this dramatically increases the cardinality of metrics, which +could lead to performance issues. + +To create a `MicrometerMetrics` implementation that behaves how it has historically behaved, you can just create an +instance via: + +```java +MeterRegistry registry= …; +Metrics metrics=new MicrometerMetrics(registry) +``` + +Note, however, that this constructor is deprecated and we encourage you to use the factory methods instead, which either +return a fully pre-configured instance or a builder object that will allow you to configure more easily how the instance +will behave. You can, for example, configure whether or not the implementation should collect metrics on a per-resource +basis, whether or not associated meters should be removed when a resource is deleted and how the clean-up is performed. +See the relevant classes documentation for more details. + +For example, the following will create a `MicrometerMetrics` instance configured to collect metrics on a per-resource +basis, deleting the associated meters after 5 seconds when a resource is deleted, using up to 2 threads to do so. + +```java +MicrometerMetrics.newPerResourceCollectingMicrometerMetricsBuilder(registry) + .withCleanUpDelayInSeconds(5) + .withCleaningThreadNumber(2) + .build() +``` + +The micrometer implementation records the following metrics: + +| Meter name | Type | Tag names | Description | +|-----------------------------------------------------------|----------------|-----------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------| +| operator.sdk.reconciliations.executions. | gauge | group, version, kind | Number of executions of the named reconciler | +| operator.sdk.reconciliations.queue.size. | gauge | group, version, kind | How many resources are queued to get reconciled by named reconciler | +| operator.sdk..size | gauge map size | | Gauge tracking the size of a specified map (currently unused but could be used to monitor caches size) | +| operator.sdk.events.received | counter | , event, action | Number of received Kubernetes events | +| operator.sdk.events.delete | counter | | Number of received Kubernetes delete events | +| operator.sdk.reconciliations.started | counter | , reconciliations.retries.last, reconciliations.retries.number | Number of started reconciliations per resource type | +| operator.sdk.reconciliations.failed | counter | , exception | Number of failed reconciliations per resource type | +| operator.sdk.reconciliations.success | counter | | Number of successful reconciliations per resource type | +| operator.sdk.controllers.execution.reconcile | timer | , controller | Time taken for reconciliations per controller | +| operator.sdk.controllers.execution.cleanup | timer | , controller | Time taken for cleanups per controller | +| operator.sdk.controllers.execution.reconcile.success | counter | controller, type | Number of successful reconciliations per controller | +| operator.sdk.controllers.execution.reconcile.failure | counter | controller, exception | Number of failed reconciliations per controller | +| operator.sdk.controllers.execution.cleanup.success | counter | controller, type | Number of successful cleanups per controller | +| operator.sdk.controllers.execution.cleanup.failure | counter | controller, exception | Number of failed cleanups per controller | + +As you can see all the recorded metrics start with the `operator.sdk` prefix. ``, in the table above, +refers to resource-specific metadata and depends on the considered metric and how the implementation is configured and +could be summed up as follows: `group?, version, kind, [name, namespace?], scope` where the tags in square +brackets (`[]`) won't be present when per-resource collection is disabled and tags followed by a question mark are +omitted if the associated value is empty. Of note, when in the context of controllers' execution metrics, these tag +names are prefixed with `resource.`. This prefix might be removed in a future version for greater consistency. + +## Optimizing Caches + +One of the ideas around the operator pattern is that all the relevant resources are cached, thus reconciliation is +usually very fast (especially if no resources are updated in the process) since the operator is then mostly working with +in-memory state. However for large clusters, caching huge amount of primary and secondary resources might consume lots +of memory. JOSDK provides ways to mitigate this issue and optimize the memory usage of controllers. While these features +are working and tested, we need feedback from real production usage. + +### Bounded Caches for Informers + +Limiting caches for informers - thus for Kubernetes resources - is supported by ensuring that resources are in the cache +for a limited time, via a cache eviction of least recently used resources. This means that when resources are created +and frequently reconciled, they stay "hot" in the cache. However, if, over time, a given resource "cools" down, i.e. it +becomes less and less used to the point that it might not be reconciled anymore, it will eventually get evicted from the +cache to free up memory. If such an evicted resource were to become reconciled again, the bounded cache implementation +would then fetch it from the API server and the "hot/cold" cycle would start anew. + +Since all resources need to be reconciled when a controller start, it is not practical to set a maximal cache size as +it's desirable that all resources be cached as soon as possible to make the initial reconciliation process on start as +fast and efficient as possible, avoiding undue load on the API server. It's therefore more interesting to gradually +evict cold resources than try to limit cache sizes. + +See usage of the related implementation using [Caffeine](https://github.com/ben-manes/caffeine) cache in integration +tests +for [primary resources](https://github.com/java-operator-sdk/java-operator-sdk/blob/902c8a562dfd7f8993a52e03473a7ad4b00f378b/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/AbstractTestReconciler.java#L29-L29). + +See +also [CaffeineBoundedItemStores](https://github.com/java-operator-sdk/java-operator-sdk/blob/902c8a562dfd7f8993a52e03473a7ad4b00f378b/caffeine-bounded-cache-support/src/main/java/io/javaoperatorsdk/operator/processing/event/source/cache/CaffeineBoundedItemStores.java) +for more details. + + diff --git a/docsy/content/en/docs/getting-started/_index.md b/docsy/content/en/docs/getting-started/_index.md new file mode 100644 index 0000000000..e3a3f95788 --- /dev/null +++ b/docsy/content/en/docs/getting-started/_index.md @@ -0,0 +1,58 @@ +--- +title: Getting Started + +weight: 20 +--- + +## Introduction & Resources on Operators + +Operators manage both cluster and non-cluster resources on behalf of Kubernetes. This Java +Operator SDK (JOSDK) aims at making it as easy as possible to write Kubernetes operators in Java +using an API that should feel natural to Java developers and without having to worry about many +low-level details that the SDK handles automatically. + +For an introduction on operators, please see this +[blog post](https://blog.container-solutions.com/kubernetes-operators-explained). +or [this talk](https://www.youtube.com/watch?v=CvftaV-xrB4) + +You can read about the common problems JOSDK is solving for you +[here](https://blog.container-solutions.com/a-deep-dive-into-the-java-operator-sdk). + +You can also refer to the +[Writing Kubernetes operators using JOSDK blog series](https://developers.redhat.com/articles/2022/02/15/write-kubernetes-java-java-operator-sdk) +. + +## Generating Project Skeleton + +Project includes a maven plugin to generate a skeleton project: + +```shell +mvn io.javaoperatorsdk:bootstrapper:[version]:create -DprojectGroupId=org.acme -DprojectArtifactId=getting-started +``` + +## Getting Started + +The easiest way to get started with SDK is to start +[minikube](https://kubernetes.io/docs/tasks/tools/install-minikube/) and +execute one of our [examples](https://github.com/java-operator-sdk/java-operator-sdk/tree/main/sample-operators). +There is a dedicated page to describe how to [use the samples](/docs/using-samples). + +Here are the main steps to develop the code and deploy the operator to a Kubernetes cluster. +A more detailed and specific version can be found under `samples/mysql-schema/README.md`. + +1. Setup `kubectl` to work with your Kubernetes cluster of choice. +1. Apply Custom Resource Definition +1. Compile the whole project (framework + samples) using `mvn install` in the root directory +1. Run the main class of the sample you picked and check out the sample's README to see what it + does. When run locally the framework will use your Kubernetes client configuration (in `~/. + kube/config`) to establish a connection to the cluster. This is why it was important to set + up `kubectl` up front. +1. You can work in this local development mode to play with the code. +1. Build the Docker image and push it to the registry +1. Apply RBAC configuration +1. Apply deployment configuration +1. Verify if the operator is up and running. Don't run it locally anymore to avoid conflicts in + processing events from the cluster's API server. + + + diff --git a/docsy/content/en/docs/glossary/_index.md b/docsy/content/en/docs/glossary/_index.md new file mode 100644 index 0000000000..187a0bfb4a --- /dev/null +++ b/docsy/content/en/docs/glossary/_index.md @@ -0,0 +1,24 @@ +--- +title: Glossary +weight: 40 +--- + +- **Primary Resource** - the resource that represents the desired state that the controller is + working to achieve. While this is often a Custom Resource, it can be also be a Kubernetes native + resource (Deployment, ConfigMap,...). +- **Secondary Resource** - any resource that the controller needs to manage the reach the desired + state represented by the primary resource. These resources can be created, updated, deleted or + simply read depending on the use case. For example, the `Deployment` controller manages + `ReplicaSet` instances when trying to realize the state represented by the `Deployment`. In + this scenario, the `Deployment` is the primary resource while `ReplicaSet` is one of the + secondary resources managed by the `Deployment` controller. +- **Dependent Resource** - a feature of JOSDK, to make it easier to manage secondary resources. A + dependent resource represents a secondary resource with related reconciliation logic. +- **Low-level API** - refers to the SDK APIs that don't use any of features (such as Dependent + Resources or Workflows) outside of the core +- [`Reconciler`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java) + interface. See + the [WebPage sample](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java) + . The same logic + is also implemented using + [Dependent Resource and Workflows](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageManagedDependentsReconciler.java) \ No newline at end of file diff --git a/docsy/content/en/docs/intro-to-operators/_index.md b/docsy/content/en/docs/intro-to-operators/_index.md new file mode 100644 index 0000000000..54fc7d82a8 --- /dev/null +++ b/docsy/content/en/docs/intro-to-operators/_index.md @@ -0,0 +1,16 @@ +--- +title: Introduction to Operators + +weight: 10 +--- + +This page provides a selection of articles that gives an introduction to Kubernetes operators. + +## Operators in General + - [Implementing Kubernetes Operators in Java talk](https://www.youtube.com/watch?v=CvftaV-xrB4) + - [Introduction of the concept of Kubernetes Operators](https://blog.container-solutions.com/kubernetes-operators-explained) + - [Operator pattern explained in Kubernetes documentation](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) + - [An explanation why Java Operators makes sense](https://blog.container-solutions.com/cloud-native-java-infrastructure-automation-with-kubernetes-operators) + - [What are the problems an operator framework is solving](https://csviri.medium.com/deep-dive-building-a-kubernetes-operator-sdk-for-java-developers-5008218822cb) + - [Writing Kubernetes operators using JOSDK blog series](https://developers.redhat.com/articles/2022/02/15/write-kubernetes-java-java-operator-sdk) + diff --git a/docsy/content/en/docs/migration/_index.md b/docsy/content/en/docs/migration/_index.md new file mode 100644 index 0000000000..9d7ca4d7f2 --- /dev/null +++ b/docsy/content/en/docs/migration/_index.md @@ -0,0 +1,4 @@ +--- +title: Migrations +--- + diff --git a/docsy/content/en/docs/migration/v2-migration.md b/docsy/content/en/docs/migration/v2-migration.md new file mode 100644 index 0000000000..4500672308 --- /dev/null +++ b/docsy/content/en/docs/migration/v2-migration.md @@ -0,0 +1,60 @@ +--- +title: Migrating from v1 to v2 +description: Migrating from v1 to v2 +layout: docs +permalink: /docs/v2-migration +--- + +# Migrating from v1 to v2 + +Version 2 of the framework introduces improvements, features and breaking changes for the APIs both +internal and user facing ones. The migration should be however trivial in most of the cases. For +detailed overview of all major issues until the release of +v`2.0.0` [see milestone on GitHub](https://github.com/java-operator-sdk/java-operator-sdk/milestone/1) +. For a summary and reasoning behind some naming changes +see [this issue](https://github.com/java-operator-sdk/java-operator-sdk/issues/655) + +## User Facing API Changes + +The following items are renamed and slightly changed: + +- [`ResourceController`](https://github.com/java-operator-sdk/java-operator-sdk/blob/v1/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/ResourceController.java) + interface is renamed + to [`Reconciler`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java) + . In addition, methods: + - `createOrUpdateResource` renamed to `reconcile` + - `deleteResource` renamed to `cleanup` +- Events are removed from + the [`Context`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java) + of `Reconciler` methods . The rationale behind this, is that there is a consensus now on the + pattern that the events should not be used to implement a reconciliation logic. +- The `init` method is extracted from `ResourceController` / `Reconciler` to a separate interface + called [EventSourceInitializer](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java) + that `Reconciler` should implement in order to register event sources. The method has been renamed + to `prepareEventSources` and should now return a list of `EventSource` implementations that + the `Controller` will automatically register. See + also [sample](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/WebappReconciler.java) + for usage. +- [`EventSourceManager`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java) + is now an internal class that users shouldn't need to interact with. +- [`@Controller`](https://github.com/java-operator-sdk/java-operator-sdk/blob/v1/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/Controller.java) + annotation renamed + to [`@ControllerConfiguration`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java) +- The metrics use `reconcile`, `cleanup` and `resource` labels instead of `createOrUpdate`, `delete` + and `cr`, respectively to match the new logic. + +### Event Sources + +- Addressing resources within event sources (and in the framework internally) is now changed + from `.metadata.uid` to a pair of `.metadata.name` and optional `.metadata.namespace` of resource. + Represented + by [`ResourceID.`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ResourceID.java) +- + +The [`Event`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/Event.java) +API is simplified. Now if an event source produces an event it needs to just produce an instance of +this class. + +- [`EventSource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSource.java) + is refactored, but the changes are trivial. + diff --git a/docsy/content/en/docs/migration/v3-1-migration.md b/docsy/content/en/docs/migration/v3-1-migration.md new file mode 100644 index 0000000000..9a7d9f7a9f --- /dev/null +++ b/docsy/content/en/docs/migration/v3-1-migration.md @@ -0,0 +1,47 @@ +--- +title: Migrating from v3 to v3.1 +description: Migrating from v3 to v3.1 +layout: docs +permalink: /docs/v3-1-migration +--- + +# Migrating from v3 to v3.1 + +## ReconciliationMaxInterval Annotation has been renamed to MaxReconciliationInterval + +Associated methods on both the `ControllerConfiguration` class and annotation have also been +renamed accordingly. + +## Workflows Impact on Managed Dependent Resources Behavior + +Version 3.1 comes with a workflow engine that replaces the previous behavior of managed dependent +resources. +See [Workflows documentation](https://javaoperatorsdk.io/docs/workflows) for further details. +The primary impact after upgrade is a change of the order in which managed dependent resources +are reconciled. They are now reconciled in parallel with optional ordering defined using the +['depends_on'](https://github.com/java-operator-sdk/java-operator-sdk/blob/df44917ef81725c10bbcb772ab7b434d511b13b9/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Dependent.java#L23-L23) +relation to define order between resources if needed. In v3, managed dependent resources were +implicitly reconciled in the order they were defined in. + +## Garbage Collected Kubernetes Dependent Resources + +In version 3 all Kubernetes Dependent Resource +implementing [`Deleter`](https://github.com/java-operator-sdk/java-operator-sdk/blob/bd063ccb7d55c110e96f24d2a10860d10aedfdb6/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Deleter.java#L13-L13) +interface were meant to be also using owner references (thus garbage collected by Kubernetes). +In 3.1 there is a +dedicated [`GarbageCollected`](https://github.com/java-operator-sdk/java-operator-sdk/blob/bd063ccb7d55c110e96f24d2a10860d10aedfdb6/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/GarbageCollected.java#L28-L28) +interface to distinguish between Kubernetes resources meant to be garbage collected or explicitly +deleted. Please refer also to the `GarbageCollected` javadoc for more details on how this +impacts how owner references are managed. + +The supporting classes were also updated. Instead +of [`CRUKubernetesDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/d99f65a736e9180e3f6de9a4239f80e47fc653fc/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/CRUKubernetesDependentResource.java) +there are two: + +- [`CRUDKubernetesDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/bd063ccb7d55c110e96f24d2a10860d10aedfdb6/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/CRUDKubernetesDependentResource.java) + that is `GarbageCollected` +- [`CRUDNoGCKubernetesDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/bd063ccb7d55c110e96f24d2a10860d10aedfdb6/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/CRUDNoGCKubernetesDependentResource.java) + what is `Deleter` but not `GarbageCollected` + +Use the one according to your use case. We anticipate that most people would want to use +`CRUDKubernetesDependentResource` whenever they have to work with Kubernetes dependent resources. \ No newline at end of file diff --git a/docsy/content/en/docs/migration/v3-migration.md b/docsy/content/en/docs/migration/v3-migration.md new file mode 100644 index 0000000000..97e844904e --- /dev/null +++ b/docsy/content/en/docs/migration/v3-migration.md @@ -0,0 +1,40 @@ +--- +title: Migrating from v2 to v3 +description: Migrating from v2 to v3 +layout: docs +permalink: /docs/v3-migration +--- + +# Migrating from v2 to v3 + +Version 3 introduces some breaking changes to APIs, however the migration to these changes should be trivial. + +## Reconciler + +- [`Reconciler`](https://github.com/java-operator-sdk/java-operator-sdk/blob/67d8e25c26eb92392c6d2a9eb39ea6dddbbfafcc/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Reconciler.java#L16-L16) + can throw checked exception (not just runtime exception), and that also can be handled by `ErrorStatusHandler`. +- `cleanup` method is extracted from the `Reconciler` interface to a + separate [`Cleaner`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Cleaner.java) + interface. Finalizers only makes sense that the `Cleanup` is implemented, from + now finalizer is only added if the `Reconciler` implements this interface (or has managed dependent resources + implementing `Deleter` interface, see dependent resource docs). +- [`Context`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java#L9-L9) + object of `Reconciler` now takes the Primary resource as parametrized type: `Context`. +- [`ErrorStatusHandler`](https://github.com/java-operator-sdk/java-operator-sdk/blob/67d8e25c26eb92392c6d2a9eb39ea6dddbbfafcc/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusHandler.java) + result changed, it functionally has been extended to now prevent Exception to be retried and handles checked + exceptions as mentioned above. + + +## Event Sources + +- Event Sources are now registered with a name. But [utility method](https://github.com/java-operator-sdk/java-operator-sdk/blob/92bfafd8831e5fb9928663133f037f1bf4783e3e/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java#L33-L33) + is available to make it easy to [migrate](https://github.com/java-operator-sdk/java-operator-sdk/blob/92bfafd8831e5fb9928663133f037f1bf4783e3e/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java#L51-L52) + to a default name. +- [InformerEventSource](https://github.com/java-operator-sdk/java-operator-sdk/blob/92bfafd8831e5fb9928663133f037f1bf4783e3e/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java#L75-L75) + constructor changed to reflect additional functionality in a non backwards compatible way. All the configuration + options from the constructor where moved to [`InformerConfiguration`](https://github.com/java-operator-sdk/java-operator-sdk/blob/f6c6d568ea0a098e11beeeded20fe70f9c5bf692/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java) + . See sample usage in [`WebPageReconciler`](https://github.com/java-operator-sdk/java-operator-sdk/blob/f6c6d568ea0a098e11beeeded20fe70f9c5bf692/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java#L56-L59) + . +- `PrimaryResourcesRetriever` was renamed to `SecondaryToPrimaryMapper` +- `AssociatedSecondaryResourceIdentifier` was renamed to `PrimaryToSecondaryMapper` +- `getAssociatedResource` is now renamed to get `getSecondaryResource` in multiple places \ No newline at end of file diff --git a/docsy/content/en/docs/migration/v4-3-migration.md b/docsy/content/en/docs/migration/v4-3-migration.md new file mode 100644 index 0000000000..17d3be70b4 --- /dev/null +++ b/docsy/content/en/docs/migration/v4-3-migration.md @@ -0,0 +1,50 @@ +--- +title: Migrating from v4.2 to v4.3 +description: Migrating from v4.2 to v4.3 +layout: docs +permalink: /docs/v4-3-migration +--- + +# Migrating from v4.2 to v4.3 + +## Condition API Change + +In Workflows the target of the condition was the managed resource itself, not the target dependent resource. +This changed, now the API contains the dependent resource. + +New API: + +```java +public interface Condition { + + boolean isMet(DependentResource dependentResource, P primary, Context

context); + +} +``` + +Former API: + +```java +public interface Condition { + + boolean isMet(P primary, R secondary, Context

context); + +} +``` + +Migration is trivial. Since the secondary resource can be accessed from the dependent resource. So to access the +secondary +resource just use `dependentResource.getSecondaryResource(primary,context)`. + +## HTTP client choice + +It is now possible to change the HTTP client used by the Fabric8 client to communicate with the Kubernetes API server. +By default, the SDK uses the historical default HTTP client which relies on Okhttp and there shouldn't be anything +needed to keep using this implementation. The `tomcat-operator` sample has been migrated to use the Vert.X based +implementation. You can see how to change the client by looking at +that [sample POM file](https://github.com/java-operator-sdk/java-operator-sdk/blob/d259fcd084f7e22032dfd0df3c7e64fe68850c1b/sample-operators/tomcat-operator/pom.xml#L37-L50): + +- You need to exclude the default implementation (in this case okhttp) from the `operator-framework` dependency +- You need to add the appropriate implementation dependency, `kubernetes-httpclient-vertx` in this case, HTTP client + implementations provided as part of the Fabric8 client all following the `kubernetes-httpclient-` + pattern for their artifact identifier. \ No newline at end of file diff --git a/docsy/content/en/docs/migration/v4-4-migration.md b/docsy/content/en/docs/migration/v4-4-migration.md new file mode 100644 index 0000000000..c198871f3f --- /dev/null +++ b/docsy/content/en/docs/migration/v4-4-migration.md @@ -0,0 +1,93 @@ +--- +title: Migrating from v4.3 to v4.4 +description: Migrating from v4.3 to v4.4 +layout: docs +permalink: /docs/v4-4-migration +--- + +# Migrating from v4.3 to v4.4 + +## API changes + +### ConfigurationService + +We have simplified how to deal with the Kubernetes client. Previous versions provided direct +access to underlying aspects of the client's configuration or serialization mechanism. However, +the link between these aspects wasn't as explicit as it should have been. Moreover, the Fabric8 +client framework has also revised their serialization architecture in the 6.7 version (see [this +fabric8 pull request](https://github.com/fabric8io/kubernetes-client/pull/4662) for a discussion of +that change), moving from statically configured serialization to a per-client configuration +(though it's still possible to share serialization mechanism between client instances). As a +consequence, we made the following changes to the `ConfigurationService` API: + +- Replaced `getClientConfiguration` and `getObjectMapper` methods by a new `getKubernetesClient` + method: instead of providing the configuration and mapper, you now provide a client instance + configured according to your needs and the SDK will extract the needed information from it + +If you had previously configured a custom configuration or `ObjectMapper`, it is now recommended +that you do so when creating your client instance, as follows, usually using +`ConfigurationServiceOverrider.withKubernetesClient`: + +```java + +class Example { + + public static void main(String[] args) { + Config config; // your configuration + ObjectMapper mapper; // your mapper + final var operator = new Operator(overrider -> overrider.withKubernetesClient( + new KubernetesClientBuilder() + .withConfig(config) + .withKubernetesSerialization(new KubernetesSerialization(mapper, true)) + .build() + )); + } +} +``` + +Consequently, it is now recommended to get the client instance from the `ConfigurationService`. + +### Operator + +It is now recommended to configure your Operator instance by using a +`ConfigurationServiceOverrider` when creating it. This allows you to change the default +configuration values as needed. In particular, instead of passing a Kubernetes client instance +explicitly to the Operator constructor, it is now recommended to provide that value using +`ConfigurationServiceOverrider.withKubernetesClient` as shown above. + +## Using Server-Side Apply in Dependent Resources + +From this version by +default [Dependent Resources](https://javaoperatorsdk.io/docs/dependent-resources) use +[Server Side Apply (SSA)](https://kubernetes.io/docs/reference/using-api/server-side-apply/) to +create and +update Kubernetes resources. A +new [default matching](https://github.com/java-operator-sdk/java-operator-sdk/blob/2cc3bb7710adb8fca14767fbff8d93533dd05ef0/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java#L157-L157) +algorithm is provided for `KubernetesDependentResource` that is based on `managedFields` of SSA. For +details +see [SSABasedGenericKubernetesResourceMatcher](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java) + +Since those features are hard to completely test, we provided feature flags to revert to the +legacy behavior if needed, +see +in [ConfigurationService](https://github.com/java-operator-sdk/java-operator-sdk/blob/2cc3bb7710adb8fca14767fbff8d93533dd05ef0/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L332-L347) + +Note that it is possible to override the related methods/behavior on class level when extending +the `KubernetesDependentResource`. + +The SSA based create/update can be combined with the legacy matcher, simply override the `match` method +and use the [GenericKubernetesResourceMatcher](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java#L19-L19) +directly. See related [sample](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java#L39-L44). + +### Migration from plain Update/Create to SSA Based Patch + +Migration to SSA might not be trivial based on the uses cases and the type of managed resources. +In general this is not a solved problem is Kubernetes. The Java Operator SDK Team tries to follow +the related issues, but in terms of implementation this is not something that the framework explicitly +supports. Thus, no code is added that tries to mitigate related issues. Users should thoroughly +test the migration, and even consider not to migrate in some cases (see feature flags above). + +See some related issues in [kubernetes](https://github.com/kubernetes/kubernetes/issues/118725) or +[here](https://github.com/keycloak/keycloak/pull). Please create related issue in JOSDK if any. + + diff --git a/docsy/content/en/docs/migration/v4-5-migration.md b/docsy/content/en/docs/migration/v4-5-migration.md new file mode 100644 index 0000000000..0ff08eef13 --- /dev/null +++ b/docsy/content/en/docs/migration/v4-5-migration.md @@ -0,0 +1,26 @@ +--- +title: Migrating from v4.4 to v4.5 +description: Migrating from v4.4 to v4.5 +layout: docs +permalink: /docs/v4-5-migration +--- + +# Migrating from v4.4 to v4.5 + +Version 4.5 introduces improvements related to event handling for Dependent Resources, more precisely the +[caching and event handling](https://javaoperatorsdk.io/docs/dependent-resources#caching-and-event-handling-in-kubernetesdependentresource) +features. As a result the Kubernetes resources managed using +[KubernetesDependentResource](https://github.com/java-operator-sdk/java-operator-sdk/blob/73b1d8db926a24502c3a70da34f6bcac4f66b4eb/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java#L72-L72) +or its subclasses, will add an annotation recording the resource's version whenever JOSDK updates or creates such +resources. This can be turned off using a +[feature flag](https://github.com/java-operator-sdk/java-operator-sdk/blob/73b1d8db926a24502c3a70da34f6bcac4f66b4eb/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L375-L375) +if causes some issues in your use case. + +Using this feature, JOSDK now tracks versions of cached resources. It also uses, by default, that information to prevent +unneeded reconciliations that could occur when, depending on the timing of operations, an outdated resource would happen +to be in the cache. This relies on the fact that versions (as recorded by the `metadata.resourceVersion` field) are +currently implemented as monotonically increasing integers (though they should be considered as opaque and their +interpretation discouraged). Note that, while this helps preventing unneeded reconciliations, things would eventually +reach consistency even in the absence of this feature. Also, if this interpreting of the resource versions causes +issues, you can turn the feature off using the +[following feature flag](https://github.com/java-operator-sdk/java-operator-sdk/blob/73b1d8db926a24502c3a70da34f6bcac4f66b4eb/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L390-L390). diff --git a/docsy/content/en/docs/patters-and-best-practices/_index.md b/docsy/content/en/docs/patters-and-best-practices/_index.md new file mode 100644 index 0000000000..422f3f7bfe --- /dev/null +++ b/docsy/content/en/docs/patters-and-best-practices/_index.md @@ -0,0 +1,122 @@ +--- +title: Patterns and Best Practices +weight: 25 +--- + + +This document describes patterns and best practices, to build and run operators, and how to +implement them in terms of the Java Operator SDK (JOSDK). + +See also best practices +in [Operator SDK](https://sdk.operatorframework.io/docs/best-practices/best-practices/). + +## Implementing a Reconciler + +### Reconcile All The Resources All the Time + +The reconciliation can be triggered by events from multiple sources. It could be tempting to check +the events and reconcile just the related resource or subset of resources that the controller +manages. However, this is **considered an anti-pattern** for operators because the distributed +nature of Kubernetes makes it difficult to ensure that all events are always received. If, for +some reason, your operator doesn't receive some events, if you do not reconcile the whole state, +you might be operating with improper assumptions about the state of the cluster. This is why it +is important to always reconcile all the resources, no matter how tempting it might be to only +consider a subset. Luckily, JOSDK tries to make it as easy and efficient as possible by +providing smart caches to avoid unduly accessing the Kubernetes API server and by making sure +your reconciler is only triggered when needed. + +Since there is a consensus regarding this topic in the industry, JOSDK does not provide +event access from `Reconciler` implementations anymore starting with version 2 of the framework. + +### EventSources and Caching + +As mentioned above during a reconciliation best practice is to reconcile all the dependent resources +managed by the controller. This means that we want to compare a desired state with the actual +state of the cluster. Reading the actual state of a resource from the Kubernetes API Server +directly all the time would mean a significant load. Therefore, it's a common practice to +instead create a watch for the dependent resources and cache their latest state. This is done +following the Informer pattern. In Java Operator SDK, informers are wrapped into an `EventSource`, +to integrate it with the eventing system of the framework. This is implemented by the +`InformerEventSource` class. + +A new event that triggers the reconciliation is only propagated to the `Reconciler` when the actual +resource is already in cache. `Reconciler` implementations therefore only need to compare the +desired state with the observed one provided by the cached resource. If the resource cannot be +found in the cache, it therefore needs to be created. If the actual state doesn't match the +desired state, the resource needs to be updated. + +### Idempotency + +Since all resources should be reconciled when your `Reconciler` is triggered and reconciliations +can be triggered multiple times for any given resource, especially when retry policies are in +place, it is especially important that `Reconciler` implementations be idempotent, meaning that +the same observed state should result in exactly the same outcome. This also means that +operators should generally operate in stateless fashion. Luckily, since operators are usually +managing declarative resources, ensuring idempotency is usually not difficult. + +### Sync or Async Way of Resource Handling + +Depending on your use case, it's possible that your reconciliation logic needs to wait a +non-insignificant amount of time while the operator waits for resources to reach their desired +state. For example, you `Reconciler` might need to wait for a `Pod` to get ready before +performing additional actions. This problem can be approached either synchronously or +asynchronously. + +The asynchronous way is to just exit the reconciliation logic as soon as the `Reconciler` +determines that it cannot complete its full logic at this point in time. This frees resources to +process other primary resource events. However, this requires that adequate event sources are +put in place to monitor state changes of all the resources the operator waits for. When this is +done properly, any state change will trigger the `Reconciler` again and it will get the +opportunity to finish its processing + +The synchronous way would be to periodically poll the resources' state until they reach their +desired state. If this is done in the context of the `reconcile` method of your `Reconciler` +implementation, this would block the current thread for possibly a long time. It's therefore +usually recommended to use the asynchronous processing fashion. + +## Why have Automatic Retries? + +Automatic retries are in place by default and can be configured to your needs. It is also +possible to completely deactivate the feature, though we advise against it. The main reason +configure automatic retries for your `Reconciler` is due to the fact that errors occur quite +often due to the distributed nature of Kubernetes: transient network errors can be easily dealt +with by automatic retries. Similarly, resources can be modified by different actors at the same +time, so it's not unheard of to get conflicts when working with Kubernetes resources. Such +conflicts can usually be quite naturally resolved by reconciling the resource again. If it's +done automatically, the whole process can be completely transparent. + +## Managing State + +Thanks to the declarative nature of Kubernetes resources, operators that deal only with +Kubernetes resources can operate in a stateless fashion, i.e. they do not need to maintain +information about the state of these resources, as it should be possible to completely rebuild +the resource state from its representation (that's what declarative means, after all). +However, this usually doesn't hold true anymore when dealing with external resources, and it +might be necessary for the operator to keep track of this external state so that it is available +when another reconciliation occurs. While such state could be put in the primary resource's +status sub-resource, this could become quickly difficult to manage if a lot of state needs to be +tracked. It also goes against the best practice that a resource's status should represent the +actual resource state, when its spec represents the desired state. Putting state that doesn't +strictly represent the resource's actual state is therefore discouraged. Instead, it's +advised to put such state into a separate resource meant for this purpose such as a +Kubernetes Secret or ConfigMap or even a dedicated Custom Resource, which structure can be more +easily validated. + +## Stopping (or not) Operator in case of Informer Errors and Cache Sync Timeouts + +It can +be [configured](https://github.com/java-operator-sdk/java-operator-sdk/blob/2cb616c4c4fd0094ee6e3a0ef2a0ea82173372bf/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L168-L168) +if the operator should stop in case of any informer error happens on startup. By default, if there ia an error on +startup and the informer for example has no permissions list the target resources (both the primary resource or +secondary resources) the operator will stop instantly. This behavior can be altered by setting the mentioned flag +to `false`, so operator will start even some informers are not started. In this case - same as in case when an informer +is started at first but experienced problems later - will continuously retry the connection indefinitely with an +exponential backoff. The operator will just stop if there is a fatal +error, [currently](https://github.com/java-operator-sdk/java-operator-sdk/blob/0e55c640bf8be418bc004e51a6ae2dcf7134c688/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerWrapper.java#L64-L66) +that is when a resource cannot be deserialized. The typical use case for changing this flag is when a list of namespaces +is watched by a controller. In is better to start up the operator, so it can handle other namespaces while there +might be a permission issue for some resources in another namespace. + +The `stopOnInformerErrorDuringStartup` has implication on [cache sync timeout](https://github.com/java-operator-sdk/java-operator-sdk/blob/114c4312c32b34688811df8dd7cea275878c9e73/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L177-L179) +behavior. If true operator will stop on cache sync timeout. if `false`, after the timeout the controller will start +reconcile resources even if one or more event source caches did not sync yet. diff --git a/docsy/content/en/docs/using-samples/_index.md b/docsy/content/en/docs/using-samples/_index.md new file mode 100644 index 0000000000..62319860ac --- /dev/null +++ b/docsy/content/en/docs/using-samples/_index.md @@ -0,0 +1,255 @@ +--- +title: Using sample Operators +weight: 30 +--- + +We have examples under [sample-operators](https://github.com/java-operator-sdk/java-operator-sdk/tree/master/sample-operators) +directory which are intended to demonstrate the usage of different components in different scenarios, but mainly are more real world +examples: + +* *webpage*: Simple example creating an NGINX webserver from a Custom Resource containing HTML code. +* *mysql-schema*: Operator managing schemas in a MySQL database. Shows how to manage non Kubernetes resources. +* *tomcat*: Operator with two controllers, managing Tomcat instances and Webapps running in Tomcat. The intention + with this example to show how to manage multiple related custom resources and/or more controllers. + +# Implementing a Sample Operator + +Add [dependency](https://search.maven.org/search?q=a:operator-framework%20AND%20g:io.javaoperatorsdk) to your project with Maven: + +```xml + + + io.javaoperatorsdk + operator-framework + {see https://search.maven.org/search?q=a:operator-framework%20AND%20g:io.javaoperatorsdk for latest version} + +``` + +Or alternatively with Gradle, which also requires declaring the SDK as an annotation processor to generate the mappings +between controllers and custom resource classes: + +```groovy +dependencies { + implementation "io.javaoperatorsdk:operator-framework:${javaOperatorVersion}" + annotationProcessor "io.javaoperatorsdk:operator-framework:${javaOperatorVersion}" +} +``` + +Once you've added the dependency, define a main method initializing the Operator and registering a controller. + +```java +public class Runner { + + public static void main(String[] args) { + Operator operator = new Operator(); + operator.register(new WebPageReconciler()); + operator.start(); + } +} +``` + +The Controller implements the business logic and describes all the classes needed to handle the CRD. + +```java + +@ControllerConfiguration +public class WebPageReconciler implements Reconciler { + + // Return the changed resource, so it gets updated. See javadoc for details. + @Override + public UpdateControl reconcile(CustomService resource, + Context context) { + // ... your logic ... + return UpdateControl.patchStatus(resource); + } +} +``` + +A sample custom resource POJO representation + +```java + +@Group("sample.javaoperatorsdk") +@Version("v1") +public class WebPage extends CustomResource implements + Namespaced { +} + +public class WebServerSpec { + + private String html; + + public String getHtml() { + return html; + } + + public void setHtml(String html) { + this.html = html; + } +} +``` + +### Deactivating CustomResource implementations validation + +The operator will, by default, query the deployed CRDs to check that the `CustomResource` +implementations match what is known to the cluster. This requires an additional query to the cluster and, sometimes, +elevated privileges for the operator to be able to read the CRDs from the cluster. This validation is mostly meant to +help users new to operator development get started and avoid common mistakes. Advanced users or production deployments +might want to skip this step. This is done by setting the `CHECK_CRD_ENV_KEY` environment variable to `false`. + +### Automatic generation of CRDs + +To automatically generate CRD manifests from your annotated Custom Resource classes, you only need to add the following +dependencies to your project (in the background an annotation processor is used), with Maven: + +```xml + + + io.fabric8 + crd-generator-apt + provided + +``` + +or with Gradle: + +```groovy +dependencies { + annotationProcessor 'io.fabric8:crd-generator-apt:' + ... +} +``` + +The CRD will be generated in `target/classes/META-INF/fabric8` (or in `target/test-classes/META-INF/fabric8`, if you use +the `test` scope) with the CRD name suffixed by the generated spec version. For example, a CR using +the `java-operator-sdk.io` group with a `mycrs` plural form will result in 2 files: + +- `mycrs.java-operator-sdk.io-v1.yml` +- `mycrs.java-operator-sdk.io-v1beta1.yml` + +**NOTE:** +> Quarkus users using the `quarkus-operator-sdk` extension do not need to add any extra dependency to get their CRD generated as this is handled by the extension itself. + +### Quarkus + +A [Quarkus](https://quarkus.io) extension is also provided to ease the development of Quarkus-based operators. + +Add [this dependency](https://search.maven.org/search?q=a:quarkus-operator-sdk) +to your project: + +```xml + + + io.quarkiverse.operatorsdk + quarkus-operator-sdk + {see https://search.maven.org/search?q=a:quarkus-operator-sdk for latest version} + + +``` + +Create an Application, Quarkus will automatically create and inject a `KubernetesClient` ( +or `OpenShiftClient`), `Operator`, `ConfigurationService` and `ResourceController` instances that your application can +use. Below, you can see the minimal code you need to write to get your operator and controllers up and running: + +```java + +@QuarkusMain +public class QuarkusOperator implements QuarkusApplication { + + @Inject + Operator operator; + + public static void main(String... args) { + Quarkus.run(QuarkusOperator.class, args); + } + + @Override + public int run(String... args) throws Exception { + operator.start(); + Quarkus.waitForExit(); + return 0; + } +} +``` + +### Spring Boot + +You can also let Spring Boot wire your application together and automatically register the controllers. + +Add [this dependency](https://search.maven.org/search?q=a:operator-framework-spring-boot-starter%20AND%20g:io.javaoperatorsdk) to your project: + +```xml + + + io.javaoperatorsdk + operator-framework-spring-boot-starter + {see https://search.maven.org/search?q=a:operator-framework-spring-boot-starter%20AND%20g:io.javaoperatorsdk for + latest version} + + +``` + +Create an Application + +```java + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} +``` + +You will also need a `@Configuration` to make sure that your reconciler is registered: + +```java + +@Configuration +public class Config { + + @Bean + public WebPageReconciler customServiceController() { + return new WebPageReconciler(); + } + + @Bean(initMethod = "start", destroyMethod = "stop") + @SuppressWarnings("rawtypes") + public Operator operator(List controllers) { + Operator operator = new Operator(); + controllers.forEach(operator::register); + return operator; + } +} +``` + +#### Spring Boot test support + +Adding the following dependency would let you mock the operator for the tests where loading the spring container is +necessary, but it doesn't need real access to a Kubernetes cluster. + +```xml + + + io.javaoperatorsdk + operator-framework-spring-boot-starter-test + {see https://search.maven.org/search?q=a:operator-framework-spring-boot-starter%20AND%20g:io.javaoperatorsdk for + latest version} + + +``` + +Mock the operator: + +```java + +@SpringBootTest +@EnableMockOperator +public class SpringBootStarterSampleApplicationTest { + + @Test + void contextLoads() { + } +} +``` diff --git a/docsy/content/en/docs/workflows/_index.md b/docsy/content/en/docs/workflows/_index.md new file mode 100644 index 0000000000..4eba1f5d07 --- /dev/null +++ b/docsy/content/en/docs/workflows/_index.md @@ -0,0 +1,354 @@ +--- +title: Workflows +weight: 70 +--- + +## Overview + +Kubernetes (k8s) does not have the notion of a resource "depending on" on another k8s resource, +at least not in terms of the order in which these resources should be reconciled. Kubernetes +operators typically need to reconcile resources in order because these resources' state often +depends on the state of other resources or cannot be processed until these other resources reach +a given state or some condition holds true for them. Dealing with such scenarios are therefore +rather common for operators and the purpose of the workflow feature of the Java Operator SDK +(JOSDK) is to simplify supporting such cases in a declarative way. Workflows build on top of the +[dependent resources](https://javaoperatorsdk.io/docs/dependent-resources) feature. +While dependent resources focus on how a given secondary resource should be reconciled, +workflows focus on orchestrating how these dependent resources should be reconciled. + +Workflows describe how as a set of +[dependent resources](https://javaoperatorsdk.io/docs/dependent-resources) (DR) depend on one +another, along with the conditions that need to hold true at certain stages of the +reconciliation process. + +## Elements of Workflow + +- **Dependent resource** (DR) - are the resources being managed in a given reconciliation logic. +- **Depends-on relation** - a `B` DR depends on another `A` DR if `B` needs to be reconciled + after `A`. +- **Reconcile precondition** - is a condition on a given DR that needs to be become true before the + DR is reconciled. This also allows to define optional resources that would, for example, only be + created if a flag in a custom resource `.spec` has some specific value. +- **Ready postcondition** - is a condition on a given DR to prevent the workflow from + proceeding until the condition checking whether the DR is ready holds true +- **Delete postcondition** - is a condition on a given DR to check if the reconciliation of + dependents can proceed after the DR is supposed to have been deleted +- **Activation condition** - is a special condition meant to specify under which condition the DR is used in the + workflow. A typical use-case for this feature is to only activate some dependents depending on the presence of + optional resources / features on the target cluster. Without this activation condition, JOSDK would attempt to + register an informer for these optional resources, which would cause an error in the case where the resource is + missing. With this activation condition, you can now conditionally register informers depending on whether the + condition holds or not. This is a very useful feature when your operator needs to handle different flavors of the + platform (e.g. OpenShift vs plain Kubernetes) and/or change its behavior based on the availability of optional + resources / features (e.g. CertManager, a specific Ingress controller, etc.). + + Activation condition is semi-experimental at the moment, and it has its limitations. + For example event sources cannot be shared between multiple managed dependent resources which use activation condition. + The intention is to further improve and explore the possibilities with this approach. + +## Defining Workflows + +Similarly to dependent resources, there are two ways to define workflows, in managed and standalone +manner. + +### Managed + +Annotations can be used to declaratively define a workflow for a `Reconciler`. Similarly to how +things are done for dependent resources, managed workflows execute before the `reconcile` method +is called. The result of the reconciliation can be accessed via the `Context` object that is +passed to the `reconcile` method. + +The following sample shows a hypothetical use case to showcase all the elements: the primary +`TestCustomResource` resource handled by our `Reconciler` defines two dependent resources, a +`Deployment` and a `ConfigMap`. The `ConfigMap` depends on the `Deployment` so will be +reconciled after it. Moreover, the `Deployment` dependent resource defines a ready +post-condition, meaning that the `ConfigMap` will not be reconciled until the condition defined +by the `Deployment` becomes `true`. Additionally, the `ConfigMap` dependent also defines a +reconcile pre-condition, so it also won't be reconciled until that condition becomes `true`. The +`ConfigMap` also defines a delete post-condition, which means that the workflow implementation +will only consider the `ConfigMap` deleted until that post-condition becomes `true`. + +```java + +@ControllerConfiguration(dependents = { + @Dependent(name = DEPLOYMENT_NAME, type = DeploymentDependentResource.class, + readyPostcondition = DeploymentReadyCondition.class), + @Dependent(type = ConfigMapDependentResource.class, + reconcilePrecondition = ConfigMapReconcileCondition.class, + deletePostcondition = ConfigMapDeletePostCondition.class, + activationCondition = ConfigMapActivationCondition.class, + dependsOn = DEPLOYMENT_NAME) +}) +public class SampleWorkflowReconciler implements Reconciler, + Cleaner { + + public static final String DEPLOYMENT_NAME = "deployment"; + + @Override + public UpdateControl reconcile( + WorkflowAllFeatureCustomResource resource, + Context context) { + + resource.getStatus() + .setReady( + context.managedDependentResourceContext() // accessing workflow reconciliation results + .getWorkflowReconcileResult().orElseThrow() + .allDependentResourcesReady()); + return UpdateControl.patchStatus(resource); + } + + @Override + public DeleteControl cleanup(WorkflowAllFeatureCustomResource resource, + Context context) { + // emitted code + + return DeleteControl.defaultDelete(); + } +} + +``` + +### Standalone + +In this mode workflow is built manually +using [standalone dependent resources](https://javaoperatorsdk.io/docs/dependent-resources#standalone-dependent-resources) +. The workflow is created using a builder, that is explicitly called in the reconciler (from web +page sample): + +```java + +@ControllerConfiguration( + labelSelector = WebPageDependentsWorkflowReconciler.DEPENDENT_RESOURCE_LABEL_SELECTOR) +public class WebPageDependentsWorkflowReconciler + implements Reconciler, ErrorStatusHandler, EventSourceInitializer { + + public static final String DEPENDENT_RESOURCE_LABEL_SELECTOR = "!low-level"; + private static final Logger log = + LoggerFactory.getLogger(WebPageDependentsWorkflowReconciler.class); + + private KubernetesDependentResource configMapDR; + private KubernetesDependentResource deploymentDR; + private KubernetesDependentResource serviceDR; + private KubernetesDependentResource ingressDR; + + private Workflow workflow; + + public WebPageDependentsWorkflowReconciler(KubernetesClient kubernetesClient) { + initDependentResources(kubernetesClient); + workflow = new WorkflowBuilder() + .addDependentResource(configMapDR) + .addDependentResource(deploymentDR) + .addDependentResource(serviceDR) + .addDependentResource(ingressDR).withReconcilePrecondition(new ExposedIngressCondition()) + .build(); + } + + @Override + public Map prepareEventSources(EventSourceContext context) { + return EventSourceInitializer.nameEventSources( + configMapDR.initEventSource(context), + deploymentDR.initEventSource(context), + serviceDR.initEventSource(context), + ingressDR.initEventSource(context)); + } + + @Override + public UpdateControl reconcile(WebPage webPage, Context context) { + + var result = workflow.reconcile(webPage, context); + + webPage.setStatus(createStatus(result)); + return UpdateControl.patchStatus(webPage); + } + // omitted code +} + +``` + +## Workflow Execution + +This section describes how a workflow is executed in details, how the ordering is determined and +how conditions and errors affect the behavior. The workflow execution is divided in two parts +similarly to how `Reconciler` and `Cleaner` behavior are separated. +[Cleanup](https://javaoperatorsdk.io/docs/features#the-reconcile-and-cleanup) is +executed if a resource is marked for deletion. + +## Common Principles + +- **As complete as possible execution** - when a workflow is reconciled, it tries to reconcile as + many resources as possible. Thus, if an error happens or a ready condition is not met for a + resources, all the other independent resources will be still reconciled. This is the opposite + to a fail-fast approach. The assumption is that eventually in this way the overall state will + converge faster towards the desired state than would be the case if the reconciliation was + aborted as soon as an error occurred. +- **Concurrent reconciliation of independent resources** - the resources which doesn't depend on + others are processed concurrently. The level of concurrency is customizable, could be set to + one if required. By default, workflows use the executor service + from [ConfigurationService](https://github.com/java-operator-sdk/java-operator-sdk/blob/6f2a252952d3a91f6b0c3c38e5e6cc28f7c0f7b3/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L120-L120) + +## Reconciliation + +This section describes how a workflow is executed, considering first which rules apply, then +demonstrated using examples: + +### Rules + +1. A workflow is a Directed Acyclic Graph (DAG) build from the DRs and their associated + `depends-on` relations. +2. Root nodes, i.e. nodes in the graph that do not depend on other nodes are reconciled first, + in a parallel manner. +3. A DR is reconciled if it does not depend on any other DRs, or *ALL* the DRs it depends on are + reconciled and ready. If a DR defines a reconcile pre-condition and/or an activation condition, + then these condition must become `true` before the DR is reconciled. +4. A DR is considered *ready* if it got successfully reconciled and any ready post-condition it + might define is `true`. +5. If a DR's reconcile pre-condition is not met, this DR is deleted. All the DRs that depend + on the dependent resource are also recursively deleted. This implies that + DRs are deleted in reverse order compared the one in which they are reconciled. The reason + for this behavior is (Will make a more detailed blog post about the design decision, much deeper + than the reference documentation) + The reasoning behind this behavior is as follows: a DR with a reconcile pre-condition is only + reconciled if the condition holds `true`. This means that if the condition is `false` and the + resource didn't exist already, then the associated resource would not be created. To ensure + idempotency (i.e. with the same input state, we should have the same output state), from this + follows that if the condition doesn't hold `true` anymore, the associated resource needs to + be deleted because the resource shouldn't exist/have been created. +6. If a DR's activation condition is not met, it won't be reconciled or deleted. If other DR's depend on it, those will + be recursively deleted in a way similar to reconcile pre-conditions. Event sources for a dependent resource with + activation condition are registered/de-registered dynamically, thus during the reconciliation. +7. For a DR to be deleted by a workflow, it needs to implement the `Deleter` interface, in which + case its `delete` method will be called, unless it also implements the `GarbageCollected` + interface. If a DR doesn't implement `Deleter` it is considered as automatically deleted. If + a delete post-condition exists for this DR, it needs to become `true` for the workflow to + consider the DR as successfully deleted. + +### Samples + +Notation: The arrows depicts reconciliation ordering, thus following the reverse direction of the +`depends-on` relation: +`1 --> 2` mean `DR 2` depends-on `DR 1`. + +#### Reconcile Sample + +

+ +stateDiagram-v2 +1 --> 2 +1 --> 3 +2 --> 4 +3 --> 4 + +
+ +- Root nodes (i.e. nodes that don't depend on any others) are reconciled first. In this example, + DR `1` is reconciled first since it doesn't depend on others. + After that both DR `2` and `3` are reconciled concurrently, then DR `4` once both are + reconciled successfully. +- If DR `2` had a ready condition and if it evaluated to as `false`, DR `4` would not be reconciled. + However `1`,`2` and `3` would be. +- If `1` had a `false` ready condition, neither `2`,`3` or `4` would be reconciled. +- If `2`'s reconciliation resulted in an error, `4` would not be reconciled, but `3` + would be (and `1` as well, of course). + +#### Sample with Reconcile Precondition + +
+ +stateDiagram-v2 +1 --> 2 +1 --> 3 +3 --> 4 +3 --> 5 + +
+ +- If `3` has a reconcile pre-condition that is not met, `1` and `2` would be reconciled. However, + DR `3`,`4`,`5` would be deleted: `4` and `5` would be deleted concurrently but `3` would only + be deleted if `4` and `5` were deleted successfully (i.e. without error) and all existing + delete post-conditions were met. +- If `5` had a delete post-condition that was `false`, `3` would not be deleted but `4` + would still be because they don't depend on one another. +- Similarly, if `5`'s deletion resulted in an error, `3` would not be deleted but `4` would be. + +## Cleanup + +Cleanup works identically as delete for resources in reconciliation in case reconcile pre-condition +is not met, just for the whole workflow. + +### Rules + +1. Delete is called on a DR if there is no DR that depends on it +2. If a DR has DRs that depend on it, it will only be deleted if all these DRs are successfully + deleted without error and any delete post-condition is `true`. +3. A DR is "manually" deleted (i.e. it's `Deleter.delete` method is called) if it implements the + `Deleter` interface but does not implement `GarbageCollected`. If a DR does not implement + `Deleter` interface, it is considered as deleted automatically. + +### Sample + +
+ +stateDiagram-v2 +1 --> 2 +1 --> 3 +2 --> 4 +3 --> 4 + +
+ +- The DRs are deleted in the following order: `4` is deleted first, then `2` and `3` are deleted + concurrently, and, only after both are successfully deleted, `1` is deleted. +- If `2` had a delete post-condition that was `false`, `1` would not be deleted. `4` and `3` + would be deleted. +- If `2` was in error, DR `1` would not be deleted. DR `4` and `3` would be deleted. +- if `4` was in error, no other DR would be deleted. + +## Error Handling + +As mentioned before if an error happens during a reconciliation, the reconciliation of other +dependent resources will still happen, assuming they don't depend on the one that failed. If +case multiple DRs fail, the workflow would throw an +['AggregatedOperatorException'](https://github.com/java-operator-sdk/java-operator-sdk/blob/86e5121d56ed4ecb3644f2bc8327166f4f7add72/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/AggregatedOperatorException.java) +containing all the related exceptions. + +The exceptions can be handled +by [`ErrorStatusHandler`](https://github.com/java-operator-sdk/java-operator-sdk/blob/14620657fcacc8254bb96b4293eded84c20ba685/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ErrorStatusHandler.java) + +## Waiting for the actual deletion of Kubernetes Dependent Resources + +Let's consider a case when a Kubernetes Dependent Resources (KDR) depends on another resource, on cleanup +the resources will be deleted in reverse order, thus the KDR will be deleted first. +However, the workflow implementation currently simply asks the Kubernetes API server to delete the resource. This is, +however, an asynchronous process, meaning that the deletion might not occur immediately, in particular if the resource +uses finalizers that block the deletion or if the deletion itself takes some time. From the SDK's perspective, though, +the deletion has been requested and it moves on to other tasks without waiting for the resource to be actually deleted +from the server (which might never occur if it uses finalizers which are not removed). +In situations like these, if your logic depends on resources being actually removed from the cluster before a +cleanup workflow can proceed correctly, you need to block the workflow progression using a delete post-condition that +checks that the resource is actually removed or that it, at least, doesn't have any finalizers any longer. JOSDK +provides such a delete post-condition implementation in the form of +[`KubernetesResourceDeletedCondition`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/workflow/KubernetesResourceDeletedCondition.java) + +Also, check usage in an [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/manageddependentdeletecondition/ManagedDependentDefaultDeleteConditionReconciler.java). + +In such cases the Kubernetes Dependent Resource should extend `CRUDNoGCKubernetesDependentResource` +and NOT `CRUDKubernetesDependentResource` since otherwise the Kubernetes Garbage Collector would delete the resources. +In other words if a Kubernetes Dependent Resource depends on another dependent resource, it should not implement +`GargageCollected` interface, otherwise the deletion order won't be guaranteed. + +## Notes and Caveats + +- Delete is almost always called on every resource during the cleanup. However, it might be the case + that the resources were already deleted in a previous run, or not even created. This should + not be a problem, since dependent resources usually cache the state of the resource, so are + already aware that the resource does not exist and that nothing needs to be done if delete is + called. +- If a resource has owner references, it will be automatically deleted by the Kubernetes garbage + collector if the owner resource is marked for deletion. This might not be desirable, to make + sure that delete is handled by the workflow don't use garbage collected kubernetes dependent + resource, use for + example [`CRUDNoGCKubernetesDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/86e5121d56ed4ecb3644f2bc8327166f4f7add72/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/CRUDNoGCKubernetesDependentResource.java) + . +- No state is persisted regarding the workflow execution. Every reconciliation causes all the + resources to be reconciled again, in other words the whole workflow is again evaluated. + diff --git a/docsy/content/en/featured-background.jpg b/docsy/content/en/featured-background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9be72c65cf293d3001ede9324ac059e76a1bb59a GIT binary patch literal 129070 zcmbTd2Ut_t7ASmD2m})h)ewpagh-bXs-mG9LXi$ZR63y}MFq?Q-LYYxapvE_`|iE(ecyZk|Gy2%q>kJ7z~0ibW8t`P&f{PfU=DZ9Vcx;s zTzmlFNhhOx0FJN(c;ZQapHl#z0XR7*D%c<3-vBNW?BfvuK}ZaDJkrOD1#mThW5ONm zi~+tMg7`3g|Al-07ar+z8mtq7j6=hs!~OkOkwkef1){p1o-UE@b1KLuGE&9H!z<7u z+?!||8XV>k5)DDWXy$$j65{ff2$-y`uBWZ7qM-`d|8Mv|KK%Er|1-kf+g~%bY`6Ce zCid_@WB>W=f5t*9AV~K!;7#U##ykrl=vD#*;UE8Jj9dmmJL4hf=JagI|rgyRQO3Q4$cJk!UOR`J0THB9Fm4)A$dpz(tvcJeGm;Y zg&5Fb$N^$P#~?3=1qDOl&?)FF6bmInsZb`A2XUY)P!&`UHA5}XE$9x^2Mt0a&;&FK zJ%L_8%g`qD9{K|P34_6SVOW?jOdPfwCI?f3X~1-02VkZ!OPC#u33G?}!9rkBu(PlW zuvAz!i~}o&)x&PUI$?dVVb~;W0rnEM4*LlE0Y|_wa1po^oC4nq*M%FxE#MCDqi{d? z33v=V9-aX&fLFkq;5XrY@Dcbd`~`dy{uu!wb|AzMB!mh=7h#MzjBrKxBEk{p5h;j# zL>UL=uJ5?NR;7$J-z#u(#r%I}LXp+ZnSne`o8?@ttpQ zXdDG+jPt;q#}(l^ar3y(g2IC8f`(}E%9drBtem2 zOE^U+CEO#tkr0vCC*dWLBGDr8SQ0L&C}}5oMzT`!q2y;NX{kd}VN!)scctD)i%HX@ z1Eh1Md!*NQ3-3O#+kbcN?%#KB5JicG#2{h;ae(-qBuS!^qDbYWG18whdt@AC;$*JL zJd@>@)s^*?&6Vw!eNWy^wj!S;H)mZQvax- zsNtniq%ot3)il%mO|wJu167IYLoKB~(h}CP(z>YCuk}+~M>|}*S$kcFtmCdztTV4G zqHCj@rh8wHN6$#_H@!Q0-}SZiBlTPK-|bV`7r3us-`f5?`+fFT?O!sGG4L=bH+XS? zc)l>dl?lnP}95P8U z88a0!bu{IeE}F@h`I$AEy+5RN=**#BIuG4~o<*NGmooP@7GJ zuPhZU!!5h4;8qN)9IL0+a@HZ%w+=&x%@5}serB`B=7h~{Ta>MhZISJYox0swyCHjF z`{VWv_Fo)~94Ez~A@ATE##5vpfh09)-b1oxH0@I(_;mYgkpliP**>ej2EN(8YkmfPIezP`gRFek8-HVej{k=Mdcc){uYrdH zYXkoYat^u{%opq)+!-Pi5*RWNDjj+{bTUjSEHUiG3H=j!C*Fr!gx5sCB92CMM2Y}s z>S2_8R6^9tlLt-~o&0vn=~U}!!P6n9A4V%iCr7Wwn8j3|L7wqC(|?w9HumhxbB5>2 z&%@4pp6~xn_P6-omf45cb+P=hfw7};YH`_dpDs9G=!%z$XU8uk97I^5-Wb)m-sILaantrs24j>%3&XMfkeuJ+riw`=c^?i6*4c3sw3B8G~$^DZ(QwOK|rcI^?XUu0tX02x@=N#uA&AZLN zc;x+PZ6Rpk!{d{W|9rxJ%JVek8SYvBqU2)5bA{*EUTDAQerfXZ;Vb)BPnNuvHeW}) z{%bjY1-p{Jx_h;LO=IoOy4m`~#*vNX&9Kcs-z5Ga_($XfuZ^Nu{*Hh0s`V%WNEV2|8MxG9}?u_fq2;nm<$9L zgdqfB{|rC`;J^a!;lKSF7#xA*L4jv@?t}m75r~)&$bTL~7z7M_1ws%wL?56(Rtfw# z^_e{mzOG~z3*v#n{gM4Atf5Xb=tdq3dSa$bd|0}~tPfP+FWxphlD z{dxMiSyqisaiB;8^RRwO_ybW>w<$K8W?_U%xGEByeHEvck8lv`#bM#(*Y=F;aFUfP zy$-izZms+^ovwx1Q(;d*F7-r>HwF4W@u^`wb|MBaJ?kP1maCIH=|x2{AxI8|%1Q1N z@*(#@NxwX7cdl3VUoZe+AY=g%f>?MyDh7l=NGfCp-@ZanTB?&pP`;?6fVSq8Z9v*= zyb3dALHw$1_C(W&xnjR)g=oCCOQl|Hx3)x=3HwPpFyT{fGCN=zjlmBn z$;b>BlXX$?O^#8$NV^?JC?Io&)F4cQV<8C3rR!gSq7=j?u~_a9B@s%Dr-IRmGzjv9 zm9aeG@e>d!4l+hUiBmgFa)ll#THYREy7W54t2=Dq$0o9`7ODvDF!4P?r&<*HnA#^h zC2@*`+}SrMXgeYIdKZF%Rrq6O`Ugt&ET!W1X??lP=c%{!AK$1y8K%-H<9XMrGWysB z9&;Z(JYOO@4L@TAk?kfp{A2>ICR?H1R!7E>n&Yc}(?4$)y)$`AF?S~2lF};ATy(OI zDzSF8Djds}ItxD~8QD`)>NB$V*GR_aAwT=U%ZF6a5sUzPy-rFzHcsh1|{t-2|5F8Vf@GYn4^?mhO@ z)ne_y(dD*SD{}Ir_*jddzLlT8Il_U$hG=XqeTZK~LIn2$%D+$wA7r(S5+Q1@C4?%V z)LDVF0jUi7L#(jnZT=2S$)xg$>}h>_b0NH4MHc5>?SYoHL_Y~~U!?4=poFHvv2se< zpuYEVX|-Fzms2t-(o0v4q)+-u_iH(>QbmO@f0`6C&U&GB3;1*+%M+Oi{j$vP>Cr5R=DB2q+6D zSMP^b-E!NyLvfX&=rmr= zkI4>~$QyrRpz+MQa4yxdI%zskH#E}YlCM_j2&;b5B5k8-{7_q?scD-$pF5h0<Q?6$y zijr+=fL7&YE?9f7O=m3sp?0F->aJ3KP0Ky>dI#~`21jIr5dk@12~#sh_8Noy3|GBz zuh78s_M1>ycAS}z8f`#b81M-UC8F(c6Hui8!?DX_%THIZX(a*Pl@Y}{F2hqEX6@sF z4P#b|1VYD&7%z*--=#adEfigeDs*bL&_|JBA3g7}F7e2Qd|BG+?W)m@nLu-AqdB+L z3ci~UN3+s`@ZH{)6%0@OE~>qieNY~&u#Le&V##r2IZ{3So|d=9@D8#91&at^SCQg^ z;!Q10`d9#?UZCgQ z?v`Wsql!ka_(lyIh}T#!>y$N)$jX`%TUt+wb6SOM?oZ;b0&Dby41NGlibIju+g$i{ zN#t|?^#_5`M6|lMdrna%y&;tvT_0Ico}A&9QJqoav;u#pq|+3Y|JKdF#=C1Ss0AG* zmnNugT3A%Mr_Q=_rpv)!S>!%JGFLUNOYU|))d5rHAg&_FX(^xLF_bm5H?^yCzltlr zpPA)qkt<{zXXN(iH7&b=tTK`kK07mo@$kQAfvmTIa*PNfGgF)#{G6&ci|KSyq1I+S z#UJkeYD*3)?{66Akd&<)K_AO>n4sKk_(nPI@-gU>U-qb2Sg@}7L`3E3d(7K?MRV8~ zX)Q6+WQXjlLOSMo!aC%%dIE0hUqq9V@Ue0D0tBuPgPWM<$_V&V2X|!8r=M25_C4@* zmC@pBaxgs@Im>(5$e=CDPBkR;xl&(cvefc`pt%~(h%sbu5D5$y-WF2s6 zv|d0xjn5r|fXy2i1UFnja7kCA5evGy-8#m;gdcX>qd%{o=V`iHH>)+u!mAXf2m9$Y zd#x|e?MrBm60KqsRfr;0?jp+cyxJvQPx8t>D;{amn6`7+SRT}uf3@DtGvQ_yV<=Ei zaSifaDMyv`Q^Q4w zFt{DdxY4d+qK?8(Kcp!dy}#)M|ATZ*nXn?Q)2_jKey)WJl@HUY{g-1#Y&-4N_uA_{ zCyAuxXBRdo=}pl&M$W#6X>nN!@ilKajrm96HE3NMl4P|zu`!XkO9c&wu^|i%B&>k> zhty~gk)<#qk*~I$$b}#j+dUC&6Z5W8^~{KLv9UpGYte!1v52tOi%s`J%VTHl-k0Qu z_53`n6%!tPYQ65&+T!wqnCzD~FYncxKcu*k!|4(qI%=5QiC4`JUwoPUNVB0rsy#J` zk;UJ?gHHw5Y%Z?>JQ&H(DMk4irqpC7;q|Rq9 zN^ChDw!>VmB9^UIFh_UFk&9jspJ76d_joa1#KI0A*D8cXIPaoPdQD7;B~HD*nGn;M zKgS2HDrUU5{$?4DIN6-zRXeb6YfAN>K{zK03o3O%^IrbVwJr%w!2-MHsRz)8yqgv)V4P7omPPZ4t(BKUa0ku+5Ts?V@;1oiQZkb`r%#kGW z+ihN!lb74(EF21oy6y(l?Fe7G?BFbIu;BKwyJA>nM})cg%w_qG7NU~}-%J#hZYvP$ zHq*w(3`D0))GaFC$bRT*s;W@KA1I_I%dF*CrP;Q<7G>tOtz>WNA3X-v)m|=WEp7x3 zhPoPr?1d#sOjaEqO5vnvne#6Dsz3#&#{ zKUDhVsZ=#&%Vc{FMO*7`rYwy&>i7Bc#ZD0*+G|50EgoC6@~8y9)k`eMQ{q6_de4z# z31d>cO8SlYOJ#{Sebc3lf<6RR#Ist>>oJq779mXU1l$Aq9)k-!6Vp;7%#z#)pV_?P zJ3n1E_ir*=0v^8#lyQ1Em`JxXBI~E)SXuZ7V{NBfeTsLDeV8+q8xg`oy$~#=sKQmI zxV^$Q1i={Q;Feol1~9Y%OlE~q{2(z38+pQ()|YO`25JPADKtPEZ)P4AcqTgHXWv&O zj!F@XQ1jO_?7FwdaNO*3g6gEr|GVj7`S!VrA{@@mZ|7v6nCOYJeof8*)yU6J}O33 zyHq)`Ev!hT>%Agz%|leDN9(E$KK{$*0fOx>E1o7vCT2ul^sj>k;4F@~Rfoe`QLtS# z@8&0m*S~DSH;fHYn~K}Vh8?ni zfuv$$L4LMA}aYW!zU$GbK zh#GBoHZ@{7SztEFg`5T_@mrp2B|gcM6iSOsW&`VHf_-=n0j1fcmXY0g+(^&wx^80y z@(+O!%UZe|i!32`e=^JAo+Td9)IU@H;DSAFVXLy--KmDuv?52Zx1tv(8B(jO3OifO zJ#=Kegc>vzgdUOZ57>uE921q86S=KC8LG{Z4?L9_?9wqamaatY79BrvBj-qTa%2B| zz=I`cG3{g)y~2ghEUwil9(;Xq=pM}lXKjP;wM7?OGir1H4D0NDq;^Dqx#YU+z7p@w zDYx+F5+to~J)vw7RDz<7cU_ICc8i@%q>~{FXf5sHN+azAPj{%VG0K*@!K@jmg96|Z zAnb&z3Q}iS_zN3RBi2&NkridhZH10nL((1A=9`=cZMFn$N19zOwW_Vap{3WBngq)p zgvlXu)0T|NCJU|_i*{*T6)&psWuQPop6WmX`j?iey!-1VSb!_q8(m+L@_0g&RkcBk5pVa%0FiLr_cVU2CC=$#>Q_O zSf5i?zuPLZ>eNoIF)TBz7oXM2&Qf8&mS@-7FnMw_vACx##TslI_W}fAGops|s6NdY z?M^Cl=R-kOGG=TDcAz=u*9iL7an1yFAZ=yWQh9!(4ob&U^XYC5OtoOTPafE#9u zWZFLjW)6CcT4u|{CldV;(JfCW5@V^viajRY>vMXaDofss`Av-JOlpnq^UZEkQvM<2 z9wfQ&xlz~Iu1SFXU~(sOqN!^*dXu&?a`w$~dPEC@lRNPkHKB%LLlXJN3N{Ig+Ff^& zCTY}^sjZG%IY%ugTL-Aj#6-)v8g_!9;^x~V|8}4=2jfFgvVQP%{xPB=ahLOD7b(H*s zx>|i;&(m&ZlXv}1Mknya%JTTpxW*_E2xQcJT7T;Og+1 zZokxn_OcH%p0?{PHA<)pwIrJswoTG*(wM-4WQtX(+)b5h4Bu6Ca^#ZfW{GdeA^pdE zMUJvY)+`!0;C*R%cJw~z3cdWpdQ@@qRzZ9=zf8NjFf+MPF4s3bVob?28<@7v6#c-g zlBl6WM^89(U(3j7Ezq}i-_YZHnpZhwyz09t65=kQ9JeUHR@^@qa8n(dW($Ibrld(9 zt*&0{l-GVoma8|<&PpBTT=pUdy6_t2nbx~cIGUzGBQEelLIbY<#9EH-b4~FnQ7RD_^ZQuLUBArRPRcXD zXm;Gf%)PHa89lYO<$Fy(RhR$~;_K?<WnbHUW&2lNzwb9*7q9Ol`Jkx?tRD!W1kS%Ge!;3{5O)n92(oPCvX zacsVNOSAf8$EMrEwPsg+KdQf8Wx$G`QLk3<>t~*$rOFfcwF-9FG~CafyB;`QD|N`{ z#MI|`sUhYz^pZen&{RT&VUHqa7K|wanAIFglu@+>|b4=6bKtr;Qo^ zE|0;YrG!1e+2^Yx=;9n|8 zTaW*6(Th>qp-oKZ^Fgyo<=IUn7q82f^E>y}jy8SYzgTeIZ|A*%@6 zX}8(E7JyZ#$OES&=CwG5!=3D4y}pLAfPBG-N1b2tI!u}>Qp%BQXj++6K_G47 z;uGU_NG4sLAe2p&u&ildQZaMoIg>Sk4y|-XxXO$JQ#r(FgYYPJrlXb=RdjTd|FUzD z%F3v;WefdQk#d&XBy(_BFZ@lau2-v4sr*Kf-aMmeYxBg4&*rjU$*~0Km`~Z?zdn{e z8|C9m$?|-%)7o+Iw%$7@@kPm>1=_-)N08C(@GjBr-iw36_>108K=z!4R~8!FV0z3ZvqL4!IViDr2KE zBhX7yOY+X1B$-rXD|;vC?T{M@K{)4VpYC|}Vk~vJdd($qRYU(>N@d$?Kih|6N&Qx1 zF^$73MaTE)FN!LS(_1yF+T8iffaR z0G?cN#U=&pQ+w*sW0teawv~xTediB}iY#9R`LJv;-*i7+rClYX-fvs zkbp6UaS)6OC4!_7j+>%}Foq^A#n}raYojDAX0n1k!3K)=xu#AMR@(4JCd+s9nB~*K zirn%C4l@_%kh~EM%@IZCL%E}Qe32rb`i>Uy6uh4sBlq1g{mM-nN@zM7ZCD5hy zR4Ry8ZqMsU9WKznqNTcmc^q-VPLT!67i)I5H?CSP*EM#ql5tEt(NQRYvhaw$Y+-q< z?tyknL0MeggBVTAXSOA-n&ZGNBYX9T7AQ%VNH@)$Zz`B8UOcSu8aAKF4JlZRaMLO{ zzdNL59>)zYxIwruEfzG0ASaWYh%gKtZ2pZTBsVw14bley(E}J5xa&mmv0!DMfH|n; zTso6vZ617AKC{BspLE{^PQY<}^Iljoo9nrAFWh+)b;LILfCE|9M#ZRj!Ny_E9p(*S zw+b7F2WKzns0H504DcQeB&2VaUasEiSUdYi%x>Mt;=XC!N|4fVVcs5GuCO)X$&{s7 ziSX1n$n~i(Smlc2E-j=bpVw>SHCmmfUdvmC7{!Bd5zpmV59n9e>lZA@=R*n2eHH)Vs zF59gJ-E-YBF42G7A<9DPn9iia%KEZ#hW_H24qs~SQuay zbzb`X$*ql;1H85i`L8`D4@?dZ>8WOp2(u@EmDRM@5vxKf!M!K_Vte*4Y(&NM9GqA+ z_t%>lWsdzk89exL^ySyHSM2VT?miqhhW~Lk=)Lym$&YuB^n#@zfCn#_+zY|+Y&aX- zLk?=jG>C1oO)HH%fM!#O;LXz=&}@n9g+M;}e}D~=0IMn6zT=i$0K4$9Wo6)9VOT6v zokwU6?B75yxCcoW1dLsp=(y0-6aFqI;SAqLZ20xm%cFg zeJ}IP>e*#8`}*d9ORl#ML=fKmuK3yD?@+aUr%gSd6F(m>+Vp+>7!SBrnY%Gk!o2CW zuo0N1#F1(G(w$-5Z17G;uW@?IKx=jR)19gz@tBh1#!EjI<|G!?@2<`tsIB|9Z#)-q zc3^h9d_n^i1R9jc=I5>ksU`|G40JJZ3kbr%Gu#Gr9N~W?ltHxgDO*{q(y8&e`Z58`lZ=UK-l? zpwvHRBj)F>q4bkOd26M=6*k9=J3ITO^*|CU2vFK9uYrhsp6-(vAeA-{MC8)KZEOSd zL)>yF$eeFi+P25RlfLZ|D)$Z*3v?0y1g#fBPU9d5Mg!S(xI1^y9lWOT4g6Lv@PPPd zLPyd@(2ao-?`lGx{)o>0fj?a0>-gk}UsAW5f|-0t^la(1iL=LB)6Yz=eDpi|R}b}_ zgzCA^`+gqIYkKbX>J29HVZW+^QX@&*aviCL%w`rkD%w~#Y6q#l`QCa)`{UJffgiFq z4{0a#$F~a~@zDre|9vIl34O!?Z{plxKg;JBdH`dmmMH+2*Us>w}Ao`B(h=2 zNn9hu1{@dwRTr2VS9xsfLGD*@0h|`_DYhMIQjF4Eli1HwYBo74`uMvlwk79Q3Z*Sq zR+y0IR9zW8c`DChGwfyfz|#$@`?l1BhaW!I>558@{+y(b34Q(30fF^z(-yl0U;ofu*l3u(Vq()!J^1Wz=Q{oO4eg&g+b>ZJ z+=5m={9T*U!}@aPncwY&@5cl6zb`j!7K=2Pq1BAh;&c{7gFs1KgALJoaebhm3{S4| zF9YhF=+6cuaH$7X^Irh>|5ba1vteZfcOWVVpb>x;L2+kppCZ7{?WuSOgQps^6k7vN zAA{%dO*CCyk*g+7If5LP90^?(tlsGrHg~_gCYJqq#Q$8{_07S~8=I@G#T{4qyhogb zS!0p$Nwdt7>nsr=hFo2dV6aAGASJ#wRN$g>sPduevj%$ezMrQ{I3N57>#Jv?;+_wr zMVE5Me;>b=uC@03Vpq)Hzf}%&pAVJR*}rNg!5RDRQw;pJ+y*l~f1xT;Ii^aD2FR}A zt{Yav2Lu<;2!~;|6&$x{vV9s*MDW;>1_7o}A#g&V?NU1*FvY)sEA`agUxI-EUzD6? zqOLElR^E9cU9*MhPZx8%pJL=-Cr_-(RM(IHCq5z;hs(m}_w&rr3HGbvT{{pZK!wG&@P-bI&`9yBO?UhWra(pe95 zM%nu}TLuC<1DWTKx4v50YDgci9UA)M-p9`F!#dFq1I7c3Cf&ZS_-$-0tgb#8k4Tvc zip!%9WW}f9L=qD(@$)8I~NjTxr%HW*~gV<0)%Hn@<9Fppn$l8 z4F?x4{IVFoa1_xULg2LHTJN;_=2WV9XUFH!!~3|h!FZj(=u0<)riCqeZR$M7>Aae* z`|GNBecu0Ib}m*d_3-%x2)|misl^;CMM0cr$egH@{~&%tK}z<*xZ^QN`w`-c~U-6~p7 z9SPTTbo}69ufCru+05Ce8sQXq9DlnI)qVKU=-XF4m`#;$>-(OoSWKr3P&7Jwq?>~+ z2b*n>X*VdbVAXI!89tE>R=B;Z0D%FV3w#hnLzitIYvQlt`fD7_NaAiU76>s!{I#>V z?aC4NJXF14P6jJ@v%I_P!$^D-HoPjU6Du85&!Vk&hJj*RY&yHI$%?Tr(T3lOY($&% zAvIKCYe;1%0XKi<;|WCF4pKT5^TuFzz@46>kw=T}orv60+Wc@%Wc_2eDq?(V-)WsZ z0j(^ueq4LR#>&^2^P!dL>!YLbVbu2Yy<%Mt={^zOruQ=IWe7smb{yI^F+7lb0Wi%p zKoHmJfC@iE0((S+Kzqn9VE<1Nx;+NO6sT(q7f1G5A%ua%_o6Dam@A=fPgGVJnng|| z^_zK9yhJ%eS#xEy0~?gpCt@$)dx4EpXh6QsVpFN4DzrvomiL8DFE}W&3d67IAHh-k z)Dt_;S$2Fq@%%vPm7KLu!SU&plH#AG=0i1tO`ng;AKv9msj6x+&nJ4=ja@Q+(6rg8 zT=-mEw-!w;G$uFX-#_9O(Jkdux=?7H@^Hjl4w)tdBFS_+AD~Q)X>cM0!-6$a*f44z zS18%w1%dqm-Qu7H{eOjCa8iK_3M@37`v}%Kr7=!tI{TY@sSJQ}Aa&nZx^&Pa)&^o5 z3pr{y5(DDv`P>UqgoSD9Y4{vuZ}@8ZjU+14kreDWjPvK(2zef(T;$FI5e=QVBKI- z0j)%Uf!(5l)ATPDygl&iqDxWN-E%AW3mC)D(?O!T>9soCco$*N}yuxW4-RT_r^nRta851@4UqyzU%Z% zz{kMyB2{l9W0cxAWb$g>IWPaJg=RP@4&DoEdntl*m{BxIw}FFWMD9c2;CLc1P(UI7 z0xoMrw&kDm9g>fYIqXJB@4POpz z!a(!$d}Hfe=~3#|Icc}&nyiBJf1wjR* zxL@XpD=$PIxcfGTxGGwJzj&^NXEYfqlFyWTfbQZC&(o2I*gSODg1Q|vFp(+pV4R=T&zy#(fqUH`~6AM)K9jMfQ`3V#K z=~K(cnV7~0gWbjLOKE~{Y#(+m-M)A2p#9{V_dUsHgU(;RZ*@-cNA=cES!iUqclxk; z;6d|+kELz%jZ0DCX8UzAJ`~yerohV^KL4b@TJ8D!(#|#KOZUFs@m@+zUmf#kjjO)wU)O%J`{QMu9^Qjk)>Ka%xwnC2` z$+ga#y<}o>?e~n2AHR41Eq=DA#wqm8n8x^(ao$_AcMpZ~?zUZuxpO|RRQfmL8%uxQ z>Qn9f(AvDId3eWF=GN9`MCg9Ux2K2vuD$qqGBR)_V&&`iJKve{Pv0E~#JZyp$a-i3 z1Xm6?7e&KrA6su!hC*;do+vRWs-J%(MM}|uN+F}-LA0#K$V|kJ;7M(RguTgyZUA8*@j&Qtl!>!_+{(q(#z)$^_LzL z9Vj}uZ`?rIQmQE8Wc10CCr{6vqewfu&EGgXqEmFy`kZfWgMY(TVjw3t>6SQ0Mj}ed zQT(=|72m_MJVR=qBCU67OU_?kHN@3FdmU{j=PIX%C$ZI#Xad~KLCHkXAq9=6113;O zR)(YH?ROTSb4T&U~J0iTU?p$FqC*Y_RxZT@nt{Mzw@Jy~~4zH6K+{@u{r z#A5c|NXe}FDT>>6`RV8ZRN=hy&f4TvM!KI#)|keN z*-s-E)&j?F^S#=KNdJ`gFtU=TORY3n?Z^Wk{ZZp!a+ga(z58`ekSPh`qp{872*_Sf zWFI9H#b~#?$`_Ou&M3=cWWp^CxjV{@2LRBB5NQfhjLerAt}juiTL)Q@!$r_(?rwUn z{0_z1Y&^N&Q3;k=FG2y+VOaJ6qmMnI&L*{qWI~A(I?6CM^12koCN@dl%E*JN?mMvI zyD>+30sM~hzwez~3JiR;dZ(M`3DawQTIqv+bkMZ)fpdNfuU|}6A8GMdTkkv6x$q+9 z+w;g1mV5U;dOWuGME}-@$oFOo(z9njouL*ln*Hrmy;K~k|BxKQ=o-#rKJD7Sw*KXg zz@5#RkLNS0zx)4?4Enxws5zo4`}1*$V|NQO9=x87qQ^G`n8i~S+6oD%K-%bn`7I$E z3wO4hYn`)<71T#TU(YU-Yn8k1c{5uqwy@4SKwO2G#~3ckHmd{N`Ioz8OoP}o;46y+ zmS#U-1hmxCLH!XGU+7s;X6*oHgKA}kkjpVhF-u?>3{-XRV0}wh5_t?GH zQzm|pQr2%KZq~_ED7R9Qvm^U(yR8K=Lhg_pod$ezLp9@ymMPzAHRFd(4MFh>a%I72 zHJTkv!rE0Bg7FbNtz3wZ`?M_;sASr-Jep?gpI(Mck=s?X__RmzOnmE;A-(zXd!>Hb zgg-aBr;w6J=$PukX`wkJUP_Z*{>EH_$w$T7Rwj&C5@npGuE@E8hwoD|sq) zz@tn1>gh8*=ae$G*3+h)v^h8HPIypd8kMx~1ROtf>+a{RYwpWwo6Dh`AK{B(7aG26 z>xX9N)D41KOuCq%F@Jsgj_`Z>nyMxYW%lICNSIhQ!E!7zmE=%i?N1ez_dca8ojW%t)_lb=5`UwjSiiTv^1 zJnYGNlaJrdoW51+zYyS8St&mys9CqX`Kf#TTI$-5#>pPJzE*SS?;r6VRBTU z?PJVejio)PTWEix52et#1Y=p(W;IICleNxJJod+(Kjc2-A9evHz|G-lDgK(l*L#n} z==-V2Q6G#3m`66B?7lp7Gvr2a^wy&C{rc-+1e{nkVgEvSLZN@2DvMhk!`=r+%Rb-! zvIsmmzJ@8wqn)<$Ixdx5#;8i5n>RpQ6~+cWvyIS-lLymQ-PXh2dow>VxW)H%CQ^&m zhm{rP&xf!e7=*E7FGQ*O-XHPC(iN|dMcx;!x?sJ$6}2(bt#McXN#4CUeu9@U0r;L1 z5LV-9N8@njt;#F2uYUw>4*bZl`p{!KJaIf{dU>I?amlgt?uVb|XY@~h8NH_8p}c-p z>g0)`8?RZ%qP(rUDZ81&8%y>>ze`7r&PpXq30yYdb^EJ*b=XbnX?{2(eWkp?HY~o~ zJdLA#(J~P<=ZA|_i)~fft8L*l^n4<>T)*~MRm?V$-H!yk+m~K595H!AMd)g)-MSDK zrrxxG$VH}viP3C{791p~6mXN16m=d4RED@Y|Kl)-Jexxm@1m(Cb=scOR}`&Y?3=CEE&eRAnyZ_8bNTS=Y>8pW*{D3fi0F&>}j2d}+YG{w@rP{HL{g3*!@`|l%uC>lx zDwuz^HT>zU(s8emxyrpY&!d~ZpV|L#alUVZe9Ue0@n6qPKDNwv?s9Tf_PT~%xFxz{ z^z&a;cQ4Gpn0du1Sw_%ZX+*hNXXeBtF5A=#UPvwa9iKUt8ZMii*IdMql9vwP==dGB+?Rz6)poJM1nhCh0%SV z%#pAWx!gU94o&uUWST{h5Wg{P0$qiJgXCvLq<5#^%^Sl9a`zS)bOh?PB)2JuDk#Lk z2$1#F3-l~vxjK$NP~w6kH4Dv5a+Eo`9Pp*NFytuXeSe_KRr}Z&UCHhn<>JR={2x7S zw}QAHBl!V8#;eZ zRX{ItY~O>ug3&)-NBr1fY$c&N63n;tQ#yiPEbtalsPIKzC zz|>0=9**&J7ZvGY2@@dGOX#NoX07&op)Rv=dVy#gRMVEg#6~k#c+J37;hK|*qZxL>4&>LuIERb# zQo_y|#Zz~lx*%?VR2H0uirZB4qJgetV!4g&f-3Wj!0}y;oBFNSlx9z)M-2Ye_~e+# zp4+P*Jx|4yIyZHOjufu_t}pQHujjP0JLBgYFH%2ge^~n(*!%SJ_v^bPL-QXzh`8bF z=bOco|M7;5K+(#Kdw4!B zRaZN6hbEvEIe;^kIFOqHc%aLU@&fxr&i)NoVOwCNEny%=P1d4q_b*f!Wg}EhP$C~D z)!)$fhz7<&s58P-PU5(ML?J2#HxXx&OJf=1OZHeRx*lZ~x0o(8XN3>CnkM0<%%h5q z(9!k0RQY-{BI{5{!KT*PKer0=SS5@HqM&1$4`glG6o`+7y7zpyVaf6G=CfUgtz8?2 zNdsFYXU)*#rLEpp=JW5qpD(`imqGDnqN`^~$=`dMBn|c(zdGAhWbIQTCFwdceKteC z^P&93k`(myteGj+a>a(qQCcvzzld|!;Dp)o6xoPLkEAoH_a)1d%J1706o^owqeL>Y z2#fj_Pp)aVZ1|NKI&vQ8l(tp!v^gl{0?!%zFRfod;18Q?2!JQ#(ZPRGsB@1cLKHg) z+AghYc8GcA_8*QG4blh{>`a(Cq}MD99Dn) zUH_04%I!%+j!3plON-s1->zNq?g;xF(d>5a5AE(w=dqXTTc0^eCmp$sUQJc)MJ>4% zQwnyTR%KV4?7W}0P1v<7+G%#w`^%A%4HVC8?tl7D)R7bKFTw{m?Bpj>n+jJug&AY7 z8iJ#mp5FE!_o>f`C@JAY|2X7-U#eDCUtph(3%hNc$<4(BWzFVuSHIiYZtSf>POxLg zmSOd~YVIU|`6iqmQyP_dG90Z1D$)Ica-`n!MttnBY&e!|t8CtgC*nX~Hw#Hkg13#E zq8PTOzQ}h}1}hf?cvd!;AUWV%qt(d)`H#Ms)sIC<{69QB2|Sbk|EnZ~97~S5N5c?C zHdoHgZ3rtJj+rYlw)G=>^Ln1o z@&3H8&->zbN869HzX1ZWV)!Az9Uv%sqULknbG-*?=fuT2-_j`^GGBMTi{6c0`8P@8Ikcb=9ouU6dAQs3e}8#RBQ=ijAHFM!%)p@bTGkHTy)w@yJJP zYfF(rQ@}5Dx;V2(D9VcSbf9%8_eaR}gKBmh%JR0!B2>ObFBA_%-V--^px~&geI5G^ zc8PslfzQrD8*uW$a#=^!i{PUWzGv4hN+n|*D7fAnvenGkbK%~}$s5E*ckWDaqsBw_ zdD~Z_+MoBo`@(fq=;xuVhOMF-g`pd7m6>0n4pkH^f4ia`R3MZt@B?mWN*4~C8Pgp0 z4jc()>fE&^={W}%``La|7@1A`b+w|VSTQp7wJ4*V-^9vS{V98!i#itd;Z|EJ7AkbR z050fNwBM6@!0Tv%k-URh(1r0ID-OZik;NhC=M9|+v`P9%fmURZ>Xdz!0Sn7%cvm%h z#Q{U)dTilj{WI1G4>(jd4o;oRzS(Msl1lxy^H8QVfWJB-nhkjHMo&OpI1zHT6Kr{7 z4n)(ju|kqlK*;XY5p|MBAv9EpLx+iC;UyL^PY$Kcs-K7b&S@5&m39PHmbin0*$hl)y3(sfwgh;Nt{ydw%WyLTDiLw!@pDz7-FZk2l7oR>C zq9Seve+z$Jv>tKB?W)!JAu;Q+(dQ-UV*wPg!f~c^xh$ebsmRy7;Z_U@2vsOQ6(o0gs+wjIfowWmZ)iF2lGR{tObAe~RbHL7Y6{zO~q=bMBfQb=jFA9v~|CY9YjZmM$o_VN2^ z#P!!%Q@I6tXY()YSKz)Cj&9=F&l<-D%;r!C7wbgjf}NqN=rZQE+g3aUsTeL5@Zb`U8~p?6(U$?3&j~Xv+OtQ6KUeepGzbzBH#`s$B6p ze|PuWBbB?E+mDoWA6c6(MFiX}+tOZf3NP_lc&n#-xCTV2%T>H0RGRfC+7rZ9#K%6p zI!6p#8!7%m4vgp&@L|60R&4iR8rIOat2UmYNjhqW7qCGAG{?B2&y+6tzLY@G(_LlH zYgqfAM@JmHaoR)DXW*HT{EGU*>hj46#`K4!+vp_>8e{aatq{c&*Nl?dIiIR!b~nVSa@;|QZz9`+mH z{y`CYxM@B8aqdHAPiinZeAfrFq<~N4l5pj%f=-liB1`!7gQo!@Gzi`@1*wRJ$0Owr=7A?^= z)wv+TBiroe;d=O*3f81BUo0-Lw^`GQ_FhbPd`hjTAmXaV*cblA2<>mg#i)}yVON6R zx;={!e9kJyOg+yXnrjs#V`*mfn5orxL0HFhDzfdKql{uIf6k={zO9f;t8SK$fxumz zTW8!KnLnTBe!2U{_mfLYMIOabIrr;UIxm!-*Q-%)REzfL_E@eA3JG$tq4FUqZe@3} z{HxX`at+6JnT1pS>snGfPpekUMOCmRSkvO->g2Qrwa(p&`__79 zt6NvD53GDs^3l|c5`(Av#J{vNCa?58kLg;z^6CP zB*bKEnBb@AO1XKD$lA}2*-C=FlFj0^FOzM%uAXPSP5!Dl#d`Tp-*r^D>9e&R%)kq5 z{Klu(Pd|RYdfb_mQC!`|^!mqIV7#M{F*H!S9MwrRWO+Web;aZ1gLYK^1MPP^>4wig z{`7rYP98qj9>ieySsNg?978oeaeLMmT4Sen@7DI;ReDwwm{&ffM%4Avsi0QbmI%mAEa{u|!hPlBRNn1$B=+?9hVNnZO<=CUyXW?lzmQrRKEx&ndhL3|%b#B`#nPob+mQ`@r6UmeA+<-Ok$ zlP%&8q&Mb2S887j*%Wk=%U^wr(-OOy-Pu`$DUL7edYu~nrb>))aR%eV|MrM*R!QrisE5q^UOB|CMihn&; zK6}n?U)R9Q%4~bWWJe;+*;$tS%>7YQA&4@Kg6u{jLgwiFXX&6pQzEu zYu&1v>L`8J2#tX4jMX@%*L%%<7jsyVR+$P)$rD;_$mlA|RI=mX8FC}jZIgP49vt;g z>CvZz-5G27j21>LuLeO;j((Vo;Is1J2gUCod^ekjv||8&}MYb6^Zs|Kl{dcGvN=g*dv#9$R@Ym!iSsdxYV*y zF@qBMrI39@`*KSg2^?Ya%`cjNhMVn`k@10HI9*UlgLrg$}UjB$^lhQVmB zYei_M%Dfx)q|2w8(p}JM@4Gwl1T^baQ!_XXGLdZjXS$yo5Ud1GIHt{1dr@WaQ^nzv zJ#n_rAkt)Li2-B8T&>jgOGVz)X_Js3p^VmE5nbB{X=hFn@NJ(oK{|+5R7p|i>-rBn z*DCve5)yJrPetuwPs${TOH2tAdSn~V8Pv_O|q5ZBr z(slGZ*=7~XtY&DwjAO>rk_l&Q#l}|6OHNiD5|((1s~ zbRAK_6^$U*(etL56(P>cBCw=Pp6DiEg9Q7MXlfis+&FwRD;vU^REfA~yN?9|Ja;jt zaJ`%d#`0Ch-0n+h9*uWYHd~V?md}U^y<-i{&(5HY97B)fS9X^VTjz_}va$Se zT!$ROH>NnU6CU}X?lliEb>ZlTQ{SM%$7kR^cNLYb zZ_h`d|FJ1un9%kqZfl6(F6w|?N~&Mhh>MT>JhJ>{>$1pm6Q3pHl?K(*IT8na?mFt3 z1V8_m+W9r`VeUEfmE`1Q)#b15!k{S^v z<^?u=_7Do27bJK!c4aJZd#HO|Dfnf9>vqJ5#ml5xAE8xVMS^RVP{YQAMZ&XrMhd%{ zl`n8rpc-mHer!YGrO3&L+N+}@$K=h`IFg>)ypb*MvnxM;)7<&n5~2Dgufu$Key~wS z8_7KLXm)gC@i}5!eUAAPf6I8R9zJ~1tlp-)e392N+zUBTYN?Pbhj4&U_HwZieuRH6 z95V_2@NVfHGscrPo|cX(qge5?1VOS77~<0ri0k-@xqP#?byKc0`5SJgHX{S zxpQhyCu+N==FHHdAe$`REt>E=|3OD+Z0lISH}NBHn;Vt&Mz_>zR>NN1D6apsnfro1 z@-W3L3c3zzDeowX3@}~j`jGzJ;TfWj8E*zPXaVcfh2P74F56E%yfIukx=tuZ|0dAqi@%tqe)AnJ~6bq#j{jk|7?U1q{6LWr$ls96f%!G&6R7HV4+K7Pu( zT8URSnnQRmX`&1mC@m}?g0b8EBj3VKG9Ct08qE@#VJZXrDoZ*nHVP?w)ePf`>8Px z?Xdpz0}1)Sn3KA zCtxmL(SrF|`*vvxYVk1a-yc)t@LvN3o$L3WGQ6sZevS^o>bimRQ{M2YQ?9@W`l3ws zfFRca{WB|Mh9h5+dmT@f!%?K?{-Vs!oW%(Y%GvBYgC~oGdFI!B`Ay}Y!TStZRC$&& zT{*oaIkTy!Jk4Mn14<^4@+G+UgS@cGhd%k^IQzJKliqf>#{w3U)6s_{joMx1Vg(^A z5IfP-G?}IxvV@_hVh^gJ?-|MVKGeQlRzVBedR@OF*@o>BW;9+=l0!j@R}Lg*nqj3{ z^`VLiSPn}zA1{_NiA*7x|LHgUf;?T(UHc4SjwWYsPsrzfuS zz0XF>EILeRixb99rO&|A+%q`ZAk?RPJQc30Xb@w1$8#2E8I ztFo&E43$ppc}Rje$82-hWaZ`cZ6F^o$$^HRlzpZL=r~m?Pckrj@ZCp-7Ff#O8bHj( zz-y!Taasr?KrYHH)L3E)2oHPG(ekk4kz9itt=Mq|R2@+oAaQIgb;Ks~vzx@U9&x^N z<-w1lz$;-j(w4hQjcVB&X;JJ2NrxojQh~CbMD8~i?YrGkn?2?TZ8b~^a5qe1aeA_^ z!@asf7z8r1c}GLM*;^G`{RkY*wYC$q)a;RIs~qoer^C1vAmXA|Dx z7QG@DH*PPOQ2idvpC;Rgf)e$iueag*yV-!cuv^710b3F=JK`W=h2?&R)XK(*; z=me|ET5SCca{o%b<%WZk0M|3NmUNNENkzD68rYu+nsF1;o+#H>TH`BOVj+0x?oe(WP|UB54=7@g&Q`0 z5m5(it#y}7sym%pCRkZ{gHN*52Gj!MO}uV=0-R3GK15gqbCwgVg#N853V(DZe4}CL zPRh)^&S2%BB@cePhRV@f8Kn?oc1~VXl?0T(oT3C+U*wYuC~Js~E1t>!E}$op|i#VPgsO`-+I9r9|ULxrKSUC|S^bs#R!Bf<+0<;ajT zGnidP*JYEtP`EBzx4Kc{;lfF&{1{Uddzy2sAT?#khvkHgU~~){#0DfM?8VvdODr9; z04GTA2G~ae*RDrSPG4f}E!n)gSY`WmMI}b?hdJdGui}=Q5|Hl1$M1J*=RbF-+!en& zzP+&v`&ILVcJsNSJ8)&2^)IT2Pd@84yK85GK@CT>Kht6IKBKsE&SWi$uRK`UW z$-y|BEv_;L701FQDa>oI@8Es_GeGYK`fU5`_<2A+iCE0h)YkoOoNcjilbqBzTS;5= zg6~EKYojo)ex9j0)hSspwmyh@dY^5wjev)Y#SP7>XDfyV(PnqLpcxkWr?WIvrIt_I z$KqZrx5h}Y=G*1l>9`M8a5N4((jcDRetd((~v6%IKr9u7G%l7$ z66`5t_uG$4Ce$C~$^JwvYgnodan(4% z!e$BSPc0Q3Cd(VNWE#UMOVKftnlMVz{#QYE2C=4Q260I;r}>OEgZ*G$)Y!$=OnupO zjJ#1TA3^a9NGFjEK6ccbu+L@`0{njvSKihq93V$ca4!`_^yo<$jcmcaf+_!=57~S< z(O3D%E>G!Wo3`HtNBUZfRtIy8Il=hp9Z$cr^q7S7VGqmjK>HNsrad~I*!TIWz~+j%`GoSH7LPt-a=b-heJ= z%tGB`V2|p*i8{jkAQb!R6fj|rLO_uhRtN+`Ik!X}=S#qi8}p1O3M8_c znP+oJ$dq-+7q)vEf?QRUyw`!f8G{n4r%+w{OHW1bljhm4@VghH%mdlKe?Lfj-p2y! z$bth58B~+yW8smIJi)JW%0>#Rs(xB&{3n`PU#4-}Qy|9vMz;-QfcHb&fL z2)4RBIw~o?IT?mnOt@(v6*ji*K&EBM@Eh7D38R}5e~yUS2Ue`waUe(<~srVuX)TEO4bM8(()ukd2DPF2ckSZA*M(^s+^rlAQ|v(XQON~hSLwQ2H`h+ zohly`D?Pq82MydCV$q(rLsDW|Ec+T}?A2t7@Q~ zq!8HWv;raNsvFl`E>_C1mprfCdo2eVju6Cy?roBUL3`Rzyn#VNZZL@6fSFK|ghte0 zArVQ(QAXGoO%+*!Gj9ys-3iaIpNF+Wq>H#jp-{Zx9%x{-rRA}4QiI=nI*j=eHZyN< zA|?YQ4~VJZ<2Q#7O-<90Ya}fZp?O?F#?OF*doRpPQrM}1VAQrr2*gTVT^(p+5|2WZ zr0f zpN%)Eu7Z-wlhAOuw>KV(Fo}zUt5M4hv51N)BOG>0EekU<9CHJTA5GFp9ZA-JCbTf@ zuQ|5#chixdB-N^u5SwsBHraD>a#Vj`3a+e7GL=IL4Pc@B=sISG5u3!fH!@f)RsniL zsuxUJd@@vHZ#i4&;KB$Y5R2rBWeHbquu!B3?*I1yY)1}w(Vum;+@Tlk?OBrS_r%o>hFPLs83TNnj;)snDU z+-eIQO=u=kog`t?aJaFUIkJU$pJYjOa+-0)yg=`D`xMOk`xRa=kMY>Fe6$o&9kDf5 zR|}Ueg2Lfs(vueE(Go04LF6!UskxaX%ZOvtt7~tEd9JlEA54}><9jE)(<~1Hl&Qc= zrJAuNzmS2|mPy;$*%{h_xFbY)Di@cf8DetO25M!G$8NJSeDx)%A|e7#1Q%CyMUE&6 ztO_(}3>(WR(0yr;ivKY>I##!b$_9q|Ce_vP)e#0U7DY9?EOJ;TR4A|}fY4WIe??x65>`4LMqD3|3C3#XAIxY6yt6o5Tz<*8=xGsYQ7>WETOPT^{Kntc?_7^<0He5*NM zEN@LLV>Ow5tvC-HWp#CBdtX2dBB|7_V^AU2nr<$u^bne;UgjIGWIpq#I-FE|7803-rXl#&LnB}(0N?QQ({SnV6lY&INj$&eL?%}in;H_^&1 ze7}F!rO=UpKY|YpAYuz0vqvU}wV^hnT_vpG4}fODX!fuavv;#Mva!0l(hOtRq8i|5 zuADSihGm*z#!prz7w8%sH>g1~03ZAJ?g$=z1p)*Y;*G)$8q?4)u?`EmTOw)w*A!?C zYe@~?_-Hd$Cq;?d<8NV}#wh?7kr_)BeZ&&$y$1iZ`RB6N9@U93OlJ+l5C0w55V1(W zX_|QyApC!ifak|!>BwDZ5XkKlR!0Ctpo9xDC{bix(LFLV{?jD52oUC746z0XKth0M z4*ujdYn%RRUv4k%P5L(!f8wv$vktYex zNy^`QuM0b5fB*=Owiz9(mCn?afd>8&S%?azF_*Z=tS29$wBpSSDGiL}&up(70?Mnd zNEjU*l^|IHG(9M;C@v=^yeHz`(iX-5CVnK$Rb*j&mt*5V51+;+09=XG$TKkPej6AU zmzl7z_7^9@$FWboI|2j-v$W!Ghkz3UF;Jc)EQ}~EgOzK3!A(wP80vEHzQHO0)Y?NQ zz`;pffEILA7EmxPZMT>*Z1J9a)gIiP0$qeP>@5hbj|5O<2hb3J8tM-v0ofx=iEqO5 zOfHV%b`UFjkN(HnX+>1RQbkr`*;;0=InNtUZ||u6yj#e%y}8mg{s<2wK=|Ihg}x4u za}QNW3P@V_usWjb@4zPmg!y=GW`I!Id2eqNDl&NwP;d8S#@@kjh?Iw2vKE}%lM5(l zFyZ4W9#Ca^GLafg@aXUFUtR{7zDIz77ZZp8>HmO>{P%tI-(TSTAB9qb@eHt%lNEOQ zr|<}2L>XXNo}Lx9>G8y3AM_04Pp7mwJc6KUQ|?IOeKJ{AQ4a)r3zH>k9D!Fy?0f-@ zk^c@3U>X_B5nN_x|6<*LgZ?}8zZCrEPk$i+ZfOHpd2~x`5-W-m@o5IoLg4=hzy%N| zZO)VckR62++EV$N?eY?DR55@}V>s-AZ13eRmp^k9`R^m}m+OFO7dHHV&os9^!S?s( zj>Yn*&8Q8t1}s0uw}nX=t3wELaUUO;`wiJHlOQFf*@yY=E#cT+yT$);2aW%Ikb9gi z`EOf)6@cdE|3UZ$HT+grVcscb0jcj#XWEmRX)I-i!h0%#HZ*wt=k%+wvJ_HcdHT^L zV=7@DJOmg}>|c#w?~U&N!3T)HKWhdS@&6|ThVute0AEC0?50Fj{rR<}iu0E_0AwEu z1;rlN)2hm28_J}T5ayjyt~rMvxCt^vuoS#B-?`Lu00p5pKyfG%0LZ$hgMjY-_7gnw zr@Or#{{Qe809pZ3h@=tu08z0xv&SfzhZE*Cg}J2@YezF`H#7Ua_oSn@Cn`ukG(hFl zxeP?A7^qs=c!GwT_?qiE95n&o058RmX7-u~?DGE`7jRls?WLntilC9pQa}OSp+*Yu zaUdou&Z5NB#&y&Tff{<~fI*s*%S!{c#r`C16iTfCZBvdY(^7N);YuJT{=w>NMqnC1 z9suF9_es{!5Ya&THmj)8S)&f__2!hf*uqSko*|}G*x`*vCj(IGfD11fb06sUdM&(h zMS$$4Z9y{TO~_Q4pBdnEE%9VN6k^czs`duFH|GBSKB_Ol4Lx&_+3-i@A{K6J5{RjV zwLs=t8YQ9ef0$QwHH8va?uN;GhBd_S{11QbG_bguIEs^_< zILhL_k$*#O{RPv1*aM^sAWO@=-q1k)4jn*HRN!e(yN)ozgH?&s)U#ntoq2k{oU^D~ zzab?~S3x~qi@0XS;hw*+CQ^g$5t`GtgcTk^QC9>5%+*Sc{A$xkvDw}v=6BwGD0z|{ z?R$+8c2$h9l68b@zqT%{dEf~RE{47)xTD!E=x?HJ;ya4Zh0dfaz?+wgEo}SA0~CVo zn=xe2l92w^Ux=(X50W)bD1Xi-duUrDi`;I^7N2~pZ$4h)WpS~5y2-NSlcztLC^T1$ z9uT-mNBW;w%7$s?T@Gt;FM*a{ZBtiLo6syQut@m~ZRp9JwCh0}<~GR|;1&*tCoFHz z?zEj$6k2Q14aubM14-VBov;FP1dE&#DWt z1Dw-8O$`pi)R>RgRh@n9qkO}ycaPL44D|dWv?rx#Zf=@(h6OCg?XdF?ATRf&b8hj! zQSH~fa65jRap_~DGzDjkdUa1$*2-aH$(=l~y(`liM9DfCx+8Yg7QWMD5fS8) z_`gYdF(jnQZ^+x>!cTOEUVpPsW?yLPlkXQ2mxn(Nu&3Xk@c+`kT1d*QLEgy>5ztk# zI-ESz5H?KF)(qs*d~6P@{0-Up(UWZFtl{84dwAqn&&Tg>VP)w`7Z`!#LYkC0JL}9Czw<1?)gfHmX zPqvGHB{8#qL(<2xW-2NKggmladg4!~Cj`#PB+4~3^>n+woT&cJn-W3|TPWOVFwvDo z!#008ENBT>ZkicUf@qE1^ke?`_Ze946*r8K0i|C_WNYByLFQ~aH%7HP<(7|7x_Dh? z8zHb#f0#U^Y$mkj=ijM!SG~bS?!5KRGgukL&VOzJ7Jg#Egqv6BgzKO=tQ5<+2+j*> zc41Tt+u^D2_;ngcCVD)z9rkcp##ty`^<-0QJg(uzAl{L#5aO(3r2uCG|YD zpck&h>7G3fn0zesy5LPlnBM1b^>FbyWKnTwqmmfGLeN1vp}=U#e1DifX~ezSKi!IV zlUud0@xo?4qWlQVxc5oqnYvAakdg}Hu#EZhi}lsmtDCn`KsV>@uJ&0)EntwEmn5D zy*Dj|9FRTNl&`!se~*gYaT`(4)cZ-hx>k?&SDO0wpZR;}%#aiM8z)IQ01u{soHG8XB*r8(NKHe{fU!ZTC@uK4og)LW$3+(@(N zORUiyiU=h4R#s57JaXr!sk_%W&4em=1CB)IJwmVee#Q~cY@(HvX^7vD#D820e`aAC zc5Ebb|M8MldoweDbpvvo1YW>CiYetv5(@M!JL$<}2+>R|n-#dm;*Lo`@T#UsP6RgrFEq)qi zG1npjGKOQ*Rka1TBK*(-MvNn{Vn69G_oR<;1vIXuhKz8ry3Dy8%nw@<;)K?m>~Se5 z;Z1g6SRJ^*&02x|fiBG3ZvO}V>>%_6DG8`XZqydik;^v%+L`gGbJqtbswH)q5mgx- z#+v;$?qObw!=Lei1JcUev$=<SLZw4{QHm^3@9Hd*m3xVfpy1ZFpat^~n`7RD(7Fq_eNl-jRj zKcbAOzGT|G%K);&Jx$))>*^~pC2j4L0KD}U<=9RD?~h7Ts)j(2f4dGS2H@E1^pgPZ zlNw2e_wyU-z1jGc`b&>;#rtbmvGds6^G55}BD9?^Y3H}-sr|^e=8s|5st4GM5gDU|#`j+=||1IVW^w&G>zBNO`AZfoK|B7%M7tbFCRsrT}B)2#=ekju}5;=ZZ z#MR!){6ff*4Lx%RsxUOzcBl6r zzZU~%vt$&ZRn7Ne-=#}`7#h6E05%>6ZSwG3kLB_#tp_Ws_Wf=X!;~xK`{1=yKfd1( z*jTs!{K<7dC4@?w;>+kTXjs^wG64`#g%a9>hJ`ZKcE*55^y$Vt+%# z@$?(>7+Z2ADoR&CHG7#rI+tcly>_nEHyC}mW5Qzqqs`{~eaJte8z$g2AfRj>pZ#zl zN0y;XDaIo065j{;cOD)#3(7vdm?NipesDm_w#_#n2rVMQeXgmCII^=~JM=oCuq~Wy zFHs|pHjEuPnM@goml1Cx1Hp|si)>c=_PlA4+@jnx{j-2&wWXKr`hJ7v78n=-+pr}j zQuBtgqh234q^%S|pPUU_uw4B@o0_yEi1`VKrL+@zqY7P@KVC~|XPEJJDa>08JRI7o zdjF_!WXNjZU3`3TXbFXS;MhKNzq1Ce(<$({Orv&(x|oSJwc`rx7`x6pBReA+e5JRd zh#IVx12!q-iXmh1vAnS$U*Ah4<>l3LuYf`v>~!3aNHsAOK_b6vo!^k|=}VULm;n8{*#LBe!U)Hd*kMq;xDg#qGVvx!JjdpeWoDMe_?)=s(C#lMk_} zbm?dAxeGA6jPzqQtPh8I-P?_xMk<-QCwVpa*=9M#7ld!}LmYRglTt;upJY`?bo zs~TgQm1!=gJJiBV$or|AzTi@yBlv6)LmsuJamFgxCR z=BJ@iJ9Sd^QQ8hk-KCO1|(#RcV_UO@j^yNPv zr%OVMT9-&1g|zz~&Q}!tQ&i|`g~284-NnOpTHkI}&dhMt&y#-r^Bdx{6P!Xnh@5Fg zlGwY^EesXpt&*)J;dz*Ge^`+C*2tOrAHkI4HgtyPnrO<>WG_>JhFt zAd}=Dw#2gN8ebESEc$jAE7c!q&s_7&_<1F^u*G%Trb=)?!$+~%wZmnOij2C`)_BaH zt`VPaV%ni;{?q*Wb>a4jhMVMpZ^-O73%a5*-OPtZudj04H%kE;ZR^$Q!~h2ab=ZuS zt^$qz`mz3(lV|4UgJepG^26;GSBsDL+R?MzTuLmBp;6;PjPyj(wgvdV=V&GIW9v>W zUkCdxeVlH!y{B!f!+sK4+JaihZOsgn?$*fsAzN9+$*{Y8dR=G}nG9CAN4kPr58rUY zMBBe#E#cOu+RUfRCZ~~wr!$9V9!v1uQbtS+aAFq@g8+3GNF*D`c_o-uR^0*XMP>RrR3BA z>0;FZ&gMM&E>k|RBvN6rJ>E2%ZR=W`x^qO&m z7kc>1VnoDav1VGG(H|!nq5@b%N-Mem6T8La(5v>JReBpg=OE-h0LySv&pi@95w~T+ z+y96VAb!uRV6aS()IntO5oXIK(q*ezk(8c{lIb^d$1~kCw6opmt&%<386})!>9K)I zngL66_m&sHunLSduI?mjR!gd%kS2orcA=3s*w0ra0$V*WX8r{PR$i|Zh@+XGQuM?8 z!0~8(_$bL*_ESV>1_yQD*1o93uizaeFDFXx)nln(}a-&!J_ ziJGnR^Y!yfmh7?eImU%>KR2QwjXj#V6yu=%ez8C3o?zJx1I>!NaDUrN7IRKR=AAMx ztd?8{$1+JFbHb`>5)69)VA!bZm+S97$RtAJ!hBok+Q3W;+>^isMvXes#IRS}`HnNN z3+&Q%?bGm|)kv~WAwTEbsWuC_5b11D`kI&BZRYYfN(9yK>8l0oxgsZ#uqa19p~0)u zS6@l~id48tar86PF4VYS4j<1BFvJZ$e>9PO7tW{VZg!yqarHv)a$<8)5U_qi6G&At z9~4v5vXjtb03E+gMQ)RuNXFtWJ+1`uB~IS7OEpSTH*%H&YiqKEw0&&%j4nC`UsT-V zU~`;fk?>a*x2jTif^K5Jx&^a`QjvOvTFI?yS3Z{H9?APf78(+Rg{itbpFDza`vOaJ z7xt6q8oJLfHPbj2-}$J;e5<+G9(Hp6zC|*?MnHlLh6Q$N?9=n6e#s*79^Gm>x<@3h z$90=Z(3q^9w)4EyBD$nePS~@g3$+?1W~y2ehO=`bgvPi<;7k(_ZazYSfBPF7%hYDKV8aZ#TMN6(Up_Au z%%4+xLl7!1gT;C*FLxhn14g0323mD&dM)rgM`p*we`KUDtk$kz&ugC*99pV6PP~yw z4d;!j;y|pV`oJPJEULNp3xa5=54lodANy7Y8buwC{CadRz9y}11AXldgPewI!A&k1 zqA$*^6n*@0z}Xm41wSLgqwbo%xL9s2C1w}kjvFbs-)qqVEN^FdfVtShVol$bLy%E` zCVa(_40Ur9)JuV{EG5LJHL5~`@NpymeR+g$&y%5U7^-b(Vi(hJ0d+vgR2YCr(KdcX-w{;@yA+<@guJkJnqZuWeg_{GsE2<&J+kl z`d|V?9h@Xux-if_$?J%ZGhbFOGA!1yPbalRU>i{kud|g|DFoi(teZ1iN83%z`Ck&V zWZGBEp*z&Xp`qdm1IENa->mCMe#$4m!qoT-hC=Lbi1YmXq>OD!ITltWKDP8cx^Hbx z24#g8!=wrNaN7$# z`kOZkNm)@%F7|G@myq?^3NnhQME7_<zqPP>2!tmvtAa#`|@!hxA z@FkPrg@yiR*tNy0h1oEx6!TBMF2oWs#?ec?!!lVV;Q@!o1M8NG$D8`P7qfG@M0Jp1 z3|ThQHX-kbMzCvDyY&&vw^a1YX-@KrmP}@fYUhM%e~QfnhjAuc`q8jXb%K1FTUkXl zGuhSMgIrPG+ov@06>C{|3)tdERmxMXJP|udlJD8b=$T=`S;llGIqzO`cxpqT-I?Zk zmU<+K-lIrfnb#1&UP&XS#vh2E9FcpMdC5emKDT~?+}D(o-YD|$ zYTwn0;g{Q^DxtwIr9PxyYy3y{X@+5tl|vA1S=KFzj>$r%jKly-$e6KsFcy`aZV`49 zghz~+?;zJqG&jCLuh6BE$j!!sX>x;MM1F^O(fn8>=_#&>q@#mk-XN(lI1^r-&TTj4-~b17LeN>9IO`xP&D zV|<%zp(AOyRnqKO9dkDkdb?>eE7^QFoy8zgtt-{`?y#>@jSMFXR3akn!0^o5W~Q5u zAd{NTdR|h~W#l*HS>ZjRlPfjPX7PCQ(Os|C+3_syIoJpvX#rOu-_N{qV{bzVQcp8% z1KV4tT5?iID7BRt@oS<<1}@F(hb1q9DO(Ik17|}S?jt-{)`(O;hJFE*^+W}}GOm=j zu^m@rzT1a{D~fz25j#B8`!!i+z(@a*Ge~FY~dtBn~>R|o7bF@po1q?_2(49x8; z}w_!d=W$DF=@{2 z{@*;Ohon>o|82EWfD?b|1s*!g$$@{L!)j{#(p5z-ovf2)QLyo|U&9v-%dRCulUbu= zgbOn^vm~Xn1ev97ZkV-fvTs=|LPR@+Tz2rrjr5L*4JRfyVsu9K8s`>)l&YX3S*}99 zRy7nUesHxK7t?~h%||d@l2o>dLzKKvZ~9l{C7k%)cx*jnHqFR4Zo{{52-n=)+`+aqlM_PmZHVWe}&wWQ;2PBI5G8r|y|cuCGV*w#+1+{dHU;UUqn6 z(JvytzAvX@N@xPEYbfvGm8~WqskGGovEms#ZdgxozB>|0F zL4~QQ3BY=isM360+cdRsX0hT;srkJ!>}$15EFy)65#mGu=Bp!1DLhxWN{+z1xKhkU ztX)dD6fVb8XOD0-Vk&32-*lVw_qZ8zs(d$|bzf`2c{%8mVX9=!?5!n9Z~`%N$j7CH zDU5-KsR!G859@NUeU|{P^D*qp6E4`Zx*X`zi^<5H15l&p8Gc`}#9)LT=EXG{VuTu8knXUTQzv9NvtAUZRE%5hF4$zBe)^>Wbk z;^vY1;6+-N?sdD|Pn*pHuJXBtx-dKPoF>-PcDgVT*P{ACC^Mtk4LR-G92%*s<0dzz zeZAlr*$gy|J|6D5JRtbze$pXLFDehN}ODDu;lemZ<@guN3 z59oB$^fV7MH(Bf*_MUULiG!PmsbK4?aL(J4=LhW2YRl49Y>U8#Ihi-4)+K0Wn|nA@ zwjoT_Lg!Chr>(JnYzgE_gFjMyz>#dJB=RlUk=M&tv{Z8aVIXwlKUh zfPMBjG$>`+TBZP>tjL$2(Z=oW;oiR-)Y3(bWQl~vaqa}k%zC;<%?ue2M(P?>Py$u` zw|bjhKg(R_xZmT{R9mMHb3C#?tTz5Ix}+)x=v0@t6Y1jYg1j-OZVo*V5i~ux$Hu<) zeXmkk1jWVcr6(&UJ1mCMJ!^-hL#~{Be?@Es(_9by&*`x_2^8$U6|$Aba{uyT73qnA zc1X~);p?S&LsgZQ-c>sd87-bi9Ry+uatF65U3Fy(`-H;2c)Vvdzf95y=lb3-jx5g3 zek7*<>J6ixoM#7mYP0(D!`i^<|9E;6aHzlU4_sP4*0N4x$vXD2j4gz+GnN?p5Sg(L z3ME3ymSq_GzBBfT!H_6fW^CE_P+3D15{mSH`~H9b|2$7UJ@2RYz3+4Gx#ym9&+BzB zj-Fi<&*H~M*%@X`TEdy&O!_FPQE~EqcVB-<95w<)J|E2?ZbE9FJqGp}PhMW?0GiehZP!JI3Q!kj~1Lf8aT)z#I<(l!Tj+|&{h zutAlpC2OJ&V=@_8g|FbDve=-~HSNvV;o;gqe1_jYsv9Zby?;~*d8Mh*dBRibk8Soe zUZ2JG71EpdPW_`|j>quQD`&mF$0#XUR?|@*4>f#CCx2BDE<$t$oAyeb#Ns~ooh?Mh zbHC(Ido;)KWWlG~sjrcN;O!d(`dn>>+iGjyD(yke>GxOlb0^=NA9OReBfscBxjXrE z*`dq<(y#ZH_l97q>W0y8SghEkvYN%wQL}!gbatPn_@q@`v`6plv-XeIuceq3h`m4F z*wm9=sfPJwGIqV^#mcbB%Wp@F`3M|#*(MVG z=w4N0O5uYEa{I9bgN;irM5dS9xmXY|tbmG6oeEH4vc%J)u{5(~o&WYm7J6|WOH004 z$ARdyb>8mKqn*&khnrdTqyoAWln(cH1I79&3xLxA%GYLk!v5~uZCzGx`|lVXaR|ys zhrte$hok*UtK*bQOGX5g@!AG3=hDZRzpeZy=bN(Qd9REM>2QfL05So>8k!5C(CNf4 zq-h9<-i!I*!D1oP0O~7q&cp-|RWgJvzKDsnFK~N?KugTV(~~;Ia15h+=AGR-8c&(| zquHT0kB81~b59;K)N_`;67Q+pS_(vl_oU9-*q7N1E%sht?pgfC!PLtxy$-tqxC6!v zFYVirii$p7!hV`p2BlloyE0w9KPg{MnoS8PyNCN27$7U2OeEC?elmb_CM}5wMMR$d zeE65RO0sPwIl*(fm zG;3AykxiDo-lB}|T7K4Yb{yLSy}D2S3%$HU4dzwPN}G3+qbPx26M*duQfgEr>}PN6 zYUZ`>Ztx1VQmX7amTO?P!bH_jyP*~QbC8?pOD}e&N2h0Dn)rYShC367uf6P=V_Rd# zdZxj){|Y^3Q^MSOZ72{6q}h=opLtgWQ@Ipx-sDo`m*8+paa~_LWQ&sR=>tMF#oKB9 z8TS%QrMeU$ZKGap2?ID?BVYF~^=A^)Y#x@Jf|l&5jHwatkPR=;v%OKq?XVdU236^x zhdt3OL0w5uxXuz?=M+p5{nyO71Eu!AJkC(R_Gal920r}PEP_dyIbZqYge4o=owO?9s^p3KU+9;rybbPfA8h&@ z=06+5&*o58{&W)Bd?e7%$U{z~F?<6r8@I~!SA_H_h=}f}+SC@(9g-RO9D|h&kb~W} z44je=g!9V)Xg@bE)@hD1P|CL^@NE0|;Um1jAVW}P!4v+*RkNkizQ`z^k8#jmPV-0( zD7^CLKPuLvv}iwgPi09IYjKQM!%!5YHzN=KiL9cgiGUKFORq7z?!BA*8h6D{DuPJ}MM$rpE9&0o zrjwkKD5Er;8&2`eG?2=AUqz7C^vy=p3S_s$R$h3!d%bpW+l5tm+e;Y;E;DRVFCIbDwBpmy z{qQK2z`*I8{Hn>~T%Lr43@@AP7S}-uKbv4oRX=l0Jk7iD@5WPETGV%uc(fA}Ux&85y!)})5}8f2ku;4zK{Sy}B# z*Ttg}Sp*CgtZcd%XWlS=u?02gU`|FgZxrGaj^Ws9WG|r8`x^F zu)!_Q*dDL<|EN?SPDy(J%3C+&%TGR18vrM>ro}SmUe#{PIWv(r``WnazNQ)bMSrqL zPZD~7Gr)1_zv_y}zRGh`iq+#;to23;FMVlucQH!#;Q%}Y`b9wxqTpHCprcvBUOI&i*bX6#M&qH+wWIs3%*idGQNNj&@>0K)<6qLhs0dpT5OJUVOq$zlY`1rn z6LBND?Quuz>V6Bh^jmTuCMzAfKYYEiJwUu-vf}+(B@lnC9N_1it9H{y2AnFI0tu(+ zhsGE-udnn$!}F8x_XpoyY#8J~f7d?|9?qcyXcsTIlXaK{%YTF?cmP!7NalX=%?{M5*i;j#3&~UIo1y!0ohGTM#7{$X zP8D7tuNqpCybVmuAS16eR9I?4KN`6j-O%~crMz5yFGpnIv!=9by6COAqeELq4DsEm z>UN3W`D}qe1lI|&brm_D zb1si!#A#z$l;`TpyzXJKCvzD_SzgLKs{oqY?OtB?%(Vr1xlWf1y}76iHl=Vu6x+uT zDVL3R;@72aaifk87jF0U6|!@7_WVf&h$_Woxlw%^GN-bsZT+fqAJQ1I;>F3v+w{!yYOP(KH7Z8sIA zCeoGGoWFiF>1WIkeq`&U;R1k7DdEwHQFG)uK}zzMNdvxyp?q7kYmcA&!vyFEE-rWE zGDFZxnh{W&^#WKU2*n1&7C-kSTQ?JMxlpya^S-c3?cG3fii>TXhtya+;_hBruTWD) zcQ0h~6Wa>!69ZBJ;seV7F;CFzBlF%&ta_$^w`U~sU$`3>>gRJ!~ zc^e#~iFT8+O_Uz8+$3tbTuU~k4bkVLCvnqqi%z>OQ!7c%T(k14Zf!B}#>hn#mhAym zF*g56==F|UfP^ZnB||YoJ!HxPKUwo`dIsoG@YQ?ct%e**4RBqolMkeQJ;EQ-7Ak=H!{?ms!~d&C9(R>NjCXl^FZ zFPH*t0Py#@Adr`BeKwKUY20piIhUvSbv8PkH5UWTLZ3XE6l}`&5)-0Ic2zJ zQc$+blp9=HbHuKlinxv2sQc6z+=Dt2EfG`+P=s!z#VgObX{OWZV2QFlz(!c^{W+Js zq>&pDDgqS0V(}|}xJKnUmx#j+E!6<&kkGYjr?V8H&t?HUS}4jOG}TNN-b3h0^K;fx zNxtltc>7RlQ@$tJLa#jqnk~%01rfgaX((n@u&|>F^<72#>*q31`B0PZ=+1C&tEpBQ5V$QJIMij3?-E_E%8EGWMi$1-Q>fMPGgrgWs z^#V#DIOnzb-^pl*KiUnzCNCgv$2ar}=EufH{D1g!Md)7RW)5-Xdy%e)7N81fy<2Bv ziYjzdFPni=Syw(DT0c2C#hty>_@x}3=}I9B`cDFm;pR=n`i5asZHOx+YuLT>+OKXl z+nl9zMW=kO+=*X$X)pM^l4flcAIYUW`fD-|daMlqg1_iw@Re2->O5*z1=xk@8HzN= zDlxmn0!w;%6{e|zTolFNnLz+>vKK2rywErz76D(gOCH-A|J1KLmUxR5x5f}`0yB$T zFLE(ik_cS9#<%XJYq508drs>8oUrm$bW)jII*&fqEuZH~h>C*fPwibI&;$U<&?^WZ zRN?5qNC%Xy{X&3^*%b`&UJDeKc7wHZ5qIW6unr#WA?W-eCCZ7B^D#9Os*_X!~W! z%dGxTXnRLBHPxg~9Q*dSyeJbc40X3@|EgP;HqbFyhkI;bI9>&ySSILY#6fUHjRT2k zk8B4C&vNI+%>E`xr!qIMBcSdfo1y%kA z+3q=q8mcQ4nns30-nK8?`awHKl=@nwIq15&x&@09#Gz#;QycnlB7c@LHEmlEN5HEC z01B@OC(FEFyQXuQ%^iT)@9H0?1=X&(b-5*9F1!;-Q)B-3ll_Bt%DIeZa_I`{C&F;8 zL09OWb01M_o(Vxhx!1U4^&Q;ks$Z|DG*4DlM zmakN-{%j%~65{;Wc5ht8>-Y9vgTC8X>2hOVocdF~TCAu1UE-icL1iG0MUkyvpOt$! zKrU6aZ?iF1U6NWov1y&q9Rzk+!Gib# zd0b1<@XMXO`#3eWpzL4uea!ov7?ur&pLchhFys`)^zVYcQC(Ux{ zWzk+YDOQMqrfHaDu%BKyz;4`O;`#h z<`0|_W<0+5`;tp5Yz5yGT;Bq~wSitg%WWdV0MwEozK}Xj6sXTOmXF-Xu>A@YXzkb_ zVSl=*Uvk+hS(^7OzX^QQf@?_Z3fH0GB(CW9Cm4mOdIl~y_5plJ>}vM-NR(R?D8ve< z#tR%2y0}AnSci%fe?P^tVgK4n#LJoNYM( z@?w@7*-a?X2uH8Dw>v;5vFETF2bMwc%lhMcJV)Z*wg-d`s!H;@xXq5;N!Gc+CK>}3 zu=WTr;esnc^tgZAGvC%Z)L~eq$om<+%?ObX(a(51x6-)7sXUwAAH_S%6m?-)p$MqU zLj3d~n)mQJkT1<ia#{sr~IU;~KNW<-rrgZ!iC1A=~ zZl--7e$j$f(b`*^PIoOU(ocJlizOL-Szwz}Eg@#G*7zq6XOD z02%z84SxQ+z27QxTJlFk}RNJhl??q}Q zyh+^bP;OBZ|v*341q;=ut(A}K0hCJCH9zTJ{Nt-*P=Jn*bI$33mWX%!UIj`QaR zc3;Gc?Q4CDY5A<(-TJZ@{`9RyMYXEE;%_I6U3p5Ou_4k7j>wl6n$j|e)S6P4juRML zF%}`OFhqy2YX{Dc8QP2Vo<7)nIR{4|$MZhp-<)9J(OX{Swiv?@`RENNdAyj+FY}#W zh#W*5qVSTEq|YnRXX%DdgLW(p(;GW1pP}!#)|$C?FiuIwJKh=N_RXXQdgS~mB8reT zo-Zi|cOo(hHMn#$1lSdO*ts<1_>dac` z3@&x9ZiN9x1^NGtit7Bv%Jbg^WFi9zmF60s|k1EuBp}Yx^;(B z()kZc|LBtDRH}vo@Nk8&=BM}_4Gfa& zjF^V?4aFV>OJa~h{aYVYxigvuF;T$a-DPjUE57V6e|RL!ZEvwR(Mub+`BO{=FSfhR z$~Fw100&l03+2Hw9^n=7Dr@I1mB= z1e}TSKRdm^OwG^4A^_u)(J*^>$LXT1>3v^T!57Jzi08#9VtD=g|2q-m%5Ca@R2#(9 ze^j4u-A^5ArqMf{Z(W~fHCtcQM#R@gda6!g1hylGMika6d~eFXEe87by?I+xR(BxA-T}eLoD$;V>Bq8f;4aSXS> zY0U)^}>Y~ zBZpU~Mn7Qry{B?rL+3o%vQb}Sg}Fh-1rfit{!uOac#E9fdudIs=Gu4zQW9ddoOM0U zsPLD5KmIn#m_QVZ-uJ$u0y&U<=y8*=D=IvVD{=Wo8(Y6Q=o)>73>~z>rTrx%@)I=)pFoS0VeRpy!dA^^>zU~B zXSRPZuhx+Py4QAX_?cYJ`dWGj+jo1WtpD=x71TD~yeVVozOCu1i+`NFMyQyLzF(3V zirYK;@YXOy(Uq`J; z?9nNq3fJOt#BBBP;^IOUg4XH6oi7SXo8dNdEWdUF)V*bkd z8>Vl^9@oX@_}7lBAkV&1KKxCx&1sesVdtqJwr(W#-_yMEDNPOWCo*;KX4rubmo~BB z#`m$XjR~U!MHbg8188z?CM>dU(%bvHuIn83kxcYcH7vVbw@@BP%D*g4X#7&8aX&#v z{vXwBe+)x9NXFuj>mKcK;n>om-hZO~0r z_z$fSSJ5Whs}bLn0;f-SqWVB+koQh&;*$xKb7$G|WjNGcUTJW$tu@?d|4)XnOA=@L zNrBQJT+Y(uuSzm9Vn)YWCg_a-MLg{lLuYlzAo_(BTs7#YoI^?BgwNA{|C#EUffk4w z+0rj>TVIY&UC4WQH#loke5673#ec6#rBUEt@qe)-zBpq`{$H{bhwZmtUh>A=_7-k4 z;6U&Dl(w?1RT_G}DP8C`SsdXxDIk89l&Gw%aJI>2`_8QY(}zXlZU4~i2!C_p{SO{| zmexN(sxL$;El&dgzDi8GqRx=;)9JdupoJS+5nL=EZpzeGSCk6eEnr@YGQO4ahly?8 z(k@x()wS8Rtt^QWXns7XY`^PxYW}a;_RTZVmya(9gJ|6ZE^XBuL-vQ*P6n0GmA1(u zt^aYSB3h-LgPhECw{fvgKkcYRzq`I~ANRE2uOX`$zpFnq2(17YuZ)bV3~mfm`fk&v z+HI_M(3WCap8nPkXXVU{I-lBh8$UkHO=?kQc{pJ>msFd1 zXWS*i($>f-ucpm;{Efy9dfrf*6Dd!Aj;96dDlx}S3~}aF@4Ekn{(*c*`^c22(`}sT z_oU)=bu}K2p2)eys>ArqaPdg3YhC^nIbNRC^gW12_|i`cmw!~=eRdbC02`%U#lLBB zNfYQfHEcA}m+j%7N8b?mN9AOup>W{Lr_K3>n{8(A%zLHC2l=Dbzf)#};9B#CpOxRw z1BR#_6m;^Om<_lr)O;hXldsrE1H~1gqoZ6I^fW0=&}uP8-(q~wQmCuDpdqVAh8(-BArKTqLS{N#bUPcDwzj*WK5(v`z{$TLC?^#_> zmdRi%jX_6VVibxjb!>D|tRJQ_{K_%36b_3k4xqo%qhi6Fezh*T zDQObi`6vBz14|8h_7ECGD@%iCMaUn>{MH`%rPEO#+lo?oUqg^@xpIH&dzT80Z1J1o zMtY`LF9$MK?y=@ZTaM?ni!%bBHZdizZWYAr(c)*zb|4ca8LRduOVJ66^TV{#<|YUh zv(t+u=-y(AttMw*kh`)j71z;l1t(B#jmQz(z&f!UK_BtAF-6CNq##UKsESHC>u7^O z`USMdWuXX6Dk8Zo5e(Uv@CNHh{8q3Ot+(?JbiQsa?SzLHtR2CKmxn%#+g1JdU;X+v zWwP0`Y!yCNpfPCR^6bk$DiPxM*s@8R*(1opO~~7RJ&^gOhjuPgg{}4(LE3~Hy;r{S zj}KITy2iUDo>&H(FwzK)eirr0sk#!l{LGDkF;6*DD?-79*;T|Y(xntdqntF5Fa8zh z=nFB*5PD628i`=>OMwNwp=H7}DX!H=JZaJfFtLQr0Fpl4T4Rv-(#Y{ikaO%@?|j zW2DftlyzsODDMbMv1mL563!sBjRV=-)crcTahjWDlVZeHsrA^NBuh@o3OACkdBQJ9 z&z0Aw7h96*zfl!00Tjyi$6d-2%b6HYVgrFL_dYN0* zpeQFH$R*p?dacS^IRB*JcIu1|NYlW_*vB@i8#s8Uw*mcM^@sH2>^ZLX@?N14tyKSk z>8J4}%=GBd&XqYe%b49FIcdb4q9BbE;d@q(a}a72n?98V*)w31wBV1L@x6 zJGpwot(@~ZxX=T*DTgSP8pk~Q@oP~E1tj&*{tu_FqD;=+`d5B(rQ3sI>WIFa_&Jt% zA|xEq>ODC7-8lG~VsA-mv}UK%5U#}jgvZ2)*RkPdD><0<(Y<(qOHQb-m&3mjTFD}> za$3{}T0ca3x@KOIh&@s-%!q;x&D7^xit8ia_PL66qC8!aA2!g|_$S^i{fweqr{{U& zIhzd)O%S;WSK{VoNv`76iww^4VX1ko;ZJ{EJ%YFa4W*-%a;ZS?RB~0N8gS9-k~ei? zf?0JOI~lomvN!qXc%g}v(ZgV_a0aPRm9OJwhf~;Rw!%_Q0k-`_c8MIsjYNqX2@yAY zTAakSB;i@NU75!UUWC9~HcZBCC_R%lQX^%v&+9b>tEBoeM{{|4g;BkAA3|GDUwK`T zOZD@qV8(DU{qBEMI&)(A+4-X1{pH8!p4wEq>#mc#Xv4P;0@Nh2&g9n%trz^5=KQ10 zuJ(YmAy0#|7WjF6X1f=@q}`v8CN3z-c=-4V(1vfUE=budrF^~AxOr2u-sJ0z=#Nl) zsp~St|2_t|O-#;4c7H{;_qVv4ZUJ`1$ZM9fWV%Z^iKFVapf^v zj>=64=KIsAJx-)i+V-72iDo7qY`9hEue73H?rMCK@-;XLDfRbnmDPeikqVV-Z35e` zRtZBBlF{k^F+_K{w<$CE4nR7={r=$;=xakr>roU|%3HX5+x}0N(4|SKm|3DfI^0fC zAdVSoYsT+C;i~B-{`C^mu=hyw5!B!ISNWFj1@DnGqy?w#e*$YbI94i{_K7m~q?($V z){8i>aB{^C0E?7UGM)~m8azz>k(+{U_4nVNGn)FzEHmsfcsXI%YDI=P(s~q;x-*~m zExU+swR6?J4n69F{3^91k~)ghpjo|R@LyWdI#AD66B@QC(97}iwXq;Z7PzE6oPD>l zJuFcm(E4i==9tQ`I3iyupG7P`Qp3qDlmk|2A{-QFLQ9_#lnwFKxBv37r@(FD-B*T7 za%cDZH;eWcaY_d3kNtXY;AFdno6^2IPY0KVUly*blqF%nxJI;4_nPy5np5BDwhfLt^LH-v4(l;%)v@ zFhyPE^q6v6io}k!Ic0s7dVyO_nU+^>wO(4fr zk=5083TWQr53wvTH2Bn}ci#gaEz`NusHSqStA>IPe6d$23qh07Jra9UrNE8kWCbyq z3p)fuSSRPPCyYm)j35V90~yF37Tsel4N|p%VZjvD6>x71<@O74#1I4q;*V7h{SH%2 zu-yLswuZed#t4Q*gJ6OzkPz{A$Y~M=xo0t1?K6oPCx$zj(3y(1JZHL}j2?;y6CE%B zrM-86U);r%3ivzMu>A=UZA2ypUVwO&`wRCznH z!esCfUs(}UQ*%n-XN!1L)nnQ_q}_9I0W$x}n#6^=bX+0~%@D$uMLb?gv>HO??5W2O zH9H9BL|WPo1nRTgzN&8NDE`xtuE^wq_!k9t$uTEU)O2VG*nBA zfMTJdFi1Kfztk&Hbz83RM(e@^zy%Hhq;ZGIO>nBIkX4x`^LmFcA#j>hmw@Jh-Ju83 zf}p69%4$k2)Z9b7IBAOhoO_n;3Je?6HH?mY$Zg*ymEEh9$DW89 z@DuuzXl=ZNdBdRhg`$qEQ`xIa2&o|lwtzNW8^!a}yTP%1G<%W3R!W+jKd}f3)TZ~0 zA1g@V7Z?VqT4x0yKvfao`|s~G6>I0{qb9KG912%07!XZE~oqT($QLSXbD zu^1cv&UhZdTTxA;IdEqAxCO)OiQicXmx8m5{#BGS^^seRd zxIVX+nu?Vkh=(6&QrQ@oc~k#4H_mw2EymXMa=zfD^{F?JXzI!+B{|&+g)Ndi1-8Nv zwj?{@V)%g;*;Zb0nMd1GXzfF~c+*T*1}AwFl~*->DEtu}ASk~M4&R<8rZO+&H7A4%0%DyYpB=zno#Remp|-shNu-=EJZV7B!hhlFw3 zmx{L$FgotqLQ5Kv3e>IIpajqHDt$eXaOm12d(dA2U7ZLfJQmFy0oKby4~0DToT>pN zAYhQcb=5718kG!)UDC=82L05iK#E^iS~VEaEJ63>%>^VHOa^+nWWjLW9d1AEqD6R) zjz!>@z9vh_jW`9INRAm+Kha>I6Wg23gaaq(6OB-v`!UHs%Si-e(==(tSYbC=kaC;- zqB5$LuA7&0#w!R=UIvy!_}@T}~zv*kdKo!{^cfQvIV6VsH|GVURyPz?&Ec zK0%AATWHIOp^M~5GtE2?@idyWht0;=DTB!W4TR2Q8y^L3`H{i3p^LR}|ZRWDA} zQVWa}68c-kS#2+>@G6ozhg6qH2m`LD;}Kn10!#GhIm06Lqah(W)j24L*xU}4xOIZ( zG~o(qH+gpg&tcyJ)1-BA-*|TYJxfiCzPUQ~-2@DL zNz*E4j1ZRA03};vowdNk80+k-{b*LSAm#Z~)r&x}3W%PV3IF|14qaXBrZ{$j`$gnW zLg2aT&;M8_cvK-u1eXXQ9(4-KaTU$WY4RyK=>*SI+Q*w7r5B~s1_4)Bmk#X!XQAz3uVD>p?V zr#t$_KS^M~?2sIaoVoM`^W>a{8}Ui{$OruE30cXZ486}@%E>rcv`gz0R)_HB_U8)&?e66`~L9OWVh zxE2lW1_R!$I%ba%Lm_$QOus{7mUsk_xF~E$b=QHVXkKEX57&EyV9zC34qOMP;2`=w z8&#bG!(~*}I4Yez3gfbjvoeZXdlRO2!1gImO~}#M&2af`)}Ommkzv-q9&G+){bdvl zT;m+`9L=JNSpsYnm=c#HmguIdr#vi=6^@-G%y#Q!WhhY8ha2g^o(fjIG)oSu+WZ_Q zJ`uXo>?R{@1~QhCfN`_H9E>3s(M;WrH^Mjtk89eBJUnZ--K00pVjW&CoK;G&v1u}$ zPXb_~DII%Sk&aeY^th5sJBgr=31FXPro$c!5Qr=OqnZ zbeaS=B&ouXc!;jp3p|RPkLh1agR*72Fg`4SCFrY|ccKj5anArV!3e-r*b zR_6&qK$qWP8Wy$Y8DCzRei3Kws+5LK|nFI`y>Y^h(2!_fKAJfb^?j1A^ajG)rWW+c;CSWX` z?nAVpoL7aj5{i89`%6n*?f!scimSQQ4dD^<%qW>|1U@XJn5AhZA?!co%)sp%K?;Nr z;6=cCs{p%20!v0I@_D4-Wopj7qEXIBK#D9;!SqCW<7ae$co&LnIyD{>-1(?Dr;`a7 zLv}K20i`K)_8P35h5ipLqjmK7z@25#6>D9Wjn*`HI{yMf{ zcFX%c52GRa3Fa_@I|xF+EMH*4(;=IzNI>6!U$9(m$2d|6(fangr@M1b37GLRO0Yms z+A+u1Qxa+G*^@hT_=rm8y0yUZz@o1$Lty*3XxM2M^Wfghpn{XQ5C*x6fZ@2B?!OO= zLB%KpF}Gj$zE#c|rz?F~70n~B1?cuN6?F`#n&4sS;ec^WMc`SQ%#qW0nQ6TH8$dgn z+Irm%z9aeKg;vkdT^~N9n=U7f;dIPu$HDk4uM1ggIFDNKUEi>Cw5#4bX3AQsfP`mPB1~B z6t0K@CiM(xx0;K;`oR^x0+1gOd!JA13iBSRE)9mu76iQI>Er!mW1x$eYSX}Jeqe>D zV?GvKLQ`PRFM`Rj;NL6sOugqmh~fR)bPJy>f7E@b%`p2b)VrrM`5qGgTdROF9?g3N zf&#EQB5F|^%4zPmi=_S+jG!GJfvNz@xB-N_eS#~FU9n6G<)k{WO>aDs5k9FP;Q&kn zd?1c&900@Krwd@Kzql}mV^7rfye$7dFyF^dL_t7j+;_c06b`I`(}i#DPY1&jXxk(q10ERg)IiO?bxqs0KM2#ZO&gsviN4 z6R4j~xS%8HPAyIsUUY>JA_j!zOck&`IR+)FQpP{8CHCPH$kB6?Ja_rp1o!DC>MAh; ze5M;PCy=<1cTXej?1$DG^0~;<5y1be1NkH-Qj_D3t>b?3s!<`PiV-i~^TOjx-t$q! zE6LiLk%o7ui^Ksld(L^RheeTBlVke@dSaI5@~#fDSn&s0^QOpiPB(E*7XelPr>5dm zAZRiHp4IUs56btRq@XtHaI1bQ1dt7RY95I)@tP!BL2b;z$wufUM{4=Y)g^d{0=ycK zi#?v*BBq*FW2%S^M6$Xh2;yS`!pSnM;Lr<8_^=5B0(MOLdLC+=tMLE*tBEDts=ez9 z-qWfB1j9bKUZ|s8J5X29AthHqol)Ixg9dxqz}9Pn_-l}yNULg?RLOKZ@TR+nj06i+ z@qflPjN;FM;3=kySsPrh04zT-=dnx^Csex%Wpn!He}N6@eBzZiO*ch1O&3#NV8na{ za%QpOr?F7BQD}%v4>Y7jn0S*2eqqQ1!|GGw0?9abtdioZEq~;APK{O5|RnyC~@(mXs#IgA|DnjJi({d2h}|0kdTpfm>|_eg%i z71D|$7dZJZ>Jwd8&TFnw)eDJ2eWvuu@1L+-Z~%I>sfR^N@C3cKvfME=_;3eFGR9Z{ zazqtP=R^bP1z_P!lERVG&#BIv*Q^%=cQH{hUq*UPnP@zq&d4mbIn#a)2>~XofWnIY zPlBff|9Rv(O{%VSztVmIrk6hShs{$ySJm9(1x2Ps1k$UilS^eK1~`7$#Ub;HW=GnR`tp)av3U#K zj5md8w8{w^6jKxx2+mn5%k45EzZ#T;e@zq5in@=iJ8vS4^*mJA`*!{jfG-1vgXYe2 z;4T}B=M^+PrIZ>=N6D~@NG8TAL{o19#@Jl}_-2JVG68e3J&oXxG5?+cJ4j8iJbNWS z-Xp%n^5pVR3}=%jMGTA5j;eAH_q+Q^;n9ITUx44>#E0qxd9AOG@jS5Kq?Pkv;GRNV z29O&Om{6mr_Yp`&ajOcpTQA@kpi2RT@+QDX65OexNhKDTHTx@ddQfBNWiwbrL zx_?x9;=lD`#z9atxCi!{q!U!jV;=cOXSdqI*5@5F&*SwDhN!UQ=^UVWYK&%Y5(6U! z8R?C&0<`@55AYC!{9jHGp}`ah5*4ab!lpT+S=1GxXPUmIlV^9p^u)i*WcQhsP+0(XmV3|>WrfK@ZD9N-}^W+AuI|A=YHp4cE1hd z70!2I2p&Ly95s_4IFrB$IFc97iwT+*_xUQ#!0?}d6O#bjvYWyxdfPTvFDrnrf z9P}CSuF&28(P<9AyQlJ>OUZquWoN*Sl)aUAZ>{eil{5i!T0pA%nF9#RWDGReq+>aODDt#8 zp9b(+d(N?b&oR?C!8NIOtNAfq0#Aa)$tNo=s=Z~p>v(=My_jYZ$x zABTdVnM1CZ>YoY#W1D_qCaMSon;_I@yfvtwtntS7=Y5lhmydR;)DC*vUhUlfusNN$ zb2N;asyK_7tXux(*gcaFQg0rSXYutE?pss$1mB*OAKHO=ZL4PYU7FikWwN5f*g59j z_{`$rC$R_IdGUYcUEVygq?`P>NwBc~i>&uEaT6a%GS*=0nsh=N8{Osc>byQt+ zwLzXEDFQ?@5frA$zto?i-5Q$Vhgp6aC;xuc6Loc=V{=UU?|;BJ^9wHk_l^D$c{+!*> zW9?_zCz!m@*YTYpq>c(2kA*3Ox#PQ)rMmRuE+MsM!YFg$n8kv7R1n9==9ZD0eW<`+ zV4J?W{IAeto7;TuJ)VqAi3i@@gF0uFhhIh_TK)~@e^*@yYm%Ma{-ZN?3S&Yb?h z*sZ#8CDz<7&aLQ@lb|516o{m}yc9D8zbYOk!!lgwSmb+8T^j-4|8Nl)IfbDWxb zB2n;HO-MPko;4Mdc2Bu7Yg3YgJhi=Ip!mo01;(ZkaZ_s{K>7!F^{br|btRpn=5#WU z0HB2%GRwYHutuq=>xmw?Y5T2BH5}2!z6~w&B02`&yE6X=IRf&x9=|sEELr7o{?pqB z-&OSso>VzvzSkTP^$-6_)8_oWE26vjd#97@*P0L*sGK{r^k+kh+A>Kx);4q=HF~JZA`z8 zeUkF`T@Fs6=JK)tkHXS839UV-X3z|`*|yV_c|IZw?ltf`u$kYiuFvYkNi>+dUQ!c88-L4O@v^{iHxZq?ff$-KaT3{HBRozemeVp1R5A!3A!g z5MrLM>=Th@Rn8mOWAD}WoJse)nip~6weu#YW6WG=sqz`wmhRrc!9>gKWb@y8`p@0~ zd~4hfjOyX@JM~j++OhLkn9bKay^o4^kdn+6@En}lH17U0Jbt8dqKS{MW2-e7;nY@C z$*VCM*Zxr&Yx?zBP9~{Mfj>xa3-mVqqp@uyT~r>6U=&W_wWJENbx6};W^4F5M&erY zvy{ipKWbeHCO?ztz1wT-Y;E>`BhtFLz09u9TSZHY<|g7stfU=)^Q~9zVEkXtzZ4(6Mg~GtE{vE$X z1nM_$SZ#%kBFeg$Z;vKmDqkiTyuQUV-(y*@*5G33*z7W+EAhH@?vL(|kB7R!F7+J; z9S2xJZ8syI%S#>KB^ckKW8K8r zG8NvI!_7C)GdCFFTdAWsn9jN6^2ZvMJGl60(cwvREB@EPazMHLkb~l*FBW}JsmIuq zlANmoqOhl1pIFlK{vhQ(99=I=U&4lM{8cc%jh9To*xizUa4r8le85l`Jd+NmRA4lk zJxgz@_pqp1*5qTE0R3(aTYIKSH)-eC19*mmWnPDwRdausiC$P~TG@!Z>rm^_L}sGr zdhGz_Y0nbid}A!7jzJ`cn`x~k(vlBuX5!T%XkI(8K8b?i{_++b$ftU8P9P@bKms*GaTMki-AI`WSjT6}uXHjuC6&yTciIa3CHSvx9B?90r|#ZW z+#Ze-rf=HcMIT-tG`C-U(1tT+5bZ46+h0;URnJc?w8(!|{6QBA07b{S@>}J`cU1!< zfE^Yz_*5xBC#IL$Ay_*PH`Br-SDxs>W{pLYfusc}@W=xREKDFg=a(lG)6qU2S_hK7 zYtk4q5#;}uZxEY#_{VkNL{IEsdwe+QRdoQouwxi8Ipfz(4aA%P{4jms(36`p-N6@^ zp{~@6)!3*oVSO2>vKFS}rk-i7u?6Grw31lb2GT-JV=PP%#EwsWY?cZ=;Qt|Pd6w)l zFf^ay{aDc4xP<&y|I@QPz0ZH8Uj>A|*;=ysBV2p)&#j^liy42?>l^F`cPfUX6@9*l z#Zhh_xL~T&=~*6k5=)Um6hV5$oS8z85AMeQaSh%}|9?0-?{K!-Ka6|(cBs+T zEULVc_e!wi&tgEod?O zNAVKuZpmHwNg>xl*A2!gS5eUN4X@f+z+^71VO<5HhzF9V{#zu0KTs^ikPF-rCH(eth%qjQ(L^(74a#{WU} z_hLxlrcc9Zg78=*^tRpz=9KxKdDL1cYKF`TF4(aW+(B?{g=?mMN19-_LxhpAbf;)s zm0N!v&QDRpy$=uS$bB+WG*5ew$8V?DVvl}TgtXE&sGlC6>A%UbAGq2?{Coz8UHmt-D5*oUv04#BoigId;hF0t>vs-5e^5T2x*|MPlKk=& zxGn_eKJ=S#Q!N(_i`DYbh13P<4$B|>Dv?;+jwMBP(=GGM|nK#z6#|1ChYo6Xh zHI@|tn`*7zrYBx8@q1nSxSBGp(T7%}kp@ofKsE8>-W64<-Hbr1$JadKgF?8zB_{|I z>i=4xk;yj?kXUvkJpy9`xrS1A=oQX#O30Ywe?8sq!BRWTEySbu@9UmMZd(igq01we zV;(WeMSB0PzNF^*$}ziF?ajg#|%1vG2sd7F1&r|Mf7=R+pKGZqI{o(3N>m!&3Tvlq z7CXfNOu*yaWK*s~vr+`>BD@6?r~D8$Q;G=zZDGPVHi1?@hVR3T1c*>(rEK~HRx~Ce zWN!T*6W-68WiE4hrZqj@J2$3ei|cbGx-H@_mS>jx#@E86L}iGfXB*nP9|u*(S^621 zKP*VGBzUlxMWW9>XjTQNCwtyWD|J%hb+3s?bWSjLGZYOdk-5w%p8N2%daTtD`Lj=J`&i#(F+U9yF1--26sGiJb^jNb0Q9X0C_oEns>{N( zzWGD1$$x&+x4nQbKteil6qAWMSsDo4yY4NDx5?S}I^ki?3L9SMEcVr|Hic=3pZ zNEd%~i#UFr>RStUJ~Y&DoJDq*pyz;5CfPb2M~V}zEpGaqH_<`U`zJt~_giB2P66+t z9EN~qEZSiup3(i#4<1i_<6rC+-v4pjaET|f^}p+RWF$}nBY|%N=Zo61=0&iVS}$#h zJhXpF1jfo+}$}-wIHN!zZPOLXX#~Zr!t|)O!RU2ogxeE`qnx{RC=; z>d263wb7mQ_x8R1D5OQDsJ7n61qrh**Go5P zkV_z$w*ex0HFx^;pFC{XD}<7WtGvPr3j0g+Q=%hfW9#}JlkC8Ta^nV$ZCN~N`z(dz z+VK9A^`(a3mZ2&OpN%y=EEaau0gfLE&GZV50s2WgVUfO0*7RFXKnxMO)u*y2=@cKL?Ax%S><=29u2R$|J(s{}r`sUq|f5dtm;y*_2-6XZWM7 zn~5wti64I%k6qUDOJ3SH-5`AR{WMQkdB>&ji}Oc8NXcHPQhdj*^|0(IKJDp*aJlN- zTgd@uYyd1`=H{IPSN)XdN%-LA@?DdoAH8S1{M=R^v)HZwD-a;WiFfjo(dwa@oJR$~ zi`yOe81PYn7S(utFhBT}nocdB^G&k~8F()H%_IpV8a`g2*h0sX=1{4Fpck}EU4Mu5 zh5@t11Ir=%{C{rGj+n4-wHn}GxQ(5POA%1}>lZ{Q=|q|M)^x?zayzVaQ(oQV%ORL_ zvPo;2pJo^499M6OVIyo(~LOal1?NGoR=^ z+QP7ifpdJ?D2>3O6(HNT!zPs`{3a}tRrF~bX^uZmEz(-tN^ldgvr1Z}$*M^MF&S}U zYu7?(&5GtZTHv0uUyw@|-e3tA>x{*d_-$V&%hlJ9uRfdR>VpJM>=D4V$56jIUDR*t z{*%S3g+Fx6`M+C4^S`vm=2=CdhQH;@<|z2F*Gbau;pqwKE_Eg|%e@va!yWk5^C!C( z$}|b^LG<9l2`_>|nl&!ig2$MCB?Ewp|qG- zv#Q;n6tm8yEX@kriW1SYF|O@+%vz4pAG*Z#KXkQoDt9^1#&O5I_770Z9Ew7|th5a2v6;Z39^lJm7TcnAn{dIk43HEI9NS&uP8>t(reD?)I@y z9r)w1!-)DQ%^uoDW$97eF^b69nTZ)$`CWb8DJzj#V&R3YL+eu0#Q-p3+1a=&Zo8)I zn?+qF15jKp^w$a+rbNZZchW>9Kzd^0kF4oM=xrXpjd|_h#?=zZAKa({iU|r12jfB; zpRyBUR6$#9O&ljrUL$6#y!cyFGY+yr$9 zK%~nbl#CYXdyl1gLDI0HkgDWUS@+x9DXa@-;>@{*`*ytQb9wb8#=i#?Wu@v#CAXm$ z&w4^Efv!kI>3UEViQ&6qqn))w7H5SaM{=m5eG6gr6C+z}K&)1jtsZLBp7Txig(w97 z<>5!HYKbwLz{S2vzZbKBgJ?*Dtq_+es$4rEur2)N4E+`{ZWc{py~EG9ad~v#@nUm^ z;2o}+8=VW@qiaT%jG|LxuUKsK&9H3bfx;l@HJaP#kCFA|NG3xy2X>SF73HFp(f2FG zg!_abon|ctmpbkJMV-BSeoEJWk6i!O0xx>@;U&@_xYOiUecQ7~!Pduq{M%dCGR}`l zvA*Fzn$o=$ya>W{V45*l#L+f5g>m!?F(k%kDB=WuvUTLO#2>|JJBWPl^X0)|i|lSt zPo8hwx32S14IfiTjBX7(6J9*}p#AEq{Res2yjHpXkeBhxk3K6F!G4Zh7M*zdRLF0Y z>hhwrxXAwU9_zF2Q-SV2f*z`;0&~F!Z-&;(py(O?ZlNy=3Md8A6Y_$R6iI$Y_H3?} znAfF;n+PrtAV$ad5*OPp3heHde?Tl;c#SyGXGt<2K*G<8ut|vP(D4n{^+=Vat6}n* zdqkzM65PkO3|_JeG<-vI4*Z((vb}xx1Bt|_&N-Vjs%dF!iPD#EaqkN%lAHLwU#XKE zQYdk6M#NUpPt!(LvQo6nr>zMrD9^;xwtN=R-MUbwG$AU*g%gftH?R)>=kLW(Bo{Cc zirn)DQn1uBmnNdNm%kRnp~JaG;h^9|SJA9^hJ(i~m4-1dYLC?%Cj=zgEJYQAT$z?xr+4S( zyc2KlL06q+n=3y78&^oOKKViM>L8{I`I6E%5Nt`^B2$s^yl%YIK7 zV3C(08m~VeZf#*Q2vf^wwSk3l{Jj~oCd~1ZW5nd=8-uSbCfw_%MvePPYuZDNMt!5C z^8P`xy!OkbgCWW9?Zv-gZSc_AwiMS*yp@DOtaGN@KB$d`4*kYFG{l@L{sg)ZwzPLVLF`?odX zVUyetppdsU1M?DsQ<4KSYjAS7Uj=(RN+tP;U=K+|@QK)ATe_3S@_MGzyS?2HKF*~g zLbqaN*NW;~xu>d&F4HH8{V=1%J$=R03ht@)v3c@1OtBol+v0xK8`7wsv!5qz5!Z37 zM~fP>>VN5D5ee_n*ok9&W{T*Mo7y~^8hp1~`4BBT;ONFw^m1t~GY|W!UPkkU@dmiV zr$v!ri^-R)V0gzM4%S^1|NSv34%@3Jcz4^`JwzG7gyhdyr3B_|@86`GA#WE8v`D?=}CI zhC!&YR&g_4LJhS z`h+YSEZcfV3^Y{_jq!Z@rehckvcW$~6%f4k?S&+;s{)JySm)E8!DD z1E=h~r15=rSskdqwJR%iO6v%T~7^M?;}-fS$ec6 zC0wX9?n5FP=t}p$wb0azdAt=av9Ivfy?SO`U|^v$abo$YAxR}^UEB(=i7oQ#u87@+G1!e0M@{L@g&pL&?K3)D51? z*AmzGf1!!7Spsr2^9*dRy=2s(WzhuCsAjPQlmS4XHAoegnBOklzoqf!{{maA53xIkn4~<2;cAN_ zet)EB1ZS&??7vo|wYeF|U+{6MywN~P1}m$qaBEt(%aV{PRJi;3yK%B8%X7k-T4bR; zu6};G<_tH{BP-s~xvxQbIqxJf>AycXP{TI-kK^SXROKH!qy9o%PtS_Er$yS+Gp^;* zcI9Q7UK+>dNcHr>kKEOglONgotH~)9*WJm&G2Zn8yXF?5`{^FbugQZj9Da z2*Y~7@=bavn|i~fB`eUZGO7o-wgCdzsZjIYmWf=1t$V0ORJ<$KvYAQNoBs>2XH2L~ z1Vx#2!izS(q#-0mI=SqP@@PxG7SGTodRY<96*-En$s9WnM|*ZpE(VZM!a=z)*c{#O zf`{;4Gtsr#obGP-AZXTF{_vpmkTG>;)VnP67f$-BmvA$vM+Q+qJU_F+aAUYj+rm)V z9Hfo$KJpP9;c3*_qVNcR?2Uh?GWj$3RsJPzAsqDUWU#q;W1i~g={uaHhfpxQZ|I{| z+q3R$%NG^c+N~>No`+FyZll03jZA*Tb~Gn@!{cwX^-tkB1O+xqacu3N;pozs-vke8+Hgbk!Y zDR;nRz@T49_k_5htd765;|eLy83(?${dljl`O{JWYbZS47m@QJJ#)0=&{ng?59oOr ze~IVU>2rkM(iutt%FNK$h$S(Tu`D%;#lFP^TReG*~Y&%)eI{(Vp5YEc`IWC*XG z$wzPIPgr+#{u)HV3m%rpRw|k-lgwg%ASJQ>%6cwD>&me^f(VQH5^RtO=YGBH^7ry@ zb<6b!{+j>TL8x@eu<`u4C@n?#r`Ym>vm=Z zP}9;Q@D5tMr?MF7AqTD1ZV-=1( zRM)E9&WN*6tNPb&uW0|t@xYCBf70^}jQ$q!m8lXA@?nYNBv0^(jqL;O_dTDg3iK;< zmKDxja1O6d+D>Xnn8lzVPzUDow)IpA4( zf%LFWwevcPtccC7h@H4oFfVIWyatJpzqKE*R45JRA})~f`j*YjNH1VrGH{a9Jy&KY zw3o?u^H-H9KFO9;CR_ISMbg(#1SQ`-2r`*ab711q=)!6~+Qu*gDLC)oVLP32=k3XB zkkD(n-FO+?*v(uTXT$dHoL))iWX}fVEeFC`LZ<7MighK6g`jQO{vz+#A3B{86mP)w ztCNatqLTXHu4eRp)gV4BRosxMa{@XUkQS-QDr37<*cil4)Q-nNQ=8(QJgzFV zbs1G^a>*~*^)}~nN@e-ZdK{b~`B(F#D>^aV;;yIDxElc#I>BvDv%+1qaD>VV(6}ad z9=xyq_t|+c-h=?(@`G*82hwYeafL4osE6OCx@YBL7FT<84~zl(!LwSO?>H%rf8n^+ zX#OjgJ+$FjH%#Y4t2V4P4CNBnuY7)4$Cn}b-9O9B3u}wFz6ZS<-q*UEVx0_95uV5U zbf{1>Dier+Vc)hq=G(rydq*1^Bg=!7{{7=tb?+NW+q-QP8muy8fgI{uttDUbQ1ecD zefH1(6#R{kxdiwv>?Ru{OV5UY=G%GA!y0NFA^!d~lvV_vo;%h8Mxn6b(Of zEp*d4G#to?rCellu@oBknESV9=-Yc`Wrxn3gs$~jn<1+ZWmPlo`DU&OJ%};lk3yfY zy37=MvXkFUkv8a;uASj(3D&jE1BS7~mE&-WftvNYG3eC4PBLi2u7VufF_eLEvNsH;N zQCn98K8myd^nb#L#1eQ8^(Qd~9w1-QyI1v`awrX8gSCOOW7*-ubTiECiU%7jC#^W} z^7ZqLWjP?ve=G;q$iz(i*d;J$&;z5Wt<;+0uXSx=g)5m3E3}6-@a%qr$J8&5W=$>I z`zF|}cS1fCW$z;jcW?Ej9XZV6z_O0NM0}#=zbysI|LPoR=W#H!i^o^eHI43+NfkD0r0fJSZYsE+f8q6nAC38Uh_j^mSwO zPl(kMSpIzOMHcNrF2Se8Cq|4?gq4JDZoD*KXFW?;LLLGh@Eo7uf66K*rMa$OodXP% zi&~O>9AMMZgjzRdBz6hdGZq~>SxDh9UAVO0MLG-q@p$8WD3i~du!vo1q0WF$)$?MrXu>NuO`v6_hl2N+#Itj2mn}c* z&T!>^VzD1ebUi3q48x9tM@o;J(!H6HQ{g{>T4drU*&PrMM4$Tt7 zB~HP!RmohxZ=FEImIpLmrH|{1m0pQ{-{4h+{ATzdc*&aA zcP&hSRA@DU<8SUMuSZhZ+Zc$`JH5unWAE~>5U7tA#C`489_AsJP4lWaR;W;E_gB(g zrM*349g6y*eOBiVxT95ZU5EtU590PAMBXrEq%j^YjKo^mo4l^Giz|rPV8E?IV(#d8 zx5DOgSZzM%eGoQpMxK|t+g%quoT3zT&Lr0fx*4iMk62MM3jIU(ISr~FL>4Z5*n^k0 zPqF4#qWvjTwyEZ(a^1T@ZA85d15$iuXw751m0>pQ?Nw z@kBh{#dt4!9cot*%V=7A9ZML6meo9k;%p z>s1eGfWTYP;TKP(b-#Ye_kzZNu8D1#a4L&Yd#+*U=eu9UY92Yc{%0e6D!Gkdz4a?} zTF^C>S|Lt&uw?b%gg(>+6f=67T8d+p*5;MBs=4v;g(pAHJiPQ-UL(7E8)YbElxHaJ z(uF#-65`O_y+`q!LIO6f=`0pZ`hI&nVJ}YP%X*+i#;42oXVg3KAhwM8?rGDO{bS25 zEu;1EkFy8`5m6Npu6d8>8!(}ULM!oH`c0O^06~?8>akyb+v{>ExdEcTcLzrC*G@u% zob25z62nk(m6tpELl>(#l{+g6fG`u;Br$p2c8)Fp+~nO@n{+m~ZbBlqV*YttgzCux zw#)PGf~}YzEL^3Ct2uZdgnlZ{ZRF~p;Uwxc3>Ia3yVN#SR+g2+I_A*H%0UlYVz-Q{ zoyvVZkC?%!exi|v+h~Pm@JnjTPam-!2raxkRVPe|!% zghzW`S@HMd46dy;$C~~smk>c>fsqN=9tUM@ zP|(8#)aEV)MEO$iKdwS9DLJiLna4F$@?FIWA?wno%#_tjsA zm)o|&bs#a##szb2fow_oCTh;>m+X&4gtS!?J%wiTipjNb+KGtTt9P6Mkk&#nSiA@@ zq*kD`S>31p{iu=lge>IUI~x*hwf3uG84o`h*06a-41GPzeJ4aJ@G+KUv+zYmZY1AD zt!w2;g=Y!RGo4sJYO$8(ldGGr@5dE+4ixErFQp={N(BOb?n5egQHlH_361#9PN+PU zZ|G06M0K*pnTv3$5)Rgl)I;Z!d(9FQmK6@ngl4+eOG=wM?Ql=^+n&^r?=Y4sSV(dH zUAWjE#InVmM{%y8b+HOfw*vDErFQlI(7k)NJF-hEa<@>{seRd(#tUp4e-;pQGNx+U zCk-SNB!);}{9iA3>NGVwgkl~Qy}QV(u32VW(r}sul&{Sf%vVS!%6hm~$rtu6@8yNxyxiQ-pnKnenNU z=c|3!md2+cF`&&HAy-?^Q=qswQgX`$0Xf$1!og&1q_+GZ+O0HAQFcn~+`mq#2VFLi z;8@GzCgF^}AzO>dR4CzgqQrAUQZp=gQQY;@15x?97>6q@7BU|_FK%cMMk!1Ejms%8 zPMn`1_k3C0qy4QF1Xhyz7$Is88v3j zJ@)reDh|@TbVt#$I8k2!y%zykZk=H;8P9!EtoCjdSA3YH8D~L&nrmCMh_)+HajeO^ z`+VamOx{yge=`IBmbkw+)t76ZViV#^xC;gjc8kljXpRsCjE^04(E+lt@aOrefLBo0 z%jdDRIzeU|x94wY8yVsYfu(|e7cHsNp7UxFkVmdu(s>TOK6XY?8sEhzK~0YaUq4|@6U^SLx5Z*lxc2?t zSEQG-{i0!VUzKZk=smI0PQEScXH05+%0DQRUe|z4Ocq;;=Cc1D(85>kVR{^!vk;h& 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

Zz|3c>k(t>k>iY&YWq(Z{e^+Ls3wwG~fXOMVV7 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 literal 0 HcmV?d00001 diff --git a/docsy/content/en/search.md b/docsy/content/en/search.md new file mode 100644 index 0000000000..394feea5fd --- /dev/null +++ b/docsy/content/en/search.md @@ -0,0 +1,4 @@ +--- +title: Search Results +layout: search +--- diff --git a/docsy/content/fileList.txt b/docsy/content/fileList.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docsy/docker-compose.yaml b/docsy/docker-compose.yaml new file mode 100644 index 0000000000..9069dc0679 --- /dev/null +++ b/docsy/docker-compose.yaml @@ -0,0 +1,13 @@ +version: "3.8" + +services: + + site: + image: docsy/docsy-example + build: + context: . + command: server + ports: + - "1313:1313" + volumes: + - .:/src diff --git a/docsy/docsy.work b/docsy/docsy.work new file mode 100644 index 0000000000..074dc2a129 --- /dev/null +++ b/docsy/docsy.work @@ -0,0 +1,5 @@ +go 1.19 + +use . +use ../docsy/ // Local docsy clone resides in sibling folder to this project +// use ./themes/docsy/ // Local docsy clone resides in themes folder diff --git a/docsy/docsy.work.sum b/docsy/docsy.work.sum new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docsy/go.mod b/docsy/go.mod new file mode 100644 index 0000000000..37ec74496c --- /dev/null +++ b/docsy/go.mod @@ -0,0 +1,5 @@ +module github.com/google/docsy-example + +go 1.12 + +require github.com/google/docsy v0.9.1 // indirect diff --git a/docsy/go.sum b/docsy/go.sum new file mode 100644 index 0000000000..c11d56b022 --- /dev/null +++ b/docsy/go.sum @@ -0,0 +1,5 @@ +github.com/FortAwesome/Font-Awesome v0.0.0-20240108205627-a1232e345536/go.mod h1:IUgezN/MFpCDIlFezw3L8j83oeiIuYoj28Miwr/KUYo= +github.com/google/docsy v0.9.1 h1:+jqges1YCd+yHeuZ1BUvD8V8mEGVtPxULg5j/vaJ984= +github.com/google/docsy v0.9.1/go.mod h1:saOqKEUOn07Bc0orM/JdIF3VkOanHta9LU5Y53bwN2U= +github.com/twbs/bootstrap v5.2.3+incompatible h1:lOmsJx587qfF7/gE7Vv4FxEofegyJlEACeVV+Mt7cgc= +github.com/twbs/bootstrap v5.2.3+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0= diff --git a/docsy/hugo.toml b/docsy/hugo.toml new file mode 100644 index 0000000000..520a1cb358 --- /dev/null +++ b/docsy/hugo.toml @@ -0,0 +1,199 @@ +baseURL = "/" +title = "Java Operator SDK" + +# Language settings +contentDir = "content/en" +defaultContentLanguage = "en" +defaultContentLanguageInSubdir = false +# Useful when translating. +enableMissingTranslationPlaceholders = true + +enableRobotsTXT = true + +# Will give values to .Lastmod etc. +enableGitInfo = true + +# Comment out to enable taxonomies in Docsy +# disableKinds = ["taxonomy", "taxonomyTerm"] + +# You can add your own taxonomies +[taxonomies] +tag = "tags" +category = "categories" + +[params.taxonomy] +# set taxonomyCloud = [] to hide taxonomy clouds +taxonomyCloud = ["tags", "categories"] + +# If used, must have same length as taxonomyCloud +taxonomyCloudTitle = ["Tag Cloud", "Categories"] + +# set taxonomyPageHeader = [] to hide taxonomies on the page headers +taxonomyPageHeader = ["tags", "categories"] + + +# Highlighting config +pygmentsCodeFences = true +pygmentsUseClasses = false +# Use the new Chroma Go highlighter in Hugo. +pygmentsUseClassic = false +#pygmentsOptions = "linenos=table" +# See https://help.farbox.com/pygments.html +pygmentsStyle = "tango" + +# Configure how URLs look like per section. +[permalinks] +blog = "/:section/:year/:month/:day/:slug/" + +# Image processing configuration. +[imaging] +resampleFilter = "CatmullRom" +quality = 75 +anchor = "smart" + +# Language configuration + +[languages] +[languages.en] +languageName ="English" +# Weight used for sorting. +weight = 1 +[languages.en.params] +title = "Java Operator SDK Docs" +description = "Documentation for Java Operator SDK" + +[markup] + [markup.goldmark] + [markup.goldmark.parser.attribute] + block = true + [markup.goldmark.renderer] + unsafe = true + [markup.highlight] + # See a complete list of available styles at https://xyproto.github.io/splash/docs/all.html + style = "tango" + # Uncomment if you want your chosen highlight style used for code blocks without a specified language + # guessSyntax = "true" + +# Everything below this are Site Params + +# Comment out if you don't want the "print entire section" link enabled. +[outputs] +section = ["HTML", "print", "RSS"] + +[params] +#privacy_policy = "https://policies.google.com/privacy" + +# First one is picked as the Twitter card image if not set on page. +# images = ["images/project-illustration.png"] + +# Menu title if your navbar has a versions selector to access old versions of your site. +# This menu appears only if you have at least one [params.versions] set. +version_menu = "Releases" + +# Flag used in the "version-banner" partial to decide whether to display a +# banner on every page indicating that this is an archived version of the docs. +# Set this flag to "true" if you want to display the banner. +archived_version = false + +# The version number for the version of the docs represented in this doc set. +# Used in the "version-banner" partial to display a version number for the +# current doc set. +version = "0.0" + +# A link to latest version of the docs. Used in the "version-banner" partial to +# point people to the main doc site. +url_latest_version = "https://javaoperatorsdk.io/" + +# Repository configuration (URLs for in-page links to opening issues and suggesting changes) +github_repo = "https://github.com/operator-framework/java-operator-sdk/" +# An optional link to a related project repo. For example, the sibling repository where your product code lives. +# github_project_repo = "https://github.com/operator-framework/java-operator-sdk" + +# Specify a value here if your content directory is not in your repo's root directory +github_subdir = "docsy" + +# Uncomment this if your GitHub repo does not have "main" as the default branch, +# or specify a new value if you want to reference another branch in your GitHub links +github_branch= "main" + +# Google Custom Search Engine ID. Remove or comment out to disable search. +gcs_engine_id = "3062936b676d2428a" + +# Enable Lunr.js offline search +offlineSearch = false + +# Enable syntax highlighting and copy buttons on code blocks with Prism +prism_syntax_highlighting = false + +[params.copyright] + authors = "Java Operator SDK Developers" + from_year = 2019 + +# User interface configuration +[params.ui] +# Set to true to disable breadcrumb navigation. +breadcrumb_disable = false +# Set to false if you don't want to display a logo (/assets/icons/logo.svg) in the top navbar +navbar_logo = true +# Set to true if you don't want the top navbar to be translucent when over a `block/cover`, like on the homepage. +navbar_translucent_over_cover_disable = true +# Enable to show the side bar menu in its compact state. +sidebar_menu_compact = false +# Set to true to hide the sidebar search box (the top nav search box will still be displayed if search is enabled) +sidebar_search_disable = false + +# Adds a H2 section titled "Feedback" to the bottom of each doc. The responses are sent to Google Analytics as events. +# This feature depends on [services.googleAnalytics] and will be disabled if "services.googleAnalytics.id" is not set. +# If you want this feature, but occasionally need to remove the "Feedback" section from a single page, +# add "hide_feedback: true" to the page's front matter. +[params.ui.feedback] +enable = true +# The responses that the user sees after clicking "yes" (the page was helpful) or "no" (the page was not helpful). +yes = 'Glad to hear it! Please tell us how we can improve.' +no = 'Sorry to hear that. Please tell us how we can improve.' + +# Adds a reading time to the top of each doc. +# If you want this feature, but occasionally need to remove the Reading time from a single page, +# add "hide_readingtime: true" to the page's front matter +[params.ui.readingtime] +enable = false + +[params.links] +[[params.links.user]] + name ="Twitter" + url = "https://twitter.com/javaoperatorsdk" + icon = "fab fa-twitter" + desc = "Follow us on Twitter to get the latest news!" +[[params.links.user]] +name = "Slack" +url = "https://kubernetes.slack.com/archives/CAW0GV7A5" +icon = "fab fa-slack" +desc = "Chat with other project developers" +[[params.links.user]] +name = "Discord" +url = "https://discord.gg/DacEhAy" +icon = "fab fa-discord" +desc = "Chat with others on Discord" +#[[params.links.user]] +# name = "Stack Overflow" +# url = "https://example.org/stack" +# icon = "fab fa-stack-overflow" +# desc = "Practical questions and curated answers" +# Developer relevant links. These will show up on right side of footer and in the community page if you have one. +[[params.links.developer]] + name = "GitHub" + url = "https://github.com/operator-framework/java-operator-sdk" + icon = "fab fa-github" + desc = "Development takes place here!" + +# hugo module configuration + +[module] + # Uncomment the next line to build and serve using local docsy clone declared in the named Hugo workspace: + # workspace = "docsy.work" + [module.hugoVersion] + extended = true + min = "0.110.0" + [[module.imports]] + path = "github.com/google/docsy" + disable = false diff --git a/docsy/layouts/404.html b/docsy/layouts/404.html new file mode 100644 index 0000000000..1a9bd70440 --- /dev/null +++ b/docsy/layouts/404.html @@ -0,0 +1,7 @@ +{{ define "main" -}} +

+

Not found

+

Oops! This page doesn't exist. Try going back to the home page.

+

You can learn how to make a 404 page like this in Custom 404 Pages.

+
+{{- end }} diff --git a/docsy/layouts/_default/_markup/render-heading.html b/docsy/layouts/_default/_markup/render-heading.html new file mode 100644 index 0000000000..7f8e97424d --- /dev/null +++ b/docsy/layouts/_default/_markup/render-heading.html @@ -0,0 +1 @@ +{{ template "_default/_markup/td-render-heading.html" . }} diff --git a/docsy/netlify.toml b/docsy/netlify.toml new file mode 100644 index 0000000000..e087db8274 --- /dev/null +++ b/docsy/netlify.toml @@ -0,0 +1,12 @@ +# Hugo build configuration for Netlify +# (https://gohugo.io/hosting-and-deployment/hosting-on-netlify/#configure-hugo-version-in-netlify) + +[build] +command = "npm run build:preview" +publish = "public" + +[build.environment] +GO_VERSION = "1.21.4" + +[context.production] +command = "npm run build:production" diff --git a/docsy/package.json b/docsy/package.json new file mode 100644 index 0000000000..054b5ced25 --- /dev/null +++ b/docsy/package.json @@ -0,0 +1,42 @@ +{ + "name": "docsy-example-site", + "version": "0.9.1", + "version.next": "0.9.2-dev.0-unreleased", + "description": "Example site that uses Docsy theme for technical documentation.", + "repository": "github:google/docsy-example", + "homepage": "https://javaoperatorsdk.io/", + "author": "Java Operator SDK Devs", + "license": "Apache-2.0", + "bugs": "https://github.com/google/docsy-example/issues", + "spelling": "cSpell:ignore HTMLTEST precheck postbuild -", + "scripts": { + "_build": "npm run _hugo-dev --", + "_check:links": "echo IMPLEMENTATION PENDING for check-links; echo", + "_hugo": "hugo --cleanDestinationDir", + "_hugo-dev": "npm run _hugo -- -e dev -DFE", + "_local": "npx cross-env HUGO_MODULE_WORKSPACE=docsy.work", + "_serve": "npm run _hugo-dev -- --minify serve", + "build:preview": "npm run _hugo-dev -- --minify --baseURL \"${DEPLOY_PRIME_URL:-/}\"", + "build:production": "npm run _hugo -- --minify", + "build": "npm run _build -- ", + "check:links:all": "HTMLTEST_ARGS= npm run _check:links", + "check:links": "npm run _check:links", + "clean": "rm -Rf public/* resources", + "local": "npm run _local -- npm run", + "make:public": "git init -b main public", + "precheck:links:all": "npm run build", + "precheck:links": "npm run build", + "postbuild:preview": "npm run _check:links", + "postbuild:production": "npm run _check:links", + "serve": "npm run _serve", + "test": "npm run check:links", + "update:pkg:dep": "npm install --save-dev autoprefixer@latest postcss-cli@latest", + "update:pkg:hugo": "npm install --save-dev --save-exact hugo-extended@latest" + }, + "devDependencies": { + "autoprefixer": "^10.4.14", + "cross-env": "^7.0.3", + "hugo-extended": "0.123.8", + "postcss-cli": "^11.0.0" + } +} diff --git a/docsy/static/favicons/favicon.ico b/docsy/static/favicons/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..de4cda66116d07d8385d960f6411eca53c59570d GIT binary patch literal 1150 zcmbVMT}xD95PpO1x{)rr?y_G~5LDZTsriw85SiTwQKngzmXvOg67&fn+EOZEP;FTo zMP*b_5#0p4=bT;FJ?^f%n$pueb9|RY0xOm|@9wM?P6PN0$Yv;w)I2;yE`1c ztCbkW5<{%w1w&u$*#LK-$HS$e3~r8RaqD3g;fRl>-lXPa4aEzlgqK|O?`(H)V|)g0 zzRqFzX%77(KCayNG59!(*Pn}sJj-cs)l#dW%PZmcc6*we^`h?!nk&@mVEak2HU}X& zD^EEXd6CCxERT?IBc@bedSUOePetuv^Ra|tiK8(OHQ3Y=$Ha#M4ht9dTf#5t*VLCp z=k00bJrvC$GLgf*=XvEq9lGyKqdA;XY<(GjYF;PxC%?@hI$6Mg@b0^tLGN$|J%hn{ zb!-L?Ud`gmk9i!rxU9b5+0WR^JYpYz zG3HP6r;i*shZ;GVKjklCe&LtaC7ySTQGEISE$PoYYvl7i{!?}2E>K^4w-TPQ + + +
Operator
Operator
Controller
Controller
EventSourceManager
EventSourceManager
EventProcessor
EventProcessor
ReconcilerDispatcher
ReconcilerDispatcher
EventSource
EventSource
Propagate Event
Propagate Event
0..*
0..*
1..*
1..*
ControllerResourceEventSource
ControllerResourceEventSource
Propagate Event
Propagate Event
Reconciler
Reconciler
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docsy/static/images/cncf_logo.png b/docsy/static/images/cncf_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..daa735c17bab6fa8eb1106673989aea27de5a269 GIT binary patch literal 4783 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 \ No newline at end of file diff --git a/docsy/static/images/full-logo-white.svg b/docsy/static/images/full-logo-white.svg new file mode 100644 index 0000000000..5ed740df53 --- /dev/null +++ b/docsy/static/images/full-logo-white.svg @@ -0,0 +1,20 @@ + + + + + + + + + + JAVA OPERATOR SDK + + + + + \ No newline at end of file diff --git a/docsy/static/images/original_full_logo.png b/docsy/static/images/original_full_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..220129ae892c7d6b7de2303a07438a4e96494bc0 GIT binary patch literal 35366 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�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

TBTA@g$M=YsOk+Di5yA7)e*7_?}=;x4EChv zWC80*!Ie4WxwqM!*Z-zRTW28SUwZZ62?vLABE{XgM(cqL{Lh1|QNzc|DDb^@Vk3wn zgPqUG9tQAOXNvzm>WQbZsui)Lo_YPbD2?+(4V&75?vVBN7Q&CGE?^P&)MLRI!dcL{ ze{Yqy zKRc=Hx@RR4NLU_&AM@P{`afkJO}@i{&|dC+(R3$sofaF1n##3wrT;F6os}@WYrX4+ z9NqIYG0n7N@(g~wH}%Ks82Zk8Bv{~e9UWkvW&@+6eak<`-{J&(@ifO)WLQNkQi@hp zX-bhuBp7wKz+6|8MenbwfnD=S>_6vxw2Ikh5zz*|@k%tDwpl3R!aHkvYpP8~S)J#a``- zjbnv@+GtPuD$c>UyVdndO-LrbqKYPn zOC(4SQ!`RMJEo7(MvQjvs}UKN${(>k_tK&h_l1$_?Xi%Pj7;;|OzC}+w$W$LwuD3d zcjYL@W8Pw6$@5$sSa%QZ*M}XENg(~#n?PDdbjT&;?s>~ddM)bprFGaN@*neoRE&+Q z>0uCx(UV)Vxah3+@lOv{#;GQJcD=f9L2Z3mmm5>N?(pMJtOsWTc|Rlch5-vNh%4i!#mexLevP7Y zYU-l~g$kOxK~IMJzV~Vf1;u4(SugIPCLVYg_>};JwLh>C_D!6$v-;w5611(L&Mvd` zJ;D@N5C#%hGWv2JKkoA@q06H@9g(01R+8ihW6yK@wlSpft#e_r($ zz~_wh9R92YR)Q98INQkZ59AmtP;h0G*Z7m9Z$2lMcfmUfs@DidJJ;zO+AnVks1%;u z4GR}n=0{0dX*a|W8p6NqDf;z9{An`tI{t>qU@sns-bbs)_a7E?$ywy3JIRSmQT^{C zYH$%S2XASe?b^gM?+#sRaI;??d`Nd&=B?1dF32IeQth%k*|ukX^0TagFoa4Hn&OIr zw+z_Q!4DpL9SA|1Dh3$q2)CDKMs zV&k9Rni_N>O~XU}>Z5@71$6GS|25L@e>wjO`!ll7<=L)_c})2${Hw2rF>Ey@mPn~^ z9|%r3&{4!4KNHzF_--}l)QJN3KHod`wA z_<%!{M-?e2`WO|jKQY^bU0$)&pSFJ~Zp$B?D9vEDAW}m1`RYmceV0Q)HMgJiL%Rd! z_3XCMuEFnl;-Du)@9IBptmCPsOVGhxf-|_gyKB(F-Q5F(po2rO1P#Fh0fG%o(BN)?!AWok7Gy5( zIp@~-eth@e-Br8x(`!Gy_Nuk2tDo-Pt*@r6oFNGSm?+8X8taOhVgmpGzL!pi0_X++ z)D#qSagkpR0m!)S_8xx7gaCktr@ybhiafoknK?biIsgek0YCw~28h|(`+3Xh>T3Rn z{eN#ai!bb#Hpl%RU;lT`|ECoj?BHkrGW+<_t?a#h{Q&?Z%NL9jQ0zhf8UFum z{tm$}@dE(L@&Lepa{Axi|2J3vYeOM>2|?hc78U<%^ZEn;h+eYKbu)U|+uzy<5JMFVs8w9)~{~efxd!5Y93V=u8 zPSt%`w_r&0~%e?Kc~+-|R&Y*CO`?5)SqP6bLeta$OLj5WCS+Jcs{L z2Y{B|f1U=3ENWcDx@ z!-RCu)rERmNd{>Jy0#IfiY>`r4xVx0iEd8hZ22pbwYe}KtoLF8cz>D4Zt;==M}ec~ ziN65BzbAb~Ga-YXkX?a9JhX0qr>76*-W5tr)_42tP>rRW;ans0Er=n@=D#6l`mBa8 zRKR5ld*;o@eO+jf5!R4)Wgwj+*OPSH*Nhp_Tfy`?2@Y6N%5is0csQQu?^q%@PXfMTa#4^V{QE~^E7>DOFg-7Z z?xVD2`&WL1elp* z4(s7^#R*vf5ER)RTn}|B=k#qP?1+7a($`5-)Y2$qTvB<)*ePF!BLkVYLFxbWJ`{&+ z#(0GCkHlcIdB&{ffUNQsf zXDsjFQkW4h8imfDkFl%vcUE2@;%Aam$8^uSvs#!;pW&lXQC&l!cr&J@7%8SVI2vqk z92Kn+c)t3tI;aGYygHBsbj&oEMjzBT^e=b44*!TX#Oc>)uo=1ov9^xfzWIqPyFWJR zzqs^?l4@KIZPO<8b!s*Apx@Su(g58GcZuPLk>sCW-!UQ&8g)_=N#4Q!8JU~e!1EwE zY5i_ zuPV;24BG%Nw#$7d2Q-eu4DJ&>ZO`MM-OaN49s{?`phz&$L6-k1O9%Ej%qOmW%tEp zGZkK_f=m5E+$qB3NBMdUMIeR<8n8N)% zN%SnyR%KT8=7;{rM}K5X7mzPb$5g6f(bc5btA1!Ze^aj|pRdRrK6rJYhTCRWM~00k z&xo4RGPEr^_nTqA}nu*=Xr+CI{0>n zLaI%5R@6JnxwQiK?g}|QU zEuBy?n|FFf3*#v`|5lvaj9CW)y^9Z6!8~oZvVpZAR?wss8Bf6#fX}o3S8wQbI&J9P zRw7;GVf9jE#8Q9?N_5c4RyP28r)F{dl$zBS^x$CqG$d!y*h2z%7sR68O+L@tIVr62 zCU~xgK;~)&gD&!}U*$~la>;^M(tRff2^ylt;Cxf7XaF%dL#m6~DwVPAi6>lG_U0D+ z0aQm}>WiWG87Jx* zR{GenQu^qe>i7fYZu@>}UNxb{(S0LD%lJWE0p7Uv6OEqq_;ah^*iYgRjJlgPwg)xP zkD9n4plZuOqY5uxa2_u&^iCo276PeA5cPgnR~ohi(Lic=RNV*Qt{ol)Md&(2;PThj z;?+^w^JU&#)JtH(Klm)iPf%WUMG#ZyiakC@X7aNWCw8_DnVxXsjOFDOyv+)IjJ$!mgBzYQ26}tI)r8GXoG@=pl_~ zXoGSlSuCYNVZw_Xki_<$9S<~ivn*JYumA0OxY@$MTSI-#I9fLJx2-^{xv!BK7(jD3 z%K*HU=AOa9Vnz|}86GJc`cV~A69M1^Qk9&#S4AVZ;uY`-xyhnP02qTB4I zi9~2-%1tbrCo4;Tm4JU(E*bhJI8;wL8Vy5~wmQ3izG=BPZ_}&iK^zvJAw^3+vpp)57-^xDCcUbe{FGPDdZX6dNp;>o zY`5t~YutyI=`><413NAuwjx7{b3-CKF-%SwkotC6=_bY&YB1EqDI=zypn~*0DHh*f zcvo!&ntfWi&!60LeJ*@aA6lW7H(_pja5U9>@BF`5Lh(K~-@WldQXaS|Qaa~HZUYmt z$dZPA2{QWgRqSU$^uVaapUgs(R~|x(X)&B61W}w61uFGbwqEt9Kqp>;*9@Fm8g1SJ zcgm8&p~bc19`t=!9l7sdlXM{VwT{$QQEF{^p%xmZ5Rhd|aLR)~IVi79$3+boR)=~{ ze@E1^-Sv6j10a$wdOY*fX55FF7uga=(Occd#-bfUnrJhxk>Wn3dYW3tM?EAx0WBJe z*Q9x{tG0(%j;N3P(3xf5w59~*!?1=%!arOJ%Vs9Q?LaLGEL%w%r1J3?F-VvX1~`uirPU_ zF|a$A`9S`gIuvU_Y-N=}!9j^}M)Q<-!KH6Ure1%iA?tT^Pe5X2HK;`@=Zu#ij~=G2 z?tmd+)wEuL<))e6H1rmWn6-}Ic7XC_Xnr|z(*y>mVxeeTZh_5zW^ApcoD4uq<+15u z0l4D3LZ&?cRqzSai@2fXkPoyM4_DUlA1o|0nja_Aj4ij5hC6jqbC*L_Zm&K^JS{?i!Qvdn4j}X2?R|MEn$#h}AOPX|&yiNh zZe8Cm|BayD>nE9B9Z-cW{Q5jqjO#&KsMy5@CRbm!+D!rOc;AdP2UKhMc3#g`+KVVa zbpIk&8!{Z)(AvUqwpgQ-Xu?x)ruZz?hJUTlp-mKWw!h|;7q}*+)43Ngo1K(;WgL$J zZ^lSfTj+pSccl(NnS!2IxC&YMZ?t3GwnNdYzRCLb8{9@9*2u%p!VtG`fh$#4E~(g@ zgK6|8pxR|mpJl`@dU=ni=)sUj#86L!pcaf$M+H66!>y+$0`De4adByF$=z#nfZLnN z{&|_)TxGHLBg*yV;7kU-{H#9bQ8|CWuGba-^PJE=Q}sER=;bCfi3Ft#%3wf4@$wkA zt%vTa|Jh7`?h1Ogzx%tBu zBDJ(^9-Y?$7Ofk9^QQi=_pp5mq5tyKhHqcA_OlHxt`S?%%;=~_jSsZNrE8!!hT4R3>ew=3UH^M>tHsB1ikxe&1(PKY|miGh8YnuiVmPJ z2m-z97)R-f9LQI^|Er5x*q6pX+69C74+eeqfKKP(n75hKXJt?ZD^@q}x_iJI;i%E@ zsT57%{VDmD6lDt~noyJO?%U|yhMcMx<$z)>KV3fz&V{(So$ zj{{H?6zdp~aP6pX03=VVC*C|KT+es@r#}*Y)#AfjPh3{6wXZW^-@Vb9DX@ z080F!;7u|?lwpa1KM}f~;k-&j$h;mmc5~cbH0>HOBd*NNzDbQ1Y~qXDhe80L=$*=k zrX-ffW|P)QPY2R+od6t3r%!!z?j4`KW_2`7aG7NNZW>e74*MEv<=Krs=0D! zUNx9fkEp-T>|#>rfuX4}dJPgD5Suiy5L13x>tDj+n5x#3wvJK2sYKn=<=ZE9%_Nop zw&k*chDvlfzggAW>*DM_Y*M0JI520b^xMn!_kEtA*eP`W{gk4`f4){TAL72Qpkcd? zMnT4)Smd`6c2-18;eKeJqNeTI1zSxr{z*EjdvaDyYCQ3xLBEvFtM>Y!!Yln1FWG}} z*?|&?i$#|w3ODOcXS)xl!4ZX<@~E;2Ou&4;a}jS-MZ$xx*oA*d&niwYVpsE;Q=O%9 zdG$SP50~s}DKPL~M8=4UFh=-jO)~;Bm}10s*c@9whug^hYAkQ))8y74X64iO?s~G_ z!%(JNGslVRB@3^og}$bBRa`Eho}tCOvxnkIbJ4=>pU0Z`@}8lpa*&k-zP9>Xj%rWz zbUA?{d3(JE{KS7Udc^Fdab=Hc=m40A`1AWs$-jTsyrxdiPEHWJ6G0^*cO_IhYfjsQ zfOL|1jx)Wrq*eQSrt*oo4O8~jFVyRf_=?Jx^*sP9cS zgkCufUzYISe)t&^I$gKrBdu+>XNc2{DLtImVTH~0HAZf6|E!9w9k?)$zO?9lkO6XM zwBsk{=@X9rRsm2@{=FkrC=@n~^eB5JmGmv1Gb9s40kZn+wn#^k}r)1X}vqwf@wL7(1EOHG3F6e1S|93d!RfKcK@UN_@t! zqsax|+9JSQDWywd?zOM85i;nrwke%$;lW&iza;g`oAGdLSK{3f=B?itT*gYojEku# z`Q38x^p6^E_-v;v%~8P2QT#+^)ya~0Fw|5Du4hmi-zl|oIWt5j?O1SVxS{VlmwF=< zM&}|%nCM}}5Z5e)gA^q2jb_Edtvp5{eRaGO+~zv&R6o?&W9~3pRRfu-OQMZZi>>$qM4=TSc3WVDn3iXtZMf%Muv02bp7O3AjrFWJvX^)|ig& zh+Z@-;3zS?(i@qLX)6kt#dj$((b-2jf`d{|KCAhFZ0XdDe6bv77%18=4nZ^fl7P&v zY_HCu^EPk06RRL7m7xE*RZ#g9bu%9>onZGW)?_|&erPHrNT?SvFbjf^%jM=>y}r}02k2bfuGF# z8DMz0N^-{kQJShsEVoL=;m9HH_){+{w=$F^@tL^en`t(wWxXZrk#~v~;NtH|6JP|u ze0`J;X$?2^IwyrFQD^u|Lco3nzZ3YLTQZUwa5QC zS;nHvvryF`b6!lKRJ|<(; zrEnKmmKoUSc+r?~((YiWw=dWz(v~H}BMWQ=rlVyEOQW1q_i0XPepXNLsbr zJ%%Bv?qf`V)^@8r0CZMJ~ z3eY?2q|5MC@$Eor{0TYJs)>P4Uf84EWqLl+RPQ6OZCp9w7kEQ<3<}ouOh#_ppq=Lt zaj3EoEB+&eB?>h%`sNcR}m+mw6Jy8?R_}@r!(OWz^)Jxgv_b6b97-+dky{ zPD4)mj;xP1Bh%!qJ3p+xnct6IdMjZh((zX?>^PpsCBaZ$^ok@ksoFkL2RL>wG++2K zE&!s&c+ljOV=PV0I^oW9>AZ(&L+e$XkrF%Dr9qErREwLKNJYI@B#( zl(g;lcxPFVB#9E(zpFw6Z90s+ir6Q=>jgo>8)_85b`i1M6ShXV9#Z6}t}1hV`>F=# zck>)EBkecT4TsdmMOs=y0X`ja8C&uRf?(#&9(XL| z>jL2IXO_YC3f?2Mj`d|DH9Zk+reFrXz8I%|avI472UQsK3`)QXyg(Ov#hn?^h`2lM z5#9i2rQS-Mq~#qzYKQ(oJLnYk>0w*kWuG&5V<`k2$4yl;Ysdb2fYFfpIk8eAx{x-0 z+H7}|10{D&*c31mQbmbjBqUt78xXAnNWA{%!cFfI*RoJNwRKElc)1|3M4Kw-@Eb3^%a8T* zm}F{jPT_k&n)#GwF|g?qO#%Nc&zCx){|NtRb!HD*naAI4aGiyALV9 z&1-k3(4>(hC+*y|JbyyJx1tKNJd}1GeY={HL3AHQUEGSO%_19A$G`&<{8OuC6BZD| zy53;$8S+u{r<&_q&MQyc573v&OukfRq>CzM_#0#uzjZ_=C02(Xic-gojhXP6%#Y*( z!L!h{|EEZiX5&r;Hr?SK`t)Tf-m)WFZ*4+8in|35r4Pj<7=LH8vWkC)=RA%9W}@nb z(K2+9`_>B|-`>jp5Nu8|;_b>fYlm4|`;ly6c~%jhGg8)r3JkmjDqzrm9t*+gXzD}y z+I>ApEA*}M^7Za_t&FYkA;FZ#L|ODWSiGSd&Z4M?hpOMXX%y=YW3BJ)D1> zx|Punrx(duB|F~v$;2?h0E--&ZmttWRVcA#XT*#gomTdSE>r|&$hEbbP&kE)53ANM z)-Kcv*)6!Xx$YKGKq4aCAD~ovuciCX^MG@Fmy%#SDAFdAJyp%+<`=mP5bT?PDQCp_ zvZ!wIi0$>tyl^baB)x(YKYpzv^Ovvt<0V28!bFY}g;ElkRa`%yn=rL42AJBs;@E9& zf*`<0w0A6{OLl{w1m8uV4j~?wD-}$wGlv{I>|^N0B%1ikk>5XCo9ceu*&je3mQo}EX zxeFB%g)*WrrTEKXD$e35CbHyYenN~)oEt9f@-+*{l}9kMkq#B?{Fzwuj+kP>+)i&L zY!x=o*eoA|nRa47ZS2Avc7=vvsg3T&6bz>Zakc!dL)k=vH`58d8s*-ij1$Ebdx`)J zd|v&64ml#NxKJ6hxz?B{v=&EPF$#PNcQu@wz}l&=Dn(L^H;mtPjDyz|_q?V^DsH|;jZ2wnv(KA^)?s>| zNkPVD=VAdRo)t8X2@q{u&{B zN;mZuL`=CdQUQG_MaIeXoES5Oydf1-(_Tw$^5I@P8XWx2Wh%jI;j`vbTlX<+K2I2h zpf2>n|37DgDczXwXFD}en4Sk)+1df;(6_GzR6%cRTu};!Op~e4Kan9(cx$KjlPQJz ze*2MF8eVi6_x#fWBhmVA__@!lj&u>C8oPo*Rx-M6GU_iAzB{E+d7%&dca(GlBY=0L zJ{X`u>oeun;~u(dt!<4&NYL+f5b@XNitcYQ?ouJ{@X-TZ^`rCTjQ9Pr!>P&(E<+Sm z(bEFMc2VejY`z>o|E;D6QJ{l?zMGE(GM>-nV%7<6NIy_^@DabtVk43*s zP@^?7+(uEMhZE@?|0bO_KO28pSRGiR?RokTRtJ!M`5tkZ#j5EZIZ(JWZP<#;U0) zW;<)T>px$CMQosL>W9VbPYbQZcykGFt@W`<{))JmGiay5gG$I6=L_1}T@kaU$|V=0 z@VQ!vMrGg8l%N{tNINTx?@gXT>V((CC2#*w0LV{gd(4KHW`3A{ZslWf#s z$3DZS9TzR-AizjbS^c0x%~V1fg#`Q@8$EkmViXA;)3Z_W`;*eHUpYgk?`IYQ!leQ5 zHP4kQyV?Hqw{3w$WtN}Rl>SMT4upB;myA4Z6-aPUx+BX^)VS|IX2k*90=&+qE#ne$ zo`bf>9^fXWB&dwS<-$j$qATg2E#qNlil`^Nc%NF6MGuaOiC>X?7JUEc1f})L@_}r# zjZABC;O{huD8B*gmMl0R2iqJ~kJ==oE1zO5IUrx0JB?QjD!mocko~R&AgKF?1Ny@l zeaY`%`5q%MA`{p6A95esQYx}2f!K8f$h=cv@7wvW*Rtqb*H6-*-0vggDstbA=qdPq zYnKn{2fYUQH;WUv-x5-^wKjVNsEXjgC7agzR8#l3&S^2fzmdwIxtFA9drQ%Y7rul8 zk2xN3QcJDmyo?m}hrP#WVJcxO&*j=7djkSU!qdYOz)eJ?cYdP&6YnuN5~bxp=4Sen zR`nmyWzlV>Fj7*?(-`~GaDTOJqb>if_8X}&jzm6tTlTPs)AWyJP8FR~406VUvJ{Wv zgKv7d?4+jLMpT|+F;K3tN`V=SKCO~&{}n(zQgvjfhON!Dhlc!@1LjmAY0%@Fpu$(1ShQ-Qe;-RBUWY!r|p z^N;tdnrkb_CI;swk=UO=V;@i#u)hNV>mK>LhC4_F%LO$D6WDCW>rkrUE%tL|$WY;> z^MKEgz!u>L1stPgj>T%JbhMbk{;xIA0a=q#U>>yuXBsw+`|?VL*i(lKe88gUb1wxm zg;9N+Gjr)W{s`)u$xI~Z_QS^C>`XA`B1J5Ox0K!+|IPGv4*+;En00o~muYC!W@lh@ znM14$pnWs9EdT)a4iEMr-d!^|>zV0h63~d_j!eJdo)iO^2Cm`IMl`Bt*6P)pY8t8a zMh%kzy324Z!qKkn10^308vUTA$>xMrLQE@uOZ>?wBdEVtw~PD$e1UB!4PlQb_jMwv z{IzZAgEh*TXB&Qx?*ZM!{vpYYn19IE4)ZlmBg@BP6u4{5CpGQ4TY3*JG;V-p26_N zTKg67C2WrBzZEw9AyVM$02h$^S0cacQ=?xe1po-00mVoh^e8<5X>PK23Jf0^h^N+3 zfyh5v+9QQ=hXZm4!q1w;U9J#=GRHC(GSiRiM%Kv@U!TelG_w(!_ff&syM1ejug}v_ zkqE@~@RQdn#t6X-0xkuWiH{YIhz(5wHXBuLy8i3&im8(?DQOU@3qnQ(Rw-kUS>ZkR60f` zGfEyIci;1XK>R#MnMRpUzQd^P!+nmH>_iy+d=OC2E{dqIinf~GG^-u^(SNyr*2IDF2i0;7%fmlb}MI3xMHXI7aIg{M9s}g`)hwML)@|Pk%oQ_rOGesq!lMwg~f7}rs z7IPvUlI?b}Oy0#uQ`it}P`boG{&C2l+&}5;FbR=nC{zh*=zP5)_Xn~i~gz+9FM)x+A6B6!ZAqUuJVjQ={JriQ!)$`_F zBl*A>-K8(c-s9QP(59Jq*gZ6@;qO*!_5ZGj8YQWeO*^_2pv*_p=EE}H0qrh-L+U?C zcPtl+DQabWc>6!DW1ux*LpdYt_Q*UE@ZAJ$Qr!sEPtFazRt1R_KvjR925b!1`MX*v z*WYXkdY_R(`E8BOmDZ@?f;a? z8}N+SN&dwzXG*`Y>(g)cj!vlXQ5)hjJiBwagH+M;gjfWZzkjWlP-{)DDIIa(F9i!1 zrqOnv%^Q%2u&f$&<&AGx`qEv)$j}tS`~639+vPS#5RNRWHah`pHVrtK7E?eCgg&Lim@F!2t8GmZC_%=S& z^IzF*NlcB@2yr*lp~U-j9HEu_mZHfJ8mhNb7rbpg1lE+3Da%O@XupOFrjGwPmiv@t z;*F}_5Bn7EZ(F64ND9AwV@JLE#=={Xf&(t}Tp?am?HV;0;hs-o>o8@^&9;L3U9I{4s&7Z)PR+>0couxj^BZ!5$W8&suZ4fg#Hbf zP&Hg7!;6T|gtR>G_R!l=>ljZzUImn#t_^8b&e&mSa6YvzF3qa+8vlwB?H10A!``IK zEww}texlcCw$R{xp0HH9b+HWTEA!wAG_QwOE3rF;#&SvtZ6*mVa{KDo7a_bEajR>8 z_Bu9tzoqreGCzMV)0!cS6tc+2=$@MW{RxTTgP-EDj8t3nmX>04yFs0S3&_VWtMY>T z&+5r1?Pa<-4-_{Jb2Nh_4}Xm}2N7FCK(658yU=eR3FN`985;j7F%x$VCVK^NEo1TGtYKj!{6^u zMctXsXqMRED@l}7Ob+)(0{~&Kd07R?tLAI@XJu;p0t`@G!=@%*-ij}{18J7X)_;=9 zxnX})sJ1($7RDef&dd58k1UDlM2r+5eQ95eLk`dPU@rh{Gvj=cvsnB9)~K8PjApPS zfo0{~qCOhCd33!&zxMh>{iw#j-!S9){B8iYCFj2!nA{yRCqI+aMIXrC2i4aOh0GQ` z#0*_pYJUb|51#rC3!s58(H5qB*6X`Hv^w3Os49zfvoLzweNy!Ps`z3bOak?G%?#6Uu=ehJwPCYO7x9R+FMQ`LK-5G;s z3dqKTWM}xp*Yt*WwT!`3BVpOZxxP+{UK6|1t;)J#8InX7{~WuZjg;jfaC3e+XOb9x zuBc~Au7ePi{54qvvk&qkW6*&JkKEb>N13X_d+q_(k6|IfImi?^2Sr6?88N&N-c#C; zbbs4l1PX<3Od~t~aOAXb91wN1e1F5O+VN$uhP>4DzL{Irt$MvWf;!3XH+Gq^YsMX3 zdg<*%?QB&w&HC@YY8m4J6+BRe|bz8zxXV%&LHwEO~{&Ar>d5HQj!BV zNc)qv>}UuwJ z0pmMuRgyIxKKY8gDdXRx>Z*RvWk1D^d$U+0;m3ubdnNIJaix>qJ?7wh&fP8*!=rbt|!%1D4(fvBd#d**7D;D2Ajtn139P ztSwMmYo1{b9~R`%$1G}3r7=E6LMnMz?wxv6klELsoj<;tMMF)$qW*O-l3?dvDQK9T zHkVrWdw?hd4=qc+8OHK}iG|4#Egn7k$f3MB8N%rILRlk&lHRvhXolckYFF-c}y~WTiE$+g3b?%P0-Kf4= zC!9ne0IEoa2CO0hftPv$FTejN-X$N1#>>Y)AhihEcRyLvxZK^lX;HUDRwWg3zG?@K z@bZqWT*u%~rR{r>3`gTuw_&ONmU?#K^yl>8Ia;gWeosEEaV;4jkA!yD{FR=UMxgCR zIjV3H)7CbDr1E!Nim3clyPV5=H~>%FvyRyFtQV{l|Cr{@Di@?$0S|`qlKQ~K5JjWe zk~7oc$VtMC#}Ayv70zdHVSj1K`c%s?=x4bShNwBC*^E_roOQ7s9em40bQ?YW17zMz zH+4|=D?x$Y}Cz6@|%}1eGSMWH+Nlksh8Z=oFPBqqZo5{;!-(G`g zQo8pcE08fFS~K3q@mlq=Q=hBD|N8RAQazfnMYI7_GD7sFM)Sm1W%J$nH=%*dd0o7B z-W9b!WH{Aojp6NGW>^vYALQE46i?S`2?$t?Al@e0nnoGC8f<=S8;_`kzjKrBN=*8T zi>0mO7|G*5pBPzp?p_VVDE&atT2E($-Ua-!w_5S2GXHy7cFq?GDh`*g5jxa&S(wKFr&ls>izc=Oe-c=U^IFh zfzoY?g52%6V8rQATW1Qy44Bas~1a);yCD~f`;Z?d2EBAWo#H*@?Zj;M% zh;mfK%7*HmccFWU7iUc4+)jE4za-t65IlPTs1LrpT9o1x!HVD0VnZ!t73m7$=)zc$ z{v|n08qM`jQa5@Q;}1QzQY=aVix}z_+FR=T2&n*z3c=0BPh(uls2H-yk)m!leo8Cy z-3jtEEX01lT}Iy3RCfr5F}Kz94kO5KuZomAG>N`)Nji}&-;kQ;7|FTUEVxDp-y)la zhnDeiSF{Iz(+z|ThvIx%N?!X!Br(<(3D`QUITP4}xA{$S|66r+`_TVO$Kee!_8#s5 z%)gm0>~6kmF@Cvg!qoDem5~W*P=D-Z3h8B!JtA189{oF|X6f(PcAbx1#B8ov7hE4N zXYi|Ba<_vW5{s4p*&v#&Slr!^RpoTFQaSumzgF1yce}@(=^DomMREeYN;RQ*CvA}o zZieScO=%0sa78T7iNMl+VNVgN59J}`K%dw-prfCpN}JTZsXA&HeGX?{Zzz}Ek=Gxac6o|RU_8oU$iH9fw8;PwQ9~O(9o3XP>jofu*b%{j+UMlNudI@Z z9i6Y?o!=RCI}=<0t9Bc=!L_3X%XhnaGJT#PZd)i)A zTpop6G~bfRKqa9+e*;UvUpp)8;wBu8 zs85nW`CYazckojo^Csvf^I{N7^V(X{Qol^Zx{fUDn-IPN1J<2(bR$^~aoIOMpIjZS zklbiRdYsWuxsJU?UUmVqf@=3CTU_6C0=kx&ILxf*>{vo1HM@V@#(glF>SP+26W(h-F|Ok5aB+S; zGp~b^QEzC`poTL!@*LT~LVs2`@8;Jdv zD*u{DK_bG8We@XLE$lh*o!2}@@hk)SK6-N325P7c&iWI11vjjcre@jCojpUWiQ0^N zIf0)k+(TG?d-;kg91|m^yjh&lV=#Vs9v{oW0z3*__dHy=^^w>_Bk1d{c}{QKGczO_ zFC@v2#+44Y>EXZfV$YAIkxwY{O|5h)J!OO~(s|=9QC$=q-{j|X9@REz);MiQiygXM zd}1Oc@xpfe#L4NH^QeO@L9)V9-NDv6D9ld#)wUPTiF&E_-zGfqkEQMCq0qCH$nEB)D!*sdh!#=>Xr3?R6* zDrTzO8Y3R6XM0CJe3n=_^j%<;>o5DJ3f)nHj+{#AQ{QDigWL64W<+wkA(*5_fw9u2 z#!X5{VQLvuUA+ZE_VCVn6W7yW^u(z|I@EaAxTr-<>dXLX-dNLf$V0R8(4iptQ zpQ=ESk8K8|`eMw3RN#c#5fMi%T~Fj|HaOf!njX-&@{K0#tW38PhtpKpDzb`sjIw*u zaDU|!Y2#geXK)03(T#uU;q7c{gU2xuUGjlh*Kx@-jv#;h>O=@DO7`$-zRXbdPq+zR zWwz#a;ki<+XR{#_fo!(F zcSip;41aeO6SLQ4}l*{A(5<9*s#H2e2Z855JelLUD0HA^|Rn^)~PRQ8wUEv3rJ zA%+f`)~3m2%me@Fm^=cWH_X*ew?|Gc3jjP&t=A;EYWVKIEtMG1RTevRVm;(u4Hm$! zL&0nvb$UbWIrX}IK=pmH1>4M#zdZNn3E~DO+;s-ByAn~ew`%>pzxrJ>oEbd1=9LUy z_NrUDmP_?`aQ3W<+bpM6i{QU5N|yQsCZ z&mZZR+)5QO0Z3UwXM)U+0W3UCwqqG*qz_f8!Ij7ThK@=>ZuzBS{Ko_~0D^Azv>6Gi zwAIHON2*RKQ^oYlBz|_YCNd-0gxJJSLASpQhqlL}QPS&z@v!MvB1uq;<*rE)IUq%) z0ttaVLaKIaMz^*z_Cj>15kN_;C_>rv-N+CUiLloYKWu2d_($T!{f6_iZk*=y{(72a;ypqN*=VsvgX@S*kE@F!FD$-ew zLh||!Imu#W!6BqdSz0n9%F`(Ua_`vi9*FgwVGpb%H=6cri}35x%so&$gvQKOX%vv9a!4ls}W z8}-5D-WD-Z-v7s7LdolqW5RLkqnB{v@BO>sXWuo)0CLZr5MDmNU6=X zb8en^>+yXVBba!$gpJ~X?jp)i^ZbyUR|SW2PwGnQeLBfV-K@*Uff~`pn6n9`V2A_z z+=K&Dw%`RpqC1h!+PJxo^kTbrbZXk}Nt9*1@Se=^HyTSP*TRn^+j%%bP2%6#yjv?` zLSW(f@k*}fI8`OBUm>z7#^|yw-$<*OSvI8xr~avaVtmtwi!L83y>6=WhvKkw(^2$Z z2^!rco%(vJ6BSBYwrLW^@@%l*_U$!E<>=J`E_#k2wm0_|UcgGt)}kx&#DiAoR5f$Vt={`W zf9BO5$Is2_kBr;oP}Zh#fY^`M#K#*=4gZP(effHgvt{-iob`B2TVKhrYd^g?(^H|= z6d{N?iDI8&VpeHFhk>MH6w)%PNZ}kZxcg+buF-yE3yVhY9_5f3-d~-hGi&i8KIi!J zmu$odiQiOF7wC-tB6RwPODfardNbF0Xw1kxHLz2@#K#naW)m`ku#@bxe&lY!1(uQ0 phXWkH{*jiY#227Z5K$Pn`?0FO!IQaaZJf{cd@JgdXafKM{vWl?{Cofa literal 0 HcmV?d00001 diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleCustomResource.java new file mode 100644 index 0000000000..1d583b1ea0 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleCustomResource.java @@ -0,0 +1,13 @@ +package io.javaoperatorsdk.operator.sample.podspecinspec; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("scr") +public class SampleCustomResource extends CustomResource implements Namespaced { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleSpec.java new file mode 100644 index 0000000000..03eabf6274 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleSpec.java @@ -0,0 +1,19 @@ +package io.javaoperatorsdk.operator.sample.podspecinspec; + +import io.fabric8.crd.generator.annotation.SchemaFrom; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodTemplateSpec; + +public class SampleSpec { + + @SchemaFrom(type = Pod.class) + private PodTemplateSpec podTemplate; + + public PodTemplateSpec getPodTemplate() { + return podTemplate; + } + + public void setPodTemplate(PodTemplateSpec podTemplate) { + this.podTemplate = podTemplate; + } +} From 0683649a5a5f05bc46c950b8e8a1027a888c504a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 21 May 2024 12:26:00 +0200 Subject: [PATCH 199/644] fix: remove not needed files (#2391) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .../podspecinspec/SampleCustomResource.java | 13 ------------- .../sample/podspecinspec/SampleSpec.java | 19 ------------------- 2 files changed, 32 deletions(-) delete mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleCustomResource.java delete mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleSpec.java diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleCustomResource.java deleted file mode 100644 index 1d583b1ea0..0000000000 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleCustomResource.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.javaoperatorsdk.operator.sample.podspecinspec; - -import io.fabric8.kubernetes.api.model.Namespaced; -import io.fabric8.kubernetes.client.CustomResource; -import io.fabric8.kubernetes.model.annotation.Group; -import io.fabric8.kubernetes.model.annotation.ShortNames; -import io.fabric8.kubernetes.model.annotation.Version; - -@Group("sample.javaoperatorsdk") -@Version("v1") -@ShortNames("scr") -public class SampleCustomResource extends CustomResource implements Namespaced { -} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleSpec.java deleted file mode 100644 index 03eabf6274..0000000000 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/podspecinspec/SampleSpec.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.javaoperatorsdk.operator.sample.podspecinspec; - -import io.fabric8.crd.generator.annotation.SchemaFrom; -import io.fabric8.kubernetes.api.model.Pod; -import io.fabric8.kubernetes.api.model.PodTemplateSpec; - -public class SampleSpec { - - @SchemaFrom(type = Pod.class) - private PodTemplateSpec podTemplate; - - public PodTemplateSpec getPodTemplate() { - return podTemplate; - } - - public void setPodTemplate(PodTemplateSpec podTemplate) { - this.podTemplate = podTemplate; - } -} From e07acc7294fad5ac8875c7dcf43ee3714f98a8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 21 May 2024 16:35:08 +0200 Subject: [PATCH 200/644] docs: docsy update and build workflow (#2392) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/hugo.yaml | 80 +++++++++++++++++++++++++++++++++++++ docsy/README.md | 6 +++ docsy/go.mod | 2 +- docsy/go.sum | 4 ++ docsy/package.json | 2 +- 5 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/hugo.yaml diff --git a/.github/workflows/hugo.yaml b/.github/workflows/hugo.yaml new file mode 100644 index 0000000000..ce9703b491 --- /dev/null +++ b/.github/workflows/hugo.yaml @@ -0,0 +1,80 @@ +# Sample workflow for building and deploying a Hugo site to GitHub Pages +name: Deploy Hugo site to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: + - main + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +# Default to bash +defaults: + run: + shell: bash + +jobs: + # Build job + build: + runs-on: ubuntu-latest + env: + HUGO_VERSION: 0.124.1 + steps: + - name: Install Hugo CLI + run: | + wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ + && sudo dpkg -i ${{ runner.temp }}/hugo.deb + - name: Install Dart Sass + run: sudo snap install dart-sass + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + - name: Setup Pages + id: pages + uses: actions/configure-pages@v4 + - name: Install Node.js dependencies + run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" + - name: Build with Hugo + env: + # For maximum backward compatibility with Hugo modules + HUGO_ENVIRONMENT: production + HUGO_ENV: production + TZ: America/Los_Angeles + run: | + cd docsy + hugo \ + --gc \ + --minify \ + --baseURL "${{ steps.pages.outputs.base_url }}/" + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./docsy/public + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/docsy/README.md b/docsy/README.md index 481ce67413..f9d6ce7183 100644 --- a/docsy/README.md +++ b/docsy/README.md @@ -1,3 +1,9 @@ +# JOSDK comments: + +see: sample github action: https://gohugo.io/hosting-and-deployment/hosting-on-github/ + +currently use hugo version v0.125.7 + # Docsy Example [Docsy][] is a [Hugo theme module][] for technical documentation sites, providing easy diff --git a/docsy/go.mod b/docsy/go.mod index 37ec74496c..00890a6408 100644 --- a/docsy/go.mod +++ b/docsy/go.mod @@ -2,4 +2,4 @@ module github.com/google/docsy-example go 1.12 -require github.com/google/docsy v0.9.1 // indirect +require github.com/google/docsy v0.10.0 // indirect diff --git a/docsy/go.sum b/docsy/go.sum index c11d56b022..1b3ed24b03 100644 --- a/docsy/go.sum +++ b/docsy/go.sum @@ -1,5 +1,9 @@ github.com/FortAwesome/Font-Awesome v0.0.0-20240108205627-a1232e345536/go.mod h1:IUgezN/MFpCDIlFezw3L8j83oeiIuYoj28Miwr/KUYo= +github.com/FortAwesome/Font-Awesome v0.0.0-20240402185447-c0f460dca7f7/go.mod h1:IUgezN/MFpCDIlFezw3L8j83oeiIuYoj28Miwr/KUYo= github.com/google/docsy v0.9.1 h1:+jqges1YCd+yHeuZ1BUvD8V8mEGVtPxULg5j/vaJ984= github.com/google/docsy v0.9.1/go.mod h1:saOqKEUOn07Bc0orM/JdIF3VkOanHta9LU5Y53bwN2U= +github.com/google/docsy v0.10.0 h1:6tMDacPwAyRWNCfvsn/9qGOZDQ8b0aRzjRZvnZPY5dg= +github.com/google/docsy v0.10.0/go.mod h1:c0nIAqmRTOuJ01F85U/wJPQtc3Zj9N58Kea9bOT2AJc= github.com/twbs/bootstrap v5.2.3+incompatible h1:lOmsJx587qfF7/gE7Vv4FxEofegyJlEACeVV+Mt7cgc= github.com/twbs/bootstrap v5.2.3+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0= +github.com/twbs/bootstrap v5.3.3+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0= diff --git a/docsy/package.json b/docsy/package.json index 054b5ced25..6e995489ce 100644 --- a/docsy/package.json +++ b/docsy/package.json @@ -36,7 +36,7 @@ "devDependencies": { "autoprefixer": "^10.4.14", "cross-env": "^7.0.3", - "hugo-extended": "0.123.8", + "hugo-extended": "0.125.4", "postcss-cli": "^11.0.0" } } From 2c64b054003c2aefdac9d6dd8b8eaae2cb345119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 21 May 2024 17:08:05 +0200 Subject: [PATCH 201/644] fix: hugo version (#2393) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/hugo.yaml | 2 +- docsy/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/hugo.yaml b/.github/workflows/hugo.yaml index ce9703b491..fb7da3eee5 100644 --- a/.github/workflows/hugo.yaml +++ b/.github/workflows/hugo.yaml @@ -32,7 +32,7 @@ jobs: build: runs-on: ubuntu-latest env: - HUGO_VERSION: 0.124.1 + HUGO_VERSION: 0.125.4 steps: - name: Install Hugo CLI run: | diff --git a/docsy/package.json b/docsy/package.json index 6e995489ce..02cc7f496a 100644 --- a/docsy/package.json +++ b/docsy/package.json @@ -34,7 +34,7 @@ "update:pkg:hugo": "npm install --save-dev --save-exact hugo-extended@latest" }, "devDependencies": { - "autoprefixer": "^10.4.14", + "autoprefixer": "^10.4.19", "cross-env": "^7.0.3", "hugo-extended": "0.125.4", "postcss-cli": "^11.0.0" From 1edd2bc1bde0d4f24022b211e7a4742757ea282b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 21 May 2024 17:52:03 +0200 Subject: [PATCH 202/644] docs: docsy workflow fix working dir (#2394) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/hugo.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/hugo.yaml b/.github/workflows/hugo.yaml index fb7da3eee5..5780186de0 100644 --- a/.github/workflows/hugo.yaml +++ b/.github/workflows/hugo.yaml @@ -49,6 +49,7 @@ jobs: id: pages uses: actions/configure-pages@v4 - name: Install Node.js dependencies + working-directory: ./docsy run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" - name: Build with Hugo env: @@ -56,8 +57,8 @@ jobs: HUGO_ENVIRONMENT: production HUGO_ENV: production TZ: America/Los_Angeles + working-directory: ./docsy run: | - cd docsy hugo \ --gc \ --minify \ From e6edd174e9abdc566264b1ae5916b6397df7c5aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 21 May 2024 18:47:31 +0200 Subject: [PATCH 203/644] fix: hugo post css (#2395) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/hugo.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/hugo.yaml b/.github/workflows/hugo.yaml index 5780186de0..6c2918fbeb 100644 --- a/.github/workflows/hugo.yaml +++ b/.github/workflows/hugo.yaml @@ -50,7 +50,11 @@ jobs: uses: actions/configure-pages@v4 - name: Install Node.js dependencies working-directory: ./docsy - run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" + run: | + [[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true + npm install -D autoprefixer + npm install -D postcss-cli + npm install -D postcss - name: Build with Hugo env: # For maximum backward compatibility with Hugo modules From afd1cb60f82e63fe9db1366fde328d06d154ec0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 21 May 2024 21:09:12 +0200 Subject: [PATCH 204/644] docs: remove old docs (#2396) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- docs/.gitignore | 4 - docs/404.md | 12 - docs/CNAME | 1 - docs/CODE_OF_CONDUCT.md | 138 - docs/Gemfile | 8 - docs/Gemfile.lock | 86 - docs/_config.yml | 25 - docs/_data/navbar.yml | 19 - docs/_data/sidebar.yml | 35 - docs/_includes/analytics.html | 9 - docs/_includes/anchor_headings.html | 172 - docs/_includes/footer.html | 11 - docs/_includes/hero.html | 20 - docs/_includes/heroDefault.html | 5 - docs/_includes/links.html | 4 - docs/_includes/menuItems.html | 49 - docs/_includes/navbar.html | 42 - docs/_includes/scripts.html | 3 - docs/_includes/sidebar.html | 10 - docs/_layouts/default.html | 21 - docs/_layouts/docs.html | 31 - docs/_layouts/homepage.html | 19 - docs/_sass/theme/mixins.scss | 13 - docs/_sass/theme/uikit.scss | 100 - docs/_sass/theme/variables.scss | 138 - docs/_sass/uikit/components/_buttons.scss | 33 - docs/_sass/uikit/components/_content.scss | 120 - docs/_sass/uikit/components/_footer.scss | 49 - docs/_sass/uikit/components/_header.scss | 19 - .../uikit/components/_import.components.scss | 56 - docs/_sass/uikit/components/_import.scss | 94 - .../uikit/components/_import.utilities.scss | 19 - docs/_sass/uikit/components/_logo.scss | 8 - docs/_sass/uikit/components/_main-menu.scss | 32 - .../uikit/components/_navigation-bar.scss | 91 - docs/_sass/uikit/components/_page.scss | 9 - docs/_sass/uikit/components/_theme.scss | 25 - docs/_sass/uikit/components/_title.scss | 26 - docs/_sass/uikit/components/accordion.scss | 107 - docs/_sass/uikit/components/alert.scss | 147 - docs/_sass/uikit/components/align.scss | 142 - docs/_sass/uikit/components/animation.scss | 430 - docs/_sass/uikit/components/article.scss | 99 - docs/_sass/uikit/components/background.scss | 148 - docs/_sass/uikit/components/badge.scss | 80 - docs/_sass/uikit/components/base.scss | 628 - docs/_sass/uikit/components/breadcrumb.scss | 123 - docs/_sass/uikit/components/button.scss | 452 - docs/_sass/uikit/components/card.scss | 384 - docs/_sass/uikit/components/close.scss | 57 - docs/_sass/uikit/components/column.scss | 138 - docs/_sass/uikit/components/comment.scss | 160 - docs/_sass/uikit/components/container.scss | 185 - docs/_sass/uikit/components/countdown.scss | 131 - docs/_sass/uikit/components/cover.scss | 57 - .../uikit/components/description-list.scss | 71 - docs/_sass/uikit/components/divider.scss | 153 - docs/_sass/uikit/components/dotnav.scss | 157 - docs/_sass/uikit/components/drop.scss | 74 - docs/_sass/uikit/components/dropdown.scss | 153 - docs/_sass/uikit/components/flex.scss | 209 - docs/_sass/uikit/components/form-range.scss | 186 - docs/_sass/uikit/components/form.scss | 811 - docs/_sass/uikit/components/grid-masonry.scss | 68 - docs/_sass/uikit/components/grid.scss | 407 - docs/_sass/uikit/components/heading.scss | 321 - docs/_sass/uikit/components/height.scss | 54 - docs/_sass/uikit/components/icon.scss | 220 - docs/_sass/uikit/components/iconnav.scss | 148 - docs/_sass/uikit/components/inverse.scss | 46 - docs/_sass/uikit/components/label.scss | 102 - docs/_sass/uikit/components/leader.scss | 70 - docs/_sass/uikit/components/lightbox.scss | 245 - docs/_sass/uikit/components/link.scss | 140 - docs/_sass/uikit/components/list.scss | 235 - docs/_sass/uikit/components/margin.scss | 250 - docs/_sass/uikit/components/marker.scss | 63 - docs/_sass/uikit/components/mixin.scss | 32 - docs/_sass/uikit/components/modal.scss | 353 - docs/_sass/uikit/components/nav.scss | 406 - docs/_sass/uikit/components/navbar.scss | 554 - docs/_sass/uikit/components/notification.scss | 191 - docs/_sass/uikit/components/offcanvas.scss | 306 - docs/_sass/uikit/components/overlay.scss | 85 - docs/_sass/uikit/components/padding.scss | 81 - docs/_sass/uikit/components/pagination.scss | 131 - docs/_sass/uikit/components/placeholder.scss | 45 - docs/_sass/uikit/components/position.scss | 265 - docs/_sass/uikit/components/print.scss | 61 - docs/_sass/uikit/components/progress.scss | 105 - docs/_sass/uikit/components/search.scss | 328 - docs/_sass/uikit/components/section.scss | 212 - docs/_sass/uikit/components/slidenav.scss | 122 - docs/_sass/uikit/components/slider.scss | 120 - docs/_sass/uikit/components/slideshow.scss | 97 - docs/_sass/uikit/components/sortable.scss | 90 - docs/_sass/uikit/components/spinner.scss | 74 - docs/_sass/uikit/components/sticky.scss | 53 - docs/_sass/uikit/components/subnav.scss | 249 - docs/_sass/uikit/components/svg.scss | 36 - docs/_sass/uikit/components/switcher.scss | 47 - docs/_sass/uikit/components/tab.scss | 197 - docs/_sass/uikit/components/table.scss | 315 - docs/_sass/uikit/components/text.scss | 284 - docs/_sass/uikit/components/thumbnav.scss | 121 - docs/_sass/uikit/components/tile.scss | 213 - docs/_sass/uikit/components/tooltip.scss | 87 - docs/_sass/uikit/components/totop.scss | 71 - docs/_sass/uikit/components/transition.scss | 157 - docs/_sass/uikit/components/utility.scss | 482 - docs/_sass/uikit/components/variables.scss | 123 - docs/_sass/uikit/components/visibility.scss | 175 - docs/_sass/uikit/components/width.scss | 379 - docs/_sass/uikit/mixins-theme.scss | 2204 --- docs/_sass/uikit/mixins.scss | 1748 --- docs/_sass/uikit/theme/_import.scss | 81 - docs/_sass/uikit/theme/accordion.scss | 59 - docs/_sass/uikit/theme/alert.scss | 46 - docs/_sass/uikit/theme/align.scss | 14 - docs/_sass/uikit/theme/animation.scss | 14 - docs/_sass/uikit/theme/article.scss | 51 - docs/_sass/uikit/theme/background.scss | 14 - docs/_sass/uikit/theme/badge.scss | 29 - docs/_sass/uikit/theme/base.scss | 116 - docs/_sass/uikit/theme/breadcrumb.scss | 45 - docs/_sass/uikit/theme/button.scss | 159 - docs/_sass/uikit/theme/card.scss | 128 - docs/_sass/uikit/theme/close.scss | 29 - docs/_sass/uikit/theme/column.scss | 14 - docs/_sass/uikit/theme/comment.scss | 69 - docs/_sass/uikit/theme/container.scss | 14 - docs/_sass/uikit/theme/countdown.scss | 53 - docs/_sass/uikit/theme/description-list.scss | 32 - docs/_sass/uikit/theme/divider.scss | 49 - docs/_sass/uikit/theme/dotnav.scss | 52 - docs/_sass/uikit/theme/drop.scss | 14 - docs/_sass/uikit/theme/dropdown.scss | 45 - docs/_sass/uikit/theme/form-range.scss | 45 - docs/_sass/uikit/theme/form.scss | 131 - docs/_sass/uikit/theme/grid.scss | 28 - docs/_sass/uikit/theme/heading.scss | 67 - docs/_sass/uikit/theme/height.scss | 14 - docs/_sass/uikit/theme/icon.scss | 50 - docs/_sass/uikit/theme/iconnav.scss | 40 - docs/_sass/uikit/theme/inverse.scss | 14 - docs/_sass/uikit/theme/label.scss | 43 - docs/_sass/uikit/theme/leader.scss | 26 - docs/_sass/uikit/theme/lightbox.scss | 50 - docs/_sass/uikit/theme/link.scss | 55 - docs/_sass/uikit/theme/list.scss | 36 - docs/_sass/uikit/theme/margin.scss | 14 - docs/_sass/uikit/theme/marker.scss | 29 - docs/_sass/uikit/theme/modal.scss | 84 - docs/_sass/uikit/theme/nav.scss | 102 - docs/_sass/uikit/theme/navbar.scss | 138 - docs/_sass/uikit/theme/notification.scss | 44 - docs/_sass/uikit/theme/offcanvas.scss | 32 - docs/_sass/uikit/theme/overlay.scss | 33 - docs/_sass/uikit/theme/padding.scss | 14 - docs/_sass/uikit/theme/pagination.scss | 41 - docs/_sass/uikit/theme/placeholder.scss | 29 - docs/_sass/uikit/theme/position.scss | 14 - docs/_sass/uikit/theme/progress.scss | 24 - docs/_sass/uikit/theme/search.scss | 75 - docs/_sass/uikit/theme/section.scss | 32 - docs/_sass/uikit/theme/slidenav.scss | 52 - docs/_sass/uikit/theme/slider.scss | 14 - docs/_sass/uikit/theme/sortable.scss | 38 - docs/_sass/uikit/theme/spinner.scss | 14 - docs/_sass/uikit/theme/sticky.scss | 14 - docs/_sass/uikit/theme/subnav.scss | 74 - docs/_sass/uikit/theme/tab.scss | 74 - docs/_sass/uikit/theme/table.scss | 68 - docs/_sass/uikit/theme/text.scss | 50 - docs/_sass/uikit/theme/thumbnav.scss | 42 - docs/_sass/uikit/theme/tile.scss | 32 - docs/_sass/uikit/theme/tooltip.scss | 20 - docs/_sass/uikit/theme/totop.scss | 32 - docs/_sass/uikit/theme/transition.scss | 14 - docs/_sass/uikit/theme/utility.scss | 49 - docs/_sass/uikit/theme/variables.scss | 36 - docs/_sass/uikit/theme/width.scss | 14 - docs/_sass/uikit/uikit-theme.scss | 9 - docs/_sass/uikit/uikit.scss | 5 - docs/_sass/uikit/variables-theme.scss | 1172 -- docs/_sass/uikit/variables.scss | 1061 -- docs/assets/css/prism.css | 218 - docs/assets/css/style.scss | 18 - docs/assets/images/architecture.svg | 4 - docs/assets/images/cs-logo.svg | 1 - docs/assets/images/cs.png | Bin 5544 -> 0 bytes docs/assets/images/event-sources.png | Bin 46120 -> 0 bytes docs/assets/images/favicon.ico | Bin 1150 -> 0 bytes docs/assets/images/logo-icon.svg | 1 - docs/assets/images/logo-white.svg | 1 - docs/assets/images/logo.png | Bin 35366 -> 0 bytes docs/assets/images/red-hat.webp | Bin 15512 -> 0 bytes docs/assets/js/mermaid.min.js | 3 - docs/assets/js/mermaid.min.js.map | 1 - docs/assets/js/prism.js | 23 - docs/assets/js/uikit.js | 12402 ---------------- docs/assets/js/uikit.min.js | 3 - .../architecture-and-internals.md | 68 - docs/documentation/configuration.md | 69 - docs/documentation/contributing.md | 88 - docs/documentation/dependent-resources.md | 556 - docs/documentation/faq.md | 98 - docs/documentation/features.md | 864 -- docs/documentation/getting-started.md | 61 - docs/documentation/glossary.md | 28 - docs/documentation/intro-operators.md | 19 - docs/documentation/patterns-best-practices.md | 125 - docs/documentation/use-samples.md | 259 - docs/documentation/v2-migration.md | 60 - docs/documentation/v3-1-migration.md | 47 - docs/documentation/v3-migration.md | 40 - docs/documentation/v4-3-migration.md | 50 - docs/documentation/v4-4-migration.md | 93 - docs/documentation/v4-5-migration.md | 26 - docs/documentation/workflows.md | 356 - docs/etc/v1_model.drawio.svg | 4 - docs/etc/v2_model.drawio.svg | 4 - docs/event-design.xml | 1 - docs/index.html | 120 - docs/readme.md | 58 - docs/releases.html | 25 - 226 files changed, 40915 deletions(-) delete mode 100644 docs/.gitignore delete mode 100644 docs/404.md delete mode 100644 docs/CNAME delete mode 100644 docs/CODE_OF_CONDUCT.md delete mode 100644 docs/Gemfile delete mode 100644 docs/Gemfile.lock delete mode 100644 docs/_config.yml delete mode 100644 docs/_data/navbar.yml delete mode 100644 docs/_data/sidebar.yml delete mode 100644 docs/_includes/analytics.html delete mode 100644 docs/_includes/anchor_headings.html delete mode 100644 docs/_includes/footer.html delete mode 100644 docs/_includes/hero.html delete mode 100644 docs/_includes/heroDefault.html delete mode 100644 docs/_includes/links.html delete mode 100644 docs/_includes/menuItems.html delete mode 100644 docs/_includes/navbar.html delete mode 100644 docs/_includes/scripts.html delete mode 100644 docs/_includes/sidebar.html delete mode 100644 docs/_layouts/default.html delete mode 100644 docs/_layouts/docs.html delete mode 100644 docs/_layouts/homepage.html delete mode 100644 docs/_sass/theme/mixins.scss delete mode 100644 docs/_sass/theme/uikit.scss delete mode 100644 docs/_sass/theme/variables.scss delete mode 100644 docs/_sass/uikit/components/_buttons.scss delete mode 100644 docs/_sass/uikit/components/_content.scss delete mode 100644 docs/_sass/uikit/components/_footer.scss delete mode 100644 docs/_sass/uikit/components/_header.scss delete mode 100644 docs/_sass/uikit/components/_import.components.scss delete mode 100644 docs/_sass/uikit/components/_import.scss delete mode 100644 docs/_sass/uikit/components/_import.utilities.scss delete mode 100644 docs/_sass/uikit/components/_logo.scss delete mode 100644 docs/_sass/uikit/components/_main-menu.scss delete mode 100644 docs/_sass/uikit/components/_navigation-bar.scss delete mode 100644 docs/_sass/uikit/components/_page.scss delete mode 100644 docs/_sass/uikit/components/_theme.scss delete mode 100644 docs/_sass/uikit/components/_title.scss delete mode 100644 docs/_sass/uikit/components/accordion.scss delete mode 100644 docs/_sass/uikit/components/alert.scss delete mode 100644 docs/_sass/uikit/components/align.scss delete mode 100644 docs/_sass/uikit/components/animation.scss delete mode 100644 docs/_sass/uikit/components/article.scss delete mode 100644 docs/_sass/uikit/components/background.scss delete mode 100644 docs/_sass/uikit/components/badge.scss delete mode 100644 docs/_sass/uikit/components/base.scss delete mode 100644 docs/_sass/uikit/components/breadcrumb.scss delete mode 100644 docs/_sass/uikit/components/button.scss delete mode 100644 docs/_sass/uikit/components/card.scss delete mode 100644 docs/_sass/uikit/components/close.scss delete mode 100644 docs/_sass/uikit/components/column.scss delete mode 100644 docs/_sass/uikit/components/comment.scss delete mode 100644 docs/_sass/uikit/components/container.scss delete mode 100644 docs/_sass/uikit/components/countdown.scss delete mode 100644 docs/_sass/uikit/components/cover.scss delete mode 100644 docs/_sass/uikit/components/description-list.scss delete mode 100644 docs/_sass/uikit/components/divider.scss delete mode 100644 docs/_sass/uikit/components/dotnav.scss delete mode 100644 docs/_sass/uikit/components/drop.scss delete mode 100644 docs/_sass/uikit/components/dropdown.scss delete mode 100644 docs/_sass/uikit/components/flex.scss delete mode 100644 docs/_sass/uikit/components/form-range.scss delete mode 100644 docs/_sass/uikit/components/form.scss delete mode 100644 docs/_sass/uikit/components/grid-masonry.scss delete mode 100644 docs/_sass/uikit/components/grid.scss delete mode 100644 docs/_sass/uikit/components/heading.scss delete mode 100644 docs/_sass/uikit/components/height.scss delete mode 100644 docs/_sass/uikit/components/icon.scss delete mode 100644 docs/_sass/uikit/components/iconnav.scss delete mode 100644 docs/_sass/uikit/components/inverse.scss delete mode 100644 docs/_sass/uikit/components/label.scss delete mode 100644 docs/_sass/uikit/components/leader.scss delete mode 100644 docs/_sass/uikit/components/lightbox.scss delete mode 100644 docs/_sass/uikit/components/link.scss delete mode 100644 docs/_sass/uikit/components/list.scss delete mode 100644 docs/_sass/uikit/components/margin.scss delete mode 100644 docs/_sass/uikit/components/marker.scss delete mode 100644 docs/_sass/uikit/components/mixin.scss delete mode 100644 docs/_sass/uikit/components/modal.scss delete mode 100644 docs/_sass/uikit/components/nav.scss delete mode 100644 docs/_sass/uikit/components/navbar.scss delete mode 100644 docs/_sass/uikit/components/notification.scss delete mode 100644 docs/_sass/uikit/components/offcanvas.scss delete mode 100644 docs/_sass/uikit/components/overlay.scss delete mode 100644 docs/_sass/uikit/components/padding.scss delete mode 100644 docs/_sass/uikit/components/pagination.scss delete mode 100644 docs/_sass/uikit/components/placeholder.scss delete mode 100644 docs/_sass/uikit/components/position.scss delete mode 100644 docs/_sass/uikit/components/print.scss delete mode 100644 docs/_sass/uikit/components/progress.scss delete mode 100644 docs/_sass/uikit/components/search.scss delete mode 100644 docs/_sass/uikit/components/section.scss delete mode 100644 docs/_sass/uikit/components/slidenav.scss delete mode 100644 docs/_sass/uikit/components/slider.scss delete mode 100644 docs/_sass/uikit/components/slideshow.scss delete mode 100644 docs/_sass/uikit/components/sortable.scss delete mode 100644 docs/_sass/uikit/components/spinner.scss delete mode 100644 docs/_sass/uikit/components/sticky.scss delete mode 100644 docs/_sass/uikit/components/subnav.scss delete mode 100644 docs/_sass/uikit/components/svg.scss delete mode 100644 docs/_sass/uikit/components/switcher.scss delete mode 100644 docs/_sass/uikit/components/tab.scss delete mode 100644 docs/_sass/uikit/components/table.scss delete mode 100644 docs/_sass/uikit/components/text.scss delete mode 100644 docs/_sass/uikit/components/thumbnav.scss delete mode 100644 docs/_sass/uikit/components/tile.scss delete mode 100644 docs/_sass/uikit/components/tooltip.scss delete mode 100644 docs/_sass/uikit/components/totop.scss delete mode 100644 docs/_sass/uikit/components/transition.scss delete mode 100644 docs/_sass/uikit/components/utility.scss delete mode 100644 docs/_sass/uikit/components/variables.scss delete mode 100644 docs/_sass/uikit/components/visibility.scss delete mode 100644 docs/_sass/uikit/components/width.scss delete mode 100644 docs/_sass/uikit/mixins-theme.scss delete mode 100644 docs/_sass/uikit/mixins.scss delete mode 100644 docs/_sass/uikit/theme/_import.scss delete mode 100644 docs/_sass/uikit/theme/accordion.scss delete mode 100644 docs/_sass/uikit/theme/alert.scss delete mode 100644 docs/_sass/uikit/theme/align.scss delete mode 100644 docs/_sass/uikit/theme/animation.scss delete mode 100644 docs/_sass/uikit/theme/article.scss delete mode 100644 docs/_sass/uikit/theme/background.scss delete mode 100644 docs/_sass/uikit/theme/badge.scss delete mode 100644 docs/_sass/uikit/theme/base.scss delete mode 100644 docs/_sass/uikit/theme/breadcrumb.scss delete mode 100644 docs/_sass/uikit/theme/button.scss delete mode 100644 docs/_sass/uikit/theme/card.scss delete mode 100644 docs/_sass/uikit/theme/close.scss delete mode 100644 docs/_sass/uikit/theme/column.scss delete mode 100644 docs/_sass/uikit/theme/comment.scss delete mode 100644 docs/_sass/uikit/theme/container.scss delete mode 100644 docs/_sass/uikit/theme/countdown.scss delete mode 100644 docs/_sass/uikit/theme/description-list.scss delete mode 100644 docs/_sass/uikit/theme/divider.scss delete mode 100644 docs/_sass/uikit/theme/dotnav.scss delete mode 100644 docs/_sass/uikit/theme/drop.scss delete mode 100644 docs/_sass/uikit/theme/dropdown.scss delete mode 100644 docs/_sass/uikit/theme/form-range.scss delete mode 100644 docs/_sass/uikit/theme/form.scss delete mode 100644 docs/_sass/uikit/theme/grid.scss delete mode 100644 docs/_sass/uikit/theme/heading.scss delete mode 100644 docs/_sass/uikit/theme/height.scss delete mode 100644 docs/_sass/uikit/theme/icon.scss delete mode 100644 docs/_sass/uikit/theme/iconnav.scss delete mode 100644 docs/_sass/uikit/theme/inverse.scss delete mode 100644 docs/_sass/uikit/theme/label.scss delete mode 100644 docs/_sass/uikit/theme/leader.scss delete mode 100644 docs/_sass/uikit/theme/lightbox.scss delete mode 100644 docs/_sass/uikit/theme/link.scss delete mode 100644 docs/_sass/uikit/theme/list.scss delete mode 100644 docs/_sass/uikit/theme/margin.scss delete mode 100644 docs/_sass/uikit/theme/marker.scss delete mode 100644 docs/_sass/uikit/theme/modal.scss delete mode 100644 docs/_sass/uikit/theme/nav.scss delete mode 100644 docs/_sass/uikit/theme/navbar.scss delete mode 100644 docs/_sass/uikit/theme/notification.scss delete mode 100644 docs/_sass/uikit/theme/offcanvas.scss delete mode 100644 docs/_sass/uikit/theme/overlay.scss delete mode 100644 docs/_sass/uikit/theme/padding.scss delete mode 100644 docs/_sass/uikit/theme/pagination.scss delete mode 100644 docs/_sass/uikit/theme/placeholder.scss delete mode 100644 docs/_sass/uikit/theme/position.scss delete mode 100644 docs/_sass/uikit/theme/progress.scss delete mode 100644 docs/_sass/uikit/theme/search.scss delete mode 100644 docs/_sass/uikit/theme/section.scss delete mode 100644 docs/_sass/uikit/theme/slidenav.scss delete mode 100644 docs/_sass/uikit/theme/slider.scss delete mode 100644 docs/_sass/uikit/theme/sortable.scss delete mode 100644 docs/_sass/uikit/theme/spinner.scss delete mode 100644 docs/_sass/uikit/theme/sticky.scss delete mode 100644 docs/_sass/uikit/theme/subnav.scss delete mode 100644 docs/_sass/uikit/theme/tab.scss delete mode 100644 docs/_sass/uikit/theme/table.scss delete mode 100644 docs/_sass/uikit/theme/text.scss delete mode 100644 docs/_sass/uikit/theme/thumbnav.scss delete mode 100644 docs/_sass/uikit/theme/tile.scss delete mode 100644 docs/_sass/uikit/theme/tooltip.scss delete mode 100644 docs/_sass/uikit/theme/totop.scss delete mode 100644 docs/_sass/uikit/theme/transition.scss delete mode 100644 docs/_sass/uikit/theme/utility.scss delete mode 100644 docs/_sass/uikit/theme/variables.scss delete mode 100644 docs/_sass/uikit/theme/width.scss delete mode 100644 docs/_sass/uikit/uikit-theme.scss delete mode 100644 docs/_sass/uikit/uikit.scss delete mode 100644 docs/_sass/uikit/variables-theme.scss delete mode 100644 docs/_sass/uikit/variables.scss delete mode 100644 docs/assets/css/prism.css delete mode 100644 docs/assets/css/style.scss delete mode 100644 docs/assets/images/architecture.svg delete mode 100644 docs/assets/images/cs-logo.svg delete mode 100644 docs/assets/images/cs.png delete mode 100644 docs/assets/images/event-sources.png delete mode 100644 docs/assets/images/favicon.ico delete mode 100644 docs/assets/images/logo-icon.svg delete mode 100644 docs/assets/images/logo-white.svg delete mode 100644 docs/assets/images/logo.png delete mode 100644 docs/assets/images/red-hat.webp delete mode 100644 docs/assets/js/mermaid.min.js delete mode 100644 docs/assets/js/mermaid.min.js.map delete mode 100644 docs/assets/js/prism.js delete mode 100644 docs/assets/js/uikit.js delete mode 100644 docs/assets/js/uikit.min.js delete mode 100644 docs/documentation/architecture-and-internals.md delete mode 100644 docs/documentation/configuration.md delete mode 100644 docs/documentation/contributing.md delete mode 100644 docs/documentation/dependent-resources.md delete mode 100644 docs/documentation/faq.md delete mode 100644 docs/documentation/features.md delete mode 100644 docs/documentation/getting-started.md delete mode 100644 docs/documentation/glossary.md delete mode 100644 docs/documentation/intro-operators.md delete mode 100644 docs/documentation/patterns-best-practices.md delete mode 100644 docs/documentation/use-samples.md delete mode 100644 docs/documentation/v2-migration.md delete mode 100644 docs/documentation/v3-1-migration.md delete mode 100644 docs/documentation/v3-migration.md delete mode 100644 docs/documentation/v4-3-migration.md delete mode 100644 docs/documentation/v4-4-migration.md delete mode 100644 docs/documentation/v4-5-migration.md delete mode 100644 docs/documentation/workflows.md delete mode 100644 docs/etc/v1_model.drawio.svg delete mode 100644 docs/etc/v2_model.drawio.svg delete mode 100644 docs/event-design.xml delete mode 100644 docs/index.html delete mode 100644 docs/readme.md delete mode 100644 docs/releases.html diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index d1c9ff6a5b..0000000000 --- a/docs/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.jekyll-cache/ -_site/ -.DS_Store -.sass-cache \ No newline at end of file diff --git a/docs/404.md b/docs/404.md deleted file mode 100644 index 3c3670a81b..0000000000 --- a/docs/404.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: 404 - page doesn't exist! -description: 404 - are you lost? -layout: default -permalink: /404.html ---- - -## Sorry, the page you were looking for could not be found. -{:.uk-section .uk-container .uk-text-center} - -### Return to our [home page]({{ "/" | relative_url }}), or [contact us](https://discord.gg/DacEhAy) if you can’t find what you are looking for. -{: .uk-container .uk-text-center} diff --git a/docs/CNAME b/docs/CNAME deleted file mode 100644 index 492c587214..0000000000 --- a/docs/CNAME +++ /dev/null @@ -1 +0,0 @@ -javaoperatorsdk.io \ No newline at end of file diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md deleted file mode 100644 index 3fe567f1e7..0000000000 --- a/docs/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,138 +0,0 @@ ---- -title: Contributor Covenant Code of Conduct -description: Code of Conduct -layout: default -permalink: /coc.html ---- - -All participants to the Java Operator SDK project are required to comply with -the following code of conduct, which is based on v2.0 of the [Contributor -Covenant](https://www.contributor-covenant.org/). - - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, religion, or sexual identity -and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the - overall community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or - advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email - address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to adam.sandor@container-solutions.com or any of the project admins. - -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series -of actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or -permanent ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within -the community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. - -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. diff --git a/docs/Gemfile b/docs/Gemfile deleted file mode 100644 index 2334a63fb9..0000000000 --- a/docs/Gemfile +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -source "https://rubygems.org/" - -git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } - -gem "jekyll", "~> 4.2" -gem "jekyll-github-metadata" \ No newline at end of file diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock deleted file mode 100644 index 605cd1d411..0000000000 --- a/docs/Gemfile.lock +++ /dev/null @@ -1,86 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) - colorator (1.1.0) - concurrent-ruby (1.1.9) - em-websocket (0.5.2) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0.6.0) - eventmachine (1.2.7) - faraday (1.3.0) - faraday-net_http (~> 1.0) - multipart-post (>= 1.2, < 3) - ruby2_keywords - faraday-net_http (1.0.1) - ffi (1.15.3) - forwardable-extended (2.6.0) - http_parser.rb (0.6.0) - i18n (1.8.10) - concurrent-ruby (~> 1.0) - jekyll (4.2.0) - addressable (~> 2.4) - colorator (~> 1.0) - em-websocket (~> 0.5) - i18n (~> 1.0) - jekyll-sass-converter (~> 2.0) - jekyll-watch (~> 2.0) - kramdown (~> 2.3) - kramdown-parser-gfm (~> 1.0) - liquid (~> 4.0) - mercenary (~> 0.4.0) - pathutil (~> 0.9) - rouge (~> 3.0) - safe_yaml (~> 1.0) - terminal-table (~> 2.0) - jekyll-github-metadata (2.13.0) - jekyll (>= 3.4, < 5.0) - octokit (~> 4.0, != 4.4.0) - jekyll-sass-converter (2.1.0) - sassc (> 2.0.1, < 3.0) - jekyll-watch (2.2.1) - listen (~> 3.0) - kramdown (2.3.1) - rexml - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - liquid (4.0.3) - listen (3.5.1) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - mercenary (0.4.0) - multipart-post (2.1.1) - octokit (4.20.0) - faraday (>= 0.9) - sawyer (~> 0.8.0, >= 0.5.3) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (4.0.6) - rb-fsevent (0.11.0) - rb-inotify (0.10.1) - ffi (~> 1.0) - rexml (3.2.5) - rouge (3.26.0) - ruby2_keywords (0.0.4) - safe_yaml (1.0.5) - sassc (2.4.0) - ffi (~> 1.9) - sawyer (0.8.2) - addressable (>= 2.3.5) - faraday (> 0.8, < 2.0) - terminal-table (2.0.0) - unicode-display_width (~> 1.1, >= 1.1.1) - unicode-display_width (1.7.0) - -PLATFORMS - ruby - universal-darwin-20 - x86_64-linux - -DEPENDENCIES - jekyll (~> 4.2) - jekyll-github-metadata - -BUNDLED WITH - 2.2.30 diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index a2b8fba679..0000000000 --- a/docs/_config.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- - -# Site settings -name: Java Operator SDK -title: Java Operator SDK -description: Build Kubernetes Operators in Java without hassle -logo: logo-white.svg -logo-icon: logo-icon.svg -permalink: /:title/ -date_format: "%b %-d, %Y" -images: /assets/images/ - - -# Rouge highlighter -markdown: kramdown -highlighter: rouge - -kramdown: - parse_block_html: true - permalink: /:title - syntax_highlighter_opts: - disable : true - -plugins: - - "jekyll-github-metadata" diff --git a/docs/_data/navbar.yml b/docs/_data/navbar.yml deleted file mode 100644 index 0827956a3b..0000000000 --- a/docs/_data/navbar.yml +++ /dev/null @@ -1,19 +0,0 @@ -# Navbar menu navigation links - - title: Home - url: / - - title: Docs - url: /docs/getting-started - - title: Code of Conduct - url: /coc - - title: Releases - url: /releases -# Navbar buttons or social icons - - title: Join Discord - url: https://discord.gg/DacEhAy - button: default - type: discord - - title: Contribute - url: https://github.com/operator-framework/java-operator-sdk - button: default - type: github - diff --git a/docs/_data/sidebar.yml b/docs/_data/sidebar.yml deleted file mode 100644 index 8c083a6cc1..0000000000 --- a/docs/_data/sidebar.yml +++ /dev/null @@ -1,35 +0,0 @@ - # Navbar menu navigation links - - title: Intro to Operators - url: /docs/intro-operators - - title: Getting Started - url: /docs/getting-started - - title: How to use Samples - url: /docs/using-samples - - title: Glossary - url: /docs/glossary - - title: Features - url: /docs/features - - title: Dependent Resources - url: /docs/dependent-resources - - title: Workflows - url: /docs/workflows - - title: Patterns and Best Practices - url: /docs/patterns-best-practices - - title: FAQ - url: /docs/faq - - title: Architecture and Internals - url: /docs/architecture-and-internals - - title: Contributing - url: /docs/contributing - - title: Migrating from v1 to v2 - url: /docs/v2-migration - - title: Migrating from v2 to v3 - url: /docs/v3-migration - - title: Migrating from v3 to v3.1 - url: /docs/v3-1-migration - - title: Migrating from v4.2 to v4.3 - url: /docs/v4-3-migration - - title: Migrating from v4.3 to v4.4 - url: /docs/v4-4-migration - - title: Migrating from v4.4 to v4.5 - url: /docs/v4-5-migration \ No newline at end of file diff --git a/docs/_includes/analytics.html b/docs/_includes/analytics.html deleted file mode 100644 index 40863e94bc..0000000000 --- a/docs/_includes/analytics.html +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/docs/_includes/anchor_headings.html b/docs/_includes/anchor_headings.html deleted file mode 100644 index f8e22d6a0f..0000000000 --- a/docs/_includes/anchor_headings.html +++ /dev/null @@ -1,172 +0,0 @@ -{% capture headingsWorkspace %} - {% comment %} - Copyright (c) 2018 Vladimir "allejo" Jimenez - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - {% endcomment %} - {% comment %} - Version 1.0.11 - https://github.com/allejo/jekyll-anchor-headings - - "Be the pull request you wish to see in the world." ~Ben Balter - - Usage: - {% include anchor_headings.html html=content anchorBody="#" %} - - Parameters: - * html (string) - the HTML of compiled markdown generated by kramdown in Jekyll - - Optional Parameters: - * beforeHeading (bool) : false - Set to true if the anchor should be placed _before_ the heading's content - * headerAttrs (string) : '' - Any custom HTML attributes that will be added to the heading tag; you may NOT use `id`; - the `%heading%` and `%html_id%` placeholders are available - * anchorAttrs (string) : '' - Any custom HTML attributes that will be added to the `` tag; you may NOT use `href`, `class` or `title`; - the `%heading%` and `%html_id%` placeholders are available - * anchorBody (string) : '' - The content that will be placed inside the anchor; the `%heading%` placeholder is available - * anchorClass (string) : '' - The class(es) that will be used for each anchor. Separate multiple classes with a space - * anchorTitle (string) : '' - The `title` attribute that will be used for anchors - * h_min (int) : 1 - The minimum header level to build an anchor for; any header lower than this value will be ignored - * h_max (int) : 6 - The maximum header level to build an anchor for; any header greater than this value will be ignored - * bodyPrefix (string) : '' - Anything that should be inserted inside of the heading tag _before_ its anchor and content - * bodySuffix (string) : '' - Anything that should be inserted inside of the heading tag _after_ its anchor and content - * generateId (true) : false - Set to true if a header without id should generate an id to use. - - Output: - The original HTML with the addition of anchors inside of all of the h1-h6 headings. - {% endcomment %} - - {% assign minHeader = include.h_min | default: 1 %} - {% assign maxHeader = include.h_max | default: 6 %} - {% assign beforeHeading = include.beforeHeading %} - {% assign headerAttrs = include.headerAttrs %} - {% assign nodes = include.html | split: ' - {% if headerLevel == 0 %} - - {% assign firstChunk = node | split: '>' | first %} - - - {% unless firstChunk contains '<' %} - {% capture node %}{% endcapture %} - {% assign _workspace = node | split: _closingTag %} - {% capture _hAttrToStrip %}{{ _workspace[0] | split: '>' | first }}>{% endcapture %} - {% assign header = _workspace[0] | replace: _hAttrToStrip, '' %} - {% assign escaped_header = header | strip_html | strip %} - - {% assign _classWorkspace = _workspace[0] | split: 'class="' %} - {% assign _classWorkspace = _classWorkspace[1] | split: '"' %} - {% assign _html_class = _classWorkspace[0] %} - - {% if _html_class contains "no_anchor" %} - {% assign skip_anchor = true %} - {% else %} - {% assign skip_anchor = false %} - {% endif %} - - {% assign _idWorkspace = _workspace[0] | split: 'id="' %} - {% if _idWorkspace[1] %} - {% assign _idWorkspace = _idWorkspace[1] | split: '"' %} - {% assign html_id = _idWorkspace[0] %} - {% elsif include.generateId %} - - {% assign html_id = escaped_header | slugify %} - {% if html_id == "" %} - {% assign html_id = false %} - {% endif %} - {% capture headerAttrs %}{{ headerAttrs }} id="%html_id%"{% endcapture %} - {% endif %} - - - {% capture anchor %}{% endcapture %} - - {% if skip_anchor == false and html_id and headerLevel >= minHeader and headerLevel <= maxHeader %} - {% if headerAttrs %} - {% capture _hAttrToStrip %}{{ _hAttrToStrip | split: '>' | first }} {{ headerAttrs | replace: '%heading%', escaped_header | replace: '%html_id%', html_id }}>{% endcapture %} - {% endif %} - - {% capture anchor %}href="#{{ html_id }}"{% endcapture %} - - {% if include.anchorClass %} - {% capture anchor %}{{ anchor }} class="{{ include.anchorClass }}"{% endcapture %} - {% endif %} - - {% if include.anchorTitle %} - {% capture anchor %}{{ anchor }} title="{{ include.anchorTitle | replace: '%heading%', escaped_header }}"{% endcapture %} - {% endif %} - - {% if include.anchorAttrs %} - {% capture anchor %}{{ anchor }} {{ include.anchorAttrs | replace: '%heading%', escaped_header | replace: '%html_id%', html_id }}{% endcapture %} - {% endif %} - - {% capture anchor %}{{ include.anchorBody | replace: '%heading%', escaped_header | default: '' }}{% endcapture %} - - - {% if beforeHeading %} - {% capture anchor %}{{ anchor }} {% endcapture %} - {% else %} - {% capture anchor %} {{ anchor }}{% endcapture %} - {% endif %} - {% endif %} - - {% capture new_heading %} - - {% endcapture %} - - - {% assign chunkCount = _workspace | size %} - {% if chunkCount > 1 %} - {% capture new_heading %}{{ new_heading }}{{ _workspace | last }}{% endcapture %} - {% endif %} - - {% capture edited_headings %}{{ edited_headings }}{{ new_heading }}{% endcapture %} - {% endfor %} -{% endcapture %}{% assign headingsWorkspace = '' %}{{ edited_headings | strip }} diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html deleted file mode 100644 index 34449face3..0000000000 --- a/docs/_includes/footer.html +++ /dev/null @@ -1,11 +0,0 @@ -

-
-
    - {% for link in site.data.navbar%} - {% include menuItems.html %} - {% endfor %} -
-

Released under the Apache License 2.0 -
Copyright © 2020 - {{ 'now' | date: "%Y" }} Container Solutions

-
-
diff --git a/docs/_includes/hero.html b/docs/_includes/hero.html deleted file mode 100644 index d0057b772c..0000000000 --- a/docs/_includes/hero.html +++ /dev/null @@ -1,20 +0,0 @@ -
-
- {% if site.logo %} - - {% endif %} -

[ {{ site.title }} ]

- -
-
- diff --git a/docs/_includes/heroDefault.html b/docs/_includes/heroDefault.html deleted file mode 100644 index d41d20d043..0000000000 --- a/docs/_includes/heroDefault.html +++ /dev/null @@ -1,5 +0,0 @@ -
-
-

[ {{ page.title }} ]

-
-
diff --git a/docs/_includes/links.html b/docs/_includes/links.html deleted file mode 100644 index 835fa7d2e4..0000000000 --- a/docs/_includes/links.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/docs/_includes/menuItems.html b/docs/_includes/menuItems.html deleted file mode 100644 index bc59ec3990..0000000000 --- a/docs/_includes/menuItems.html +++ /dev/null @@ -1,49 +0,0 @@ -{% assign domain = '' | relative_url %} -{% if link.url == page.url %} -{% assign current = ' class="uk-active"' %} -{% else %} -{% assign current = ' class=""' %} -{% endif %} -{% if link.title %} - -{% if link.url %} -{% if link.button %} - -{% else %} -{{ link.title }} -{% endif %} -{% else %} -{{ link.title }} -{% endif %} -{% if link.dropdown != null %} -
-
    - {% for item in link.dropdown %} - {% if item.url != null %} - {% assign domain = '' | relative_url %} - {% if item.url == page.url %} - {% assign current = ' class="uk-active"' %} - {% else %} - {% assign current = ' class=""' %} - {% endif %} - {{ item.title }} - {% else %} -
  • {{ item.title }}
  • - {% endif %} - {% endfor %} -
-
-{% endif %} - -{% endif %} - diff --git a/docs/_includes/navbar.html b/docs/_includes/navbar.html deleted file mode 100644 index 736396a4a6..0000000000 --- a/docs/_includes/navbar.html +++ /dev/null @@ -1,42 +0,0 @@ -
-
- -
-
-
    - {% for link in site.data.navbar %} - {% include menuItems.html %} - {% endfor %} -
    - {% for link in site.data.sidebar %} - {% include menuItems.html %} - {% endfor %} -
-
-
-
-
- diff --git a/docs/_includes/scripts.html b/docs/_includes/scripts.html deleted file mode 100644 index f3ca7b56a5..0000000000 --- a/docs/_includes/scripts.html +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/docs/_includes/sidebar.html b/docs/_includes/sidebar.html deleted file mode 100644 index 1700a6f0b3..0000000000 --- a/docs/_includes/sidebar.html +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html deleted file mode 100644 index 0aa2dda932..0000000000 --- a/docs/_layouts/default.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - {% if page.title %}{{ page.title }}{% else %}{{ site.title | escape }}{% endif %} - {% include links.html %} - {% include analytics.html %} - - -{% include navbar.html %} -{% include heroDefault.html %} -
-
- {{ content }} -
-
-{% include footer.html %} -{% include scripts.html %} - - diff --git a/docs/_layouts/docs.html b/docs/_layouts/docs.html deleted file mode 100644 index 16db62e0c0..0000000000 --- a/docs/_layouts/docs.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - {% if page.title %}{{ page.title }}{% else %}{{ site.title | escape }}{% endif %} - {% include links.html %} - {% include analytics.html %} - - - - {% include navbar.html %} - -
-
-
- -
-
- {% include anchor_headings.html html=content anchorBody="#" %} -
- -
-
-
-
- {% include scripts.html %} - - diff --git a/docs/_layouts/homepage.html b/docs/_layouts/homepage.html deleted file mode 100644 index 2804029ac3..0000000000 --- a/docs/_layouts/homepage.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - {% if page.title %}{{ page.title }}{% else %}{{ site.title | escape }}{% endif %} - {% include links.html %} - {% include analytics.html %} - - - {% include navbar.html %} - {% include hero.html %} -
- {{ content }} -
- {% include footer.html %} - {% include scripts.html %} - - diff --git a/docs/_sass/theme/mixins.scss b/docs/_sass/theme/mixins.scss deleted file mode 100644 index 35030aa78d..0000000000 --- a/docs/_sass/theme/mixins.scss +++ /dev/null @@ -1,13 +0,0 @@ -// Mixins -// ======================================================================== - -.uk-offcanvas-bar .uk-navbar-item { - min-height: 50px; - justify-content: flex-start; -} -.full-page{ - min-height: calc(100vh - 518px) -} - - - diff --git a/docs/_sass/theme/uikit.scss b/docs/_sass/theme/uikit.scss deleted file mode 100644 index 25d543ef2f..0000000000 --- a/docs/_sass/theme/uikit.scss +++ /dev/null @@ -1,100 +0,0 @@ -// Import UIkit components - -// The commented out imports are elements that can be used but they are not necessary at the moment -// They are left in to make it easier to see what needs to be imported when creating new page elements -// for example: you want to create a form so you uncomment @import "https://github.com/uikit/components/form.scss" for the styles to apply; - -// Base -@import "https://github.com/uikit/components/variables.scss"; -@import "https://github.com/uikit/components/mixin.scss"; -@import "https://github.com/uikit/components/base.scss"; - -// Elements -@import "https://github.com/uikit/components/link.scss"; -@import "https://github.com/uikit/components/heading.scss"; -@import "https://github.com/uikit/components/divider.scss"; -@import "https://github.com/uikit/components/list.scss"; -@import "https://github.com/uikit/components/description-list.scss"; -@import "https://github.com/uikit/components/icon.scss"; -@import "https://github.com/uikit/components/button.scss"; -//@import "https://github.com/uikit/components/progress.scss"; -//@import "https://github.com/uikit/components/table.scss"; -//@import "https://github.com/uikit/components/form-range.scss"; -//@import "https://github.com/uikit/components/form.scss"; - -// Layout -@import "https://github.com/uikit/components/section.scss"; -@import "https://github.com/uikit/components/container.scss"; -@import "https://github.com/uikit/components/tile.scss"; -@import "https://github.com/uikit/components/card.scss"; - -// Common -@import "https://github.com/uikit/components/article.scss"; -//@import "https://github.com/uikit/components/close.scss"; -//@import "https://github.com/uikit/components/spinner.scss"; -//@import "https://github.com/uikit/components/totop.scss"; -//@import "https://github.com/uikit/components/marker.scss"; -//@import "https://github.com/uikit/components/alert.scss"; -//@import "https://github.com/uikit/components/placeholder.scss"; -//@import "https://github.com/uikit/components/badge.scss"; -//@import "https://github.com/uikit/components/label.scss"; -//@import "https://github.com/uikit/components/overlay.scss"; -//@import "https://github.com/uikit/components/comment.scss"; -//@import "https://github.com/uikit/components/search.scss"; - -// JavaScript -@import "https://github.com/uikit/components/modal.scss"; -@import "https://github.com/uikit/components/sticky.scss"; -@import "https://github.com/uikit/components/offcanvas.scss"; -@import "https://github.com/uikit/components/leader.scss"; -//@import "https://github.com/uikit/components/accordion.scss"; -//@import "https://github.com/uikit/components/drop.scss"; -//@import "https://github.com/uikit/components/dropdown.scss"; -//@import "https://github.com/uikit/components/slideshow.scss"; -//@import "https://github.com/uikit/components/slider.scss"; -//@import "https://github.com/uikit/components/switcher.scss"; -//@import "https://github.com/uikit/components/notification.scss"; -//@import "https://github.com/uikit/components/tooltip.scss"; -//@import "https://github.com/uikit/components/sortable.scss"; -//@import "https://github.com/uikit/components/countdown.scss"; -// Scrollspy -// Toggle -// Scroll - -@import "https://github.com/uikit/components/grid.scss"; - -// Navs -@import "https://github.com/uikit/components/nav.scss"; -@import "https://github.com/uikit/components/navbar.scss"; -@import "https://github.com/uikit/components/subnav.scss"; -//@import "https://github.com/uikit/components/breadcrumb.scss"; -//@import "https://github.com/uikit/components/pagination.scss"; -//@import "https://github.com/uikit/components/tab.scss"; -//@import "https://github.com/uikit/components/slidenav.scss"; -//@import "https://github.com/uikit/components/dotnav.scss"; -//@import "https://github.com/uikit/components/thumbnav.scss"; -//@import "https://github.com/uikit/components/iconnav.scss"; - -//@import "https://github.com/uikit/components/lightbox.scss"; - -// Utilities - -@import "https://github.com/uikit/components/width.scss"; -@import "https://github.com/uikit/components/height.scss"; -@import "https://github.com/uikit/components/text.scss"; -@import "https://github.com/uikit/components/background.scss"; -@import "https://github.com/uikit/components/align.scss"; -@import "https://github.com/uikit/components/svg.scss"; -@import "https://github.com/uikit/components/utility.scss"; -@import "https://github.com/uikit/components/flex.scss"; -@import "https://github.com/uikit/components/margin.scss"; -@import "https://github.com/uikit/components/padding.scss"; -@import "https://github.com/uikit/components/position.scss"; -@import "https://github.com/uikit/components/visibility.scss"; -//@import "https://github.com/uikit/components/transition.scss"; -//@import "https://github.com/uikit/components/column.scss"; -//@import "https://github.com/uikit/components/cover.scss"; -//@import "https://github.com/uikit/components/animation.scss"; -//@import "https://github.com/uikit/components/inverse.scss"; - -//@import "https://github.com/uikit/components/print.scss"; \ No newline at end of file diff --git a/docs/_sass/theme/variables.scss b/docs/_sass/theme/variables.scss deleted file mode 100644 index a33b84d199..0000000000 --- a/docs/_sass/theme/variables.scss +++ /dev/null @@ -1,138 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600&display=swap'); -@import url('https://fonts.googleapis.com/css2?family=Asap:wght@700&display=swap'); - -// Global variables -$global-primary-background: #fc9c62; -$global-secondary-background: darken($global-primary-background, 60%); -$global-success-background: #32d296; -$global-muted-background: #FEF6EB; -$global-warning-background: #faa05a; -$global-danger-background: #cc2b48; -$global-font-family: 'Open sans', san-serif; -$global-link-color: darken($global-primary-background, 25%); -$global-link-hover-color: darken($global-primary-background, 30%); -$global-small-font-size: 0.875rem; -$global-muted-color: #ffffff; - -$global-xxlarge-font-size: 2.75rem; -$global-xlarge-font-size: 2rem; -$global-large-font-size: 1.5rem; -$global-medium-font-size: 1.25rem; -$xsmall-font-size: 0.875rem; - -// Base variables -$base-body-font-family: 'Open sans', san-serif; -$base-body-font-size: 1rem; -$base-body-font-weight: 400; -$base-body-line-height: 1.7; -$base-heading-font-family: 'Open sans', san-serif; -$base-heading-font-weight: 600; -$base-heading-color: $global-secondary-background; -$base-h1-line-height: 1.5; -$base-h2-line-height: 1.5; -$base-link-hover-text-decoration: none; -$base-body-color: $global-secondary-background; -$base-code-font-family: 'Open sans', san-serif; -$base-code-color: $global-secondary-background; -$base-code-font-size: $xsmall-font-size; -$base-pre-font-size: $xsmall-font-size; -$base-pre-line-height: 1.65; -$base-pre-font-family: $base-code-font-family; -$base-pre-color: $base-code-color; -$border-light: $global-muted-color; -$border-rounded-border-radius: 2px; -$text-lead-font-size: 1.125rem; -$link-muted-hover-color: $global-secondary-background; -$link-text-hover-color: #9e9aaa; -$overlay-primary-background: rgba(34,34,34,0.8); -$logo-font-family: 'Asap', sans-serif; - -// Accordion variables -$accordion-item-margin-top: 20px; -$accordion-title-font-size: 1.1875rem; -$accordion-title-color: $global-link-color; -$accordion-title-hover-color: $global-link-color; -$accordion-content-margin-top: 20px; -$accordion-icon-color: $global-primary-background; -$accordion-icon-background-color: lighten( $global-primary-background, 57% ); -$internal-accordion-open-image: "data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline fill='none' stroke='$global-secondary-background' stroke-width='1.03' points='4 13 10 7 16 13' /%3E%3C/svg%3E"; -$internal-accordion-close-image: "data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolyline fill='none' stroke='$global-secondary-background' stroke-width='1.03' points='16 7 10 13 4 7' /%3E%3C/svg%3E"; - -// Article variables -$article-title-font-size-m: 2.625rem; -$article-title-line-height: 1.4; -$article-meta-font-size: 0.8125rem; -$article-meta-line-height: 1.6; - -// Button variables -$button-font-weight: 400; -$button-default-color: $global-secondary-background; -$button-default-hover-background: $button-default-color; -$button-default-hover-color: $global-muted-background; -$button-default-active-background: $button-default-color; -$button-default-active-color: $global-muted-background; -$button-default-border: $button-default-color; -$button-default-hover-border: $button-default-color; -$button-default-active-border: $button-default-color; -$button-warning-background: $global-warning-background; -$button-warning-hover-background: darken($button-warning-background, 7%); -$button-success-background: $global-success-background; -$button-success-hover-background: darken($button-success-background, 5%); -$inverse-button-primary-color: $global-secondary-background; -$inverse-button-primary-hover-color: $global-secondary-background; - -// Card variables -$card-small-body-padding-horizontal: 25px; -$card-small-body-padding-vertical: 25px; -$card-title-font-size: 1.25rem; -$card-default-title-color: $base-heading-color; -$card-default-color: $base-body-color; - -// Heading variables -$heading-large-font-size-l: 5rem; -$heading-divider-border-width: 1px; -$heading-divider-border: #d0d5de; - -// Logo variables -$logo-font-size: 1.35rem; -$logo-color: $global-secondary-background; -$logo-hover-color: $global-secondary-background; -$inverse-logo-color: $global-muted-color; -$inverse-logo-hover-color: $global-muted-color; - -// Navigation variables -$nav-primary-item-font-size: $global-large-font-size; -$navbar-background: $global-primary-background; -$navbar-nav-item-height: 60px; -$navbar-nav-item-color: $global-muted-color; -$navbar-nav-item-active-color: $global-secondary-background; -$navbar-nav-item-hover-color: lighten($global-secondary-background, 20%); -$navbar-nav-item-font-size: 0.8rem; -$navbar-nav-item-text-transform: uppercase; -$navbar-toggle-color: lighten($global-secondary-background, 30%); -$navbar-toggle-hover-color: $global-secondary-background; -$navbar-dropdown-nav-item-color: $base-body-color; -$offcanvas-bar-color-mode: dark; -$offcanvas-bar-background: $global-muted-color; -$subnav-item-font-size: $global-small-font-size; -$subnav-item-text-transform: uppercase; -$subnav-item-active-color: lighten($global-secondary-background, 30%); -$subnav-item-hover-color: lighten($global-secondary-background, 20%); -$link-muted-hover-color : lighten($global-secondary-background, 20%); - -// Search variables -$search-default-background: $global-muted-color; -$search-default-focus-background: $global-muted-color; -$inverse-search-default-background: rgba(0, 0, 0, 0.3); -$inverse-search-default-focus-background: rgba(0, 0, 0, 0.5); - -// Section variables -$section-success-background: $global-success-background; -$section-success-color-mode: light; -$section-danger-background: $global-danger-background; -$section-danger-color-mode: light; -$section-large-padding-vertical-m: 120px; - -// Sidebar variables -$sidebar-width: 200px; -$sidebar-width-l: 300px; \ No newline at end of file diff --git a/docs/_sass/uikit/components/_buttons.scss b/docs/_sass/uikit/components/_buttons.scss deleted file mode 100644 index 00a4800604..0000000000 --- a/docs/_sass/uikit/components/_buttons.scss +++ /dev/null @@ -1,33 +0,0 @@ -.button { - background-color: #2841f9; - border: 0; - border-radius: 0; - display: inline-block; - height: 30px; - line-height: inherit; - margin-left: 5px; - margin-right: 15px; - padding: 0px; - white-space: nowrap; - width: 30px; -} - -.button-text, -input[type=submit] { - background-color: #000; - border: 0; - border-radius: 20px; - box-shadow: 0; - color: #fff !important; - display: inline-block; - font-size: 20px; - line-height: 30px; - margin: 10px 0px; - padding: 10px 30px; - - &:hover { - color: #fff; - text-decoration: none; - } -} - diff --git a/docs/_sass/uikit/components/_content.scss b/docs/_sass/uikit/components/_content.scss deleted file mode 100644 index f7be03c6cc..0000000000 --- a/docs/_sass/uikit/components/_content.scss +++ /dev/null @@ -1,120 +0,0 @@ -.content { - align-items: center; - font-size: 22px; - line-height: 30px; - justify-content: space-between; - margin-left: auto; - margin-right: auto; - max-width: 940px; - padding: 80px 0px; - - h1 { - font-size: 32px; - font-weight: bold; - line-height: 36px; - margin: 20px 0px 30px; - text-transform: uppercase; - } - - table { - width: 100%; - - td { - float: none; - width: 50%; - - a { - color: #000; - margin: 20px; - vertical-align: middle; - - &:hover { - color: #000; - text-decoration: none; - } - } - } - - @media all and (max-width: 700px) { - td { - float: left; - width: 100%; - } - } - } - - ul.plusminus { - list-style-type: none; - margin: 0; - padding: 0; - - li.minus { - padding: 0px 0px 0px 40px; - position: relative; - - &:before { - content: "-"; - font-weight: 800; - left: 16px; - position: absolute; - } - } - - li.plus { - padding: 0px 0px 0px 40px; - position: relative; - - &:before { - content: "+"; - font-weight: 800; - left: 16px; - position: absolute; - } - } - } -} - -.book-section { - background-color: #000; - background-image: url("#{$baseurl}/assets/images/pattern%20white_1.png"); - background-size: cover; - color: #fff; - font-weight: 600; - - a { - color: #fff; - text-decoration: underline; - - &:hover { - color: #fff; - } - } - - div { - background-color: transparent; - background-image: none; - } -} - -.cta-section { - text-align: center; - - strong { - text-transform: uppercase; - } -} - -.patterns-section { - a { - color: #000; - font-size: 32px; - font-weight: 600; - line-height: 36px; - margin: 30px 0px 0px; - - &:hover { - color: #000; - text-decoration: none; - } - } -} diff --git a/docs/_sass/uikit/components/_footer.scss b/docs/_sass/uikit/components/_footer.scss deleted file mode 100644 index 93216c2f02..0000000000 --- a/docs/_sass/uikit/components/_footer.scss +++ /dev/null @@ -1,49 +0,0 @@ -.footer-strip { - background-image: url("#{$baseurl}/assets/images/bg.png"); - background-size: cover; - color: #fff; - font-weight: 700; - font-size: 15px; -} - -.footer-menu { - align-items: center; - display: block; - flex-direction: row; - justify-content: space-between; - margin-left: auto; - margin-right: auto; - max-width: 940px; - - ul { - list-style: none; - margin: 0; - padding: 0; - text-align: center; - - li { - display: inline-block; - padding: 20px; - - a { - color: #ffffff; - text-decoration: none; - } - } - } -} - -.footer-title { - align-items: center; - display: block; - flex-direction: row; - justify-content: space-between; - margin-left: auto; - margin-right: auto; - max-width: 940px; - text-align: right; - - img { - height: 40px - } -} diff --git a/docs/_sass/uikit/components/_header.scss b/docs/_sass/uikit/components/_header.scss deleted file mode 100644 index 59cd4c60e1..0000000000 --- a/docs/_sass/uikit/components/_header.scss +++ /dev/null @@ -1,19 +0,0 @@ -.header-strip { - background-color: #fff; - color: #000; - font-weight: 800; - position: sticky; - top: 0px; - width: 100%; - z-index: 9999999; -} - -.header { - margin-left: auto; - margin-right: auto; - max-width: 940px; - - img { - height: 40px - } -} diff --git a/docs/_sass/uikit/components/_import.components.scss b/docs/_sass/uikit/components/_import.components.scss deleted file mode 100644 index c24ec00469..0000000000 --- a/docs/_sass/uikit/components/_import.components.scss +++ /dev/null @@ -1,56 +0,0 @@ -// Base -@import "https://github.com/variables"; -@import "https://github.com/mixin"; -@import "https://github.com/base"; - -// Elements -@import "https://github.com/link"; -@import "https://github.com/heading"; -@import "https://github.com/divider"; -@import "https://github.com/list"; -@import "https://github.com/description-list"; -@import "https://github.com/table"; -@import "https://github.com/icon"; -@import "https://github.com/form"; // After: Icon -@import "https://github.com/button"; - -// Layout -@import "https://github.com/section"; -@import "https://github.com/container"; -@import "https://github.com/grid"; -@import "https://github.com/tile"; -@import "https://github.com/card"; - -// Common -@import "https://github.com/close"; // After: Icon -@import "https://github.com/spinner"; // After: Icon -@import "https://github.com/totop"; // After: Icon -@import "https://github.com/alert"; // After: Close -@import "https://github.com/badge"; -@import "https://github.com/label"; -@import "https://github.com/overlay"; // After: Icon -@import "https://github.com/article"; // After: Subnav -@import "https://github.com/comment"; // After: Subnav -@import "https://github.com/search"; // After: Icon - -// Navs -@import "https://github.com/nav"; -@import "https://github.com/navbar"; // After: Card, Grid, Nav, Icon, Search -@import "https://github.com/subnav"; -@import "https://github.com/breadcrumb"; -@import "https://github.com/pagination"; -@import "https://github.com/tab"; -@import "https://github.com/slidenav"; // After: Icon -@import "https://github.com/dotnav"; - -// JavaScript -@import "https://github.com/accordion"; -@import "https://github.com/drop"; // After: Card -@import "https://github.com/dropdown"; // After: Card -@import "https://github.com/modal"; // After: Close -@import "https://github.com/sticky"; -@import "https://github.com/offcanvas"; -@import "https://github.com/switcher"; -// Scrollspy -// Toggle -// Scroll diff --git a/docs/_sass/uikit/components/_import.scss b/docs/_sass/uikit/components/_import.scss deleted file mode 100644 index fe35f261cf..0000000000 --- a/docs/_sass/uikit/components/_import.scss +++ /dev/null @@ -1,94 +0,0 @@ -// Base -@import "https://github.com/variables"; -@import "https://github.com/mixin"; -@import "https://github.com/base"; - -// Elements -@import "https://github.com/link"; -@import "https://github.com/heading"; -@import "https://github.com/divider"; -@import "https://github.com/list"; -@import "https://github.com/description-list"; -@import "https://github.com/table"; -@import "https://github.com/icon"; -@import "https://github.com/form-range"; -@import "https://github.com/form"; // After: Icon, Form Range -@import "https://github.com/button"; -@import "https://github.com/progress"; - -// Layout -@import "https://github.com/section"; -@import "https://github.com/container"; -@import "https://github.com/tile"; -@import "https://github.com/card"; - -// Common -@import "https://github.com/close"; // After: Icon -@import "https://github.com/spinner"; // After: Icon -@import "https://github.com/totop"; // After: Icon -@import "https://github.com/marker"; // After: Icon -@import "https://github.com/alert"; // After: Close -@import "https://github.com/placeholder"; -@import "https://github.com/badge"; -@import "https://github.com/label"; -@import "https://github.com/overlay"; // After: Icon -@import "https://github.com/article"; -@import "https://github.com/comment"; -@import "https://github.com/search"; // After: Icon - -// JavaScript -@import "https://github.com/accordion"; -@import "https://github.com/drop"; // After: Card -@import "https://github.com/dropdown"; // After: Card -@import "https://github.com/modal"; // After: Close -@import "https://github.com/slideshow"; -@import "https://github.com/slider"; -@import "https://github.com/sticky"; -@import "https://github.com/offcanvas"; -@import "https://github.com/switcher"; -@import "https://github.com/leader"; -@import "https://github.com/notification"; -@import "https://github.com/tooltip"; -@import "https://github.com/sortable"; -@import "https://github.com/countdown"; -// Scrollspy -// Toggle -// Scroll - -@import "https://github.com/grid"; - -// Navs -@import "https://github.com/nav"; -@import "https://github.com/navbar"; // After: Card, Grid, Nav, Icon, Search -@import "https://github.com/subnav"; -@import "https://github.com/breadcrumb"; -@import "https://github.com/pagination"; -@import "https://github.com/tab"; -@import "https://github.com/slidenav"; // After: Icon -@import "https://github.com/dotnav"; -@import "https://github.com/thumbnav"; -@import "https://github.com/iconnav"; - -@import "https://github.com/lightbox"; // After: Close, Slidenav - -// Utilities -@import "https://github.com/animation"; -@import "https://github.com/width"; -@import "https://github.com/height"; -@import "https://github.com/text"; -@import "https://github.com/column"; -@import "https://github.com/cover"; -@import "https://github.com/background"; -@import "https://github.com/align"; -@import "https://github.com/svg"; -@import "https://github.com/utility"; -@import "https://github.com/flex"; // After: Utility -@import "https://github.com/margin"; -@import "https://github.com/padding"; -@import "https://github.com/position"; -@import "https://github.com/transition"; -@import "https://github.com/visibility"; -@import "https://github.com/inverse"; - -// Need to be loaded last -@import "https://github.com/print"; diff --git a/docs/_sass/uikit/components/_import.utilities.scss b/docs/_sass/uikit/components/_import.utilities.scss deleted file mode 100644 index 53712a56e7..0000000000 --- a/docs/_sass/uikit/components/_import.utilities.scss +++ /dev/null @@ -1,19 +0,0 @@ -// Utilities -@import "https://github.com/animation"; -@import "https://github.com/width"; -@import "https://github.com/text"; -@import "https://github.com/column"; -@import "https://github.com/cover"; -@import "https://github.com/background"; -@import "https://github.com/align"; -@import "https://github.com/utility"; -@import "https://github.com/flex"; // After: Utility -@import "https://github.com/margin"; -@import "https://github.com/padding"; -@import "https://github.com/position"; -@import "https://github.com/transition"; -@import "https://github.com/visibility"; -@import "https://github.com/inverse"; - -// Need to be loaded last -@import "https://github.com/print"; diff --git a/docs/_sass/uikit/components/_logo.scss b/docs/_sass/uikit/components/_logo.scss deleted file mode 100644 index 90875da1bc..0000000000 --- a/docs/_sass/uikit/components/_logo.scss +++ /dev/null @@ -1,8 +0,0 @@ -.logo { - font-size: 20px; - - a { - color: inherit; - text-decoration: none; - } -} diff --git a/docs/_sass/uikit/components/_main-menu.scss b/docs/_sass/uikit/components/_main-menu.scss deleted file mode 100644 index 457b9bbd0a..0000000000 --- a/docs/_sass/uikit/components/_main-menu.scss +++ /dev/null @@ -1,32 +0,0 @@ -.main-menu { - justify-content: flex-end; - - a { - color: inherit; - margin: 10px 20px; - text-decoration: none; - } - - button { - background-color: inherit; - border: none; - color: inherit; - margin: 0 20px 0 0; - } -} - -.dropdown-menu { - background-color: #fff; - color: #000; -} - -.dropdown-item { - font-size: 14px; - font-weight: 800; - padding: 10px 20px; - - &:hover { - background-color: inherit; - color: inherit; - } -} diff --git a/docs/_sass/uikit/components/_navigation-bar.scss b/docs/_sass/uikit/components/_navigation-bar.scss deleted file mode 100644 index 3cf2bdd76a..0000000000 --- a/docs/_sass/uikit/components/_navigation-bar.scss +++ /dev/null @@ -1,91 +0,0 @@ -.header { - border-bottom: 1px solid #E2E8F0; -} -.navbar { - display: flex; - justify-content: space-between; - align-items: center; - padding: 1rem 1.5rem; -} -#hamburger { - margin-bottom: 0; - display: none; -} -.bar { - display: block; - width: 25px; - height: 3px; - margin: 5px auto; - -webkit-transition: all 0.3s ease-in-out; - transition: all 0.3s ease-in-out; - background-color: #101010; -} -ul#nav-menu{ - list-style: none; - display: flex; - align-content: center; - justify-content: space-evenly; - margin-bottom:0; - li{ - padding: 1rem; - margin-bottom: 0; - a{ - text-decoration: none; - } - } - -} -#nav-item { - margin-left: 5rem; -} -.nav-link { - font-size: 1.6rem; - font-weight: 400; - color: #475569; - &:hover { - color: #482ff7; - } -} -.nav-logo { - font-size: 2.1rem; - font-weight: 500; - color: #482ff7; - padding: 1rem; -} -@media only screen and (max-width: 768px) { - #nav-menu { - position: fixed; - left: -100%; - top: 5rem; - flex-direction: column; - background-color: #fff; - width: 100%; - border-radius: 10px; - text-align: center; - transition: 0.3s; - box-shadow: 0 10px 27px rgba(0, 0, 0, 0.05); - } - #nav-menu.active { - left: 0; - } - #nav-item { - margin: 2.5rem 0; - } - #hamburger { - display: block; - cursor: pointer; - } - #hamburger.active { - .bar { - &:nth-child(2) { - opacity: 0; - } - &:nth-child(1) { - transform: translateY(8px) rotate(45deg); - } - &:nth-child(3) { - transform: translateY(-8px) rotate(-45deg); - } - } - } -} diff --git a/docs/_sass/uikit/components/_page.scss b/docs/_sass/uikit/components/_page.scss deleted file mode 100644 index 7559ad4178..0000000000 --- a/docs/_sass/uikit/components/_page.scss +++ /dev/null @@ -1,9 +0,0 @@ -.page { - background-color: #fff; - color: #333; - font-family: Open-sans, sans-serif; - font-size: 14px; - line-height: 20px; - margin: 0; - min-height: 100%; -} diff --git a/docs/_sass/uikit/components/_theme.scss b/docs/_sass/uikit/components/_theme.scss deleted file mode 100644 index f5a07ccc18..0000000000 --- a/docs/_sass/uikit/components/_theme.scss +++ /dev/null @@ -1,25 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600&display=swap'); - -/* colors */ -$primary: #e78a5fff; -$secondary: #b75065ff; -$info: #898ea3ff; -$dark: #433a51ff; -$light: #f5f5f5ff; /* applied fonts */ - - -html body { - font-family: 'Open Sans', sans-serif; - line-height: 1.5; - background-color: $primary; - -} - -/* sections spacing and colors */ -.section { - padding: 3rem 2rem; -} - -.dark-section { - background-color: $dark; -} \ No newline at end of file diff --git a/docs/_sass/uikit/components/_title.scss b/docs/_sass/uikit/components/_title.scss deleted file mode 100644 index 556a2526d2..0000000000 --- a/docs/_sass/uikit/components/_title.scss +++ /dev/null @@ -1,26 +0,0 @@ -.title-strip { - background-image: url("#{$baseurl}/assets/images/bg.png"); - background-size: cover; - color: #fff; - font-size: 25px; - font-weight: 500; - line-height: 30px; -} - -.title { - align-items: center; - justify-content: space-between; - max-width: 940px; - margin-left: auto; - margin-right: auto; - - h1 { - font-size: 60px; - font-weight: bold; - text-transform: uppercase; - max-height: 300px; - } - h3 { - line-height: 50px; - } -} diff --git a/docs/_sass/uikit/components/accordion.scss b/docs/_sass/uikit/components/accordion.scss deleted file mode 100644 index 477675469e..0000000000 --- a/docs/_sass/uikit/components/accordion.scss +++ /dev/null @@ -1,107 +0,0 @@ -// Name: Accordion -// Description: Component to create accordions -// -// Component: `uk-accordion` -// -// Sub-objects: `uk-accordion-title` -// `uk-accordion-content` -// -// States: `uk-open` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$accordion-item-margin-top: $global-margin !default; - -$accordion-title-font-size: $global-medium-font-size !default; -$accordion-title-line-height: 1.4 !default; -$accordion-title-color: $global-emphasis-color !default; -$accordion-title-hover-color: $global-color !default; - -$accordion-content-margin-top: $global-margin !default; - - -/* ======================================================================== - Component: Accordion - ========================================================================== */ - -.uk-accordion { - padding: 0; - list-style: none; - @if(mixin-exists(hook-accordion)) {@include hook-accordion();} -} - - -/* Item - ========================================================================== */ - -.uk-accordion > :nth-child(n+2) { - margin-top: $accordion-item-margin-top; - @if(mixin-exists(hook-accordion-item)) {@include hook-accordion-item();} -} - - -/* Title - ========================================================================== */ - -.uk-accordion-title { - display: block; - font-size: $accordion-title-font-size; - line-height: $accordion-title-line-height; - color: $accordion-title-color; - @if(mixin-exists(hook-accordion-title)) {@include hook-accordion-title();} -} - -/* Hover + Focus */ -.uk-accordion-title:hover, -.uk-accordion-title:focus { - color: $accordion-title-hover-color; - text-decoration: none; - outline: none; - @if(mixin-exists(hook-accordion-title-hover)) {@include hook-accordion-title-hover();} -} - - -/* Content - ========================================================================== */ - -.uk-accordion-content { - display: flow-root; - margin-top: $accordion-content-margin-top; - @if(mixin-exists(hook-accordion-content)) {@include hook-accordion-content();} -} - -/* - * Remove margin from the last-child - */ - - .uk-accordion-content > :last-child { margin-bottom: 0; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-accordion-misc)) {@include hook-accordion-misc();} - -// @mixin hook-accordion(){} -// @mixin hook-accordion-item(){} -// @mixin hook-accordion-title(){} -// @mixin hook-accordion-title-hover(){} -// @mixin hook-accordion-content(){} -// @mixin hook-accordion-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-accordion-title-color: $inverse-global-emphasis-color !default; -$inverse-accordion-title-hover-color: $inverse-global-color !default; - - - -// @mixin hook-inverse-accordion-item(){} -// @mixin hook-inverse-accordion-title(){} -// @mixin hook-inverse-accordion-title-hover(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/alert.scss b/docs/_sass/uikit/components/alert.scss deleted file mode 100644 index 236cc6787e..0000000000 --- a/docs/_sass/uikit/components/alert.scss +++ /dev/null @@ -1,147 +0,0 @@ -// Name: Alert -// Description: Component to create alert messages -// -// Component: `uk-alert` -// -// Adopted: `uk-alert-close` -// -// Modifiers: `uk-alert-primary` -// `uk-alert-success` -// `uk-alert-warning` -// `uk-alert-danger` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$alert-margin-vertical: $global-margin !default; -$alert-padding: 15px !default; -$alert-padding-right: $alert-padding + 14px !default; -$alert-background: $global-muted-background !default; -$alert-color: $global-color !default; - -$alert-close-top: $alert-padding + 5px !default; -$alert-close-right: $alert-padding !default; - -$alert-primary-background: lighten(mix(white, $global-primary-background, 40%), 20%) !default; -$alert-primary-color: $global-primary-background !default; - -$alert-success-background: lighten(mix(white, $global-success-background, 40%), 25%) !default; -$alert-success-color: $global-success-background !default; - -$alert-warning-background: lighten(mix(white, $global-warning-background, 45%), 15%) !default; -$alert-warning-color: $global-warning-background !default; - -$alert-danger-background: lighten(mix(white, $global-danger-background, 40%), 20%) !default; -$alert-danger-color: $global-danger-background !default; - - -/* ======================================================================== - Component: Alert - ========================================================================== */ - -.uk-alert { - position: relative; - margin-bottom: $alert-margin-vertical; - padding: $alert-padding $alert-padding-right $alert-padding $alert-padding; - background: $alert-background; - color: $alert-color; - @if(mixin-exists(hook-alert)) {@include hook-alert();} -} - -/* Add margin if adjacent element */ -* + .uk-alert { margin-top: $alert-margin-vertical; } - -/* - * Remove margin from the last-child - */ - -.uk-alert > :last-child { margin-bottom: 0; } - - -/* Close - * Adopts `uk-close` - ========================================================================== */ - -.uk-alert-close { - position: absolute; - top: $alert-close-top; - right: $alert-close-right; - @if(mixin-exists(hook-alert-close)) {@include hook-alert-close();} -} - -/* - * Remove margin from adjacent element - */ - -.uk-alert-close:first-child + * { margin-top: 0; } - -/* - * Hover + Focus - */ - -.uk-alert-close:hover, -.uk-alert-close:focus { - @if(mixin-exists(hook-alert-close-hover)) {@include hook-alert-close-hover();} -} - - -/* Style modifiers - ========================================================================== */ - -/* - * Primary - */ - -.uk-alert-primary { - background: $alert-primary-background; - color: $alert-primary-color; - @if(mixin-exists(hook-alert-primary)) {@include hook-alert-primary();} -} - -/* - * Success - */ - -.uk-alert-success { - background: $alert-success-background; - color: $alert-success-color; - @if(mixin-exists(hook-alert-success)) {@include hook-alert-success();} -} - -/* - * Warning - */ - -.uk-alert-warning { - background: $alert-warning-background; - color: $alert-warning-color; - @if(mixin-exists(hook-alert-warning)) {@include hook-alert-warning();} -} - -/* - * Danger - */ - -.uk-alert-danger { - background: $alert-danger-background; - color: $alert-danger-color; - @if(mixin-exists(hook-alert-danger)) {@include hook-alert-danger();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-alert-misc)) {@include hook-alert-misc();} - -// @mixin hook-alert(){} -// @mixin hook-alert-close(){} -// @mixin hook-alert-close-hover(){} -// @mixin hook-alert-primary(){} -// @mixin hook-alert-success(){} -// @mixin hook-alert-warning(){} -// @mixin hook-alert-danger(){} -// @mixin hook-alert-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/align.scss b/docs/_sass/uikit/components/align.scss deleted file mode 100644 index bee6702bca..0000000000 --- a/docs/_sass/uikit/components/align.scss +++ /dev/null @@ -1,142 +0,0 @@ -// Name: Align -// Description: Utilities to align embedded content -// -// Component: `uk-align-left-*` -// `uk-align-right-*` -// `uk-align-center` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$align-margin-horizontal: $global-gutter !default; -$align-margin-vertical: $global-gutter !default; - -$align-margin-horizontal-l: $global-medium-gutter !default; - - -/* ======================================================================== - Component: Align - ========================================================================== */ - -/* - * Default - */ - -[class*='uk-align'] { - display: block; - margin-bottom: $align-margin-vertical; -} - -* + [class*='uk-align'] { margin-top: $align-margin-vertical; } - -/* - * Center - */ - -.uk-align-center { - margin-left: auto; - margin-right: auto; -} - -/* - * Left/Right - */ - -.uk-align-left { - margin-top: 0; - margin-right: $align-margin-horizontal; - float: left; -} - -.uk-align-right { - margin-top: 0; - margin-left: $align-margin-horizontal; - float: right; -} - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-align-left\@s { - margin-top: 0; - margin-right: $align-margin-horizontal; - float: left; - } - - .uk-align-right\@s { - margin-top: 0; - margin-left: $align-margin-horizontal; - float: right; - } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-align-left\@m { - margin-top: 0; - margin-right: $align-margin-horizontal; - float: left; - } - - .uk-align-right\@m { - margin-top: 0; - margin-left: $align-margin-horizontal; - float: right; - } - -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-align-left\@l { - margin-top: 0; - float: left; - } - - .uk-align-right\@l { - margin-top: 0; - float: right; - } - - .uk-align-left, - .uk-align-left\@s, - .uk-align-left\@m, - .uk-align-left\@l { margin-right: $align-margin-horizontal-l; } - - .uk-align-right, - .uk-align-right\@s, - .uk-align-right\@m, - .uk-align-right\@l { margin-left: $align-margin-horizontal-l; } - -} - -/* Large screen and bigger */ -@media (min-width: $breakpoint-xlarge) { - - .uk-align-left\@xl { - margin-top: 0; - margin-right: $align-margin-horizontal-l; - float: left; - } - - .uk-align-right\@xl { - margin-top: 0; - margin-left: $align-margin-horizontal-l; - float: right; - } - -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-align-misc)) {@include hook-align-misc();} - -// @mixin hook-align-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/animation.scss b/docs/_sass/uikit/components/animation.scss deleted file mode 100644 index c955238499..0000000000 --- a/docs/_sass/uikit/components/animation.scss +++ /dev/null @@ -1,430 +0,0 @@ -// Name: Animation -// Description: Utilities for keyframe animations -// -// Component: `uk-animation-*` -// -// Modifiers: `uk-animation-fade` -// `uk-animation-scale-up` -// `uk-animation-scale-down` -// `uk-animation-slide-top-*` -// `uk-animation-slide-bottom-*` -// `uk-animation-slide-left-*` -// `uk-animation-slide-right-*` -// `uk-animation-kenburns` -// `uk-animation-shake` -// `uk-animation-stroke` -// `uk-animation-reverse` -// `uk-animation-fast` -// -// Sub-objects: `uk-animation-toggle` -// -// States: `uk-active` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$animation-duration: 0.5s !default; -$animation-fade-duration: 0.8s !default; -$animation-stroke-duration: 2s !default; -$animation-kenburns-duration: 15s !default; -$animation-fast-duration: 0.1s !default; - -$animation-slide-small-translate: 10px !default; -$animation-slide-medium-translate: 50px !default; - - -/* ======================================================================== - Component: Animation - ========================================================================== */ - -[class*='uk-animation-'] { - animation-duration: $animation-duration; - animation-timing-function: ease-out; - animation-fill-mode: both; -} - - -/* Animations - ========================================================================== */ - -/* - * Fade - */ - -.uk-animation-fade { - animation-name: uk-fade; - animation-duration: $animation-fade-duration; - animation-timing-function: linear; -} - -/* - * Scale - */ - -.uk-animation-scale-up { animation-name: uk-fade-scale-02; } -.uk-animation-scale-down { animation-name: uk-fade-scale-18; } - -/* - * Slide - */ - -.uk-animation-slide-top { animation-name: uk-fade-top; } -.uk-animation-slide-bottom { animation-name: uk-fade-bottom; } -.uk-animation-slide-left { animation-name: uk-fade-left; } -.uk-animation-slide-right { animation-name: uk-fade-right; } - -/* - * Slide Small - */ - -.uk-animation-slide-top-small { animation-name: uk-fade-top-small; } -.uk-animation-slide-bottom-small { animation-name: uk-fade-bottom-small; } -.uk-animation-slide-left-small { animation-name: uk-fade-left-small; } -.uk-animation-slide-right-small { animation-name: uk-fade-right-small; } - -/* - * Slide Medium - */ - -.uk-animation-slide-top-medium { animation-name: uk-fade-top-medium; } -.uk-animation-slide-bottom-medium { animation-name: uk-fade-bottom-medium; } -.uk-animation-slide-left-medium { animation-name: uk-fade-left-medium; } -.uk-animation-slide-right-medium { animation-name: uk-fade-right-medium; } - -/* - * Kenburns - */ - -.uk-animation-kenburns { - animation-name: uk-scale-kenburns; - animation-duration: $animation-kenburns-duration; -} - -/* - * Shake - */ - -.uk-animation-shake { animation-name: uk-shake; } - -/* - * SVG Stroke - * The `--uk-animation-stroke` custom property contains the longest path length. - * Set it manually or use `uk-svg="stroke-animation: true"` to set it automatically. - * All strokes are animated by the same pace and doesn't end simultaneously. - * To end simultaneously, `pathLength="1"` could be used, but it's not working in Safari yet. - */ - -.uk-animation-stroke { - animation-name: uk-stroke; - stroke-dasharray: var(--uk-animation-stroke); - animation-duration: $animation-stroke-duration; -} - - -/* Direction modifier - ========================================================================== */ - - .uk-animation-reverse { - animation-direction: reverse; - animation-timing-function: ease-in; -} - - -/* Duration modifier - ========================================================================== */ - - .uk-animation-fast { animation-duration: $animation-fast-duration; } - - -/* Toggle (Hover + Focus) -========================================================================== */ - -/* - * The toggle is triggered on touch devices using `:focus` and tabindex - */ - -.uk-animation-toggle:not(:hover):not(:focus) [class*='uk-animation-'] { animation-name: none; } - -/* - * 1. Prevent tab highlighting on iOS. - */ - -.uk-animation-toggle { - /* 1 */ - -webkit-tap-highlight-color: transparent; -} - -/* - * Remove outline for `tabindex` - */ - -.uk-animation-toggle:focus { outline: none; } - - -/* Keyframes used by animation classes - ========================================================================== */ - -/* - * Fade - */ - -@keyframes uk-fade { - 0% { opacity: 0; } - 100% { opacity: 1; } -} - -/* - * Slide Top - */ - -@keyframes uk-fade-top { - 0% { - opacity: 0; - transform: translateY(-100%); - } - 100% { - opacity: 1; - transform: translateY(0); - } -} - -/* - * Slide Bottom - */ - -@keyframes uk-fade-bottom { - 0% { - opacity: 0; - transform: translateY(100%); - } - 100% { - opacity: 1; - transform: translateY(0); - } -} - -/* - * Slide Left - */ - -@keyframes uk-fade-left { - 0% { - opacity: 0; - transform: translateX(-100%); - } - 100% { - opacity: 1; - transform: translateX(0); - } -} - -/* - * Slide Right - */ - -@keyframes uk-fade-right { - 0% { - opacity: 0; - transform: translateX(100%); - } - 100% { - opacity: 1; - transform: translateX(0); - } -} - -/* - * Slide Top Small - */ - -@keyframes uk-fade-top-small { - 0% { - opacity: 0; - transform: translateY(-$animation-slide-small-translate); - } - 100% { - opacity: 1; - transform: translateY(0); - } -} - -/* - * Slide Bottom Small - */ - -@keyframes uk-fade-bottom-small { - 0% { - opacity: 0; - transform: translateY($animation-slide-small-translate); - } - 100% { - opacity: 1; - transform: translateY(0); - } -} - -/* - * Slide Left Small - */ - -@keyframes uk-fade-left-small { - 0% { - opacity: 0; - transform: translateX(-$animation-slide-small-translate); - } - 100% { - opacity: 1; - transform: translateX(0); - } -} - -/* - * Slide Right Small - */ - -@keyframes uk-fade-right-small { - 0% { - opacity: 0; - transform: translateX($animation-slide-small-translate); - } - 100% { - opacity: 1; - transform: translateX(0); - } -} - -/* - * Slide Top Medium - */ - -@keyframes uk-fade-top-medium { - 0% { - opacity: 0; - transform: translateY(-$animation-slide-medium-translate); - } - 100% { - opacity: 1; - transform: translateY(0); - } -} - -/* - * Slide Bottom Medium - */ - -@keyframes uk-fade-bottom-medium { - 0% { - opacity: 0; - transform: translateY($animation-slide-medium-translate); - } - 100% { - opacity: 1; - transform: translateY(0); - } -} - -/* - * Slide Left Medium - */ - -@keyframes uk-fade-left-medium { - 0% { - opacity: 0; - transform: translateX(-$animation-slide-medium-translate); - } - 100% { - opacity: 1; - transform: translateX(0); - } -} - -/* - * Slide Right Medium - */ - -@keyframes uk-fade-right-medium { - 0% { - opacity: 0; - transform: translateX($animation-slide-medium-translate); - } - 100% { - opacity: 1; - transform: translateX(0); - } -} - -/* - * Scale Up - */ - -@keyframes uk-fade-scale-02 { - 0% { - opacity: 0; - transform: scale(0.2); - } - 100% { - opacity: 1; - transform: scale(1); - } -} - -/* - * Scale Down - */ - -@keyframes uk-fade-scale-18 { - 0% { - opacity: 0; - transform: scale(1.8); - } - 100% { - opacity: 1; - transform: scale(1); - } -} - -/* - * Kenburns - */ - -@keyframes uk-scale-kenburns { - 0% { transform: scale(1); } - 100% { transform: scale(1.2); } -} - -/* - * Shake - */ - -@keyframes uk-shake { - 0%, 100% { transform: translateX(0); } - 10% { transform: translateX(-9px); } - 20% { transform: translateX(8px); } - 30% { transform: translateX(-7px); } - 40% { transform: translateX(6px); } - 50% { transform: translateX(-5px); } - 60% { transform: translateX(4px); } - 70% { transform: translateX(-3px); } - 80% { transform: translateX(2px); } - 90% { transform: translateX(-1px); } -} - -/* - * Stroke - */ - - @keyframes uk-stroke { - 0% { stroke-dashoffset: var(--uk-animation-stroke); } - 100% { stroke-dashoffset: 0; } -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-animation-misc)) {@include hook-animation-misc();} - -// @mixin hook-animation-misc(){} diff --git a/docs/_sass/uikit/components/article.scss b/docs/_sass/uikit/components/article.scss deleted file mode 100644 index 4fa4e2b2d0..0000000000 --- a/docs/_sass/uikit/components/article.scss +++ /dev/null @@ -1,99 +0,0 @@ -// Name: Article -// Description: Component to create articles -// -// Component: `uk-article` -// -// Sub-objects: `uk-article-title` -// `uk-article-meta` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$article-margin-top: $global-large-margin !default; - -$article-title-font-size-m: $global-2xlarge-font-size !default; -$article-title-font-size: $article-title-font-size-m * 0.85 !default; -$article-title-line-height: 1.2 !default; - -$article-meta-font-size: $global-small-font-size !default; -$article-meta-line-height: 1.4 !default; -$article-meta-color: $global-muted-color !default; - - -/* ======================================================================== - Component: Article - ========================================================================== */ - -.uk-article { - display: flow-root; - @if(mixin-exists(hook-article)) {@include hook-article();} -} - -/* - * Remove margin from the last-child - */ - -.uk-article > :last-child { margin-bottom: 0; } - - -/* Adjacent sibling - ========================================================================== */ - -.uk-article + .uk-article { - margin-top: $article-margin-top; - @if(mixin-exists(hook-article-adjacent)) {@include hook-article-adjacent();} -} - - -/* Title - ========================================================================== */ - -.uk-article-title { - font-size: $article-title-font-size; - line-height: $article-title-line-height; - @if(mixin-exists(hook-article-title)) {@include hook-article-title();} -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-article-title { font-size: $article-title-font-size-m; } - -} - - -/* Meta - ========================================================================== */ - -.uk-article-meta { - font-size: $article-meta-font-size; - line-height: $article-meta-line-height; - color: $article-meta-color; - @if(mixin-exists(hook-article-meta)) {@include hook-article-meta();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-article-misc)) {@include hook-article-misc();} - -// @mixin hook-article(){} -// @mixin hook-article-adjacent(){} -// @mixin hook-article-title(){} -// @mixin hook-article-meta(){} -// @mixin hook-article-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-article-meta-color: $inverse-global-muted-color !default; - - - -// @mixin hook-inverse-article-title(){} -// @mixin hook-inverse-article-meta(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/background.scss b/docs/_sass/uikit/components/background.scss deleted file mode 100644 index d486672b59..0000000000 --- a/docs/_sass/uikit/components/background.scss +++ /dev/null @@ -1,148 +0,0 @@ -// Name: Background -// Description: Utilities for backgrounds -// -// Component: `uk-background-*` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$background-default-background: $global-background !default; -$background-muted-background: $global-muted-background !default; -$background-primary-background: $global-primary-background !default; -$background-secondary-background: $global-secondary-background !default; - - -/* ======================================================================== - Component: Background - ========================================================================== */ - - -/* Color - ========================================================================== */ - -.uk-background-default { background-color: $background-default-background; } -.uk-background-muted { background-color: $background-muted-background; } -.uk-background-primary { background-color: $background-primary-background; } -.uk-background-secondary { background-color: $background-secondary-background; } - - -/* Size - ========================================================================== */ - -.uk-background-cover, -.uk-background-contain, -.uk-background-width-1-1, -.uk-background-height-1-1 { - background-position: 50% 50%; - background-repeat: no-repeat; -} - -.uk-background-cover { background-size: cover; } -.uk-background-contain { background-size: contain; } -.uk-background-width-1-1 { background-size: 100%; } -.uk-background-height-1-1 { background-size: auto 100%; } - - -/* Position - ========================================================================== */ - -.uk-background-top-left { background-position: 0 0; } -.uk-background-top-center { background-position: 50% 0; } -.uk-background-top-right { background-position: 100% 0; } -.uk-background-center-left { background-position: 0 50%; } -.uk-background-center-center { background-position: 50% 50%; } -.uk-background-center-right { background-position: 100% 50%; } -.uk-background-bottom-left { background-position: 0 100%; } -.uk-background-bottom-center { background-position: 50% 100%; } -.uk-background-bottom-right { background-position: 100% 100%; } - - -/* Repeat - ========================================================================== */ - -.uk-background-norepeat { background-repeat: no-repeat; } - - -/* Attachment - ========================================================================== */ - -/* - * 1. Fix bug introduced in Chrome 67: the background image is not visible if any element on the page uses `translate3d` - */ - -.uk-background-fixed { - background-attachment: fixed; - /* 1 */ - backface-visibility: hidden; -} - -/* - * Exclude touch devices because `fixed` doesn't work on iOS and Android - */ - -@media (pointer: coarse) { - .uk-background-fixed { background-attachment: scroll; } -} - - -/* Image - ========================================================================== */ - -/* Phone portrait and smaller */ -@media (max-width: $breakpoint-xsmall-max) { - - .uk-background-image\@s { background-image: none !important; } - -} - -/* Phone landscape and smaller */ -@media (max-width: $breakpoint-small-max) { - - .uk-background-image\@m { background-image: none !important; } - -} - -/* Tablet landscape and smaller */ -@media (max-width: $breakpoint-medium-max) { - - .uk-background-image\@l { background-image: none !important; } - -} - -/* Desktop and smaller */ -@media (max-width: $breakpoint-large-max) { - - .uk-background-image\@xl {background-image: none !important; } - -} - - -/* Blend modes - ========================================================================== */ - -.uk-background-blend-multiply { background-blend-mode: multiply; } -.uk-background-blend-screen { background-blend-mode: screen; } -.uk-background-blend-overlay { background-blend-mode: overlay; } -.uk-background-blend-darken { background-blend-mode: darken; } -.uk-background-blend-lighten { background-blend-mode: lighten; } -.uk-background-blend-color-dodge { background-blend-mode: color-dodge; } -.uk-background-blend-color-burn { background-blend-mode: color-burn; } -.uk-background-blend-hard-light { background-blend-mode: hard-light; } -.uk-background-blend-soft-light { background-blend-mode: soft-light; } -.uk-background-blend-difference { background-blend-mode: difference; } -.uk-background-blend-exclusion { background-blend-mode: exclusion; } -.uk-background-blend-hue { background-blend-mode: hue; } -.uk-background-blend-saturation { background-blend-mode: saturation; } -.uk-background-blend-color { background-blend-mode: color; } -.uk-background-blend-luminosity { background-blend-mode: luminosity; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-background-misc)) {@include hook-background-misc();} - -// @mixin hook-background-misc(){} diff --git a/docs/_sass/uikit/components/badge.scss b/docs/_sass/uikit/components/badge.scss deleted file mode 100644 index 1df2236bf9..0000000000 --- a/docs/_sass/uikit/components/badge.scss +++ /dev/null @@ -1,80 +0,0 @@ -// Name: Badge -// Description: Component to create notification badges -// -// Component: `uk-badge` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$badge-size: 18px !default; -$badge-padding-vertical: 0 !default; -$badge-padding-horizontal: 5px !default; -$badge-border-radius: 500px !default; -$badge-background: $global-primary-background !default; -$badge-color: $global-inverse-color !default; -$badge-font-size: 11px !default; - - -/* ======================================================================== - Component: Badge - ========================================================================== */ - -/* - * 1. Style - * 2. Center child vertically and horizontally - */ - -.uk-badge { - box-sizing: border-box; - min-width: $badge-size; - height: $badge-size; - padding: $badge-padding-vertical $badge-padding-horizontal; - border-radius: $badge-border-radius; - vertical-align: middle; - /* 1 */ - background: $badge-background; - color: $badge-color !important; - font-size: $badge-font-size; - /* 2 */ - display: inline-flex; - justify-content: center; - align-items: center; - line-height: 0; - @if(mixin-exists(hook-badge)) {@include hook-badge();} -} - -/* - * Required for `a` - */ - -.uk-badge:hover, -.uk-badge:focus { - text-decoration: none; - outline: none; - @if(mixin-exists(hook-badge-hover)) {@include hook-badge-hover();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-badge-misc)) {@include hook-badge-misc();} - -// @mixin hook-badge(){} -// @mixin hook-badge-hover(){} -// @mixin hook-badge-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-badge-background: $inverse-global-primary-background !default; -$inverse-badge-color: $inverse-global-inverse-color !default; - - - -// @mixin hook-inverse-badge(){} -// @mixin hook-inverse-badge-hover(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/base.scss b/docs/_sass/uikit/components/base.scss deleted file mode 100644 index 188af873fd..0000000000 --- a/docs/_sass/uikit/components/base.scss +++ /dev/null @@ -1,628 +0,0 @@ -// Name: Base -// Description: Default values for HTML elements -// -// Component: `uk-link` -// `uk-h1`, `uk-h2`, `uk-h3`, `uk-h4`, `uk-h5`, `uk-h6` -// `uk-hr` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$base-body-background: $global-background !default; -$base-body-font-family: $global-font-family !default; -$base-body-font-weight: normal !default; -$base-body-font-size: $global-font-size !default; -$base-body-line-height: $global-line-height !default; -$base-body-color: $global-color !default; - -$base-link-color: $global-link-color !default; -$base-link-text-decoration: none !default; -$base-link-hover-color: $global-link-hover-color !default; -$base-link-hover-text-decoration: underline !default; - -$base-strong-font-weight: bolder !default; -$base-code-font-size: $global-small-font-size !default; -$base-code-font-family: Consolas, monaco, monospace !default; -$base-code-color: $global-danger-background !default; -$base-em-color: $global-danger-background !default; -$base-ins-background: #ffd !default; -$base-ins-color: $global-color !default; -$base-mark-background: #ffd !default; -$base-mark-color: $global-color !default; -$base-quote-font-style: italic !default; -$base-small-font-size: 80% !default; - -$base-margin-vertical: $global-margin !default; - -$base-heading-font-family: $global-font-family !default; -$base-heading-font-weight: normal !default; -$base-heading-color: $global-emphasis-color !default; -$base-heading-text-transform: none !default; -$base-heading-margin-top: $global-medium-margin !default; -$base-h1-font-size-m: $global-2xlarge-font-size !default; -$base-h1-font-size: $base-h1-font-size-m * 0.85 !default; -$base-h1-line-height: 1.2 !default; -$base-h2-font-size-m: $global-xlarge-font-size !default; -$base-h2-font-size: $base-h2-font-size-m * 0.85 !default; -$base-h2-line-height: 1.3 !default; -$base-h3-font-size: $global-large-font-size !default; -$base-h3-line-height: 1.4 !default; -$base-h4-font-size: $global-medium-font-size !default; -$base-h4-line-height: 1.4 !default; -$base-h5-font-size: $global-font-size !default; -$base-h5-line-height: 1.4 !default; -$base-h6-font-size: $global-small-font-size !default; -$base-h6-line-height: 1.4 !default; - -$base-list-padding-left: 30px !default; - -$base-hr-margin-vertical: $global-margin !default; -$base-hr-border-width: $global-border-width !default; -$base-hr-border: $global-border !default; - -$base-blockquote-font-size: $global-medium-font-size !default; -$base-blockquote-line-height: 1.5 !default; -$base-blockquote-font-style: italic !default; -$base-blockquote-margin-vertical: $global-margin !default; -$base-blockquote-footer-margin-top: $global-small-margin !default; -$base-blockquote-footer-font-size: $global-small-font-size !default; -$base-blockquote-footer-line-height: 1.5 !default; - -$base-pre-font-size: $global-small-font-size !default; -$base-pre-line-height: 1.5 !default; -$base-pre-font-family: $base-code-font-family !default; -$base-pre-color: $global-color !default; - -$base-selection-background: #39f !default; -$base-selection-color: $global-inverse-color !default; - - -/* ======================================================================== - Component: Base - ========================================================================== */ - -/* - * 1. Set `font-size` to support `rem` units - * Not using `font` property because a leading hyphen (e.g. -apple-system) causes the font to break in IE11 and Edge - * 2. Prevent adjustments of font size after orientation changes in iOS. - * 3. Style - */ - -html { - /* 1 */ - font-family: $base-body-font-family; - font-size: $base-body-font-size; - font-weight: $base-body-font-weight; - line-height: $base-body-line-height; - /* 2 */ - -webkit-text-size-adjust: 100%; - /* 3 */ - background: $base-body-background; - color: $base-body-color; - @if(mixin-exists(hook-base-body)) {@include hook-base-body();} -} - -/* - * Remove the margin in all browsers. - */ - -body { margin: 0; } - - -/* Links - ========================================================================== */ - -/* - * Remove the outline on focused links when they are also active or hovered - */ - -a:active, -a:hover { outline: none; } - -/* - * Style - */ - -a, -.uk-link { - color: $base-link-color; - text-decoration: $base-link-text-decoration; - cursor: pointer; - @if(mixin-exists(hook-base-link)) {@include hook-base-link();} -} - -a:hover, -.uk-link:hover, -.uk-link-toggle:hover .uk-link, -.uk-link-toggle:focus .uk-link { - color: $base-link-hover-color; - text-decoration: $base-link-hover-text-decoration; - @if(mixin-exists(hook-base-link-hover)) {@include hook-base-link-hover();} -} - - -/* Text-level semantics - ========================================================================== */ - -/* - * 1. Add the correct text decoration in Edge. - * 2. The shorthand declaration `underline dotted` is not supported in Safari. - */ - -abbr[title] { - /* 1 */ - text-decoration: underline dotted; - /* 2 */ - -webkit-text-decoration-style: dotted; -} - -/* - * Add the correct font weight in Chrome, Edge, and Safari. - */ - -b, -strong { font-weight: $base-strong-font-weight; } - -/* - * 1. Consolas has a better baseline in running text compared to `Courier` - * 2. Correct the odd `em` font sizing in all browsers. - * 3. Style - */ - -:not(pre) > code, -:not(pre) > kbd, -:not(pre) > samp { - /* 1 */ - font-family: $base-code-font-family; - /* 2 */ - font-size: $base-code-font-size; - /* 3 */ - color: $base-code-color; - white-space: nowrap; - @if(mixin-exists(hook-base-code)) {@include hook-base-code();} -} - -/* - * Emphasize - */ - -em { color: $base-em-color; } - -/* - * Insert - */ - -ins { - background: $base-ins-background; - color: $base-ins-color; - text-decoration: none; -} - -/* - * Mark - */ - -mark { - background: $base-mark-background; - color: $base-mark-color; -} - -/* - * Quote - */ - -q { font-style: $base-quote-font-style; } - -/* - * Add the correct font size in all browsers. - */ - -small { font-size: $base-small-font-size; } - -/* - * Prevents `sub` and `sup` affecting `line-height` in all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sup { top: -0.5em; } -sub { bottom: -0.25em; } - - -/* Embedded content - ========================================================================== */ - -/* - * Remove the gap between embedded content and the bottom of their containers. - */ - -audio, -canvas, -iframe, -img, -svg, -video { vertical-align: middle; } - -/* - * 1. Add responsiveness. - * 2. Auto-scale the height. Only needed if `height` attribute is present. - * 3. Corrects responsive `max-width` behavior if padding and border are used. - * 4. Exclude SVGs for IE11 because they don't preserve their aspect ratio. - */ - -canvas, -img, -video { - /* 1 */ - max-width: 100%; - /* 2 */ - height: auto; - /* 3 */ - box-sizing: border-box; -} - -/* 4 */ -@supports (display: block) { - - svg { - max-width: 100%; - height: auto; - box-sizing: border-box; - } - -} - -/* - * Hide the overflow in IE. - */ - -svg:not(:root) { overflow: hidden; } - -/* - * 1. Fix lazy loading images if parent element is set to `display: inline` and has `overflow: hidden`. - * 2. Hide `alt` text for lazy loading images. - * Note: Selector for background while loading img[data-src*='.jpg'][src*='data:image'] { background: grey; } - */ - -img:not([src]) { - /* 1 */ - min-width: 1px; - /* 2 */ - visibility: hidden; -} - -/* - * Iframe - * Remove border in all browsers - */ - -iframe { border: 0; } - - -/* Block elements - ========================================================================== */ - -/* - * Margins - */ - -p, -ul, -ol, -dl, -pre, -address, -fieldset, -figure { margin: 0 0 $base-margin-vertical 0; } - -/* Add margin if adjacent element */ -* + p, -* + ul, -* + ol, -* + dl, -* + pre, -* + address, -* + fieldset, -* + figure { margin-top: $base-margin-vertical; } - - -/* Headings - ========================================================================== */ - -h1, .uk-h1, -h2, .uk-h2, -h3, .uk-h3, -h4, .uk-h4, -h5, .uk-h5, -h6, .uk-h6, -.uk-heading-small, -.uk-heading-medium, -.uk-heading-large, -.uk-heading-xlarge, -.uk-heading-2xlarge { - margin: 0 0 $base-margin-vertical 0; - font-family: $base-heading-font-family; - font-weight: $base-heading-font-weight; - color: $base-heading-color; - text-transform: $base-heading-text-transform; - @if(mixin-exists(hook-base-heading)) {@include hook-base-heading();} -} - -/* Add margin if adjacent element */ -* + h1, * + .uk-h1, -* + h2, * + .uk-h2, -* + h3, * + .uk-h3, -* + h4, * + .uk-h4, -* + h5, * + .uk-h5, -* + h6, * + .uk-h6, -* + .uk-heading-small, -* + .uk-heading-medium, -* + .uk-heading-large, -* + .uk-heading-xlarge, -* + .uk-heading-2xlarge { margin-top: $base-heading-margin-top; } - -/* - * Sizes - */ - -h1, .uk-h1 { - font-size: $base-h1-font-size; - line-height: $base-h1-line-height; - @if(mixin-exists(hook-base-h1)) {@include hook-base-h1();} -} - -h2, .uk-h2 { - font-size: $base-h2-font-size; - line-height: $base-h2-line-height; - @if(mixin-exists(hook-base-h2)) {@include hook-base-h2();} -} - -h3, .uk-h3 { - font-size: $base-h3-font-size; - line-height: $base-h3-line-height; - @if(mixin-exists(hook-base-h3)) {@include hook-base-h3();} -} - -h4, .uk-h4 { - font-size: $base-h4-font-size; - line-height: $base-h4-line-height; - @if(mixin-exists(hook-base-h4)) {@include hook-base-h4();} -} - -h5, .uk-h5 { - font-size: $base-h5-font-size; - line-height: $base-h5-line-height; - @if(mixin-exists(hook-base-h5)) {@include hook-base-h5();} -} - -h6, .uk-h6 { - font-size: $base-h6-font-size; - line-height: $base-h6-line-height; - @if(mixin-exists(hook-base-h6)) {@include hook-base-h6();} -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - h1, .uk-h1 { font-size: $base-h1-font-size-m; } - h2, .uk-h2 { font-size: $base-h2-font-size-m; } - -} - - -/* Lists - ========================================================================== */ - -ul, -ol { padding-left: $base-list-padding-left; } - -/* - * Reset margin for nested lists - */ - -ul > li > ul, -ul > li > ol, -ol > li > ol, -ol > li > ul { margin: 0; } - - -/* Description lists - ========================================================================== */ - -dt { font-weight: bold; } -dd { margin-left: 0; } - - -/* Horizontal rules - ========================================================================== */ - -/* - * 1. Show the overflow in Chrome, Edge and IE. - * 2. Add the correct text-align in Edge and IE. - * 3. Style - */ - -hr, .uk-hr { - /* 1 */ - overflow: visible; - /* 2 */ - text-align: inherit; - /* 3 */ - margin: 0 0 $base-hr-margin-vertical 0; - border: 0; - border-top: $base-hr-border-width solid $base-hr-border; - @if(mixin-exists(hook-base-hr)) {@include hook-base-hr();} -} - -/* Add margin if adjacent element */ -* + hr, -* + .uk-hr { margin-top: $base-hr-margin-vertical } - - -/* Address - ========================================================================== */ - -address { font-style: normal; } - - -/* Blockquotes - ========================================================================== */ - -blockquote { - margin: 0 0 $base-blockquote-margin-vertical 0; - font-size: $base-blockquote-font-size; - line-height: $base-blockquote-line-height; - font-style: $base-blockquote-font-style; - @if(mixin-exists(hook-base-blockquote)) {@include hook-base-blockquote();} -} - -/* Add margin if adjacent element */ -* + blockquote { margin-top: $base-blockquote-margin-vertical; } - -/* - * Content - */ - -blockquote p:last-of-type { margin-bottom: 0; } - -blockquote footer { - margin-top: $base-blockquote-footer-margin-top; - font-size: $base-blockquote-footer-font-size; - line-height: $base-blockquote-footer-line-height; - @if(mixin-exists(hook-base-blockquote-footer)) {@include hook-base-blockquote-footer();} -} - - -/* Preformatted text - ========================================================================== */ - -/* - * 1. Contain overflow in all browsers. - */ - -pre { - font: $base-pre-font-size unquote("/") $base-pre-line-height $base-pre-font-family; - color: $base-pre-color; - -moz-tab-size: 4; - tab-size: 4; - /* 1 */ - overflow: auto; - @if(mixin-exists(hook-base-pre)) {@include hook-base-pre();} -} - -pre code { font-family: $base-pre-font-family; } - - -/* Selection pseudo-element - ========================================================================== */ - -::selection { - background: $base-selection-background; - color: $base-selection-color; - text-shadow: none; -} - - -/* HTML5 elements - ========================================================================== */ - -/* - * 1. Add the correct display in Edge, IE 10+, and Firefox. - * 2. Add the correct display in IE. - */ - -details, /* 1 */ -main { /* 2 */ - display: block; -} - -/* - * Add the correct display in all browsers. - */ - -summary { display: list-item; } - -/* - * Add the correct display in IE. - */ - -template { display: none; } - - -/* Pass media breakpoints to JS - ========================================================================== */ - -/* - * Breakpoints - */ - -.uk-breakpoint-s::before { content: '#{$breakpoint-small}'; } -.uk-breakpoint-m::before { content: '#{$breakpoint-medium}'; } -.uk-breakpoint-l::before { content: '#{$breakpoint-large}'; } -.uk-breakpoint-xl::before { content: '#{$breakpoint-xlarge}'; } - -:root { - --uk-breakpoint-s: #{$breakpoint-small}; - --uk-breakpoint-m: #{$breakpoint-medium}; - --uk-breakpoint-l: #{$breakpoint-large}; - --uk-breakpoint-xl: #{$breakpoint-xlarge}; -} - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-base-misc)) {@include hook-base-misc();} - -// @mixin hook-base-body(){} -// @mixin hook-base-link(){} -// @mixin hook-base-link-hover(){} -// @mixin hook-base-code(){} -// @mixin hook-base-heading(){} -// @mixin hook-base-h1(){} -// @mixin hook-base-h2(){} -// @mixin hook-base-h3(){} -// @mixin hook-base-h4(){} -// @mixin hook-base-h5(){} -// @mixin hook-base-h6(){} -// @mixin hook-base-hr(){} -// @mixin hook-base-blockquote(){} -// @mixin hook-base-blockquote-footer(){} -// @mixin hook-base-pre(){} -// @mixin hook-base-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-base-color: $inverse-global-color !default; -$inverse-base-link-color: $inverse-global-emphasis-color !default; -$inverse-base-link-hover-color: $inverse-global-emphasis-color !default; -$inverse-base-code-color: $inverse-global-color !default; -$inverse-base-em-color: $inverse-global-emphasis-color !default; -$inverse-base-heading-color: $inverse-global-emphasis-color !default; -$inverse-base-hr-border: $inverse-global-border !default; - - - -// @mixin hook-inverse-base-link(){} -// @mixin hook-inverse-base-link-hover(){} -// @mixin hook-inverse-base-code(){} -// @mixin hook-inverse-base-heading(){} -// @mixin hook-inverse-base-h1(){} -// @mixin hook-inverse-base-h2(){} -// @mixin hook-inverse-base-h3(){} -// @mixin hook-inverse-base-h4(){} -// @mixin hook-inverse-base-h5(){} -// @mixin hook-inverse-base-h6(){} -// @mixin hook-inverse-base-blockquote(){} -// @mixin hook-inverse-base-blockquote-footer(){} -// @mixin hook-inverse-base-hr(){} diff --git a/docs/_sass/uikit/components/breadcrumb.scss b/docs/_sass/uikit/components/breadcrumb.scss deleted file mode 100644 index 3035391765..0000000000 --- a/docs/_sass/uikit/components/breadcrumb.scss +++ /dev/null @@ -1,123 +0,0 @@ -// Name: Breadcrumb -// Description: Component to create a breadcrumb navigation -// -// Component: `uk-breadcrumb` -// -// States: `uk-disabled` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$breadcrumb-item-font-size: $global-small-font-size !default; -$breadcrumb-item-color: $global-muted-color !default; -$breadcrumb-item-hover-color: $global-color !default; -$breadcrumb-item-hover-text-decoration: none !default; -$breadcrumb-item-active-color: $global-color !default; - -$breadcrumb-divider: "/" !default; -$breadcrumb-divider-margin-horizontal: 20px !default; -$breadcrumb-divider-font-size: $breadcrumb-item-font-size !default; -$breadcrumb-divider-color: $global-muted-color !default; - - -/* ======================================================================== - Component: Breadcrumb - ========================================================================== */ - -/* - * Reset list - */ - -.uk-breadcrumb { - padding: 0; - list-style: none; - @if(mixin-exists(hook-breadcrumb)) {@include hook-breadcrumb();} -} - -/* - * 1. Doesn't generate any box and replaced by child boxes - */ - -.uk-breadcrumb > * { display: contents; } - - -/* Items - ========================================================================== */ - -.uk-breadcrumb > * > * { - font-size: $breadcrumb-item-font-size; - color: $breadcrumb-item-color; - @if(mixin-exists(hook-breadcrumb-item)) {@include hook-breadcrumb-item();} -} - -/* Hover + Focus */ -.uk-breadcrumb > * > :hover, -.uk-breadcrumb > * > :focus { - color: $breadcrumb-item-hover-color; - text-decoration: $breadcrumb-item-hover-text-decoration; - @if(mixin-exists(hook-breadcrumb-item-hover)) {@include hook-breadcrumb-item-hover();} -} - -/* Disabled */ -.uk-breadcrumb > .uk-disabled > * { - @if(mixin-exists(hook-breadcrumb-item-disabled)) {@include hook-breadcrumb-item-disabled();} -} - -/* Active */ -.uk-breadcrumb > :last-child > span, -.uk-breadcrumb > :last-child > a:not([href]) { - color: $breadcrumb-item-active-color; - @if(mixin-exists(hook-breadcrumb-item-active)) {@include hook-breadcrumb-item-active();} -} - -/* - * Divider - * `nth-child` makes it also work without JS if it's only one row - * 1. Remove space between inline block elements. - * 2. Style - */ - -.uk-breadcrumb > :nth-child(n+2):not(.uk-first-column)::before { - content: $breadcrumb-divider; - display: inline-block; - /* 1 */ - margin: 0 $breadcrumb-divider-margin-horizontal 0 unquote('calc(#{$breadcrumb-divider-margin-horizontal} - 4px)'); - /* 2 */ - font-size: $breadcrumb-divider-font-size; - color: $breadcrumb-divider-color; - @if(mixin-exists(hook-breadcrumb-divider)) {@include hook-breadcrumb-divider();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-breadcrumb-misc)) {@include hook-breadcrumb-misc();} - -// @mixin hook-breadcrumb(){} -// @mixin hook-breadcrumb-item(){} -// @mixin hook-breadcrumb-item-hover(){} -// @mixin hook-breadcrumb-item-disabled(){} -// @mixin hook-breadcrumb-item-active(){} -// @mixin hook-breadcrumb-divider(){} -// @mixin hook-breadcrumb-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-breadcrumb-item-color: $inverse-global-muted-color !default; -$inverse-breadcrumb-item-hover-color: $inverse-global-color !default; -$inverse-breadcrumb-item-active-color: $inverse-global-color !default; -$inverse-breadcrumb-divider-color: $inverse-global-muted-color !default; - - - -// @mixin hook-inverse-breadcrumb-item(){} -// @mixin hook-inverse-breadcrumb-item-hover(){} -// @mixin hook-inverse-breadcrumb-item-disabled(){} -// @mixin hook-inverse-breadcrumb-item-active(){} -// @mixin hook-inverse-breadcrumb-divider(){} diff --git a/docs/_sass/uikit/components/button.scss b/docs/_sass/uikit/components/button.scss deleted file mode 100644 index 752791793f..0000000000 --- a/docs/_sass/uikit/components/button.scss +++ /dev/null @@ -1,452 +0,0 @@ -// Name: Button -// Description: Styles for buttons -// -// Component: `uk-button` -// -// Sub-objects: `uk-button-group` -// -// Modifiers: `uk-button-default` -// `uk-button-primary` -// `uk-button-secondary` -// `uk-button-danger` -// `uk-button-text` -// `uk-button-link` -// `uk-button-small` -// `uk-button-large` -// -// States: `uk-active` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$button-line-height: $global-control-height !default; -$button-small-line-height: $global-control-small-height !default; -$button-large-line-height: $global-control-large-height !default; - -$button-font-size: $global-font-size !default; -$button-small-font-size: $global-small-font-size !default; -$button-large-font-size: $global-medium-font-size !default; - -$button-padding-horizontal: $global-gutter !default; -$button-small-padding-horizontal: $global-small-gutter !default; -$button-large-padding-horizontal: $global-medium-gutter !default; - -$button-default-background: $global-muted-background !default; -$button-default-color: $global-emphasis-color !default; -$button-default-hover-background: darken($button-default-background, 5%) !default; -$button-default-hover-color: $global-emphasis-color !default; -$button-default-active-background: darken($button-default-background, 10%) !default; -$button-default-active-color: $global-emphasis-color !default; - -$button-primary-background: $global-primary-background !default; -$button-primary-color: $global-inverse-color !default; -$button-primary-hover-background: darken($button-primary-background, 5%) !default; -$button-primary-hover-color: $global-inverse-color !default; -$button-primary-active-background: darken($button-primary-background, 10%) !default; -$button-primary-active-color: $global-inverse-color !default; - -$button-secondary-background: $global-secondary-background !default; -$button-secondary-color: $global-inverse-color !default; -$button-secondary-hover-background: darken($button-secondary-background, 5%) !default; -$button-secondary-hover-color: $global-inverse-color !default; -$button-secondary-active-background: darken($button-secondary-background, 10%) !default; -$button-secondary-active-color: $global-inverse-color !default; - -$button-danger-background: $global-danger-background !default; -$button-danger-color: $global-inverse-color !default; -$button-danger-hover-background: darken($button-danger-background, 5%) !default; -$button-danger-hover-color: $global-inverse-color !default; -$button-danger-active-background: darken($button-danger-background, 10%) !default; -$button-danger-active-color: $global-inverse-color !default; - -$button-disabled-background: $global-muted-background !default; -$button-disabled-color: $global-muted-color !default; - -$button-text-line-height: $global-line-height !default; -$button-text-color: $global-emphasis-color !default; -$button-text-hover-color: $global-muted-color !default; -$button-text-disabled-color: $global-muted-color !default; - -$button-link-line-height: $global-line-height !default; -$button-link-color: $global-emphasis-color !default; -$button-link-hover-color: $global-muted-color !default; -$button-link-hover-text-decoration: none !default; -$button-link-disabled-color: $global-muted-color !default; - - -/* ======================================================================== - Component: Button - ========================================================================== */ - -/* - * 1. Remove margins in Chrome, Safari and Opera. - * 2. Remove borders for `button`. - * 3. Address `overflow` set to `hidden` in IE. - * 4. Correct `font` properties and `color` not being inherited for `button`. - * 5. Remove the inheritance of text transform in Edge, Firefox, and IE. - * 6. Remove default style for `input type="submit"`in iOS. - * 7. Style - * 8. `line-height` is used to create a height because it also centers the text vertically for `a` elements. - * Better would be to use height and flexbox to center the text vertically but flexbox doesn't work in Firefox on `button` elements. - * 9. Align text if button has a width - * 10. Required for `a`. - */ - -.uk-button { - /* 1 */ - margin: 0; - /* 2 */ - border: none; - /* 3 */ - overflow: visible; - /* 4 */ - font: inherit; - color: inherit; - /* 5 */ - text-transform: none; - /* 6 */ - -webkit-appearance: none; - border-radius: 0; - /* 7 */ - display: inline-block; - box-sizing: border-box; - padding: 0 $button-padding-horizontal; - vertical-align: middle; - font-size: $button-font-size; - /* 8 */ - line-height: $button-line-height; - /* 9 */ - text-align: center; - /* 10 */ - text-decoration: none; - @if(mixin-exists(hook-button)) {@include hook-button();} -} - -.uk-button:not(:disabled) { cursor: pointer; } - -/* - * Remove the inner border and padding in Firefox. - */ - -.uk-button::-moz-focus-inner { - border: 0; - padding: 0; -} - -/* Hover */ -.uk-button:hover { - /* 9 */ - text-decoration: none; - @if(mixin-exists(hook-button-hover)) {@include hook-button-hover();} -} - -/* Focus */ -.uk-button:focus { - outline: none; - @if(mixin-exists(hook-button-focus)) {@include hook-button-focus();} -} - -/* OnClick + Active */ -.uk-button:active, -.uk-button.uk-active { - @if(mixin-exists(hook-button-active)) {@include hook-button-active();} -} - - -/* Style modifiers - ========================================================================== */ - -/* - * Default - */ - -.uk-button-default { - background-color: $button-default-background; - color: $button-default-color; - @if(mixin-exists(hook-button-default)) {@include hook-button-default();} -} - -/* Hover + Focus */ -.uk-button-default:hover, -.uk-button-default:focus { - background-color: $button-default-hover-background; - color: $button-default-hover-color; - @if(mixin-exists(hook-button-default-hover)) {@include hook-button-default-hover();} -} - -/* OnClick + Active */ -.uk-button-default:active, -.uk-button-default.uk-active { - background-color: $button-default-active-background; - color: $button-default-active-color; - @if(mixin-exists(hook-button-default-active)) {@include hook-button-default-active();} -} - -/* - * Primary - */ - -.uk-button-primary { - background-color: $button-primary-background; - color: $button-primary-color; - @if(mixin-exists(hook-button-primary)) {@include hook-button-primary();} -} - -/* Hover + Focus */ -.uk-button-primary:hover, -.uk-button-primary:focus { - background-color: $button-primary-hover-background; - color: $button-primary-hover-color; - @if(mixin-exists(hook-button-primary-hover)) {@include hook-button-primary-hover();} -} - -/* OnClick + Active */ -.uk-button-primary:active, -.uk-button-primary.uk-active { - background-color: $button-primary-active-background; - color: $button-primary-active-color; - @if(mixin-exists(hook-button-primary-active)) {@include hook-button-primary-active();} -} - -/* - * Secondary - */ - -.uk-button-secondary { - background-color: $button-secondary-background; - color: $button-secondary-color; - @if(mixin-exists(hook-button-secondary)) {@include hook-button-secondary();} -} - -/* Hover + Focus */ -.uk-button-secondary:hover, -.uk-button-secondary:focus { - background-color: $button-secondary-hover-background; - color: $button-secondary-hover-color; - @if(mixin-exists(hook-button-secondary-hover)) {@include hook-button-secondary-hover();} -} - -/* OnClick + Active */ -.uk-button-secondary:active, -.uk-button-secondary.uk-active { - background-color: $button-secondary-active-background; - color: $button-secondary-active-color; - @if(mixin-exists(hook-button-secondary-active)) {@include hook-button-secondary-active();} -} - -/* - * Danger - */ - -.uk-button-danger { - background-color: $button-danger-background; - color: $button-danger-color; - @if(mixin-exists(hook-button-danger)) {@include hook-button-danger();} -} - -/* Hover + Focus */ -.uk-button-danger:hover, -.uk-button-danger:focus { - background-color: $button-danger-hover-background; - color: $button-danger-hover-color; - @if(mixin-exists(hook-button-danger-hover)) {@include hook-button-danger-hover();} -} - -/* OnClick + Active */ -.uk-button-danger:active, -.uk-button-danger.uk-active { - background-color: $button-danger-active-background; - color: $button-danger-active-color; - @if(mixin-exists(hook-button-danger-active)) {@include hook-button-danger-active();} -} - -/* - * Disabled - * The same for all style modifiers - */ - -.uk-button-default:disabled, -.uk-button-primary:disabled, -.uk-button-secondary:disabled, -.uk-button-danger:disabled { - background-color: $button-disabled-background; - color: $button-disabled-color; - @if(mixin-exists(hook-button-disabled)) {@include hook-button-disabled();} -} - - -/* Size modifiers - ========================================================================== */ - -.uk-button-small { - padding: 0 $button-small-padding-horizontal; - line-height: $button-small-line-height; - font-size: $button-small-font-size; - @if(mixin-exists(hook-button-small)) {@include hook-button-small();} -} - -.uk-button-large { - padding: 0 $button-large-padding-horizontal; - line-height: $button-large-line-height; - font-size: $button-large-font-size; - @if(mixin-exists(hook-button-large)) {@include hook-button-large();} -} - - -/* Text modifiers - ========================================================================== */ - -/* - * Text - * 1. Reset - * 2. Style - */ - -.uk-button-text { - /* 1 */ - padding: 0; - line-height: $button-text-line-height; - background: none; - /* 2 */ - color: $button-text-color; - @if(mixin-exists(hook-button-text)) {@include hook-button-text();} -} - -/* Hover + Focus */ -.uk-button-text:hover, -.uk-button-text:focus { - color: $button-text-hover-color; - @if(mixin-exists(hook-button-text-hover)) {@include hook-button-text-hover();} -} - -/* Disabled */ -.uk-button-text:disabled { - color: $button-text-disabled-color; - @if(mixin-exists(hook-button-text-disabled)) {@include hook-button-text-disabled();} -} - -/* - * Link - * 1. Reset - * 2. Style - */ - -.uk-button-link { - /* 1 */ - padding: 0; - line-height: $button-link-line-height; - background: none; - /* 2 */ - color: $button-link-color; - @if(mixin-exists(hook-button-link)) {@include hook-button-link();} -} - -/* Hover + Focus */ -.uk-button-link:hover, -.uk-button-link:focus { - color: $button-link-hover-color; - text-decoration: $button-link-hover-text-decoration; -} - -/* Disabled */ -.uk-button-link:disabled { - color: $button-link-disabled-color; - text-decoration: none; -} - - -/* Group - ========================================================================== */ - -/* - * 1. Using `flex` instead of `inline-block` to prevent whitespace betweent child elements - * 2. Behave like button - * 3. Create position context - */ - -.uk-button-group { - /* 1 */ - display: inline-flex; - /* 2 */ - vertical-align: middle; - /* 3 */ - position: relative; -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-button-misc)) {@include hook-button-misc();} - -// @mixin hook-button(){} -// @mixin hook-button-hover(){} -// @mixin hook-button-focus(){} -// @mixin hook-button-active(){} -// @mixin hook-button-default(){} -// @mixin hook-button-default-hover(){} -// @mixin hook-button-default-active(){} -// @mixin hook-button-primary(){} -// @mixin hook-button-primary-hover(){} -// @mixin hook-button-primary-active(){} -// @mixin hook-button-secondary(){} -// @mixin hook-button-secondary-hover(){} -// @mixin hook-button-secondary-active(){} -// @mixin hook-button-danger(){} -// @mixin hook-button-danger-hover(){} -// @mixin hook-button-danger-active(){} -// @mixin hook-button-disabled(){} -// @mixin hook-button-small(){} -// @mixin hook-button-large(){} -// @mixin hook-button-text(){} -// @mixin hook-button-text-hover(){} -// @mixin hook-button-text-disabled(){} -// @mixin hook-button-link(){} -// @mixin hook-button-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-button-default-background: $inverse-global-primary-background !default; -$inverse-button-default-color: $inverse-global-inverse-color !default; -$inverse-button-default-hover-background: darken($inverse-button-default-background, 5%) !default; -$inverse-button-default-hover-color: $inverse-global-inverse-color !default; -$inverse-button-default-active-background: darken($inverse-button-default-background, 10%) !default; -$inverse-button-default-active-color: $inverse-global-inverse-color !default; -$inverse-button-primary-background: $inverse-global-primary-background !default; -$inverse-button-primary-color: $inverse-global-inverse-color !default; -$inverse-button-primary-hover-background: darken($inverse-button-primary-background, 5%) !default; -$inverse-button-primary-hover-color: $inverse-global-inverse-color !default; -$inverse-button-primary-active-background: darken($inverse-button-primary-background, 10%) !default; -$inverse-button-primary-active-color: $inverse-global-inverse-color !default; -$inverse-button-secondary-background: $inverse-global-primary-background !default; -$inverse-button-secondary-color: $inverse-global-inverse-color !default; -$inverse-button-secondary-hover-background: darken($inverse-button-secondary-background, 5%) !default; -$inverse-button-secondary-hover-color: $inverse-global-inverse-color !default; -$inverse-button-secondary-active-background: darken($inverse-button-secondary-background, 10%) !default; -$inverse-button-secondary-active-color: $inverse-global-inverse-color !default; -$inverse-button-text-color: $inverse-global-emphasis-color !default; -$inverse-button-text-hover-color: $inverse-global-muted-color !default; -$inverse-button-text-disabled-color: $inverse-global-muted-color !default; -$inverse-button-link-color: $inverse-global-emphasis-color !default; -$inverse-button-link-hover-color: $inverse-global-muted-color !default; - - - -// @mixin hook-inverse-button-default(){} -// @mixin hook-inverse-button-default-hover(){} -// @mixin hook-inverse-button-default-active(){} -// @mixin hook-inverse-button-primary(){} -// @mixin hook-inverse-button-primary-hover(){} -// @mixin hook-inverse-button-primary-active(){} -// @mixin hook-inverse-button-secondary(){} -// @mixin hook-inverse-button-secondary-hover(){} -// @mixin hook-inverse-button-secondary-active(){} -// @mixin hook-inverse-button-text(){} -// @mixin hook-inverse-button-text-hover(){} -// @mixin hook-inverse-button-text-disabled(){} -// @mixin hook-inverse-button-link(){} diff --git a/docs/_sass/uikit/components/card.scss b/docs/_sass/uikit/components/card.scss deleted file mode 100644 index e529cc0eec..0000000000 --- a/docs/_sass/uikit/components/card.scss +++ /dev/null @@ -1,384 +0,0 @@ -// Name: Card -// Description: Component to create boxed content containers -// -// Component: `uk-card` -// -// Sub-objects: `uk-card-body` -// `uk-card-header` -// `uk-card-footer` -// `uk-card-media-*` -// `uk-card-title` -// `uk-card-badge` -// -// Modifiers: `uk-card-hover` -// `uk-card-default` -// `uk-card-primary` -// `uk-card-secondary` -// `uk-card-small` -// `uk-card-large` -// -// Uses: `uk-grid-stack` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$card-body-padding-horizontal: $global-gutter !default; -$card-body-padding-vertical: $global-gutter !default; - -$card-body-padding-horizontal-l: $global-medium-gutter !default; -$card-body-padding-vertical-l: $global-medium-gutter !default; - -$card-header-padding-horizontal: $global-gutter !default; -$card-header-padding-vertical: round($global-gutter / 2) !default; - -$card-header-padding-horizontal-l: $global-medium-gutter !default; -$card-header-padding-vertical-l: round($global-medium-gutter / 2) !default; - -$card-footer-padding-horizontal: $global-gutter !default; -$card-footer-padding-vertical: ($global-gutter / 2) !default; - -$card-footer-padding-horizontal-l: $global-medium-gutter !default; -$card-footer-padding-vertical-l: round($global-medium-gutter / 2) !default; - -$card-title-font-size: $global-large-font-size !default; -$card-title-line-height: 1.4 !default; - -$card-badge-top: 15px !default; -$card-badge-right: 15px !default; -$card-badge-height: 22px !default; -$card-badge-padding-horizontal: 10px !default; -$card-badge-background: $global-primary-background !default; -$card-badge-color: $global-inverse-color !default; -$card-badge-font-size: $global-small-font-size !default; - -$card-hover-background: $global-muted-background !default; - -$card-default-background: $global-muted-background !default; -$card-default-color: $global-color !default; -$card-default-title-color: $global-emphasis-color !default; -$card-default-hover-background: darken($card-default-background, 5%) !default; - -$card-primary-background: $global-primary-background !default; -$card-primary-color: $global-inverse-color !default; -$card-primary-title-color: $card-primary-color !default; -$card-primary-hover-background: darken($card-primary-background, 5%) !default; -$card-primary-color-mode: light !default; - -$card-secondary-background: $global-secondary-background !default; -$card-secondary-color: $global-inverse-color !default; -$card-secondary-title-color: $card-secondary-color !default; -$card-secondary-hover-background: darken($card-secondary-background, 5%) !default; -$card-secondary-color-mode: light !default; - -$card-small-body-padding-horizontal: $global-margin !default; -$card-small-body-padding-vertical: $global-margin !default; -$card-small-header-padding-horizontal: $global-margin !default; -$card-small-header-padding-vertical: round($global-margin / 1.5) !default; -$card-small-footer-padding-horizontal: $global-margin !default; -$card-small-footer-padding-vertical: round($global-margin / 1.5) !default; - -$card-large-body-padding-horizontal-l: $global-large-gutter !default; -$card-large-body-padding-vertical-l: $global-large-gutter !default; -$card-large-header-padding-horizontal-l: $global-large-gutter !default; -$card-large-header-padding-vertical-l: round($global-large-gutter / 2) !default; -$card-large-footer-padding-horizontal-l: $global-large-gutter !default; -$card-large-footer-padding-vertical-l: round($global-large-gutter / 2) !default; - - -/* ======================================================================== - Component: Card - ========================================================================== */ - -.uk-card { - position: relative; - box-sizing: border-box; - @if(mixin-exists(hook-card)) {@include hook-card();} -} - - -/* Sections - ========================================================================== */ - -.uk-card-body { - display: flow-root; - padding: $card-body-padding-vertical $card-body-padding-horizontal; - @if(mixin-exists(hook-card-body)) {@include hook-card-body();} -} - -.uk-card-header { - display: flow-root; - padding: $card-header-padding-vertical $card-header-padding-horizontal; - @if(mixin-exists(hook-card-header)) {@include hook-card-header();} -} - -.uk-card-footer { - display: flow-root; - padding: $card-footer-padding-vertical $card-footer-padding-horizontal; - @if(mixin-exists(hook-card-footer)) {@include hook-card-footer();} -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-card-body { padding: $card-body-padding-vertical-l $card-body-padding-horizontal-l; } - - .uk-card-header { padding: $card-header-padding-vertical-l $card-header-padding-horizontal-l; } - - .uk-card-footer { padding: $card-footer-padding-vertical-l $card-footer-padding-horizontal-l; } - -} - -/* - * Remove margin from the last-child - */ - -.uk-card-body > :last-child, -.uk-card-header > :last-child, -.uk-card-footer > :last-child { margin-bottom: 0; } - - -/* Media - ========================================================================== */ - -/* - * Reserved alignment modifier to style the media element, e.g. with `border-radius` - * Implemented by the theme - */ - -[class*='uk-card-media'] { - @if(mixin-exists(hook-card-media)) {@include hook-card-media();} -} - -.uk-card-media-top, -.uk-grid-stack > .uk-card-media-left, -.uk-grid-stack > .uk-card-media-right { - @if(mixin-exists(hook-card-media-top)) {@include hook-card-media-top();} -} - -.uk-card-media-bottom { - @if(mixin-exists(hook-card-media-bottom)) {@include hook-card-media-bottom();} -} - -:not(.uk-grid-stack) > .uk-card-media-left { - @if(mixin-exists(hook-card-media-left)) {@include hook-card-media-left();} -} - -:not(.uk-grid-stack) > .uk-card-media-right { - @if(mixin-exists(hook-card-media-right)) {@include hook-card-media-right();} -} - - -/* Title - ========================================================================== */ - -.uk-card-title { - font-size: $card-title-font-size; - line-height: $card-title-line-height; - @if(mixin-exists(hook-card-title)) {@include hook-card-title();} -} - - -/* Badge - ========================================================================== */ - -/* - * 1. Position - * 2. Size - * 3. Style - * 4. Center child vertically - */ - -.uk-card-badge { - /* 1 */ - position: absolute; - top: $card-badge-top; - right: $card-badge-right; - z-index: 1; - /* 2 */ - height: $card-badge-height; - padding: 0 $card-badge-padding-horizontal; - /* 3 */ - background: $card-badge-background; - color: $card-badge-color; - font-size: $card-badge-font-size; - /* 4 */ - display: flex; - justify-content: center; - align-items: center; - line-height: 0; - @if(mixin-exists(hook-card-badge)) {@include hook-card-badge();} -} - -/* - * Remove margin from adjacent element - */ - -.uk-card-badge:first-child + * { margin-top: 0; } - - -/* Hover modifier - ========================================================================== */ - -.uk-card-hover:not(.uk-card-default):not(.uk-card-primary):not(.uk-card-secondary):hover { - background: $card-hover-background; - @if(mixin-exists(hook-card-hover)) {@include hook-card-hover();} -} - - -/* Style modifiers - ========================================================================== */ - -/* - * Default - * Note: Header and Footer are only implemented for the default style - */ - -.uk-card-default { - background: $card-default-background; - color: $card-default-color; - @if(mixin-exists(hook-card-default)) {@include hook-card-default();} -} - -.uk-card-default .uk-card-title { - color: $card-default-title-color; - @if(mixin-exists(hook-card-default-title)) {@include hook-card-default-title();} -} - -.uk-card-default.uk-card-hover:hover { - background-color: $card-default-hover-background; - @if(mixin-exists(hook-card-default-hover)) {@include hook-card-default-hover();} -} - -.uk-card-default .uk-card-header { - @if(mixin-exists(hook-card-default-header)) {@include hook-card-default-header();} -} - -.uk-card-default .uk-card-footer { - @if(mixin-exists(hook-card-default-footer)) {@include hook-card-default-footer();} -} - -/* - * Primary - */ - -.uk-card-primary { - background: $card-primary-background; - color: $card-primary-color; - @if(mixin-exists(hook-card-primary)) {@include hook-card-primary();} -} - -.uk-card-primary .uk-card-title { - color: $card-primary-title-color; - @if(mixin-exists(hook-card-primary-title)) {@include hook-card-primary-title();} -} - -.uk-card-primary.uk-card-hover:hover { - background-color: $card-primary-hover-background; - @if(mixin-exists(hook-card-primary-hover)) {@include hook-card-primary-hover();} -} - -// Color Mode -@if ( $card-primary-color-mode == light ) { .uk-card-primary.uk-card-body { @extend .uk-light !optional;} } -@if ( $card-primary-color-mode == light ) { .uk-card-primary > :not([class*='uk-card-media']) { @extend .uk-light !optional;} } -@if ( $card-primary-color-mode == dark ) { .uk-card-primary.uk-card-body { @extend .uk-dark !optional;} } -@if ( $card-primary-color-mode == dark ) { .uk-card-primary > :not([class*='uk-card-media']) { @extend .uk-dark !optional;} } - -/* - * Secondary - */ - -.uk-card-secondary { - background: $card-secondary-background; - color: $card-secondary-color; - @if(mixin-exists(hook-card-secondary)) {@include hook-card-secondary();} -} - -.uk-card-secondary .uk-card-title { - color: $card-secondary-title-color; - @if(mixin-exists(hook-card-secondary-title)) {@include hook-card-secondary-title();} -} - -.uk-card-secondary.uk-card-hover:hover { - background-color: $card-secondary-hover-background; - @if(mixin-exists(hook-card-secondary-hover)) {@include hook-card-secondary-hover();} -} - -// Color Mode -@if ( $card-secondary-color-mode == light ) { .uk-card-secondary.uk-card-body { @extend .uk-light !optional;} } -@if ( $card-secondary-color-mode == light ) { .uk-card-secondary > :not([class*='uk-card-media']) { @extend .uk-light !optional;} } -@if ( $card-secondary-color-mode == dark ) { .uk-card-secondary.uk-card-body { @extend .uk-dark !optional;} } -@if ( $card-secondary-color-mode == dark ) { .uk-card-secondary > :not([class*='uk-card-media']) { @extend .uk-dark !optional;} } - - -/* Size modifier - ========================================================================== */ - -/* - * Small - */ - -.uk-card-small.uk-card-body, -.uk-card-small .uk-card-body { padding: $card-small-body-padding-vertical $card-small-body-padding-horizontal; } - -.uk-card-small .uk-card-header { padding: $card-small-header-padding-vertical $card-small-header-padding-horizontal; } -.uk-card-small .uk-card-footer { padding: $card-small-footer-padding-vertical $card-small-footer-padding-horizontal; } - -/* - * Large - */ - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-card-large.uk-card-body, - .uk-card-large .uk-card-body { padding: $card-large-body-padding-vertical-l $card-large-body-padding-horizontal-l; } - - .uk-card-large .uk-card-header { padding: $card-large-header-padding-vertical-l $card-large-header-padding-horizontal-l; } - .uk-card-large .uk-card-footer { padding: $card-large-footer-padding-vertical-l $card-large-footer-padding-horizontal-l; } - -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-card-misc)) {@include hook-card-misc();} - -// @mixin hook-card(){} -// @mixin hook-card-body(){} -// @mixin hook-card-header(){} -// @mixin hook-card-footer(){} -// @mixin hook-card-media(){} -// @mixin hook-card-media-top(){} -// @mixin hook-card-media-bottom(){} -// @mixin hook-card-media-left(){} -// @mixin hook-card-media-right(){} -// @mixin hook-card-title(){} -// @mixin hook-card-badge(){} -// @mixin hook-card-hover(){} -// @mixin hook-card-default(){} -// @mixin hook-card-default-title(){} -// @mixin hook-card-default-hover(){} -// @mixin hook-card-default-header(){} -// @mixin hook-card-default-footer(){} -// @mixin hook-card-primary(){} -// @mixin hook-card-primary-title(){} -// @mixin hook-card-primary-hover(){} -// @mixin hook-card-secondary(){} -// @mixin hook-card-secondary-title(){} -// @mixin hook-card-secondary-hover(){} -// @mixin hook-card-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-card-badge-background: $inverse-global-primary-background !default; -$inverse-card-badge-color: $inverse-global-inverse-color !default; - - - -// @mixin hook-inverse-card-badge(){} diff --git a/docs/_sass/uikit/components/close.scss b/docs/_sass/uikit/components/close.scss deleted file mode 100644 index 32e2775642..0000000000 --- a/docs/_sass/uikit/components/close.scss +++ /dev/null @@ -1,57 +0,0 @@ -// Name: Close -// Description: Component to create a close button -// -// Component: `uk-close` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$close-color: $global-muted-color !default; -$close-hover-color: $global-color !default; - - -/* ======================================================================== - Component: Close - ========================================================================== */ - -/* - * Adopts `uk-icon` - */ - -.uk-close { - color: $close-color; - @if(mixin-exists(hook-close)) {@include hook-close();} -} - -/* Hover + Focus */ -.uk-close:hover, -.uk-close:focus { - color: $close-hover-color; - outline: none; - @if(mixin-exists(hook-close-hover)) {@include hook-close-hover();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-close-misc)) {@include hook-close-misc();} - -// @mixin hook-close(){} -// @mixin hook-close-hover(){} -// @mixin hook-close-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-close-color: $inverse-global-muted-color !default; -$inverse-close-hover-color: $inverse-global-color !default; - - - -// @mixin hook-inverse-close(){} -// @mixin hook-inverse-close-hover(){} diff --git a/docs/_sass/uikit/components/column.scss b/docs/_sass/uikit/components/column.scss deleted file mode 100644 index 54bae26e37..0000000000 --- a/docs/_sass/uikit/components/column.scss +++ /dev/null @@ -1,138 +0,0 @@ -// Name: Column -// Description: Utilities for text columns -// -// Component: `uk-column-*` -// -// Sub-objects: `uk-column-span` -// -// Modifiers: `uk-column-divider` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$column-gutter: $global-gutter !default; -$column-gutter-l: $global-medium-gutter !default; - -$column-divider-rule-color: $global-border !default; -$column-divider-rule-width: 1px !default; - - -/* ======================================================================== - Component: Column - ========================================================================== */ - -[class*='uk-column-'] { column-gap: $column-gutter; } - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - [class*='uk-column-'] { column-gap: $column-gutter-l; } - -} - -/* - * Fix image 1px line wrapping into the next column in Chrome - */ - -[class*='uk-column-'] img { transform: translate3d(0,0,0); } - - -/* Divider - ========================================================================== */ - -/* - * 1. Double the column gap - */ - -.uk-column-divider { - column-rule: $column-divider-rule-width solid $column-divider-rule-color; - /* 1 */ - column-gap: ($column-gutter * 2); -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-column-divider { - column-gap: ($column-gutter-l * 2); - } - -} - - -/* Width modifiers - ========================================================================== */ - -.uk-column-1-2 { column-count: 2;} -.uk-column-1-3 { column-count: 3; } -.uk-column-1-4 { column-count: 4; } -.uk-column-1-5 { column-count: 5; } -.uk-column-1-6 { column-count: 6; } - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-column-1-2\@s { column-count: 2; } - .uk-column-1-3\@s { column-count: 3; } - .uk-column-1-4\@s { column-count: 4; } - .uk-column-1-5\@s { column-count: 5; } - .uk-column-1-6\@s { column-count: 6; } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-column-1-2\@m { column-count: 2; } - .uk-column-1-3\@m { column-count: 3; } - .uk-column-1-4\@m { column-count: 4; } - .uk-column-1-5\@m { column-count: 5; } - .uk-column-1-6\@m { column-count: 6; } - -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-column-1-2\@l { column-count: 2; } - .uk-column-1-3\@l { column-count: 3; } - .uk-column-1-4\@l { column-count: 4; } - .uk-column-1-5\@l { column-count: 5; } - .uk-column-1-6\@l { column-count: 6; } - -} - -/* Large screen and bigger */ -@media (min-width: $breakpoint-xlarge) { - - .uk-column-1-2\@xl { column-count: 2; } - .uk-column-1-3\@xl { column-count: 3; } - .uk-column-1-4\@xl { column-count: 4; } - .uk-column-1-5\@xl { column-count: 5; } - .uk-column-1-6\@xl { column-count: 6; } - -} - -/* Make element span across all columns - * Does not work in Firefox yet - ========================================================================== */ - -.uk-column-span { column-span: all; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-column-misc)) {@include hook-column-misc();} - -// @mixin hook-column-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-column-divider-rule-color: $inverse-global-border !default; - diff --git a/docs/_sass/uikit/components/comment.scss b/docs/_sass/uikit/components/comment.scss deleted file mode 100644 index 212b096016..0000000000 --- a/docs/_sass/uikit/components/comment.scss +++ /dev/null @@ -1,160 +0,0 @@ -// Name: Comment -// Description: Component to create nested comments -// -// Component: `uk-comment` -// -// Sub-objects: `uk-comment-body` -// `uk-comment-header` -// `uk-comment-title` -// `uk-comment-meta` -// `uk-comment-avatar` -// `uk-comment-list` -// -// Modifier: `uk-comment-primary` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$comment-header-margin-bottom: $global-margin !default; - -$comment-title-font-size: $global-medium-font-size !default; -$comment-title-line-height: 1.4 !default; - -$comment-meta-font-size: $global-small-font-size !default; -$comment-meta-line-height: 1.4 !default; -$comment-meta-color: $global-muted-color !default; - -$comment-list-margin-top: $global-large-margin !default; -$comment-list-padding-left: 30px !default; -$comment-list-padding-left-m: 100px !default; - - -/* ======================================================================== - Component: Comment - ========================================================================== */ - -.uk-comment { - @if(mixin-exists(hook-comment)) {@include hook-comment();} -} - - -/* Sections - ========================================================================== */ - -.uk-comment-body { - display: flow-root; - overflow-wrap: break-word; - word-wrap: break-word; - @if(mixin-exists(hook-comment-body)) {@include hook-comment-body();} -} - -.uk-comment-header { - display: flow-root; - margin-bottom: $comment-header-margin-bottom; - @if(mixin-exists(hook-comment-header)) {@include hook-comment-header();} -} - -/* - * Remove margin from the last-child - */ - -.uk-comment-body > :last-child, -.uk-comment-header > :last-child { margin-bottom: 0; } - - -/* Title - ========================================================================== */ - -.uk-comment-title { - font-size: $comment-title-font-size; - line-height: $comment-title-line-height; - @if(mixin-exists(hook-comment-title)) {@include hook-comment-title();} -} - - -/* Meta - ========================================================================== */ - -.uk-comment-meta { - font-size: $comment-meta-font-size; - line-height: $comment-meta-line-height; - color: $comment-meta-color; - @if(mixin-exists(hook-comment-meta)) {@include hook-comment-meta();} -} - - -/* Avatar - ========================================================================== */ - -.uk-comment-avatar { - @if(mixin-exists(hook-comment-avatar)) {@include hook-comment-avatar();} -} - - -/* List - ========================================================================== */ - -.uk-comment-list { - padding: 0; - list-style: none; -} - -/* Adjacent siblings */ -.uk-comment-list > :nth-child(n+2) { - margin-top: $comment-list-margin-top; - @if(mixin-exists(hook-comment-list-adjacent)) {@include hook-comment-list-adjacent();} -} - -/* - * Sublists - * Note: General sibling selector allows reply block between comment and sublist - */ - -.uk-comment-list .uk-comment ~ ul { - margin: $comment-list-margin-top 0 0 0; - padding-left: $comment-list-padding-left; - list-style: none; - @if(mixin-exists(hook-comment-list-sub)) {@include hook-comment-list-sub();} -} - -/* Tablet and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-comment-list .uk-comment ~ ul { padding-left: $comment-list-padding-left-m; } - -} - -/* Adjacent siblings */ -.uk-comment-list .uk-comment ~ ul > :nth-child(n+2) { - margin-top: $comment-list-margin-top; - @if(mixin-exists(hook-comment-list-sub-adjacent)) {@include hook-comment-list-sub-adjacent();} -} - - -/* Style modifier - ========================================================================== */ - -.uk-comment-primary { - @if(mixin-exists(hook-comment-primary)) {@include hook-comment-primary();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-comment-misc)) {@include hook-comment-misc();} - -// @mixin hook-comment(){} -// @mixin hook-comment-body(){} -// @mixin hook-comment-header(){} -// @mixin hook-comment-title(){} -// @mixin hook-comment-meta(){} -// @mixin hook-comment-avatar(){} -// @mixin hook-comment-list-adjacent(){} -// @mixin hook-comment-list-sub(){} -// @mixin hook-comment-list-sub-adjacent(){} -// @mixin hook-comment-primary(){} -// @mixin hook-comment-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/container.scss b/docs/_sass/uikit/components/container.scss deleted file mode 100644 index dcf798a220..0000000000 --- a/docs/_sass/uikit/components/container.scss +++ /dev/null @@ -1,185 +0,0 @@ -// Name: Container -// Description: Component to align and center your site and grid content -// -// Component: `uk-container` -// -// Modifier: `uk-container-small` -// `uk-container-large` -// `uk-container-expand` -// `uk-container-expand-left` -// `uk-container-expand-right` -// `uk-container-item-padding-remove-left` -// `uk-container-item-padding-remove-right` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$container-max-width: 1200px !default; -$container-xsmall-max-width: 750px !default; -$container-small-max-width: 900px !default; -$container-large-max-width: 1400px !default; -$container-xlarge-max-width: 1600px !default; - -$container-padding-horizontal: 15px !default; -$container-padding-horizontal-s: $global-gutter !default; -$container-padding-horizontal-m: $global-medium-gutter !default; - - -/* ======================================================================== - Component: Container - ========================================================================== */ - -/* - * 1. Box sizing has to be `content-box` so the max-width is always the same and - * unaffected by the padding on different breakpoints. It's important for the size modifiers. - */ - -.uk-container { - display: flow-root; - /* 1 */ - box-sizing: content-box; - max-width: $container-max-width; - margin-left: auto; - margin-right: auto; - padding-left: $container-padding-horizontal; - padding-right: $container-padding-horizontal; -} - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-container { - padding-left: $container-padding-horizontal-s; - padding-right: $container-padding-horizontal-s; - } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-container { - padding-left: $container-padding-horizontal-m; - padding-right: $container-padding-horizontal-m; - } - -} - -/* - * Remove margin from the last-child - */ - -.uk-container > :last-child { margin-bottom: 0; } - -/* - * Remove padding from nested containers - */ - -.uk-container .uk-container { - padding-left: 0; - padding-right: 0; -} - - -/* Size modifier - ========================================================================== */ - -.uk-container-xsmall { max-width: $container-xsmall-max-width; } - -.uk-container-small { max-width: $container-small-max-width; } - -.uk-container-large { max-width: $container-large-max-width; } - -.uk-container-xlarge { max-width: $container-xlarge-max-width; } - -.uk-container-expand { max-width: none; } - - -/* Expand modifier - ========================================================================== */ - -/* - * Expand one side only - */ - -.uk-container-expand-left { margin-left: 0; } -.uk-container-expand-right { margin-right: 0; } - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-container-expand-left.uk-container-xsmall, - .uk-container-expand-right.uk-container-xsmall { max-width: unquote('calc(50% + (#{$container-xsmall-max-width} / 2) - #{$container-padding-horizontal-s})'); } - - .uk-container-expand-left.uk-container-small, - .uk-container-expand-right.uk-container-small { max-width: unquote('calc(50% + (#{$container-small-max-width} / 2) - #{$container-padding-horizontal-s})'); } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-container-expand-left, - .uk-container-expand-right { max-width: unquote('calc(50% + (#{$container-max-width} / 2) - #{$container-padding-horizontal-m})'); } - - .uk-container-expand-left.uk-container-xsmall, - .uk-container-expand-right.uk-container-xsmall { max-width: unquote('calc(50% + (#{$container-xsmall-max-width} / 2) - #{$container-padding-horizontal-m})'); } - - .uk-container-expand-left.uk-container-small, - .uk-container-expand-right.uk-container-small { max-width: unquote('calc(50% + (#{$container-small-max-width} / 2) - #{$container-padding-horizontal-m})'); } - - .uk-container-expand-left.uk-container-large, - .uk-container-expand-right.uk-container-large { max-width: unquote('calc(50% + (#{$container-large-max-width} / 2) - #{$container-padding-horizontal-m})'); } - - .uk-container-expand-left.uk-container-xlarge, - .uk-container-expand-right.uk-container-xlarge { max-width: unquote('calc(50% + (#{$container-xlarge-max-width} / 2) - #{$container-padding-horizontal-m})'); } - -} - - -/* Item - ========================================================================== */ - -/* - * Utility classes to reset container padding on the left or right side - * Note: It has to be negative margin on the item, because it's specific to the item. - */ - -.uk-container-item-padding-remove-left, -.uk-container-item-padding-remove-right { width: unquote('calc(100% + #{$container-padding-horizontal})') } - -.uk-container-item-padding-remove-left { margin-left: (-$container-padding-horizontal); } -.uk-container-item-padding-remove-right { margin-right: (-$container-padding-horizontal); } - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-container-item-padding-remove-left, - .uk-container-item-padding-remove-right { width: unquote('calc(100% + #{$container-padding-horizontal-s})') } - - .uk-container-item-padding-remove-left { margin-left: (-$container-padding-horizontal-s); } - .uk-container-item-padding-remove-right { margin-right: (-$container-padding-horizontal-s); } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-container-item-padding-remove-left, - .uk-container-item-padding-remove-right { width: unquote('calc(100% + #{$container-padding-horizontal-m})') } - - .uk-container-item-padding-remove-left { margin-left: (-$container-padding-horizontal-m); } - .uk-container-item-padding-remove-right { margin-right: (-$container-padding-horizontal-m); } - -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-container-misc)) {@include hook-container-misc();} - -// @mixin hook-container-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/countdown.scss b/docs/_sass/uikit/components/countdown.scss deleted file mode 100644 index b01209d711..0000000000 --- a/docs/_sass/uikit/components/countdown.scss +++ /dev/null @@ -1,131 +0,0 @@ -// Name: Countdown -// Description: Component to create countdown timers -// -// Component: `uk-countdown` -// -// Sub-objects: `uk-countdown-number` -// `uk-countdown-separator` -// `uk-countdown-label` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$countdown-number-line-height: 0.8 !default; -$countdown-number-font-size: 2rem !default; // 32px -$countdown-number-font-size-s: 4rem !default; // 64px -$countdown-number-font-size-m: 6rem !default; // 96px - -$countdown-separator-line-height: 1.6 !default; -$countdown-separator-font-size: 1rem !default; // 16px -$countdown-separator-font-size-s: 2rem !default; // 32px -$countdown-separator-font-size-m: 3rem !default; // 48px - - -/* ======================================================================== - Component: Countdown - ========================================================================== */ - -.uk-countdown { - @if(mixin-exists(hook-countdown)) {@include hook-countdown();} -} - - -/* Item - ========================================================================== */ - -.uk-countdown-number, -.uk-countdown-separator { - @if(mixin-exists(hook-countdown-item)) {@include hook-countdown-item();} -} - - -/* Number - ========================================================================== */ - - -/* - * 1. Make numbers all of the same size to prevent jumping. Must be supported by the font. - * 2. Style - */ - -.uk-countdown-number { - /* 1 */ - font-variant-numeric: tabular-nums; - /* 2 */ - font-size: $countdown-number-font-size; - line-height: $countdown-number-line-height; - @if(mixin-exists(hook-countdown-number)) {@include hook-countdown-number();} -} - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-countdown-number { font-size: $countdown-number-font-size-s; } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-countdown-number { font-size: $countdown-number-font-size-m; } - -} - - -/* Separator - ========================================================================== */ - -.uk-countdown-separator { - font-size: $countdown-separator-font-size; - line-height: $countdown-separator-line-height; - @if(mixin-exists(hook-countdown-separator)) {@include hook-countdown-separator();} -} - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-countdown-separator { font-size: $countdown-separator-font-size-s; } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-countdown-separator { font-size: $countdown-separator-font-size-m; } - -} - - -/* Label - ========================================================================== */ - -.uk-countdown-label { - @if(mixin-exists(hook-countdown-label)) {@include hook-countdown-label();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-countdown-misc)) {@include hook-countdown-misc();} - -// @mixin hook-countdown(){} -// @mixin hook-countdown-item(){} -// @mixin hook-countdown-number(){} -// @mixin hook-countdown-separator(){} -// @mixin hook-countdown-label(){} -// @mixin hook-countdown-misc(){} - - -// Inverse -// ======================================================================== - - - -// @mixin hook-inverse-countdown-item(){} -// @mixin hook-inverse-countdown-number(){} -// @mixin hook-inverse-countdown-separator(){} -// @mixin hook-inverse-countdown-label(){} diff --git a/docs/_sass/uikit/components/cover.scss b/docs/_sass/uikit/components/cover.scss deleted file mode 100644 index b44a6847d5..0000000000 --- a/docs/_sass/uikit/components/cover.scss +++ /dev/null @@ -1,57 +0,0 @@ -// Name: Cover -// Description: Utilities to let embedded content cover their container in a centered position -// -// Component: `uk-cover` -// -// Sub-object: `uk-cover-container` -// -// ======================================================================== - - -/* ======================================================================== - Component: Cover - ========================================================================== */ - -/* - * Works with iframes and embedded content - * 1. Reset responsiveness for embedded content - * 2. Center object - * Note: Percent values on the `top` property only works if this element - * is absolute positioned or if the container has a height - */ - -.uk-cover { - /* 1 */ - max-width: none; - /* 2 */ - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%,-50%); -} - -iframe.uk-cover { pointer-events: none; } - - -/* Container - ========================================================================== */ - -/* - * 1. Parent container which clips resized object - * 2. Needed if the child is positioned absolute. See note above - */ - -.uk-cover-container { - /* 1 */ - overflow: hidden; - /* 2 */ - position: relative; -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-cover-misc)) {@include hook-cover-misc();} - -// @mixin hook-cover-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/description-list.scss b/docs/_sass/uikit/components/description-list.scss deleted file mode 100644 index 6683286dfd..0000000000 --- a/docs/_sass/uikit/components/description-list.scss +++ /dev/null @@ -1,71 +0,0 @@ -// Name: Description list -// Description: Styles for description lists -// -// Component: `uk-description-list` -// -// Modifiers: `uk-description-list-divider` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$description-list-term-color: $global-emphasis-color !default; -$description-list-term-margin-top: $global-margin !default; - -$description-list-divider-term-margin-top: $global-margin !default; -$description-list-divider-term-border-width: $global-border-width !default; -$description-list-divider-term-border: $global-border !default; - - -/* ======================================================================== - Component: Description list - ========================================================================== */ - -/* - * Term - */ - -.uk-description-list > dt { - color: $description-list-term-color; - @if(mixin-exists(hook-description-list-term)) {@include hook-description-list-term();} -} - -.uk-description-list > dt:nth-child(n+2) { - margin-top: $description-list-term-margin-top; -} - -/* - * Description - */ - -.uk-description-list > dd { - @if(mixin-exists(hook-description-list-description)) {@include hook-description-list-description();} -} - - -/* Style modifier - ========================================================================== */ - -/* - * Line - */ - -.uk-description-list-divider > dt:nth-child(n+2) { - margin-top: $description-list-divider-term-margin-top; - padding-top: $description-list-divider-term-margin-top; - border-top: $description-list-divider-term-border-width solid $description-list-divider-term-border; - @if(mixin-exists(hook-description-list-divider-term)) {@include hook-description-list-divider-term();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-description-list-misc)) {@include hook-description-list-misc();} - -// @mixin hook-description-list-term(){} -// @mixin hook-description-list-description(){} -// @mixin hook-description-list-divider-term(){} -// @mixin hook-description-list-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/divider.scss b/docs/_sass/uikit/components/divider.scss deleted file mode 100644 index 104fcdb48d..0000000000 --- a/docs/_sass/uikit/components/divider.scss +++ /dev/null @@ -1,153 +0,0 @@ -// Name: Divider -// Description: Styles for dividers -// -// Component: `uk-divider-icon` -// `uk-divider-small` -// `uk-divider-vertical` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$divider-margin-vertical: $global-margin !default; - -$divider-icon-width: 50px !default; -$divider-icon-height: 20px !default; -$divider-icon-color: $global-border !default; -$divider-icon-line-top: 50% !default; -$divider-icon-line-width: 100% !default; -$divider-icon-line-border-width: $global-border-width !default; -$divider-icon-line-border: $global-border !default; - -$internal-divider-icon-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default; - -$divider-small-width: 100px !default; -$divider-small-border-width: $global-border-width !default; -$divider-small-border: $global-border !default; - -$divider-vertical-height: 100px !default; -$divider-vertical-border-width: $global-border-width !default; -$divider-vertical-border: $global-border !default; - - -/* ======================================================================== - Component: Divider - ========================================================================== */ - -/* - * 1. Reset default `hr` - * 2. Set margin if a `div` is used for semantical reason - */ - -[class*='uk-divider'] { - /* 1 */ - border: none; - /* 2 */ - margin-bottom: $divider-margin-vertical; -} - -/* Add margin if adjacent element */ -* + [class*='uk-divider'] { margin-top: $divider-margin-vertical; } - - -/* Icon - ========================================================================== */ - -.uk-divider-icon { - position: relative; - height: $divider-icon-height; - @include svg-fill($internal-divider-icon-image, "#000", $divider-icon-color); - background-repeat: no-repeat; - background-position: 50% 50%; - @if(mixin-exists(hook-divider-icon)) {@include hook-divider-icon();} -} - -.uk-divider-icon::before, -.uk-divider-icon::after { - content: ""; - position: absolute; - top: $divider-icon-line-top; - max-width: unquote('calc(50% - (#{$divider-icon-width} / 2))'); - border-bottom: $divider-icon-line-border-width solid $divider-icon-line-border; - @if(mixin-exists(hook-divider-icon-line)) {@include hook-divider-icon-line();} -} - -.uk-divider-icon::before { - right: unquote('calc(50% + (#{$divider-icon-width} / 2))'); - width: $divider-icon-line-width; - @if(mixin-exists(hook-divider-icon-line-left)) {@include hook-divider-icon-line-left();} -} - -.uk-divider-icon::after { - left: unquote('calc(50% + (#{$divider-icon-width} / 2))'); - width: $divider-icon-line-width; - @if(mixin-exists(hook-divider-icon-line-right)) {@include hook-divider-icon-line-right();} -} - - -/* Small - ========================================================================== */ - -/* - * 1. Fix height because of `inline-block` - * 2. Using ::after and inline-block to make `text-align` work - */ - -/* 1 */ -.uk-divider-small { line-height: 0; } - -/* 2 */ -.uk-divider-small::after { - content: ""; - display: inline-block; - width: $divider-small-width; - max-width: 100%; - border-top: $divider-small-border-width solid $divider-small-border; - vertical-align: top; - @if(mixin-exists(hook-divider-small)) {@include hook-divider-small();} -} - - -/* Vertical - ========================================================================== */ - -.uk-divider-vertical { - width: 1px; - height: $divider-vertical-height; - margin-left: auto; - margin-right: auto; - border-left: $divider-vertical-border-width solid $divider-vertical-border; - @if(mixin-exists(hook-divider-vertical)) {@include hook-divider-vertical();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-divider-misc)) {@include hook-divider-misc();} - -// @mixin hook-divider-icon(){} -// @mixin hook-divider-icon-line(){} -// @mixin hook-divider-icon-line-left(){} -// @mixin hook-divider-icon-line-right(){} -// @mixin hook-divider-small(){} -// @mixin hook-divider-vertical(){} -// @mixin hook-divider-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-divider-icon-color: $inverse-global-border !default; -$inverse-divider-icon-line-border: $inverse-global-border !default; -$inverse-divider-small-border: $inverse-global-border !default; -$inverse-divider-vertical-border: $inverse-global-border !default; - - - -// @mixin hook-inverse-divider-icon(){} -// @mixin hook-inverse-divider-icon-line(){} -// @mixin hook-inverse-divider-small(){} -// @mixin hook-inverse-divider-vertical(){} diff --git a/docs/_sass/uikit/components/dotnav.scss b/docs/_sass/uikit/components/dotnav.scss deleted file mode 100644 index f1f2a4029c..0000000000 --- a/docs/_sass/uikit/components/dotnav.scss +++ /dev/null @@ -1,157 +0,0 @@ -// Name: Dotnav -// Description: Component to create dot navigations -// -// Component: `uk-dotnav` -// -// Modifier: `uk-dotnav-vertical` -// -// States: `uk-active` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$dotnav-margin-horizontal: 12px !default; -$dotnav-margin-vertical: $dotnav-margin-horizontal !default; - -$dotnav-item-width: 10px !default; -$dotnav-item-height: $dotnav-item-width !default; -$dotnav-item-border-radius: 50% !default; - -$dotnav-item-background: rgba($global-color, 0.2) !default; -$dotnav-item-hover-background: rgba($global-color, 0.6) !default; -$dotnav-item-onclick-background: rgba($global-color, 0.2) !default; -$dotnav-item-active-background: rgba($global-color, 0.6) !default; - - -/* ======================================================================== - Component: Dotnav - ========================================================================== */ - -/* - * 1. Allow items to wrap into the next line - * 2. Reset list - * 3. Gutter - */ - -.uk-dotnav { - display: flex; - /* 1 */ - flex-wrap: wrap; - /* 2 */ - margin: 0; - padding: 0; - list-style: none; - /* 3 */ - margin-left: (-$dotnav-margin-horizontal); - @if(mixin-exists(hook-dotnav)) {@include hook-dotnav();} -} - -/* - * 1. Space is allocated solely based on content dimensions: 0 0 auto - * 2. Gutter - */ - -.uk-dotnav > * { - /* 1 */ - flex: none; - /* 2 */ - padding-left: $dotnav-margin-horizontal; -} - - -/* Items - ========================================================================== */ - -/* - * Items - * 1. Hide text if present - */ - -.uk-dotnav > * > * { - display: block; - box-sizing: border-box; - width: $dotnav-item-width; - height: $dotnav-item-height; - border-radius: $dotnav-item-border-radius; - background: $dotnav-item-background; - /* 1 */ - text-indent: 100%; - overflow: hidden; - white-space: nowrap; - @if(mixin-exists(hook-dotnav-item)) {@include hook-dotnav-item();} -} - -/* Hover + Focus */ -.uk-dotnav > * > :hover, -.uk-dotnav > * > :focus { - background-color: $dotnav-item-hover-background; - outline: none; - @if(mixin-exists(hook-dotnav-item-hover)) {@include hook-dotnav-item-hover();} -} - -/* OnClick */ -.uk-dotnav > * > :active { - background-color: $dotnav-item-onclick-background; - @if(mixin-exists(hook-dotnav-item-onclick)) {@include hook-dotnav-item-onclick();} -} - -/* Active */ -.uk-dotnav > .uk-active > * { - background-color: $dotnav-item-active-background; - @if(mixin-exists(hook-dotnav-item-active)) {@include hook-dotnav-item-active();} -} - - -/* Modifier: 'uk-dotnav-vertical' - ========================================================================== */ - -/* - * 1. Change direction - * 2. Gutter - */ - -.uk-dotnav-vertical { - /* 1 */ - flex-direction: column; - /* 2 */ - margin-left: 0; - margin-top: (-$dotnav-margin-vertical); -} - -/* 2 */ -.uk-dotnav-vertical > * { - padding-left: 0; - padding-top: $dotnav-margin-vertical; -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-dotnav-misc)) {@include hook-dotnav-misc();} - -// @mixin hook-dotnav(){} -// @mixin hook-dotnav-item(){} -// @mixin hook-dotnav-item-hover(){} -// @mixin hook-dotnav-item-onclick(){} -// @mixin hook-dotnav-item-active(){} -// @mixin hook-dotnav-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-dotnav-item-background: rgba($inverse-global-color, 0.5) !default; -$inverse-dotnav-item-hover-background: rgba($inverse-global-color, 0.9) !default; -$inverse-dotnav-item-onclick-background: rgba($inverse-global-color, 0.5) !default; -$inverse-dotnav-item-active-background: rgba($inverse-global-color, 0.9) !default; - - - -// @mixin hook-inverse-dotnav-item(){} -// @mixin hook-inverse-dotnav-item-hover(){} -// @mixin hook-inverse-dotnav-item-onclick(){} -// @mixin hook-inverse-dotnav-item-active(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/drop.scss b/docs/_sass/uikit/components/drop.scss deleted file mode 100644 index fb5e9e8c5a..0000000000 --- a/docs/_sass/uikit/components/drop.scss +++ /dev/null @@ -1,74 +0,0 @@ -// Name: Drop -// Description: Component to position any element next to any other element. -// -// Component: `uk-drop` -// -// Modifiers: `uk-drop-top-*` -// `uk-drop-bottom-*` -// `uk-drop-left-*` -// `uk-drop-right-*` -// `uk-drop-stack` -// `uk-drop-grid` -// -// States: `uk-open` -// -// Uses: Animation -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$drop-z-index: $global-z-index + 20 !default; -$drop-width: 300px !default; -$drop-margin: $global-margin !default; - - -/* ======================================================================== - Component: Drop - ========================================================================== */ - -/* - * 1. Hide by default - * 2. Set position - * 3. Set a default width - */ - -.uk-drop { - /* 1 */ - display: none; - /* 2 */ - position: absolute; - z-index: $drop-z-index; - /* 3 */ - box-sizing: border-box; - width: $drop-width; -} - -/* Show */ -.uk-drop.uk-open { display: block; } - - -/* Direction / Alignment modifiers - ========================================================================== */ - -/* Direction */ -[class*='uk-drop-top'] { margin-top: (-$drop-margin); } -[class*='uk-drop-bottom'] { margin-top: $drop-margin; } -[class*='uk-drop-left'] { margin-left: (-$drop-margin); } -[class*='uk-drop-right'] { margin-left: $drop-margin; } - - -/* Grid modifiers - ========================================================================== */ - -.uk-drop-stack .uk-drop-grid > * { width: 100% !important; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-drop-misc)) {@include hook-drop-misc();} - -// @mixin hook-drop-misc(){} diff --git a/docs/_sass/uikit/components/dropdown.scss b/docs/_sass/uikit/components/dropdown.scss deleted file mode 100644 index 25af1079d2..0000000000 --- a/docs/_sass/uikit/components/dropdown.scss +++ /dev/null @@ -1,153 +0,0 @@ -// Name: Dropdown -// Description: Component to create dropdown menus -// -// Component: `uk-dropdown` -// -// Adopted: `uk-dropdown-nav` -// -// Modifiers: `uk-dropdown-top-*` -// `uk-dropdown-bottom-*` -// `uk-dropdown-left-*` -// `uk-dropdown-right-*` -// `uk-dropdown-stack` -// `uk-dropdown-grid` -// -// States: `uk-active` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$dropdown-z-index: $global-z-index + 20 !default; -$dropdown-min-width: 200px !default; -$dropdown-padding: 15px !default; -$dropdown-background: $global-muted-background !default; -$dropdown-color: $global-color !default; -$dropdown-margin: $global-small-margin !default; - -$dropdown-nav-item-color: $global-muted-color !default; -$dropdown-nav-item-hover-color: $global-color !default; -$dropdown-nav-header-color: $global-emphasis-color !default; -$dropdown-nav-divider-border-width: $global-border-width !default; -$dropdown-nav-divider-border: $global-border !default; -$dropdown-nav-sublist-item-color: $global-muted-color !default; -$dropdown-nav-sublist-item-hover-color: $global-color !default; - - -/* ======================================================================== - Component: Dropdown - ========================================================================== */ - -/* - * 1. Hide by default - * 2. Set position - * 3. Set a default width - * 4. Style - */ - -.uk-dropdown { - /* 1 */ - display: none; - /* 2 */ - position: absolute; - z-index: $dropdown-z-index; - /* 3 */ - box-sizing: border-box; - min-width: $dropdown-min-width; - /* 4 */ - padding: $dropdown-padding; - background: $dropdown-background; - color: $dropdown-color; - @if(mixin-exists(hook-dropdown)) {@include hook-dropdown();} -} - -/* Show */ -.uk-dropdown.uk-open { display: block; } - - -/* Nav - * Adopts `uk-nav` - ========================================================================== */ - -.uk-dropdown-nav { - white-space: nowrap; - @if(mixin-exists(hook-dropdown-nav)) {@include hook-dropdown-nav();} -} - -/* - * Items - */ - -.uk-dropdown-nav > li > a { - color: $dropdown-nav-item-color; - @if(mixin-exists(hook-dropdown-nav-item)) {@include hook-dropdown-nav-item();} -} - -/* Hover + Focus + Active */ -.uk-dropdown-nav > li > a:hover, -.uk-dropdown-nav > li > a:focus, -.uk-dropdown-nav > li.uk-active > a { - color: $dropdown-nav-item-hover-color; - @if(mixin-exists(hook-dropdown-nav-item-hover)) {@include hook-dropdown-nav-item-hover();} -} - -/* - * Header - */ - -.uk-dropdown-nav .uk-nav-header { - color: $dropdown-nav-header-color; - @if(mixin-exists(hook-dropdown-nav-header)) {@include hook-dropdown-nav-header();} -} - -/* - * Divider - */ - -.uk-dropdown-nav .uk-nav-divider { - border-top: $dropdown-nav-divider-border-width solid $dropdown-nav-divider-border; - @if(mixin-exists(hook-dropdown-nav-divider)) {@include hook-dropdown-nav-divider();} -} - -/* - * Sublists - */ - -.uk-dropdown-nav .uk-nav-sub a { color: $dropdown-nav-sublist-item-color; } - -.uk-dropdown-nav .uk-nav-sub a:hover, -.uk-dropdown-nav .uk-nav-sub a:focus, -.uk-dropdown-nav .uk-nav-sub li.uk-active > a { color: $dropdown-nav-sublist-item-hover-color; } - - -/* Direction / Alignment modifiers - ========================================================================== */ - -/* Direction */ -[class*='uk-dropdown-top'] { margin-top: (-$dropdown-margin); } -[class*='uk-dropdown-bottom'] { margin-top: $dropdown-margin; } -[class*='uk-dropdown-left'] { margin-left: (-$dropdown-margin); } -[class*='uk-dropdown-right'] { margin-left: $dropdown-margin; } - - -/* Grid modifiers - ========================================================================== */ - -.uk-dropdown-stack .uk-dropdown-grid > * { width: 100% !important; } - - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-dropdown-misc)) {@include hook-dropdown-misc();} - -// @mixin hook-dropdown(){} -// @mixin hook-dropdown-nav(){} -// @mixin hook-dropdown-nav-item(){} -// @mixin hook-dropdown-nav-item-hover(){} -// @mixin hook-dropdown-nav-header(){} -// @mixin hook-dropdown-nav-divider(){} -// @mixin hook-dropdown-misc(){} diff --git a/docs/_sass/uikit/components/flex.scss b/docs/_sass/uikit/components/flex.scss deleted file mode 100644 index 1301fc4335..0000000000 --- a/docs/_sass/uikit/components/flex.scss +++ /dev/null @@ -1,209 +0,0 @@ -// Name: Flex -// Description: Utilities for layouts based on flexbox -// -// Component: `uk-flex-*` -// -// ======================================================================== - - -/* ======================================================================== - Component: Flex - ========================================================================== */ - -.uk-flex { display: flex; } -.uk-flex-inline { display: inline-flex; } - -/* - * Remove pseudo elements created by micro clearfix as precaution - */ - -.uk-flex::before, -.uk-flex::after, -.uk-flex-inline::before, -.uk-flex-inline::after { display: none; } - - -/* Alignment - ========================================================================== */ - -/* - * Align items along the main axis of the current line of the flex container - * Row: Horizontal - */ - -// Default -.uk-flex-left { justify-content: flex-start; } -.uk-flex-center { justify-content: center; } -.uk-flex-right { justify-content: flex-end; } -.uk-flex-between { justify-content: space-between; } -.uk-flex-around { justify-content: space-around; } - - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-flex-left\@s { justify-content: flex-start; } - .uk-flex-center\@s { justify-content: center; } - .uk-flex-right\@s { justify-content: flex-end; } - .uk-flex-between\@s { justify-content: space-between; } - .uk-flex-around\@s { justify-content: space-around; } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-flex-left\@m { justify-content: flex-start; } - .uk-flex-center\@m { justify-content: center; } - .uk-flex-right\@m { justify-content: flex-end; } - .uk-flex-between\@m { justify-content: space-between; } - .uk-flex-around\@m { justify-content: space-around; } - -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-flex-left\@l { justify-content: flex-start; } - .uk-flex-center\@l { justify-content: center; } - .uk-flex-right\@l { justify-content: flex-end; } - .uk-flex-between\@l { justify-content: space-between; } - .uk-flex-around\@l { justify-content: space-around; } - -} - -/* Large screen and bigger */ -@media (min-width: $breakpoint-xlarge) { - - .uk-flex-left\@xl { justify-content: flex-start; } - .uk-flex-center\@xl { justify-content: center; } - .uk-flex-right\@xl { justify-content: flex-end; } - .uk-flex-between\@xl { justify-content: space-between; } - .uk-flex-around\@xl { justify-content: space-around; } - -} - -/* - * Align items in the cross axis of the current line of the flex container - * Row: Vertical - */ - -// Default -.uk-flex-stretch { align-items: stretch; } -.uk-flex-top { align-items: flex-start; } -.uk-flex-middle { align-items: center; } -.uk-flex-bottom { align-items: flex-end; } - - -/* Direction - ========================================================================== */ - -// Default -.uk-flex-row { flex-direction: row; } -.uk-flex-row-reverse { flex-direction: row-reverse; } -.uk-flex-column { flex-direction: column; } -.uk-flex-column-reverse { flex-direction: column-reverse; } - - -/* Wrap - ========================================================================== */ - -// Default -.uk-flex-nowrap { flex-wrap: nowrap; } -.uk-flex-wrap { flex-wrap: wrap; } -.uk-flex-wrap-reverse { flex-wrap: wrap-reverse; } - -/* - * Aligns items within the flex container when there is extra space in the cross-axis - * Only works if there is more than one line of flex items - */ - -// Default -.uk-flex-wrap-stretch { align-content: stretch; } -.uk-flex-wrap-top { align-content: flex-start; } -.uk-flex-wrap-middle { align-content: center; } -.uk-flex-wrap-bottom { align-content: flex-end; } -.uk-flex-wrap-between { align-content: space-between; } -.uk-flex-wrap-around { align-content: space-around; } - - -/* Item ordering - ========================================================================== */ - -/* - * Default is 0 - */ - -.uk-flex-first { order: -1;} -.uk-flex-last { order: 99;} - - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-flex-first\@s { order: -1; } - .uk-flex-last\@s { order: 99; } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-flex-first\@m { order: -1; } - .uk-flex-last\@m { order: 99; } - -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-flex-first\@l { order: -1; } - .uk-flex-last\@l { order: 99; } - -} - -/* Large screen and bigger */ -@media (min-width: $breakpoint-xlarge) { - - .uk-flex-first\@xl { order: -1; } - .uk-flex-last\@xl { order: 99; } - -} - - -/* Item dimensions - ========================================================================== */ - -/* - * Initial: 0 1 auto - * Content dimensions, but shrinks - */ - -/* - * No Flex: 0 0 auto - * Content dimensions - */ - -.uk-flex-none { flex: none; } - -/* - * Relative Flex: 1 1 auto - * Space is allocated considering content - */ - -.uk-flex-auto { flex: auto; } - -/* - * Absolute Flex: 1 1 0% - * Space is allocated solely based on flex - */ - -.uk-flex-1 { flex: 1; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-flex-misc)) {@include hook-flex-misc();} - -// @mixin hook-flex-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/form-range.scss b/docs/_sass/uikit/components/form-range.scss deleted file mode 100644 index 328f08fc3e..0000000000 --- a/docs/_sass/uikit/components/form-range.scss +++ /dev/null @@ -1,186 +0,0 @@ -// Name: Form Range -// Description: Styles for the range input type -// -// Component: `uk-range` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$form-range-thumb-height: 15px !default; -$form-range-thumb-width: $form-range-thumb-height !default; -$form-range-thumb-border-radius: 500px !default; -$form-range-thumb-background: $global-color !default; - -$form-range-track-height: 3px !default; -$form-range-track-background: darken($global-muted-background, 5%) !default; -$form-range-track-focus-background: darken($form-range-track-background, 5%) !default; - - -/* ======================================================================== - Component: Form Range - ========================================================================== */ - -/* - * 1. Normalize and defaults - * 2. Prevent content overflow if a fixed width is used - * 3. Take the full width - * 4. Remove default style - * 5. Remove white background in Chrome - * 6. Remove padding in IE11 - */ - -.uk-range { - /* 1 */ - box-sizing: border-box; - margin: 0; - vertical-align: middle; - /* 2 */ - max-width: 100%; - /* 3 */ - width: 100%; - /* 4 */ - -webkit-appearance: none; - /* 5 */ - background: transparent; - /* 6 */ - padding: 0; - @if(mixin-exists(hook-form-range)) {@include hook-form-range();} -} - -/* Focus */ -.uk-range:focus { outline: none; } -.uk-range::-moz-focus-outer { border: none; } - -/* IE11 Reset */ -.uk-range::-ms-track { - height: $form-range-thumb-height; - background: transparent; - border-color: transparent; - color: transparent; -} - -/* - * Improves consistency of cursor style for clickable elements - */ - -.uk-range:not(:disabled)::-webkit-slider-thumb { cursor: pointer; } -.uk-range:not(:disabled)::-moz-range-thumb { cursor: pointer; } -.uk-range:not(:disabled)::-ms-thumb { cursor: pointer; } - - -/* Thumb - ========================================================================== */ - -/* - * 1. Reset - * 2. Style - */ - -/* Webkit */ -.uk-range::-webkit-slider-thumb { - /* 1 */ - -webkit-appearance: none; - margin-top: (floor($form-range-thumb-height / 2) * -1); - /* 2 */ - height: $form-range-thumb-height; - width: $form-range-thumb-width; - border-radius: $form-range-thumb-border-radius; - background: $form-range-thumb-background; - @if(mixin-exists(hook-form-range-thumb)) {@include hook-form-range-thumb();} -} - -/* Firefox */ -.uk-range::-moz-range-thumb { - /* 1 */ - border: none; - /* 2 */ - height: $form-range-thumb-height; - width: $form-range-thumb-width; - border-radius: $form-range-thumb-border-radius; - background: $form-range-thumb-background; - @if(mixin-exists(hook-form-range-thumb)) {@include hook-form-range-thumb();} -} - -/* Edge */ -.uk-range::-ms-thumb { - /* 1 */ - margin-top: 0; -} - -/* IE11 */ -.uk-range::-ms-thumb { - /* 1 */ - border: none; - /* 2 */ - height: $form-range-thumb-height; - width: $form-range-thumb-width; - border-radius: $form-range-thumb-border-radius; - background: $form-range-thumb-background; - @if(mixin-exists(hook-form-range-thumb)) {@include hook-form-range-thumb();} -} - -/* Edge + IE11 */ -.uk-range::-ms-tooltip { display: none; } - - -/* Track - ========================================================================== */ - -/* - * 1. Safari doesn't have a focus state. Using active instead. - */ - -/* Webkit */ -.uk-range::-webkit-slider-runnable-track { - height: $form-range-track-height; - background: $form-range-track-background; - @if(mixin-exists(hook-form-range-track)) {@include hook-form-range-track();} -} - -.uk-range:focus::-webkit-slider-runnable-track, -/* 1 */ -.uk-range:active::-webkit-slider-runnable-track { - background: $form-range-track-focus-background; - @if(mixin-exists(hook-form-range-track-focus)) {@include hook-form-range-track-focus();} -} - -/* Firefox */ -.uk-range::-moz-range-track { - height: $form-range-track-height; - background: $form-range-track-background; - @if(mixin-exists(hook-form-range-track)) {@include hook-form-range-track();} -} - -.uk-range:focus::-moz-range-track { - background: $form-range-track-focus-background; - @if(mixin-exists(hook-form-range-track-focus)) {@include hook-form-range-track-focus();} -} - -/* Edge */ -.uk-range::-ms-fill-lower, -.uk-range::-ms-fill-upper { - height: $form-range-track-height; - background: $form-range-track-background; - @if(mixin-exists(hook-form-range-track)) {@include hook-form-range-track();} -} - -.uk-range:focus::-ms-fill-lower, -.uk-range:focus::-ms-fill-upper { - background: $form-range-track-focus-background; - @if(mixin-exists(hook-form-range-track-focus)) {@include hook-form-range-track-focus();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-form-range-misc)) {@include hook-form-range-misc();} - -// @mixin hook-form-range(){} -// @mixin hook-form-range-thumb(){} -// @mixin hook-form-range-track(){} -// @mixin hook-form-range-track-focus(){} -// @mixin hook-form-range-misc(){} diff --git a/docs/_sass/uikit/components/form.scss b/docs/_sass/uikit/components/form.scss deleted file mode 100644 index 08fe9920ae..0000000000 --- a/docs/_sass/uikit/components/form.scss +++ /dev/null @@ -1,811 +0,0 @@ -// Name: Form -// Description: Styles for forms -// -// Component: `uk-form-*` -// `uk-input` -// `uk-select` -// `uk-textarea` -// `uk-radio` -// `uk-checkbox` -// `uk-legend` -// `uk-fieldset` -// -// Sub-objects: `uk-form-custom` -// `uk-form-stacked` -// `uk-form-horizontal` -// `uk-form-label` -// `uk-form-controls` -// `uk-form-icon` -// `uk-form-icon-flip` -// -// Modifiers: `uk-form-small` -// `uk-form-large` -// `uk-form-danger` -// `uk-form-success` -// `uk-form-blank` -// `uk-form-width-xsmall` -// `uk-form-width-small` -// `uk-form-width-medium` -// `uk-form-width-large` -// `uk-form-controls-text` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$form-height: $global-control-height !default; -$form-line-height: $form-height !default; -$form-padding-horizontal: 10px !default; -$form-padding-vertical: round($form-padding-horizontal * 0.6) !default; - -$form-background: $global-muted-background !default; -$form-color: $global-color !default; - -$form-focus-background: darken($form-background, 5%) !default; -$form-focus-color: $global-color !default; - -$form-disabled-background: $global-muted-background !default; -$form-disabled-color: $global-muted-color !default; - -$form-placeholder-color: $global-muted-color !default; - -$form-small-height: $global-control-small-height !default; -$form-small-padding-horizontal: 8px !default; -$form-small-padding-vertical: round($form-small-padding-horizontal * 0.6) !default; -$form-small-line-height: $form-small-height !default; -$form-small-font-size: $global-small-font-size !default; - -$form-large-height: $global-control-large-height !default; -$form-large-padding-horizontal: 12px !default; -$form-large-padding-vertical: round($form-large-padding-horizontal * 0.6) !default; -$form-large-line-height: $form-large-height !default; -$form-large-font-size: $global-medium-font-size !default; - -$form-danger-color: $global-danger-background !default; -$form-success-color: $global-success-background !default; - -$form-width-xsmall: 50px !default; -$form-width-small: 130px !default; -$form-width-medium: 200px !default; -$form-width-large: 500px !default; - -$form-select-padding-right: 20px !default; -$form-select-icon-color: $global-color !default; -$form-select-option-color: #444 !default; -$form-select-disabled-icon-color: $global-muted-color !default; - -$form-datalist-padding-right: 20px !default; -$form-datalist-icon-color: $global-color !default; - -$form-radio-size: 16px !default; -$form-radio-margin-top: -4px !default; -$form-radio-background: darken($global-muted-background, 5%) !default; - -$form-radio-focus-background: darken($form-radio-background, 5%) !default; - -$form-radio-checked-background: $global-primary-background !default; -$form-radio-checked-icon-color: $global-inverse-color !default; - -$form-radio-checked-focus-background: darken($global-primary-background, 10%) !default; - -$form-radio-disabled-background: $global-muted-background !default; -$form-radio-disabled-icon-color: $global-muted-color !default; - -$form-legend-font-size: $global-large-font-size !default; -$form-legend-line-height: 1.4 !default; - -$form-stacked-margin-bottom: $global-small-margin !default; - -$form-horizontal-label-width: 200px !default; -$form-horizontal-label-margin-top: 7px !default; -$form-horizontal-controls-margin-left: 215px !default; -$form-horizontal-controls-text-padding-top: 7px !default; - -$form-icon-width: $form-height !default; -$form-icon-color: $global-muted-color !default; -$form-icon-hover-color: $global-color !default; - -$internal-form-select-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default; -$internal-form-datalist-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%2012%208%206%2016%206%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default; -$internal-form-radio-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22#000%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$internal-form-checkbox-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default; -$internal-form-checkbox-indeterminate-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; - - -/* ======================================================================== - Component: Form - ========================================================================== */ - -/* - * 1. Define consistent box sizing. - * Default is `content-box` with following exceptions set to `border-box` - * `select`, `input[type="checkbox"]` and `input[type="radio"]` - * `input[type="search"]` in Chrome, Safari and Opera - * `input[type="color"]` in Firefox - * 2. Address margins set differently in Firefox/IE and Chrome/Safari/Opera. - * 3. Remove `border-radius` in iOS. - * 4. Change font properties to `inherit` in all browsers. - */ - -.uk-input, -.uk-select, -.uk-textarea, -.uk-radio, -.uk-checkbox { - /* 1 */ - box-sizing: border-box; - /* 2 */ - margin: 0; - /* 3 */ - border-radius: 0; - /* 4 */ - font: inherit; -} - -/* - * Show the overflow in Edge. - */ - -.uk-input { overflow: visible; } - -/* - * Remove the inheritance of text transform in Firefox. - */ - -.uk-select { text-transform: none; } - -/* - * 1. Change font properties to `inherit` in all browsers - * 2. Don't inherit the `font-weight` and use `bold` instead. - * NOTE: Both declarations don't work in Chrome, Safari and Opera. - */ - -.uk-select optgroup { - /* 1 */ - font: inherit; - /* 2 */ - font-weight: bold; -} - -/* - * Remove the default vertical scrollbar in IE 10+. - */ - -.uk-textarea { overflow: auto; } - -/* - * Remove the inner padding and cancel buttons in Chrome on OS X and Safari on OS X. - */ - -.uk-input[type="search"]::-webkit-search-cancel-button, -.uk-input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } - - -/* - * Correct the cursor style of increment and decrement buttons in Chrome. - */ - -.uk-input[type="number"]::-webkit-inner-spin-button, -.uk-input[type="number"]::-webkit-outer-spin-button { height: auto; } - -/* - * Removes placeholder transparency in Firefox. - */ - -.uk-input::-moz-placeholder, -.uk-textarea::-moz-placeholder { opacity: 1; } - -/* - * Improves consistency of cursor style for clickable elements - */ - -.uk-radio:not(:disabled), -.uk-checkbox:not(:disabled) { cursor: pointer; } - -/* - * Define consistent border, margin, and padding. - */ - -.uk-fieldset { - border: none; - margin: 0; - padding: 0; -} - - -/* Input, select and textarea - * Allowed: `text`, `password`, `datetime`, `datetime-local`, `date`, `month`, - `time`, `week`, `number`, `email`, `url`, `search`, `tel`, `color` - * Disallowed: `range`, `radio`, `checkbox`, `file`, `submit`, `reset` and `image` - ========================================================================== */ - -/* - * Remove default style in iOS. - */ - -.uk-input, -.uk-textarea { -webkit-appearance: none; } - -/* - * 1. Prevent content overflow if a fixed width is used - * 2. Take the full width - * 3. Reset default - * 4. Style - */ - -.uk-input, -.uk-select, -.uk-textarea { - /* 1 */ - max-width: 100%; - /* 2 */ - width: 100%; - /* 3 */ - border: 0 none; - /* 4 */ - padding: 0 $form-padding-horizontal; - background: $form-background; - color: $form-color; - @if(mixin-exists(hook-form)) {@include hook-form();} -} - -/* - * Single-line - * 1. Allow any element to look like an `input` or `select` element - * 2. Make sure line-height is not larger than height - * Also needed to center the text vertically - */ - -.uk-input, -.uk-select:not([multiple]):not([size]) { - height: $form-height; - vertical-align: middle; - /* 1 */ - display: inline-block; - @if(mixin-exists(hook-form-single-line)) {@include hook-form-single-line();} -} - -/* 2 */ -.uk-input:not(input), -.uk-select:not(select) { line-height: $form-line-height; } - -/* - * Multi-line - */ - -.uk-select[multiple], -.uk-select[size], -.uk-textarea { - padding-top: $form-padding-vertical; - padding-bottom: $form-padding-vertical; - vertical-align: top; - @if(mixin-exists(hook-form-multi-line)) {@include hook-form-multi-line();} -} - -.uk-select[multiple], -.uk-select[size] { resize: vertical; } - -/* Focus */ -.uk-input:focus, -.uk-select:focus, -.uk-textarea:focus { - outline: none; - background-color: $form-focus-background; - color: $form-focus-color; - @if(mixin-exists(hook-form-focus)) {@include hook-form-focus();} -} - -/* Disabled */ -.uk-input:disabled, -.uk-select:disabled, -.uk-textarea:disabled { - background-color: $form-disabled-background; - color: $form-disabled-color; - @if(mixin-exists(hook-form-disabled)) {@include hook-form-disabled();} -} - -/* - * Placeholder - */ - -.uk-input::-ms-input-placeholder { color: $form-placeholder-color !important; } -.uk-input::placeholder { color: $form-placeholder-color; } - -.uk-textarea::-ms-input-placeholder { color: $form-placeholder-color !important; } -.uk-textarea::placeholder { color: $form-placeholder-color; } - - -/* Style modifier (`uk-input`, `uk-select` and `uk-textarea`) - ========================================================================== */ - -/* - * Small - */ - -.uk-form-small { font-size: $form-small-font-size; } - -/* Single-line */ -.uk-form-small:not(textarea):not([multiple]):not([size]) { - height: $form-small-height; - padding-left: $form-small-padding-horizontal; - padding-right: $form-small-padding-horizontal; -} - -/* Multi-line */ -textarea.uk-form-small, -[multiple].uk-form-small, -[size].uk-form-small { padding: $form-small-padding-vertical $form-small-padding-horizontal; } - -.uk-form-small:not(select):not(input):not(textarea) { line-height: $form-small-line-height; } - -/* - * Large - */ - -.uk-form-large { font-size: $form-large-font-size; } - -/* Single-line */ -.uk-form-large:not(textarea):not([multiple]):not([size]) { - height: $form-large-height; - padding-left: $form-large-padding-horizontal; - padding-right: $form-large-padding-horizontal; -} - -/* Multi-line */ -textarea.uk-form-large, -[multiple].uk-form-large, -[size].uk-form-large { padding: $form-large-padding-vertical $form-large-padding-horizontal; } - -.uk-form-large:not(select):not(input):not(textarea) { line-height: $form-large-line-height; } - - -/* Style modifier (`uk-input`, `uk-select` and `uk-textarea`) - ========================================================================== */ - -/* - * Error - */ - -.uk-form-danger, -.uk-form-danger:focus { - color: $form-danger-color; - @if(mixin-exists(hook-form-danger)) {@include hook-form-danger();} -} - -/* - * Success - */ - -.uk-form-success, -.uk-form-success:focus { - color: $form-success-color; - @if(mixin-exists(hook-form-success)) {@include hook-form-success();} -} - -/* - * Blank - */ - -.uk-form-blank { - background: none; - @if(mixin-exists(hook-form-blank)) {@include hook-form-blank();} -} - -.uk-form-blank:focus { - @if(mixin-exists(hook-form-blank-focus)) {@include hook-form-blank-focus();} -} - - -/* Width modifiers (`uk-input`, `uk-select` and `uk-textarea`) - ========================================================================== */ - -/* - * Fixed widths - * Different widths for mini sized `input` and `select` elements - */ - -input.uk-form-width-xsmall { width: $form-width-xsmall; } - -select.uk-form-width-xsmall { width: ($form-width-xsmall + 25px); } - -.uk-form-width-small { width: $form-width-small; } - -.uk-form-width-medium { width: $form-width-medium; } - -.uk-form-width-large { width: $form-width-large; } - - -/* Select - ========================================================================== */ - -/* - * 1. Remove default style. Also works in Firefox - * 2. Style - * 3. Remove default style in IE 10/11 - * 4. Set `color` for options in the select dropdown, because the inherited `color` might be too light. - */ - -.uk-select:not([multiple]):not([size]) { - /* 1 */ - -webkit-appearance: none; - -moz-appearance: none; - /* 2 */ - padding-right: $form-select-padding-right; - @include svg-fill($internal-form-select-image, "#000", $form-select-icon-color); - background-repeat: no-repeat; - background-position: 100% 50%; -} - -/* 3 */ -.uk-select:not([multiple]):not([size])::-ms-expand { display: none; } - -/* 4 */ -.uk-select:not([multiple]):not([size]) option { color: $form-select-option-color; } - -/* - * Disabled - */ - -.uk-select:not([multiple]):not([size]):disabled { @include svg-fill($internal-form-select-image, "#000", $form-select-disabled-icon-color); } - - -/* Datalist - ========================================================================== */ - -/* - * 1. Remove default style in Chrome - */ - - .uk-input[list] { - padding-right: $form-datalist-padding-right; - background-repeat: no-repeat; - background-position: 100% 50%; -} - -.uk-input[list]:hover, -.uk-input[list]:focus { @include svg-fill($internal-form-datalist-image, "#000", $form-datalist-icon-color); } - -/* 1 */ -.uk-input[list]::-webkit-calendar-picker-indicator { display: none !important; } - - -/* Radio and checkbox - * Note: Does not work in IE11 - ========================================================================== */ - -/* - * 1. Style - * 2. Make box more robust so it clips the child element - * 3. Vertical alignment - * 4. Remove default style - * 5. Fix black background on iOS - * 6. Center icons - */ - -.uk-radio, -.uk-checkbox { - /* 1 */ - display: inline-block; - height: $form-radio-size; - width: $form-radio-size; - /* 2 */ - overflow: hidden; - /* 3 */ - margin-top: $form-radio-margin-top; - vertical-align: middle; - /* 4 */ - -webkit-appearance: none; - -moz-appearance: none; - /* 5 */ - background-color: $form-radio-background; - /* 6 */ - background-repeat: no-repeat; - background-position: 50% 50%; - @if(mixin-exists(hook-form-radio)) {@include hook-form-radio();} -} - -.uk-radio { border-radius: 50%; } - -/* Focus */ -.uk-radio:focus, -.uk-checkbox:focus { - background-color: $form-radio-focus-background; - outline: none; - @if(mixin-exists(hook-form-radio-focus)) {@include hook-form-radio-focus();} -} - -/* - * Checked - */ - -.uk-radio:checked, -.uk-checkbox:checked, -.uk-checkbox:indeterminate { - background-color: $form-radio-checked-background; - @if(mixin-exists(hook-form-radio-checked)) {@include hook-form-radio-checked();} -} - -/* Focus */ -.uk-radio:checked:focus, -.uk-checkbox:checked:focus, -.uk-checkbox:indeterminate:focus { - background-color: $form-radio-checked-focus-background; - @if(mixin-exists(hook-form-radio-checked-focus)) {@include hook-form-radio-checked-focus();} -} - -/* - * Icons - */ - -.uk-radio:checked { @include svg-fill($internal-form-radio-image, "#000", $form-radio-checked-icon-color); } -.uk-checkbox:checked { @include svg-fill($internal-form-checkbox-image, "#000", $form-radio-checked-icon-color); } -.uk-checkbox:indeterminate { @include svg-fill($internal-form-checkbox-indeterminate-image, "#000", $form-radio-checked-icon-color); } - -/* - * Disabled - */ - -.uk-radio:disabled, -.uk-checkbox:disabled { - background-color: $form-radio-disabled-background; - @if(mixin-exists(hook-form-radio-disabled)) {@include hook-form-radio-disabled();} -} - -.uk-radio:disabled:checked { @include svg-fill($internal-form-radio-image, "#000", $form-radio-disabled-icon-color); } -.uk-checkbox:disabled:checked { @include svg-fill($internal-form-checkbox-image, "#000", $form-radio-disabled-icon-color); } -.uk-checkbox:disabled:indeterminate { @include svg-fill($internal-form-checkbox-indeterminate-image, "#000", $form-radio-disabled-icon-color); } - - -/* Legend - ========================================================================== */ - -/* - * Legend - * 1. Behave like block element - * 2. Correct the color inheritance from `fieldset` elements in IE. - * 3. Remove padding so people aren't caught out if they zero out fieldsets. - * 4. Style - */ - -.uk-legend { - /* 1 */ - width: 100%; - /* 2 */ - color: inherit; - /* 3 */ - padding: 0; - /* 4 */ - font-size: $form-legend-font-size; - line-height: $form-legend-line-height; - @if(mixin-exists(hook-form-legend)) {@include hook-form-legend();} -} - - -/* Custom controls - ========================================================================== */ - -/* - * 1. Container fits its content - * 2. Create position context - * 3. Prevent content overflow - * 4. Behave like most inline-block elements - */ - -.uk-form-custom { - /* 1 */ - display: inline-block; - /* 2 */ - position: relative; - /* 3 */ - max-width: 100%; - /* 4 */ - vertical-align: middle; -} - -/* - * 1. Position and resize the form control to always cover its container - * 2. Required for Firefox for positioning to the left - * 3. Required for Webkit to make `height` work - * 4. Hide controle and show cursor - * 5. Needed for the cursor - * 6. Clip height caused by 5. Needed for Webkit only - */ - -.uk-form-custom select, -.uk-form-custom input[type="file"] { - /* 1 */ - position: absolute; - top: 0; - z-index: 1; - width: 100%; - height: 100%; - /* 2 */ - left: 0; - /* 3 */ - -webkit-appearance: none; - /* 4 */ - opacity: 0; - cursor: pointer; -} - -.uk-form-custom input[type="file"] { - /* 5 */ - font-size: 500px; - /* 6 */ - overflow: hidden; -} - - -/* Label - ========================================================================== */ - -.uk-form-label { - @if(mixin-exists(hook-form-label)) {@include hook-form-label();} -} - - -/* Layout - ========================================================================== */ - -/* - * Stacked - */ - -.uk-form-stacked .uk-form-label { - display: block; - margin-bottom: $form-stacked-margin-bottom; - @if(mixin-exists(hook-form-stacked-label)) {@include hook-form-stacked-label();} -} - -/* - * Horizontal - */ - -/* Tablet portrait and smaller */ -@media (max-width: $breakpoint-small-max) { - - /* Behave like `uk-form-stacked` */ - .uk-form-horizontal .uk-form-label { - display: block; - margin-bottom: $form-stacked-margin-bottom; - @if(mixin-exists(hook-form-stacked-label)) {@include hook-form-stacked-label();} - } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-form-horizontal .uk-form-label { - width: $form-horizontal-label-width; - margin-top: $form-horizontal-label-margin-top; - float: left; - @if(mixin-exists(hook-form-horizontal-label)) {@include hook-form-horizontal-label();} - } - - .uk-form-horizontal .uk-form-controls { margin-left: $form-horizontal-controls-margin-left; } - - /* Better vertical alignment if controls are checkboxes and radio buttons with text */ - .uk-form-horizontal .uk-form-controls-text { padding-top: $form-horizontal-controls-text-padding-top; } - -} - - -/* Icons - ========================================================================== */ - -/* - * 1. Set position - * 2. Set width - * 3. Center icon vertically and horizontally - * 4. Style - */ - -.uk-form-icon { - /* 1 */ - position: absolute; - top: 0; - bottom: 0; - left: 0; - /* 2 */ - width: $form-icon-width; - /* 3 */ - display: inline-flex; - justify-content: center; - align-items: center; - /* 4 */ - color: $form-icon-color; -} - -/* - * Required for `a`. - */ - -.uk-form-icon:hover { color: $form-icon-hover-color; } - -/* - * Make `input` element clickable through icon, e.g. if it's a `span` - */ - -.uk-form-icon:not(a):not(button):not(input) { pointer-events: none; } - -/* - * Input padding - */ - -.uk-form-icon:not(.uk-form-icon-flip) ~ .uk-input { padding-left: $form-icon-width !important; } - -/* - * Position modifier - */ - -.uk-form-icon-flip { - right: 0; - left: auto; -} - -.uk-form-icon-flip ~ .uk-input { padding-right: $form-icon-width !important; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-form-misc)) {@include hook-form-misc();} - -// @mixin hook-form(){} -// @mixin hook-form-single-line(){} -// @mixin hook-form-multi-line(){} -// @mixin hook-form-focus(){} -// @mixin hook-form-disabled(){} -// @mixin hook-form-danger(){} -// @mixin hook-form-success(){} -// @mixin hook-form-blank(){} -// @mixin hook-form-blank-focus(){} -// @mixin hook-form-radio(){} -// @mixin hook-form-radio-focus(){} -// @mixin hook-form-radio-checked(){} -// @mixin hook-form-radio-checked-focus(){} -// @mixin hook-form-radio-disabled(){} -// @mixin hook-form-legend(){} -// @mixin hook-form-label(){} -// @mixin hook-form-stacked-label(){} -// @mixin hook-form-horizontal-label(){} -// @mixin hook-form-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-form-background: $inverse-global-muted-background !default; -$inverse-form-color: $inverse-global-color !default; -$inverse-form-focus-background: fadein($inverse-form-background, 5%) !default; -$inverse-form-focus-color: $inverse-global-color !default; -$inverse-form-placeholder-color: $inverse-global-muted-color !default; - -$inverse-form-select-icon-color: $inverse-global-color !default; - -$inverse-form-datalist-icon-color: $inverse-global-color !default; - -$inverse-form-radio-background: $inverse-global-muted-background !default; - -$inverse-form-radio-focus-background: fadein($inverse-form-radio-background, 5%) !default; - -$inverse-form-radio-checked-background: $inverse-global-primary-background !default; -$inverse-form-radio-checked-icon-color: $inverse-global-inverse-color !default; - -$inverse-form-radio-checked-focus-background: fadein($inverse-global-primary-background, 10%) !default; - -$inverse-form-icon-color: $inverse-global-muted-color !default; -$inverse-form-icon-hover-color: $inverse-global-color !default; - - - -// @mixin hook-inverse-form(){} -// @mixin hook-inverse-form-focus(){} -// @mixin hook-inverse-form-radio(){} -// @mixin hook-inverse-form-radio-focus(){} -// @mixin hook-inverse-form-radio-checked(){} -// @mixin hook-inverse-form-radio-checked-focus(){} -// @mixin hook-inverse-form-label(){} diff --git a/docs/_sass/uikit/components/grid-masonry.scss b/docs/_sass/uikit/components/grid-masonry.scss deleted file mode 100644 index 47e890fc8f..0000000000 --- a/docs/_sass/uikit/components/grid-masonry.scss +++ /dev/null @@ -1,68 +0,0 @@ -// Name: Grid -// Description: Component to create two dimensional grids -// -// Component: `uk-grid2` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$grid-column-xsmall: 100px !default; -$grid-column-small: 200px !default; -$grid-column-medium: 300px !default; -$grid-column-large: 400px !default; -$grid-column-xlarge: 500px !default; -$grid-column-xxlarge: 600px !default; - -$grid-gap-small: $global-small-gutter !default; -$grid-gap-medium: $global-gutter !default; -$grid-gap-large: $global-large-gutter !default; - - -/* ======================================================================== - Component: Grid - ========================================================================== */ - -.uk-grid-masonry { display: grid; } -.uk-grid-inline { display: inline-grid; } - - -/* Columns Width - ========================================================================== */ - -.uk-grid-column-xsmall { grid-template-columns: repeat(auto-fill, minmax($grid-column-xsmall,1fr)); } -.uk-grid-column-small { grid-template-columns: repeat(auto-fill, minmax($grid-column-small,1fr)); } -.uk-grid-column-medium { grid-template-columns: repeat(auto-fill, minmax($grid-column-medium,1fr)); } -.uk-grid-column-large { grid-template-columns: repeat(auto-fill, minmax($grid-column-large,1fr)); } -.uk-grid-column-xlarge { grid-template-columns: repeat(auto-fill, minmax($grid-column-xlarge,1fr)); } -.uk-grid-column-xxlarge { grid-template-columns: repeat(auto-fill, minmax($grid-column-xxlarge,1fr)); } - - -/* Gap - ========================================================================== */ - -.uk-grid-gap-none { grid-gap: 0; } -.uk-grid-gap-small { grid-gap: $grid-gap-small; } -.uk-grid-gap-medium { grid-gap: $grid-gap-medium; } -.uk-grid-gap-large { grid-gap: $grid-gap-large; } - - -/* Auto Placement - ========================================================================== */ - -// Default -.uk-grid-auto-flow-row { grid-auto-flow: row; } -.uk-grid-auto-flow-column { grid-auto-flow: column; } -.uk-grid-auto-flow-dense { grid-auto-flow: dense; } - - -/* Item Span - ========================================================================== */ - -.uk-grid-item-span-2 { grid-column-start: span 2; } -.uk-grid-item-span-3 { grid-column-start: span 3; } -.uk-grid-item-span-4 { grid-column-start: span 4; } -.uk-grid-item-span-5 { grid-column-start: span 5; } - diff --git a/docs/_sass/uikit/components/grid.scss b/docs/_sass/uikit/components/grid.scss deleted file mode 100644 index 3f92c877e5..0000000000 --- a/docs/_sass/uikit/components/grid.scss +++ /dev/null @@ -1,407 +0,0 @@ -// Name: Grid -// Description: Component to create responsive, fluid and nestable grids -// -// Component: `uk-grid` -// -// Modifiers: `uk-grid-small` -// `uk-grid-medium` -// `uk-grid-large` -// `uk-grid-collapse` -// `uk-grid-divider` -// `uk-grid-match` -// `uk-grid-stack` -// `uk-grid-margin` -// `uk-grid-margin-small` -// `uk-grid-margin-medium` -// `uk-grid-margin-large` -// `uk-grid-margin-collapse` -// -// Sub-modifier: `uk-grid-item-match` -// -// States: `uk-first-column` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$grid-gutter-horizontal: $global-gutter !default; -$grid-gutter-vertical: $grid-gutter-horizontal !default; -$grid-gutter-horizontal-l: $global-medium-gutter !default; -$grid-gutter-vertical-l: $grid-gutter-horizontal-l !default; - -$grid-small-gutter-horizontal: $global-small-gutter !default; -$grid-small-gutter-vertical: $grid-small-gutter-horizontal !default; - -$grid-medium-gutter-horizontal: $global-gutter !default; -$grid-medium-gutter-vertical: $grid-medium-gutter-horizontal !default; - -$grid-large-gutter-horizontal: $global-medium-gutter !default; -$grid-large-gutter-vertical: $grid-large-gutter-horizontal !default; -$grid-large-gutter-horizontal-l: $global-large-gutter !default; -$grid-large-gutter-vertical-l: $grid-large-gutter-horizontal-l !default; - -$grid-divider-border-width: $global-border-width !default; -$grid-divider-border: $global-border !default; - - -/* ======================================================================== - Component: Grid - ========================================================================== */ - -/* - * 1. Allow cells to wrap into the next line - * 2. Reset list - */ - -.uk-grid { - display: flex; - /* 1 */ - flex-wrap: wrap; - /* 2 */ - margin: 0; - padding: 0; - list-style: none; -} - -/* - * Grid cell - * Note: Space is allocated solely based on content dimensions, but shrinks: 0 1 auto - * Reset margin for e.g. paragraphs - */ - -.uk-grid > * { margin: 0; } - -/* - * Remove margin from the last-child - */ - -.uk-grid > * > :last-child { margin-bottom: 0; } - - -/* Gutter - ========================================================================== */ - -/* - * Default - */ - -/* Horizontal */ -.uk-grid { margin-left: (-$grid-gutter-horizontal); } -.uk-grid > * { padding-left: $grid-gutter-horizontal; } - -/* Vertical */ -.uk-grid + .uk-grid, -.uk-grid > .uk-grid-margin, -* + .uk-grid-margin { margin-top: $grid-gutter-vertical; } - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - /* Horizontal */ - .uk-grid { margin-left: (-$grid-gutter-horizontal-l); } - .uk-grid > * { padding-left: $grid-gutter-horizontal-l; } - - /* Vertical */ - .uk-grid + .uk-grid, - .uk-grid > .uk-grid-margin, - * + .uk-grid-margin { margin-top: $grid-gutter-vertical-l; } - -} - -/* - * Small - */ - -/* Horizontal */ -.uk-grid-small, -.uk-grid-column-small { margin-left: (-$grid-small-gutter-horizontal); } -.uk-grid-small > *, -.uk-grid-column-small > * { padding-left: $grid-small-gutter-horizontal; } - -/* Vertical */ -.uk-grid + .uk-grid-small, -.uk-grid + .uk-grid-row-small, -.uk-grid-small > .uk-grid-margin, -.uk-grid-row-small > .uk-grid-margin, -* + .uk-grid-margin-small { margin-top: $grid-small-gutter-vertical; } - -/* - * Medium - */ - -/* Horizontal */ -.uk-grid-medium, -.uk-grid-column-medium { margin-left: (-$grid-medium-gutter-horizontal); } -.uk-grid-medium > *, -.uk-grid-column-medium > * { padding-left: $grid-medium-gutter-horizontal; } - -/* Vertical */ -.uk-grid + .uk-grid-medium, -.uk-grid + .uk-grid-row-medium, -.uk-grid-medium > .uk-grid-margin, -.uk-grid-row-medium > .uk-grid-margin, -* + .uk-grid-margin-medium { margin-top: $grid-medium-gutter-vertical; } - -/* - * Large - */ - -/* Horizontal */ -.uk-grid-large, -.uk-grid-column-large { margin-left: (-$grid-large-gutter-horizontal); } -.uk-grid-large > *, -.uk-grid-column-large > * { padding-left: $grid-large-gutter-horizontal; } - -/* Vertical */ -.uk-grid + .uk-grid-large, -.uk-grid + .uk-grid-row-large, -.uk-grid-large > .uk-grid-margin, -.uk-grid-row-large > .uk-grid-margin, -* + .uk-grid-margin-large { margin-top: $grid-large-gutter-vertical; } - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - /* Horizontal */ - .uk-grid-large, - .uk-grid-column-large { margin-left: (-$grid-large-gutter-horizontal-l); } - .uk-grid-large > *, - .uk-grid-column-large > * { padding-left: $grid-large-gutter-horizontal-l; } - - /* Vertical */ - .uk-grid + .uk-grid-large, - .uk-grid + .uk-grid-row-large, - .uk-grid-large > .uk-grid-margin, - .uk-grid-row-large > .uk-grid-margin, - * + .uk-grid-margin-large { margin-top: $grid-large-gutter-vertical-l; } - -} - -/* - * Collapse - */ - -/* Horizontal */ -.uk-grid-collapse, -.uk-grid-column-collapse { margin-left: 0; } -.uk-grid-collapse > *, -.uk-grid-column-collapse > * { padding-left: 0; } - -/* Vertical */ -.uk-grid + .uk-grid-collapse, -.uk-grid + .uk-grid-row-collapse, -.uk-grid-collapse > .uk-grid-margin, -.uk-grid-row-collapse > .uk-grid-margin { margin-top: 0; } - - -/* Divider - ========================================================================== */ - -.uk-grid-divider > * { position: relative; } - -.uk-grid-divider > :not(.uk-first-column)::before { - content: ""; - position: absolute; - top: 0; - bottom: 0; - border-left: $grid-divider-border-width solid $grid-divider-border; - @if(mixin-exists(hook-grid-divider-horizontal)) {@include hook-grid-divider-horizontal();} -} - -/* Vertical */ -.uk-grid-divider.uk-grid-stack > .uk-grid-margin::before { - content: ""; - position: absolute; - left: 0; - right: 0; - border-top: $grid-divider-border-width solid $grid-divider-border; - @if(mixin-exists(hook-grid-divider-vertical)) {@include hook-grid-divider-vertical();} -} - -/* - * Default - */ - -/* Horizontal */ -.uk-grid-divider { margin-left: -($grid-gutter-horizontal * 2); } -.uk-grid-divider > * { padding-left: ($grid-gutter-horizontal * 2); } - -.uk-grid-divider > :not(.uk-first-column)::before { left: $grid-gutter-horizontal; } - -/* Vertical */ -.uk-grid-divider.uk-grid-stack > .uk-grid-margin { margin-top: ($grid-gutter-vertical * 2); } - -.uk-grid-divider.uk-grid-stack > .uk-grid-margin::before { - top: (-$grid-gutter-vertical); - left: ($grid-gutter-horizontal * 2); -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - /* Horizontal */ - .uk-grid-divider { margin-left: -($grid-gutter-horizontal-l * 2); } - .uk-grid-divider > * { padding-left: ($grid-gutter-horizontal-l * 2); } - - .uk-grid-divider > :not(.uk-first-column)::before { left: $grid-gutter-horizontal-l; } - - /* Vertical */ - .uk-grid-divider.uk-grid-stack > .uk-grid-margin { margin-top: ($grid-gutter-vertical-l * 2); } - - .uk-grid-divider.uk-grid-stack > .uk-grid-margin::before { - top: (-$grid-gutter-vertical-l); - left: ($grid-gutter-horizontal-l * 2); - } - -} - -/* - * Small - */ - -/* Horizontal */ -.uk-grid-divider.uk-grid-small, -.uk-grid-divider.uk-grid-column-small { margin-left: -($grid-small-gutter-horizontal * 2); } -.uk-grid-divider.uk-grid-small > *, -.uk-grid-divider.uk-grid-column-small > * { padding-left: ($grid-small-gutter-horizontal * 2); } - -.uk-grid-divider.uk-grid-small > :not(.uk-first-column)::before, -.uk-grid-divider.uk-grid-column-small > :not(.uk-first-column)::before { left: $grid-small-gutter-horizontal; } - -/* Vertical */ -.uk-grid-divider.uk-grid-small.uk-grid-stack > .uk-grid-margin, -.uk-grid-divider.uk-grid-row-small.uk-grid-stack > .uk-grid-margin { margin-top: ($grid-small-gutter-vertical * 2); } - -.uk-grid-divider.uk-grid-small.uk-grid-stack > .uk-grid-margin::before { - top: (-$grid-small-gutter-vertical); - left: ($grid-small-gutter-horizontal * 2); -} - -.uk-grid-divider.uk-grid-row-small.uk-grid-stack > .uk-grid-margin::before { top: (-$grid-small-gutter-vertical); } -.uk-grid-divider.uk-grid-column-small.uk-grid-stack > .uk-grid-margin::before { left: ($grid-small-gutter-horizontal * 2); } - -/* - * Medium - */ - -/* Horizontal */ -.uk-grid-divider.uk-grid-medium, -.uk-grid-divider.uk-grid-column-medium { margin-left: -($grid-medium-gutter-horizontal * 2); } -.uk-grid-divider.uk-grid-medium > *, -.uk-grid-divider.uk-grid-column-medium > * { padding-left: ($grid-medium-gutter-horizontal * 2); } - -.uk-grid-divider.uk-grid-medium > :not(.uk-first-column)::before, -.uk-grid-divider.uk-grid-column-medium > :not(.uk-first-column)::before { left: $grid-medium-gutter-horizontal; } - -/* Vertical */ -.uk-grid-divider.uk-grid-medium.uk-grid-stack > .uk-grid-margin, -.uk-grid-divider.uk-grid-row-medium.uk-grid-stack > .uk-grid-margin { margin-top: ($grid-medium-gutter-vertical * 2); } - -.uk-grid-divider.uk-grid-medium.uk-grid-stack > .uk-grid-margin::before { - top: (-$grid-medium-gutter-vertical); - left: ($grid-medium-gutter-horizontal * 2); -} - -.uk-grid-divider.uk-grid-row-medium.uk-grid-stack > .uk-grid-margin::before { top: (-$grid-medium-gutter-vertical); } -.uk-grid-divider.uk-grid-column-medium.uk-grid-stack > .uk-grid-margin::before { left: ($grid-medium-gutter-horizontal * 2); } - -/* - * Large - */ - -/* Horizontal */ -.uk-grid-divider.uk-grid-large, -.uk-grid-divider.uk-grid-column-large { margin-left: -($grid-large-gutter-horizontal * 2); } -.uk-grid-divider.uk-grid-large > *, -.uk-grid-divider.uk-grid-column-large > * { padding-left: ($grid-large-gutter-horizontal * 2); } - -.uk-grid-divider.uk-grid-large > :not(.uk-first-column)::before, -.uk-grid-divider.uk-grid-column-large > :not(.uk-first-column)::before { left: $grid-large-gutter-horizontal; } - -/* Vertical */ -.uk-grid-divider.uk-grid-large.uk-grid-stack > .uk-grid-margin, -.uk-grid-divider.uk-grid-row-large.uk-grid-stack > .uk-grid-margin { margin-top: ($grid-large-gutter-vertical * 2); } - -.uk-grid-divider.uk-grid-large.uk-grid-stack > .uk-grid-margin::before { - top: (-$grid-large-gutter-vertical); - left: ($grid-large-gutter-horizontal * 2); -} - -.uk-grid-divider.uk-grid-row-large.uk-grid-stack > .uk-grid-margin::before { top: (-$grid-large-gutter-vertical); } -.uk-grid-divider.uk-grid-column-large.uk-grid-stack > .uk-grid-margin::before { left: ($grid-large-gutter-horizontal * 2); } - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - /* Horizontal */ - .uk-grid-divider.uk-grid-large, - .uk-grid-divider.uk-grid-column-large { margin-left: -($grid-large-gutter-horizontal-l * 2); } - .uk-grid-divider.uk-grid-large > *, - .uk-grid-divider.uk-grid-column-large > * { padding-left: ($grid-large-gutter-horizontal-l * 2); } - - .uk-grid-divider.uk-grid-large > :not(.uk-first-column)::before, - .uk-grid-divider.uk-grid-column-large > :not(.uk-first-column)::before { left: $grid-large-gutter-horizontal-l; } - - /* Vertical */ - .uk-grid-divider.uk-grid-large.uk-grid-stack > .uk-grid-margin, - .uk-grid-divider.uk-grid-row-large.uk-grid-stack > .uk-grid-margin { margin-top: ($grid-large-gutter-vertical-l * 2); } - - .uk-grid-divider.uk-grid-large.uk-grid-stack > .uk-grid-margin::before { - top: (-$grid-large-gutter-vertical-l); - left: ($grid-large-gutter-horizontal-l * 2); - } - - .uk-grid-divider.uk-grid-row-large.uk-grid-stack > .uk-grid-margin::before { top: (-$grid-large-gutter-vertical-l); } - .uk-grid-divider.uk-grid-column-large.uk-grid-stack > .uk-grid-margin::before { left: ($grid-large-gutter-horizontal-l * 2); } - -} - - -/* Match child of a grid cell - ========================================================================== */ - -/* - * Behave like a block element - * 1. Wrap into the next line - * 2. Take the full width, at least 100%. Only if no class from the Width component is set. - * 3. Expand width even if larger than 100%, e.g. because of negative margin (Needed for nested grids) - */ - -.uk-grid-match > *, -.uk-grid-item-match { - display: flex; - /* 1 */ - flex-wrap: wrap; -} - -.uk-grid-match > * > :not([class*='uk-width']), -.uk-grid-item-match > :not([class*='uk-width']) { - /* 2 */ - box-sizing: border-box; - width: 100%; - /* 3 */ - flex: auto; -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-grid-misc)) {@include hook-grid-misc();} - -// @mixin hook-grid-divider-horizontal(){} -// @mixin hook-grid-divider-vertical(){} -// @mixin hook-grid-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-grid-divider-border: $inverse-global-border !default; - - - -// @mixin hook-inverse-grid-divider-horizontal(){} -// @mixin hook-inverse-grid-divider-vertical(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/heading.scss b/docs/_sass/uikit/components/heading.scss deleted file mode 100644 index 05518547d2..0000000000 --- a/docs/_sass/uikit/components/heading.scss +++ /dev/null @@ -1,321 +0,0 @@ -// Name: Heading -// Description: Styles for headings -// -// Component: `uk-heading-primary` -// `uk-heading-hero` -// `uk-heading-divider` -// `uk-heading-bullet` -// `uk-heading-line` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$heading-small-font-size: $heading-small-font-size-m * 0.8 !default; // 38px 0.73 -$heading-medium-font-size: $heading-medium-font-size-m * 0.825 !default; // 40px 0.714 -$heading-large-font-size: $heading-large-font-size-m * 0.85 !default; // 50px 0.78 -$heading-xlarge-font-size: $heading-large-font-size-m !default; // 4rem / 64px -$heading-2xlarge-font-size: $heading-xlarge-font-size-m !default; // 6rem / 96px - -$heading-small-font-size-m: $heading-medium-font-size-l * 0.8125 !default; // 3.25rem / 52px -$heading-medium-font-size-m: $heading-medium-font-size-l * 0.875 !default; // 3.5rem / 56px -$heading-large-font-size-m: $heading-medium-font-size-l !default; // 4rem / 64px -$heading-xlarge-font-size-m: $heading-large-font-size-l !default; // 6rem / 96px -$heading-2xlarge-font-size-m: $heading-xlarge-font-size-l !default; // 8rem / 128px - -$heading-medium-font-size-l: 4rem !default; // 64px -$heading-large-font-size-l: 6rem !default; // 96px -$heading-xlarge-font-size-l: 8rem !default; // 128px -$heading-2xlarge-font-size-l: 11rem !default; // 176px - -$heading-small-line-height: 1.2 !default; -$heading-medium-line-height: 1.1 !default; -$heading-large-line-height: 1.1 !default; -$heading-xlarge-line-height: 1 !default; -$heading-2xlarge-line-height: 1 !default; - -$heading-divider-padding-bottom: unquote('calc(5px + 0.1em)') !default; -$heading-divider-border-width: unquote('calc(0.2px + 0.05em)') !default; -$heading-divider-border: $global-border !default; - -$heading-bullet-top: unquote('calc(-0.1 * 1em)') !default; -$heading-bullet-height: unquote('calc(4px + 0.7em)') !default; -$heading-bullet-margin-right: unquote('calc(5px + 0.2em)') !default; -$heading-bullet-border-width: unquote('calc(5px + 0.1em)') !default; -$heading-bullet-border: $global-border !default; - -$heading-line-top: 50% !default; -$heading-line-height: $heading-line-border-width !default; -$heading-line-width: 2000px !default; -$heading-line-border-width: unquote('calc(0.2px + 0.05em)') !default; -$heading-line-border: $global-border !default; -$heading-line-margin-horizontal: unquote('calc(5px + 0.3em)') !default; - - -/* ======================================================================== - Component: Heading - ========================================================================== */ - -.uk-heading-small { - font-size: $heading-small-font-size; - line-height: $heading-small-line-height; - @if(mixin-exists(hook-heading-small)) {@include hook-heading-small();} -} - -.uk-heading-medium { - font-size: $heading-medium-font-size; - line-height: $heading-medium-line-height; - @if(mixin-exists(hook-heading-medium)) {@include hook-heading-medium();} -} - -.uk-heading-large { - font-size: $heading-large-font-size; - line-height: $heading-large-line-height; - @if(mixin-exists(hook-heading-large)) {@include hook-heading-large();} -} - -.uk-heading-xlarge { - font-size: $heading-xlarge-font-size; - line-height: $heading-xlarge-line-height; - @if(mixin-exists(hook-heading-xlarge)) {@include hook-heading-xlarge();} -} - -.uk-heading-2xlarge { - font-size: $heading-2xlarge-font-size; - line-height: $heading-2xlarge-line-height; - @if(mixin-exists(hook-heading-2xlarge)) {@include hook-heading-2xlarge();} -} - -/* Tablet Landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-heading-small { font-size: $heading-small-font-size-m; } - .uk-heading-medium { font-size: $heading-medium-font-size-m; } - .uk-heading-large { font-size: $heading-large-font-size-m; } - .uk-heading-xlarge { font-size: $heading-xlarge-font-size-m; } - .uk-heading-2xlarge { font-size: $heading-2xlarge-font-size-m; } - -} - -/* Laptop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-heading-medium { font-size: $heading-medium-font-size-l; } - .uk-heading-large { font-size: $heading-large-font-size-l; } - .uk-heading-xlarge { font-size: $heading-xlarge-font-size-l; } - .uk-heading-2xlarge { font-size: $heading-2xlarge-font-size-l; } - -} - - -/* Primary - Deprecated: Use `uk-heading-medium` instead - ========================================================================== */ - -$heading-primary-font-size-l: 3.75rem !default; // 60px -$heading-primary-line-height-l: 1.1 !default; - -$heading-primary-font-size-m: $heading-primary-font-size-l * 0.9 !default; // 54px - -$heading-primary-font-size: $heading-primary-font-size-l * 0.8 !default; // 48px -$heading-primary-line-height: 1.2 !default; - -@if ($deprecated == true) { -.uk-heading-primary { - font-size: $heading-primary-font-size; - line-height: $heading-primary-line-height; - @if(mixin-exists(hook-heading-primary)) {@include hook-heading-primary();} -} -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - @if ($deprecated == true) { -.uk-heading-primary { font-size: $heading-primary-font-size-m; } -} - -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - @if ($deprecated == true) { -.uk-heading-primary { - font-size: $heading-primary-font-size-l; - line-height: $heading-primary-line-height-l; - } -} - -} - - -/* Hero - Deprecated: Use `uk-heading-xlarge` instead - ========================================================================== */ - -$heading-hero-font-size-l: 8rem !default; // 128px -$heading-hero-line-height-l: 1 !default; - -$heading-hero-font-size-m: $heading-hero-font-size-l * 0.75 !default; // 96px -$heading-hero-line-height-m: 1 !default; - -$heading-hero-font-size: $heading-hero-font-size-l * 0.5 !default; // 64px -$heading-hero-line-height: 1.1 !default; - -@if ($deprecated == true) { -.uk-heading-hero { - font-size: $heading-hero-font-size; - line-height: $heading-hero-line-height; - @if(mixin-exists(hook-heading-hero)) {@include hook-heading-hero();} -} -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - @if ($deprecated == true) { -.uk-heading-hero { - font-size: $heading-hero-font-size-m; - line-height: $heading-hero-line-height-m; - } -} - -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - @if ($deprecated == true) { -.uk-heading-hero { - font-size: $heading-hero-font-size-l; - line-height: $heading-hero-line-height-l; - } -} - -} - - -/* Divider - ========================================================================== */ - -.uk-heading-divider { - padding-bottom: $heading-divider-padding-bottom; - border-bottom: $heading-divider-border-width solid $heading-divider-border; - @if(mixin-exists(hook-heading-divider)) {@include hook-heading-divider();} -} - - -/* Bullet - ========================================================================== */ - -.uk-heading-bullet { position: relative; } - -/* - * 1. Using `inline-block` to make it work with text alignment - * 2. Center vertically - * 3. Style - */ - -.uk-heading-bullet::before { - content: ""; - /* 1 */ - display: inline-block; - /* 2 */ - position: relative; - top: $heading-bullet-top; - vertical-align: middle; - /* 3 */ - height: $heading-bullet-height; - margin-right: $heading-bullet-margin-right; - border-left: $heading-bullet-border-width solid $heading-bullet-border; - @if(mixin-exists(hook-heading-bullet)) {@include hook-heading-bullet();} -} - - -/* Line - ========================================================================== */ - -/* - * Clip the child element - */ - -.uk-heading-line { overflow: hidden; } - -/* - * Extra markup is needed to make it work with text align - */ - -.uk-heading-line > * { - display: inline-block; - position: relative; -} - -/* - * 1. Center vertically - * 2. Make the element as large as possible. It's clipped by the container. - * 3. Style - */ - -.uk-heading-line > ::before, -.uk-heading-line > ::after { - content: ""; - /* 1 */ - position: absolute; - top: unquote('calc(#{$heading-line-top} - (#{$heading-line-height} / 2))'); - /* 2 */ - width: $heading-line-width; - /* 3 */ - border-bottom: $heading-line-border-width solid $heading-line-border; - @if(mixin-exists(hook-heading-line)) {@include hook-heading-line();} -} - -.uk-heading-line > ::before { - right: 100%; - margin-right: $heading-line-margin-horizontal; -} -.uk-heading-line > ::after { - left: 100%; - margin-left: $heading-line-margin-horizontal; -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-heading-misc)) {@include hook-heading-misc();} - -// @mixin hook-heading-small(){} -// @mixin hook-heading-medium(){} -// @mixin hook-heading-large(){} -// @mixin hook-heading-xlarge(){} -// @mixin hook-heading-2xlarge(){} -// @mixin hook-heading-primary(){} -// @mixin hook-heading-hero(){} -// @mixin hook-heading-divider(){} -// @mixin hook-heading-bullet(){} -// @mixin hook-heading-line(){} -// @mixin hook-heading-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-heading-divider-border: $inverse-global-border !default; -$inverse-heading-bullet-border: $inverse-global-border !default; -$inverse-heading-line-border: $inverse-global-border !default; - - - -// @mixin hook-inverse-heading-small(){} -// @mixin hook-inverse-heading-medium(){} -// @mixin hook-inverse-heading-large(){} -// @mixin hook-inverse-heading-xlarge(){} -// @mixin hook-inverse-heading-2xlarge(){} -// @mixin hook-inverse-heading-primary(){} -// @mixin hook-inverse-heading-hero(){} -// @mixin hook-inverse-heading-divider(){} -// @mixin hook-inverse-heading-bullet(){} -// @mixin hook-inverse-heading-line(){} diff --git a/docs/_sass/uikit/components/height.scss b/docs/_sass/uikit/components/height.scss deleted file mode 100644 index 3bcc150436..0000000000 --- a/docs/_sass/uikit/components/height.scss +++ /dev/null @@ -1,54 +0,0 @@ -// Name: Height -// Description: Utilities for heights -// -// Component: `uk-height-*` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$height-small-height: 150px !default; -$height-medium-height: 300px !default; -$height-large-height: 450px !default; - - -/* ======================================================================== - Component: Height - ========================================================================== */ - -[class*='uk-height'] { box-sizing: border-box; } - -/* - * Only works if parent element has a height set - */ - -.uk-height-1-1 { height: 100%; } - -/* - * Useful to create image teasers - */ - -.uk-height-viewport { min-height: 100vh; } - -/* - * Pixel - * Useful for `overflow: auto` - */ - -.uk-height-small { height: $height-small-height; } -.uk-height-medium { height: $height-medium-height; } -.uk-height-large { height: $height-large-height; } - -.uk-height-max-small { max-height: $height-small-height; } -.uk-height-max-medium { max-height: $height-medium-height; } -.uk-height-max-large { max-height: $height-large-height; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-height-misc)) {@include hook-height-misc();} - -// @mixin hook-height-misc(){} diff --git a/docs/_sass/uikit/components/icon.scss b/docs/_sass/uikit/components/icon.scss deleted file mode 100644 index d801424b5b..0000000000 --- a/docs/_sass/uikit/components/icon.scss +++ /dev/null @@ -1,220 +0,0 @@ -// Name: Icon -// Description: Component to create icons -// -// Component: `uk-icon` -// -// Modifiers: `uk-icon-image` -// `uk-icon-link` -// `uk-icon-button` -// -// States: `uk-preserve` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$icon-image-size: 20px !default; - -$icon-link-color: $global-muted-color !default; -$icon-link-hover-color: $global-color !default; -$icon-link-active-color: darken($global-color, 5%) !default; - -$icon-button-size: 36px !default; -$icon-button-border-radius: 500px !default; -$icon-button-background: $global-muted-background !default; -$icon-button-color: $global-muted-color !default; - -$icon-button-hover-background: darken($icon-button-background, 5%) !default; -$icon-button-hover-color: $global-color !default; - -$icon-button-active-background: darken($icon-button-background, 10%) !default; -$icon-button-active-color: $global-color !default; - - -/* ======================================================================== - Component: Icon - ========================================================================== */ - -/* - * Note: 1. - 7. is required for `button` elements. Needed for Close and Form Icon component. - * 1. Remove margins in Chrome, Safari and Opera. - * 2. Remove borders for `button`. - * 3. Remove border-radius in Chrome. - * 4. Address `overflow` set to `hidden` in IE. - * 5. Correct `font` properties and `color` not being inherited for `button`. - * 6. Remove the inheritance of text transform in Edge, Firefox, and IE. - * 7. Remove default `button` padding and background color - * 8. Style - * 9. Fill all SVG elements with the current text color if no `fill` attribute is set - * 10. Let the container fit the height of the icon - */ - -.uk-icon { - /* 1 */ - margin: 0; - /* 2 */ - border: none; - /* 3 */ - border-radius: 0; - /* 4 */ - overflow: visible; - /* 5 */ - font: inherit; - color: inherit; - /* 6 */ - text-transform: none; - /* 7. */ - padding: 0; - background-color: transparent; - /* 8 */ - display: inline-block; - /* 9 */ - fill: currentcolor; - /* 10 */ - line-height: 0; -} - -/* Required for `button`. */ -button.uk-icon:not(:disabled) { cursor: pointer; } - -/* - * Remove the inner border and padding in Firefox. - */ - -.uk-icon::-moz-focus-inner { - border: 0; - padding: 0; -} - -/* - * Set the fill and stroke color of all SVG elements to the current text color - */ - -.uk-icon:not(.uk-preserve) [fill*='#']:not(.uk-preserve) { fill: currentcolor; } -.uk-icon:not(.uk-preserve) [stroke*='#']:not(.uk-preserve) { stroke: currentcolor; } - -/* - * Fix Firefox blurry SVG rendering: https://bugzilla.mozilla.org/show_bug.cgi?id=1046835 - */ - -.uk-icon > * { transform: translate(0,0); } - - -/* Image modifier - ========================================================================== */ - -/* - * Display images in icon dimensions - */ - -.uk-icon-image { - width: $icon-image-size; - height: $icon-image-size; - background-position: 50% 50%; - background-repeat: no-repeat; - background-size: contain; - vertical-align: middle; -} - - -/* Style modifiers - ========================================================================== */ - -/* - * Link - */ - -.uk-icon-link { - color: $icon-link-color; - @if(mixin-exists(hook-icon-link)) {@include hook-icon-link();} -} - -.uk-icon-link:hover, -.uk-icon-link:focus { - color: $icon-link-hover-color; - outline: none; - @if(mixin-exists(hook-icon-link-hover)) {@include hook-icon-link-hover();} -} - -/* OnClick + Active */ -.uk-icon-link:active, -.uk-active > .uk-icon-link { - color: $icon-link-active-color; - @if(mixin-exists(hook-icon-link-active)) {@include hook-icon-link-active();} -} - -/* - * Button - * 1. Center icon vertically and horizontally - */ - -.uk-icon-button { - box-sizing: border-box; - width: $icon-button-size; - height: $icon-button-size; - border-radius: $icon-button-border-radius; - background: $icon-button-background; - color: $icon-button-color; - vertical-align: middle; - /* 1 */ - display: inline-flex; - justify-content: center; - align-items: center; - @if(mixin-exists(hook-icon-button)) {@include hook-icon-button();} -} - -/* Hover + Focus */ -.uk-icon-button:hover, -.uk-icon-button:focus { - background-color: $icon-button-hover-background; - color: $icon-button-hover-color; - outline: none; - @if(mixin-exists(hook-icon-button-hover)) {@include hook-icon-button-hover();} -} - -/* OnClick + Active */ -.uk-icon-button:active, -.uk-active > .uk-icon-button { - background-color: $icon-button-active-background; - color: $icon-button-active-color; - @if(mixin-exists(hook-icon-button-active)) {@include hook-icon-button-active();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-icon-misc)) {@include hook-icon-misc();} - -// @mixin hook-icon-link(){} -// @mixin hook-icon-link-hover(){} -// @mixin hook-icon-link-active(){} -// @mixin hook-icon-button(){} -// @mixin hook-icon-button-hover(){} -// @mixin hook-icon-button-active(){} -// @mixin hook-icon-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-icon-link-color: $inverse-global-muted-color !default; -$inverse-icon-link-hover-color: $inverse-global-color !default; -$inverse-icon-link-active-color: $inverse-global-color !default; -$inverse-icon-button-background: $inverse-global-muted-background !default; -$inverse-icon-button-color: $inverse-global-muted-color !default; -$inverse-icon-button-hover-background: fadein($inverse-icon-button-background, 5%) !default; -$inverse-icon-button-hover-color: $inverse-global-color !default; -$inverse-icon-button-active-background: fadein($inverse-icon-button-background, 10%) !default; -$inverse-icon-button-active-color: $inverse-global-color !default; - - - -// @mixin hook-inverse-icon-link(){} -// @mixin hook-inverse-icon-link-hover(){} -// @mixin hook-inverse-icon-link-active(){} -// @mixin hook-inverse-icon-button(){} -// @mixin hook-inverse-icon-button-hover(){} -// @mixin hook-inverse-icon-button-active(){} diff --git a/docs/_sass/uikit/components/iconnav.scss b/docs/_sass/uikit/components/iconnav.scss deleted file mode 100644 index e0d2ae1a14..0000000000 --- a/docs/_sass/uikit/components/iconnav.scss +++ /dev/null @@ -1,148 +0,0 @@ -// Name: Iconnav -// Description: Component to create icon navigations -// -// Component: `uk-iconnav` -// -// Modifier: `uk-iconnav-vertical` -// -// States: `uk-active` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$iconnav-margin-horizontal: $global-small-margin !default; -$iconnav-margin-vertical: $iconnav-margin-horizontal !default; - -$iconnav-item-color: $global-muted-color !default; - -$iconnav-item-hover-color: $global-color !default; - -$iconnav-item-active-color: $global-color !default; - - -/* ======================================================================== - Component: Iconnav - ========================================================================== */ - -/* - * 1. Allow items to wrap into the next line - * 2. Reset list - * 3. Gutter - */ - -.uk-iconnav { - display: flex; - /* 1 */ - flex-wrap: wrap; - /* 2 */ - margin: 0; - padding: 0; - list-style: none; - /* 3 */ - margin-left: (-$iconnav-margin-horizontal); - @if(mixin-exists(hook-iconnav)) {@include hook-iconnav();} -} - -/* - * Space is allocated based on content dimensions, but shrinks: 0 1 auto - * 1. Gutter - */ - -.uk-iconnav > * { - /* 1 */ - padding-left: $iconnav-margin-horizontal; -} - - -/* Items - ========================================================================== */ - -/* - * Items must target `a` elements to exclude other elements (e.g. dropdowns) - * 1. Center content vertically if there is still some text - * 2. Imitate white space gap when using flexbox - * 3. Force text not to affect item height - * 4. Style - * 5. Required for `a` if there is still some text - */ - -.uk-iconnav > * > a { - /* 1 */ - display: flex; - align-items: center; - /* 2 */ - column-gap: 0.25em; - /* 3 */ - line-height: 0; - /* 4 */ - color: $iconnav-item-color; - /* 5 */ - text-decoration: none; - @if(mixin-exists(hook-iconnav-item)) {@include hook-iconnav-item();} -} - -/* Hover + Focus */ -.uk-iconnav > * > a:hover, -.uk-iconnav > * > a:focus { - color: $iconnav-item-hover-color; - outline: none; - @if(mixin-exists(hook-iconnav-item-hover)) {@include hook-iconnav-item-hover();} -} - -/* Active */ -.uk-iconnav > .uk-active > a { - color: $iconnav-item-active-color; - @if(mixin-exists(hook-iconnav-item-active)) {@include hook-iconnav-item-active();} -} - - -/* Modifier: 'uk-iconnav-vertical' - ========================================================================== */ - -/* - * 1. Change direction - * 2. Gutter - */ - -.uk-iconnav-vertical { - /* 1 */ - flex-direction: column; - /* 2 */ - margin-left: 0; - margin-top: (-$iconnav-margin-vertical); -} - -/* 2 */ -.uk-iconnav-vertical > * { - padding-left: 0; - padding-top: $iconnav-margin-vertical; -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-iconnav-misc)) {@include hook-iconnav-misc();} - -// @mixin hook-iconnav(){} -// @mixin hook-iconnav-item(){} -// @mixin hook-iconnav-item-hover(){} -// @mixin hook-iconnav-item-active(){} -// @mixin hook-iconnav-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-iconnav-item-color: $inverse-global-muted-color !default; -$inverse-iconnav-item-hover-color: $inverse-global-color !default; -$inverse-iconnav-item-active-color: $inverse-global-color !default; - - - -// @mixin hook-inverse-iconnav-item(){} -// @mixin hook-inverse-iconnav-item-hover(){} -// @mixin hook-inverse-iconnav-item-active(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/inverse.scss b/docs/_sass/uikit/components/inverse.scss deleted file mode 100644 index cc5efee3f3..0000000000 --- a/docs/_sass/uikit/components/inverse.scss +++ /dev/null @@ -1,46 +0,0 @@ -// Name: Inverse -// Description: Inverse component style for light or dark backgrounds -// -// Component: `uk-light` -// `uk-dark` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$inverse-global-color-mode: light !default; - -$inverse-global-color: rgba($global-inverse-color, 0.7) !default; -$inverse-global-emphasis-color: $global-inverse-color !default; -$inverse-global-muted-color: rgba($global-inverse-color, 0.5) !default; -$inverse-global-inverse-color: $global-color !default; - -$inverse-global-primary-background: $global-inverse-color !default; -$inverse-global-muted-background: rgba($global-inverse-color, 0.1) !default; - -$inverse-global-border: rgba($global-inverse-color, 0.2) !default; - - -/* ======================================================================== - Component: Inverse - ========================================================================== */ - - - -/* - * Implemented class depends on the general theme color - * `uk-light` is for light colors on dark backgrounds - * `uk-dark` is or dark colors on light backgrounds - */ - -@if ($inverse-global-color-mode == light) { .uk-light { @if (mixin-exists(hook-inverse)) {@include hook-inverse();}}} - -@if ($inverse-global-color-mode == dark) { .uk-dark { @if (mixin-exists(hook-inverse)) {@include hook-inverse();}}} - - -// Hooks -// ======================================================================== - -// @mixin hook-inverse(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/label.scss b/docs/_sass/uikit/components/label.scss deleted file mode 100644 index 6600aedfab..0000000000 --- a/docs/_sass/uikit/components/label.scss +++ /dev/null @@ -1,102 +0,0 @@ -// Name: Label -// Description: Component to indicate important notes -// -// Component: `uk-label` -// -// Modifiers: `uk-label-success` -// `uk-label-warning` -// `uk-label-danger` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$label-padding-vertical: 0 !default; -$label-padding-horizontal: $global-small-margin !default; -$label-background: $global-primary-background !default; -$label-line-height: $global-line-height !default; -$label-font-size: $global-small-font-size !default; -$label-color: $global-inverse-color !default; - -$label-success-background: $global-success-background !default; -$label-success-color: $global-inverse-color !default; -$label-warning-background: $global-warning-background !default; -$label-warning-color: $global-inverse-color !default; -$label-danger-background: $global-danger-background !default; -$label-danger-color: $global-inverse-color !default; - - -/* ======================================================================== - Component: Label - ========================================================================== */ - -.uk-label { - display: inline-block; - padding: $label-padding-vertical $label-padding-horizontal; - background: $label-background; - line-height: $label-line-height; - font-size: $label-font-size; - color: $label-color; - vertical-align: middle; - white-space: nowrap; - @if(mixin-exists(hook-label)) {@include hook-label();} -} - - -/* Color modifiers - ========================================================================== */ - -/* - * Success - */ - -.uk-label-success { - background-color: $label-success-background; - color: $label-success-color; - @if(mixin-exists(hook-label-success)) {@include hook-label-success();} -} - -/* - * Warning - */ - -.uk-label-warning { - background-color: $label-warning-background; - color: $label-warning-color; - @if(mixin-exists(hook-label-warning)) {@include hook-label-warning();} -} - -/* - * Danger - */ - -.uk-label-danger { - background-color: $label-danger-background; - color: $label-danger-color; - @if(mixin-exists(hook-label-danger)) {@include hook-label-danger();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-label-misc)) {@include hook-label-misc();} - -// @mixin hook-label(){} -// @mixin hook-label-success(){} -// @mixin hook-label-warning(){} -// @mixin hook-label-danger(){} -// @mixin hook-label-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-label-background: $inverse-global-primary-background !default; -$inverse-label-color: $inverse-global-inverse-color !default; - - - -// @mixin hook-inverse-label(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/leader.scss b/docs/_sass/uikit/components/leader.scss deleted file mode 100644 index a671f098bf..0000000000 --- a/docs/_sass/uikit/components/leader.scss +++ /dev/null @@ -1,70 +0,0 @@ -// Name: Leader -// Description: Component to create dot leaders -// -// Component: `uk-leader` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$leader-fill-content: unquote('.') !default; -$leader-fill-margin-left: $global-small-gutter !default; - - -/* ======================================================================== - Component: Leader - ========================================================================== */ - -.uk-leader { overflow: hidden; } - -/* - * 1. Place element in text flow - * 2. Never break into a new line - * 3. Get a string back with as many repeating characters to fill the container - * 4. Prevent wrapping. Overflowing characters will be clipped by the container - */ - -.uk-leader-fill::after { - /* 1 */ - display: inline-block; - margin-left: $leader-fill-margin-left; - /* 2 */ - width: 0; - /* 3 */ - content: attr(data-fill); - /* 4 */ - white-space: nowrap; - @if(mixin-exists(hook-leader)) {@include hook-leader();} -} - -/* - * Hide if media does not match - */ - -.uk-leader-fill.uk-leader-hide::after { display: none; } - -/* - * Pass fill character to JS - */ - -.uk-leader-fill-content::before { content: '#{$leader-fill-content}'; } -:root { --uk-leader-fill-content: #{$leader-fill-content}; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-leader-misc)) {@include hook-leader-misc();} - -// @mixin hook-leader(){} -// @mixin hook-leader-misc(){} - - -// Inverse -// ======================================================================== - - - -// @mixin hook-inverse-leader(){} diff --git a/docs/_sass/uikit/components/lightbox.scss b/docs/_sass/uikit/components/lightbox.scss deleted file mode 100644 index 16f58c7882..0000000000 --- a/docs/_sass/uikit/components/lightbox.scss +++ /dev/null @@ -1,245 +0,0 @@ -// Name: Lightbox -// Description: Component to create an lightbox image gallery -// -// Component: `uk-lightbox` -// -// Sub-objects: `uk-lightbox-page` -// `uk-lightbox-items` -// `uk-lightbox-toolbar` -// `uk-lightbox-toolbar-icon` -// `uk-lightbox-button` -// `uk-lightbox-caption` -// `uk-lightbox-iframe` -// -// States: `uk-open` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$lightbox-z-index: $global-z-index + 10 !default; -$lightbox-background: #000 !default; - -$lightbox-item-color: rgba(255,255,255,0.7) !default; -$lightbox-item-max-width: 100vw !default; -$lightbox-item-max-height: 100vh !default; - -$lightbox-toolbar-padding-vertical: 10px !default; -$lightbox-toolbar-padding-horizontal: 10px !default; -$lightbox-toolbar-background: rgba(0,0,0,0.3) !default; -$lightbox-toolbar-color: rgba(255,255,255,0.7) !default; - -$lightbox-toolbar-icon-padding: 5px !default; -$lightbox-toolbar-icon-color: rgba(255,255,255,0.7) !default; - -$lightbox-toolbar-icon-hover-color: #fff !default; - -$lightbox-button-size: 50px !default; -$lightbox-button-background: $lightbox-toolbar-background !default; -$lightbox-button-color: rgba(255,255,255,0.7) !default; - -$lightbox-button-hover-color: #fff !default; - - -/* ======================================================================== - Component: Lightbox - ========================================================================== */ - -/* - * 1. Hide by default - * 2. Set position - * 3. Allow scrolling for the modal dialog - * 4. Horizontal padding - * 5. Mask the background page - * 6. Fade-in transition - * 7. Prevent cancellation of pointer events while dragging - */ - -.uk-lightbox { - /* 1 */ - display: none; - /* 2 */ - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: $lightbox-z-index; - /* 5 */ - background: $lightbox-background; - /* 6 */ - opacity: 0; - transition: opacity 0.15s linear; - /* 7 */ - touch-action: pinch-zoom; - @if(mixin-exists(hook-lightbox)) {@include hook-lightbox();} -} - -/* - * Open - * 1. Center child - * 2. Fade-in - */ - -.uk-lightbox.uk-open { - display: block; - /* 2 */ - opacity: 1; -} - - -/* Page - ========================================================================== */ - -/* - * Prevent scrollbars - */ - -.uk-lightbox-page { overflow: hidden; } - - -/* Item - ========================================================================== */ - -/* - * 1. Center child within the viewport - * 2. Not visible by default - * 3. Color needed for spinner icon - * 4. Optimize animation - * 5. Responsiveness - * Using `vh` for `max-height` to fix image proportions after resize in Safari and Opera - * Using `vh` and `vw` to make responsive image work in IE11 - * 6. Suppress outline on focus - */ - -.uk-lightbox-items > * { - /* 1 */ - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - /* 2 */ - display: none; - justify-content: center; - align-items: center; - /* 3 */ - color: $lightbox-item-color; - /* 4 */ - will-change: transform, opacity; - @if(mixin-exists(hook-lightbox-item)) {@include hook-lightbox-item();} -} - -/* 5 */ -.uk-lightbox-items > * > * { - max-width: $lightbox-item-max-width; - max-height: $lightbox-item-max-height; -} - -/* 6 */ -.uk-lightbox-items > :focus { outline: none; } - -.uk-lightbox-items > * > :not(iframe) { - width: auto; - height: auto; -} - -.uk-lightbox-items > .uk-active { display: flex; } - -/* Toolbar - ========================================================================== */ - -.uk-lightbox-toolbar { - padding: $lightbox-toolbar-padding-vertical $lightbox-toolbar-padding-horizontal; - background: $lightbox-toolbar-background; - color: $lightbox-toolbar-color; - @if(mixin-exists(hook-lightbox-toolbar)) {@include hook-lightbox-toolbar();} -} - -.uk-lightbox-toolbar > * { color: $lightbox-toolbar-color; } - - -/* Toolbar Icon (Close) - ========================================================================== */ - -.uk-lightbox-toolbar-icon { - padding: $lightbox-toolbar-icon-padding; - color: $lightbox-toolbar-icon-color; - @if(mixin-exists(hook-lightbox-toolbar-icon)) {@include hook-lightbox-toolbar-icon();} -} - -/* - * Hover - */ - -.uk-lightbox-toolbar-icon:hover { - color: $lightbox-toolbar-icon-hover-color; - @if(mixin-exists(hook-lightbox-toolbar-icon-hover)) {@include hook-lightbox-toolbar-icon-hover();} -} - - - -/* Button (Slidenav) - ========================================================================== */ - -/* - * 1. Center icon vertically and horizontally - */ - -.uk-lightbox-button { - box-sizing: border-box; - width: $lightbox-button-size; - height: $lightbox-button-size; - background: $lightbox-button-background; - color: $lightbox-button-color; - /* 1 */ - display: inline-flex; - justify-content: center; - align-items: center; - @if(mixin-exists(hook-lightbox-button)) {@include hook-lightbox-button();} -} - -/* Hover + Focus */ -.uk-lightbox-button:hover, -.uk-lightbox-button:focus { - color: $lightbox-button-hover-color; - @if(mixin-exists(hook-lightbox-button-hover)) {@include hook-lightbox-button-hover();} -} - -/* OnClick */ -.uk-lightbox-button:active { - @if(mixin-exists(hook-lightbox-button-active)) {@include hook-lightbox-button-active();} -} - - -/* Caption - ========================================================================== */ - -.uk-lightbox-caption:empty { display: none; } - - -/* Iframe - ========================================================================== */ - -.uk-lightbox-iframe { - width: 80%; - height: 80%; -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-lightbox-misc)) {@include hook-lightbox-misc();} - -// @mixin hook-lightbox(){} -// @mixin hook-lightbox-item(){} -// @mixin hook-lightbox-toolbar(){} -// @mixin hook-lightbox-toolbar-icon(){} -// @mixin hook-lightbox-toolbar-icon-hover(){} -// @mixin hook-lightbox-button(){} -// @mixin hook-lightbox-button-hover(){} -// @mixin hook-lightbox-button-active(){} -// @mixin hook-lightbox-misc(){} diff --git a/docs/_sass/uikit/components/link.scss b/docs/_sass/uikit/components/link.scss deleted file mode 100644 index 2df663525a..0000000000 --- a/docs/_sass/uikit/components/link.scss +++ /dev/null @@ -1,140 +0,0 @@ -// Name: Link -// Description: Styles for links -// -// Component: `uk-link-muted` -// `uk-link-text` -// `uk-link-heading` -// `uk-link-reset` -// -// Sub-objects: `uk-link-toggle` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$link-muted-color: $global-muted-color !default; -$link-muted-hover-color: $global-color !default; - -$link-text-hover-color: $global-muted-color !default; - -$link-heading-hover-color: $global-primary-background !default; -$link-heading-hover-text-decoration: none !default; - - -/* ======================================================================== - Component: Link - ========================================================================== */ - - -/* Muted - ========================================================================== */ - -a.uk-link-muted, -.uk-link-muted a { - color: $link-muted-color; - @if(mixin-exists(hook-link-muted)) {@include hook-link-muted();} -} - -a.uk-link-muted:hover, -.uk-link-muted a:hover, -.uk-link-toggle:hover .uk-link-muted, -.uk-link-toggle:focus .uk-link-muted { - color: $link-muted-hover-color; - @if(mixin-exists(hook-link-muted-hover)) {@include hook-link-muted-hover();} -} - - -/* Text - ========================================================================== */ - -a.uk-link-text, -.uk-link-text a { - color: inherit; - @if(mixin-exists(hook-link-text)) {@include hook-link-text();} -} - -a.uk-link-text:hover, -.uk-link-text a:hover, -.uk-link-toggle:hover .uk-link-text, -.uk-link-toggle:focus .uk-link-text { - color: $link-text-hover-color; - @if(mixin-exists(hook-link-text-hover)) {@include hook-link-text-hover();} -} - - -/* Heading - ========================================================================== */ - -a.uk-link-heading, -.uk-link-heading a { - color: inherit; - @if(mixin-exists(hook-link-heading)) {@include hook-link-heading();} -} - -a.uk-link-heading:hover, -.uk-link-heading a:hover, -.uk-link-toggle:hover .uk-link-heading, -.uk-link-toggle:focus .uk-link-heading { - color: $link-heading-hover-color; - text-decoration: $link-heading-hover-text-decoration; - @if(mixin-exists(hook-link-heading-hover)) {@include hook-link-heading-hover();} -} - - -/* Reset - ========================================================================== */ - -/* - * `!important` needed to override inverse component - */ - -a.uk-link-reset, -.uk-link-reset a { - color: inherit !important; - text-decoration: none !important; - @if(mixin-exists(hook-link-reset)) {@include hook-link-reset();} -} - - -/* Toggle - ========================================================================== */ - -.uk-link-toggle { - color: inherit !important; - text-decoration: none !important; -} - -.uk-link-toggle:focus { outline: none; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-link-misc)) {@include hook-link-misc();} - -// @mixin hook-link-muted(){} -// @mixin hook-link-muted-hover(){} -// @mixin hook-link-text(){} -// @mixin hook-link-text-hover(){} -// @mixin hook-link-heading(){} -// @mixin hook-link-heading-hover(){} -// @mixin hook-link-reset(){} -// @mixin hook-link-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-link-muted-color: $inverse-global-muted-color !default; -$inverse-link-muted-hover-color: $inverse-global-color !default; -$inverse-link-text-hover-color: $inverse-global-muted-color !default; -$inverse-link-heading-hover-color: $inverse-global-primary-background !default; - - - -// @mixin hook-inverse-link-muted(){} -// @mixin hook-inverse-link-muted-hover(){} -// @mixin hook-inverse-link-text-hover(){} -// @mixin hook-inverse-link-heading-hover(){} diff --git a/docs/_sass/uikit/components/list.scss b/docs/_sass/uikit/components/list.scss deleted file mode 100644 index bc66eb3b50..0000000000 --- a/docs/_sass/uikit/components/list.scss +++ /dev/null @@ -1,235 +0,0 @@ -// Name: List -// Description: Styles for lists -// -// Component: `uk-list` -// -// Modifiers: `uk-list-disc` -// `uk-list-circle` -// `uk-list-square` -// `uk-list-decimal` -// `uk-list-hyphen` -// `uk-list-muted` -// `uk-list-emphasis` -// `uk-list-primary` -// `uk-list-secondary` -// `uk-list-bullet` -// `uk-list-divider` -// `uk-list-striped` -// `uk-list-large` -// `uk-list-collapse` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$list-margin-top: $global-small-margin !default; - -$list-padding-left: 30px !default; - -$list-marker-height: ($global-line-height * 1em) !default; - -$list-muted-color: $global-muted-color !default; -$list-emphasis-color: $global-emphasis-color !default; -$list-primary-color: $global-primary-background !default; -$list-secondary-color: $global-secondary-background !default; - -$list-bullet-icon-color: $global-color !default; - -$list-divider-margin-top: $global-small-margin !default; -$list-divider-border-width: $global-border-width !default; -$list-divider-border: $global-border !default; - -$list-striped-padding-vertical: $global-small-margin !default; -$list-striped-padding-horizontal: $global-small-margin !default; -$list-striped-background: $global-muted-background !default; - -$list-large-margin-top: $global-margin !default; -$list-large-divider-margin-top: $global-margin !default; -$list-large-striped-padding-vertical: $global-margin !default; -$list-large-striped-padding-horizontal: $global-small-margin !default; - -$internal-list-bullet-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22#000%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; - - -/* ======================================================================== - Component: List - ========================================================================== */ - -.uk-list { - padding: 0; - list-style: none; -} - -/* - * Remove margin from the last-child - */ - -.uk-list > * > :last-child { margin-bottom: 0; } - -/* - * Style - */ - -.uk-list > :nth-child(n+2), -.uk-list > * > ul { margin-top: $list-margin-top; } - - -/* Marker modifiers - * Moving `::marker` inside `::before` to style it differently - * To style the `::marker` is currently only supported in Firefox and Safari - ========================================================================== */ - -.uk-list-disc > *, -.uk-list-circle > *, -.uk-list-square > *, -.uk-list-decimal > *, -.uk-list-hyphen > * { padding-left: $list-padding-left; } - -/* - * Type modifiers - */ - -.uk-list-decimal { counter-reset: decimal; } -.uk-list-decimal > * { counter-increment: decimal; } - -[class*='uk-list'] > ::before { - content: ''; - position: relative; - left: (-$list-padding-left); - width: $list-padding-left; - height: $list-marker-height; - margin-bottom: (-$list-marker-height); - display: list-item; - list-style-position: inside; - text-align: right; -} - -.uk-list-disc > ::before { list-style-type: disc; } -.uk-list-circle > ::before { list-style-type: circle; } -.uk-list-square > ::before { list-style-type: square; } -.uk-list-decimal > ::before { content: counter(decimal, decimal) '\200A.\00A0'; } -.uk-list-hyphen > ::before { content: '–\00A0\00A0'; } - -/* - * Color modifiers - */ - -.uk-list-muted > ::before { color: $list-muted-color !important; } -.uk-list-emphasis > ::before { color: $list-emphasis-color !important; } -.uk-list-primary > ::before { color: $list-primary-color !important; } -.uk-list-secondary > ::before { color: $list-secondary-color !important; } - - -/* Image bullet modifier - ========================================================================== */ - -.uk-list-bullet > * { padding-left: $list-padding-left; } - -.uk-list-bullet > ::before { - content: ""; - position: relative; - left: (-$list-padding-left); - width: $list-padding-left; - height: $list-marker-height; - margin-bottom: (-$list-marker-height); - @include svg-fill($internal-list-bullet-image, "#000", $list-bullet-icon-color); - background-repeat: no-repeat; - background-position: 50% 50%; -} - - -/* Style modifiers - ========================================================================== */ - -/* - * Divider - */ - -.uk-list-divider > :nth-child(n+2) { - margin-top: $list-divider-margin-top; - padding-top: $list-divider-margin-top; - border-top: $list-divider-border-width solid $list-divider-border; - @if(mixin-exists(hook-list-divider)) {@include hook-list-divider();} -} - -/* - * Striped - */ - -.uk-list-striped > * { - padding: $list-striped-padding-vertical $list-striped-padding-horizontal; - @if(mixin-exists(hook-list-striped)) {@include hook-list-striped();} -} - -.uk-list-striped > :nth-of-type(odd) { background: $list-striped-background; } - -.uk-list-striped > :nth-child(n+2) { margin-top: 0; } - - -/* Size modifier - ========================================================================== */ - -.uk-list-large > :nth-child(n+2), -.uk-list-large > * > ul { margin-top: $list-large-margin-top; } - -.uk-list-collapse > :nth-child(n+2), -.uk-list-collapse > * > ul { margin-top: 0; } - -/* - * Divider - */ - -.uk-list-large.uk-list-divider > :nth-child(n+2) { - margin-top: $list-large-divider-margin-top; - padding-top: $list-large-divider-margin-top; -} - -.uk-list-collapse.uk-list-divider > :nth-child(n+2) { - margin-top: 0; - padding-top: 0; -} - -/* - * Striped - */ - -.uk-list-large.uk-list-striped > * { padding: $list-large-striped-padding-vertical $list-large-striped-padding-horizontal; } - -.uk-list-collapse.uk-list-striped > * { - padding-top: 0; - padding-bottom: 0; -} - -.uk-list-large.uk-list-striped > :nth-child(n+2), -.uk-list-collapse.uk-list-striped > :nth-child(n+2) { margin-top: 0; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-list-misc)) {@include hook-list-misc();} - -// @mixin hook-list-divider(){} -// @mixin hook-list-striped(){} -// @mixin hook-list-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-list-muted-color: $inverse-global-muted-color !default; -$inverse-list-emphasis-color: $inverse-global-emphasis-color !default; -$inverse-list-primary-color: $inverse-global-primary-background !default; -$inverse-list-secondary-color: $inverse-global-primary-background !default; - -$inverse-list-divider-border: $inverse-global-border !default; -$inverse-list-striped-background: $inverse-global-muted-background !default; - -$inverse-list-bullet-icon-color: $inverse-global-color !default; - - - -// @mixin hook-inverse-list-divider(){} -// @mixin hook-inverse-list-striped(){} diff --git a/docs/_sass/uikit/components/margin.scss b/docs/_sass/uikit/components/margin.scss deleted file mode 100644 index 87d948dc2a..0000000000 --- a/docs/_sass/uikit/components/margin.scss +++ /dev/null @@ -1,250 +0,0 @@ -// Name: Margin -// Description: Utilities for margins -// -// Component: `uk-margin-*` -// `uk-margin-small-*` -// `uk-margin-medium-*` -// `uk-margin-large-*` -// `uk-margin-xlarge-*` -// `uk-margin-remove-*` -// `uk-margin-auto-*` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$margin-margin: $global-margin !default; - -$margin-small-margin: $global-small-margin !default; - -$margin-medium-margin: $global-medium-margin !default; - -$margin-large-margin: $global-medium-margin !default; -$margin-large-margin-l: $global-large-margin !default; - -$margin-xlarge-margin: $global-large-margin !default; -$margin-xlarge-margin-l: $global-xlarge-margin !default; - - -/* ======================================================================== - Component: Margin - ========================================================================== */ - -/* - * Default - */ - -.uk-margin { margin-bottom: $margin-margin; } -* + .uk-margin { margin-top: $margin-margin !important; } - -.uk-margin-top { margin-top: $margin-margin !important; } -.uk-margin-bottom { margin-bottom: $margin-margin !important; } -.uk-margin-left { margin-left: $margin-margin !important; } -.uk-margin-right { margin-right: $margin-margin !important; } - - -/* Small - ========================================================================== */ - -.uk-margin-small { margin-bottom: $margin-small-margin; } -* + .uk-margin-small { margin-top: $margin-small-margin !important; } - -.uk-margin-small-top { margin-top: $margin-small-margin !important; } -.uk-margin-small-bottom { margin-bottom: $margin-small-margin !important; } -.uk-margin-small-left { margin-left: $margin-small-margin !important; } -.uk-margin-small-right { margin-right: $margin-small-margin !important; } - - -/* Medium - ========================================================================== */ - -.uk-margin-medium { margin-bottom: $margin-medium-margin; } -* + .uk-margin-medium { margin-top: $margin-medium-margin !important; } - -.uk-margin-medium-top { margin-top: $margin-medium-margin !important; } -.uk-margin-medium-bottom { margin-bottom: $margin-medium-margin !important; } -.uk-margin-medium-left { margin-left: $margin-medium-margin !important; } -.uk-margin-medium-right { margin-right: $margin-medium-margin !important; } - - -/* Large - ========================================================================== */ - -.uk-margin-large { margin-bottom: $margin-large-margin; } -* + .uk-margin-large { margin-top: $margin-large-margin !important; } - -.uk-margin-large-top { margin-top: $margin-large-margin !important; } -.uk-margin-large-bottom { margin-bottom: $margin-large-margin !important; } -.uk-margin-large-left { margin-left: $margin-large-margin !important; } -.uk-margin-large-right { margin-right: $margin-large-margin !important; } - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-margin-large { margin-bottom: $margin-large-margin-l; } - * + .uk-margin-large { margin-top: $margin-large-margin-l !important; } - - .uk-margin-large-top { margin-top: $margin-large-margin-l !important; } - .uk-margin-large-bottom { margin-bottom: $margin-large-margin-l !important; } - .uk-margin-large-left { margin-left: $margin-large-margin-l !important; } - .uk-margin-large-right { margin-right: $margin-large-margin-l !important; } - -} - - -/* XLarge - ========================================================================== */ - -.uk-margin-xlarge { margin-bottom: $margin-xlarge-margin; } -* + .uk-margin-xlarge { margin-top: $margin-xlarge-margin !important; } - -.uk-margin-xlarge-top { margin-top: $margin-xlarge-margin !important; } -.uk-margin-xlarge-bottom { margin-bottom: $margin-xlarge-margin !important; } -.uk-margin-xlarge-left { margin-left: $margin-xlarge-margin !important; } -.uk-margin-xlarge-right { margin-right: $margin-xlarge-margin !important; } - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-margin-xlarge { margin-bottom: $margin-xlarge-margin-l; } - * + .uk-margin-xlarge { margin-top: $margin-xlarge-margin-l !important; } - - .uk-margin-xlarge-top { margin-top: $margin-xlarge-margin-l !important; } - .uk-margin-xlarge-bottom { margin-bottom: $margin-xlarge-margin-l !important; } - .uk-margin-xlarge-left { margin-left: $margin-xlarge-margin-l !important; } - .uk-margin-xlarge-right { margin-right: $margin-xlarge-margin-l !important; } - -} - - -/* Auto - ========================================================================== */ - -.uk-margin-auto { - margin-left: auto !important; - margin-right: auto !important; -} - -.uk-margin-auto-top { margin-top: auto !important; } -.uk-margin-auto-bottom { margin-bottom: auto !important; } -.uk-margin-auto-left { margin-left: auto !important; } -.uk-margin-auto-right { margin-right: auto !important; } - -.uk-margin-auto-vertical { - margin-top: auto !important; - margin-bottom: auto !important; -} - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-margin-auto\@s { - margin-left: auto !important; - margin-right: auto !important; - } - - .uk-margin-auto-left\@s { margin-left: auto !important; } - .uk-margin-auto-right\@s { margin-right: auto !important; } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-margin-auto\@m { - margin-left: auto !important; - margin-right: auto !important; - } - - .uk-margin-auto-left\@m { margin-left: auto !important; } - .uk-margin-auto-right\@m { margin-right: auto !important; } - -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-margin-auto\@l { - margin-left: auto !important; - margin-right: auto !important; - } - - .uk-margin-auto-left\@l { margin-left: auto !important; } - .uk-margin-auto-right\@l { margin-right: auto !important; } - -} - -/* Large screen and bigger */ -@media (min-width: $breakpoint-xlarge) { - - .uk-margin-auto\@xl { - margin-left: auto !important; - margin-right: auto !important; - } - - .uk-margin-auto-left\@xl { margin-left: auto !important; } - .uk-margin-auto-right\@xl { margin-right: auto !important; } - -} - - -/* Remove - ========================================================================== */ - - .uk-margin-remove { margin: 0 !important; } - .uk-margin-remove-top { margin-top: 0 !important; } - .uk-margin-remove-bottom { margin-bottom: 0 !important; } - .uk-margin-remove-left { margin-left: 0 !important; } - .uk-margin-remove-right { margin-right: 0 !important; } - - .uk-margin-remove-vertical { - margin-top: 0 !important; - margin-bottom: 0 !important; - } - - .uk-margin-remove-adjacent + *, - .uk-margin-remove-first-child > :first-child { margin-top: 0 !important; } - .uk-margin-remove-last-child > :last-child { margin-bottom: 0 !important; } - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-margin-remove-left\@s { margin-left: 0 !important; } - .uk-margin-remove-right\@s { margin-right: 0 !important; } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-margin-remove-left\@m { margin-left: 0 !important; } - .uk-margin-remove-right\@m { margin-right: 0 !important; } - -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-margin-remove-left\@l { margin-left: 0 !important; } - .uk-margin-remove-right\@l { margin-right: 0 !important; } - -} - -/* Large screen and bigger */ -@media (min-width: $breakpoint-xlarge) { - - .uk-margin-remove-left\@xl { margin-left: 0 !important; } - .uk-margin-remove-right\@xl { margin-right: 0 !important; } - -} - - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-margin-misc)) {@include hook-margin-misc();} - -// @mixin hook-margin-misc(){} diff --git a/docs/_sass/uikit/components/marker.scss b/docs/_sass/uikit/components/marker.scss deleted file mode 100644 index 97e436098c..0000000000 --- a/docs/_sass/uikit/components/marker.scss +++ /dev/null @@ -1,63 +0,0 @@ -// Name: Marker -// Description: Component to create a marker icon -// -// Component: `uk-marker` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$marker-padding: 5px !default; -$marker-background: $global-secondary-background !default; -$marker-color: $global-inverse-color !default; - -$marker-hover-color: $global-inverse-color !default; - - -/* ======================================================================== - Component: Marker - ========================================================================== */ - -/* - * Addopts `uk-icon` - */ - -.uk-marker { - padding: $marker-padding; - background: $marker-background; - color: $marker-color; - @if(mixin-exists(hook-marker)) {@include hook-marker();} -} - -/* Hover + Focus */ -.uk-marker:hover, -.uk-marker:focus { - color: $marker-hover-color; - outline: none; - @if(mixin-exists(hook-marker-hover)) {@include hook-marker-hover();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-marker-misc)) {@include hook-marker-misc();} - -// @mixin hook-marker(){} -// @mixin hook-marker-hover(){} -// @mixin hook-marker-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-marker-background: $global-muted-background !default; -$inverse-marker-color: $global-color !default; -$inverse-marker-hover-color: $global-color !default; - - - -// @mixin hook-inverse-marker(){} -// @mixin hook-inverse-marker-hover(){} diff --git a/docs/_sass/uikit/components/mixin.scss b/docs/_sass/uikit/components/mixin.scss deleted file mode 100644 index 5ed438a569..0000000000 --- a/docs/_sass/uikit/components/mixin.scss +++ /dev/null @@ -1,32 +0,0 @@ -// -// Component: Mixin -// Description: Defines mixins which are used across all components -// -// ======================================================================== - - -// SVG -// ======================================================================== - -/// Replace `$search` with `$replace` in `$string` -/// @author Hugo Giraudel -/// @param {String} $string - Initial string -/// @param {String} $search - Substring to replace -/// @param {String} $replace ('') - New value -/// @return {String} - Updated string -@function str-replace($string, $search, $replace: '') { - $index: str-index($string, $search); - - @if $index { - @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); - } - - @return $string; -} - -@mixin svg-fill($src, $color-default, $color-new){ - - $replace-src: str-replace($src, $color-default, $color-new) !default; - $replace-src: str-replace($replace-src, "#", "%23"); - background-image: url(https://github.com/quote($replace-src)); -} \ No newline at end of file diff --git a/docs/_sass/uikit/components/modal.scss b/docs/_sass/uikit/components/modal.scss deleted file mode 100644 index e93c99ca5d..0000000000 --- a/docs/_sass/uikit/components/modal.scss +++ /dev/null @@ -1,353 +0,0 @@ -// Name: Modal -// Description: Component to create modal dialogs -// -// Component: `uk-modal` -// -// Sub-objects: `uk-modal-page` -// `uk-modal-dialog` -// `uk-modal-header` -// `uk-modal-body` -// `uk-modal-footer` -// `uk-modal-title` -// `uk-modal-close` -// -// Adopted: `uk-modal-close-default` -// `uk-modal-close-outside` -// `uk-modal-close-full` -// -// Modifiers: `uk-modal-container` -// `uk-modal-full` -// -// States: `uk-open` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$modal-z-index: $global-z-index + 10 !default; -$modal-background: rgba(0,0,0,0.6) !default; - -$modal-padding-horizontal: 15px !default; -$modal-padding-horizontal-s: $global-gutter !default; -$modal-padding-horizontal-m: $global-medium-gutter !default; -$modal-padding-vertical: $modal-padding-horizontal !default; -$modal-padding-vertical-s: 50px !default; - -$modal-dialog-width: 600px !default; -$modal-dialog-background: $global-background !default; - -$modal-container-width: 1200px !default; - -$modal-body-padding-horizontal: $global-gutter !default; -$modal-body-padding-vertical: $global-gutter !default; - -$modal-header-padding-horizontal: $global-gutter !default; -$modal-header-padding-vertical: ($modal-header-padding-horizontal / 2) !default; -$modal-header-background: $global-muted-background !default; - -$modal-footer-padding-horizontal: $global-gutter !default; -$modal-footer-padding-vertical: ($modal-footer-padding-horizontal / 2) !default; -$modal-footer-background: $global-muted-background !default; - -$modal-title-font-size: $global-xlarge-font-size !default; -$modal-title-line-height: 1.3 !default; - -$modal-close-position: $global-small-margin !default; -$modal-close-padding: 5px !default; - -$modal-close-outside-position: 0 !default; -$modal-close-outside-translate: 100% !default; -$modal-close-outside-color: lighten($global-inverse-color, 20%) !default; -$modal-close-outside-hover-color: $global-inverse-color !default; - - -/* ======================================================================== - Component: Modal - ========================================================================== */ - -/* - * 1. Hide by default - * 2. Set position - * 3. Allow scrolling for the modal dialog - * 4. Horizontal padding - * 5. Mask the background page - * 6. Fade-in transition - */ - -.uk-modal { - /* 1 */ - display: none; - /* 2 */ - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: $modal-z-index; - /* 3 */ - overflow-y: auto; - -webkit-overflow-scrolling: touch; - /* 4 */ - padding: $modal-padding-vertical $modal-padding-horizontal; - /* 5 */ - background: $modal-background; - /* 6 */ - opacity: 0; - transition: opacity 0.15s linear; - @if(mixin-exists(hook-modal)) {@include hook-modal();} -} - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-modal { padding: $modal-padding-vertical-s $modal-padding-horizontal-s; } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-modal { - padding-left: $modal-padding-horizontal-m; - padding-right: $modal-padding-horizontal-m; - } - -} - -/* - * Open - */ - -.uk-modal.uk-open { opacity: 1; } - - -/* Page - ========================================================================== */ - -/* - * Prevent scrollbars - */ - -.uk-modal-page { overflow: hidden; } - - -/* Dialog - ========================================================================== */ - -/* - * 1. Create position context for spinner and close button - * 2. Dimensions - * 3. Fix `max-width: 100%` not working in combination with flex and responsive images in IE11 - * `!important` needed to overwrite `uk-width-auto`. See `#modal-media-image` in tests - * 4. Style - * 5. Slide-in transition - */ - -.uk-modal-dialog { - /* 1 */ - position: relative; - /* 2 */ - box-sizing: border-box; - margin: 0 auto; - width: $modal-dialog-width; - /* 3 */ - max-width: unquote('calc(100% - 0.01px)') !important; - /* 4 */ - background: $modal-dialog-background; - /* 5 */ - opacity: 0; - transform: translateY(-100px); - transition: 0.3s linear; - transition-property: opacity, transform; - @if(mixin-exists(hook-modal-dialog)) {@include hook-modal-dialog();} -} - -/* - * Open - */ - -.uk-open > .uk-modal-dialog { - opacity: 1; - transform: translateY(0); -} - - -/* Size modifier - ========================================================================== */ - -/* - * Container size - * Take the same size as the Container component - */ - -.uk-modal-container .uk-modal-dialog { width: $modal-container-width; } - -/* - * Full size - * 1. Remove padding and background from modal - * 2. Reset all default declarations from modal dialog - */ - -/* 1 */ -.uk-modal-full { - padding: 0; - background: none; -} - -/* 2 */ -.uk-modal-full .uk-modal-dialog { - margin: 0; - width: 100%; - max-width: 100%; - transform: translateY(0); - @if(mixin-exists(hook-modal-full)) {@include hook-modal-full();} -} - - -/* Sections - ========================================================================== */ - -.uk-modal-body { - display: flow-root; - padding: $modal-body-padding-vertical $modal-body-padding-horizontal; - @if(mixin-exists(hook-modal-body)) {@include hook-modal-body();} -} - -.uk-modal-header { - display: flow-root; - padding: $modal-header-padding-vertical $modal-header-padding-horizontal; - background: $modal-header-background; - @if(mixin-exists(hook-modal-header)) {@include hook-modal-header();} -} - -.uk-modal-footer { - display: flow-root; - padding: $modal-footer-padding-vertical $modal-footer-padding-horizontal; - background: $modal-footer-background; - @if(mixin-exists(hook-modal-footer)) {@include hook-modal-footer();} -} - -/* - * Remove margin from the last-child - */ - -.uk-modal-body > :last-child, -.uk-modal-header > :last-child, -.uk-modal-footer > :last-child { margin-bottom: 0; } - - -/* Title - ========================================================================== */ - -.uk-modal-title { - font-size: $modal-title-font-size; - line-height: $modal-title-line-height; - @if(mixin-exists(hook-modal-title)) {@include hook-modal-title();} -} - - -/* Close - * Adopts `uk-close` - ========================================================================== */ - -[class*='uk-modal-close-'] { - position: absolute; - z-index: $modal-z-index; - top: $modal-close-position; - right: $modal-close-position; - padding: $modal-close-padding; - @if(mixin-exists(hook-modal-close)) {@include hook-modal-close();} -} - -/* - * Remove margin from adjacent element - */ - -[class*='uk-modal-close-']:first-child + * { margin-top: 0; } - -/* - * Hover - */ - -[class*='uk-modal-close-']:hover { - @if(mixin-exists(hook-modal-close-hover)) {@include hook-modal-close-hover();} -} - -/* - * Default - */ - -.uk-modal-close-default { - @if(mixin-exists(hook-modal-close-default)) {@include hook-modal-close-default();} -} - -.uk-modal-close-default:hover { - @if(mixin-exists(hook-modal-close-default-hover)) {@include hook-modal-close-default-hover();} -} - -/* - * Outside - * 1. Prevent scrollbar on small devices - */ - -.uk-modal-close-outside { - top: $modal-close-outside-position; - /* 1 */ - right: (-$modal-close-padding); - transform: translate(0, -($modal-close-outside-translate)); - color: $modal-close-outside-color; - @if(mixin-exists(hook-modal-close-outside)) {@include hook-modal-close-outside();} -} - -.uk-modal-close-outside:hover { - color: $modal-close-outside-hover-color; - @if(mixin-exists(hook-modal-close-outside-hover)) {@include hook-modal-close-outside-hover();} -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - /* 1 */ - .uk-modal-close-outside { - right: $modal-close-outside-position; - transform: translate($modal-close-outside-translate, -($modal-close-outside-translate)); - } - -} - -/* - * Full - */ - -.uk-modal-close-full { - @if(mixin-exists(hook-modal-close-full)) {@include hook-modal-close-full();} -} - -.uk-modal-close-full:hover { - @if(mixin-exists(hook-modal-close-full-hover)) {@include hook-modal-close-full-hover();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-modal-misc)) {@include hook-modal-misc();} - -// @mixin hook-modal(){} -// @mixin hook-modal-dialog(){} -// @mixin hook-modal-full(){} -// @mixin hook-modal-header(){} -// @mixin hook-modal-body(){} -// @mixin hook-modal-footer(){} -// @mixin hook-modal-title(){} -// @mixin hook-modal-close(){} -// @mixin hook-modal-close-hover(){} -// @mixin hook-modal-close-default(){} -// @mixin hook-modal-close-default-hover(){} -// @mixin hook-modal-close-outside(){} -// @mixin hook-modal-close-outside-hover(){} -// @mixin hook-modal-close-full(){} -// @mixin hook-modal-close-full-hover(){} -// @mixin hook-modal-misc(){} diff --git a/docs/_sass/uikit/components/nav.scss b/docs/_sass/uikit/components/nav.scss deleted file mode 100644 index 78b0f6015d..0000000000 --- a/docs/_sass/uikit/components/nav.scss +++ /dev/null @@ -1,406 +0,0 @@ -// Name: Nav -// Description: Defines styles for list navigations -// -// Component: `uk-nav` -// -// Sub-objects: `uk-nav-header` -// `uk-nav-divider` -// `uk-nav-sub` -// -// Modifiers: `uk-nav-parent-icon` -// `uk-nav-default` -// `uk-nav-primary` -// `uk-nav-center`, -// `uk-nav-divider` -// -// States: `uk-active` -// `uk-parent` -// `uk-open` -// `uk-touch` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$nav-item-padding-vertical: 5px !default; -$nav-item-padding-horizontal: 0 !default; - -$nav-sublist-padding-vertical: 5px !default; -$nav-sublist-padding-left: 15px !default; -$nav-sublist-deeper-padding-left: 15px !default; -$nav-sublist-item-padding-vertical: 2px !default; - -$nav-parent-icon-width: ($global-line-height * 1em) !default; -$nav-parent-icon-height: $nav-parent-icon-width !default; -$nav-parent-icon-color: $global-color !default; - -$nav-header-padding-vertical: $nav-item-padding-vertical !default; -$nav-header-padding-horizontal: $nav-item-padding-horizontal !default; -$nav-header-font-size: $global-small-font-size !default; -$nav-header-text-transform: uppercase !default; -$nav-header-margin-top: $global-margin !default; - -$nav-divider-margin-vertical: 5px !default; -$nav-divider-margin-horizontal: 0 !default; - -$nav-default-item-color: $global-muted-color !default; -$nav-default-item-hover-color: $global-color !default; -$nav-default-item-active-color: $global-emphasis-color !default; -$nav-default-header-color: $global-emphasis-color !default; -$nav-default-divider-border-width: $global-border-width !default; -$nav-default-divider-border: $global-border !default; -$nav-default-sublist-item-color: $global-muted-color !default; -$nav-default-sublist-item-hover-color: $global-color !default; -$nav-default-sublist-item-active-color: $global-emphasis-color !default; - -$nav-primary-item-font-size: $global-large-font-size !default; -$nav-primary-item-line-height: $global-line-height !default; -$nav-primary-item-color: $global-muted-color !default; -$nav-primary-item-hover-color: $global-color !default; -$nav-primary-item-active-color: $global-emphasis-color !default; -$nav-primary-header-color: $global-emphasis-color !default; -$nav-primary-divider-border-width: $global-border-width !default; -$nav-primary-divider-border: $global-border !default; -$nav-primary-sublist-item-color: $global-muted-color !default; -$nav-primary-sublist-item-hover-color: $global-color !default; -$nav-primary-sublist-item-active-color: $global-emphasis-color !default; - -$nav-dividers-margin-top: 0 !default; -$nav-dividers-border-width: $global-border-width !default; -$nav-dividers-border: $global-border !default; - -$internal-nav-parent-close-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%221.1%22%20points%3D%2210%201%204%207%2010%2013%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$internal-nav-parent-open-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%221.1%22%20points%3D%221%204%207%2010%2013%204%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; - - -/* ======================================================================== - Component: Nav - ========================================================================== */ - -/* - * Reset - */ - -.uk-nav, -.uk-nav ul { - margin: 0; - padding: 0; - list-style: none; -} - -/* -* 1. Center content vertically, e.g. an icon -* 2. Imitate white space gap when using flexbox -* 3. Reset link -* 4. Space is allocated solely based on content dimensions: 0 0 auto - */ - -.uk-nav li > a { - /* 1 */ - display: flex; - align-items: center; - /* 2 */ - column-gap: 0.25em; - /* 3*/ - text-decoration: none; -} - -/* 4 */ -.uk-nav li > a > * { flex: none; } - -/* - * Remove default focus style - */ - -.uk-nav li > a:focus { outline: none; } - -/* - * Items - * Must target `a` elements to exclude other elements (e.g. lists) - */ - -.uk-nav > li > a { padding: $nav-item-padding-vertical $nav-item-padding-horizontal; } - - -/* Sublists - ========================================================================== */ - -/* - * Level 2 - * `ul` needed for higher specificity to override padding - */ - -ul.uk-nav-sub { - padding: $nav-sublist-padding-vertical 0 $nav-sublist-padding-vertical $nav-sublist-padding-left; - @if(mixin-exists(hook-nav-sub)) {@include hook-nav-sub();} -} - -/* - * Level 3 and deeper - */ - -.uk-nav-sub ul { padding-left: $nav-sublist-deeper-padding-left; } - -/* - * Items - */ - -.uk-nav-sub a { padding: $nav-sublist-item-padding-vertical 0; } - - -/* Parent icon modifier - ========================================================================== */ - -.uk-nav-parent-icon > .uk-parent > a::after { - content: ""; - width: $nav-parent-icon-width; - height: $nav-parent-icon-height; - margin-left: auto; - @include svg-fill($internal-nav-parent-close-image, "#000", $nav-parent-icon-color); - background-repeat: no-repeat; - background-position: 50% 50%; - @if(mixin-exists(hook-nav-parent-icon)) {@include hook-nav-parent-icon();} -} - -.uk-nav-parent-icon > .uk-parent.uk-open > a::after { @include svg-fill($internal-nav-parent-open-image, "#000", $nav-parent-icon-color); } - - -/* Header - ========================================================================== */ - -.uk-nav-header { - padding: $nav-header-padding-vertical $nav-header-padding-horizontal; - text-transform: $nav-header-text-transform; - font-size: $nav-header-font-size; - @if(mixin-exists(hook-nav-header)) {@include hook-nav-header();} -} - -.uk-nav-header:not(:first-child) { margin-top: $nav-header-margin-top; } - - -/* Divider - ========================================================================== */ - -.uk-nav >.uk-nav-divider { - margin: $nav-divider-margin-vertical $nav-divider-margin-horizontal; - @if(mixin-exists(hook-nav-divider)) {@include hook-nav-divider();} -} - - -/* Default modifier - ========================================================================== */ - -.uk-nav-default { - @if(mixin-exists(hook-nav-default)) {@include hook-nav-default();} -} - -/* - * Items - */ - -.uk-nav-default > li > a { - color: $nav-default-item-color; - @if(mixin-exists(hook-nav-default-item)) {@include hook-nav-default-item();} -} - -/* Hover + Focus */ -.uk-nav-default > li > a:hover, -.uk-nav-default > li > a:focus { - color: $nav-default-item-hover-color; - @if(mixin-exists(hook-nav-default-item-hover)) {@include hook-nav-default-item-hover();} -} - -/* Active */ -.uk-nav-default > li.uk-active > a { - color: $nav-default-item-active-color; - @if(mixin-exists(hook-nav-default-item-active)) {@include hook-nav-default-item-active();} -} - -/* - * Header - */ - -.uk-nav-default .uk-nav-header { - color: $nav-default-header-color; - @if(mixin-exists(hook-nav-default-header)) {@include hook-nav-default-header();} -} - -/* - * Divider - */ - -.uk-nav-default .uk-nav-divider { - border-top: $nav-default-divider-border-width solid $nav-default-divider-border; - @if(mixin-exists(hook-nav-default-divider)) {@include hook-nav-default-divider();} -} - -/* - * Sublists - */ - -.uk-nav-default .uk-nav-sub a { color: $nav-default-sublist-item-color; } - -.uk-nav-default .uk-nav-sub a:hover, -.uk-nav-default .uk-nav-sub a:focus { color: $nav-default-sublist-item-hover-color; } - -.uk-nav-default .uk-nav-sub li.uk-active > a { color: $nav-default-sublist-item-active-color; } - - -/* Primary modifier - ========================================================================== */ - -.uk-nav-primary { - @if(mixin-exists(hook-nav-primary)) {@include hook-nav-primary();} -} - -/* - * Items - */ - -.uk-nav-primary > li > a { - font-size: $nav-primary-item-font-size; - line-height: $nav-primary-item-line-height; - color: $nav-primary-item-color; - @if(mixin-exists(hook-nav-primary-item)) {@include hook-nav-primary-item();} -} - -/* Hover + Focus */ -.uk-nav-primary > li > a:hover, -.uk-nav-primary > li > a:focus { - color: $nav-primary-item-hover-color; - @if(mixin-exists(hook-nav-primary-item-hover)) {@include hook-nav-primary-item-hover();} -} - -/* Active */ -.uk-nav-primary > li.uk-active > a { - color: $nav-primary-item-active-color; - @if(mixin-exists(hook-nav-primary-item-active)) {@include hook-nav-primary-item-active();} -} - -/* - * Header - */ - -.uk-nav-primary .uk-nav-header { - color: $nav-primary-header-color; - @if(mixin-exists(hook-nav-primary-header)) {@include hook-nav-primary-header();} -} - -/* - * Divider - */ - -.uk-nav-primary .uk-nav-divider { - border-top: $nav-primary-divider-border-width solid $nav-primary-divider-border; - @if(mixin-exists(hook-nav-primary-divider)) {@include hook-nav-primary-divider();} -} - -/* - * Sublists - */ - -.uk-nav-primary .uk-nav-sub a { color: $nav-primary-sublist-item-color; } - -.uk-nav-primary .uk-nav-sub a:hover, -.uk-nav-primary .uk-nav-sub a:focus { color: $nav-primary-sublist-item-hover-color; } - -.uk-nav-primary .uk-nav-sub li.uk-active > a { color: $nav-primary-sublist-item-active-color; } - - -/* Alignment modifier - ========================================================================== */ - -/* - * 1. Center header - * 2. Center items - */ - - /* 1 */ -.uk-nav-center { text-align: center; } - /* 2 */ -.uk-nav-center li > a { justify-content: center; } - -/* Sublists */ -.uk-nav-center .uk-nav-sub, -.uk-nav-center .uk-nav-sub ul { padding-left: 0; } - -/* Parent icon modifier */ -.uk-nav-center.uk-nav-parent-icon > .uk-parent > a::after { margin-left: 0; } - - -/* Style modifier - ========================================================================== */ - -.uk-nav.uk-nav-divider > :not(.uk-nav-divider) + :not(.uk-nav-header, .uk-nav-divider) { - margin-top: $nav-dividers-margin-top; - padding-top: $nav-dividers-margin-top; - border-top: $nav-dividers-border-width solid $nav-dividers-border; - @if(mixin-exists(hook-nav-dividers)) {@include hook-nav-dividers();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-nav-misc)) {@include hook-nav-misc();} - -// @mixin hook-nav-sub(){} -// @mixin hook-nav-parent-icon(){} -// @mixin hook-nav-header(){} -// @mixin hook-nav-divider(){} -// @mixin hook-nav-default(){} -// @mixin hook-nav-default-item(){} -// @mixin hook-nav-default-item-hover(){} -// @mixin hook-nav-default-item-active(){} -// @mixin hook-nav-default-header(){} -// @mixin hook-nav-default-divider(){} -// @mixin hook-nav-primary(){} -// @mixin hook-nav-primary-item(){} -// @mixin hook-nav-primary-item-hover(){} -// @mixin hook-nav-primary-item-active(){} -// @mixin hook-nav-primary-header(){} -// @mixin hook-nav-primary-divider(){} -// @mixin hook-nav-dividers(){} -// @mixin hook-nav-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-nav-parent-icon-color: $inverse-global-color !default; -$inverse-nav-default-item-color: $inverse-global-muted-color !default; -$inverse-nav-default-item-hover-color: $inverse-global-color !default; -$inverse-nav-default-item-active-color: $inverse-global-emphasis-color !default; -$inverse-nav-default-header-color: $inverse-global-emphasis-color !default; -$inverse-nav-default-divider-border: $inverse-global-border !default; -$inverse-nav-default-sublist-item-color: $inverse-global-muted-color !default; -$inverse-nav-default-sublist-item-hover-color: $inverse-global-color !default; -$inverse-nav-default-sublist-item-active-color: $inverse-global-emphasis-color !default; - -$inverse-nav-primary-item-color: $inverse-global-muted-color !default; -$inverse-nav-primary-item-hover-color: $inverse-global-color !default; -$inverse-nav-primary-item-active-color: $inverse-global-emphasis-color !default; -$inverse-nav-primary-header-color: $inverse-global-emphasis-color !default; -$inverse-nav-primary-divider-border: $inverse-global-border !default; -$inverse-nav-primary-sublist-item-color: $inverse-global-muted-color !default; -$inverse-nav-primary-sublist-item-hover-color: $inverse-global-color !default; -$inverse-nav-primary-sublist-item-active-color: $inverse-global-emphasis-color !default; - -$inverse-nav-dividers-border: $inverse-global-border !default; - - - -// @mixin hook-inverse-nav-parent-icon(){} -// @mixin hook-inverse-nav-default-item(){} -// @mixin hook-inverse-nav-default-item-hover(){} -// @mixin hook-inverse-nav-default-item-active(){} -// @mixin hook-inverse-nav-default-header(){} -// @mixin hook-inverse-nav-default-divider(){} -// @mixin hook-inverse-nav-primary-item(){} -// @mixin hook-inverse-nav-primary-item-hover(){} -// @mixin hook-inverse-nav-primary-item-active(){} -// @mixin hook-inverse-nav-primary-header(){} -// @mixin hook-inverse-nav-primary-divider(){} -// @mixin hook-inverse-nav-dividers(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/navbar.scss b/docs/_sass/uikit/components/navbar.scss deleted file mode 100644 index 3cfd6a3a62..0000000000 --- a/docs/_sass/uikit/components/navbar.scss +++ /dev/null @@ -1,554 +0,0 @@ -// Name: Navbar -// Description: Component to create horizontal navigation bars -// -// Component: `uk-navbar` -// -// Sub-objects: `uk-navbar-container` -// `uk-navbar-left` -// `uk-navbar-right` -// `uk-navbar-center` -// `uk-navbar-center-left` -// `uk-navbar-center-right` -// `uk-navbar-nav` -// `uk-navbar-item` -// `uk-navbar-toggle` -// `uk-navbar-subtitle` -// `uk-navbar-dropbar` -// -// Adopted: `uk-navbar-dropdown` + Modifiers -// `uk-navbar-dropdown-nav` -// `uk-navbar-dropdown-grid` -// `uk-navbar-toggle-icon` -// -// Modifiers: `uk-navbar-primary` -// `uk-navbar-transparent` -// `uk-navbar-sticky` -// `uk-navbar-dropdown-stack` -// -// States: `uk-active` -// `uk-parent` -// `uk-open` -// -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$navbar-background: $global-muted-background !default; -$navbar-color-mode: none !default; - -$navbar-nav-item-height: 80px !default; -$navbar-nav-item-padding-horizontal: 15px !default; -$navbar-nav-item-color: $global-muted-color !default; -$navbar-nav-item-font-size: $global-font-size !default; -$navbar-nav-item-font-family: $global-font-family !default; -$navbar-nav-item-hover-color: $global-color !default; -$navbar-nav-item-onclick-color: $global-emphasis-color !default; -$navbar-nav-item-active-color: $global-emphasis-color !default; - -$navbar-item-color: $global-color !default; - -$navbar-toggle-color: $global-muted-color !default; -$navbar-toggle-hover-color: $global-color !default; - -$navbar-subtitle-font-size: $global-small-font-size !default; - -$navbar-dropdown-z-index: $global-z-index + 20 !default; -$navbar-dropdown-width: 200px !default; -$navbar-dropdown-margin: 0 !default; -$navbar-dropdown-padding: 15px !default; -$navbar-dropdown-background: $global-muted-background !default; -$navbar-dropdown-color: $global-color !default; -$navbar-dropdown-grid-gutter-horizontal: $global-gutter !default; -$navbar-dropdown-grid-gutter-vertical: $navbar-dropdown-grid-gutter-horizontal !default; - -$navbar-dropdown-dropbar-margin-top: 0 !default; -$navbar-dropdown-dropbar-margin-bottom: $navbar-dropdown-dropbar-margin-top !default; - -$navbar-dropdown-nav-item-color: $global-muted-color !default; -$navbar-dropdown-nav-item-hover-color: $global-color !default; -$navbar-dropdown-nav-item-active-color: $global-emphasis-color !default; -$navbar-dropdown-nav-header-color: $global-emphasis-color !default; -$navbar-dropdown-nav-divider-border-width: $global-border-width !default; -$navbar-dropdown-nav-divider-border: $global-border !default; -$navbar-dropdown-nav-sublist-item-color: $global-muted-color !default; -$navbar-dropdown-nav-sublist-item-hover-color: $global-color !default; -$navbar-dropdown-nav-sublist-item-active-color: $global-emphasis-color !default; - -$navbar-dropbar-background: $navbar-dropdown-background !default; -$navbar-dropbar-z-index: $global-z-index - 20 !default; - - -/* ======================================================================== - Component: Navbar - ========================================================================== */ - -/* - * 1. Create position context to center navbar group - */ - -.uk-navbar { - display: flex; - /* 1 */ - position: relative; - @if(mixin-exists(hook-navbar)) {@include hook-navbar();} -} - - -/* Container - ========================================================================== */ - -.uk-navbar-container:not(.uk-navbar-transparent) { - background: $navbar-background; - @if(mixin-exists(hook-navbar-container)) {@include hook-navbar-container();} -} - -// Color Mode -@if ( $navbar-color-mode == light ) { .uk-navbar-container:not(.uk-navbar-transparent) { @extend .uk-light !optional;} } -@if ( $navbar-color-mode == dark ) { .uk-navbar-container:not(.uk-navbar-transparent) { @extend .uk-dark !optional;} } - -/* - * Remove pseudo elements created by micro clearfix as precaution (if Container component is used) - */ - -.uk-navbar-container > ::before, -.uk-navbar-container > ::after { display: none !important; } - - -/* Groups - ========================================================================== */ - -/* - * 1. Align navs and items vertically if they have a different height - * 2. Note: IE 11 requires an extra `div` which affects the center selector - */ - -.uk-navbar-left, -.uk-navbar-right, -// 2. [class*='uk-navbar-center'], -.uk-navbar-center, -.uk-navbar-center-left > *, -.uk-navbar-center-right > * { - display: flex; - /* 1 */ - align-items: center; -} - -/* - * Horizontal alignment - * 1. Create position context for centered navbar with sub groups (left/right) - * 2. Fix text wrapping if content is larger than 50% of the container. - * 3. Needed for dropdowns because a new position context is created - * `z-index` must be smaller than off-canvas - * 4. Align sub groups for centered navbar - */ - -.uk-navbar-right { margin-left: auto; } - -.uk-navbar-center:only-child { - margin-left: auto; - margin-right: auto; - /* 1 */ - position: relative; -} - -.uk-navbar-center:not(:only-child) { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%,-50%); - /* 2 */ - width: max-content; - box-sizing: border-box; - /* 3 */ - z-index: $global-z-index - 10; -} - -/* 4 */ -.uk-navbar-center-left, -.uk-navbar-center-right { - position: absolute; - top: 0; -} - -.uk-navbar-center-left { right: 100%; } -.uk-navbar-center-right { left: 100%; } - -[class*='uk-navbar-center-'] { - width: max-content; - box-sizing: border-box; -} - - -/* Nav - ========================================================================== */ - -/* - * 1. Reset list - */ - -.uk-navbar-nav { - display: flex; - /* 1 */ - margin: 0; - padding: 0; - list-style: none; -} - -/* - * Allow items to wrap into the next line - * Only not `absolute` positioned groups - */ - -.uk-navbar-left, -.uk-navbar-right, -.uk-navbar-center:only-child { flex-wrap: wrap; } - -/* - * Items - * 1. Center content vertically and horizontally - * 2. Imitate white space gap when using flexbox - * 3. Dimensions - * 4. Style - * 5. Required for `a` - */ - -.uk-navbar-nav > li > a, // Nav item -.uk-navbar-item, // Content item -.uk-navbar-toggle { // Clickable item - /* 1 */ - display: flex; - justify-content: center; - align-items: center; - /* 2 */ - column-gap: 0.25em; - /* 3 */ - box-sizing: border-box; - min-height: $navbar-nav-item-height; - padding: 0 $navbar-nav-item-padding-horizontal; - /* 4 */ - font-size: $navbar-nav-item-font-size; - font-family: $navbar-nav-item-font-family; - /* 5 */ - text-decoration: none; -} - -/* - * Nav items - */ - -.uk-navbar-nav > li > a { - color: $navbar-nav-item-color; - @if(mixin-exists(hook-navbar-nav-item)) {@include hook-navbar-nav-item();} -} - -/* - * Hover - * Apply hover style also to focus state and if dropdown is opened - */ - -.uk-navbar-nav > li:hover > a, -.uk-navbar-nav > li > a:focus, -.uk-navbar-nav > li > a.uk-open { - color: $navbar-nav-item-hover-color; - outline: none; - @if(mixin-exists(hook-navbar-nav-item-hover)) {@include hook-navbar-nav-item-hover();} -} - -/* OnClick */ -.uk-navbar-nav > li > a:active { - color: $navbar-nav-item-onclick-color; - @if(mixin-exists(hook-navbar-nav-item-onclick)) {@include hook-navbar-nav-item-onclick();} -} - -/* Active */ -.uk-navbar-nav > li.uk-active > a { - color: $navbar-nav-item-active-color; - @if(mixin-exists(hook-navbar-nav-item-active)) {@include hook-navbar-nav-item-active();} -} - - -/* Item - ========================================================================== */ - -.uk-navbar-item { - color: $navbar-item-color; - @if(mixin-exists(hook-navbar-item)) {@include hook-navbar-item();} -} - -/* - * Remove margin from the last-child - */ - -.uk-navbar-item > :last-child { margin-bottom: 0; } - - -/* Toggle - ========================================================================== */ - -.uk-navbar-toggle { - color: $navbar-toggle-color; - @if(mixin-exists(hook-navbar-toggle)) {@include hook-navbar-toggle();} -} - -.uk-navbar-toggle:hover, -.uk-navbar-toggle:focus, -.uk-navbar-toggle.uk-open { - color: $navbar-toggle-hover-color; - outline: none; - text-decoration: none; - @if(mixin-exists(hook-navbar-toggle-hover)) {@include hook-navbar-toggle-hover();} -} - -/* - * Icon - * Adopts `uk-icon` - */ - -.uk-navbar-toggle-icon { - @if(mixin-exists(hook-navbar-toggle-icon)) {@include hook-navbar-toggle-icon();} -} - -/* Hover + Focus */ -:hover > .uk-navbar-toggle-icon, -:focus > .uk-navbar-toggle-icon { - @if(mixin-exists(hook-navbar-toggle-icon-hover)) {@include hook-navbar-toggle-icon-hover();} -} - - -/* Subtitle - ========================================================================== */ - -.uk-navbar-subtitle { - font-size: $navbar-subtitle-font-size; - @if(mixin-exists(hook-navbar-subtitle)) {@include hook-navbar-subtitle();} -} - - -/* Style modifiers - ========================================================================== */ - -.uk-navbar-primary { - @if(mixin-exists(hook-navbar-primary)) {@include hook-navbar-primary();} -} - -.uk-navbar-transparent { - @if(mixin-exists(hook-navbar-transparent)) {@include hook-navbar-transparent();} -} - -.uk-navbar-sticky { - @if(mixin-exists(hook-navbar-sticky)) {@include hook-navbar-sticky();} -} - - -/* Dropdown - ========================================================================== */ - -/* - * Adopts `uk-dropdown` - * 1. Hide by default - * 2. Set position - * 3. Set a default width - * 4. Style - */ - -.uk-navbar-dropdown { - /* 1 */ - display: none; - /* 2 */ - position: absolute; - z-index: $navbar-dropdown-z-index; - /* 3 */ - box-sizing: border-box; - width: $navbar-dropdown-width; - /* 4 */ - padding: $navbar-dropdown-padding; - background: $navbar-dropdown-background; - color: $navbar-dropdown-color; - @if(mixin-exists(hook-navbar-dropdown)) {@include hook-navbar-dropdown();} -} - -/* Show */ -.uk-navbar-dropdown.uk-open { display: block; } - -/* - * Direction / Alignment modifiers - */ - -/* Direction */ -[class*='uk-navbar-dropdown-top'] { margin-top: (-$navbar-dropdown-margin); } -[class*='uk-navbar-dropdown-bottom'] { margin-top: $navbar-dropdown-margin; } -[class*='uk-navbar-dropdown-left'] { margin-left: (-$navbar-dropdown-margin); } -[class*='uk-navbar-dropdown-right'] { margin-left: $navbar-dropdown-margin; } - -/* - * Grid - * Adopts `uk-grid` - */ - -/* Gutter Horizontal */ -.uk-navbar-dropdown-grid { margin-left: (-$navbar-dropdown-grid-gutter-horizontal); } -.uk-navbar-dropdown-grid > * { padding-left: $navbar-dropdown-grid-gutter-horizontal; } - -/* Gutter Vertical */ -.uk-navbar-dropdown-grid > .uk-grid-margin { margin-top: $navbar-dropdown-grid-gutter-vertical; } - -/* Stack */ -.uk-navbar-dropdown-stack .uk-navbar-dropdown-grid > * { width: 100% !important; } - -/* - * Width modifier - */ - -.uk-navbar-dropdown-width-2:not(.uk-navbar-dropdown-stack) { width: ($navbar-dropdown-width * 2); } -.uk-navbar-dropdown-width-3:not(.uk-navbar-dropdown-stack) { width: ($navbar-dropdown-width * 3); } -.uk-navbar-dropdown-width-4:not(.uk-navbar-dropdown-stack) { width: ($navbar-dropdown-width * 4); } -.uk-navbar-dropdown-width-5:not(.uk-navbar-dropdown-stack) { width: ($navbar-dropdown-width * 5); } - -/* - * Dropbar modifier - */ - -.uk-navbar-dropdown-dropbar { - margin-top: $navbar-dropdown-dropbar-margin-top; - margin-bottom: $navbar-dropdown-dropbar-margin-bottom; - @if(mixin-exists(hook-navbar-dropdown-dropbar)) {@include hook-navbar-dropdown-dropbar();} -} - - -/* Dropdown Nav - * Adopts `uk-nav` - ========================================================================== */ - -.uk-navbar-dropdown-nav { - @if(mixin-exists(hook-navbar-dropdown-nav)) {@include hook-navbar-dropdown-nav();} -} - -/* - * Items - */ - -.uk-navbar-dropdown-nav > li > a { - color: $navbar-dropdown-nav-item-color; - @if(mixin-exists(hook-navbar-dropdown-nav-item)) {@include hook-navbar-dropdown-nav-item();} -} - -/* Hover + Focus */ -.uk-navbar-dropdown-nav > li > a:hover, -.uk-navbar-dropdown-nav > li > a:focus { - color: $navbar-dropdown-nav-item-hover-color; - @if(mixin-exists(hook-navbar-dropdown-nav-item-hover)) {@include hook-navbar-dropdown-nav-item-hover();} -} - -/* Active */ -.uk-navbar-dropdown-nav > li.uk-active > a { - color: $navbar-dropdown-nav-item-active-color; - @if(mixin-exists(hook-navbar-dropdown-nav-item-active)) {@include hook-navbar-dropdown-nav-item-active();} -} - -/* - * Header - */ - -.uk-navbar-dropdown-nav .uk-nav-header { - color: $navbar-dropdown-nav-header-color; - @if(mixin-exists(hook-navbar-dropdown-nav-header)) {@include hook-navbar-dropdown-nav-header();} -} - -/* - * Divider - */ - -.uk-navbar-dropdown-nav .uk-nav-divider { - border-top: $navbar-dropdown-nav-divider-border-width solid $navbar-dropdown-nav-divider-border; - @if(mixin-exists(hook-navbar-dropdown-nav-divider)) {@include hook-navbar-dropdown-nav-divider();} -} - -/* - * Sublists - */ - -.uk-navbar-dropdown-nav .uk-nav-sub a { color: $navbar-dropdown-nav-sublist-item-color; } - -.uk-navbar-dropdown-nav .uk-nav-sub a:hover, -.uk-navbar-dropdown-nav .uk-nav-sub a:focus { color: $navbar-dropdown-nav-sublist-item-hover-color; } - -.uk-navbar-dropdown-nav .uk-nav-sub li.uk-active > a { color: $navbar-dropdown-nav-sublist-item-active-color; } - - -/* Dropbar - ========================================================================== */ - -.uk-navbar-dropbar { - background: $navbar-dropbar-background; - @if(mixin-exists(hook-navbar-dropbar)) {@include hook-navbar-dropbar();} -} - -/* - * Slide modifier - */ - -.uk-navbar-dropbar-slide { - position: absolute; - z-index: $navbar-dropbar-z-index; - left: 0; - right: 0; - @if(mixin-exists(hook-navbar-dropbar-slide)) {@include hook-navbar-dropbar-slide();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-navbar-misc)) {@include hook-navbar-misc();} - -// @mixin hook-navbar(){} -// @mixin hook-navbar-container(){} -// @mixin hook-navbar-nav-item(){} -// @mixin hook-navbar-nav-item-hover(){} -// @mixin hook-navbar-nav-item-onclick(){} -// @mixin hook-navbar-nav-item-active(){} -// @mixin hook-navbar-item(){} -// @mixin hook-navbar-toggle(){} -// @mixin hook-navbar-toggle-hover(){} -// @mixin hook-navbar-toggle-icon(){} -// @mixin hook-navbar-toggle-icon-hover(){} -// @mixin hook-navbar-subtitle(){} -// @mixin hook-navbar-primary(){} -// @mixin hook-navbar-transparent(){} -// @mixin hook-navbar-sticky(){} -// @mixin hook-navbar-dropdown(){} -// @mixin hook-navbar-dropdown-dropbar(){} -// @mixin hook-navbar-dropdown-nav(){} -// @mixin hook-navbar-dropdown-nav-item(){} -// @mixin hook-navbar-dropdown-nav-item-hover(){} -// @mixin hook-navbar-dropdown-nav-item-active(){} -// @mixin hook-navbar-dropdown-nav-header(){} -// @mixin hook-navbar-dropdown-nav-divider(){} -// @mixin hook-navbar-dropbar(){} -// @mixin hook-navbar-dropbar-slide(){} -// @mixin hook-navbar-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-navbar-nav-item-color: $inverse-global-muted-color !default; -$inverse-navbar-nav-item-hover-color: $inverse-global-color !default; -$inverse-navbar-nav-item-onclick-color: $inverse-global-emphasis-color !default; -$inverse-navbar-nav-item-active-color: $inverse-global-emphasis-color !default; -$inverse-navbar-item-color: $inverse-global-color !default; -$inverse-navbar-toggle-color: $inverse-global-muted-color !default; -$inverse-navbar-toggle-hover-color: $inverse-global-color !default; - - - -// @mixin hook-inverse-navbar-nav-item(){} -// @mixin hook-inverse-navbar-nav-item-hover(){} -// @mixin hook-inverse-navbar-nav-item-onclick(){} -// @mixin hook-inverse-navbar-nav-item-active(){} -// @mixin hook-inverse-navbar-item(){} -// @mixin hook-inverse-navbar-toggle(){} -// @mixin hook-inverse-navbar-toggle-hover(){} diff --git a/docs/_sass/uikit/components/notification.scss b/docs/_sass/uikit/components/notification.scss deleted file mode 100644 index 37aff72963..0000000000 --- a/docs/_sass/uikit/components/notification.scss +++ /dev/null @@ -1,191 +0,0 @@ -// Name: Notification -// Description: Component to create notification messages -// -// Component: `uk-notification` -// -// Sub-objects: `uk-notification-message` -// -// Adopted: `uk-notification-close` -// -// Modifiers: `uk-notification-top-center` -// `uk-notification-top-right` -// `uk-notification-bottom-left` -// `uk-notification-bottom-center` -// `uk-notification-bottom-right` -// `uk-notification-message-primary` -// `uk-notification-message-success` -// `uk-notification-message-warning` -// `uk-notification-message-danger` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$notification-position: 10px !default; -$notification-z-index: $global-z-index + 40 !default; -$notification-width: 350px !default; - -$notification-message-margin-top: 10px !default; -$notification-message-padding: $global-small-gutter !default; -$notification-message-background: $global-muted-background !default; -$notification-message-color: $global-color !default; -$notification-message-font-size: $global-medium-font-size !default; -$notification-message-line-height: 1.4 !default; - -$notification-close-top: $notification-message-padding + 5px !default; -$notification-close-right: $notification-message-padding !default; - -$notification-message-primary-color: $global-primary-background !default; -$notification-message-success-color: $global-success-background !default; -$notification-message-warning-color: $global-warning-background !default; -$notification-message-danger-color: $global-danger-background !default; - - -/* ======================================================================== - Component: Notification - ========================================================================== */ - -/* - * 1. Set position - * 2. Dimensions - */ - -.uk-notification { - /* 1 */ - position: fixed; - top: $notification-position; - left: $notification-position; - z-index: $notification-z-index; - /* 2 */ - box-sizing: border-box; - width: $notification-width; - @if(mixin-exists(hook-notification)) {@include hook-notification();} -} - - -/* Position modifiers -========================================================================== */ - -.uk-notification-top-right, -.uk-notification-bottom-right { - left: auto; - right: $notification-position; -} - -.uk-notification-top-center, -.uk-notification-bottom-center { - left: 50%; - margin-left: ($notification-width / -2); -} - -.uk-notification-bottom-left, -.uk-notification-bottom-right, -.uk-notification-bottom-center { - top: auto; - bottom: $notification-position; -} - - -/* Responsiveness -========================================================================== */ - -/* Phones portrait and smaller */ -@media (max-width: $breakpoint-xsmall-max) { - - .uk-notification { - left: $notification-position; - right: $notification-position; - width: auto; - margin: 0; - } - -} - - -/* Message -========================================================================== */ - -.uk-notification-message { - position: relative; - padding: $notification-message-padding; - background: $notification-message-background; - color: $notification-message-color; - font-size: $notification-message-font-size; - line-height: $notification-message-line-height; - cursor: pointer; - @if(mixin-exists(hook-notification-message)) {@include hook-notification-message();} -} - -* + .uk-notification-message { margin-top: $notification-message-margin-top; } - - -/* Close - * Adopts `uk-close` - ========================================================================== */ - -.uk-notification-close { - display: none; - position: absolute; - top: $notification-close-top; - right: $notification-close-right; - @if(mixin-exists(hook-notification-close)) {@include hook-notification-close();} -} - -.uk-notification-message:hover .uk-notification-close { display: block; } - - -/* Style modifiers - ========================================================================== */ - -/* - * Primary - */ - -.uk-notification-message-primary { - color: $notification-message-primary-color; - @if(mixin-exists(hook-notification-message-primary)) {@include hook-notification-message-primary();} -} - -/* - * Success - */ - -.uk-notification-message-success { - color: $notification-message-success-color; - @if(mixin-exists(hook-notification-message-success)) {@include hook-notification-message-success();} -} - -/* - * Warning - */ - -.uk-notification-message-warning { - color: $notification-message-warning-color; - @if(mixin-exists(hook-notification-message-warning)) {@include hook-notification-message-warning();} -} - -/* - * Danger - */ - -.uk-notification-message-danger { - color: $notification-message-danger-color; - @if(mixin-exists(hook-notification-message-danger)) {@include hook-notification-message-danger();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-notification-misc)) {@include hook-notification-misc();} - -// @mixin hook-notification(){} -// @mixin hook-notification-message(){} -// @mixin hook-notification-close(){} -// @mixin hook-notification-message-primary(){} -// @mixin hook-notification-message-success(){} -// @mixin hook-notification-message-warning(){} -// @mixin hook-notification-message-danger(){} -// @mixin hook-notification-misc(){} diff --git a/docs/_sass/uikit/components/offcanvas.scss b/docs/_sass/uikit/components/offcanvas.scss deleted file mode 100644 index af5e7a67d4..0000000000 --- a/docs/_sass/uikit/components/offcanvas.scss +++ /dev/null @@ -1,306 +0,0 @@ -// Name: Off-canvas -// Description: Component to create an off-canvas sidebar -// -// Component: `uk-offcanvas` -// -// Sub-objects: `uk-offcanvas-bar` -// `uk-offcanvas-container` -// `uk-offcanvas-page` -// -// Adopted: `uk-offcanvas-close` -// -// Modifiers: `uk-offcanvas-flip` -// `uk-offcanvas-bar-animation` -// `uk-offcanvas-reveal` -// `uk-offcanvas-overlay` -// `uk-offcanvas-container-animation` -// -// States: `uk-open` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$offcanvas-z-index: $global-z-index !default; - -$offcanvas-bar-width: 270px !default; -$offcanvas-bar-padding-vertical: $global-margin !default; -$offcanvas-bar-padding-horizontal: $global-margin !default; -$offcanvas-bar-background: $global-secondary-background !default; -$offcanvas-bar-color-mode: light !default; - -$offcanvas-bar-width-m: 350px !default; -$offcanvas-bar-padding-vertical-m: $global-medium-gutter !default; -$offcanvas-bar-padding-horizontal-m: $global-medium-gutter !default; - -$offcanvas-close-position: 20px !default; -$offcanvas-close-padding: 5px !default; - -$offcanvas-overlay-background: rgba(0,0,0,0.1) !default; - - -/* ======================================================================== - Component: Off-canvas - ========================================================================== */ - -/* - * 1. Hide by default - * 2. Set position - */ - -.uk-offcanvas { - /* 1 */ - display: none; - /* 2 */ - position: fixed; - top: 0; - bottom: 0; - left: 0; - z-index: $offcanvas-z-index; -} - -/* - * Flip modifier - */ - -.uk-offcanvas-flip .uk-offcanvas { - right: 0; - left: auto; -} - - -/* Bar - ========================================================================== */ - -/* - * 1. Set position - * 2. Size and style - * 3. Allow scrolling - */ - -.uk-offcanvas-bar { - /* 1 */ - position: absolute; - top: 0; - bottom: 0; - left: (-$offcanvas-bar-width); - /* 2 */ - box-sizing: border-box; - width: $offcanvas-bar-width; - padding: $offcanvas-bar-padding-vertical $offcanvas-bar-padding-horizontal; - background: $offcanvas-bar-background; - /* 3 */ - overflow-y: auto; - -webkit-overflow-scrolling: touch; - @if(mixin-exists(hook-offcanvas-bar)) {@include hook-offcanvas-bar();} -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-offcanvas-bar { - left: (-$offcanvas-bar-width-m); - width: $offcanvas-bar-width-m; - padding: $offcanvas-bar-padding-vertical-m $offcanvas-bar-padding-horizontal-m; - } - -} - -// Color Mode -@if ( $offcanvas-bar-color-mode == light ) { .uk-offcanvas-bar { @extend .uk-light !optional;} } -@if ( $offcanvas-bar-color-mode == dark ) { .uk-offcanvas-bar { @extend .uk-dark !optional;} } - -/* Flip modifier */ -.uk-offcanvas-flip .uk-offcanvas-bar { - left: auto; - right: (-$offcanvas-bar-width); -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-offcanvas-flip .uk-offcanvas-bar { right: (-$offcanvas-bar-width-m); } - -} - -/* - * Open - */ - -.uk-open > .uk-offcanvas-bar { left: 0; } -.uk-offcanvas-flip .uk-open > .uk-offcanvas-bar { - left: auto; - right: 0; -} - -/* - * Slide Animation (Used in slide and push mode) - */ - -.uk-offcanvas-bar-animation { transition: left 0.3s ease-out; } -.uk-offcanvas-flip .uk-offcanvas-bar-animation { transition-property: right; } - -/* - * Reveal Animation - * 1. Set position - * 2. Clip the bar - * 3. Animation - * 4. Reset position - */ - -.uk-offcanvas-reveal { - /* 1 */ - position: absolute; - top: 0; - bottom: 0; - left: 0; - /* 2 */ - width: 0; - overflow: hidden; - /* 3 */ - transition: width 0.3s ease-out; -} - -.uk-offcanvas-reveal .uk-offcanvas-bar { - /* 4 */ - left: 0; -} - -.uk-offcanvas-flip .uk-offcanvas-reveal .uk-offcanvas-bar { - /* 4 */ - left: auto; - right: 0; -} - -.uk-open > .uk-offcanvas-reveal { width: $offcanvas-bar-width; } - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-open > .uk-offcanvas-reveal { width: $offcanvas-bar-width-m; } - -} - -/* - * Flip modifier - */ - -.uk-offcanvas-flip .uk-offcanvas-reveal { - right: 0; - left: auto; -} - - -/* Close - * Adopts `uk-close` - ========================================================================== */ - -.uk-offcanvas-close { - position: absolute; - z-index: $offcanvas-z-index; - top: $offcanvas-close-position; - right: $offcanvas-close-position; - padding: $offcanvas-close-padding; - @if(mixin-exists(hook-offcanvas-close)) {@include hook-offcanvas-close();} -} - - -/* Overlay - ========================================================================== */ - -/* - * Overlay the whole page. Needed for the `::before` - * 1. Using `100vw` so no modification is needed when off-canvas is flipped - * 2. Allow for closing with swipe gesture on devices with pointer events. - */ - -.uk-offcanvas-overlay { - /* 1 */ - width: 100vw; - /* 2 */ - touch-action: none; -} - -/* - * 1. Mask the whole page - * 2. Fade-in transition - */ - -.uk-offcanvas-overlay::before { - /* 1 */ - content: ""; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - background: $offcanvas-overlay-background; - /* 2 */ - opacity: 0; - transition: opacity 0.15s linear; - @if(mixin-exists(hook-offcanvas-overlay)) {@include hook-offcanvas-overlay();} -} - -.uk-offcanvas-overlay.uk-open::before { opacity: 1; } - - -/* Prevent scrolling - ========================================================================== */ - -/* - * Prevent horizontal scrollbar when the content is slide-out - * Has to be on the `html` element too to make it work on the `body` - */ - -.uk-offcanvas-page, -.uk-offcanvas-container { overflow-x: hidden; } - - -/* Container - ========================================================================== */ - -/* - * Prepare slide-out animation (Used in reveal and push mode) - * Using `position: left` instead of `transform` because position `fixed` elements like sticky navbars - * lose their fixed state and behaves like `absolute` within a transformed container - * 1. Provide a fixed width and prevent shrinking - */ - -.uk-offcanvas-container { - position: relative; - left: 0; - transition: left 0.3s ease-out; - /* 1 */ - box-sizing: border-box; - width: 100%; -} - -/* - * Activate slide-out animation - */ - -:not(.uk-offcanvas-flip).uk-offcanvas-container-animation { left: $offcanvas-bar-width; } - -.uk-offcanvas-flip.uk-offcanvas-container-animation { left: (-$offcanvas-bar-width); } - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - :not(.uk-offcanvas-flip).uk-offcanvas-container-animation { left: $offcanvas-bar-width-m; } - - .uk-offcanvas-flip.uk-offcanvas-container-animation { left: (-$offcanvas-bar-width-m); } - -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-offcanvas-misc)) {@include hook-offcanvas-misc();} - -// @mixin hook-offcanvas-bar(){} -// @mixin hook-offcanvas-close(){} -// @mixin hook-offcanvas-overlay(){} -// @mixin hook-offcanvas-misc(){} diff --git a/docs/_sass/uikit/components/overlay.scss b/docs/_sass/uikit/components/overlay.scss deleted file mode 100644 index c3eb0a5711..0000000000 --- a/docs/_sass/uikit/components/overlay.scss +++ /dev/null @@ -1,85 +0,0 @@ -// Name: Overlay -// Description: Component to create content areas overlaying an image -// -// Component: `uk-overlay` -// -// Adopted: `uk-overlay-icon` -// -// Modifier: `uk-overlay-default` -// `uk-overlay-primary` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$overlay-padding-horizontal: $global-gutter !default; -$overlay-padding-vertical: $global-gutter !default; - -$overlay-default-background: rgba($global-background, 0.8) !default; - -$overlay-primary-background: rgba($global-secondary-background, 0.8) !default; -$overlay-primary-color-mode: light !default; - - -/* ======================================================================== - Component: Overlay - ========================================================================== */ - -.uk-overlay { - padding: $overlay-padding-vertical $overlay-padding-horizontal; - @if(mixin-exists(hook-overlay)) {@include hook-overlay();} -} - -/* - * Remove margin from the last-child - */ - -.uk-overlay > :last-child { margin-bottom: 0; } - - -/* Icon - ========================================================================== */ - -.uk-overlay-icon { - @if(mixin-exists(hook-overlay-icon)) {@include hook-overlay-icon();} -} - - -/* Style modifiers - ========================================================================== */ - -/* - * Default - */ - -.uk-overlay-default { - background: $overlay-default-background; - @if(mixin-exists(hook-overlay-default)) {@include hook-overlay-default();} -} - -/* - * Primary - */ - -.uk-overlay-primary { - background: $overlay-primary-background; - @if(mixin-exists(hook-overlay-primary)) {@include hook-overlay-primary();} -} - -// Color Mode -@if ( $overlay-primary-color-mode == light ) { .uk-overlay-primary { @extend .uk-light !optional;} } -@if ( $overlay-primary-color-mode == dark ) { .uk-overlay-primary { @extend .uk-dark !optional;} } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-overlay-misc)) {@include hook-overlay-misc();} - -// @mixin hook-overlay(){} -// @mixin hook-overlay-icon(){} -// @mixin hook-overlay-default(){} -// @mixin hook-overlay-primary(){} -// @mixin hook-overlay-misc(){} diff --git a/docs/_sass/uikit/components/padding.scss b/docs/_sass/uikit/components/padding.scss deleted file mode 100644 index 0c0f1ed10b..0000000000 --- a/docs/_sass/uikit/components/padding.scss +++ /dev/null @@ -1,81 +0,0 @@ -// Name: Padding -// Description: Utilities for padding -// -// Component: `uk-padding` -// `uk-padding-large` -// `uk-padding-remove-*` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$padding-padding: $global-gutter !default; -$padding-padding-l: $global-medium-gutter !default; - -$padding-small-padding: $global-small-gutter !default; - -$padding-large-padding: $global-gutter !default; -$padding-large-padding-l: $global-large-gutter !default; - - -/* ======================================================================== - Component: Padding - ========================================================================== */ - -.uk-padding { padding: $padding-padding; } - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-padding { padding: $padding-padding-l; } - -} - - -/* Small - ========================================================================== */ - -.uk-padding-small { padding: $padding-small-padding; } - - -/* Large - ========================================================================== */ - -.uk-padding-large { padding: $padding-large-padding; } - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-padding-large { padding: $padding-large-padding-l; } - -} - - -/* Remove - ========================================================================== */ - -.uk-padding-remove { padding: 0 !important; } -.uk-padding-remove-top { padding-top: 0 !important; } -.uk-padding-remove-bottom { padding-bottom: 0 !important; } -.uk-padding-remove-left { padding-left: 0 !important; } -.uk-padding-remove-right { padding-right: 0 !important; } - -.uk-padding-remove-vertical { - padding-top: 0 !important; - padding-bottom: 0 !important; -} - -.uk-padding-remove-horizontal { - padding-left: 0 !important; - padding-right: 0 !important; -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-padding-misc)) {@include hook-padding-misc();} - -// @mixin hook-padding-misc(){} diff --git a/docs/_sass/uikit/components/pagination.scss b/docs/_sass/uikit/components/pagination.scss deleted file mode 100644 index 6c501e7bdf..0000000000 --- a/docs/_sass/uikit/components/pagination.scss +++ /dev/null @@ -1,131 +0,0 @@ -// Name: Pagination -// Description: Component to create a page navigation -// -// Component: `uk-pagination` -// -// Adopted: `uk-pagination-next` -// `uk-pagination-previous` -// -// States: `uk-active` -// `uk-disabled` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$pagination-margin-horizontal: 0 !default; - -$pagination-item-padding-vertical: 5px !default; -$pagination-item-padding-horizontal: 10px !default; -$pagination-item-color: $global-muted-color !default; -$pagination-item-hover-color: $global-color !default; -$pagination-item-hover-text-decoration: none !default; -$pagination-item-active-color: $global-color !default; -$pagination-item-disabled-color: $global-muted-color !default; - - -/* ======================================================================== - Component: Pagination - ========================================================================== */ - -/* - * 1. Allow items to wrap into the next line - * 2. Gutter - * 3. Reset list - */ - -.uk-pagination { - display: flex; - /* 1 */ - flex-wrap: wrap; - /* 2 */ - margin-left: (-$pagination-margin-horizontal); - /* 3 */ - padding: 0; - list-style: none; - @if(mixin-exists(hook-pagination)) {@include hook-pagination();} -} - -/* - * 1. Space is allocated solely based on content dimensions: 0 0 auto - * 2. Gutter - * 3. Create position context for dropdowns - */ - -.uk-pagination > * { - /* 1 */ - flex: none; - /* 2 */ - padding-left: $pagination-margin-horizontal; - /* 3 */ - position: relative; -} - - -/* Items - ========================================================================== */ - -/* - * 1. Prevent gap if child element is `inline-block`, e.g. an icon - * 2. Style - */ - -.uk-pagination > * > * { - /* 1 */ - display: block; - /* 2 */ - padding: $pagination-item-padding-vertical $pagination-item-padding-horizontal; - color: $pagination-item-color; - @if(mixin-exists(hook-pagination-item)) {@include hook-pagination-item();} -} - -/* Hover + Focus */ -.uk-pagination > * > :hover, -.uk-pagination > * > :focus { - color: $pagination-item-hover-color; - text-decoration: $pagination-item-hover-text-decoration; - @if(mixin-exists(hook-pagination-item-hover)) {@include hook-pagination-item-hover();} -} - -/* Active */ -.uk-pagination > .uk-active > * { - color: $pagination-item-active-color; - @if(mixin-exists(hook-pagination-item-active)) {@include hook-pagination-item-active();} -} - -/* Disabled */ -.uk-pagination > .uk-disabled > * { - color: $pagination-item-disabled-color; - @if(mixin-exists(hook-pagination-item-disabled)) {@include hook-pagination-item-disabled();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-pagination-misc)) {@include hook-pagination-misc();} - -// @mixin hook-pagination(){} -// @mixin hook-pagination-item(){} -// @mixin hook-pagination-item-hover(){} -// @mixin hook-pagination-item-active(){} -// @mixin hook-pagination-item-disabled(){} -// @mixin hook-pagination-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-pagination-item-color: $inverse-global-muted-color !default; -$inverse-pagination-item-hover-color: $inverse-global-color !default; -$inverse-pagination-item-active-color: $inverse-global-color !default; -$inverse-pagination-item-disabled-color: $inverse-global-muted-color !default; - - - -// @mixin hook-inverse-pagination-item(){} -// @mixin hook-inverse-pagination-item-hover(){} -// @mixin hook-inverse-pagination-item-active(){} -// @mixin hook-inverse-pagination-item-disabled(){} diff --git a/docs/_sass/uikit/components/placeholder.scss b/docs/_sass/uikit/components/placeholder.scss deleted file mode 100644 index 05c06f7d92..0000000000 --- a/docs/_sass/uikit/components/placeholder.scss +++ /dev/null @@ -1,45 +0,0 @@ -// Name: Placeholder -// Description: Component to create placeholder boxes -// -// Component: `uk-placeholder` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$placeholder-margin-vertical: $global-margin !default; -$placeholder-padding-vertical: $global-gutter !default; -$placeholder-padding-horizontal: $global-gutter !default; -$placeholder-background: $global-muted-background !default; - - -/* ======================================================================== - Component: Placeholder - ========================================================================== */ - -.uk-placeholder { - margin-bottom: $placeholder-margin-vertical; - padding: $placeholder-padding-vertical $placeholder-padding-horizontal; - background: $placeholder-background; - @if(mixin-exists(hook-placeholder)) {@include hook-placeholder();} -} - -/* Add margin if adjacent element */ -* + .uk-placeholder { margin-top: $placeholder-margin-vertical; } - -/* - * Remove margin from the last-child - */ - -.uk-placeholder > :last-child { margin-bottom: 0; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-placeholder-misc)) {@include hook-placeholder-misc();} - -// @mixin hook-placeholder(){} -// @mixin hook-placeholder-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/position.scss b/docs/_sass/uikit/components/position.scss deleted file mode 100644 index 419e9270f4..0000000000 --- a/docs/_sass/uikit/components/position.scss +++ /dev/null @@ -1,265 +0,0 @@ -// Name: Position -// Description: Utilities to position content -// -// Component: `uk-position-absolute` -// `uk-position-relative` -// `uk-position-z-index` -// `uk-position-top` -// `uk-position-bottom` -// `uk-position-left` -// `uk-position-right` -// `uk-position-top-left` -// `uk-position-top-center` -// `uk-position-top-right` -// `uk-position-bottom-left` -// `uk-position-bottom-center` -// `uk-position-bottom-right` -// `uk-position-center` -// `uk-position-center-left` -// `uk-position-center-right` -// `uk-position-cover` -// -// Modifiers: `uk-position-small` -// `uk-position-medium` -// `uk-position-large` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$position-small-margin: $global-small-gutter !default; -$position-medium-margin: $global-gutter !default; -$position-large-margin: $global-gutter !default; -$position-large-margin-l: 50px !default; - - -/* ======================================================================== - Component: Position - ========================================================================== */ - - -/* Directions - ========================================================================== */ - -/* - * 1. Prevent content overflow if `max-width: 100%` is used inside position container. - */ - -[class*='uk-position-top'], -[class*='uk-position-bottom'], -[class*='uk-position-left'], -[class*='uk-position-right'], -[class*='uk-position-center'] { - position: absolute !important; - /* 1 */ - max-width: 100%; -} - - -/* Edges - ========================================================================== */ - -/* Don't use `width: 100%` because it is wrong if the parent has padding. */ -.uk-position-top { - top: 0; - left: 0; - right: 0; -} - -.uk-position-bottom { - bottom: 0; - left: 0; - right: 0; -} - -.uk-position-left { - top: 0; - bottom: 0; - left: 0; -} - -.uk-position-right { - top: 0; - bottom: 0; - right: 0; -} - - -/* Corners - ========================================================================== */ - -.uk-position-top-left { - top: 0; - left: 0; -} - -.uk-position-top-right { - top: 0; - right: 0; -} - -.uk-position-bottom-left { - bottom: 0; - left: 0; -} - -.uk-position-bottom-right { - bottom: 0; - right: 0; -} - -/* - * Center - * 1. Fix text wrapping if content is larger than 50% of the container. - */ - -.uk-position-center { - top: 50%; - left: 50%; - transform: translate(-50%,-50%); - /* 1 */ - width: max-content; - max-width: 100%; - box-sizing: border-box; -} - -/* Vertical */ -[class*='uk-position-center-left'], -[class*='uk-position-center-right'] { - top: 50%; - transform: translateY(-50%); -} - -.uk-position-center-left { left: 0; } -.uk-position-center-right { right: 0; } - -.uk-position-center-left-out { - right: 100%; - width: max-content; -} - -.uk-position-center-right-out { - left: 100%; - width: max-content; -} - -/* Horizontal */ -.uk-position-top-center, -.uk-position-bottom-center { - left: 50%; - transform: translateX(-50%); - /* 1 */ - width: max-content; - max-width: 100%; - box-sizing: border-box; -} - -.uk-position-top-center { top: 0; } -.uk-position-bottom-center { bottom: 0; } - - -/* Cover - ========================================================================== */ - -.uk-position-cover { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; -} - - -/* Utility - ========================================================================== */ - -.uk-position-relative { position: relative !important; } - -.uk-position-absolute { position: absolute !important; } - -.uk-position-fixed { position: fixed !important; } - -.uk-position-z-index { z-index: 1; } - - -/* Margin modifier - ========================================================================== */ - -/* - * Small - */ - -.uk-position-small { - max-width: unquote('calc(100% - (#{$position-small-margin} * 2))'); - margin: $position-small-margin; -} - -.uk-position-small.uk-position-center { transform: translate(-50%, -50%) translate(-$position-small-margin, (-$position-small-margin)); } - -.uk-position-small[class*='uk-position-center-left'], -.uk-position-small[class*='uk-position-center-right'] { transform: translateY(-50%) translateY(-$position-small-margin); } - -.uk-position-small.uk-position-top-center, -.uk-position-small.uk-position-bottom-center { transform: translateX(-50%) translateX(-$position-small-margin); } - -/* - * Medium - */ - -.uk-position-medium { - max-width: unquote('calc(100% - (#{$position-medium-margin} * 2))'); - margin: $position-medium-margin; -} - -.uk-position-medium.uk-position-center { transform: translate(-50%, -50%) translate(-$position-medium-margin, (-$position-medium-margin)); } - -.uk-position-medium[class*='uk-position-center-left'], -.uk-position-medium[class*='uk-position-center-right'] { transform: translateY(-50%) translateY(-$position-medium-margin); } - -.uk-position-medium.uk-position-top-center, -.uk-position-medium.uk-position-bottom-center { transform: translateX(-50%) translateX(-$position-medium-margin); } - -/* - * Large - */ - -.uk-position-large { - max-width: unquote('calc(100% - (#{$position-large-margin} * 2))'); - margin: $position-large-margin; -} - -.uk-position-large.uk-position-center { transform: translate(-50%, -50%) translate(-$position-large-margin, (-$position-large-margin)); } - -.uk-position-large[class*='uk-position-center-left'], -.uk-position-large[class*='uk-position-center-right'] { transform: translateY(-50%) translateY(-$position-large-margin); } - -.uk-position-large.uk-position-top-center, -.uk-position-large.uk-position-bottom-center { transform: translateX(-50%) translateX(-$position-large-margin); } - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-position-large { - max-width: unquote('calc(100% - (#{$position-large-margin-l} * 2))'); - margin: $position-large-margin-l; - } - - .uk-position-large.uk-position-center { transform: translate(-50%, -50%) translate(-$position-large-margin-l, (-$position-large-margin-l)); } - - .uk-position-large[class*='uk-position-center-left'], - .uk-position-large[class*='uk-position-center-right'] { transform: translateY(-50%) translateY(-$position-large-margin-l); } - - .uk-position-large.uk-position-top-center, - .uk-position-large.uk-position-bottom-center { transform: translateX(-50%) translateX(-$position-large-margin-l); } - -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-position-misc)) {@include hook-position-misc();} - -// @mixin hook-position-misc(){} diff --git a/docs/_sass/uikit/components/print.scss b/docs/_sass/uikit/components/print.scss deleted file mode 100644 index 6162df525f..0000000000 --- a/docs/_sass/uikit/components/print.scss +++ /dev/null @@ -1,61 +0,0 @@ -// Name: Print -// Description: Optimize page for printing -// -// Adapted from http://github.com/h5bp/html5-boilerplate -// -// Modifications: Removed link `href` and `title` related rules -// -// ======================================================================== - - -/* ======================================================================== - Component: Print - ========================================================================== */ - -@media print { - - *, - *::before, - *::after { - background: transparent !important; - color: black !important; - box-shadow: none !important; - text-shadow: none !important; - } - - a, - a:visited { text-decoration: underline; } - - pre, - blockquote { - border: 1px solid #999; - page-break-inside: avoid; - } - - thead { display: table-header-group; } - - tr, - img { page-break-inside: avoid; } - - img { max-width: 100% !important; } - - @page { margin: 0.5cm; } - - p, - h2, - h3 { - orphans: 3; - widows: 3; - } - - h2, - h3 { page-break-after: avoid; } - - @if(mixin-exists(hook-print)) {@include hook-print();} - -} - -// Hooks -// ======================================================================== - -// @mixin hook-print(){} diff --git a/docs/_sass/uikit/components/progress.scss b/docs/_sass/uikit/components/progress.scss deleted file mode 100644 index 4575513ed6..0000000000 --- a/docs/_sass/uikit/components/progress.scss +++ /dev/null @@ -1,105 +0,0 @@ -// Name: Progress -// Description: Component to create progress bars -// -// Component: `uk-progress` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$progress-height: 15px !default; -$progress-margin-vertical: $global-margin !default; -$progress-background: $global-muted-background !default; - -$progress-bar-background: $global-primary-background !default; - - -/* ======================================================================== - Component: Progress - ========================================================================== */ - -/* - * 1. Add the correct vertical alignment in Chrome, Firefox, and Opera. - * 2. Remove default style - * 3. Behave like a block element - * 4. Remove borders in Firefox and Edge - * 5. Set background color for progress container in Firefox, IE11 and Edge - * 6. Style - */ - -.uk-progress { - /* 1 */ - vertical-align: baseline; - /* 2 */ - -webkit-appearance: none; - -moz-appearance: none; - /* 3 */ - display: block; - width: 100%; - /* 4 */ - border: 0; - /* 5 */ - background-color: $progress-background; - /* 6 */ - margin-bottom: $progress-margin-vertical; - height: $progress-height; - @if(mixin-exists(hook-progress)) {@include hook-progress();} -} - -/* Add margin if adjacent element */ -* + .uk-progress { margin-top: $progress-margin-vertical; } - -/* - * Remove animated circles for indeterminate state in IE11 and Edge - */ - -.uk-progress:indeterminate { color: transparent; } - -/* - * Progress container - * 2. Remove progress bar for indeterminate state in Firefox - */ - -.uk-progress::-webkit-progress-bar { - background-color: $progress-background; - @if(mixin-exists(hook-progress)) {@include hook-progress();} -} - -/* 2 */ -.uk-progress:indeterminate::-moz-progress-bar { width: 0; } - -/* - * Progress bar - * 1. Remove right border in IE11 and Edge - */ - -.uk-progress::-webkit-progress-value { - background-color: $progress-bar-background; - transition: width 0.6s ease; - @if(mixin-exists(hook-progress-bar)) {@include hook-progress-bar();} -} - -.uk-progress::-moz-progress-bar { - background-color: $progress-bar-background; - @if(mixin-exists(hook-progress-bar)) {@include hook-progress-bar();} -} - -.uk-progress::-ms-fill { - background-color: $progress-bar-background; - transition: width 0.6s ease; - /* 1 */ - border: 0; - @if(mixin-exists(hook-progress-bar)) {@include hook-progress-bar();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-progress-misc)) {@include hook-progress-misc();} - -// @mixin hook-progress(){} -// @mixin hook-progress-bar(){} -// @mixin hook-progress-misc(){} diff --git a/docs/_sass/uikit/components/search.scss b/docs/_sass/uikit/components/search.scss deleted file mode 100644 index 9f5e0e090c..0000000000 --- a/docs/_sass/uikit/components/search.scss +++ /dev/null @@ -1,328 +0,0 @@ -// Name: Search -// Description: Component to create the search -// -// Component: `uk-search` -// -// Sub-objects: `uk-search-input` -// `uk-search-toggle` -// -// Adopted: `uk-search-icon` -// -// Modifier: `uk-search-default` -// `uk-search-navbar` -// `uk-search-large` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$search-color: $global-color !default; -$search-placeholder-color: $global-muted-color !default; - -$search-icon-color: $global-muted-color !default; - -$search-default-width: 240px !default; -$search-default-height: $global-control-height !default; -$search-default-padding-horizontal: 10px !default; -$search-default-background: $global-muted-background !default; -$search-default-focus-background: darken($search-default-background, 5%) !default; - -$search-default-icon-width: $global-control-height !default; - -$search-navbar-width: 400px !default; -$search-navbar-height: 40px !default; -$search-navbar-background: transparent !default; -$search-navbar-font-size: $global-large-font-size !default; - -$search-navbar-icon-width: 40px !default; - -$search-large-width: 500px !default; -$search-large-height: 80px !default; -$search-large-background: transparent !default; -$search-large-font-size: $global-2xlarge-font-size !default; - -$search-large-icon-width: 80px !default; - -$search-toggle-color: $global-muted-color !default; -$search-toggle-hover-color: $global-color !default; - - -/* ======================================================================== - Component: Search - ========================================================================== */ - -/* - * 1. Container fits its content - * 2. Create position context - * 3. Prevent content overflow - * 4. Reset `form` - */ - -.uk-search { - /* 1 */ - display: inline-block; - /* 2 */ - position: relative; - /* 3 */ - max-width: 100%; - /* 4 */ - margin: 0; -} - - -/* Input - ========================================================================== */ - -/* - * Remove the inner padding and cancel buttons in Chrome on OS X and Safari on OS X. - */ - -.uk-search-input::-webkit-search-cancel-button, -.uk-search-input::-webkit-search-decoration { -webkit-appearance: none; } - -/* - * Removes placeholder transparency in Firefox. - */ - -.uk-search-input::-moz-placeholder { opacity: 1; } - -/* - * 1. Define consistent box sizing. - * 2. Address margins set differently in Firefox/IE and Chrome/Safari/Opera. - * 3. Remove `border-radius` in iOS. - * 4. Change font properties to `inherit` in all browsers - * 5. Show the overflow in Edge. - * 6. Remove default style in iOS. - * 7. Vertical alignment - * 8. Take the full container width - * 9. Style - */ - -.uk-search-input { - /* 1 */ - box-sizing: border-box; - /* 2 */ - margin: 0; - /* 3 */ - border-radius: 0; - /* 4 */ - font: inherit; - /* 5 */ - overflow: visible; - /* 6 */ - -webkit-appearance: none; - /* 7 */ - vertical-align: middle; - /* 8 */ - width: 100%; - /* 9 */ - border: none; - color: $search-color; - @if(mixin-exists(hook-search-input)) {@include hook-search-input();} -} - -.uk-search-input:focus { outline: none; } - -/* Placeholder */ -.uk-search-input:-ms-input-placeholder { color: $search-placeholder-color !important; } -.uk-search-input::placeholder { color: $search-placeholder-color; } - - -/* Icon (Adopts `uk-icon`) - ========================================================================== */ - -/* - * Remove default focus style - */ - -.uk-search-icon:focus { outline: none; } - -/* - * Position above input - * 1. Set position - * 2. Center icon vertically and horizontally - * 3. Style - */ - -.uk-search .uk-search-icon { - /* 1 */ - position: absolute; - top: 0; - bottom: 0; - left: 0; - /* 2 */ - display: inline-flex; - justify-content: center; - align-items: center; - /* 3 */ - color: $search-icon-color; -} - -/* - * Required for `a`. - */ - -.uk-search .uk-search-icon:hover { color: $search-icon-color; } - -/* - * Make `input` element clickable through icon, e.g. if it's a `span` - */ - -.uk-search .uk-search-icon:not(a):not(button):not(input) { pointer-events: none; } - -/* - * Position modifier - */ - -.uk-search .uk-search-icon-flip { - right: 0; - left: auto; -} - - -/* Default modifier - ========================================================================== */ - -.uk-search-default { width: $search-default-width; } - -/* - * Input - */ - -.uk-search-default .uk-search-input { - height: $search-default-height; - padding-left: $search-default-padding-horizontal; - padding-right: $search-default-padding-horizontal; - background: $search-default-background; - @if(mixin-exists(hook-search-default-input)) {@include hook-search-default-input();} -} - -/* Focus */ -.uk-search-default .uk-search-input:focus { - background-color: $search-default-focus-background; - @if(mixin-exists(hook-search-default-input-focus)) {@include hook-search-default-input-focus();} -} - -/* - * Icon - */ - -.uk-search-default .uk-search-icon { width: $search-default-icon-width; } - -.uk-search-default .uk-search-icon:not(.uk-search-icon-flip) ~ .uk-search-input { padding-left: ($search-default-icon-width); } -.uk-search-default .uk-search-icon-flip ~ .uk-search-input { padding-right: ($search-default-icon-width); } - - -/* Navbar modifier - ========================================================================== */ - -.uk-search-navbar { width: $search-navbar-width; } - -/* - * Input - */ - -.uk-search-navbar .uk-search-input { - height: $search-navbar-height; - background: $search-navbar-background; - font-size: $search-navbar-font-size; - @if(mixin-exists(hook-search-navbar-input)) {@include hook-search-navbar-input();} -} - -/* - * Icon - */ - -.uk-search-navbar .uk-search-icon { width: $search-navbar-icon-width; } - -.uk-search-navbar .uk-search-icon:not(.uk-search-icon-flip) ~ .uk-search-input { padding-left: ($search-navbar-icon-width); } -.uk-search-navbar .uk-search-icon-flip ~ .uk-search-input { padding-right: ($search-navbar-icon-width); } - - -/* Large modifier - ========================================================================== */ - -.uk-search-large { width: $search-large-width; } - -/* - * Input - */ - -.uk-search-large .uk-search-input { - height: $search-large-height; - background: $search-large-background; - font-size: $search-large-font-size; - @if(mixin-exists(hook-search-large-input)) {@include hook-search-large-input();} -} - -/* - * Icon - */ - -.uk-search-large .uk-search-icon { width: $search-large-icon-width; } - -.uk-search-large .uk-search-icon:not(.uk-search-icon-flip) ~ .uk-search-input { padding-left: ($search-large-icon-width); } -.uk-search-large .uk-search-icon-flip ~ .uk-search-input { padding-right: ($search-large-icon-width); } - - -/* Toggle - ========================================================================== */ - -.uk-search-toggle { - color: $search-toggle-color; - @if(mixin-exists(hook-search-toggle)) {@include hook-search-toggle();} -} - -/* Hover + Focus */ -.uk-search-toggle:hover, -.uk-search-toggle:focus { - color: $search-toggle-hover-color; - @if(mixin-exists(hook-search-toggle-hover)) {@include hook-search-toggle-hover();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-search-misc)) {@include hook-search-misc();} - -// @mixin hook-search-input(){} -// @mixin hook-search-default-input(){} -// @mixin hook-search-default-input-focus(){} -// @mixin hook-search-navbar-input(){} -// @mixin hook-search-large-input(){} - -// @mixin hook-search-toggle(){} -// @mixin hook-search-toggle-hover(){} - -// @mixin hook-search-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-search-color: $inverse-global-color !default; -$inverse-search-placeholder-color: $inverse-global-muted-color !default; - -$inverse-search-icon-color: $inverse-global-muted-color !default; - -$inverse-search-default-background: $inverse-global-muted-background !default; -$inverse-search-default-focus-background: fadein($inverse-search-default-background, 5%) !default; - -$inverse-search-navbar-background: transparent !default; - -$inverse-search-large-background: transparent !default; - -$inverse-search-toggle-color: $inverse-global-muted-color !default; -$inverse-search-toggle-hover-color: $inverse-global-color !default; - - - -// @mixin hook-inverse-search-default-input(){} -// @mixin hook-inverse-search-default-input-focus(){} -// @mixin hook-inverse-search-navbar-input(){} -// @mixin hook-inverse-search-large-input(){} -// @mixin hook-inverse-search-toggle(){} -// @mixin hook-inverse-search-toggle-hover(){} diff --git a/docs/_sass/uikit/components/section.scss b/docs/_sass/uikit/components/section.scss deleted file mode 100644 index a3eacb1d06..0000000000 --- a/docs/_sass/uikit/components/section.scss +++ /dev/null @@ -1,212 +0,0 @@ -// Name: Section -// Description: Component to create horizontal layout section -// -// Component: `uk-section` -// -// Modifiers: `uk-section-xsmall` -// `uk-section-small` -// `uk-section-large` -// `uk-section-xlarge` -// `uk-section-default` -// `uk-section-muted` -// `uk-section-primary` -// `uk-section-secondary` -// `uk-section-overlap` -// -// States: `uk-preserve-color` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$section-padding-vertical: $global-medium-margin !default; -$section-padding-vertical-m: $global-large-margin !default; - -$section-xsmall-padding-vertical: $global-margin !default; - -$section-small-padding-vertical: $global-medium-margin !default; - -$section-large-padding-vertical: $global-large-margin !default; -$section-large-padding-vertical-m: $global-xlarge-margin !default; - -$section-xlarge-padding-vertical: $global-xlarge-margin !default; -$section-xlarge-padding-vertical-m: ($global-large-margin + $global-xlarge-margin) !default; - -$section-default-background: $global-background !default; - -$section-muted-background: $global-muted-background !default; - -$section-primary-background: $global-primary-background !default; -$section-primary-color-mode: light !default; - -$section-secondary-background: $global-secondary-background !default; -$section-secondary-color-mode: light !default; - - -/* ======================================================================== - Component: Section - ========================================================================== */ - -/* - * 1. Make it work with `100vh` and height in general - */ - -.uk-section { - display: flow-root; - box-sizing: border-box; /* 1 */ - padding-top: $section-padding-vertical; - padding-bottom: $section-padding-vertical; - @if(mixin-exists(hook-section)) {@include hook-section();} -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-section { - padding-top: $section-padding-vertical-m; - padding-bottom: $section-padding-vertical-m; - } - -} - -/* - * Remove margin from the last-child - */ - -.uk-section > :last-child { margin-bottom: 0; } - - -/* Size modifiers - ========================================================================== */ - -/* - * XSmall - */ - -.uk-section-xsmall { - padding-top: $section-xsmall-padding-vertical; - padding-bottom: $section-xsmall-padding-vertical; -} - -/* - * Small - */ - -.uk-section-small { - padding-top: $section-small-padding-vertical; - padding-bottom: $section-small-padding-vertical; -} - -/* - * Large - */ - -.uk-section-large { - padding-top: $section-large-padding-vertical; - padding-bottom: $section-large-padding-vertical; -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-section-large { - padding-top: $section-large-padding-vertical-m; - padding-bottom: $section-large-padding-vertical-m; - } - -} - - -/* - * XLarge - */ - -.uk-section-xlarge { - padding-top: $section-xlarge-padding-vertical; - padding-bottom: $section-xlarge-padding-vertical; -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-section-xlarge { - padding-top: $section-xlarge-padding-vertical-m; - padding-bottom: $section-xlarge-padding-vertical-m; - } - -} - - -/* Style modifiers - ========================================================================== */ - -/* - * Default - */ - -.uk-section-default { - background: $section-default-background; - @if(mixin-exists(hook-section-default)) {@include hook-section-default();} -} - -/* - * Muted - */ - -.uk-section-muted { - background: $section-muted-background; - @if(mixin-exists(hook-section-muted)) {@include hook-section-muted();} -} - -/* - * Primary - */ - -.uk-section-primary { - background: $section-primary-background; - @if(mixin-exists(hook-section-primary)) {@include hook-section-primary();} -} - -@if ( $section-primary-color-mode == light ) { .uk-section-primary:not(.uk-preserve-color) { @extend .uk-light !optional;} } -@if ( $section-primary-color-mode == dark ) { .uk-section-primary:not(.uk-preserve-color) { @extend .uk-dark !optional;} } - -/* - * Secondary - */ - -.uk-section-secondary { - background: $section-secondary-background; - @if(mixin-exists(hook-section-secondary)) {@include hook-section-secondary();} -} - -@if ( $section-secondary-color-mode == light ) { .uk-section-secondary:not(.uk-preserve-color) { @extend .uk-light !optional;} } -@if ( $section-secondary-color-mode == dark ) { .uk-section-secondary:not(.uk-preserve-color) { @extend .uk-dark !optional;} } - - -/* Overlap modifier - ========================================================================== */ - -/* - * Reserved modifier to make a section overlap another section with an border image - * Implemented by the theme - */ - -.uk-section-overlap { - @if(mixin-exists(hook-section-overlap)) {@include hook-section-overlap();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-section-misc)) {@include hook-section-misc();} - -// @mixin hook-section(){} -// @mixin hook-section-default(){} -// @mixin hook-section-muted(){} -// @mixin hook-section-secondary(){} -// @mixin hook-section-primary(){} -// @mixin hook-section-overlap(){} -// @mixin hook-section-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/slidenav.scss b/docs/_sass/uikit/components/slidenav.scss deleted file mode 100644 index 0b9af8f256..0000000000 --- a/docs/_sass/uikit/components/slidenav.scss +++ /dev/null @@ -1,122 +0,0 @@ -// Name: Slidenav -// Description: Component to create previous/next icon navigations -// -// Component: `uk-slidenav` -// -// Sub-objects: `uk-slidenav-container` -// -// Modifiers: `uk-slidenav-previous` -// `uk-slidenav-next` -// `uk-slidenav-large` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$slidenav-padding-vertical: 5px !default; -$slidenav-padding-horizontal: 10px !default; - -$slidenav-color: rgba($global-color, 0.5) !default; -$slidenav-hover-color: rgba($global-color, 0.9) !default; -$slidenav-active-color: rgba($global-color, 0.5) !default; - -$slidenav-large-padding-vertical: 10px !default; -$slidenav-large-padding-horizontal: $slidenav-large-padding-vertical !default; - - -/* ======================================================================== - Component: Slidenav - ========================================================================== */ - -/* - * Adopts `uk-icon` - */ - -.uk-slidenav { - padding: $slidenav-padding-vertical $slidenav-padding-horizontal; - color: $slidenav-color; - @if(mixin-exists(hook-slidenav)) {@include hook-slidenav();} -} - -/* Hover + Focus */ -.uk-slidenav:hover, -.uk-slidenav:focus { - color: $slidenav-hover-color; - outline: none; - @if(mixin-exists(hook-slidenav-hover)) {@include hook-slidenav-hover();} -} - -/* OnClick */ -.uk-slidenav:active { - color: $slidenav-active-color; - @if(mixin-exists(hook-slidenav-active)) {@include hook-slidenav-active();} -} - - -/* Icon modifier - ========================================================================== */ - -/* - * Previous - */ - -.uk-slidenav-previous { - @if(mixin-exists(hook-slidenav-previous)) {@include hook-slidenav-previous();} -} - -/* - * Next - */ - -.uk-slidenav-next { - @if(mixin-exists(hook-slidenav-next)) {@include hook-slidenav-next();} -} - - -/* Size modifier - ========================================================================== */ - -.uk-slidenav-large { - padding: $slidenav-large-padding-vertical $slidenav-large-padding-horizontal; - @if(mixin-exists(hook-slidenav-large)) {@include hook-slidenav-large();} -} - - -/* Container - ========================================================================== */ - -.uk-slidenav-container { - display: flex; - @if(mixin-exists(hook-slidenav-container)) {@include hook-slidenav-container();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-slidenav-misc)) {@include hook-slidenav-misc();} - -// @mixin hook-slidenav(){} -// @mixin hook-slidenav-hover(){} -// @mixin hook-slidenav-active(){} -// @mixin hook-slidenav-previous(){} -// @mixin hook-slidenav-next(){} -// @mixin hook-slidenav-large(){} -// @mixin hook-slidenav-container(){} -// @mixin hook-slidenav-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-slidenav-color: rgba($inverse-global-color, 0.7) !default; -$inverse-slidenav-hover-color: rgba($inverse-global-color, 0.95) !default; -$inverse-slidenav-active-color: rgba($inverse-global-color, 0.7) !default; - - - -// @mixin hook-inverse-slidenav(){} -// @mixin hook-inverse-slidenav-hover(){} -// @mixin hook-inverse-slidenav-active(){} diff --git a/docs/_sass/uikit/components/slider.scss b/docs/_sass/uikit/components/slider.scss deleted file mode 100644 index d73ec1f8da..0000000000 --- a/docs/_sass/uikit/components/slider.scss +++ /dev/null @@ -1,120 +0,0 @@ -// Name: Slider -// Description: Component to create horizontal sliders -// -// Component: `uk-slider` -// -// Sub-objects: `uk-slider-container` -// `uk-slider-items` -// -// States: `uk-active` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$slider-container-margin-top: -11px !default; -$slider-container-margin-bottom: -39px !default; -$slider-container-margin-left: -25px !default; -$slider-container-margin-right: -25px !default; - - -/* ======================================================================== - Component: Slider - ========================================================================== */ - -/* - * 1. Prevent tab highlighting on iOS. - */ - -.uk-slider { - /* 1 */ - -webkit-tap-highlight-color: transparent; - @if(mixin-exists(hook-slider)) {@include hook-slider();} -} - - -/* Container - ========================================================================== */ - -/* - * Clip child elements - */ - -.uk-slider-container { overflow: hidden; } - -/* - * Widen container to prevent box-shadows from clipping, `large-box-shadow` - */ - -.uk-slider-container-offset { - margin: $slider-container-margin-top $slider-container-margin-right $slider-container-margin-bottom $slider-container-margin-left; - padding: ($slider-container-margin-top * -1) ($slider-container-margin-right * -1) ($slider-container-margin-bottom * -1) ($slider-container-margin-left * -1); -} - -/* Items - ========================================================================== */ - -/* - * 1. Optimize animation - * 2. Create a containing block. In Safari it's neither created by `transform` nor `will-change`. - */ - -.uk-slider-items { - /* 1 */ - will-change: transform; - /* 2 */ - position: relative; -} - -/* - * 1. Reset list style without interfering with grid - * 2. Prevent displaying the callout information on iOS. - */ - -.uk-slider-items:not(.uk-grid) { - display: flex; - /* 1 */ - margin: 0; - padding: 0; - list-style: none; - /* 2 */ - -webkit-touch-callout: none; -} - -.uk-slider-items.uk-grid { flex-wrap: nowrap; } - - -/* Item - ========================================================================== */ - -/* - * 1. Let items take content dimensions (0 0 auto) - * `max-width` needed to keep image responsiveness and prevent content overflow - * 3. Create position context - * 4. Disable horizontal panning gestures in IE11 and Edge - * 5. Suppress outline on focus - */ - -.uk-slider-items > * { - /* 1 */ - flex: none; - max-width: 100%; - /* 3 */ - position: relative; - /* 4 */ - touch-action: pan-y; -} - -/* 5 */ -.uk-slider-items > :focus { outline: none; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-slider-misc)) {@include hook-slider-misc();} - -// @mixin hook-slider(){} -// @mixin hook-slider-misc(){} diff --git a/docs/_sass/uikit/components/slideshow.scss b/docs/_sass/uikit/components/slideshow.scss deleted file mode 100644 index 8a8117eb98..0000000000 --- a/docs/_sass/uikit/components/slideshow.scss +++ /dev/null @@ -1,97 +0,0 @@ -// Name: Slideshow -// Description: Component to create slideshows -// -// Component: `uk-slideshow` -// -// Sub-objects: `uk-slideshow-items` -// -// States: `uk-active` -// -// ======================================================================== - - -/* ======================================================================== - Component: Slideshow - ========================================================================== */ - -/* - * 1. Prevent tab highlighting on iOS. - */ - -.uk-slideshow { - /* 1 */ - -webkit-tap-highlight-color: transparent; - @if(mixin-exists(hook-slideshow)) {@include hook-slideshow();} -} - - -/* Items - ========================================================================== */ - -/* - * 1. Create position and stacking context - * 2. Reset list - * 3. Clip child elements - * 4. Prevent displaying the callout information on iOS. - */ - -.uk-slideshow-items { - /* 1 */ - position: relative; - z-index: 0; - /* 2 */ - margin: 0; - padding: 0; - list-style: none; - /* 3 */ - overflow: hidden; - /* 4 */ - -webkit-touch-callout: none; -} - - -/* Item - ========================================================================== */ - -/* - * 1. Position items above each other - * 2. Take the full width - * 3. Clip child elements, e.g. for `uk-cover` - * 4. Optimize animation - * 5. Disable horizontal panning gestures in IE11 and Edge - * 6. Suppress outline on focus - */ - -.uk-slideshow-items > * { - /* 1 */ - position: absolute; - top: 0; - left: 0; - /* 2 */ - right: 0; - bottom: 0; - /* 3 */ - overflow: hidden; - /* 4 */ - will-change: transform, opacity; - /* 5 */ - touch-action: pan-y; -} - -/* 6 */ -.uk-slideshow-items > :focus { outline: none; } - -/* - * Hide not active items - */ - -.uk-slideshow-items > :not(.uk-active) { display: none; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-slideshow-misc)) {@include hook-slideshow-misc();} - -// @mixin hook-slideshow(){} -// @mixin hook-slideshow-misc(){} diff --git a/docs/_sass/uikit/components/sortable.scss b/docs/_sass/uikit/components/sortable.scss deleted file mode 100644 index 5bc66aeb02..0000000000 --- a/docs/_sass/uikit/components/sortable.scss +++ /dev/null @@ -1,90 +0,0 @@ -// Name: Sortable -// Description: Component to create sortable grids and lists -// -// Component: `uk-sortable` -// -// Sub-objects: `uk-sortable-drag` -// `uk-sortable-placeholder` -// `uk-sortable-handle` -// -// Modifiers: `uk-sortable-empty` -// -// States: `uk-drag` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$sortable-dragged-z-index: $global-z-index + 50 !default; - -$sortable-placeholder-opacity: 0 !default; - -$sortable-empty-height: 50px !default; - - -/* ======================================================================== - Component: Sortable - ========================================================================== */ - -.uk-sortable { - position: relative; - @if(mixin-exists(hook-sortable)) {@include hook-sortable();} -} - -/* - * Remove margin from the last-child - */ - -.uk-sortable > :last-child { margin-bottom: 0; } - - -/* Drag - ========================================================================== */ - -.uk-sortable-drag { - position: fixed !important; - z-index: $sortable-dragged-z-index !important; - pointer-events: none; - @if(mixin-exists(hook-sortable-drag)) {@include hook-sortable-drag();} -} - - -/* Placeholder - ========================================================================== */ - -.uk-sortable-placeholder { - opacity: $sortable-placeholder-opacity; - pointer-events: none; - @if(mixin-exists(hook-sortable-placeholder)) {@include hook-sortable-placeholder();} -} - - -/* Empty modifier - ========================================================================== */ - -.uk-sortable-empty { - min-height: $sortable-empty-height; - @if(mixin-exists(hook-sortable-empty)) {@include hook-sortable-empty();} -} - - -/* Handle - ========================================================================== */ - -/* Hover */ -.uk-sortable-handle:hover { cursor: move; } - - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-sortable-misc)) {@include hook-sortable-misc();} - -// @mixin hook-sortable(){} -// @mixin hook-sortable-drag(){} -// @mixin hook-sortable-placeholder(){} -// @mixin hook-sortable-empty(){} -// @mixin hook-sortable-misc(){} diff --git a/docs/_sass/uikit/components/spinner.scss b/docs/_sass/uikit/components/spinner.scss deleted file mode 100644 index a02f41d17b..0000000000 --- a/docs/_sass/uikit/components/spinner.scss +++ /dev/null @@ -1,74 +0,0 @@ -// Name: Spinner -// Description: Component to create a loading spinner -// -// Component: `uk-spinner` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$spinner-size: 30px !default; -$spinner-stroke-width: 1 !default; -$spinner-radius: floor(($spinner-size - $spinner-stroke-width) / 2) !default; // Minus stroke width to prevent overflow clipping -$spinner-circumference: round(2 * 3.141 * $spinner-radius) !default; -$spinner-duration: 1.4s !default; - - -/* ======================================================================== - Component: Spinner - ========================================================================== */ - -/* - * Adopts `uk-icon` - */ - -.uk-spinner { - @if(mixin-exists(hook-spinner)) {@include hook-spinner();} -} - - -/* SVG - ========================================================================== */ - -.uk-spinner > * { animation: uk-spinner-rotate $spinner-duration linear infinite; } - -@keyframes uk-spinner-rotate { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(270deg); } -} - -/* - * Circle - */ - -.uk-spinner > * > * { - stroke-dasharray: $spinner-circumference; - stroke-dashoffset: 0; - transform-origin: center; - animation: uk-spinner-dash $spinner-duration ease-in-out infinite; - stroke-width: $spinner-stroke-width; - stroke-linecap: round; -} - -@keyframes uk-spinner-dash { - 0% { stroke-dashoffset: $spinner-circumference; } - 50% { - stroke-dashoffset: $spinner-circumference/4; - transform:rotate(135deg); - } - 100% { - stroke-dashoffset: $spinner-circumference; - transform:rotate(450deg); - } -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-spinner-misc)) {@include hook-spinner-misc();} - -// @mixin hook-spinner(){} -// @mixin hook-spinner-misc(){} diff --git a/docs/_sass/uikit/components/sticky.scss b/docs/_sass/uikit/components/sticky.scss deleted file mode 100644 index fe976d1926..0000000000 --- a/docs/_sass/uikit/components/sticky.scss +++ /dev/null @@ -1,53 +0,0 @@ -// Name: Sticky -// Description: Component to make elements sticky in the viewport -// -// Component: `uk-sticky` -// -// Modifier: `uk-sticky-fixed` -// -// States: `uk-active` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$sticky-z-index: $global-z-index - 20 !default; - -$sticky-animation-duration: 0.2s !default; -$sticky-reverse-animation-duration: 0.2s !default; - - -/* ======================================================================== - Component: Sticky - ========================================================================== */ - -/* - * 1. Force new layer to resolve frame rate issues on devices with lower frame rates - */ - -.uk-sticky-fixed { - z-index: $sticky-z-index; - box-sizing: border-box; - margin: 0 !important; - /* 1 */ - -webkit-backface-visibility: hidden; - backface-visibility: hidden; -} - -/* - * Faster animations - */ - -.uk-sticky[class*='uk-animation-'] { animation-duration: $sticky-animation-duration; } - -.uk-sticky.uk-animation-reverse { animation-duration: $sticky-reverse-animation-duration; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-sticky-misc)) {@include hook-sticky-misc();} - -// @mixin hook-sticky-misc(){} diff --git a/docs/_sass/uikit/components/subnav.scss b/docs/_sass/uikit/components/subnav.scss deleted file mode 100644 index 8b0d4548ed..0000000000 --- a/docs/_sass/uikit/components/subnav.scss +++ /dev/null @@ -1,249 +0,0 @@ -// Name: Subnav -// Description: Component to create a sub navigation -// -// Component: `uk-subnav` -// -// Modifiers: `uk-subnav-divider` -// `uk-subnav-pill` -// -// States: `uk-active` -// `uk-first-column` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$subnav-margin-horizontal: 20px !default; - -$subnav-item-color: $global-muted-color !default; -$subnav-item-hover-color: $global-color !default; -$subnav-item-hover-text-decoration: none !default; -$subnav-item-active-color: $global-emphasis-color !default; - -$subnav-divider-margin-horizontal: $subnav-margin-horizontal !default; -$subnav-divider-border-height: 1.5em !default; -$subnav-divider-border-width: $global-border-width !default; -$subnav-divider-border: $global-border !default; - -$subnav-pill-item-padding-vertical: 5px !default; -$subnav-pill-item-padding-horizontal: 10px !default; -$subnav-pill-item-background: transparent !default; -$subnav-pill-item-color: $subnav-item-color !default; -$subnav-pill-item-hover-background: $global-muted-background !default; -$subnav-pill-item-hover-color: $global-color !default; -$subnav-pill-item-onclick-background: $subnav-pill-item-hover-background !default; -$subnav-pill-item-onclick-color: $subnav-pill-item-hover-color !default; -$subnav-pill-item-active-background: $global-primary-background !default; -$subnav-pill-item-active-color: $global-inverse-color !default; - -$subnav-item-disabled-color: $global-muted-color !default; - - -/* ======================================================================== - Component: Subnav - ========================================================================== */ - -/* - * 1. Allow items to wrap into the next line - * 2. Center items vertically if they have a different height - * 3. Gutter - * 4. Reset list - */ - -.uk-subnav { - display: flex; - /* 1 */ - flex-wrap: wrap; - /* 2 */ - align-items: center; - /* 3 */ - margin-left: (-$subnav-margin-horizontal); - /* 4 */ - padding: 0; - list-style: none; - @if(mixin-exists(hook-subnav)) {@include hook-subnav();} -} - -/* - * 1. Space is allocated solely based on content dimensions: 0 0 auto - * 2. Gutter - * 3. Create position context for dropdowns - */ - -.uk-subnav > * { - /* 1 */ - flex: none; - /* 2 */ - padding-left: $subnav-margin-horizontal; - /* 3 */ - position: relative; -} - - -/* Items - ========================================================================== */ - -/* - * Items must target `a` elements to exclude other elements (e.g. dropdowns) - * Using `:first-child` instead of `a` to support `span` elements for text - * 1. Center content vertically, e.g. an icon - * 2. Imitate white space gap when using flexbox - * 3. Style - */ - -.uk-subnav > * > :first-child { - /* 1 */ - display: flex; - align-items: center; - /* 2 */ - column-gap: 0.25em; - /* 3 */ - color: $subnav-item-color; - @if(mixin-exists(hook-subnav-item)) {@include hook-subnav-item();} -} - -/* Hover + Focus */ -.uk-subnav > * > a:hover, -.uk-subnav > * > a:focus { - color: $subnav-item-hover-color; - text-decoration: $subnav-item-hover-text-decoration; - outline: none; - @if(mixin-exists(hook-subnav-item-hover)) {@include hook-subnav-item-hover();} -} - -/* Active */ -.uk-subnav > .uk-active > a { - color: $subnav-item-active-color; - @if(mixin-exists(hook-subnav-item-active)) {@include hook-subnav-item-active();} -} - - -/* Divider modifier - ========================================================================== */ - -/* - * Set gutter - */ - -.uk-subnav-divider { margin-left: -(($subnav-divider-margin-horizontal * 2) + $subnav-divider-border-width); } - -/* - * Align items and divider vertically - */ - -.uk-subnav-divider > * { - display: flex; - align-items: center; -} - -/* - * Divider - * 1. `nth-child` makes it also work without JS if it's only one row - */ - -.uk-subnav-divider > ::before { - content: ""; - height: $subnav-divider-border-height; - margin-left: ($subnav-divider-margin-horizontal - $subnav-margin-horizontal); - margin-right: $subnav-divider-margin-horizontal; - border-left: $subnav-divider-border-width solid transparent; -} - -/* 1 */ -.uk-subnav-divider > :nth-child(n+2):not(.uk-first-column)::before { - border-left-color: $subnav-divider-border; - @if(mixin-exists(hook-subnav-divider)) {@include hook-subnav-divider();} -} - - -/* Pill modifier - ========================================================================== */ - -.uk-subnav-pill > * > :first-child { - padding: $subnav-pill-item-padding-vertical $subnav-pill-item-padding-horizontal; - background: $subnav-pill-item-background; - color: $subnav-pill-item-color; - @if(mixin-exists(hook-subnav-pill-item)) {@include hook-subnav-pill-item();} -} - -/* Hover + Focus */ -.uk-subnav-pill > * > a:hover, -.uk-subnav-pill > * > a:focus { - background-color: $subnav-pill-item-hover-background; - color: $subnav-pill-item-hover-color; - @if(mixin-exists(hook-subnav-pill-item-hover)) {@include hook-subnav-pill-item-hover();} -} - -/* OnClick */ -.uk-subnav-pill > * > a:active { - background-color: $subnav-pill-item-onclick-background; - color: $subnav-pill-item-onclick-color; - @if(mixin-exists(hook-subnav-pill-item-onclick)) {@include hook-subnav-pill-item-onclick();} -} - -/* Active */ -.uk-subnav-pill > .uk-active > a { - background-color: $subnav-pill-item-active-background; - color: $subnav-pill-item-active-color; - @if(mixin-exists(hook-subnav-pill-item-active)) {@include hook-subnav-pill-item-active();} -} - - -/* Disabled - * The same for all style modifiers - ========================================================================== */ - -.uk-subnav > .uk-disabled > a { - color: $subnav-item-disabled-color; - @if(mixin-exists(hook-subnav-item-disabled)) {@include hook-subnav-item-disabled();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-subnav-misc)) {@include hook-subnav-misc();} - -// @mixin hook-subnav(){} -// @mixin hook-subnav-item(){} -// @mixin hook-subnav-item-hover(){} -// @mixin hook-subnav-item-active(){} -// @mixin hook-subnav-divider(){} -// @mixin hook-subnav-pill-item(){} -// @mixin hook-subnav-pill-item-hover(){} -// @mixin hook-subnav-pill-item-onclick(){} -// @mixin hook-subnav-pill-item-active(){} -// @mixin hook-subnav-item-disabled(){} -// @mixin hook-subnav-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-subnav-item-color: $inverse-global-muted-color !default; -$inverse-subnav-item-hover-color: $inverse-global-color !default; -$inverse-subnav-item-active-color: $inverse-global-emphasis-color !default; -$inverse-subnav-divider-border: $inverse-global-border !default; -$inverse-subnav-pill-item-background: transparent !default; -$inverse-subnav-pill-item-color: $inverse-global-muted-color !default; -$inverse-subnav-pill-item-hover-background: $inverse-global-muted-background !default; -$inverse-subnav-pill-item-hover-color: $inverse-global-color !default; -$inverse-subnav-pill-item-onclick-background: $inverse-subnav-pill-item-hover-background !default; -$inverse-subnav-pill-item-onclick-color: $inverse-subnav-pill-item-hover-color !default; -$inverse-subnav-pill-item-active-background: $inverse-global-primary-background !default; -$inverse-subnav-pill-item-active-color: $inverse-global-inverse-color !default; -$inverse-subnav-item-disabled-color: $inverse-global-muted-color !default; - - - -// @mixin hook-inverse-subnav-item(){} -// @mixin hook-inverse-subnav-item-hover(){} -// @mixin hook-inverse-subnav-item-active(){} -// @mixin hook-inverse-subnav-divider(){} -// @mixin hook-inverse-subnav-pill-item(){} -// @mixin hook-inverse-subnav-pill-item-hover(){} -// @mixin hook-inverse-subnav-pill-item-onclick(){} -// @mixin hook-inverse-subnav-pill-item-active(){} -// @mixin hook-inverse-subnav-item-disabled(){} diff --git a/docs/_sass/uikit/components/svg.scss b/docs/_sass/uikit/components/svg.scss deleted file mode 100644 index bcf804af07..0000000000 --- a/docs/_sass/uikit/components/svg.scss +++ /dev/null @@ -1,36 +0,0 @@ -// Name: SVG -// Description: Component to style SVGs -// -// Component: `uk-svg` -// -// ======================================================================== - - -/* ======================================================================== - Component: SVG - ========================================================================== */ - -/* - * 1. Fill all SVG elements with the current text color if no `fill` attribute is set - * 2. Set the fill and stroke color of all SVG elements to the current text color - */ - -/* 1 */ -.uk-svg, -/* 2 */ -.uk-svg:not(.uk-preserve) [fill*='#']:not(.uk-preserve) { fill: currentcolor; } -.uk-svg:not(.uk-preserve) [stroke*='#']:not(.uk-preserve) { stroke: currentcolor; } - -/* - * Fix Firefox blurry SVG rendering: https://bugzilla.mozilla.org/show_bug.cgi?id=1046835 - */ - -.uk-svg { transform: translate(0,0); } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-svg-misc)) {@include hook-svg-misc();} - -// @mixin hook-svg-misc(){} diff --git a/docs/_sass/uikit/components/switcher.scss b/docs/_sass/uikit/components/switcher.scss deleted file mode 100644 index 0d99cdf7b9..0000000000 --- a/docs/_sass/uikit/components/switcher.scss +++ /dev/null @@ -1,47 +0,0 @@ -// Name: Switcher -// Description: Component to navigate through different content panes -// -// Component: `uk-switcher` -// -// States: `uk-active` -// -// ======================================================================== - - -/* ======================================================================== - Component: Switcher - ========================================================================== */ - -/* - * Reset list - */ - -.uk-switcher { - margin: 0; - padding: 0; - list-style: none; -} - - -/* Items - ========================================================================== */ - -/* - * Hide not active items - */ - -.uk-switcher > :not(.uk-active) { display: none; } - -/* - * Remove margin from the last-child - */ - -.uk-switcher > * > :last-child { margin-bottom: 0; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-switcher-misc)) {@include hook-switcher-misc();} - -// @mixin hook-switcher-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/tab.scss b/docs/_sass/uikit/components/tab.scss deleted file mode 100644 index 16d297f617..0000000000 --- a/docs/_sass/uikit/components/tab.scss +++ /dev/null @@ -1,197 +0,0 @@ -// Name: Tab -// Description: Component to create a tabbed navigation -// -// Component: `uk-tab` -// -// Modifiers: `uk-tab-bottom` -// `uk-tab-left` -// `uk-tab-right` -// -// States: `uk-active` -// `uk-disabled` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$tab-margin-horizontal: 20px !default; - -$tab-item-padding-horizontal: 10px !default; -$tab-item-padding-vertical: 5px !default; -$tab-item-color: $global-muted-color !default; -$tab-item-hover-color: $global-color !default; -$tab-item-hover-text-decoration: none !default; -$tab-item-active-color: $global-emphasis-color !default; -$tab-item-disabled-color: $global-muted-color !default; - - -/* ======================================================================== - Component: Tab - ========================================================================== */ - -/* - * 1. Allow items to wrap into the next line - * 2. Gutter - * 3. Reset list - */ - -.uk-tab { - display: flex; - /* 1 */ - flex-wrap: wrap; - /* 2 */ - margin-left: (-$tab-margin-horizontal); - /* 3 */ - padding: 0; - list-style: none; - @if(mixin-exists(hook-tab)) {@include hook-tab();} -} - -/* - * 1. Space is allocated solely based on content dimensions: 0 0 auto - * 2. Gutter - * 3. Create position context for dropdowns - */ - -.uk-tab > * { - /* 1 */ - flex: none; - /* 2 */ - padding-left: $tab-margin-horizontal; - /* 3 */ - position: relative; -} - - -/* Items - ========================================================================== */ - -/* - * Items must target `a` elements to exclude other elements (e.g. dropdowns) - * 1. Center content vertically, e.g. an icon - * 2. Imitate white space gap when using flexbox - * 3. Center content if a width is set - * 4. Style - */ - -.uk-tab > * > a { - /* 1 */ - display: flex; - align-items: center; - /* 2 */ - column-gap: 0.25em; - /* 3 */ - justify-content: center; - /* 4 */ - padding: $tab-item-padding-vertical $tab-item-padding-horizontal; - color: $tab-item-color; - @if(mixin-exists(hook-tab-item)) {@include hook-tab-item();} -} - -/* Hover + Focus */ -.uk-tab > * > a:hover, -.uk-tab > * > a:focus { - color: $tab-item-hover-color; - text-decoration: $tab-item-hover-text-decoration; - @if(mixin-exists(hook-tab-item-hover)) {@include hook-tab-item-hover();} -} - -/* Active */ -.uk-tab > .uk-active > a { - color: $tab-item-active-color; - @if(mixin-exists(hook-tab-item-active)) {@include hook-tab-item-active();} -} - -/* Disabled */ -.uk-tab > .uk-disabled > a { - color: $tab-item-disabled-color; - @if(mixin-exists(hook-tab-item-disabled)) {@include hook-tab-item-disabled();} -} - - -/* Position modifier - ========================================================================== */ - -/* - * Bottom - */ - -.uk-tab-bottom { - @if(mixin-exists(hook-tab-bottom)) {@include hook-tab-bottom();} -} - -.uk-tab-bottom > * > a { - @if(mixin-exists(hook-tab-bottom-item)) {@include hook-tab-bottom-item();} -} - -/* - * Left + Right - * 1. Reset Gutter - */ - -.uk-tab-left, -.uk-tab-right { - flex-direction: column; - /* 1 */ - margin-left: 0; -} - -/* 1 */ -.uk-tab-left > *, -.uk-tab-right > * { padding-left: 0; } - -.uk-tab-left { - @if(mixin-exists(hook-tab-left)) {@include hook-tab-left();} -} - -.uk-tab-right { - @if(mixin-exists(hook-tab-right)) {@include hook-tab-right();} -} - -.uk-tab-left > * > a { - text-align: left; - @if(mixin-exists(hook-tab-left-item)) {@include hook-tab-left-item();} -} - -.uk-tab-right > * > a { - text-align: left; - @if(mixin-exists(hook-tab-right-item)) {@include hook-tab-right-item();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-tab-misc)) {@include hook-tab-misc();} - -// @mixin hook-tab(){} -// @mixin hook-tab-item(){} -// @mixin hook-tab-item-hover(){} -// @mixin hook-tab-item-active(){} -// @mixin hook-tab-item-disabled(){} -// @mixin hook-tab-bottom(){} -// @mixin hook-tab-bottom-item(){} -// @mixin hook-tab-left(){} -// @mixin hook-tab-left-item(){} -// @mixin hook-tab-right(){} -// @mixin hook-tab-right-item(){} -// @mixin hook-tab-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-tab-item-color: $inverse-global-muted-color !default; -$inverse-tab-item-hover-color: $inverse-global-color !default; -$inverse-tab-item-active-color: $inverse-global-emphasis-color !default; -$inverse-tab-item-disabled-color: $inverse-global-muted-color !default; - - - -// @mixin hook-inverse-tab(){} -// @mixin hook-inverse-tab-item(){} -// @mixin hook-inverse-tab-item-hover(){} -// @mixin hook-inverse-tab-item-active(){} -// @mixin hook-inverse-tab-item-disabled(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/table.scss b/docs/_sass/uikit/components/table.scss deleted file mode 100644 index 50e2f81abf..0000000000 --- a/docs/_sass/uikit/components/table.scss +++ /dev/null @@ -1,315 +0,0 @@ -// Name: Table -// Description: Styles for tables -// -// Component: `uk-table` -// -// Modifiers: `uk-table-middle` -// `uk-table-divider` -// `uk-table-striped` -// `uk-table-hover` -// `uk-table-small` -// `uk-table-justify` -// `uk-table-shrink` -// `uk-table-expand` -// `uk-table-link` -// `uk-table-responsive` -// -// States: `uk-active` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$table-margin-vertical: $global-margin !default; - -$table-cell-padding-vertical: 16px !default; -$table-cell-padding-horizontal: 12px !default; - -$table-header-cell-font-size: $global-font-size !default; -$table-header-cell-font-weight: bold !default; -$table-header-cell-color: $global-color !default; - -$table-footer-font-size: $global-small-font-size !default; - -$table-caption-font-size: $global-small-font-size !default; -$table-caption-color: $global-muted-color !default; - -$table-row-active-background: #ffd !default; - -$table-divider-border-width: $global-border-width !default; -$table-divider-border: $global-border !default; - -$table-striped-row-background: $global-muted-background !default; - -$table-hover-row-background: $table-row-active-background !default; - -$table-small-cell-padding-vertical: 10px !default; -$table-small-cell-padding-horizontal: 12px !default; - -$table-large-cell-padding-vertical: 22px !default; -$table-large-cell-padding-horizontal: 12px !default; - -$table-expand-min-width: 150px !default; - - -/* ======================================================================== - Component: Table - ========================================================================== */ - -/* - * 1. Remove most spacing between table cells. - * 2. Behave like a block element - * 3. Style - */ - -.uk-table { - /* 1 */ - border-collapse: collapse; - border-spacing: 0; - /* 2 */ - width: 100%; - /* 3 */ - margin-bottom: $table-margin-vertical; - @if(mixin-exists(hook-table)) {@include hook-table();} -} - -/* Add margin if adjacent element */ -* + .uk-table { margin-top: $table-margin-vertical; } - - -/* Header cell - ========================================================================== */ - -/* - * 1. Style - */ - -.uk-table th { - padding: $table-cell-padding-vertical $table-cell-padding-horizontal; - text-align: left; - vertical-align: bottom; - /* 1 */ - font-size: $table-header-cell-font-size; - font-weight: $table-header-cell-font-weight; - color: $table-header-cell-color; - @if(mixin-exists(hook-table-header-cell)) {@include hook-table-header-cell();} -} - - -/* Cell - ========================================================================== */ - -.uk-table td { - padding: $table-cell-padding-vertical $table-cell-padding-horizontal; - vertical-align: top; - @if(mixin-exists(hook-table-cell)) {@include hook-table-cell();} -} - -/* - * Remove margin from the last-child - */ - -.uk-table td > :last-child { margin-bottom: 0; } - - -/* Footer - ========================================================================== */ - -.uk-table tfoot { - font-size: $table-footer-font-size; - @if(mixin-exists(hook-table-footer)) {@include hook-table-footer();} -} - - -/* Caption - ========================================================================== */ - -.uk-table caption { - font-size: $table-caption-font-size; - text-align: left; - color: $table-caption-color; - @if(mixin-exists(hook-table-caption)) {@include hook-table-caption();} -} - - -/* Alignment modifier - ========================================================================== */ - -.uk-table-middle, -.uk-table-middle td { vertical-align: middle !important; } - - -/* Style modifiers - ========================================================================== */ - -/* - * Divider - */ - -.uk-table-divider > tr:not(:first-child), -.uk-table-divider > :not(:first-child) > tr, -.uk-table-divider > :first-child > tr:not(:first-child) { - border-top: $table-divider-border-width solid $table-divider-border; - @if(mixin-exists(hook-table-divider)) {@include hook-table-divider();} -} - -/* - * Striped - */ - -.uk-table-striped > tr:nth-of-type(odd), -.uk-table-striped tbody tr:nth-of-type(odd) { - background: $table-striped-row-background; - @if(mixin-exists(hook-table-striped)) {@include hook-table-striped();} -} - -/* - * Hover - */ - -.uk-table-hover > tr:hover, -.uk-table-hover tbody tr:hover { - background: $table-hover-row-background; - @if(mixin-exists(hook-table-hover)) {@include hook-table-hover();} -} - - -/* Active state - ========================================================================== */ - -.uk-table > tr.uk-active, -.uk-table tbody tr.uk-active { - background: $table-row-active-background; - @if(mixin-exists(hook-table-row-active)) {@include hook-table-row-active();} -} - -/* Size modifier - ========================================================================== */ - -.uk-table-small th, -.uk-table-small td { - padding: $table-small-cell-padding-vertical $table-small-cell-padding-horizontal; - @if(mixin-exists(hook-table-small)) {@include hook-table-small();} -} - -.uk-table-large th, -.uk-table-large td { - padding: $table-large-cell-padding-vertical $table-large-cell-padding-horizontal; - @if(mixin-exists(hook-table-large)) {@include hook-table-large();} -} - - -/* Justify modifier - ========================================================================== */ - -.uk-table-justify th:first-child, -.uk-table-justify td:first-child { padding-left: 0; } - -.uk-table-justify th:last-child, -.uk-table-justify td:last-child { padding-right: 0; } - - -/* Cell size modifier - ========================================================================== */ - -.uk-table-shrink { width: 1px; } -.uk-table-expand { min-width: $table-expand-min-width; } - - -/* Cell link modifier - ========================================================================== */ - -/* - * Does not work with `uk-table-justify` at the moment - */ - -.uk-table-link { padding: 0 !important; } - -.uk-table-link > a { - display: block; - padding: $table-cell-padding-vertical $table-cell-padding-horizontal; -} - -.uk-table-small .uk-table-link > a { padding: $table-small-cell-padding-vertical $table-small-cell-padding-horizontal; } - - -/* Responsive table - ========================================================================== */ - - -/* Phone landscape and smaller */ -@media (max-width: $breakpoint-small-max) { - - .uk-table-responsive, - .uk-table-responsive tbody, - .uk-table-responsive th, - .uk-table-responsive td, - .uk-table-responsive tr { display: block; } - - .uk-table-responsive thead { display: none; } - - .uk-table-responsive th, - .uk-table-responsive td { - width: auto !important; - max-width: none !important; - min-width: 0 !important; - overflow: visible !important; - white-space: normal !important; - } - - .uk-table-responsive th:not(:first-child):not(.uk-table-link), - .uk-table-responsive td:not(:first-child):not(.uk-table-link), - .uk-table-responsive .uk-table-link:not(:first-child) > a { padding-top: round($table-cell-padding-vertical / 3) !important; } - - .uk-table-responsive th:not(:last-child):not(.uk-table-link), - .uk-table-responsive td:not(:last-child):not(.uk-table-link), - .uk-table-responsive .uk-table-link:not(:last-child) > a { padding-bottom: round($table-cell-padding-vertical / 3) !important; } - - .uk-table-justify.uk-table-responsive th, - .uk-table-justify.uk-table-responsive td { - padding-left: 0; - padding-right: 0; - } - -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-table-misc)) {@include hook-table-misc();} - -// @mixin hook-table(){} -// @mixin hook-table-header-cell(){} -// @mixin hook-table-cell(){} -// @mixin hook-table-footer(){} -// @mixin hook-table-caption(){} -// @mixin hook-table-row-active(){} -// @mixin hook-table-divider(){} -// @mixin hook-table-striped(){} -// @mixin hook-table-hover(){} -// @mixin hook-table-small(){} -// @mixin hook-table-large(){} -// @mixin hook-table-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-table-header-cell-color: $inverse-global-color !default; -$inverse-table-caption-color: $inverse-global-muted-color !default; -$inverse-table-row-active-background: fade-out($inverse-global-muted-background, 0.02) !default; -$inverse-table-divider-border: $inverse-global-border !default; -$inverse-table-striped-row-background: $inverse-global-muted-background !default; -$inverse-table-hover-row-background: $inverse-table-row-active-background !default; - - - -// @mixin hook-inverse-table-header-cell(){} -// @mixin hook-inverse-table-caption(){} -// @mixin hook-inverse-table-row-active(){} -// @mixin hook-inverse-table-divider(){} -// @mixin hook-inverse-table-striped(){} -// @mixin hook-inverse-table-hover(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/text.scss b/docs/_sass/uikit/components/text.scss deleted file mode 100644 index 25f5df2203..0000000000 --- a/docs/_sass/uikit/components/text.scss +++ /dev/null @@ -1,284 +0,0 @@ -// Name: Text -// Description: Utilities for text -// -// Component: `uk-text-*` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$text-lead-font-size: $global-large-font-size !default; -$text-lead-line-height: 1.5 !default; -$text-lead-color: $global-emphasis-color !default; - -$text-meta-font-size: $global-small-font-size !default; -$text-meta-line-height: 1.4 !default; -$text-meta-color: $global-muted-color !default; - -$text-small-font-size: $global-small-font-size !default; -$text-small-line-height: 1.5 !default; - -$text-large-font-size: $global-large-font-size !default; -$text-large-line-height: 1.5 !default; - -$text-muted-color: $global-muted-color !default; -$text-emphasis-color: $global-emphasis-color !default; -$text-primary-color: $global-primary-background !default; -$text-secondary-color: $global-secondary-background !default; -$text-success-color: $global-success-background !default; -$text-warning-color: $global-warning-background !default; -$text-danger-color: $global-danger-background !default; - -$text-background-color: $global-primary-background !default; - - -/* ======================================================================== - Component: Text - ========================================================================== */ - - -/* Style modifiers - ========================================================================== */ - -.uk-text-lead { - font-size: $text-lead-font-size; - line-height: $text-lead-line-height; - color: $text-lead-color; - @if(mixin-exists(hook-text-lead)) {@include hook-text-lead();} -} - -.uk-text-meta { - font-size: $text-meta-font-size; - line-height: $text-meta-line-height; - color: $text-meta-color; - @if(mixin-exists(hook-text-meta)) {@include hook-text-meta();} -} - - -/* Size modifiers - ========================================================================== */ - -.uk-text-small { - font-size: $text-small-font-size; - line-height: $text-small-line-height; - @if(mixin-exists(hook-text-small)) {@include hook-text-small();} -} - -.uk-text-large { - font-size: $text-large-font-size; - line-height: $text-large-line-height; - @if(mixin-exists(hook-text-large)) {@include hook-text-large();} -} - -.uk-text-default { - font-size: $global-font-size; - line-height: $global-line-height; -} - - -/* Weight modifier - ========================================================================== */ - -.uk-text-light { font-weight: 300; } -.uk-text-normal { font-weight: 400; } -.uk-text-bold { font-weight: 700; } - -.uk-text-lighter { font-weight: lighter; } -.uk-text-bolder { font-weight: bolder; } - - -/* Style modifier - ========================================================================== */ - -.uk-text-italic { font-style: italic; } - - -/* Transform modifier - ========================================================================== */ - -.uk-text-capitalize { text-transform: capitalize !important; } -.uk-text-uppercase { text-transform: uppercase !important; } -.uk-text-lowercase { text-transform: lowercase !important; } - - -/* Decoration modifier - ========================================================================== */ - -.uk-text-decoration-none { text-decoration: none !important; } - - -/* Color modifiers - ========================================================================== */ - -.uk-text-muted { color: $text-muted-color !important; } -.uk-text-emphasis { color: $text-emphasis-color !important; } -.uk-text-primary { color: $text-primary-color !important; } -.uk-text-secondary { color: $text-secondary-color !important; } -.uk-text-success { color: $text-success-color !important; } -.uk-text-warning { color: $text-warning-color !important; } -.uk-text-danger { color: $text-danger-color !important; } - - -/* Background modifier - ========================================================================== */ - -/* - * 1. The background clips to the foreground text. Works in Chrome, Firefox, Safari, Edge and Opera - * Default color is set to transparent - * 2. Container fits the text - * 3. Fallback color for IE11 - */ - -.uk-text-background { - /* 1 */ - -webkit-background-clip: text; - /* 2 */ - display: inline-block; - /* 3 */ - color: $text-background-color !important; -} - -@supports (-webkit-background-clip: text) { - - .uk-text-background { - background-color: $text-background-color; - color: transparent !important; - @if(mixin-exists(hook-text-background)) {@include hook-text-background();} - } - -} - - -/* Alignment modifiers - ========================================================================== */ - -.uk-text-left { text-align: left !important; } -.uk-text-right { text-align: right !important; } -.uk-text-center { text-align: center !important; } -.uk-text-justify { text-align: justify !important; } - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-text-left\@s { text-align: left !important; } - .uk-text-right\@s { text-align: right !important; } - .uk-text-center\@s { text-align: center !important; } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-text-left\@m { text-align: left !important; } - .uk-text-right\@m { text-align: right !important; } - .uk-text-center\@m { text-align: center !important; } - -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-text-left\@l { text-align: left !important; } - .uk-text-right\@l { text-align: right !important; } - .uk-text-center\@l { text-align: center !important; } - -} - -/* Large screen and bigger */ -@media (min-width: $breakpoint-xlarge) { - - .uk-text-left\@xl { text-align: left !important; } - .uk-text-right\@xl { text-align: right !important; } - .uk-text-center\@xl { text-align: center !important; } - -} - -/* - * Vertical - */ - -.uk-text-top { vertical-align: top !important; } -.uk-text-middle { vertical-align: middle !important; } -.uk-text-bottom { vertical-align: bottom !important; } -.uk-text-baseline { vertical-align: baseline !important; } - - -/* Wrap modifiers - ========================================================================== */ - -/* - * Prevent text from wrapping onto multiple lines - */ - -.uk-text-nowrap { white-space: nowrap; } - -/* - * 1. Make sure a max-width is set after which truncation can occur - * 2. Prevent text from wrapping onto multiple lines, and truncate with an ellipsis - * 3. Fix for table cells - */ - -.uk-text-truncate { - /* 1 */ - max-width: 100%; - /* 2 */ - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -/* 2 */ -th.uk-text-truncate, -td.uk-text-truncate { max-width: 0; } - - -/* - * 1. Wrap long words onto the next line and break them if they are too long to fit - * 2. Legacy `word-wrap` as fallback for `overflow-wrap` - * 3. Fix `overflow-wrap` which doesn't work with table cells in Chrome, Opera, IE11 and Edge - * Must use `break-all` to support IE11 and Edge - * Note: Not using `hyphens: auto;` because it hyphenates text even if not needed - */ - -.uk-text-break { - /* 1 */ - overflow-wrap: break-word; - /* 2 */ - word-wrap: break-word; -} - -/* 3 */ -th.uk-text-break, -td.uk-text-break { word-break: break-all; } - - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-text-misc)) {@include hook-text-misc();} - -// @mixin hook-text-lead(){} -// @mixin hook-text-meta(){} -// @mixin hook-text-small(){} -// @mixin hook-text-large(){} -// @mixin hook-text-background(){} -// @mixin hook-text-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-text-lead-color: $inverse-global-color !default; -$inverse-text-meta-color: $inverse-global-muted-color !default; -$inverse-text-muted-color: $inverse-global-muted-color !default; -$inverse-text-emphasis-color: $inverse-global-emphasis-color !default; -$inverse-text-primary-color: $inverse-global-primary-background !default; -$inverse-text-secondary-color: $inverse-global-primary-background !default; - - - -// @mixin hook-inverse-text-lead(){} -// @mixin hook-inverse-text-meta(){} diff --git a/docs/_sass/uikit/components/thumbnav.scss b/docs/_sass/uikit/components/thumbnav.scss deleted file mode 100644 index ce211a1f52..0000000000 --- a/docs/_sass/uikit/components/thumbnav.scss +++ /dev/null @@ -1,121 +0,0 @@ -// Name: Thumbnav -// Description: Component to create thumbnail navigations -// -// Component: `uk-thumbnav` -// -// Modifier: `uk-thumbnav-vertical` -// -// States: `uk-active` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$thumbnav-margin-horizontal: 15px !default; -$thumbnav-margin-vertical: $thumbnav-margin-horizontal !default; - - -/* ======================================================================== - Component: Thumbnav - ========================================================================== */ - -/* - * 1. Allow items to wrap into the next line - * 2. Reset list - * 3. Gutter - */ - -.uk-thumbnav { - display: flex; - /* 1 */ - flex-wrap: wrap; - /* 2 */ - margin: 0; - padding: 0; - list-style: none; - /* 3 */ - margin-left: (-$thumbnav-margin-horizontal); - @if(mixin-exists(hook-thumbnav)) {@include hook-thumbnav();} -} - -/* - * Space is allocated based on content dimensions, but shrinks: 0 1 auto - * 1. Gutter - */ - -.uk-thumbnav > * { - /* 1 */ - padding-left: $thumbnav-margin-horizontal; -} - - -/* Items - ========================================================================== */ - -/* - * Items - */ - -.uk-thumbnav > * > * { - display: inline-block; - @if(mixin-exists(hook-thumbnav-item)) {@include hook-thumbnav-item();} -} - -/* Hover + Focus */ -.uk-thumbnav > * > :hover, -.uk-thumbnav > * > :focus { - outline: none; - @if(mixin-exists(hook-thumbnav-item-hover)) {@include hook-thumbnav-item-hover();} -} - -/* Active */ -.uk-thumbnav > .uk-active > * { - @if(mixin-exists(hook-thumbnav-item-active)) {@include hook-thumbnav-item-active();} -} - - -/* Modifier: 'uk-thumbnav-vertical' - ========================================================================== */ - -/* - * 1. Change direction - * 2. Gutter - */ - -.uk-thumbnav-vertical { - /* 1 */ - flex-direction: column; - /* 2 */ - margin-left: 0; - margin-top: (-$thumbnav-margin-vertical); -} - -/* 2 */ -.uk-thumbnav-vertical > * { - padding-left: 0; - padding-top: $thumbnav-margin-vertical; -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-thumbnav-misc)) {@include hook-thumbnav-misc();} - -// @mixin hook-thumbnav(){} -// @mixin hook-thumbnav-item(){} -// @mixin hook-thumbnav-item-hover(){} -// @mixin hook-thumbnav-item-active(){} -// @mixin hook-thumbnav-misc(){} - - -// Inverse -// ======================================================================== - - - -// @mixin hook-inverse-thumbnav-item(){} -// @mixin hook-inverse-thumbnav-item-hover(){} -// @mixin hook-inverse-thumbnav-item-active(){} \ No newline at end of file diff --git a/docs/_sass/uikit/components/tile.scss b/docs/_sass/uikit/components/tile.scss deleted file mode 100644 index 129ee19786..0000000000 --- a/docs/_sass/uikit/components/tile.scss +++ /dev/null @@ -1,213 +0,0 @@ -// Name: Tile -// Description: Component to create tiled boxes -// -// Component: `uk-tile` -// -// Modifiers: `uk-tile-xsmall` -// `uk-tile-small` -// `uk-tile-large` -// `uk-tile-xlarge` -// `uk-tile-default` -// `uk-tile-muted` -// `uk-tile-primary` -// `uk-tile-secondary` -// -// States: `uk-preserve-color` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$tile-padding-horizontal: 15px !default; -$tile-padding-horizontal-s: $global-gutter !default; -$tile-padding-horizontal-m: $global-medium-gutter !default; -$tile-padding-vertical: $global-medium-margin !default; -$tile-padding-vertical-m: $global-large-margin !default; - -$tile-xsmall-padding-vertical: $global-margin !default; - -$tile-small-padding-vertical: $global-medium-margin !default; - -$tile-large-padding-vertical: $global-large-margin !default; -$tile-large-padding-vertical-m: $global-xlarge-margin !default; - -$tile-xlarge-padding-vertical: $global-xlarge-margin !default; -$tile-xlarge-padding-vertical-m: ($global-large-margin + $global-xlarge-margin) !default; - -$tile-default-background: $global-background !default; - -$tile-muted-background: $global-muted-background !default; - -$tile-primary-background: $global-primary-background !default; -$tile-primary-color-mode: light !default; - -$tile-secondary-background: $global-secondary-background !default; -$tile-secondary-color-mode: light !default; - - -/* ======================================================================== - Component: Tile - ========================================================================== */ - -.uk-tile { - display: flow-root; - position: relative; - box-sizing: border-box; - padding-left: $tile-padding-horizontal; - padding-right: $tile-padding-horizontal; - padding-top: $tile-padding-vertical; - padding-bottom: $tile-padding-vertical; - @if(mixin-exists(hook-tile)) {@include hook-tile();} -} - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-tile { - padding-left: $tile-padding-horizontal-s; - padding-right: $tile-padding-horizontal-s; - } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-tile { - padding-left: $tile-padding-horizontal-m; - padding-right: $tile-padding-horizontal-m; - padding-top: $tile-padding-vertical-m; - padding-bottom: $tile-padding-vertical-m; - } - -} - -/* - * Remove margin from the last-child - */ - -.uk-tile > :last-child { margin-bottom: 0; } - - -/* Size modifiers - ========================================================================== */ - -/* - * XSmall - */ - -.uk-tile-xsmall { - padding-top: $tile-xsmall-padding-vertical; - padding-bottom: $tile-xsmall-padding-vertical; -} - -/* - * Small - */ - -.uk-tile-small { - padding-top: $tile-small-padding-vertical; - padding-bottom: $tile-small-padding-vertical; -} - -/* - * Large - */ - -.uk-tile-large { - padding-top: $tile-large-padding-vertical; - padding-bottom: $tile-large-padding-vertical; -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-tile-large { - padding-top: $tile-large-padding-vertical-m; - padding-bottom: $tile-large-padding-vertical-m; - } - -} - - -/* - * XLarge - */ - -.uk-tile-xlarge { - padding-top: $tile-xlarge-padding-vertical; - padding-bottom: $tile-xlarge-padding-vertical; -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-tile-xlarge { - padding-top: $tile-xlarge-padding-vertical-m; - padding-bottom: $tile-xlarge-padding-vertical-m; - } - -} - - -/* Style modifiers - ========================================================================== */ - -/* - * Default - */ - -.uk-tile-default { - background: $tile-default-background; - @if(mixin-exists(hook-tile-default)) {@include hook-tile-default();} -} - -/* - * Muted - */ - -.uk-tile-muted { - background: $tile-muted-background; - @if(mixin-exists(hook-tile-muted)) {@include hook-tile-muted();} -} - -/* - * Primary - */ - -.uk-tile-primary { - background: $tile-primary-background; - @if(mixin-exists(hook-tile-primary)) {@include hook-tile-primary();} -} - -// Color Mode -@if ( $tile-primary-color-mode == light ) { .uk-tile-primary:not(.uk-preserve-color) { @extend .uk-light !optional;} } -@if ( $tile-primary-color-mode == dark ) { .uk-tile-primary:not(.uk-preserve-color) { @extend .uk-dark !optional;} } - -/* - * Secondary - */ - -.uk-tile-secondary { - background: $tile-secondary-background; - @if(mixin-exists(hook-tile-secondary)) {@include hook-tile-secondary();} -} - -// Color Mode -@if ( $tile-secondary-color-mode == light ) { .uk-tile-secondary:not(.uk-preserve-color) { @extend .uk-light !optional;} } -@if ( $tile-secondary-color-mode == dark ) { .uk-tile-secondary:not(.uk-preserve-color) { @extend .uk-dark !optional;} } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-tile-misc)) {@include hook-tile-misc();} - -// @mixin hook-tile(){} -// @mixin hook-tile-default(){} -// @mixin hook-tile-muted(){} -// @mixin hook-tile-primary(){} -// @mixin hook-tile-secondary(){} -// @mixin hook-tile-misc(){} diff --git a/docs/_sass/uikit/components/tooltip.scss b/docs/_sass/uikit/components/tooltip.scss deleted file mode 100644 index 416d289e4c..0000000000 --- a/docs/_sass/uikit/components/tooltip.scss +++ /dev/null @@ -1,87 +0,0 @@ -// Name: Tooltip -// Description: Component to create tooltips -// -// Component: `uk-tooltip` -// -// Modifiers `uk-tooltip-top` -// `uk-tooltip-top-left` -// `uk-tooltip-top-right` -// `uk-tooltip-bottom` -// `uk-tooltip-bottom-left` -// `uk-tooltip-bottom-right` -// `uk-tooltip-left` -// `uk-tooltip-right` -// -// States: `uk-active` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$tooltip-z-index: $global-z-index + 30 !default; -$tooltip-max-width: 200px !default; -$tooltip-padding-vertical: 3px !default; -$tooltip-padding-horizontal: 6px !default; -$tooltip-background: #666 !default; -$tooltip-border-radius: 2px !default; -$tooltip-color: $global-inverse-color !default; -$tooltip-font-size: 12px !default; - -$tooltip-margin: 10px !default; - - -/* ======================================================================== - Component: Tooltip - ========================================================================== */ - -/* - * 1. Hide by default - * 2. Position - * 3. Remove tooltip from document flow to keep the UIkit container from changing its size when injected into the document initially - * 4. Dimensions - * 5. Style - */ - -.uk-tooltip { - /* 1 */ - display: none; - /* 2 */ - position: absolute; - z-index: $tooltip-z-index; - /* 3 */ - top: 0; - /* 4 */ - box-sizing: border-box; - max-width: $tooltip-max-width; - padding: $tooltip-padding-vertical $tooltip-padding-horizontal; - /* 5 */ - background: $tooltip-background; - border-radius: $tooltip-border-radius; - color: $tooltip-color; - font-size: $tooltip-font-size; - @if(mixin-exists(hook-tooltip)) {@include hook-tooltip();} -} - -/* Show */ -.uk-tooltip.uk-active { display: block; } - - -/* Direction / Alignment modifiers - ========================================================================== */ - -/* Direction */ -[class*='uk-tooltip-top'] { margin-top: (-$tooltip-margin); } -[class*='uk-tooltip-bottom'] { margin-top: $tooltip-margin; } -[class*='uk-tooltip-left'] { margin-left: (-$tooltip-margin); } -[class*='uk-tooltip-right'] { margin-left: $tooltip-margin; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-tooltip-misc)) {@include hook-tooltip-misc();} - -// @mixin hook-tooltip(){} -// @mixin hook-tooltip-misc(){} diff --git a/docs/_sass/uikit/components/totop.scss b/docs/_sass/uikit/components/totop.scss deleted file mode 100644 index 4b8aa1d88f..0000000000 --- a/docs/_sass/uikit/components/totop.scss +++ /dev/null @@ -1,71 +0,0 @@ -// Name: Totop -// Description: Component to create an icon to scroll back to top -// -// Component: `uk-totop` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$totop-padding: 5px !default; -$totop-color: $global-muted-color !default; - -$totop-hover-color: $global-color !default; - -$totop-active-color: $global-emphasis-color !default; - - -/* ======================================================================== - Component: Totop - ========================================================================== */ - -/* - * Addopts `uk-icon` - */ - -.uk-totop { - padding: $totop-padding; - color: $totop-color; - @if(mixin-exists(hook-totop)) {@include hook-totop();} -} - -/* Hover + Focus */ -.uk-totop:hover, -.uk-totop:focus { - color: $totop-hover-color; - outline: none; - @if(mixin-exists(hook-totop-hover)) {@include hook-totop-hover();} -} - -/* OnClick */ -.uk-totop:active { - color: $totop-active-color; - @if(mixin-exists(hook-totop-active)) {@include hook-totop-active();} -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-totop-misc)) {@include hook-totop-misc();} - -// @mixin hook-totop(){} -// @mixin hook-totop-hover(){} -// @mixin hook-totop-active(){} -// @mixin hook-totop-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-totop-color: $inverse-global-muted-color !default; -$inverse-totop-hover-color: $inverse-global-color !default; -$inverse-totop-active-color: $inverse-global-emphasis-color !default; - - - -// @mixin hook-inverse-totop(){} -// @mixin hook-inverse-totop-hover(){} -// @mixin hook-inverse-totop-active(){} diff --git a/docs/_sass/uikit/components/transition.scss b/docs/_sass/uikit/components/transition.scss deleted file mode 100644 index abcf794e15..0000000000 --- a/docs/_sass/uikit/components/transition.scss +++ /dev/null @@ -1,157 +0,0 @@ -// Name: Transition -// Description: Utilities for transitions -// -// Component: `uk-transition-*` -// -// Modifiers: `uk-transition-fade` -// `uk-transition-scale-up` -// `uk-transition-scale-down` -// `uk-transition-slide-top-*` -// `uk-transition-slide-bottom-*` -// `uk-transition-slide-left-*` -// `uk-transition-slide-right-*` -// `uk-transition-opaque` -// `uk-transition-slow` -// -// Sub-objects: `uk-transition-toggle`, -// `uk-transition-active` -// -// States: `uk-active` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$transition-duration: 0.3s !default; - -$transition-scale: 1.03 !default; - -$transition-slide-small-translate: 10px !default; -$transition-slide-medium-translate: 50px !default; - -$transition-slow-duration: 0.7s !default; - - -/* ======================================================================== - Component: Transition - ========================================================================== */ - - -/* Toggle (Hover + Focus) - ========================================================================== */ - -/* - * 1. Prevent tab highlighting on iOS. - */ - -.uk-transition-toggle { - /* 1 */ - -webkit-tap-highlight-color: transparent; -} - -/* - * Remove outline for `tabindex` - */ - -.uk-transition-toggle:focus { outline: none; } - - -/* Transitions - ========================================================================== */ - -/* - * The toggle is triggered on touch devices by two methods: - * 1. Using `:focus` and tabindex - * 2. Using `:hover` and a `touchstart` event listener registered on the document - * (Doesn't work on Surface touch devices) - * - * Note: Transitions don't work with `uk-postion-center-*` classes because they also use `transform`, - * therefore it's recommended to use an extra `div` for the transition. - */ - -.uk-transition-fade, -[class*='uk-transition-scale'], -[class*='uk-transition-slide'] { - transition: $transition-duration ease-out; - transition-property: opacity, transform, filter; - opacity: 0; -} - -/* - * Fade - */ - -.uk-transition-toggle:hover .uk-transition-fade, -.uk-transition-toggle:focus .uk-transition-fade, -.uk-transition-active.uk-active .uk-transition-fade { opacity: 1; } - -/* - * Scale - */ - -.uk-transition-scale-up { transform: scale(1,1); } -.uk-transition-scale-down { transform: scale($transition-scale,$transition-scale); } - -/* Show */ -.uk-transition-toggle:hover .uk-transition-scale-up, -.uk-transition-toggle:focus .uk-transition-scale-up, -.uk-transition-active.uk-active .uk-transition-scale-up { - opacity: 1; - transform: scale($transition-scale,$transition-scale); -} - -.uk-transition-toggle:hover .uk-transition-scale-down, -.uk-transition-toggle:focus .uk-transition-scale-down, -.uk-transition-active.uk-active .uk-transition-scale-down { - opacity: 1; - transform: scale(1,1); -} - -/* - * Slide - */ - -.uk-transition-slide-top { transform: translateY(-100%); } -.uk-transition-slide-bottom { transform: translateY(100%); } -.uk-transition-slide-left { transform: translateX(-100%); } -.uk-transition-slide-right { transform: translateX(100%); } - -.uk-transition-slide-top-small { transform: translateY(-$transition-slide-small-translate); } -.uk-transition-slide-bottom-small { transform: translateY($transition-slide-small-translate); } -.uk-transition-slide-left-small { transform: translateX(-$transition-slide-small-translate); } -.uk-transition-slide-right-small { transform: translateX($transition-slide-small-translate); } - -.uk-transition-slide-top-medium { transform: translateY(-$transition-slide-medium-translate); } -.uk-transition-slide-bottom-medium { transform: translateY($transition-slide-medium-translate); } -.uk-transition-slide-left-medium { transform: translateX(-$transition-slide-medium-translate); } -.uk-transition-slide-right-medium { transform: translateX($transition-slide-medium-translate); } - -/* Show */ -.uk-transition-toggle:hover [class*='uk-transition-slide'], -.uk-transition-toggle:focus [class*='uk-transition-slide'], -.uk-transition-active.uk-active [class*='uk-transition-slide'] { - opacity: 1; - transform: translate(0,0); -} - - -/* Opacity modifier - ========================================================================== */ - -.uk-transition-opaque { opacity: 1; } - - -/* Duration modifiers - ========================================================================== */ - -.uk-transition-slow { transition-duration: $transition-slow-duration; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-transition-misc)) {@include hook-transition-misc();} - -// @mixin hook-transition-misc(){} diff --git a/docs/_sass/uikit/components/utility.scss b/docs/_sass/uikit/components/utility.scss deleted file mode 100644 index beb55562b2..0000000000 --- a/docs/_sass/uikit/components/utility.scss +++ /dev/null @@ -1,482 +0,0 @@ -// Name: Utility -// Description: Utilities collection -// -// Component: `uk-panel-*` -// `uk-clearfix` -// `uk-float-*` -// `uk-overflow-*` -// `uk-resize-*` -// `uk-display-*` -// `uk-inline-*` -// `uk-responsive-*` -// `uk-preserve-width` -// `uk-border-*` -// `uk-box-shadow-*` -// `uk-box-shadow-bottom` -// `uk-dropcap` -// `uk-logo` -// `uk-blend-*` -// `uk-transform-*` -// `uk-transform-origin-*` -// -// States: `uk-disabled` -// `uk-drag` -// `uk-dragover` -// `uk-preserve` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$panel-scrollable-height: 170px !default; -$panel-scrollable-padding: 10px !default; -$panel-scrollable-border-width: $global-border-width !default; -$panel-scrollable-border: $global-border !default; - -$border-rounded-border-radius: 5px !default; - -$box-shadow-duration: 0.1s !default; - -$box-shadow-bottom-height: 30px !default; -$box-shadow-bottom-border-radius: 100% !default; -$box-shadow-bottom-background: #444 !default; -$box-shadow-bottom-blur: 20px !default; - -$dropcap-margin-right: 10px !default; -$dropcap-font-size: (($global-line-height * 3) * 1em) !default; - -$logo-font-size: $global-large-font-size !default; -$logo-font-family: $global-font-family !default; -$logo-color: $global-color !default; -$logo-hover-color: $global-color !default; - -$dragover-box-shadow: 0 0 20px rgba(100,100,100,0.3) !default; - - -/* ======================================================================== - Component: Utility - ========================================================================== */ - - -/* Panel - ========================================================================== */ - -.uk-panel { - display: flow-root; - position: relative; - box-sizing: border-box; -} - -/* - * Remove margin from the last-child - */ - -.uk-panel > :last-child { margin-bottom: 0; } - - -/* - * Scrollable - */ - -.uk-panel-scrollable { - height: $panel-scrollable-height; - padding: $panel-scrollable-padding; - border: $panel-scrollable-border-width solid $panel-scrollable-border; - overflow: auto; - -webkit-overflow-scrolling: touch; - resize: both; - @if(mixin-exists(hook-panel-scrollable)) {@include hook-panel-scrollable();} -} - - -/* Clearfix - ========================================================================== */ - -/* - * 1. `table-cell` is used with `::before` because `table` creates a 1px gap when it becomes a flex item, only in Webkit - * 2. `table` is used again with `::after` because `clear` only works with block elements. - * Note: `display: block` with `overflow: hidden` is currently not working in the latest Safari - */ - -/* 1 */ -.uk-clearfix::before { - content: ""; - display: table-cell; -} - -/* 2 */ -.uk-clearfix::after { - content: ""; - display: table; - clear: both; -} - - -/* Float - ========================================================================== */ - -/* - * 1. Prevent content overflow - */ - -.uk-float-left { float: left; } -.uk-float-right { float: right; } - -/* 1 */ -[class*='uk-float-'] { max-width: 100%; } - - -/* Overfow - ========================================================================== */ - -.uk-overflow-hidden { overflow: hidden; } - -/* - * Enable scrollbars if content is clipped - * Note: Firefox ignores `padding-bottom` for the scrollable overflow https://bugzilla.mozilla.org/show_bug.cgi?id=748518 - */ - -.uk-overflow-auto { - overflow: auto; - -webkit-overflow-scrolling: touch; -} - -.uk-overflow-auto > :last-child { margin-bottom: 0; } - - -/* Resize - ========================================================================== */ - -.uk-resize { resize: both; } -.uk-resize-vertical { resize: vertical; } - - -/* Display - ========================================================================== */ - -.uk-display-block { display: block !important; } -.uk-display-inline { display: inline !important; } -.uk-display-inline-block { display: inline-block !important; } - - -/* Inline - ========================================================================== */ - -/* - * 1. Container fits its content - * 2. Create position context - * 3. Prevent content overflow - * 4. Behave like most inline-block elements - * 5. Force new layer without creating a new stacking context - * to fix 1px glitch when combined with overlays and transitions in Webkit - * 6. Clip child elements - */ - -[class*='uk-inline'] { - /* 1 */ - display: inline-block; - /* 2 */ - position: relative; - /* 3 */ - max-width: 100%; - /* 4 */ - vertical-align: middle; - /* 5 */ - -webkit-backface-visibility: hidden; -} - -.uk-inline-clip { - /* 6 */ - overflow: hidden; -} - - -/* Responsive objects - ========================================================================== */ - -/* - * Preserve original dimensions - * Because `img, `video`, `canvas` and `audio` are already responsive by default, see Base component - */ - -.uk-preserve-width, -.uk-preserve-width canvas, -.uk-preserve-width img, -.uk-preserve-width svg, -.uk-preserve-width video { max-width: none; } - -/* - * Responsiveness - * Corrects `max-width` and `max-height` behavior if padding and border are used - */ - -.uk-responsive-width, -.uk-responsive-height { box-sizing: border-box; } - -/* - * 1. Set a maximum width. `important` needed to override `uk-preserve-width img` - * 2. Auto scale the height. Only needed if `height` attribute is present - */ - -.uk-responsive-width { - /* 1 */ - max-width: 100% !important; - /* 2 */ - height: auto; -} - -/* - * 1. Set a maximum height. Only works if the parent element has a fixed height - * 2. Auto scale the width. Only needed if `width` attribute is present - * 3. Reset max-width, which `img, `video`, `canvas` and `audio` already have by default - */ - -.uk-responsive-height { - /* 1 */ - max-height: 100%; - /* 2 */ - width: auto; - /* 3 */ - max-width: none; -} - - -/* Border - ========================================================================== */ - -.uk-border-circle { border-radius: 50%; } -.uk-border-pill { border-radius: 500px; } -.uk-border-rounded { border-radius: $border-rounded-border-radius; } - -/* - * Fix `overflow: hidden` to be ignored with border-radius and CSS transforms in Webkit - */ - -.uk-inline-clip[class*='uk-border-'] { -webkit-transform: translateZ(0); } - - -/* Box-shadow - ========================================================================== */ - -.uk-box-shadow-small { box-shadow: $global-small-box-shadow; } -.uk-box-shadow-medium { box-shadow: $global-medium-box-shadow; } -.uk-box-shadow-large { box-shadow: $global-large-box-shadow; } -.uk-box-shadow-xlarge { box-shadow: $global-xlarge-box-shadow; } - -/* - * Hover - */ - -[class*='uk-box-shadow-hover'] { transition: box-shadow $box-shadow-duration ease-in-out; } - -.uk-box-shadow-hover-small:hover { box-shadow: $global-small-box-shadow; } -.uk-box-shadow-hover-medium:hover { box-shadow: $global-medium-box-shadow; } -.uk-box-shadow-hover-large:hover { box-shadow: $global-large-box-shadow; } -.uk-box-shadow-hover-xlarge:hover { box-shadow: $global-xlarge-box-shadow; } - - -/* Box-shadow bottom - ========================================================================== */ - -/* - * 1. Set position. - * 2. Set style - * 3. Fix shadow being clipped in Safari if container is animated - */ - -@supports (filter: blur(0)) { - - .uk-box-shadow-bottom { - display: inline-block; - position: relative; - z-index: 0; - max-width: 100%; - vertical-align: middle; - } - - .uk-box-shadow-bottom::after { - content: ''; - /* 1 */ - position: absolute; - bottom: (-$box-shadow-bottom-height); - left: 0; - right: 0; - z-index: -1; - /* 2 */ - height: $box-shadow-bottom-height; - border-radius: $box-shadow-bottom-border-radius; - background: $box-shadow-bottom-background; - filter: blur($box-shadow-bottom-blur); - /* 3 */ - will-change: filter; - @if(mixin-exists(hook-box-shadow-bottom)) {@include hook-box-shadow-bottom();} - } - -} - - -/* Drop cap - ========================================================================== */ - -/* - * 1. Firefox doesn't apply `::first-letter` if the first letter is inside child elements - * https://bugzilla.mozilla.org/show_bug.cgi?id=214004 - * 2. In Firefox, a floating `::first-letter` doesn't have a line box and there for no `line-height` - * https://bugzilla.mozilla.org/show_bug.cgi?id=317933 - * 3. Caused by 1.: Edge creates two nested `::first-letter` containers, one for each selector - * This doubles the `font-size` exponential when using the `em` unit. - */ - -.uk-dropcap::first-letter, -/* 1 */ -.uk-dropcap > p:first-of-type::first-letter { - display: block; - margin-right: $dropcap-margin-right; - float: left; - font-size: $dropcap-font-size; - line-height: 1; - @if(mixin-exists(hook-dropcap)) {@include hook-dropcap();} -} - -/* 2 */ -@-moz-document url-prefix() { - - .uk-dropcap::first-letter, - .uk-dropcap > p:first-of-type::first-letter { margin-top: 1.1%; } - -} - -/* 3 */ -@supports (-ms-ime-align: auto) { - - .uk-dropcap > p:first-of-type::first-letter { font-size: 1em; } - -} - - -/* Logo - ========================================================================== */ - -/* - * 1. Required for `a` - */ - -.uk-logo { - font-size: $logo-font-size; - font-family: $logo-font-family; - color: $logo-color; - /* 1 */ - text-decoration: none; - @if(mixin-exists(hook-logo)) {@include hook-logo();} -} - -/* Hover + Focus */ -.uk-logo:hover, -.uk-logo:focus { - color: $logo-hover-color; - outline: none; - /* 1 */ - text-decoration: none; - @if(mixin-exists(hook-logo-hover)) {@include hook-logo-hover();} -} - -.uk-logo-inverse { display: none; } - - -/* Disabled State - ========================================================================== */ - -.uk-disabled { pointer-events: none; } - - -/* Drag State - ========================================================================== */ - -/* - * 1. Needed if moving over elements with have their own cursor on hover, e.g. links or buttons - * 2. Fix dragging over iframes - */ - -.uk-drag, -/* 1 */ -.uk-drag * { cursor: move; } - -/* 2 */ -.uk-drag iframe { pointer-events: none; } - - -/* Dragover State - ========================================================================== */ - -/* - * Create a box-shadow when dragging a file over the upload area - */ - -.uk-dragover { box-shadow: $dragover-box-shadow; } - - -/* Blend modes - ========================================================================== */ - -.uk-blend-multiply { mix-blend-mode: multiply; } -.uk-blend-screen { mix-blend-mode: screen; } -.uk-blend-overlay { mix-blend-mode: overlay; } -.uk-blend-darken { mix-blend-mode: darken; } -.uk-blend-lighten { mix-blend-mode: lighten; } -.uk-blend-color-dodge { mix-blend-mode: color-dodge; } -.uk-blend-color-burn { mix-blend-mode: color-burn; } -.uk-blend-hard-light { mix-blend-mode: hard-light; } -.uk-blend-soft-light { mix-blend-mode: soft-light; } -.uk-blend-difference { mix-blend-mode: difference; } -.uk-blend-exclusion { mix-blend-mode: exclusion; } -.uk-blend-hue { mix-blend-mode: hue; } -.uk-blend-saturation { mix-blend-mode: saturation; } -.uk-blend-color { mix-blend-mode: color; } -.uk-blend-luminosity { mix-blend-mode: luminosity; } - - -/* Transform -========================================================================== */ - -.uk-transform-center { transform: translate(-50%, -50%); } - - -/* Transform Origin -========================================================================== */ - -.uk-transform-origin-top-left { transform-origin: 0 0; } -.uk-transform-origin-top-center { transform-origin: 50% 0; } -.uk-transform-origin-top-right { transform-origin: 100% 0; } -.uk-transform-origin-center-left { transform-origin: 0 50%; } -.uk-transform-origin-center-right { transform-origin: 100% 50%; } -.uk-transform-origin-bottom-left { transform-origin: 0 100%; } -.uk-transform-origin-bottom-center { transform-origin: 50% 100%; } -.uk-transform-origin-bottom-right { transform-origin: 100% 100%; } - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-utility-misc)) {@include hook-utility-misc();} - -// @mixin hook-panel-scrollable(){} -// @mixin hook-box-shadow-bottom(){} -// @mixin hook-dropcap(){} -// @mixin hook-logo(){} -// @mixin hook-logo-hover(){} -// @mixin hook-utility-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-logo-color: $inverse-global-color !default; -$inverse-logo-hover-color: $inverse-global-color !default; - - - -// @mixin hook-inverse-dropcap(){} -// @mixin hook-inverse-logo(){} -// @mixin hook-inverse-logo-hover(){} diff --git a/docs/_sass/uikit/components/variables.scss b/docs/_sass/uikit/components/variables.scss deleted file mode 100644 index 0d3b304e70..0000000000 --- a/docs/_sass/uikit/components/variables.scss +++ /dev/null @@ -1,123 +0,0 @@ -// -// Component: Variables -// Description: Defines common values which are used across all components -// -// ======================================================================== - - -// Load deprecated components -// ======================================================================== - -$deprecated: false !default; - - -// Breakpoints -// ======================================================================== - -// Phone Portrait: Galaxy (360x640), iPhone 6 (375x667), iPhone 6+ (414x736) -// Phone Landscape: Galaxy (640x360), iPhone 6 (667x375), iPhone 6+ (736x414) -// Tablet Portrait: iPad (768x1024), Galaxy Tab (800x1280), -// Tablet Landscape: iPad (1024x768), iPad Pro (1024x1366), -// Desktop: Galaxy Tab (1280x800), iPad Pro (1366x1024) - -$breakpoint-small: 640px !default; // Phone landscape -$breakpoint-medium: 960px !default; // Tablet Landscape -$breakpoint-large: 1200px !default; // Desktop -$breakpoint-xlarge: 1600px !default; // Large Screens - -$breakpoint-xsmall-max: ($breakpoint-small - 1) !default; -$breakpoint-small-max: ($breakpoint-medium - 1) !default; -$breakpoint-medium-max: ($breakpoint-large - 1) !default; -$breakpoint-large-max: ($breakpoint-xlarge - 1) !default; - - -// Global variables -// ======================================================================== - -// -// Typography -// - -$global-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; -$global-font-size: 16px !default; -$global-line-height: 1.5 !default; // 24px - -$global-2xlarge-font-size: 2.625rem !default; // 42px -$global-xlarge-font-size: 2rem !default; // 32px -$global-large-font-size: 1.5rem !default; // 24px -$global-medium-font-size: 1.25rem !default; // 20px -$global-small-font-size: 0.875rem !default; // 14px - -// -// Colors -// - -$global-color: #666 !default; -$global-emphasis-color: #333 !default; -$global-muted-color: #999 !default; - -$global-link-color: #1e87f0 !default; -$global-link-hover-color: #0f6ecd !default; - -$global-inverse-color: #fff !default; - -// -// Backgrounds -// - -$global-background: #fff !default; - -$global-muted-background: #f8f8f8 !default; -$global-primary-background: #1e87f0 !default; -$global-secondary-background: #222 !default; - -$global-success-background: #32d296 !default; -$global-warning-background: #faa05a !default; -$global-danger-background: #f0506e !default; - -// -// Borders -// - -$global-border-width: 1px !default; -$global-border: #e5e5e5 !default; - -// -// Box-Shadows -// - -$global-small-box-shadow: 0 2px 8px rgba(0,0,0,0.08) !default; -$global-medium-box-shadow: 0 5px 15px rgba(0,0,0,0.08) !default; -$global-large-box-shadow: 0 14px 25px rgba(0,0,0,0.16) !default; -$global-xlarge-box-shadow: 0 28px 50px rgba(0,0,0,0.16) !default; - -// -// Spacings -// - -// Used in margin, section, list -$global-margin: 20px !default; -$global-small-margin: 10px !default; -$global-medium-margin: 40px !default; -$global-large-margin: 70px !default; -$global-xlarge-margin: 140px !default; - -// Used in grid, column, container, align, card, padding -$global-gutter: 30px !default; -$global-small-gutter: 15px !default; -$global-medium-gutter: 40px !default; -$global-large-gutter: 70px !default; - -// -// Controls -// - -$global-control-height: 40px !default; -$global-control-small-height: 30px !default; -$global-control-large-height: 55px !default; - -// -// Z-index -// - -$global-z-index: 1000 !default; diff --git a/docs/_sass/uikit/components/visibility.scss b/docs/_sass/uikit/components/visibility.scss deleted file mode 100644 index 376af51639..0000000000 --- a/docs/_sass/uikit/components/visibility.scss +++ /dev/null @@ -1,175 +0,0 @@ -// Name: Visibility -// Description: Utilities to show or hide content on breakpoints, hover or touch -// -// Component: `uk-hidden-*` -// `uk-visible-*` -// `uk-invisible` -// `uk-visible-toggle` -// `uk-hidden-hover` -// `uk-invisible-hover` -// `uk-hidden-touch` -// `uk-hidden-notouch` -// -// ======================================================================== - - -/* ======================================================================== - Component: Visibility - ========================================================================== */ - -/* - * Hidden - * `hidden` attribute also set here to make it stronger - */ - -[hidden], -.uk-hidden { display: none !important; } - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-hidden\@s { display: none !important; } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-hidden\@m { display: none !important; } - -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-hidden\@l { display: none !important; } - -} - -/* Large screen and bigger */ -@media (min-width: $breakpoint-xlarge) { - - .uk-hidden\@xl { display: none !important; } - -} - -/* - * Visible - */ - -/* Phone portrait and smaller */ -@media (max-width: $breakpoint-xsmall-max) { - - .uk-visible\@s { display: none !important; } - -} - -/* Phone landscape and smaller */ -@media (max-width: $breakpoint-small-max) { - - .uk-visible\@m { display: none !important; } - -} - -/* Tablet landscape and smaller */ -@media (max-width: $breakpoint-medium-max) { - - .uk-visible\@l { display: none !important; } - -} - -/* Desktop and smaller */ -@media (max-width: $breakpoint-large-max) { - - .uk-visible\@xl { display: none !important; } - -} - - -/* Visibility - ========================================================================== */ - -.uk-invisible { visibility: hidden !important; } - - -/* Toggle (Hover + Focus) - ========================================================================== */ - -/* - * Hidden - * 1. The toggle is triggered on touch devices using `:focus` and tabindex - * 2. The target stays visible if any element within receives focus through keyboard - * Doesn't work in Edge, yet. - * 3. Can't use `display: none` nor `visibility: hidden` because both are not focusable. - * - */ - -/* 1 + 2 */ -.uk-visible-toggle:not(:hover):not(:focus) .uk-hidden-hover:not(:focus-within) { - /* 3 */ - position: absolute !important; - width: 0 !important; - height: 0 !important; - padding: 0 !important; - margin: 0 !important; - overflow: hidden !important; -} - -/* - * Invisible - */ - -/* 1 + 2 */ -.uk-visible-toggle:not(:hover):not(:focus) .uk-invisible-hover:not(:focus-within) { - /* 3 */ - opacity: 0 !important; -} - -/* - * 1. Prevent tab highlighting on iOS. - */ - -.uk-visible-toggle { - /* 1 */ - -webkit-tap-highlight-color: transparent; -} - -/* - * Remove outline for `tabindex` - */ - -.uk-visible-toggle:focus { outline: none; } - - -/* Touch - ========================================================================== */ - -/* - * Hide if primary pointing device has limited accuracy, e.g. a touch screen. - * Works on mobile browsers: Safari, Chrome and Android browser - */ - -@media (pointer: coarse) { - .uk-hidden-touch { display: none !important; } -} - -/* - * Hide if primary pointing device is accurate, e.g. mouse. - * 1. Fallback for IE11 and Firefox, because `pointer` is not supported - * 2. Reset if supported - */ - -/* 1 */ -.uk-hidden-notouch { display: none !important; } - -@media (pointer: coarse) { - .uk-hidden-notouch { display: block !important; } -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-visibility-misc)) {@include hook-visibility-misc();} - -// @mixin hook-visibility-misc(){} diff --git a/docs/_sass/uikit/components/width.scss b/docs/_sass/uikit/components/width.scss deleted file mode 100644 index 30b873da00..0000000000 --- a/docs/_sass/uikit/components/width.scss +++ /dev/null @@ -1,379 +0,0 @@ -// Name: Width -// Description: Utilities for widths -// -// Component: `uk-child-width-*` -// `uk-width-*` -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$width-small-width: 150px !default; -$width-medium-width: 300px !default; -$width-large-width: 450px !default; -$width-xlarge-width: 600px !default; -$width-2xlarge-width: 750px !default; - - -/* ======================================================================== - Component: Width - ========================================================================== */ - - -/* Equal child widths - ========================================================================== */ - -[class*='uk-child-width'] > * { - box-sizing: border-box; - width: 100%; -} - -.uk-child-width-1-2 > * { width: 50%; } -.uk-child-width-1-3 > * { width: unquote('calc(100% * 1 / 3.001)'); } -.uk-child-width-1-4 > * { width: 25%; } -.uk-child-width-1-5 > * { width: 20%; } -.uk-child-width-1-6 > * { width: unquote('calc(100% * 1 / 6.001)'); } - -.uk-child-width-auto > * { width: auto; } - -/* - * 1. Reset the `min-width`, which is set to auto by default, because - * flex items won't shrink below their minimum intrinsic content size. - * Using `1px` instead of `0`, so items still wrap into the next line, - * if they have zero width and padding and the predecessor is 100% wide. - */ - -.uk-child-width-expand > :not([class*='uk-width']) { - flex: 1; - /* 1 */ - min-width: 1px; -} - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - .uk-child-width-1-1\@s > * { width: 100%; } - .uk-child-width-1-2\@s > * { width: 50%; } - .uk-child-width-1-3\@s > * { width: unquote('calc(100% * 1 / 3.001)'); } - .uk-child-width-1-4\@s > * { width: 25%; } - .uk-child-width-1-5\@s > * { width: 20%; } - .uk-child-width-1-6\@s > * { width: unquote('calc(100% * 1 / 6.001)'); } - - .uk-child-width-auto\@s > * { width: auto; } - .uk-child-width-expand\@s > :not([class*='uk-width']) { - flex: 1; - min-width: 1px; - } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - .uk-child-width-1-1\@m > * { width: 100%; } - .uk-child-width-1-2\@m > * { width: 50%; } - .uk-child-width-1-3\@m > * { width: unquote('calc(100% * 1 / 3.001)'); } - .uk-child-width-1-4\@m > * { width: 25%; } - .uk-child-width-1-5\@m > * { width: 20%; } - .uk-child-width-1-6\@m > * { width: unquote('calc(100% * 1 / 6.001)'); } - - .uk-child-width-auto\@m > * { width: auto; } - .uk-child-width-expand\@m > :not([class*='uk-width']) { - flex: 1; - min-width: 1px; - } - -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - .uk-child-width-1-1\@l > * { width: 100%; } - .uk-child-width-1-2\@l > * { width: 50%; } - .uk-child-width-1-3\@l > * { width: unquote('calc(100% * 1 / 3.001)'); } - .uk-child-width-1-4\@l > * { width: 25%; } - .uk-child-width-1-5\@l > * { width: 20%; } - .uk-child-width-1-6\@l > * { width: unquote('calc(100% * 1 / 6.001)'); } - - .uk-child-width-auto\@l > * { width: auto; } - .uk-child-width-expand\@l > :not([class*='uk-width']) { - flex: 1; - min-width: 1px; - } - -} - -/* Large screen and bigger */ -@media (min-width: $breakpoint-xlarge) { - - .uk-child-width-1-1\@xl > * { width: 100%; } - .uk-child-width-1-2\@xl > * { width: 50%; } - .uk-child-width-1-3\@xl > * { width: unquote('calc(100% * 1 / 3.001)'); } - .uk-child-width-1-4\@xl > * { width: 25%; } - .uk-child-width-1-5\@xl > * { width: 20%; } - .uk-child-width-1-6\@xl > * { width: unquote('calc(100% * 1 / 6.001)'); } - - .uk-child-width-auto\@xl > * { width: auto; } - .uk-child-width-expand\@xl > :not([class*='uk-width']) { - flex: 1; - min-width: 1px; - } - -} - - -/* Single Widths - ========================================================================== */ - -/* - * 1. `max-width` is needed for the pixel-based classes - */ - -[class*='uk-width'] { - box-sizing: border-box; - width: 100%; - /* 1 */ - max-width: 100%; -} - -/* Halves */ -.uk-width-1-2 { width: 50%; } - -/* Thirds */ -.uk-width-1-3 { width: unquote('calc(100% * 1 / 3.001)'); } -.uk-width-2-3 { width: unquote('calc(100% * 2 / 3.001)'); } - -/* Quarters */ -.uk-width-1-4 { width: 25%; } -.uk-width-3-4 { width: 75%; } - -/* Fifths */ -.uk-width-1-5 { width: 20%; } -.uk-width-2-5 { width: 40%; } -.uk-width-3-5 { width: 60%; } -.uk-width-4-5 { width: 80%; } - -/* Sixths */ -.uk-width-1-6 { width: unquote('calc(100% * 1 / 6.001)'); } -.uk-width-5-6 { width: unquote('calc(100% * 5 / 6.001)'); } - -/* Pixel */ -.uk-width-small { width: $width-small-width; } -.uk-width-medium { width: $width-medium-width; } -.uk-width-large { width: $width-large-width; } -.uk-width-xlarge { width: $width-xlarge-width; } -.uk-width-2xlarge { width: $width-2xlarge-width; } -@if ($deprecated == true) { -.uk-width-xxlarge { width: $width-2xlarge-width; } -} - -/* Auto */ -.uk-width-auto { width: auto; } - -/* Expand */ -.uk-width-expand { - flex: 1; - min-width: 1px; -} - -/* Phone landscape and bigger */ -@media (min-width: $breakpoint-small) { - - /* Whole */ - .uk-width-1-1\@s { width: 100%; } - - /* Halves */ - .uk-width-1-2\@s { width: 50%; } - - /* Thirds */ - .uk-width-1-3\@s { width: unquote('calc(100% * 1 / 3.001)'); } - .uk-width-2-3\@s { width: unquote('calc(100% * 2 / 3.001)'); } - - /* Quarters */ - .uk-width-1-4\@s { width: 25%; } - .uk-width-3-4\@s { width: 75%; } - - /* Fifths */ - .uk-width-1-5\@s { width: 20%; } - .uk-width-2-5\@s { width: 40%; } - .uk-width-3-5\@s { width: 60%; } - .uk-width-4-5\@s { width: 80%; } - - /* Sixths */ - .uk-width-1-6\@s { width: unquote('calc(100% * 1 / 6.001)'); } - .uk-width-5-6\@s { width: unquote('calc(100% * 5 / 6.001)'); } - - /* Pixel */ - .uk-width-small\@s { width: $width-small-width; } - .uk-width-medium\@s { width: $width-medium-width; } - .uk-width-large\@s { width: $width-large-width; } - .uk-width-xlarge\@s { width: $width-xlarge-width; } - .uk-width-2xlarge\@s { width: $width-2xlarge-width; } - @if ($deprecated == true) { -.uk-width-xxlarge\@s { width: $width-2xlarge-width; } -} - - /* Auto */ - .uk-width-auto\@s { width: auto; } - - /* Expand */ - .uk-width-expand\@s { - flex: 1; - min-width: 1px; - } - -} - -/* Tablet landscape and bigger */ -@media (min-width: $breakpoint-medium) { - - /* Whole */ - .uk-width-1-1\@m { width: 100%; } - - /* Halves */ - .uk-width-1-2\@m { width: 50%; } - - /* Thirds */ - .uk-width-1-3\@m { width: unquote('calc(100% * 1 / 3.001)'); } - .uk-width-2-3\@m { width: unquote('calc(100% * 2 / 3.001)'); } - - /* Quarters */ - .uk-width-1-4\@m { width: 25%; } - .uk-width-3-4\@m { width: 75%; } - - /* Fifths */ - .uk-width-1-5\@m { width: 20%; } - .uk-width-2-5\@m { width: 40%; } - .uk-width-3-5\@m { width: 60%; } - .uk-width-4-5\@m { width: 80%; } - - /* Sixths */ - .uk-width-1-6\@m { width: unquote('calc(100% * 1 / 6.001)'); } - .uk-width-5-6\@m { width: unquote('calc(100% * 5 / 6.001)'); } - - /* Pixel */ - .uk-width-small\@m { width: $width-small-width; } - .uk-width-medium\@m { width: $width-medium-width; } - .uk-width-large\@m { width: $width-large-width; } - .uk-width-xlarge\@m { width: $width-xlarge-width; } - .uk-width-2xlarge\@m { width: $width-2xlarge-width; } - @if ($deprecated == true) { -.uk-width-xxlarge\@m { width: $width-2xlarge-width; } -} - - /* Auto */ - .uk-width-auto\@m { width: auto; } - - /* Expand */ - .uk-width-expand\@m { - flex: 1; - min-width: 1px; - } - -} - -/* Desktop and bigger */ -@media (min-width: $breakpoint-large) { - - /* Whole */ - .uk-width-1-1\@l { width: 100%; } - - /* Halves */ - .uk-width-1-2\@l { width: 50%; } - - /* Thirds */ - .uk-width-1-3\@l { width: unquote('calc(100% * 1 / 3.001)'); } - .uk-width-2-3\@l { width: unquote('calc(100% * 2 / 3.001)'); } - - /* Quarters */ - .uk-width-1-4\@l { width: 25%; } - .uk-width-3-4\@l { width: 75%; } - - /* Fifths */ - .uk-width-1-5\@l { width: 20%; } - .uk-width-2-5\@l { width: 40%; } - .uk-width-3-5\@l { width: 60%; } - .uk-width-4-5\@l { width: 80%; } - - /* Sixths */ - .uk-width-1-6\@l { width: unquote('calc(100% * 1 / 6.001)'); } - .uk-width-5-6\@l { width: unquote('calc(100% * 5 / 6.001)'); } - - /* Pixel */ - .uk-width-small\@l { width: $width-small-width; } - .uk-width-medium\@l { width: $width-medium-width; } - .uk-width-large\@l { width: $width-large-width; } - .uk-width-xlarge\@l { width: $width-xlarge-width; } - .uk-width-2xlarge\@l { width: $width-2xlarge-width; } - @if ($deprecated == true) { -.uk-width-xxlarge\@l { width: $width-2xlarge-width; } -} - - /* Auto */ - .uk-width-auto\@l { width: auto; } - - /* Expand */ - .uk-width-expand\@l { - flex: 1; - min-width: 1px; - } - -} - -/* Large screen and bigger */ -@media (min-width: $breakpoint-xlarge) { - - /* Whole */ - .uk-width-1-1\@xl { width: 100%; } - - /* Halves */ - .uk-width-1-2\@xl { width: 50%; } - - /* Thirds */ - .uk-width-1-3\@xl { width: unquote('calc(100% * 1 / 3.001)'); } - .uk-width-2-3\@xl { width: unquote('calc(100% * 2 / 3.001)'); } - - /* Quarters */ - .uk-width-1-4\@xl { width: 25%; } - .uk-width-3-4\@xl { width: 75%; } - - /* Fifths */ - .uk-width-1-5\@xl { width: 20%; } - .uk-width-2-5\@xl { width: 40%; } - .uk-width-3-5\@xl { width: 60%; } - .uk-width-4-5\@xl { width: 80%; } - - /* Sixths */ - .uk-width-1-6\@xl { width: unquote('calc(100% * 1 / 6.001)'); } - .uk-width-5-6\@xl { width: unquote('calc(100% * 5 / 6.001)'); } - - /* Pixel */ - .uk-width-small\@xl { width: $width-small-width; } - .uk-width-medium\@xl { width: $width-medium-width; } - .uk-width-large\@xl { width: $width-large-width; } - .uk-width-xlarge\@xl { width: $width-xlarge-width; } - .uk-width-2xlarge\@xl { width: $width-2xlarge-width; } - @if ($deprecated == true) { -.uk-width-xxlarge\@xl { width: $width-2xlarge-width; } -} - - /* Auto */ - .uk-width-auto\@xl { width: auto; } - - /* Expand */ - .uk-width-expand\@xl { - flex: 1; - min-width: 1px; - } - -} - - -// Hooks -// ======================================================================== - -@if(mixin-exists(hook-width-misc)) {@include hook-width-misc();} - -// @mixin hook-width-misc(){} diff --git a/docs/_sass/uikit/mixins-theme.scss b/docs/_sass/uikit/mixins-theme.scss deleted file mode 100644 index 59826ca64f..0000000000 --- a/docs/_sass/uikit/mixins-theme.scss +++ /dev/null @@ -1,2204 +0,0 @@ -@mixin hook-accordion(){} -@mixin hook-accordion-item(){} -@mixin hook-accordion-title(){ - - overflow: hidden; - - &::before { - content: ""; - width: ($accordion-title-line-height * 1em); - height: ($accordion-title-line-height * 1em); - margin-left: $accordion-icon-margin-left; - float: right; - @include svg-fill($internal-accordion-close-image, "#000", $accordion-icon-color); - background-repeat: no-repeat; - background-position: 50% 50%; - } - - .uk-open > &::before { @include svg-fill($internal-accordion-open-image, "#000", $accordion-icon-color); } - -} -@mixin hook-accordion-title-hover(){} -@mixin hook-accordion-content(){} -@mixin hook-accordion-misc(){} -@mixin hook-inverse-accordion-item(){} -@mixin hook-inverse-accordion-title(){} -@mixin hook-inverse-accordion-title-hover(){} -@mixin hook-inverse-component-accordion(){ - - .uk-accordion-title::before { @include svg-fill($internal-accordion-close-image, "#000", $inverse-global-color); } - - .uk-open > .uk-accordion-title::before { @include svg-fill($internal-accordion-open-image, "#000", $inverse-global-color); } - -} -@mixin hook-alert(){} -@mixin hook-alert-close(){ - color: inherit; - opacity: $alert-close-opacity; -} -@mixin hook-alert-close-hover(){ - color: inherit; - opacity: $alert-close-hover-opacity; -} -@mixin hook-alert-primary(){} -@mixin hook-alert-success(){} -@mixin hook-alert-warning(){} -@mixin hook-alert-danger(){} -@mixin hook-alert-misc(){ - - /* - * Content - */ - - .uk-alert h1, - .uk-alert h2, - .uk-alert h3, - .uk-alert h4, - .uk-alert h5, - .uk-alert h6 { color: inherit; } - - .uk-alert a:not([class]) { - color: inherit; - text-decoration: underline; - } - - .uk-alert a:not([class]):hover { - color: inherit; - text-decoration: underline; - } - -} -@mixin hook-align-misc(){} -@mixin hook-animation-misc(){} -@mixin hook-article(){} -@mixin hook-article-adjacent(){} -@mixin hook-article-title(){} -@mixin hook-article-meta(){ - - a { color: $article-meta-link-color; } - - a:hover { - color: $article-meta-link-hover-color; - text-decoration: none; - } - -} -@mixin hook-article-misc(){} -@mixin hook-inverse-article-title(){} -@mixin hook-inverse-article-meta(){} -@mixin hook-inverse-component-article(){ - - .uk-article-title { - @if(mixin-exists(hook-inverse-article-title)) {@include hook-inverse-article-title();} - } - - .uk-article-meta { - color: $inverse-article-meta-color; - @if(mixin-exists(hook-inverse-article-meta)) {@include hook-inverse-article-meta();} - } - -} -@mixin hook-background-misc(){} -@mixin hook-badge(){} -@mixin hook-badge-hover(){} -@mixin hook-badge-misc(){} -@mixin hook-inverse-badge(){} -@mixin hook-inverse-badge-hover(){} -@mixin hook-inverse-component-badge(){ - - .uk-badge { - background-color: $inverse-badge-background; - color: $inverse-badge-color !important; - @if(mixin-exists(hook-inverse-badge)) {@include hook-inverse-badge();} - } - - .uk-badge:hover, - .uk-badge:focus { - @if(mixin-exists(hook-inverse-badge-hover)) {@include hook-inverse-badge-hover();} - } - -} -@mixin hook-base-body(){} -@mixin hook-base-link(){} -@mixin hook-base-link-hover(){} -@mixin hook-base-code(){ - padding: $base-code-padding-vertical $base-code-padding-horizontal; - background: $base-code-background; -} -@mixin hook-base-heading(){} -@mixin hook-base-h1(){} -@mixin hook-base-h2(){} -@mixin hook-base-h3(){} -@mixin hook-base-h4(){} -@mixin hook-base-h5(){} -@mixin hook-base-h6(){} -@mixin hook-base-hr(){} -@mixin hook-base-blockquote(){ - color: $base-blockquote-color; -} -@mixin hook-base-blockquote-footer(){ - - color: $base-blockquote-footer-color; - - &::before { content: "— "; } - -} -@mixin hook-base-pre(){ - padding: $base-pre-padding; - border: $base-pre-border-width solid $base-pre-border; - border-radius: $base-pre-border-radius; - background: $base-pre-background; -} -@mixin hook-base-misc(){} -@mixin hook-inverse-base-link(){} -@mixin hook-inverse-base-link-hover(){} -@mixin hook-inverse-base-code(){ - background: $inverse-global-muted-background; -} -@mixin hook-inverse-base-heading(){} -@mixin hook-inverse-base-h1(){} -@mixin hook-inverse-base-h2(){} -@mixin hook-inverse-base-h3(){} -@mixin hook-inverse-base-h4(){} -@mixin hook-inverse-base-h5(){} -@mixin hook-inverse-base-h6(){} -@mixin hook-inverse-base-blockquote(){ color: $inverse-base-blockquote-color; } -@mixin hook-inverse-base-blockquote-footer(){ color: $inverse-base-blockquote-footer-color; } -@mixin hook-inverse-base-hr(){} -@mixin hook-inverse-component-base(){ - - color: $inverse-base-color; - - // Base - // ======================================================================== - - // - // Link - // - - a, - .uk-link { - color: $inverse-base-link-color; - @if(mixin-exists(hook-inverse-base-link)) {@include hook-inverse-base-link();} - } - - a:hover, - .uk-link:hover, - .uk-link-toggle:hover .uk-link, - .uk-link-toggle:focus .uk-link { - color: $inverse-base-link-hover-color; - @if(mixin-exists(hook-inverse-base-link-hover)) {@include hook-inverse-base-link-hover();} - } - - // - // Code - // - - :not(pre) > code, - :not(pre) > kbd, - :not(pre) > samp { - color: $inverse-base-code-color; - @if(mixin-exists(hook-inverse-base-code)) {@include hook-inverse-base-code();} - } - - // - // Emphasize - // - - em { color: $inverse-base-em-color; } - - // - // Headings - // - - h1, .uk-h1, - h2, .uk-h2, - h3, .uk-h3, - h4, .uk-h4, - h5, .uk-h5, - h6, .uk-h6, - .uk-heading-small, - .uk-heading-medium, - .uk-heading-large, - .uk-heading-xlarge, - .uk-heading-2xlarge { - color: $inverse-base-heading-color; - @if(mixin-exists(hook-inverse-base-heading)) {@include hook-inverse-base-heading();} - } - - h1, .uk-h1 { - @if(mixin-exists(hook-inverse-base-h1)) {@include hook-inverse-base-h1();} - } - - h2, .uk-h2 { - @if(mixin-exists(hook-inverse-base-h2)) {@include hook-inverse-base-h2();} - } - - h3, .uk-h3 { - @if(mixin-exists(hook-inverse-base-h3)) {@include hook-inverse-base-h3();} - } - - h4, .uk-h4 { - @if(mixin-exists(hook-inverse-base-h4)) {@include hook-inverse-base-h4();} - } - - h5, .uk-h5 { - @if(mixin-exists(hook-inverse-base-h5)) {@include hook-inverse-base-h5();} - } - - h6, .uk-h6 { - @if(mixin-exists(hook-inverse-base-h6)) {@include hook-inverse-base-h6();} - } - - // - // Blockquotes - // - - blockquote { - @if(mixin-exists(hook-inverse-base-blockquote)) {@include hook-inverse-base-blockquote();} - } - - blockquote footer { - @if(mixin-exists(hook-inverse-base-blockquote-footer)) {@include hook-inverse-base-blockquote-footer();} - } - - // - // Horizontal rules - // - - hr, .uk-hr { - border-top-color: $inverse-base-hr-border; - @if(mixin-exists(hook-inverse-base-hr)) {@include hook-inverse-base-hr();} - } - -} -@mixin hook-breadcrumb(){} -@mixin hook-breadcrumb-item(){} -@mixin hook-breadcrumb-item-hover(){} -@mixin hook-breadcrumb-item-disabled(){} -@mixin hook-breadcrumb-item-active(){} -@mixin hook-breadcrumb-divider(){} -@mixin hook-breadcrumb-misc(){} -@mixin hook-inverse-breadcrumb-item(){} -@mixin hook-inverse-breadcrumb-item-hover(){} -@mixin hook-inverse-breadcrumb-item-disabled(){} -@mixin hook-inverse-breadcrumb-item-active(){} -@mixin hook-inverse-breadcrumb-divider(){} -@mixin hook-inverse-component-breadcrumb(){ - - .uk-breadcrumb > * > * { - color: $inverse-breadcrumb-item-color; - @if(mixin-exists(hook-inverse-breadcrumb-item)) {@include hook-inverse-breadcrumb-item();} - } - - .uk-breadcrumb > * > :hover, - .uk-breadcrumb > * > :focus { - color: $inverse-breadcrumb-item-hover-color; - @if(mixin-exists(hook-inverse-breadcrumb-item-hover)) {@include hook-inverse-breadcrumb-item-hover();} - } - - - .uk-breadcrumb > .uk-disabled > * { - @if(mixin-exists(hook-inverse-breadcrumb-item-disabled)) {@include hook-inverse-breadcrumb-item-disabled();} - } - - .uk-breadcrumb > :last-child > * { - color: $inverse-breadcrumb-item-active-color; - @if(mixin-exists(hook-inverse-breadcrumb-item-active)) {@include hook-inverse-breadcrumb-item-active();} - } - - // - // Divider - // - - .uk-breadcrumb > :nth-child(n+2):not(.uk-first-column)::before { - color: $inverse-breadcrumb-divider-color; - @if(mixin-exists(hook-inverse-breadcrumb-divider)) {@include hook-inverse-breadcrumb-divider();} - } - -} -@mixin hook-button(){ - text-transform: $button-text-transform; - transition: 0.1s ease-in-out; - transition-property: color, background-color, border-color; -} -@mixin hook-button-hover(){} -@mixin hook-button-focus(){} -@mixin hook-button-active(){} -@mixin hook-button-default(){ border: $button-border-width solid $button-default-border; } -@mixin hook-button-default-hover(){ border-color: $button-default-hover-border; } -@mixin hook-button-default-active(){ border-color: $button-default-active-border; } -@mixin hook-button-primary(){ border: $button-border-width solid transparent; } -@mixin hook-button-primary-hover(){} -@mixin hook-button-primary-active(){} -@mixin hook-button-secondary(){ border: $button-border-width solid transparent; } -@mixin hook-button-secondary-hover(){} -@mixin hook-button-secondary-active(){} -@mixin hook-button-danger(){ border: $button-border-width solid transparent; } -@mixin hook-button-danger-hover(){} -@mixin hook-button-danger-active(){} -@mixin hook-button-disabled(){ border-color: $button-disabled-border; } -@mixin hook-button-small(){} -@mixin hook-button-large(){} -@mixin hook-button-text(){ - - position: relative; - - &::before { - content: ""; - position: absolute; - bottom: 0; - left: 0; - right: 100%; - border-bottom: $button-text-border-width solid $button-text-border; - transition: right 0.3s ease-out; - } - -} -@mixin hook-button-text-hover(){ - - &::before { right: 0; } - -} -@mixin hook-button-text-disabled(){ - - &::before { display: none; } - -} -@mixin hook-button-link(){} -@mixin hook-button-misc(){ - - /* Group - ========================================================================== */ - - /* - * Collapse border - */ - - .uk-button-group > .uk-button:nth-child(n+2), - .uk-button-group > div:nth-child(n+2) .uk-button { margin-left: (-$button-border-width); } - - /* - * Create position context to superimpose the successor elements border - * Known issue: If you use an `a` element as button and an icon inside, - * the active state will not work if you click the icon inside the button - * Workaround: Just use a `button` or `input` element as button - */ - - .uk-button-group .uk-button:hover, - .uk-button-group .uk-button:focus, - .uk-button-group .uk-button:active, - .uk-button-group .uk-button.uk-active { - position: relative; - z-index: 1; - } - -} -@mixin hook-inverse-button-default(){ border-color: $inverse-global-color; } -@mixin hook-inverse-button-default-hover(){ border-color: $inverse-global-emphasis-color; } -@mixin hook-inverse-button-default-active(){ border-color: $inverse-global-emphasis-color; } -@mixin hook-inverse-button-primary(){} -@mixin hook-inverse-button-primary-hover(){} -@mixin hook-inverse-button-primary-active(){} -@mixin hook-inverse-button-secondary(){} -@mixin hook-inverse-button-secondary-hover(){} -@mixin hook-inverse-button-secondary-active(){} -@mixin hook-inverse-button-text(){ - &::before { border-bottom-color: $inverse-global-emphasis-color; } -} -@mixin hook-inverse-button-text-hover(){} -@mixin hook-inverse-button-text-disabled(){} -@mixin hook-inverse-button-link(){} -@mixin hook-inverse-component-button(){ - - // - // Default - // - - .uk-button-default { - background-color: $inverse-button-default-background; - color: $inverse-button-default-color; - @if(mixin-exists(hook-inverse-button-default)) {@include hook-inverse-button-default();} - } - - .uk-button-default:hover, - .uk-button-default:focus { - background-color: $inverse-button-default-hover-background; - color: $inverse-button-default-hover-color; - @if(mixin-exists(hook-inverse-button-default-hover)) {@include hook-inverse-button-default-hover();} - } - - .uk-button-default:active, - .uk-button-default.uk-active { - background-color: $inverse-button-default-active-background; - color: $inverse-button-default-active-color; - @if(mixin-exists(hook-inverse-button-default-active)) {@include hook-inverse-button-default-active();} - } - - // - // Primary - // - - .uk-button-primary { - background-color: $inverse-button-primary-background; - color: $inverse-button-primary-color; - @if(mixin-exists(hook-inverse-button-primary)) {@include hook-inverse-button-primary();} - } - - .uk-button-primary:hover, - .uk-button-primary:focus { - background-color: $inverse-button-primary-hover-background; - color: $inverse-button-primary-hover-color; - @if(mixin-exists(hook-inverse-button-primary-hover)) {@include hook-inverse-button-primary-hover();} - } - - .uk-button-primary:active, - .uk-button-primary.uk-active { - background-color: $inverse-button-primary-active-background; - color: $inverse-button-primary-active-color; - @if(mixin-exists(hook-inverse-button-primary-active)) {@include hook-inverse-button-primary-active();} - } - - // - // Secondary - // - - .uk-button-secondary { - background-color: $inverse-button-secondary-background; - color: $inverse-button-secondary-color; - @if(mixin-exists(hook-inverse-button-secondary)) {@include hook-inverse-button-secondary();} - } - - .uk-button-secondary:hover, - .uk-button-secondary:focus { - background-color: $inverse-button-secondary-hover-background; - color: $inverse-button-secondary-hover-color; - @if(mixin-exists(hook-inverse-button-secondary-hover)) {@include hook-inverse-button-secondary-hover();} - } - - .uk-button-secondary:active, - .uk-button-secondary.uk-active { - background-color: $inverse-button-secondary-active-background; - color: $inverse-button-secondary-active-color; - @if(mixin-exists(hook-inverse-button-secondary-active)) {@include hook-inverse-button-secondary-active();} - } - - // - // Text - // - - .uk-button-text { - color: $inverse-button-text-color; - @if(mixin-exists(hook-inverse-button-text)) {@include hook-inverse-button-text();} - } - - .uk-button-text:hover, - .uk-button-text:focus { - color: $inverse-button-text-hover-color; - @if(mixin-exists(hook-inverse-button-text-hover)) {@include hook-inverse-button-text-hover();} - } - - .uk-button-text:disabled { - color: $inverse-button-text-disabled-color; - @if(mixin-exists(hook-inverse-button-text-disabled)) {@include hook-inverse-button-text-disabled();} - } - - // - // Link - // - - .uk-button-link { - color: $inverse-button-link-color; - @if(mixin-exists(hook-inverse-button-link)) {@include hook-inverse-button-link();} - } - - .uk-button-link:hover, - .uk-button-link:focus { color: $inverse-button-link-hover-color; } - - -} -@mixin hook-card(){ transition: box-shadow 0.1s ease-in-out; } -@mixin hook-card-body(){} -@mixin hook-card-header(){} -@mixin hook-card-footer(){} -@mixin hook-card-media(){} -@mixin hook-card-media-top(){} -@mixin hook-card-media-bottom(){} -@mixin hook-card-media-left(){} -@mixin hook-card-media-right(){} -@mixin hook-card-title(){} -@mixin hook-card-badge(){ - border-radius: $card-badge-border-radius; - text-transform: $card-badge-text-transform; -} -@mixin hook-card-hover(){ box-shadow: $card-hover-box-shadow; } -@mixin hook-card-default(){ box-shadow: $card-default-box-shadow; } -@mixin hook-card-default-title(){} -@mixin hook-card-default-hover(){ box-shadow: $card-default-hover-box-shadow; } -@mixin hook-card-default-header(){ border-bottom: $card-default-header-border-width solid $card-default-header-border; } -@mixin hook-card-default-footer(){ border-top: $card-default-footer-border-width solid $card-default-footer-border; } -@mixin hook-card-primary(){ box-shadow: $card-primary-box-shadow; } -@mixin hook-card-primary-title(){} -@mixin hook-card-primary-hover(){ box-shadow: $card-primary-hover-box-shadow; } -@mixin hook-card-secondary(){ box-shadow: $card-secondary-box-shadow; } -@mixin hook-card-secondary-title(){} -@mixin hook-card-secondary-hover(){ box-shadow: $card-secondary-hover-box-shadow; } -@mixin hook-card-misc(){ - - /* - * Default - */ - - .uk-card-body > .uk-nav-default { - margin-left: (-$card-body-padding-horizontal); - margin-right: (-$card-body-padding-horizontal); - } - .uk-card-body > .uk-nav-default:only-child { - margin-top: (-$card-body-padding-vertical + 15px); - margin-bottom: (-$card-body-padding-vertical + 15px); - } - - .uk-card-body > .uk-nav-default > li > a, - .uk-card-body > .uk-nav-default .uk-nav-header, - .uk-card-body > .uk-nav-default .uk-nav-divider { - padding-left: $card-body-padding-horizontal; - padding-right: $card-body-padding-horizontal; - } - - .uk-card-body > .uk-nav-default .uk-nav-sub { padding-left: $nav-sublist-deeper-padding-left + $card-body-padding-horizontal; } - - - /* Desktop and bigger */ - @media (min-width: $breakpoint-large) { - - .uk-card-body > .uk-nav-default { - margin-left: (-$card-body-padding-horizontal-l); - margin-right: (-$card-body-padding-horizontal-l); - } - .uk-card-body > .uk-nav-default:only-child { - margin-top: (-$card-body-padding-vertical-l + 15px); - margin-bottom: (-$card-body-padding-vertical-l + 15px); - } - - .uk-card-body > .uk-nav-default > li > a, - .uk-card-body > .uk-nav-default .uk-nav-header, - .uk-card-body > .uk-nav-default .uk-nav-divider { - padding-left: $card-body-padding-horizontal-l; - padding-right: $card-body-padding-horizontal-l; - } - - .uk-card-body > .uk-nav-default .uk-nav-sub { padding-left: $nav-sublist-deeper-padding-left + $card-body-padding-horizontal-l; } - - } - - /* - * Small - */ - - .uk-card-small > .uk-nav-default { - margin-left: (-$card-small-body-padding-horizontal); - margin-right: (-$card-small-body-padding-horizontal); - } - .uk-card-small > .uk-nav-default:only-child { - margin-top: (-$card-small-body-padding-vertical + 15px); - margin-bottom: (-$card-small-body-padding-vertical + 15px); - } - - .uk-card-small > .uk-nav-default > li > a, - .uk-card-small > .uk-nav-default .uk-nav-header, - .uk-card-small > .uk-nav-default .uk-nav-divider { - padding-left: $card-small-body-padding-horizontal; - padding-right: $card-small-body-padding-horizontal; - } - - .uk-card-small > .uk-nav-default .uk-nav-sub { padding-left: $nav-sublist-deeper-padding-left + $card-small-body-padding-horizontal; } - - /* - * Large - */ - - /* Desktop and bigger */ - @media (min-width: $breakpoint-large) { - - .uk-card-large > .uk-nav-default { margin: 0; } - .uk-card-large > .uk-nav-default:only-child { margin: 0; } - - .uk-card-large > .uk-nav-default > li > a, - .uk-card-large > .uk-nav-default .uk-nav-header, - .uk-card-large > .uk-nav-default .uk-nav-divider { - padding-left: 0; - padding-right: 0; - } - - .uk-card-large > .uk-nav-default .uk-nav-sub { padding-left: $nav-sublist-deeper-padding-left; } - - } - -} -@mixin hook-inverse-card-badge(){} -@mixin hook-inverse-component-card(){ - - &.uk-card-badge { - background-color: $inverse-card-badge-background; - color: $inverse-card-badge-color; - @if(mixin-exists(hook-inverse-card-badge)) {@include hook-inverse-card-badge();} - } - -} -@mixin hook-close(){ - transition: 0.1s ease-in-out; - transition-property: color, opacity; -} -@mixin hook-close-hover(){} -@mixin hook-close-misc(){} -@mixin hook-inverse-close(){} -@mixin hook-inverse-close-hover(){} -@mixin hook-inverse-component-close(){ - - .uk-close { - color: $inverse-close-color; - @if(mixin-exists(hook-inverse-close)) {@include hook-inverse-close();} - } - - .uk-close:hover, - .uk-close:focus { - color: $inverse-close-hover-color; - @if(mixin-exists(hook-inverse-close-hover)) {@include hook-inverse-close-hover();} - } - -} -@mixin hook-column-misc(){} -@mixin hook-inverse-component-column(){ - - .uk-column-divider { column-rule-color: $inverse-column-divider-rule-color; } - -} -@mixin hook-comment(){} -@mixin hook-comment-body(){} -@mixin hook-comment-header(){} -@mixin hook-comment-title(){} -@mixin hook-comment-meta(){} -@mixin hook-comment-avatar(){} -@mixin hook-comment-list-adjacent(){} -@mixin hook-comment-list-sub(){} -@mixin hook-comment-list-sub-adjacent(){} -@mixin hook-comment-primary(){ - padding: $comment-primary-padding; - background-color: $comment-primary-background; -} -@mixin hook-comment-misc(){} -@mixin hook-container-misc(){} -@mixin hook-countdown(){} -@mixin hook-countdown-item(){} -@mixin hook-countdown-number(){} -@mixin hook-countdown-separator(){} -@mixin hook-countdown-label(){} -@mixin hook-countdown-misc(){} -@mixin hook-inverse-countdown-item(){} -@mixin hook-inverse-countdown-number(){} -@mixin hook-inverse-countdown-separator(){} -@mixin hook-inverse-countdown-label(){} -@mixin hook-inverse-component-countdown(){ - - .uk-countdown-number, - .uk-countdown-separator { - @if(mixin-exists(hook-inverse-countdown-item)) {@include hook-inverse-countdown-item();} - } - - .uk-countdown-number { - @if(mixin-exists(hook-inverse-countdown-number)) {@include hook-inverse-countdown-number();} - } - - .uk-countdown-separator { - @if(mixin-exists(hook-inverse-countdown-separator)) {@include hook-inverse-countdown-separator();} - } - - .uk-countdown-label { - @if(mixin-exists(hook-inverse-countdown-label)) {@include hook-inverse-countdown-label();} - } - -} -@mixin hook-cover-misc(){} -@mixin hook-description-list-term(){ - font-size: $description-list-term-font-size; - font-weight: $description-list-term-font-weight; - text-transform: $description-list-term-text-transform; -} -@mixin hook-description-list-description(){} -@mixin hook-description-list-divider-term(){} -@mixin hook-description-list-misc(){} -@mixin svg-fill($src, $color-default, $color-new, $property: background-image){ - - $escape-color-default: escape($color-default) !default; - $escape-color-new: escape("#{$color-new}") !default; - - $data-uri: data-uri('image/svg+xml;charset=UTF-8', "#{$src}") !default; - $replace-src: replace("#{$data-uri}", "#{$escape-color-default}", "#{$escape-color-new}", "g") !default; - - #{$property}: unquote($replace-src); -} -@mixin hook-divider-icon(){} -@mixin hook-divider-icon-line(){} -@mixin hook-divider-icon-line-left(){} -@mixin hook-divider-icon-line-right(){} -@mixin hook-divider-small(){} -@mixin hook-divider-vertical(){} -@mixin hook-divider-misc(){} -@mixin hook-inverse-divider-icon(){} -@mixin hook-inverse-divider-icon-line(){} -@mixin hook-inverse-divider-small(){} -@mixin hook-inverse-divider-vertical(){} -@mixin hook-inverse-component-divider(){ - - .uk-divider-icon { - @include svg-fill($internal-divider-icon-image, "#000", $inverse-divider-icon-color); - @if(mixin-exists(hook-inverse-divider-icon)) {@include hook-inverse-divider-icon();} - } - - .uk-divider-icon::before, - .uk-divider-icon::after { - border-bottom-color: $inverse-divider-icon-line-border; - @if(mixin-exists(hook-inverse-divider-icon-line)) {@include hook-inverse-divider-icon-line();} - } - - .uk-divider-small::after { - border-top-color: $inverse-divider-small-border; - @if(mixin-exists(hook-inverse-divider-small)) {@include hook-inverse-divider-small();} - } - - .uk-divider-vertical { - border-left-color: $inverse-divider-vertical-border; - @if(mixin-exists(hook-inverse-divider-vertical)) {@include hook-inverse-divider-vertical();} - } - -} -@mixin hook-dotnav(){} -@mixin hook-dotnav-item(){ - border: $dotnav-item-border-width solid $dotnav-item-border; - transition: 0.2s ease-in-out; - transition-property: background-color, border-color; -} -@mixin hook-dotnav-item-hover(){ border-color: $dotnav-item-hover-border; } -@mixin hook-dotnav-item-onclick(){ border-color: $dotnav-item-onclick-border; } -@mixin hook-dotnav-item-active(){ border-color: $dotnav-item-active-border; } -@mixin hook-dotnav-misc(){} -@mixin hook-inverse-dotnav-item(){ border-color: rgba($inverse-global-color, 0.9); } -@mixin hook-inverse-dotnav-item-hover(){ border-color: transparent; } -@mixin hook-inverse-dotnav-item-onclick(){ border-color: transparent; } -@mixin hook-inverse-dotnav-item-active(){ border-color: transparent; } -@mixin hook-inverse-component-dotnav(){ - - .uk-dotnav > * > * { - background-color: $inverse-dotnav-item-background; - @if(mixin-exists(hook-inverse-dotnav-item)) {@include hook-inverse-dotnav-item();} - } - - .uk-dotnav > * > :hover, - .uk-dotnav > * > :focus { - background-color: $inverse-dotnav-item-hover-background; - @if(mixin-exists(hook-inverse-dotnav-item-hover)) {@include hook-inverse-dotnav-item-hover();} - } - - .uk-dotnav > * > :active { - background-color: $inverse-dotnav-item-onclick-background; - @if(mixin-exists(hook-inverse-dotnav-item-onclick)) {@include hook-inverse-dotnav-item-onclick();} - } - - .uk-dotnav > .uk-active > * { - background-color: $inverse-dotnav-item-active-background; - @if(mixin-exists(hook-inverse-dotnav-item-active)) {@include hook-inverse-dotnav-item-active();} - } - -} -@mixin hook-drop-misc(){} -@mixin hook-dropdown(){ box-shadow: $dropdown-box-shadow; } -@mixin hook-dropdown-nav(){ font-size: $dropdown-nav-font-size; } -@mixin hook-dropdown-nav-item(){} -@mixin hook-dropdown-nav-item-hover(){} -@mixin hook-dropdown-nav-header(){} -@mixin hook-dropdown-nav-divider(){} -@mixin hook-dropdown-misc(){} -@mixin hook-flex-misc(){} -@mixin hook-form-range(){} -@mixin hook-form-range-thumb(){ border: $form-range-thumb-border-width solid $form-range-thumb-border; } -@mixin hook-form-range-track(){ border-radius: $form-range-track-border-radius; } -@mixin hook-form-range-track-focus(){} -@mixin hook-form-range-misc(){} -@mixin hook-form(){ - border: $form-border-width solid $form-border; - transition: 0.2s ease-in-out; - transition-property: color, background-color, border; -} -@mixin hook-form-single-line(){} -@mixin hook-form-multi-line(){} -@mixin hook-form-focus(){ border-color: $form-focus-border; } -@mixin hook-form-disabled(){ border-color: $form-disabled-border; } -@mixin hook-form-danger(){ border-color: $form-danger-border; } -@mixin hook-form-success(){ border-color: $form-success-border; } -@mixin hook-form-blank(){ border-color: transparent; } -@mixin hook-form-blank-focus(){ - border-color: $form-blank-focus-border; - border-style: $form-blank-focus-border-style; -} -@mixin hook-form-radio(){ - border: $form-radio-border-width solid $form-radio-border; - transition: 0.2s ease-in-out; - transition-property: background-color, border; -} -@mixin hook-form-radio-focus(){ border-color: $form-radio-focus-border; } -@mixin hook-form-radio-checked(){ border-color: $form-radio-checked-border; } -@mixin hook-form-radio-checked-focus(){} -@mixin hook-form-radio-disabled(){ border-color: $form-radio-disabled-border; } -@mixin hook-form-legend(){} -@mixin hook-form-label(){ - color: $form-label-color; - font-size: $form-label-font-size; -} -@mixin hook-form-stacked-label(){} -@mixin hook-form-horizontal-label(){} -@mixin hook-form-misc(){} -@mixin hook-inverse-form(){ border-color: $inverse-global-border; } -@mixin hook-inverse-form-focus(){ border-color: $inverse-global-color; } -@mixin hook-inverse-form-radio(){ border-color: $inverse-global-border; } -@mixin hook-inverse-form-radio-focus(){ border-color: $inverse-global-color; } -@mixin hook-inverse-form-radio-checked(){ border-color: $inverse-global-color; } -@mixin hook-inverse-form-radio-checked-focus(){} -@mixin hook-inverse-form-label(){ color: $inverse-form-label-color; } -@mixin hook-inverse-component-form(){ - - .uk-input, - .uk-select, - .uk-textarea { - background-color: $inverse-form-background; - color: $inverse-form-color; - background-clip: padding-box; - @if(mixin-exists(hook-inverse-form)) {@include hook-inverse-form();} - - &:focus { - background-color: $inverse-form-focus-background; - color: $inverse-form-focus-color; - @if(mixin-exists(hook-inverse-form-focus)) {@include hook-inverse-form-focus();} - } - } - - // - // Placeholder - // - - .uk-input::-ms-input-placeholder { color: $inverse-form-placeholder-color !important; } - .uk-input::placeholder { color: $inverse-form-placeholder-color; } - - .uk-textarea::-ms-input-placeholder { color: $inverse-form-placeholder-color !important; } - .uk-textarea::placeholder { color: $inverse-form-placeholder-color; } - - // - // Select - // - - .uk-select:not([multiple]):not([size]) { @include svg-fill($internal-form-select-image, "#000", $inverse-form-select-icon-color); } - - // - // Datalist - // - - .uk-input[list]:hover, - .uk-input[list]:focus { @include svg-fill($internal-form-datalist-image, "#000", $inverse-form-datalist-icon-color); } - - // - // Radio and checkbox - // - - .uk-radio, - .uk-checkbox { - background-color: $inverse-form-radio-background; - @if(mixin-exists(hook-inverse-form-radio)) {@include hook-inverse-form-radio();} - } - - // Focus - .uk-radio:focus, - .uk-checkbox:focus { - background-color: $inverse-form-radio-focus-background; - @if(mixin-exists(hook-inverse-form-radio-focus)) {@include hook-inverse-form-radio-focus();} - } - - // Checked - .uk-radio:checked, - .uk-checkbox:checked, - .uk-checkbox:indeterminate { - background-color: $inverse-form-radio-checked-background; - @if(mixin-exists(hook-inverse-form-radio-checked)) {@include hook-inverse-form-radio-checked();} - } - - // Focus - .uk-radio:checked:focus, - .uk-checkbox:checked:focus, - .uk-checkbox:indeterminate:focus { - background-color: $inverse-form-radio-checked-focus-background; - @if(mixin-exists(hook-inverse-form-radio-checked-focus)) {@include hook-inverse-form-radio-checked-focus();} - } - - // Icon - .uk-radio:checked { @include svg-fill($internal-form-radio-image, "#000", $inverse-form-radio-checked-icon-color); } - .uk-checkbox:checked { @include svg-fill($internal-form-checkbox-image, "#000", $inverse-form-radio-checked-icon-color); } - .uk-checkbox:indeterminate { @include svg-fill($internal-form-checkbox-indeterminate-image, "#000", $inverse-form-radio-checked-icon-color); } - - // Label - .uk-form-label { - @if(mixin-exists(hook-inverse-form-label)) {@include hook-inverse-form-label();} - } - - // Icon - .uk-form-icon { color: $inverse-form-icon-color; } - .uk-form-icon:hover { color: $inverse-form-icon-hover-color; } - -} -@mixin hook-grid-divider-horizontal(){} -@mixin hook-grid-divider-vertical(){} -@mixin hook-grid-misc(){} -@mixin hook-inverse-grid-divider-horizontal(){} -@mixin hook-inverse-grid-divider-vertical(){} -@mixin hook-inverse-component-grid(){ - - .uk-grid-divider > :not(.uk-first-column)::before { - border-left-color: $inverse-grid-divider-border; - @if(mixin-exists(hook-inverse-grid-divider-horizontal)) {@include hook-inverse-grid-divider-horizontal();} - } - - .uk-grid-divider.uk-grid-stack > .uk-grid-margin::before { - border-top-color: $inverse-grid-divider-border; - @if(mixin-exists(hook-inverse-grid-divider-vertical)) {@include hook-inverse-grid-divider-vertical();} - } - -} -@mixin hook-heading-small(){} -@mixin hook-heading-medium(){} -@mixin hook-heading-large(){} -@mixin hook-heading-xlarge(){} -@mixin hook-heading-2xlarge(){} -@mixin hook-heading-primary(){} -@mixin hook-heading-hero(){} -@mixin hook-heading-divider(){} -@mixin hook-heading-bullet(){} -@mixin hook-heading-line(){} -@mixin hook-heading-misc(){} -@mixin hook-inverse-heading-small(){} -@mixin hook-inverse-heading-medium(){} -@mixin hook-inverse-heading-large(){} -@mixin hook-inverse-heading-xlarge(){} -@mixin hook-inverse-heading-2xlarge(){} -@mixin hook-inverse-heading-primary(){} -@mixin hook-inverse-heading-hero(){} -@mixin hook-inverse-heading-divider(){} -@mixin hook-inverse-heading-bullet(){} -@mixin hook-inverse-heading-line(){} -@mixin hook-inverse-component-heading(){ - - .uk-heading-small { - @if(mixin-exists(hook-inverse-heading-small)) {@include hook-inverse-heading-small();} - } - - .uk-heading-medium { - @if(mixin-exists(hook-inverse-heading-medium)) {@include hook-inverse-heading-medium();} - } - - .uk-heading-large { - @if(mixin-exists(hook-inverse-heading-large)) {@include hook-inverse-heading-large();} - } - - .uk-heading-xlarge { - @if(mixin-exists(hook-inverse-heading-xlarge)) {@include hook-inverse-heading-xlarge();} - } - - .uk-heading-2xlarge { - @if(mixin-exists(hook-inverse-heading-2xlarge)) {@include hook-inverse-heading-2xlarge();} - } - - @if ($deprecated == true) { .uk-heading-primary { @if (mixin-exists(hook-inverse-heading-primary)) {@include hook-inverse-heading-primary();}}} - - @if ($deprecated == true) { .uk-heading-hero { @if (mixin-exists(hook-inverse-heading-hero)) {@include hook-inverse-heading-hero();}}} - - .uk-heading-divider { - border-bottom-color: $inverse-heading-divider-border; - @if(mixin-exists(hook-inverse-heading-divider)) {@include hook-inverse-heading-divider();} - } - - .uk-heading-bullet::before { - border-left-color: $inverse-heading-bullet-border; - @if(mixin-exists(hook-inverse-heading-bullet)) {@include hook-inverse-heading-bullet();} - } - - .uk-heading-line > ::before, - .uk-heading-line > ::after { - border-bottom-color: $inverse-heading-line-border; - @if(mixin-exists(hook-inverse-heading-line)) {@include hook-inverse-heading-line();} - } - -} -@mixin hook-height-misc(){} -@mixin hook-icon-link(){} -@mixin hook-icon-link-hover(){} -@mixin hook-icon-link-active(){} -@mixin hook-icon-button(){ - transition: 0.1s ease-in-out; - transition-property: color, background-color; -} -@mixin hook-icon-button-hover(){} -@mixin hook-icon-button-active(){} -@mixin hook-icon-misc(){} -@mixin hook-inverse-icon-link(){} -@mixin hook-inverse-icon-link-hover(){} -@mixin hook-inverse-icon-link-active(){} -@mixin hook-inverse-icon-button(){} -@mixin hook-inverse-icon-button-hover(){} -@mixin hook-inverse-icon-button-active(){} -@mixin hook-inverse-component-icon(){ - - // - // Link - // - - .uk-icon-link { - color: $inverse-icon-link-color; - @if(mixin-exists(hook-inverse-icon-link)) {@include hook-inverse-icon-link();} - } - - .uk-icon-link:hover, - .uk-icon-link:focus { - color: $inverse-icon-link-hover-color; - @if(mixin-exists(hook-inverse-icon-link-hover)) {@include hook-inverse-icon-link-hover();} - } - - .uk-icon-link:active, - .uk-active > .uk-icon-link { - color: $inverse-icon-link-active-color; - @if(mixin-exists(hook-inverse-icon-link-active)) {@include hook-inverse-icon-link-active();} - } - - // - // Button - // - - .uk-icon-button { - background-color: $inverse-icon-button-background; - color: $inverse-icon-button-color; - @if(mixin-exists(hook-inverse-icon-button)) {@include hook-inverse-icon-button();} - } - - .uk-icon-button:hover, - .uk-icon-button:focus { - background-color: $inverse-icon-button-hover-background; - color: $inverse-icon-button-hover-color; - @if(mixin-exists(hook-inverse-icon-button-hover)) {@include hook-inverse-icon-button-hover();} - } - - .uk-icon-button:active { - background-color: $inverse-icon-button-active-background; - color: $inverse-icon-button-active-color; - @if(mixin-exists(hook-inverse-icon-button-active)) {@include hook-inverse-icon-button-active();} - } - -} -@mixin hook-iconnav(){} -@mixin hook-iconnav-item(){ - font-size: $subnav-item-font-size; - transition: 0.1s ease-in-out; - transition-property: color, background-color; -} -@mixin hook-iconnav-item-hover(){} -@mixin hook-iconnav-item-active(){} -@mixin hook-iconnav-misc(){} -@mixin hook-inverse-iconnav-item(){} -@mixin hook-inverse-iconnav-item-hover(){} -@mixin hook-inverse-iconnav-item-active(){} -@mixin hook-inverse-component-iconnav(){ - - .uk-iconnav > * > a { - color: $inverse-iconnav-item-color; - @if(mixin-exists(hook-inverse-iconnav-item)) {@include hook-inverse-iconnav-item();} - } - - .uk-iconnav > * > a:hover, - .uk-iconnav > * > a:focus { - color: $inverse-iconnav-item-hover-color; - @if(mixin-exists(hook-inverse-iconnav-item-hover)) {@include hook-inverse-iconnav-item-hover();} - } - - .uk-iconnav > .uk-active > a { - color: $inverse-iconnav-item-active-color; - @if(mixin-exists(hook-inverse-iconnav-item-active)) {@include hook-inverse-iconnav-item-active();} - } - -} -@mixin hook-inverse-component-link(){ - - a.uk-link-muted, - .uk-link-muted a { - color: $inverse-link-muted-color; - @if(mixin-exists(hook-inverse-link-muted)) {@include hook-inverse-link-muted();} - } - - a.uk-link-muted:hover, - .uk-link-muted a:hover, - .uk-link-toggle:hover .uk-link-muted, - .uk-link-toggle:focus .uk-link-muted { - color: $inverse-link-muted-hover-color; - @if(mixin-exists(hook-inverse-link-muted-hover)) {@include hook-inverse-link-muted-hover();} - } - - a.uk-link-text:hover, - .uk-link-text a:hover, - .uk-link-toggle:hover .uk-link-text, - .uk-link-toggle:focus .uk-link-text { - color: $inverse-link-text-hover-color; - @if(mixin-exists(hook-inverse-link-text-hover)) {@include hook-inverse-link-text-hover();} - } - - a.uk-link-heading:hover, - .uk-link-heading a:hover, - .uk-link-toggle:hover .uk-link-heading, - .uk-link-toggle:focus .uk-link-heading { - color: $inverse-link-heading-hover-color; - @if(mixin-exists(hook-inverse-link-heading-hover)) {@include hook-inverse-link-heading-hover();} - } - -} -@mixin hook-inverse-component-list(){ - - .uk-list-muted > ::before { color: $inverse-list-muted-color !important; } - .uk-list-emphasis > ::before { color: $inverse-list-emphasis-color !important; } - .uk-list-primary > ::before { color: $inverse-list-primary-color !important; } - .uk-list-secondary > ::before { color: $inverse-list-secondary-color !important; } - - .uk-list-bullet > ::before { - @include svg-fill($internal-list-bullet-image, "#000", $inverse-list-bullet-icon-color); - } - - .uk-list-divider > :nth-child(n+2) { - border-top-color: $inverse-list-divider-border; - @if(mixin-exists(hook-inverse-list-divider)) {@include hook-inverse-list-divider();} - } - - .uk-list-striped > * { - @if(mixin-exists(hook-inverse-list-striped)) {@include hook-inverse-list-striped();} - } - - .uk-list-striped > :nth-of-type(odd) { background-color: $inverse-list-striped-background; } - -} -@mixin hook-inverse-component-totop(){ - - .uk-totop { - color: $inverse-totop-color; - @if(mixin-exists(hook-inverse-totop)) {@include hook-inverse-totop();} - } - - .uk-totop:hover, - .uk-totop:focus { - color: $inverse-totop-hover-color; - @if(mixin-exists(hook-inverse-totop-hover)) {@include hook-inverse-totop-hover();} - } - - .uk-totop:active { - color: $inverse-totop-active-color; - @if(mixin-exists(hook-inverse-totop-active)) {@include hook-inverse-totop-active();} - } - -} -@mixin hook-inverse-component-label(){ - - .uk-label { - background-color: $inverse-label-background; - color: $inverse-label-color; - @if(mixin-exists(hook-inverse-label)) {@include hook-inverse-label();} - } - -} -@mixin hook-inverse-component-search(){ - - // - // Input - // - - .uk-search-input { color: $inverse-search-color; } - - .uk-search-input:-ms-input-placeholder { color: $inverse-search-placeholder-color !important; } - .uk-search-input::placeholder { color: $inverse-search-placeholder-color; } - - - // - // Icon - // - - .uk-search .uk-search-icon { color: $inverse-search-icon-color; } - .uk-search .uk-search-icon:hover { color: $inverse-search-icon-color; } - - // - // Style modifier - // - - .uk-search-default .uk-search-input { - background-color: $inverse-search-default-background; - @if(mixin-exists(hook-inverse-search-default-input)) {@include hook-inverse-search-default-input();} - } - - .uk-search-default .uk-search-input:focus { - background-color: $inverse-search-default-focus-background; - @if(mixin-exists(hook-inverse-search-default-input-focus)) {@include hook-inverse-search-default-input-focus();} - } - - .uk-search-navbar .uk-search-input { - background-color: $inverse-search-navbar-background; - @if(mixin-exists(hook-inverse-search-navbar-input)) {@include hook-inverse-search-navbar-input();} - } - - .uk-search-large .uk-search-input { - background-color: $inverse-search-large-background; - @if(mixin-exists(hook-inverse-search-large-input)) {@include hook-inverse-search-large-input();} - } - - // - // Toggle - // - - .uk-search-toggle { - color: $inverse-search-toggle-color; - @if(mixin-exists(hook-inverse-search-toggle)) {@include hook-inverse-search-toggle();} - } - - .uk-search-toggle:hover, - .uk-search-toggle:focus { - color: $inverse-search-toggle-hover-color; - @if(mixin-exists(hook-inverse-search-toggle-hover)) {@include hook-inverse-search-toggle-hover();} - } - -} -@mixin hook-inverse-component-nav(){ - - // - // Parent icon modifier - // - - .uk-nav-parent-icon > .uk-parent > a::after { - @include svg-fill($internal-nav-parent-close-image, "#000", $inverse-nav-parent-icon-color); - @if(mixin-exists(hook-inverse-nav-parent-icon)) {@include hook-inverse-nav-parent-icon();} - } - - .uk-nav-parent-icon > .uk-parent.uk-open > a::after { @include svg-fill($internal-nav-parent-open-image, "#000", $inverse-nav-parent-icon-color); } - - // - // Default - // - - .uk-nav-default > li > a { - color: $inverse-nav-default-item-color; - @if(mixin-exists(hook-inverse-nav-default-item)) {@include hook-inverse-nav-default-item();} - } - - .uk-nav-default > li > a:hover, - .uk-nav-default > li > a:focus { - color: $inverse-nav-default-item-hover-color; - @if(mixin-exists(hook-inverse-nav-default-item-hover)) {@include hook-inverse-nav-default-item-hover();} - } - - .uk-nav-default > li.uk-active > a { - color: $inverse-nav-default-item-active-color; - @if(mixin-exists(hook-inverse-nav-default-item-active)) {@include hook-inverse-nav-default-item-active();} - } - - .uk-nav-default .uk-nav-header { - color: $inverse-nav-default-header-color; - @if(mixin-exists(hook-inverse-nav-default-header)) {@include hook-inverse-nav-default-header();} - } - - .uk-nav-default .uk-nav-divider { - border-top-color: $inverse-nav-default-divider-border; - @if(mixin-exists(hook-inverse-nav-default-divider)) {@include hook-inverse-nav-default-divider();} - } - - .uk-nav-default .uk-nav-sub a { color: $inverse-nav-default-sublist-item-color; } - - .uk-nav-default .uk-nav-sub a:hover, - .uk-nav-default .uk-nav-sub a:focus { color: $inverse-nav-default-sublist-item-hover-color; } - - .uk-nav-default .uk-nav-sub li.uk-active > a { color: $inverse-nav-default-sublist-item-active-color; } - - // - // Primary - // - - .uk-nav-primary > li > a { - color: $inverse-nav-primary-item-color; - @if(mixin-exists(hook-inverse-nav-primary-item)) {@include hook-inverse-nav-primary-item();} - } - - .uk-nav-primary > li > a:hover, - .uk-nav-primary > li > a:focus { - color: $inverse-nav-primary-item-hover-color; - @if(mixin-exists(hook-inverse-nav-primary-item-hover)) {@include hook-inverse-nav-primary-item-hover();} - } - - .uk-nav-primary > li.uk-active > a { - color: $inverse-nav-primary-item-active-color; - @if(mixin-exists(hook-inverse-nav-primary-item-active)) {@include hook-inverse-nav-primary-item-active();} - } - - .uk-nav-primary .uk-nav-header { - color: $inverse-nav-primary-header-color; - @if(mixin-exists(hook-inverse-nav-primary-header)) {@include hook-inverse-nav-primary-header();} - } - - .uk-nav-primary .uk-nav-divider { - border-top-color: $inverse-nav-primary-divider-border; - @if(mixin-exists(hook-inverse-nav-primary-divider)) {@include hook-inverse-nav-primary-divider();} - } - - .uk-nav-primary .uk-nav-sub a { color: $inverse-nav-primary-sublist-item-color; } - - .uk-nav-primary .uk-nav-sub a:hover, - .uk-nav-primary .uk-nav-sub a:focus { color: $inverse-nav-primary-sublist-item-hover-color; } - - .uk-nav-primary .uk-nav-sub li.uk-active > a { color: $inverse-nav-primary-sublist-item-active-color; } - - // - // Dividers - // - - .uk-nav.uk-nav-divider > :not(.uk-nav-divider) + :not(.uk-nav-header, .uk-nav-divider) { - border-top-color: $inverse-nav-dividers-border; - @if(mixin-exists(hook-nav-dividers)) {@include hook-nav-dividers();} - } - -} -@mixin hook-inverse-component-navbar(){ - - .uk-navbar-nav > li > a { - color: $inverse-navbar-nav-item-color; - @if(mixin-exists(hook-inverse-navbar-nav-item)) {@include hook-inverse-navbar-nav-item();} - } - - .uk-navbar-nav > li:hover > a, - .uk-navbar-nav > li > a:focus, - .uk-navbar-nav > li > a.uk-open { - color: $inverse-navbar-nav-item-hover-color; - @if(mixin-exists(hook-inverse-navbar-nav-item-hover)) {@include hook-inverse-navbar-nav-item-hover();} - } - - .uk-navbar-nav > li > a:active { - color: $inverse-navbar-nav-item-onclick-color; - @if(mixin-exists(hook-inverse-navbar-nav-item-onclick)) {@include hook-inverse-navbar-nav-item-onclick();} - } - - .uk-navbar-nav > li.uk-active > a { - color: $inverse-navbar-nav-item-active-color; - @if(mixin-exists(hook-inverse-navbar-nav-item-active)) {@include hook-inverse-navbar-nav-item-active();} - } - - .uk-navbar-item { - color: $inverse-navbar-item-color; - @if(mixin-exists(hook-inverse-navbar-item)) {@include hook-inverse-navbar-item();} - } - - .uk-navbar-toggle { - color: $inverse-navbar-toggle-color; - @if(mixin-exists(hook-inverse-navbar-toggle)) {@include hook-inverse-navbar-toggle();} - } - - .uk-navbar-toggle:hover, - .uk-navbar-toggle:focus, - .uk-navbar-toggle.uk-open { - color: $inverse-navbar-toggle-hover-color; - @if(mixin-exists(hook-inverse-navbar-toggle-hover)) {@include hook-inverse-navbar-toggle-hover();} - } - -} -@mixin hook-inverse-component-subnav(){ - - .uk-subnav > * > :first-child { - color: $inverse-subnav-item-color; - @if(mixin-exists(hook-inverse-subnav-item)) {@include hook-inverse-subnav-item();} - } - - .uk-subnav > * > a:hover, - .uk-subnav > * > a:focus { - color: $inverse-subnav-item-hover-color; - @if(mixin-exists(hook-inverse-subnav-item-hover)) {@include hook-inverse-subnav-item-hover();} - } - - .uk-subnav > .uk-active > a { - color: $inverse-subnav-item-active-color; - @if(mixin-exists(hook-inverse-subnav-item-active)) {@include hook-inverse-subnav-item-active();} - } - - // - // Divider - // - - .uk-subnav-divider > :nth-child(n+2):not(.uk-first-column)::before { - border-left-color: $inverse-subnav-divider-border; - @if(mixin-exists(hook-inverse-subnav-divider)) {@include hook-inverse-subnav-divider();} - } - - // - // Pill - // - - .uk-subnav-pill > * > :first-child { - background-color: $inverse-subnav-pill-item-background; - color: $inverse-subnav-pill-item-color; - @if(mixin-exists(hook-inverse-subnav-pill-item)) {@include hook-inverse-subnav-pill-item();} - } - - .uk-subnav-pill > * > a:hover, - .uk-subnav-pill > * > a:focus { - background-color: $inverse-subnav-pill-item-hover-background; - color: $inverse-subnav-pill-item-hover-color; - @if(mixin-exists(hook-inverse-subnav-pill-item-hover)) {@include hook-inverse-subnav-pill-item-hover();} - } - - .uk-subnav-pill > * > a:active { - background-color: $inverse-subnav-pill-item-onclick-background; - color: $inverse-subnav-pill-item-onclick-color; - @if(mixin-exists(hook-inverse-subnav-pill-item-onclick)) {@include hook-inverse-subnav-pill-item-onclick();} - } - - .uk-subnav-pill > .uk-active > a { - background-color: $inverse-subnav-pill-item-active-background; - color: $inverse-subnav-pill-item-active-color; - @if(mixin-exists(hook-inverse-subnav-pill-item-active)) {@include hook-inverse-subnav-pill-item-active();} - } - - // - // Disabled - // - - .uk-subnav > .uk-disabled > a { - color: $inverse-subnav-item-disabled-color; - @if(mixin-exists(hook-inverse-subnav-item-disabled)) {@include hook-inverse-subnav-item-disabled();} - } - -} -@mixin hook-inverse-component-pagination(){ - - .uk-pagination > * > * { - color: $inverse-pagination-item-color; - @if(mixin-exists(hook-inverse-pagination-item)) {@include hook-inverse-pagination-item();} - } - - .uk-pagination > * > :hover, - .uk-pagination > * > :focus { - color: $inverse-pagination-item-hover-color; - @if(mixin-exists(hook-inverse-pagination-item-hover)) {@include hook-inverse-pagination-item-hover();} - } - - .uk-pagination > .uk-active > * { - color: $inverse-pagination-item-active-color; - @if(mixin-exists(hook-inverse-pagination-item-active)) {@include hook-inverse-pagination-item-active();} - } - - .uk-pagination > .uk-disabled > * { - color: $inverse-pagination-item-disabled-color; - @if(mixin-exists(hook-inverse-pagination-item-disabled)) {@include hook-inverse-pagination-item-disabled();} - } - -} -@mixin hook-inverse-component-tab(){ - - .uk-tab { - @if(mixin-exists(hook-inverse-tab)) {@include hook-inverse-tab();} - } - - .uk-tab > * > a { - color: $inverse-tab-item-color; - @if(mixin-exists(hook-inverse-tab-item)) {@include hook-inverse-tab-item();} - } - - .uk-tab > * > a:hover, - .uk-tab > * > a:focus{ - color: $inverse-tab-item-hover-color; - @if(mixin-exists(hook-inverse-tab-item-hover)) {@include hook-inverse-tab-item-hover();} - } - - .uk-tab > .uk-active > a { - color: $inverse-tab-item-active-color; - @if(mixin-exists(hook-inverse-tab-item-active)) {@include hook-inverse-tab-item-active();} - } - - .uk-tab > .uk-disabled > a { - color: $inverse-tab-item-disabled-color; - @if(mixin-exists(hook-inverse-tab-item-disabled)) {@include hook-inverse-tab-item-disabled();} - } - -} -@mixin hook-inverse-component-slidenav(){ - - .uk-slidenav { - color: $inverse-slidenav-color; - @if(mixin-exists(hook-inverse-slidenav)) {@include hook-inverse-slidenav();} - } - - .uk-slidenav:hover, - .uk-slidenav:focus { - color: $inverse-slidenav-hover-color; - @if(mixin-exists(hook-inverse-slidenav-hover)) {@include hook-inverse-slidenav-hover();} - } - - .uk-slidenav:active { - color: $inverse-slidenav-active-color; - @if(mixin-exists(hook-inverse-slidenav-active)) {@include hook-inverse-slidenav-active();} - } - -} -@mixin hook-inverse-component-text(){ - - .uk-text-lead { - color: $inverse-text-lead-color; - @if(mixin-exists(hook-inverse-text-lead)) {@include hook-inverse-text-lead();} - } - - .uk-text-meta { - color: $inverse-text-meta-color; - @if(mixin-exists(hook-inverse-text-meta)) {@include hook-inverse-text-meta();} - } - - .uk-text-muted { color: $inverse-text-muted-color !important; } - .uk-text-emphasis { color: $inverse-text-emphasis-color !important; } - .uk-text-primary { color: $inverse-text-primary-color !important; } - .uk-text-secondary { color: $inverse-text-secondary-color !important; } - -} -@mixin hook-inverse-component-utility(){ - - .uk-dropcap::first-letter, - .uk-dropcap p:first-of-type::first-letter { - @if(mixin-exists(hook-inverse-dropcap)) {@include hook-inverse-dropcap();} - } - - .uk-logo { - color: $inverse-logo-color; - @if(mixin-exists(hook-inverse-logo)) {@include hook-inverse-logo();} - } - - .uk-logo:hover, - .uk-logo:focus { - color: $inverse-logo-hover-color; - @if(mixin-exists(hook-inverse-logo-hover)) {@include hook-inverse-logo-hover();} - } - - .uk-logo > :not(.uk-logo-inverse):not(:only-of-type) { display: none; } - .uk-logo-inverse { display: inline; } - -} -@mixin hook-inverse(){ - @include hook-inverse-component-base(); - @include hook-inverse-component-link(); - @include hook-inverse-component-heading(); - @include hook-inverse-component-divider(); - @include hook-inverse-component-list(); - @include hook-inverse-component-icon(); - @include hook-inverse-component-form(); - @include hook-inverse-component-button(); - @include hook-inverse-component-grid(); - @include hook-inverse-component-close(); - @include hook-inverse-component-totop(); - @include hook-inverse-component-badge(); - @include hook-inverse-component-label(); - @include hook-inverse-component-article(); - @include hook-inverse-component-search(); - @include hook-inverse-component-nav(); - @include hook-inverse-component-navbar(); - @include hook-inverse-component-subnav(); - @include hook-inverse-component-breadcrumb(); - @include hook-inverse-component-pagination(); - @include hook-inverse-component-tab(); - @include hook-inverse-component-slidenav(); - @include hook-inverse-component-dotnav(); - @include hook-inverse-component-accordion(); - @include hook-inverse-component-iconnav(); - @include hook-inverse-component-text(); - @include hook-inverse-component-column(); - @include hook-inverse-component-utility(); -} -@mixin hook-label(){ - border-radius: $label-border-radius; - text-transform: $label-text-transform; -} -@mixin hook-label-success(){} -@mixin hook-label-warning(){} -@mixin hook-label-danger(){} -@mixin hook-label-misc(){} -@mixin hook-inverse-label(){} -@mixin hook-leader(){} -@mixin hook-leader-misc(){} -@mixin hook-inverse-leader(){} -@mixin hook-inverse-component-leader(){ - - .uk-leader-fill::after { - @if(mixin-exists(hook-inverse-leader)) {@include hook-inverse-leader();} - } - -} -@mixin hook-lightbox(){} -@mixin hook-lightbox-item(){} -@mixin hook-lightbox-toolbar(){} -@mixin hook-lightbox-toolbar-icon(){} -@mixin hook-lightbox-toolbar-icon-hover(){} -@mixin hook-lightbox-button(){} -@mixin hook-lightbox-button-hover(){} -@mixin hook-lightbox-button-active(){} -@mixin hook-lightbox-misc(){} -@mixin hook-link-muted(){} -@mixin hook-link-muted-hover(){} -@mixin hook-link-text(){} -@mixin hook-link-text-hover(){} -@mixin hook-link-heading(){} -@mixin hook-link-heading-hover(){} -@mixin hook-link-reset(){} -@mixin hook-link-misc(){} -@mixin hook-inverse-link-muted(){} -@mixin hook-inverse-link-muted-hover(){} -@mixin hook-inverse-link-text-hover(){} -@mixin hook-inverse-link-heading-hover(){} -@mixin hook-list-divider(){} -@mixin hook-list-striped(){ - - &:nth-of-type(odd) { - border-top: $list-striped-border-width solid $list-striped-border; - border-bottom: $list-striped-border-width solid $list-striped-border; - } - -} -@mixin hook-list-misc(){} -@mixin hook-inverse-list-divider(){} -@mixin hook-inverse-list-striped(){ - - &:nth-of-type(odd) { - border-top-color: $inverse-global-border; - border-bottom-color: $inverse-global-border; - } - -} -@mixin hook-margin-misc(){} -@mixin hook-marker(){ - border-radius: 500px; -} -@mixin hook-marker-hover(){} -@mixin hook-marker-misc(){} -@mixin hook-inverse-marker(){} -@mixin hook-inverse-marker-hover(){} -@mixin hook-inverse-component-marker(){ - - .uk-marker { - background: $inverse-marker-background; - color: $inverse-marker-color; - @if(mixin-exists(hook-inverse-marker)) {@include hook-inverse-marker();} - } - - .uk-marker:hover, - .uk-marker:focus { - color: $inverse-marker-hover-color; - @if(mixin-exists(hook-inverse-marker-hover)) {@include hook-inverse-marker-hover();} - } - -} -@mixin hook-modal(){} -@mixin hook-modal-dialog(){} -@mixin hook-modal-full(){} -@mixin hook-modal-body(){} -@mixin hook-modal-header(){ border-bottom: $modal-header-border-width solid $modal-header-border; } -@mixin hook-modal-footer(){ border-top: $modal-footer-border-width solid $modal-footer-border; } -@mixin hook-modal-title(){} -@mixin hook-modal-close(){} -@mixin hook-modal-close-hover(){} -@mixin hook-modal-close-default(){} -@mixin hook-modal-close-default-hover(){} -@mixin hook-modal-close-outside(){} -@mixin hook-modal-close-outside-hover(){} -@mixin hook-modal-close-full(){ - top: 0; - right: 0; - padding: $modal-close-full-padding; - background: $modal-close-full-background; -} -@mixin hook-modal-close-full-hover(){} -@mixin hook-modal-misc(){} -@mixin hook-nav-sub(){} -@mixin hook-nav-parent-icon(){} -@mixin hook-nav-header(){} -@mixin hook-nav-divider(){} -@mixin hook-nav-default(){ font-size: $nav-default-font-size; } -@mixin hook-nav-default-item(){} -@mixin hook-nav-default-item-hover(){} -@mixin hook-nav-default-item-active(){} -@mixin hook-nav-default-header(){} -@mixin hook-nav-default-divider(){} -@mixin hook-nav-primary(){} -@mixin hook-nav-primary-item(){} -@mixin hook-nav-primary-item-hover(){} -@mixin hook-nav-primary-item-active(){} -@mixin hook-nav-primary-header(){} -@mixin hook-nav-primary-divider(){} -@mixin hook-nav-dividers(){} -@mixin hook-nav-misc(){} -@mixin hook-inverse-nav-parent-icon(){} -@mixin hook-inverse-nav-default-item(){} -@mixin hook-inverse-nav-default-item-hover(){} -@mixin hook-inverse-nav-default-item-active(){} -@mixin hook-inverse-nav-default-header(){} -@mixin hook-inverse-nav-default-divider(){} -@mixin hook-inverse-nav-primary-item(){} -@mixin hook-inverse-nav-primary-item-hover(){} -@mixin hook-inverse-nav-primary-item-active(){} -@mixin hook-inverse-nav-primary-header(){} -@mixin hook-inverse-nav-primary-divider(){} -@mixin hook-navbar(){} -@mixin hook-navbar-container(){} -@mixin hook-navbar-nav-item(){ - text-transform: $navbar-nav-item-text-transform; - transition: 0.1s ease-in-out; - transition-property: color, background-color; -} -@mixin hook-navbar-nav-item-hover(){} -@mixin hook-navbar-nav-item-onclick(){} -@mixin hook-navbar-nav-item-active(){} -@mixin hook-navbar-item(){} -@mixin hook-navbar-toggle(){} -@mixin hook-navbar-toggle-hover(){} -@mixin hook-navbar-toggle-icon(){} -@mixin hook-navbar-toggle-icon-hover(){} -@mixin hook-navbar-subtitle(){} -@mixin hook-navbar-primary(){} -@mixin hook-navbar-transparent(){} -@mixin hook-navbar-sticky(){} -@mixin hook-navbar-dropdown(){ box-shadow: $navbar-dropdown-box-shadow; } -@mixin hook-navbar-dropdown-dropbar(){ box-shadow: none; } -@mixin hook-navbar-dropdown-nav(){ font-size: $navbar-dropdown-nav-font-size; } -@mixin hook-navbar-dropdown-nav-item(){} -@mixin hook-navbar-dropdown-nav-item-hover(){} -@mixin hook-navbar-dropdown-nav-item-active(){} -@mixin hook-navbar-dropdown-nav-header(){} -@mixin hook-navbar-dropdown-nav-divider(){} -@mixin hook-navbar-dropbar(){} -@mixin hook-navbar-dropbar-slide(){ box-shadow: $navbar-dropbar-box-shadow; } -@mixin hook-navbar-misc(){ - - /* - * Navbar - */ - - .uk-navbar-container > .uk-container .uk-navbar-left { - margin-left: (-$navbar-nav-item-padding-horizontal); - margin-right: (-$navbar-nav-item-padding-horizontal); - } - .uk-navbar-container > .uk-container .uk-navbar-right { margin-right: (-$navbar-nav-item-padding-horizontal); } - - /* - * Grid Divider - */ - - .uk-navbar-dropdown-grid > * { position: relative; } - - .uk-navbar-dropdown-grid > :not(.uk-first-column)::before { - content: ""; - position: absolute; - top: 0; - bottom: 0; - left: ($navbar-dropdown-grid-gutter-horizontal / 2); - border-left: $navbar-dropdown-grid-divider-border-width solid $navbar-dropdown-grid-divider-border; - } - - /* Vertical */ - .uk-navbar-dropdown-grid.uk-grid-stack > .uk-grid-margin::before { - content: ""; - position: absolute; - top: -($navbar-dropdown-grid-gutter-vertical / 2); - left: $navbar-dropdown-grid-gutter-horizontal; - right: 0; - border-top: $navbar-dropdown-grid-divider-border-width solid $navbar-dropdown-grid-divider-border; - } - -} -@mixin hook-inverse-navbar-nav-item(){} -@mixin hook-inverse-navbar-nav-item-hover(){} -@mixin hook-inverse-navbar-nav-item-onclick(){} -@mixin hook-inverse-navbar-nav-item-active(){} -@mixin hook-inverse-navbar-item(){} -@mixin hook-inverse-navbar-toggle(){} -@mixin hook-inverse-navbar-toggle-hover(){} -@mixin hook-notification(){} -@mixin hook-notification-message(){} -@mixin hook-notification-close(){} -@mixin hook-notification-message-primary(){} -@mixin hook-notification-message-success(){} -@mixin hook-notification-message-warning(){} -@mixin hook-notification-message-danger(){} -@mixin hook-notification-misc(){} -@mixin hook-offcanvas-bar(){} -@mixin hook-offcanvas-close(){} -@mixin hook-offcanvas-overlay(){} -@mixin hook-offcanvas-misc(){} -@mixin hook-overlay(){} -@mixin hook-overlay-icon(){} -@mixin hook-overlay-default(){} -@mixin hook-overlay-primary(){} -@mixin hook-overlay-misc(){} -@mixin hook-padding-misc(){} -@mixin hook-pagination(){} -@mixin hook-pagination-item(){ transition: color 0.1s ease-in-out; } -@mixin hook-pagination-item-hover(){} -@mixin hook-pagination-item-active(){} -@mixin hook-pagination-item-disabled(){} -@mixin hook-pagination-misc(){} -@mixin hook-inverse-pagination-item(){} -@mixin hook-inverse-pagination-item-hover(){} -@mixin hook-inverse-pagination-item-active(){} -@mixin hook-inverse-pagination-item-disabled(){} -@mixin hook-placeholder(){ border: $placeholder-border-width dashed $placeholder-border; } -@mixin hook-placeholder-misc(){} -@mixin hook-position-misc(){} -@mixin hook-print(){} -@mixin hook-progress(){ - border-radius: $progress-border-radius; - overflow: hidden; -} -@mixin hook-progress-bar(){} -@mixin hook-progress-misc(){} -@mixin hook-search-input(){} -@mixin hook-search-default-input(){ border: $search-default-border-width solid $search-default-border; } -@mixin hook-search-default-input-focus(){ border-color: $search-default-focus-border; } -@mixin hook-search-navbar-input(){} -@mixin hook-search-large-input(){} -@mixin hook-search-toggle(){} -@mixin hook-search-toggle-hover(){} -@mixin hook-search-misc(){} -@mixin hook-inverse-search-default-input(){ border-color: $inverse-global-border; } -@mixin hook-inverse-search-default-input-focus(){} -@mixin hook-inverse-search-navbar-input(){} -@mixin hook-inverse-search-large-input(){} -@mixin hook-inverse-search-toggle(){} -@mixin hook-inverse-search-toggle-hover(){} -@mixin hook-section(){} -@mixin hook-section-default(){} -@mixin hook-section-muted(){} -@mixin hook-section-primary(){} -@mixin hook-section-secondary(){} -@mixin hook-section-overlap(){} -@mixin hook-section-misc(){} -@mixin hook-slidenav(){ transition: color 0.1s ease-in-out; } -@mixin hook-slidenav-hover(){} -@mixin hook-slidenav-active(){} -@mixin hook-slidenav-previous(){} -@mixin hook-slidenav-next(){} -@mixin hook-slidenav-large(){} -@mixin hook-slidenav-container(){} -@mixin hook-slidenav-misc(){} -@mixin hook-inverse-slidenav(){} -@mixin hook-inverse-slidenav-hover(){} -@mixin hook-inverse-slidenav-active(){} -@mixin hook-slider(){} -@mixin hook-slider-misc(){} -@mixin hook-slideshow(){} -@mixin hook-slideshow-misc(){} -@mixin hook-sortable(){} -@mixin hook-sortable-drag(){} -@mixin hook-sortable-placeholder(){} -@mixin hook-sortable-empty(){} -@mixin hook-sortable-misc(){} -@mixin hook-spinner(){} -@mixin hook-spinner-misc(){} -@mixin hook-sticky-misc(){} -@mixin hook-subnav(){} -@mixin hook-subnav-item(){ - font-size: $subnav-item-font-size; - text-transform: $subnav-item-text-transform; - transition: 0.1s ease-in-out; - transition-property: color, background-color; -} -@mixin hook-subnav-item-hover(){} -@mixin hook-subnav-item-active(){} -@mixin hook-subnav-divider(){} -@mixin hook-subnav-pill-item(){} -@mixin hook-subnav-pill-item-hover(){} -@mixin hook-subnav-pill-item-onclick(){} -@mixin hook-subnav-pill-item-active(){} -@mixin hook-subnav-item-disabled(){} -@mixin hook-subnav-misc(){} -@mixin hook-inverse-subnav-item(){} -@mixin hook-inverse-subnav-item-hover(){} -@mixin hook-inverse-subnav-item-active(){} -@mixin hook-inverse-subnav-divider(){} -@mixin hook-inverse-subnav-pill-item(){} -@mixin hook-inverse-subnav-pill-item-hover(){} -@mixin hook-inverse-subnav-pill-item-onclick(){} -@mixin hook-inverse-subnav-pill-item-active(){} -@mixin hook-inverse-subnav-item-disabled(){} -@mixin hook-svg-misc(){} -@mixin hook-switcher-misc(){} -@mixin hook-tab(){ - - position: relative; - - &::before { - content: ""; - position: absolute; - bottom: 0; - left: $tab-margin-horizontal; - right: 0; - border-bottom: $tab-border-width solid $tab-border; - } - -} -@mixin hook-tab-item(){ - border-bottom: $tab-item-border-width solid transparent; - font-size: $tab-item-font-size; - text-transform: $tab-item-text-transform; - transition: color 0.1s ease-in-out; -} -@mixin hook-tab-item-hover(){} -@mixin hook-tab-item-active(){ border-color: $tab-item-active-border; } -@mixin hook-tab-item-disabled(){} -@mixin hook-tab-bottom(){ - - &::before { - top: 0; - bottom: auto; - } - -} -@mixin hook-tab-bottom-item(){ - border-top: $tab-item-border-width solid transparent; - border-bottom: none; -} -@mixin hook-tab-left(){ - - &::before { - top: 0; - bottom: 0; - left: auto; - right: 0; - border-left: $tab-border-width solid $tab-border; - border-bottom: none; - } - -} -@mixin hook-tab-right(){ - - &::before { - top: 0; - bottom: 0; - left: 0; - right: auto; - border-left: $tab-border-width solid $tab-border; - border-bottom: none; - } - -} -@mixin hook-tab-left-item(){ - border-right: $tab-item-border-width solid transparent; - border-bottom: none; -} -@mixin hook-tab-right-item(){ - border-left: $tab-item-border-width solid transparent; - border-bottom: none; -} -@mixin hook-tab-misc(){ - - .uk-tab .uk-dropdown { margin-left: ($tab-margin-horizontal + $tab-item-padding-horizontal) } - -} -@mixin hook-inverse-tab(){ - - &::before { border-color: $inverse-tab-border; } - -} -@mixin hook-inverse-tab-item(){} -@mixin hook-inverse-tab-item-hover(){} -@mixin hook-inverse-tab-item-active(){ border-color: $inverse-global-primary-background; } -@mixin hook-inverse-tab-item-disabled(){} -@mixin hook-table(){} -@mixin hook-table-header-cell(){ text-transform: uppercase; } -@mixin hook-table-cell(){} -@mixin hook-table-footer(){} -@mixin hook-table-caption(){} -@mixin hook-table-divider(){} -@mixin hook-table-striped(){ - border-top: $table-striped-border-width solid $table-striped-border; - border-bottom: $table-striped-border-width solid $table-striped-border; -} -@mixin hook-table-hover(){} -@mixin hook-table-row-active(){} -@mixin hook-table-small(){} -@mixin hook-table-large(){} -@mixin hook-table-misc(){ - - .uk-table tbody tr { transition: background-color 0.1s linear; } - -} -@mixin hook-inverse-table-header-cell(){} -@mixin hook-inverse-table-caption(){} -@mixin hook-inverse-table-row-active(){} -@mixin hook-inverse-table-divider(){} -@mixin hook-inverse-table-striped(){ - border-top-color: $inverse-global-border; - border-bottom-color: $inverse-global-border; -} -@mixin hook-inverse-table-hover(){} -@mixin hook-inverse-component-table(){ - - .uk-table th { - color: $inverse-table-header-cell-color; - @if(mixin-exists(hook-inverse-table-header-cell)) {@include hook-inverse-table-header-cell();} - } - - .uk-table caption { - color: $inverse-table-caption-color; - @if(mixin-exists(hook-inverse-table-caption)) {@include hook-inverse-table-caption();} - } - - .uk-table > tr.uk-active, - .uk-table tbody tr.uk-active { - background: $inverse-table-row-active-background; - @if(mixin-exists(hook-inverse-table-row-active)) {@include hook-inverse-table-row-active();} - } - - .uk-table-divider > tr:not(:first-child), - .uk-table-divider > :not(:first-child) > tr, - .uk-table-divider > :first-child > tr:not(:first-child) { - border-top-color: $inverse-table-divider-border; - @if(mixin-exists(hook-inverse-table-divider)) {@include hook-inverse-table-divider();} - } - - .uk-table-striped > tr:nth-of-type(odd), - .uk-table-striped tbody tr:nth-of-type(odd) { - background: $inverse-table-striped-row-background; - @if(mixin-exists(hook-inverse-table-striped)) {@include hook-inverse-table-striped();} - } - - .uk-table-hover > tr:hover, - .uk-table-hover tbody tr:hover { - background: $inverse-table-hover-row-background; - @if(mixin-exists(hook-inverse-table-hover)) {@include hook-inverse-table-hover();} - } - -} -@mixin hook-text-lead(){} -@mixin hook-text-meta(){ - - a { color: $text-meta-link-color; } - - a:hover { - color: $text-meta-link-hover-color; - text-decoration: none; - } - -} -@mixin hook-text-small(){} -@mixin hook-text-large(){} -@mixin hook-text-background(){} -@mixin hook-text-misc(){} -@mixin hook-inverse-text-lead(){} -@mixin hook-inverse-text-meta(){} -@mixin hook-thumbnav(){} -@mixin hook-thumbnav-item(){ - - position: relative; - - &::after { - content: ""; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - background: $thumbnav-item-background; - transition: background-color 0.1s ease-in-out; - } - -} -@mixin hook-thumbnav-item-hover(){ - &::after { background-color: $thumbnav-item-hover-background; } -} -@mixin hook-thumbnav-item-active(){ - &::after { background-color: $thumbnav-item-active-background; } -} -@mixin hook-thumbnav-misc(){} -@mixin hook-inverse-thumbnav-item(){} -@mixin hook-inverse-thumbnav-item-hover(){} -@mixin hook-inverse-thumbnav-item-active(){} -@mixin hook-inverse-component-thumbnav(){ - - .uk-thumbnav > * > * { - @if(mixin-exists(hook-inverse-thumbnav-item)) {@include hook-inverse-thumbnav-item();} - } - - .uk-thumbnav > * > :hover, - .uk-thumbnav > * > :focus { - @if(mixin-exists(hook-inverse-thumbnav-item-hover)) {@include hook-inverse-thumbnav-item-hover();} - } - - .uk-thumbnav > .uk-active > * { - @if(mixin-exists(hook-inverse-thumbnav-item-active)) {@include hook-inverse-thumbnav-item-active();} - } - -} -@mixin hook-tile(){} -@mixin hook-tile-default(){} -@mixin hook-tile-muted(){} -@mixin hook-tile-primary(){} -@mixin hook-tile-secondary(){} -@mixin hook-tile-misc(){} -@mixin hook-tooltip(){} -@mixin hook-tooltip-misc(){} -@mixin hook-totop(){ transition: color 0.1s ease-in-out; } -@mixin hook-totop-hover(){} -@mixin hook-totop-active(){} -@mixin hook-totop-misc(){} -@mixin hook-inverse-totop(){} -@mixin hook-inverse-totop-hover(){} -@mixin hook-inverse-totop-active(){} -@mixin hook-transition-misc(){} -@mixin hook-panel-scrollable(){} -@mixin hook-box-shadow-bottom(){} -@mixin hook-dropcap(){ - // Prevent line wrap - margin-bottom: -2px; -} -@mixin hook-logo(){} -@mixin hook-logo-hover(){} -@mixin hook-utility-misc(){} -@mixin hook-inverse-dropcap(){} -@mixin hook-inverse-logo(){} -@mixin hook-inverse-logo-hover(){} -@mixin hook-visibility-misc(){} -@mixin hook-width-misc(){} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/_sass/uikit/mixins.scss b/docs/_sass/uikit/mixins.scss deleted file mode 100644 index 61bae21e37..0000000000 --- a/docs/_sass/uikit/mixins.scss +++ /dev/null @@ -1,1748 +0,0 @@ -@mixin hook-accordion(){} -@mixin hook-accordion-item(){} -@mixin hook-accordion-title(){} -@mixin hook-accordion-title-hover(){} -@mixin hook-accordion-content(){} -@mixin hook-accordion-misc(){} -@mixin hook-inverse-accordion-item(){} -@mixin hook-inverse-accordion-title(){} -@mixin hook-inverse-accordion-title-hover(){} -@mixin hook-inverse-component-accordion(){ - - .uk-accordion > :nth-child(n+2) { - @if(mixin-exists(hook-inverse-accordion-item)) {@include hook-inverse-accordion-item();} - } - - .uk-accordion-title { - color: $inverse-accordion-title-color; - @if(mixin-exists(hook-inverse-accordion-title)) {@include hook-inverse-accordion-title();} - } - - .uk-accordion-title:hover, - .uk-accordion-title:focus { - color: $inverse-accordion-title-hover-color; - @if(mixin-exists(hook-inverse-accordion-title-hover)) {@include hook-inverse-accordion-title-hover();} - } - -} -@mixin hook-alert(){} -@mixin hook-alert-close(){} -@mixin hook-alert-close-hover(){} -@mixin hook-alert-primary(){} -@mixin hook-alert-success(){} -@mixin hook-alert-warning(){} -@mixin hook-alert-danger(){} -@mixin hook-alert-misc(){} -@mixin hook-align-misc(){} -@mixin hook-animation-misc(){} -@mixin hook-article(){} -@mixin hook-article-adjacent(){} -@mixin hook-article-title(){} -@mixin hook-article-meta(){} -@mixin hook-article-misc(){} -@mixin hook-inverse-article-title(){} -@mixin hook-inverse-article-meta(){} -@mixin hook-inverse-component-article(){ - - .uk-article-title { - @if(mixin-exists(hook-inverse-article-title)) {@include hook-inverse-article-title();} - } - - .uk-article-meta { - color: $inverse-article-meta-color; - @if(mixin-exists(hook-inverse-article-meta)) {@include hook-inverse-article-meta();} - } - -} -@mixin hook-background-misc(){} -@mixin hook-badge(){} -@mixin hook-badge-hover(){} -@mixin hook-badge-misc(){} -@mixin hook-inverse-badge(){} -@mixin hook-inverse-badge-hover(){} -@mixin hook-inverse-component-badge(){ - - .uk-badge { - background-color: $inverse-badge-background; - color: $inverse-badge-color !important; - @if(mixin-exists(hook-inverse-badge)) {@include hook-inverse-badge();} - } - - .uk-badge:hover, - .uk-badge:focus { - @if(mixin-exists(hook-inverse-badge-hover)) {@include hook-inverse-badge-hover();} - } - -} -@mixin hook-base-body(){} -@mixin hook-base-link(){} -@mixin hook-base-link-hover(){} -@mixin hook-base-code(){} -@mixin hook-base-heading(){} -@mixin hook-base-h1(){} -@mixin hook-base-h2(){} -@mixin hook-base-h3(){} -@mixin hook-base-h4(){} -@mixin hook-base-h5(){} -@mixin hook-base-h6(){} -@mixin hook-base-hr(){} -@mixin hook-base-blockquote(){} -@mixin hook-base-blockquote-footer(){} -@mixin hook-base-pre(){} -@mixin hook-base-misc(){} -@mixin hook-inverse-base-link(){} -@mixin hook-inverse-base-link-hover(){} -@mixin hook-inverse-base-code(){} -@mixin hook-inverse-base-heading(){} -@mixin hook-inverse-base-h1(){} -@mixin hook-inverse-base-h2(){} -@mixin hook-inverse-base-h3(){} -@mixin hook-inverse-base-h4(){} -@mixin hook-inverse-base-h5(){} -@mixin hook-inverse-base-h6(){} -@mixin hook-inverse-base-blockquote(){} -@mixin hook-inverse-base-blockquote-footer(){} -@mixin hook-inverse-base-hr(){} -@mixin hook-inverse-component-base(){ - - color: $inverse-base-color; - - // Base - // ======================================================================== - - // - // Link - // - - a, - .uk-link { - color: $inverse-base-link-color; - @if(mixin-exists(hook-inverse-base-link)) {@include hook-inverse-base-link();} - } - - a:hover, - .uk-link:hover, - .uk-link-toggle:hover .uk-link, - .uk-link-toggle:focus .uk-link { - color: $inverse-base-link-hover-color; - @if(mixin-exists(hook-inverse-base-link-hover)) {@include hook-inverse-base-link-hover();} - } - - // - // Code - // - - :not(pre) > code, - :not(pre) > kbd, - :not(pre) > samp { - color: $inverse-base-code-color; - @if(mixin-exists(hook-inverse-base-code)) {@include hook-inverse-base-code();} - } - - // - // Emphasize - // - - em { color: $inverse-base-em-color; } - - // - // Headings - // - - h1, .uk-h1, - h2, .uk-h2, - h3, .uk-h3, - h4, .uk-h4, - h5, .uk-h5, - h6, .uk-h6, - .uk-heading-small, - .uk-heading-medium, - .uk-heading-large, - .uk-heading-xlarge, - .uk-heading-2xlarge { - color: $inverse-base-heading-color; - @if(mixin-exists(hook-inverse-base-heading)) {@include hook-inverse-base-heading();} - } - - h1, .uk-h1 { - @if(mixin-exists(hook-inverse-base-h1)) {@include hook-inverse-base-h1();} - } - - h2, .uk-h2 { - @if(mixin-exists(hook-inverse-base-h2)) {@include hook-inverse-base-h2();} - } - - h3, .uk-h3 { - @if(mixin-exists(hook-inverse-base-h3)) {@include hook-inverse-base-h3();} - } - - h4, .uk-h4 { - @if(mixin-exists(hook-inverse-base-h4)) {@include hook-inverse-base-h4();} - } - - h5, .uk-h5 { - @if(mixin-exists(hook-inverse-base-h5)) {@include hook-inverse-base-h5();} - } - - h6, .uk-h6 { - @if(mixin-exists(hook-inverse-base-h6)) {@include hook-inverse-base-h6();} - } - - // - // Blockquotes - // - - blockquote { - @if(mixin-exists(hook-inverse-base-blockquote)) {@include hook-inverse-base-blockquote();} - } - - blockquote footer { - @if(mixin-exists(hook-inverse-base-blockquote-footer)) {@include hook-inverse-base-blockquote-footer();} - } - - // - // Horizontal rules - // - - hr, .uk-hr { - border-top-color: $inverse-base-hr-border; - @if(mixin-exists(hook-inverse-base-hr)) {@include hook-inverse-base-hr();} - } - -} -@mixin hook-breadcrumb(){} -@mixin hook-breadcrumb-item(){} -@mixin hook-breadcrumb-item-hover(){} -@mixin hook-breadcrumb-item-disabled(){} -@mixin hook-breadcrumb-item-active(){} -@mixin hook-breadcrumb-divider(){} -@mixin hook-breadcrumb-misc(){} -@mixin hook-inverse-breadcrumb-item(){} -@mixin hook-inverse-breadcrumb-item-hover(){} -@mixin hook-inverse-breadcrumb-item-disabled(){} -@mixin hook-inverse-breadcrumb-item-active(){} -@mixin hook-inverse-breadcrumb-divider(){} -@mixin hook-inverse-component-breadcrumb(){ - - .uk-breadcrumb > * > * { - color: $inverse-breadcrumb-item-color; - @if(mixin-exists(hook-inverse-breadcrumb-item)) {@include hook-inverse-breadcrumb-item();} - } - - .uk-breadcrumb > * > :hover, - .uk-breadcrumb > * > :focus { - color: $inverse-breadcrumb-item-hover-color; - @if(mixin-exists(hook-inverse-breadcrumb-item-hover)) {@include hook-inverse-breadcrumb-item-hover();} - } - - - .uk-breadcrumb > .uk-disabled > * { - @if(mixin-exists(hook-inverse-breadcrumb-item-disabled)) {@include hook-inverse-breadcrumb-item-disabled();} - } - - .uk-breadcrumb > :last-child > * { - color: $inverse-breadcrumb-item-active-color; - @if(mixin-exists(hook-inverse-breadcrumb-item-active)) {@include hook-inverse-breadcrumb-item-active();} - } - - // - // Divider - // - - .uk-breadcrumb > :nth-child(n+2):not(.uk-first-column)::before { - color: $inverse-breadcrumb-divider-color; - @if(mixin-exists(hook-inverse-breadcrumb-divider)) {@include hook-inverse-breadcrumb-divider();} - } - -} -@mixin hook-button(){} -@mixin hook-button-hover(){} -@mixin hook-button-focus(){} -@mixin hook-button-active(){} -@mixin hook-button-default(){} -@mixin hook-button-default-hover(){} -@mixin hook-button-default-active(){} -@mixin hook-button-primary(){} -@mixin hook-button-primary-hover(){} -@mixin hook-button-primary-active(){} -@mixin hook-button-secondary(){} -@mixin hook-button-secondary-hover(){} -@mixin hook-button-secondary-active(){} -@mixin hook-button-danger(){} -@mixin hook-button-danger-hover(){} -@mixin hook-button-danger-active(){} -@mixin hook-button-disabled(){} -@mixin hook-button-small(){} -@mixin hook-button-large(){} -@mixin hook-button-text(){} -@mixin hook-button-text-hover(){} -@mixin hook-button-text-disabled(){} -@mixin hook-button-link(){} -@mixin hook-button-misc(){} -@mixin hook-inverse-button-default(){} -@mixin hook-inverse-button-default-hover(){} -@mixin hook-inverse-button-default-active(){} -@mixin hook-inverse-button-primary(){} -@mixin hook-inverse-button-primary-hover(){} -@mixin hook-inverse-button-primary-active(){} -@mixin hook-inverse-button-secondary(){} -@mixin hook-inverse-button-secondary-hover(){} -@mixin hook-inverse-button-secondary-active(){} -@mixin hook-inverse-button-text(){} -@mixin hook-inverse-button-text-hover(){} -@mixin hook-inverse-button-text-disabled(){} -@mixin hook-inverse-button-link(){} -@mixin hook-inverse-component-button(){ - - // - // Default - // - - .uk-button-default { - background-color: $inverse-button-default-background; - color: $inverse-button-default-color; - @if(mixin-exists(hook-inverse-button-default)) {@include hook-inverse-button-default();} - } - - .uk-button-default:hover, - .uk-button-default:focus { - background-color: $inverse-button-default-hover-background; - color: $inverse-button-default-hover-color; - @if(mixin-exists(hook-inverse-button-default-hover)) {@include hook-inverse-button-default-hover();} - } - - .uk-button-default:active, - .uk-button-default.uk-active { - background-color: $inverse-button-default-active-background; - color: $inverse-button-default-active-color; - @if(mixin-exists(hook-inverse-button-default-active)) {@include hook-inverse-button-default-active();} - } - - // - // Primary - // - - .uk-button-primary { - background-color: $inverse-button-primary-background; - color: $inverse-button-primary-color; - @if(mixin-exists(hook-inverse-button-primary)) {@include hook-inverse-button-primary();} - } - - .uk-button-primary:hover, - .uk-button-primary:focus { - background-color: $inverse-button-primary-hover-background; - color: $inverse-button-primary-hover-color; - @if(mixin-exists(hook-inverse-button-primary-hover)) {@include hook-inverse-button-primary-hover();} - } - - .uk-button-primary:active, - .uk-button-primary.uk-active { - background-color: $inverse-button-primary-active-background; - color: $inverse-button-primary-active-color; - @if(mixin-exists(hook-inverse-button-primary-active)) {@include hook-inverse-button-primary-active();} - } - - // - // Secondary - // - - .uk-button-secondary { - background-color: $inverse-button-secondary-background; - color: $inverse-button-secondary-color; - @if(mixin-exists(hook-inverse-button-secondary)) {@include hook-inverse-button-secondary();} - } - - .uk-button-secondary:hover, - .uk-button-secondary:focus { - background-color: $inverse-button-secondary-hover-background; - color: $inverse-button-secondary-hover-color; - @if(mixin-exists(hook-inverse-button-secondary-hover)) {@include hook-inverse-button-secondary-hover();} - } - - .uk-button-secondary:active, - .uk-button-secondary.uk-active { - background-color: $inverse-button-secondary-active-background; - color: $inverse-button-secondary-active-color; - @if(mixin-exists(hook-inverse-button-secondary-active)) {@include hook-inverse-button-secondary-active();} - } - - // - // Text - // - - .uk-button-text { - color: $inverse-button-text-color; - @if(mixin-exists(hook-inverse-button-text)) {@include hook-inverse-button-text();} - } - - .uk-button-text:hover, - .uk-button-text:focus { - color: $inverse-button-text-hover-color; - @if(mixin-exists(hook-inverse-button-text-hover)) {@include hook-inverse-button-text-hover();} - } - - .uk-button-text:disabled { - color: $inverse-button-text-disabled-color; - @if(mixin-exists(hook-inverse-button-text-disabled)) {@include hook-inverse-button-text-disabled();} - } - - // - // Link - // - - .uk-button-link { - color: $inverse-button-link-color; - @if(mixin-exists(hook-inverse-button-link)) {@include hook-inverse-button-link();} - } - - .uk-button-link:hover, - .uk-button-link:focus { color: $inverse-button-link-hover-color; } - - -} -@mixin hook-card(){} -@mixin hook-card-body(){} -@mixin hook-card-header(){} -@mixin hook-card-footer(){} -@mixin hook-card-media(){} -@mixin hook-card-media-top(){} -@mixin hook-card-media-bottom(){} -@mixin hook-card-media-left(){} -@mixin hook-card-media-right(){} -@mixin hook-card-title(){} -@mixin hook-card-badge(){} -@mixin hook-card-hover(){} -@mixin hook-card-default(){} -@mixin hook-card-default-title(){} -@mixin hook-card-default-hover(){} -@mixin hook-card-default-header(){} -@mixin hook-card-default-footer(){} -@mixin hook-card-primary(){} -@mixin hook-card-primary-title(){} -@mixin hook-card-primary-hover(){} -@mixin hook-card-secondary(){} -@mixin hook-card-secondary-title(){} -@mixin hook-card-secondary-hover(){} -@mixin hook-card-misc(){} -@mixin hook-inverse-card-badge(){} -@mixin hook-inverse-component-card(){ - - &.uk-card-badge { - background-color: $inverse-card-badge-background; - color: $inverse-card-badge-color; - @if(mixin-exists(hook-inverse-card-badge)) {@include hook-inverse-card-badge();} - } - -} -@mixin hook-close(){} -@mixin hook-close-hover(){} -@mixin hook-close-misc(){} -@mixin hook-inverse-close(){} -@mixin hook-inverse-close-hover(){} -@mixin hook-inverse-component-close(){ - - .uk-close { - color: $inverse-close-color; - @if(mixin-exists(hook-inverse-close)) {@include hook-inverse-close();} - } - - .uk-close:hover, - .uk-close:focus { - color: $inverse-close-hover-color; - @if(mixin-exists(hook-inverse-close-hover)) {@include hook-inverse-close-hover();} - } - -} -@mixin hook-column-misc(){} -@mixin hook-inverse-component-column(){ - - .uk-column-divider { column-rule-color: $inverse-column-divider-rule-color; } - -} -@mixin hook-comment(){} -@mixin hook-comment-body(){} -@mixin hook-comment-header(){} -@mixin hook-comment-title(){} -@mixin hook-comment-meta(){} -@mixin hook-comment-avatar(){} -@mixin hook-comment-list-adjacent(){} -@mixin hook-comment-list-sub(){} -@mixin hook-comment-list-sub-adjacent(){} -@mixin hook-comment-primary(){} -@mixin hook-comment-misc(){} -@mixin hook-container-misc(){} -@mixin hook-countdown(){} -@mixin hook-countdown-item(){} -@mixin hook-countdown-number(){} -@mixin hook-countdown-separator(){} -@mixin hook-countdown-label(){} -@mixin hook-countdown-misc(){} -@mixin hook-inverse-countdown-item(){} -@mixin hook-inverse-countdown-number(){} -@mixin hook-inverse-countdown-separator(){} -@mixin hook-inverse-countdown-label(){} -@mixin hook-inverse-component-countdown(){ - - .uk-countdown-number, - .uk-countdown-separator { - @if(mixin-exists(hook-inverse-countdown-item)) {@include hook-inverse-countdown-item();} - } - - .uk-countdown-number { - @if(mixin-exists(hook-inverse-countdown-number)) {@include hook-inverse-countdown-number();} - } - - .uk-countdown-separator { - @if(mixin-exists(hook-inverse-countdown-separator)) {@include hook-inverse-countdown-separator();} - } - - .uk-countdown-label { - @if(mixin-exists(hook-inverse-countdown-label)) {@include hook-inverse-countdown-label();} - } - -} -@mixin hook-cover-misc(){} -@mixin hook-description-list-term(){} -@mixin hook-description-list-description(){} -@mixin hook-description-list-divider-term(){} -@mixin hook-description-list-misc(){} -@mixin svg-fill($src, $color-default, $color-new, $property: background-image){ - - $escape-color-default: escape($color-default) !default; - $escape-color-new: escape("#{$color-new}") !default; - - $data-uri: data-uri('image/svg+xml;charset=UTF-8', "#{$src}") !default; - $replace-src: replace("#{$data-uri}", "#{$escape-color-default}", "#{$escape-color-new}", "g") !default; - - #{$property}: unquote($replace-src); -} -@mixin hook-divider-icon(){} -@mixin hook-divider-icon-line(){} -@mixin hook-divider-icon-line-left(){} -@mixin hook-divider-icon-line-right(){} -@mixin hook-divider-small(){} -@mixin hook-divider-vertical(){} -@mixin hook-divider-misc(){} -@mixin hook-inverse-divider-icon(){} -@mixin hook-inverse-divider-icon-line(){} -@mixin hook-inverse-divider-small(){} -@mixin hook-inverse-divider-vertical(){} -@mixin hook-inverse-component-divider(){ - - .uk-divider-icon { - @include svg-fill($internal-divider-icon-image, "#000", $inverse-divider-icon-color); - @if(mixin-exists(hook-inverse-divider-icon)) {@include hook-inverse-divider-icon();} - } - - .uk-divider-icon::before, - .uk-divider-icon::after { - border-bottom-color: $inverse-divider-icon-line-border; - @if(mixin-exists(hook-inverse-divider-icon-line)) {@include hook-inverse-divider-icon-line();} - } - - .uk-divider-small::after { - border-top-color: $inverse-divider-small-border; - @if(mixin-exists(hook-inverse-divider-small)) {@include hook-inverse-divider-small();} - } - - .uk-divider-vertical { - border-left-color: $inverse-divider-vertical-border; - @if(mixin-exists(hook-inverse-divider-vertical)) {@include hook-inverse-divider-vertical();} - } - -} -@mixin hook-dotnav(){} -@mixin hook-dotnav-item(){} -@mixin hook-dotnav-item-hover(){} -@mixin hook-dotnav-item-onclick(){} -@mixin hook-dotnav-item-active(){} -@mixin hook-dotnav-misc(){} -@mixin hook-inverse-dotnav-item(){} -@mixin hook-inverse-dotnav-item-hover(){} -@mixin hook-inverse-dotnav-item-onclick(){} -@mixin hook-inverse-dotnav-item-active(){} -@mixin hook-inverse-component-dotnav(){ - - .uk-dotnav > * > * { - background-color: $inverse-dotnav-item-background; - @if(mixin-exists(hook-inverse-dotnav-item)) {@include hook-inverse-dotnav-item();} - } - - .uk-dotnav > * > :hover, - .uk-dotnav > * > :focus { - background-color: $inverse-dotnav-item-hover-background; - @if(mixin-exists(hook-inverse-dotnav-item-hover)) {@include hook-inverse-dotnav-item-hover();} - } - - .uk-dotnav > * > :active { - background-color: $inverse-dotnav-item-onclick-background; - @if(mixin-exists(hook-inverse-dotnav-item-onclick)) {@include hook-inverse-dotnav-item-onclick();} - } - - .uk-dotnav > .uk-active > * { - background-color: $inverse-dotnav-item-active-background; - @if(mixin-exists(hook-inverse-dotnav-item-active)) {@include hook-inverse-dotnav-item-active();} - } - -} -@mixin hook-drop-misc(){} -@mixin hook-dropdown(){} -@mixin hook-dropdown-nav(){} -@mixin hook-dropdown-nav-item(){} -@mixin hook-dropdown-nav-item-hover(){} -@mixin hook-dropdown-nav-header(){} -@mixin hook-dropdown-nav-divider(){} -@mixin hook-dropdown-misc(){} -@mixin hook-flex-misc(){} -@mixin hook-form-range(){} -@mixin hook-form-range-thumb(){} -@mixin hook-form-range-track(){} -@mixin hook-form-range-track-focus(){} -@mixin hook-form-range-misc(){} -@mixin hook-form(){} -@mixin hook-form-single-line(){} -@mixin hook-form-multi-line(){} -@mixin hook-form-focus(){} -@mixin hook-form-disabled(){} -@mixin hook-form-danger(){} -@mixin hook-form-success(){} -@mixin hook-form-blank(){} -@mixin hook-form-blank-focus(){} -@mixin hook-form-radio(){} -@mixin hook-form-radio-focus(){} -@mixin hook-form-radio-checked(){} -@mixin hook-form-radio-checked-focus(){} -@mixin hook-form-radio-disabled(){} -@mixin hook-form-legend(){} -@mixin hook-form-label(){} -@mixin hook-form-stacked-label(){} -@mixin hook-form-horizontal-label(){} -@mixin hook-form-misc(){} -@mixin hook-inverse-form(){} -@mixin hook-inverse-form-focus(){} -@mixin hook-inverse-form-radio(){} -@mixin hook-inverse-form-radio-focus(){} -@mixin hook-inverse-form-radio-checked(){} -@mixin hook-inverse-form-radio-checked-focus(){} -@mixin hook-inverse-form-label(){} -@mixin hook-inverse-component-form(){ - - .uk-input, - .uk-select, - .uk-textarea { - background-color: $inverse-form-background; - color: $inverse-form-color; - background-clip: padding-box; - @if(mixin-exists(hook-inverse-form)) {@include hook-inverse-form();} - - &:focus { - background-color: $inverse-form-focus-background; - color: $inverse-form-focus-color; - @if(mixin-exists(hook-inverse-form-focus)) {@include hook-inverse-form-focus();} - } - } - - // - // Placeholder - // - - .uk-input::-ms-input-placeholder { color: $inverse-form-placeholder-color !important; } - .uk-input::placeholder { color: $inverse-form-placeholder-color; } - - .uk-textarea::-ms-input-placeholder { color: $inverse-form-placeholder-color !important; } - .uk-textarea::placeholder { color: $inverse-form-placeholder-color; } - - // - // Select - // - - .uk-select:not([multiple]):not([size]) { @include svg-fill($internal-form-select-image, "#000", $inverse-form-select-icon-color); } - - // - // Datalist - // - - .uk-input[list]:hover, - .uk-input[list]:focus { @include svg-fill($internal-form-datalist-image, "#000", $inverse-form-datalist-icon-color); } - - // - // Radio and checkbox - // - - .uk-radio, - .uk-checkbox { - background-color: $inverse-form-radio-background; - @if(mixin-exists(hook-inverse-form-radio)) {@include hook-inverse-form-radio();} - } - - // Focus - .uk-radio:focus, - .uk-checkbox:focus { - background-color: $inverse-form-radio-focus-background; - @if(mixin-exists(hook-inverse-form-radio-focus)) {@include hook-inverse-form-radio-focus();} - } - - // Checked - .uk-radio:checked, - .uk-checkbox:checked, - .uk-checkbox:indeterminate { - background-color: $inverse-form-radio-checked-background; - @if(mixin-exists(hook-inverse-form-radio-checked)) {@include hook-inverse-form-radio-checked();} - } - - // Focus - .uk-radio:checked:focus, - .uk-checkbox:checked:focus, - .uk-checkbox:indeterminate:focus { - background-color: $inverse-form-radio-checked-focus-background; - @if(mixin-exists(hook-inverse-form-radio-checked-focus)) {@include hook-inverse-form-radio-checked-focus();} - } - - // Icon - .uk-radio:checked { @include svg-fill($internal-form-radio-image, "#000", $inverse-form-radio-checked-icon-color); } - .uk-checkbox:checked { @include svg-fill($internal-form-checkbox-image, "#000", $inverse-form-radio-checked-icon-color); } - .uk-checkbox:indeterminate { @include svg-fill($internal-form-checkbox-indeterminate-image, "#000", $inverse-form-radio-checked-icon-color); } - - // Label - .uk-form-label { - @if(mixin-exists(hook-inverse-form-label)) {@include hook-inverse-form-label();} - } - - // Icon - .uk-form-icon { color: $inverse-form-icon-color; } - .uk-form-icon:hover { color: $inverse-form-icon-hover-color; } - -} -@mixin hook-grid-divider-horizontal(){} -@mixin hook-grid-divider-vertical(){} -@mixin hook-grid-misc(){} -@mixin hook-inverse-grid-divider-horizontal(){} -@mixin hook-inverse-grid-divider-vertical(){} -@mixin hook-inverse-component-grid(){ - - .uk-grid-divider > :not(.uk-first-column)::before { - border-left-color: $inverse-grid-divider-border; - @if(mixin-exists(hook-inverse-grid-divider-horizontal)) {@include hook-inverse-grid-divider-horizontal();} - } - - .uk-grid-divider.uk-grid-stack > .uk-grid-margin::before { - border-top-color: $inverse-grid-divider-border; - @if(mixin-exists(hook-inverse-grid-divider-vertical)) {@include hook-inverse-grid-divider-vertical();} - } - -} -@mixin hook-heading-small(){} -@mixin hook-heading-medium(){} -@mixin hook-heading-large(){} -@mixin hook-heading-xlarge(){} -@mixin hook-heading-2xlarge(){} -@mixin hook-heading-primary(){} -@mixin hook-heading-hero(){} -@mixin hook-heading-divider(){} -@mixin hook-heading-bullet(){} -@mixin hook-heading-line(){} -@mixin hook-heading-misc(){} -@mixin hook-inverse-heading-small(){} -@mixin hook-inverse-heading-medium(){} -@mixin hook-inverse-heading-large(){} -@mixin hook-inverse-heading-xlarge(){} -@mixin hook-inverse-heading-2xlarge(){} -@mixin hook-inverse-heading-primary(){} -@mixin hook-inverse-heading-hero(){} -@mixin hook-inverse-heading-divider(){} -@mixin hook-inverse-heading-bullet(){} -@mixin hook-inverse-heading-line(){} -@mixin hook-inverse-component-heading(){ - - .uk-heading-small { - @if(mixin-exists(hook-inverse-heading-small)) {@include hook-inverse-heading-small();} - } - - .uk-heading-medium { - @if(mixin-exists(hook-inverse-heading-medium)) {@include hook-inverse-heading-medium();} - } - - .uk-heading-large { - @if(mixin-exists(hook-inverse-heading-large)) {@include hook-inverse-heading-large();} - } - - .uk-heading-xlarge { - @if(mixin-exists(hook-inverse-heading-xlarge)) {@include hook-inverse-heading-xlarge();} - } - - .uk-heading-2xlarge { - @if(mixin-exists(hook-inverse-heading-2xlarge)) {@include hook-inverse-heading-2xlarge();} - } - - @if ($deprecated == true) { .uk-heading-primary { @if (mixin-exists(hook-inverse-heading-primary)) {@include hook-inverse-heading-primary();}}} - - @if ($deprecated == true) { .uk-heading-hero { @if (mixin-exists(hook-inverse-heading-hero)) {@include hook-inverse-heading-hero();}}} - - .uk-heading-divider { - border-bottom-color: $inverse-heading-divider-border; - @if(mixin-exists(hook-inverse-heading-divider)) {@include hook-inverse-heading-divider();} - } - - .uk-heading-bullet::before { - border-left-color: $inverse-heading-bullet-border; - @if(mixin-exists(hook-inverse-heading-bullet)) {@include hook-inverse-heading-bullet();} - } - - .uk-heading-line > ::before, - .uk-heading-line > ::after { - border-bottom-color: $inverse-heading-line-border; - @if(mixin-exists(hook-inverse-heading-line)) {@include hook-inverse-heading-line();} - } - -} -@mixin hook-height-misc(){} -@mixin hook-icon-link(){} -@mixin hook-icon-link-hover(){} -@mixin hook-icon-link-active(){} -@mixin hook-icon-button(){} -@mixin hook-icon-button-hover(){} -@mixin hook-icon-button-active(){} -@mixin hook-icon-misc(){} -@mixin hook-inverse-icon-link(){} -@mixin hook-inverse-icon-link-hover(){} -@mixin hook-inverse-icon-link-active(){} -@mixin hook-inverse-icon-button(){} -@mixin hook-inverse-icon-button-hover(){} -@mixin hook-inverse-icon-button-active(){} -@mixin hook-inverse-component-icon(){ - - // - // Link - // - - .uk-icon-link { - color: $inverse-icon-link-color; - @if(mixin-exists(hook-inverse-icon-link)) {@include hook-inverse-icon-link();} - } - - .uk-icon-link:hover, - .uk-icon-link:focus { - color: $inverse-icon-link-hover-color; - @if(mixin-exists(hook-inverse-icon-link-hover)) {@include hook-inverse-icon-link-hover();} - } - - .uk-icon-link:active, - .uk-active > .uk-icon-link { - color: $inverse-icon-link-active-color; - @if(mixin-exists(hook-inverse-icon-link-active)) {@include hook-inverse-icon-link-active();} - } - - // - // Button - // - - .uk-icon-button { - background-color: $inverse-icon-button-background; - color: $inverse-icon-button-color; - @if(mixin-exists(hook-inverse-icon-button)) {@include hook-inverse-icon-button();} - } - - .uk-icon-button:hover, - .uk-icon-button:focus { - background-color: $inverse-icon-button-hover-background; - color: $inverse-icon-button-hover-color; - @if(mixin-exists(hook-inverse-icon-button-hover)) {@include hook-inverse-icon-button-hover();} - } - - .uk-icon-button:active { - background-color: $inverse-icon-button-active-background; - color: $inverse-icon-button-active-color; - @if(mixin-exists(hook-inverse-icon-button-active)) {@include hook-inverse-icon-button-active();} - } - -} -@mixin hook-iconnav(){} -@mixin hook-iconnav-item(){} -@mixin hook-iconnav-item-hover(){} -@mixin hook-iconnav-item-active(){} -@mixin hook-iconnav-misc(){} -@mixin hook-inverse-iconnav-item(){} -@mixin hook-inverse-iconnav-item-hover(){} -@mixin hook-inverse-iconnav-item-active(){} -@mixin hook-inverse-component-iconnav(){ - - .uk-iconnav > * > a { - color: $inverse-iconnav-item-color; - @if(mixin-exists(hook-inverse-iconnav-item)) {@include hook-inverse-iconnav-item();} - } - - .uk-iconnav > * > a:hover, - .uk-iconnav > * > a:focus { - color: $inverse-iconnav-item-hover-color; - @if(mixin-exists(hook-inverse-iconnav-item-hover)) {@include hook-inverse-iconnav-item-hover();} - } - - .uk-iconnav > .uk-active > a { - color: $inverse-iconnav-item-active-color; - @if(mixin-exists(hook-inverse-iconnav-item-active)) {@include hook-inverse-iconnav-item-active();} - } - -} -@mixin hook-inverse-component-link(){ - - a.uk-link-muted, - .uk-link-muted a { - color: $inverse-link-muted-color; - @if(mixin-exists(hook-inverse-link-muted)) {@include hook-inverse-link-muted();} - } - - a.uk-link-muted:hover, - .uk-link-muted a:hover, - .uk-link-toggle:hover .uk-link-muted, - .uk-link-toggle:focus .uk-link-muted { - color: $inverse-link-muted-hover-color; - @if(mixin-exists(hook-inverse-link-muted-hover)) {@include hook-inverse-link-muted-hover();} - } - - a.uk-link-text:hover, - .uk-link-text a:hover, - .uk-link-toggle:hover .uk-link-text, - .uk-link-toggle:focus .uk-link-text { - color: $inverse-link-text-hover-color; - @if(mixin-exists(hook-inverse-link-text-hover)) {@include hook-inverse-link-text-hover();} - } - - a.uk-link-heading:hover, - .uk-link-heading a:hover, - .uk-link-toggle:hover .uk-link-heading, - .uk-link-toggle:focus .uk-link-heading { - color: $inverse-link-heading-hover-color; - @if(mixin-exists(hook-inverse-link-heading-hover)) {@include hook-inverse-link-heading-hover();} - } - -} -@mixin hook-inverse-component-list(){ - - .uk-list-muted > ::before { color: $inverse-list-muted-color !important; } - .uk-list-emphasis > ::before { color: $inverse-list-emphasis-color !important; } - .uk-list-primary > ::before { color: $inverse-list-primary-color !important; } - .uk-list-secondary > ::before { color: $inverse-list-secondary-color !important; } - - .uk-list-bullet > ::before { - @include svg-fill($internal-list-bullet-image, "#000", $inverse-list-bullet-icon-color); - } - - .uk-list-divider > :nth-child(n+2) { - border-top-color: $inverse-list-divider-border; - @if(mixin-exists(hook-inverse-list-divider)) {@include hook-inverse-list-divider();} - } - - .uk-list-striped > * { - @if(mixin-exists(hook-inverse-list-striped)) {@include hook-inverse-list-striped();} - } - - .uk-list-striped > :nth-of-type(odd) { background-color: $inverse-list-striped-background; } - -} -@mixin hook-inverse-component-totop(){ - - .uk-totop { - color: $inverse-totop-color; - @if(mixin-exists(hook-inverse-totop)) {@include hook-inverse-totop();} - } - - .uk-totop:hover, - .uk-totop:focus { - color: $inverse-totop-hover-color; - @if(mixin-exists(hook-inverse-totop-hover)) {@include hook-inverse-totop-hover();} - } - - .uk-totop:active { - color: $inverse-totop-active-color; - @if(mixin-exists(hook-inverse-totop-active)) {@include hook-inverse-totop-active();} - } - -} -@mixin hook-inverse-component-label(){ - - .uk-label { - background-color: $inverse-label-background; - color: $inverse-label-color; - @if(mixin-exists(hook-inverse-label)) {@include hook-inverse-label();} - } - -} -@mixin hook-inverse-component-search(){ - - // - // Input - // - - .uk-search-input { color: $inverse-search-color; } - - .uk-search-input:-ms-input-placeholder { color: $inverse-search-placeholder-color !important; } - .uk-search-input::placeholder { color: $inverse-search-placeholder-color; } - - - // - // Icon - // - - .uk-search .uk-search-icon { color: $inverse-search-icon-color; } - .uk-search .uk-search-icon:hover { color: $inverse-search-icon-color; } - - // - // Style modifier - // - - .uk-search-default .uk-search-input { - background-color: $inverse-search-default-background; - @if(mixin-exists(hook-inverse-search-default-input)) {@include hook-inverse-search-default-input();} - } - - .uk-search-default .uk-search-input:focus { - background-color: $inverse-search-default-focus-background; - @if(mixin-exists(hook-inverse-search-default-input-focus)) {@include hook-inverse-search-default-input-focus();} - } - - .uk-search-navbar .uk-search-input { - background-color: $inverse-search-navbar-background; - @if(mixin-exists(hook-inverse-search-navbar-input)) {@include hook-inverse-search-navbar-input();} - } - - .uk-search-large .uk-search-input { - background-color: $inverse-search-large-background; - @if(mixin-exists(hook-inverse-search-large-input)) {@include hook-inverse-search-large-input();} - } - - // - // Toggle - // - - .uk-search-toggle { - color: $inverse-search-toggle-color; - @if(mixin-exists(hook-inverse-search-toggle)) {@include hook-inverse-search-toggle();} - } - - .uk-search-toggle:hover, - .uk-search-toggle:focus { - color: $inverse-search-toggle-hover-color; - @if(mixin-exists(hook-inverse-search-toggle-hover)) {@include hook-inverse-search-toggle-hover();} - } - -} -@mixin hook-inverse-component-nav(){ - - // - // Parent icon modifier - // - - .uk-nav-parent-icon > .uk-parent > a::after { - @include svg-fill($internal-nav-parent-close-image, "#000", $inverse-nav-parent-icon-color); - @if(mixin-exists(hook-inverse-nav-parent-icon)) {@include hook-inverse-nav-parent-icon();} - } - - .uk-nav-parent-icon > .uk-parent.uk-open > a::after { @include svg-fill($internal-nav-parent-open-image, "#000", $inverse-nav-parent-icon-color); } - - // - // Default - // - - .uk-nav-default > li > a { - color: $inverse-nav-default-item-color; - @if(mixin-exists(hook-inverse-nav-default-item)) {@include hook-inverse-nav-default-item();} - } - - .uk-nav-default > li > a:hover, - .uk-nav-default > li > a:focus { - color: $inverse-nav-default-item-hover-color; - @if(mixin-exists(hook-inverse-nav-default-item-hover)) {@include hook-inverse-nav-default-item-hover();} - } - - .uk-nav-default > li.uk-active > a { - color: $inverse-nav-default-item-active-color; - @if(mixin-exists(hook-inverse-nav-default-item-active)) {@include hook-inverse-nav-default-item-active();} - } - - .uk-nav-default .uk-nav-header { - color: $inverse-nav-default-header-color; - @if(mixin-exists(hook-inverse-nav-default-header)) {@include hook-inverse-nav-default-header();} - } - - .uk-nav-default .uk-nav-divider { - border-top-color: $inverse-nav-default-divider-border; - @if(mixin-exists(hook-inverse-nav-default-divider)) {@include hook-inverse-nav-default-divider();} - } - - .uk-nav-default .uk-nav-sub a { color: $inverse-nav-default-sublist-item-color; } - - .uk-nav-default .uk-nav-sub a:hover, - .uk-nav-default .uk-nav-sub a:focus { color: $inverse-nav-default-sublist-item-hover-color; } - - .uk-nav-default .uk-nav-sub li.uk-active > a { color: $inverse-nav-default-sublist-item-active-color; } - - // - // Primary - // - - .uk-nav-primary > li > a { - color: $inverse-nav-primary-item-color; - @if(mixin-exists(hook-inverse-nav-primary-item)) {@include hook-inverse-nav-primary-item();} - } - - .uk-nav-primary > li > a:hover, - .uk-nav-primary > li > a:focus { - color: $inverse-nav-primary-item-hover-color; - @if(mixin-exists(hook-inverse-nav-primary-item-hover)) {@include hook-inverse-nav-primary-item-hover();} - } - - .uk-nav-primary > li.uk-active > a { - color: $inverse-nav-primary-item-active-color; - @if(mixin-exists(hook-inverse-nav-primary-item-active)) {@include hook-inverse-nav-primary-item-active();} - } - - .uk-nav-primary .uk-nav-header { - color: $inverse-nav-primary-header-color; - @if(mixin-exists(hook-inverse-nav-primary-header)) {@include hook-inverse-nav-primary-header();} - } - - .uk-nav-primary .uk-nav-divider { - border-top-color: $inverse-nav-primary-divider-border; - @if(mixin-exists(hook-inverse-nav-primary-divider)) {@include hook-inverse-nav-primary-divider();} - } - - .uk-nav-primary .uk-nav-sub a { color: $inverse-nav-primary-sublist-item-color; } - - .uk-nav-primary .uk-nav-sub a:hover, - .uk-nav-primary .uk-nav-sub a:focus { color: $inverse-nav-primary-sublist-item-hover-color; } - - .uk-nav-primary .uk-nav-sub li.uk-active > a { color: $inverse-nav-primary-sublist-item-active-color; } - - // - // Dividers - // - - .uk-nav.uk-nav-divider > :not(.uk-nav-divider) + :not(.uk-nav-header, .uk-nav-divider) { - border-top-color: $inverse-nav-dividers-border; - @if(mixin-exists(hook-nav-dividers)) {@include hook-nav-dividers();} - } - -} -@mixin hook-inverse-component-navbar(){ - - .uk-navbar-nav > li > a { - color: $inverse-navbar-nav-item-color; - @if(mixin-exists(hook-inverse-navbar-nav-item)) {@include hook-inverse-navbar-nav-item();} - } - - .uk-navbar-nav > li:hover > a, - .uk-navbar-nav > li > a:focus, - .uk-navbar-nav > li > a.uk-open { - color: $inverse-navbar-nav-item-hover-color; - @if(mixin-exists(hook-inverse-navbar-nav-item-hover)) {@include hook-inverse-navbar-nav-item-hover();} - } - - .uk-navbar-nav > li > a:active { - color: $inverse-navbar-nav-item-onclick-color; - @if(mixin-exists(hook-inverse-navbar-nav-item-onclick)) {@include hook-inverse-navbar-nav-item-onclick();} - } - - .uk-navbar-nav > li.uk-active > a { - color: $inverse-navbar-nav-item-active-color; - @if(mixin-exists(hook-inverse-navbar-nav-item-active)) {@include hook-inverse-navbar-nav-item-active();} - } - - .uk-navbar-item { - color: $inverse-navbar-item-color; - @if(mixin-exists(hook-inverse-navbar-item)) {@include hook-inverse-navbar-item();} - } - - .uk-navbar-toggle { - color: $inverse-navbar-toggle-color; - @if(mixin-exists(hook-inverse-navbar-toggle)) {@include hook-inverse-navbar-toggle();} - } - - .uk-navbar-toggle:hover, - .uk-navbar-toggle:focus, - .uk-navbar-toggle.uk-open { - color: $inverse-navbar-toggle-hover-color; - @if(mixin-exists(hook-inverse-navbar-toggle-hover)) {@include hook-inverse-navbar-toggle-hover();} - } - -} -@mixin hook-inverse-component-subnav(){ - - .uk-subnav > * > :first-child { - color: $inverse-subnav-item-color; - @if(mixin-exists(hook-inverse-subnav-item)) {@include hook-inverse-subnav-item();} - } - - .uk-subnav > * > a:hover, - .uk-subnav > * > a:focus { - color: $inverse-subnav-item-hover-color; - @if(mixin-exists(hook-inverse-subnav-item-hover)) {@include hook-inverse-subnav-item-hover();} - } - - .uk-subnav > .uk-active > a { - color: $inverse-subnav-item-active-color; - @if(mixin-exists(hook-inverse-subnav-item-active)) {@include hook-inverse-subnav-item-active();} - } - - // - // Divider - // - - .uk-subnav-divider > :nth-child(n+2):not(.uk-first-column)::before { - border-left-color: $inverse-subnav-divider-border; - @if(mixin-exists(hook-inverse-subnav-divider)) {@include hook-inverse-subnav-divider();} - } - - // - // Pill - // - - .uk-subnav-pill > * > :first-child { - background-color: $inverse-subnav-pill-item-background; - color: $inverse-subnav-pill-item-color; - @if(mixin-exists(hook-inverse-subnav-pill-item)) {@include hook-inverse-subnav-pill-item();} - } - - .uk-subnav-pill > * > a:hover, - .uk-subnav-pill > * > a:focus { - background-color: $inverse-subnav-pill-item-hover-background; - color: $inverse-subnav-pill-item-hover-color; - @if(mixin-exists(hook-inverse-subnav-pill-item-hover)) {@include hook-inverse-subnav-pill-item-hover();} - } - - .uk-subnav-pill > * > a:active { - background-color: $inverse-subnav-pill-item-onclick-background; - color: $inverse-subnav-pill-item-onclick-color; - @if(mixin-exists(hook-inverse-subnav-pill-item-onclick)) {@include hook-inverse-subnav-pill-item-onclick();} - } - - .uk-subnav-pill > .uk-active > a { - background-color: $inverse-subnav-pill-item-active-background; - color: $inverse-subnav-pill-item-active-color; - @if(mixin-exists(hook-inverse-subnav-pill-item-active)) {@include hook-inverse-subnav-pill-item-active();} - } - - // - // Disabled - // - - .uk-subnav > .uk-disabled > a { - color: $inverse-subnav-item-disabled-color; - @if(mixin-exists(hook-inverse-subnav-item-disabled)) {@include hook-inverse-subnav-item-disabled();} - } - -} -@mixin hook-inverse-component-pagination(){ - - .uk-pagination > * > * { - color: $inverse-pagination-item-color; - @if(mixin-exists(hook-inverse-pagination-item)) {@include hook-inverse-pagination-item();} - } - - .uk-pagination > * > :hover, - .uk-pagination > * > :focus { - color: $inverse-pagination-item-hover-color; - @if(mixin-exists(hook-inverse-pagination-item-hover)) {@include hook-inverse-pagination-item-hover();} - } - - .uk-pagination > .uk-active > * { - color: $inverse-pagination-item-active-color; - @if(mixin-exists(hook-inverse-pagination-item-active)) {@include hook-inverse-pagination-item-active();} - } - - .uk-pagination > .uk-disabled > * { - color: $inverse-pagination-item-disabled-color; - @if(mixin-exists(hook-inverse-pagination-item-disabled)) {@include hook-inverse-pagination-item-disabled();} - } - -} -@mixin hook-inverse-component-tab(){ - - .uk-tab { - @if(mixin-exists(hook-inverse-tab)) {@include hook-inverse-tab();} - } - - .uk-tab > * > a { - color: $inverse-tab-item-color; - @if(mixin-exists(hook-inverse-tab-item)) {@include hook-inverse-tab-item();} - } - - .uk-tab > * > a:hover, - .uk-tab > * > a:focus{ - color: $inverse-tab-item-hover-color; - @if(mixin-exists(hook-inverse-tab-item-hover)) {@include hook-inverse-tab-item-hover();} - } - - .uk-tab > .uk-active > a { - color: $inverse-tab-item-active-color; - @if(mixin-exists(hook-inverse-tab-item-active)) {@include hook-inverse-tab-item-active();} - } - - .uk-tab > .uk-disabled > a { - color: $inverse-tab-item-disabled-color; - @if(mixin-exists(hook-inverse-tab-item-disabled)) {@include hook-inverse-tab-item-disabled();} - } - -} -@mixin hook-inverse-component-slidenav(){ - - .uk-slidenav { - color: $inverse-slidenav-color; - @if(mixin-exists(hook-inverse-slidenav)) {@include hook-inverse-slidenav();} - } - - .uk-slidenav:hover, - .uk-slidenav:focus { - color: $inverse-slidenav-hover-color; - @if(mixin-exists(hook-inverse-slidenav-hover)) {@include hook-inverse-slidenav-hover();} - } - - .uk-slidenav:active { - color: $inverse-slidenav-active-color; - @if(mixin-exists(hook-inverse-slidenav-active)) {@include hook-inverse-slidenav-active();} - } - -} -@mixin hook-inverse-component-text(){ - - .uk-text-lead { - color: $inverse-text-lead-color; - @if(mixin-exists(hook-inverse-text-lead)) {@include hook-inverse-text-lead();} - } - - .uk-text-meta { - color: $inverse-text-meta-color; - @if(mixin-exists(hook-inverse-text-meta)) {@include hook-inverse-text-meta();} - } - - .uk-text-muted { color: $inverse-text-muted-color !important; } - .uk-text-emphasis { color: $inverse-text-emphasis-color !important; } - .uk-text-primary { color: $inverse-text-primary-color !important; } - .uk-text-secondary { color: $inverse-text-secondary-color !important; } - -} -@mixin hook-inverse-component-utility(){ - - .uk-dropcap::first-letter, - .uk-dropcap p:first-of-type::first-letter { - @if(mixin-exists(hook-inverse-dropcap)) {@include hook-inverse-dropcap();} - } - - .uk-logo { - color: $inverse-logo-color; - @if(mixin-exists(hook-inverse-logo)) {@include hook-inverse-logo();} - } - - .uk-logo:hover, - .uk-logo:focus { - color: $inverse-logo-hover-color; - @if(mixin-exists(hook-inverse-logo-hover)) {@include hook-inverse-logo-hover();} - } - - .uk-logo > :not(.uk-logo-inverse):not(:only-of-type) { display: none; } - .uk-logo-inverse { display: inline; } - -} -@mixin hook-inverse(){ - @include hook-inverse-component-base(); - @include hook-inverse-component-link(); - @include hook-inverse-component-heading(); - @include hook-inverse-component-divider(); - @include hook-inverse-component-list(); - @include hook-inverse-component-icon(); - @include hook-inverse-component-form(); - @include hook-inverse-component-button(); - @include hook-inverse-component-grid(); - @include hook-inverse-component-close(); - @include hook-inverse-component-totop(); - @include hook-inverse-component-badge(); - @include hook-inverse-component-label(); - @include hook-inverse-component-article(); - @include hook-inverse-component-search(); - @include hook-inverse-component-nav(); - @include hook-inverse-component-navbar(); - @include hook-inverse-component-subnav(); - @include hook-inverse-component-breadcrumb(); - @include hook-inverse-component-pagination(); - @include hook-inverse-component-tab(); - @include hook-inverse-component-slidenav(); - @include hook-inverse-component-dotnav(); - @include hook-inverse-component-accordion(); - @include hook-inverse-component-iconnav(); - @include hook-inverse-component-text(); - @include hook-inverse-component-column(); - @include hook-inverse-component-utility(); -} -@mixin hook-label(){} -@mixin hook-label-success(){} -@mixin hook-label-warning(){} -@mixin hook-label-danger(){} -@mixin hook-label-misc(){} -@mixin hook-inverse-label(){} -@mixin hook-leader(){} -@mixin hook-leader-misc(){} -@mixin hook-inverse-leader(){} -@mixin hook-inverse-component-leader(){ - - .uk-leader-fill::after { - @if(mixin-exists(hook-inverse-leader)) {@include hook-inverse-leader();} - } - -} -@mixin hook-lightbox(){} -@mixin hook-lightbox-item(){} -@mixin hook-lightbox-toolbar(){} -@mixin hook-lightbox-toolbar-icon(){} -@mixin hook-lightbox-toolbar-icon-hover(){} -@mixin hook-lightbox-button(){} -@mixin hook-lightbox-button-hover(){} -@mixin hook-lightbox-button-active(){} -@mixin hook-lightbox-misc(){} -@mixin hook-link-muted(){} -@mixin hook-link-muted-hover(){} -@mixin hook-link-text(){} -@mixin hook-link-text-hover(){} -@mixin hook-link-heading(){} -@mixin hook-link-heading-hover(){} -@mixin hook-link-reset(){} -@mixin hook-link-misc(){} -@mixin hook-inverse-link-muted(){} -@mixin hook-inverse-link-muted-hover(){} -@mixin hook-inverse-link-text-hover(){} -@mixin hook-inverse-link-heading-hover(){} -@mixin hook-list-divider(){} -@mixin hook-list-striped(){} -@mixin hook-list-misc(){} -@mixin hook-inverse-list-divider(){} -@mixin hook-inverse-list-striped(){} -@mixin hook-margin-misc(){} -@mixin hook-marker(){} -@mixin hook-marker-hover(){} -@mixin hook-marker-misc(){} -@mixin hook-inverse-marker(){} -@mixin hook-inverse-marker-hover(){} -@mixin hook-inverse-component-marker(){ - - .uk-marker { - background: $inverse-marker-background; - color: $inverse-marker-color; - @if(mixin-exists(hook-inverse-marker)) {@include hook-inverse-marker();} - } - - .uk-marker:hover, - .uk-marker:focus { - color: $inverse-marker-hover-color; - @if(mixin-exists(hook-inverse-marker-hover)) {@include hook-inverse-marker-hover();} - } - -} -@mixin hook-modal(){} -@mixin hook-modal-dialog(){} -@mixin hook-modal-full(){} -@mixin hook-modal-body(){} -@mixin hook-modal-header(){} -@mixin hook-modal-footer(){} -@mixin hook-modal-title(){} -@mixin hook-modal-close(){} -@mixin hook-modal-close-hover(){} -@mixin hook-modal-close-default(){} -@mixin hook-modal-close-default-hover(){} -@mixin hook-modal-close-outside(){} -@mixin hook-modal-close-outside-hover(){} -@mixin hook-modal-close-full(){} -@mixin hook-modal-close-full-hover(){} -@mixin hook-modal-misc(){} -@mixin hook-nav-sub(){} -@mixin hook-nav-parent-icon(){} -@mixin hook-nav-header(){} -@mixin hook-nav-divider(){} -@mixin hook-nav-default(){} -@mixin hook-nav-default-item(){} -@mixin hook-nav-default-item-hover(){} -@mixin hook-nav-default-item-active(){} -@mixin hook-nav-default-header(){} -@mixin hook-nav-default-divider(){} -@mixin hook-nav-primary(){} -@mixin hook-nav-primary-item(){} -@mixin hook-nav-primary-item-hover(){} -@mixin hook-nav-primary-item-active(){} -@mixin hook-nav-primary-header(){} -@mixin hook-nav-primary-divider(){} -@mixin hook-nav-dividers(){} -@mixin hook-nav-misc(){} -@mixin hook-inverse-nav-parent-icon(){} -@mixin hook-inverse-nav-default-item(){} -@mixin hook-inverse-nav-default-item-hover(){} -@mixin hook-inverse-nav-default-item-active(){} -@mixin hook-inverse-nav-default-header(){} -@mixin hook-inverse-nav-default-divider(){} -@mixin hook-inverse-nav-primary-item(){} -@mixin hook-inverse-nav-primary-item-hover(){} -@mixin hook-inverse-nav-primary-item-active(){} -@mixin hook-inverse-nav-primary-header(){} -@mixin hook-inverse-nav-primary-divider(){} -@mixin hook-navbar(){} -@mixin hook-navbar-container(){} -@mixin hook-navbar-nav-item(){} -@mixin hook-navbar-nav-item-hover(){} -@mixin hook-navbar-nav-item-onclick(){} -@mixin hook-navbar-nav-item-active(){} -@mixin hook-navbar-item(){} -@mixin hook-navbar-toggle(){} -@mixin hook-navbar-toggle-hover(){} -@mixin hook-navbar-toggle-icon(){} -@mixin hook-navbar-toggle-icon-hover(){} -@mixin hook-navbar-subtitle(){} -@mixin hook-navbar-primary(){} -@mixin hook-navbar-transparent(){} -@mixin hook-navbar-sticky(){} -@mixin hook-navbar-dropdown(){} -@mixin hook-navbar-dropdown-dropbar(){} -@mixin hook-navbar-dropdown-nav(){} -@mixin hook-navbar-dropdown-nav-item(){} -@mixin hook-navbar-dropdown-nav-item-hover(){} -@mixin hook-navbar-dropdown-nav-item-active(){} -@mixin hook-navbar-dropdown-nav-header(){} -@mixin hook-navbar-dropdown-nav-divider(){} -@mixin hook-navbar-dropbar(){} -@mixin hook-navbar-dropbar-slide(){} -@mixin hook-navbar-misc(){} -@mixin hook-inverse-navbar-nav-item(){} -@mixin hook-inverse-navbar-nav-item-hover(){} -@mixin hook-inverse-navbar-nav-item-onclick(){} -@mixin hook-inverse-navbar-nav-item-active(){} -@mixin hook-inverse-navbar-item(){} -@mixin hook-inverse-navbar-toggle(){} -@mixin hook-inverse-navbar-toggle-hover(){} -@mixin hook-notification(){} -@mixin hook-notification-message(){} -@mixin hook-notification-close(){} -@mixin hook-notification-message-primary(){} -@mixin hook-notification-message-success(){} -@mixin hook-notification-message-warning(){} -@mixin hook-notification-message-danger(){} -@mixin hook-notification-misc(){} -@mixin hook-offcanvas-bar(){} -@mixin hook-offcanvas-close(){} -@mixin hook-offcanvas-overlay(){} -@mixin hook-offcanvas-misc(){} -@mixin hook-overlay(){} -@mixin hook-overlay-icon(){} -@mixin hook-overlay-default(){} -@mixin hook-overlay-primary(){} -@mixin hook-overlay-misc(){} -@mixin hook-padding-misc(){} -@mixin hook-pagination(){} -@mixin hook-pagination-item(){} -@mixin hook-pagination-item-hover(){} -@mixin hook-pagination-item-active(){} -@mixin hook-pagination-item-disabled(){} -@mixin hook-pagination-misc(){} -@mixin hook-inverse-pagination-item(){} -@mixin hook-inverse-pagination-item-hover(){} -@mixin hook-inverse-pagination-item-active(){} -@mixin hook-inverse-pagination-item-disabled(){} -@mixin hook-placeholder(){} -@mixin hook-placeholder-misc(){} -@mixin hook-position-misc(){} -@mixin hook-print(){} -@mixin hook-progress(){} -@mixin hook-progress-bar(){} -@mixin hook-progress-misc(){} -@mixin hook-search-input(){} -@mixin hook-search-default-input(){} -@mixin hook-search-default-input-focus(){} -@mixin hook-search-navbar-input(){} -@mixin hook-search-large-input(){} -@mixin hook-search-toggle(){} -@mixin hook-search-toggle-hover(){} -@mixin hook-search-misc(){} -@mixin hook-inverse-search-default-input(){} -@mixin hook-inverse-search-default-input-focus(){} -@mixin hook-inverse-search-navbar-input(){} -@mixin hook-inverse-search-large-input(){} -@mixin hook-inverse-search-toggle(){} -@mixin hook-inverse-search-toggle-hover(){} -@mixin hook-section(){} -@mixin hook-section-default(){} -@mixin hook-section-muted(){} -@mixin hook-section-primary(){} -@mixin hook-section-secondary(){} -@mixin hook-section-overlap(){} -@mixin hook-section-misc(){} -@mixin hook-slidenav(){} -@mixin hook-slidenav-hover(){} -@mixin hook-slidenav-active(){} -@mixin hook-slidenav-previous(){} -@mixin hook-slidenav-next(){} -@mixin hook-slidenav-large(){} -@mixin hook-slidenav-container(){} -@mixin hook-slidenav-misc(){} -@mixin hook-inverse-slidenav(){} -@mixin hook-inverse-slidenav-hover(){} -@mixin hook-inverse-slidenav-active(){} -@mixin hook-slider(){} -@mixin hook-slider-misc(){} -@mixin hook-slideshow(){} -@mixin hook-slideshow-misc(){} -@mixin hook-sortable(){} -@mixin hook-sortable-drag(){} -@mixin hook-sortable-placeholder(){} -@mixin hook-sortable-empty(){} -@mixin hook-sortable-misc(){} -@mixin hook-spinner(){} -@mixin hook-spinner-misc(){} -@mixin hook-sticky-misc(){} -@mixin hook-subnav(){} -@mixin hook-subnav-item(){} -@mixin hook-subnav-item-hover(){} -@mixin hook-subnav-item-active(){} -@mixin hook-subnav-divider(){} -@mixin hook-subnav-pill-item(){} -@mixin hook-subnav-pill-item-hover(){} -@mixin hook-subnav-pill-item-onclick(){} -@mixin hook-subnav-pill-item-active(){} -@mixin hook-subnav-item-disabled(){} -@mixin hook-subnav-misc(){} -@mixin hook-inverse-subnav-item(){} -@mixin hook-inverse-subnav-item-hover(){} -@mixin hook-inverse-subnav-item-active(){} -@mixin hook-inverse-subnav-divider(){} -@mixin hook-inverse-subnav-pill-item(){} -@mixin hook-inverse-subnav-pill-item-hover(){} -@mixin hook-inverse-subnav-pill-item-onclick(){} -@mixin hook-inverse-subnav-pill-item-active(){} -@mixin hook-inverse-subnav-item-disabled(){} -@mixin hook-svg-misc(){} -@mixin hook-switcher-misc(){} -@mixin hook-tab(){} -@mixin hook-tab-item(){} -@mixin hook-tab-item-hover(){} -@mixin hook-tab-item-active(){} -@mixin hook-tab-item-disabled(){} -@mixin hook-tab-bottom(){} -@mixin hook-tab-bottom-item(){} -@mixin hook-tab-left(){} -@mixin hook-tab-right(){} -@mixin hook-tab-left-item(){} -@mixin hook-tab-right-item(){} -@mixin hook-tab-misc(){} -@mixin hook-inverse-tab(){} -@mixin hook-inverse-tab-item(){} -@mixin hook-inverse-tab-item-hover(){} -@mixin hook-inverse-tab-item-active(){} -@mixin hook-inverse-tab-item-disabled(){} -@mixin hook-table(){} -@mixin hook-table-header-cell(){} -@mixin hook-table-cell(){} -@mixin hook-table-footer(){} -@mixin hook-table-caption(){} -@mixin hook-table-divider(){} -@mixin hook-table-striped(){} -@mixin hook-table-hover(){} -@mixin hook-table-row-active(){} -@mixin hook-table-small(){} -@mixin hook-table-large(){} -@mixin hook-table-misc(){} -@mixin hook-inverse-table-header-cell(){} -@mixin hook-inverse-table-caption(){} -@mixin hook-inverse-table-row-active(){} -@mixin hook-inverse-table-divider(){} -@mixin hook-inverse-table-striped(){} -@mixin hook-inverse-table-hover(){} -@mixin hook-inverse-component-table(){ - - .uk-table th { - color: $inverse-table-header-cell-color; - @if(mixin-exists(hook-inverse-table-header-cell)) {@include hook-inverse-table-header-cell();} - } - - .uk-table caption { - color: $inverse-table-caption-color; - @if(mixin-exists(hook-inverse-table-caption)) {@include hook-inverse-table-caption();} - } - - .uk-table > tr.uk-active, - .uk-table tbody tr.uk-active { - background: $inverse-table-row-active-background; - @if(mixin-exists(hook-inverse-table-row-active)) {@include hook-inverse-table-row-active();} - } - - .uk-table-divider > tr:not(:first-child), - .uk-table-divider > :not(:first-child) > tr, - .uk-table-divider > :first-child > tr:not(:first-child) { - border-top-color: $inverse-table-divider-border; - @if(mixin-exists(hook-inverse-table-divider)) {@include hook-inverse-table-divider();} - } - - .uk-table-striped > tr:nth-of-type(odd), - .uk-table-striped tbody tr:nth-of-type(odd) { - background: $inverse-table-striped-row-background; - @if(mixin-exists(hook-inverse-table-striped)) {@include hook-inverse-table-striped();} - } - - .uk-table-hover > tr:hover, - .uk-table-hover tbody tr:hover { - background: $inverse-table-hover-row-background; - @if(mixin-exists(hook-inverse-table-hover)) {@include hook-inverse-table-hover();} - } - -} -@mixin hook-text-lead(){} -@mixin hook-text-meta(){} -@mixin hook-text-small(){} -@mixin hook-text-large(){} -@mixin hook-text-background(){} -@mixin hook-text-misc(){} -@mixin hook-inverse-text-lead(){} -@mixin hook-inverse-text-meta(){} -@mixin hook-thumbnav(){} -@mixin hook-thumbnav-item(){} -@mixin hook-thumbnav-item-hover(){} -@mixin hook-thumbnav-item-active(){} -@mixin hook-thumbnav-misc(){} -@mixin hook-inverse-thumbnav-item(){} -@mixin hook-inverse-thumbnav-item-hover(){} -@mixin hook-inverse-thumbnav-item-active(){} -@mixin hook-inverse-component-thumbnav(){ - - .uk-thumbnav > * > * { - @if(mixin-exists(hook-inverse-thumbnav-item)) {@include hook-inverse-thumbnav-item();} - } - - .uk-thumbnav > * > :hover, - .uk-thumbnav > * > :focus { - @if(mixin-exists(hook-inverse-thumbnav-item-hover)) {@include hook-inverse-thumbnav-item-hover();} - } - - .uk-thumbnav > .uk-active > * { - @if(mixin-exists(hook-inverse-thumbnav-item-active)) {@include hook-inverse-thumbnav-item-active();} - } - -} -@mixin hook-tile(){} -@mixin hook-tile-default(){} -@mixin hook-tile-muted(){} -@mixin hook-tile-primary(){} -@mixin hook-tile-secondary(){} -@mixin hook-tile-misc(){} -@mixin hook-tooltip(){} -@mixin hook-tooltip-misc(){} -@mixin hook-totop(){} -@mixin hook-totop-hover(){} -@mixin hook-totop-active(){} -@mixin hook-totop-misc(){} -@mixin hook-inverse-totop(){} -@mixin hook-inverse-totop-hover(){} -@mixin hook-inverse-totop-active(){} -@mixin hook-transition-misc(){} -@mixin hook-panel-scrollable(){} -@mixin hook-box-shadow-bottom(){} -@mixin hook-dropcap(){} -@mixin hook-logo(){} -@mixin hook-logo-hover(){} -@mixin hook-utility-misc(){} -@mixin hook-inverse-dropcap(){} -@mixin hook-inverse-logo(){} -@mixin hook-inverse-logo-hover(){} -@mixin hook-visibility-misc(){} -@mixin hook-width-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/_import.scss b/docs/_sass/uikit/theme/_import.scss deleted file mode 100644 index ab4a71d491..0000000000 --- a/docs/_sass/uikit/theme/_import.scss +++ /dev/null @@ -1,81 +0,0 @@ -// Base -@import "https://github.com/variables"; -@import "https://github.com/base"; - -// Elements -@import "https://github.com/link"; -@import "https://github.com/heading"; -@import "https://github.com/divider"; -@import "https://github.com/list"; -@import "https://github.com/description-list"; -@import "https://github.com/table"; -@import "https://github.com/icon"; -@import "https://github.com/form-range"; -@import "https://github.com/form"; -@import "https://github.com/button"; -@import "https://github.com/progress"; - -// Layout -@import "https://github.com/section"; -@import "https://github.com/container"; -@import "https://github.com/tile"; -@import "https://github.com/card"; - -// Common -@import "https://github.com/close"; -@import "https://github.com/spinner"; -@import "https://github.com/marker"; -@import "https://github.com/totop"; -@import "https://github.com/alert"; -@import "https://github.com/placeholder"; -@import "https://github.com/badge"; -@import "https://github.com/label"; -@import "https://github.com/overlay"; -@import "https://github.com/article"; -@import "https://github.com/comment"; -@import "https://github.com/search"; - -// JavaScript -@import "https://github.com/accordion"; -@import "https://github.com/drop"; -@import "https://github.com/dropdown"; -@import "https://github.com/modal"; -@import "https://github.com/slider"; -@import "https://github.com/sticky"; -@import "https://github.com/offcanvas"; -@import "https://github.com/leader"; -@import "https://github.com/notification"; -@import "https://github.com/tooltip"; -@import "https://github.com/sortable"; -@import "https://github.com/countdown"; - -@import "https://github.com/grid"; - -// Navs -@import "https://github.com/nav"; -@import "https://github.com/navbar"; -@import "https://github.com/subnav"; -@import "https://github.com/breadcrumb"; -@import "https://github.com/pagination"; -@import "https://github.com/tab"; -@import "https://github.com/slidenav"; -@import "https://github.com/dotnav"; -@import "https://github.com/thumbnav"; -@import "https://github.com/iconnav"; - -@import "https://github.com/lightbox"; - -// Utilities -@import "https://github.com/animation"; -@import "https://github.com/width"; -@import "https://github.com/height"; -@import "https://github.com/text"; -@import "https://github.com/column"; -@import "https://github.com/background"; -@import "https://github.com/align"; -@import "https://github.com/utility"; -@import "https://github.com/margin"; -@import "https://github.com/padding"; -@import "https://github.com/position"; -@import "https://github.com/transition"; -@import "https://github.com/inverse"; diff --git a/docs/_sass/uikit/theme/accordion.scss b/docs/_sass/uikit/theme/accordion.scss deleted file mode 100644 index ae25a64afe..0000000000 --- a/docs/_sass/uikit/theme/accordion.scss +++ /dev/null @@ -1,59 +0,0 @@ -// -// Component: Accordion -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$accordion-icon-margin-left: 10px !default; -$accordion-icon-color: $global-color !default; -$internal-accordion-open-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$internal-accordion-close-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; - - -// Component -// ======================================================================== - -// @mixin hook-accordion(){} - - -// Item -// ======================================================================== - -// @mixin hook-accordion-item(){} - - -// Title -// ======================================================================== - - - -// @mixin hook-accordion-title-hover(){} - - -// Content -// ======================================================================== - -// @mixin hook-accordion-content(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-accordion-misc(){} - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-accordion-item(){} - -// @mixin hook-inverse-accordion-title(){} -// @mixin hook-inverse-accordion-title-hover(){} - - diff --git a/docs/_sass/uikit/theme/alert.scss b/docs/_sass/uikit/theme/alert.scss deleted file mode 100644 index c4baa7ca90..0000000000 --- a/docs/_sass/uikit/theme/alert.scss +++ /dev/null @@ -1,46 +0,0 @@ -// -// Component: Alert -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$alert-close-opacity: 0.4 !default; -$alert-close-hover-opacity: 0.8 !default; - - -// Component -// ======================================================================== - -// @mixin hook-alert(){} - - -// Close -// ======================================================================== - - - - - - -// Style modifiers -// ======================================================================== - -// @mixin hook-alert-primary(){} - -// @mixin hook-alert-success(){} - -// @mixin hook-alert-warning(){} - -// @mixin hook-alert-danger(){} - - -// Miscellaneous -// ======================================================================== - diff --git a/docs/_sass/uikit/theme/align.scss b/docs/_sass/uikit/theme/align.scss deleted file mode 100644 index 290abd4115..0000000000 --- a/docs/_sass/uikit/theme/align.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Align -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-align-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/animation.scss b/docs/_sass/uikit/theme/animation.scss deleted file mode 100644 index 03ebbc6eae..0000000000 --- a/docs/_sass/uikit/theme/animation.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Animation -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-animation-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/article.scss b/docs/_sass/uikit/theme/article.scss deleted file mode 100644 index a698e3ed18..0000000000 --- a/docs/_sass/uikit/theme/article.scss +++ /dev/null @@ -1,51 +0,0 @@ -// -// Component: Article -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$article-meta-link-color: $article-meta-color !default; -$article-meta-link-hover-color: $global-color !default; - - -// Component -// ======================================================================== - -// @mixin hook-article(){} - - -// Adjacent sibling -// ======================================================================== - -// @mixin hook-article-adjacent(){} - - -// Title -// ======================================================================== - -// @mixin hook-article-title(){} - - -// Meta -// ======================================================================== - - - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-article-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-article-meta(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/background.scss b/docs/_sass/uikit/theme/background.scss deleted file mode 100644 index 29e062e9d2..0000000000 --- a/docs/_sass/uikit/theme/background.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Background -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-background-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/badge.scss b/docs/_sass/uikit/theme/badge.scss deleted file mode 100644 index 22ae937122..0000000000 --- a/docs/_sass/uikit/theme/badge.scss +++ /dev/null @@ -1,29 +0,0 @@ -// -// Component: Badge -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-badge(){} - -// @mixin hook-badge-hover(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-badge-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-badge(){} -// @mixin hook-inverse-badge-hover(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/base.scss b/docs/_sass/uikit/theme/base.scss deleted file mode 100644 index 2c1c33569e..0000000000 --- a/docs/_sass/uikit/theme/base.scss +++ /dev/null @@ -1,116 +0,0 @@ -// -// Component: Base -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$base-code-padding-horizontal: 6px !default; -$base-code-padding-vertical: 2px !default; -$base-code-background: $global-muted-background !default; - -$base-blockquote-color: $global-emphasis-color !default; - -$base-blockquote-footer-color: $global-color !default; - -$base-pre-padding: 10px !default; -$base-pre-background: $global-background !default; -$base-pre-border-width: $global-border-width !default; -$base-pre-border: $global-border !default; -$base-pre-border-radius: 3px !default; - - -// Body -// ======================================================================== - -// @mixin hook-base-body(){} - - -// Links -// ======================================================================== - -// @mixin hook-base-link(){} - -// @mixin hook-base-link-hover(){} - - -// Text-level semantics -// ======================================================================== - - - - -// Headings -// ======================================================================== - -// @mixin hook-base-heading(){} - -// @mixin hook-base-h1(){} - -// @mixin hook-base-h2(){} - -// @mixin hook-base-h3(){} - -// @mixin hook-base-h4(){} - -// @mixin hook-base-h5(){} - -// @mixin hook-base-h6(){} - - -// Horizontal rules -// ======================================================================== - -// @mixin hook-base-hr(){} - - -// Blockquotes -// ======================================================================== - - - - - - -// Preformatted text -// ======================================================================== - - - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-base-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-base-blockquote-color: $inverse-global-emphasis-color !default; -$inverse-base-blockquote-footer-color: $inverse-global-color !default; - -// @mixin hook-inverse-base-link(){} -// @mixin hook-inverse-base-link-hover(){} - - - -// @mixin hook-inverse-base-heading(){} - -// @mixin hook-inverse-base-h1(){} -// @mixin hook-inverse-base-h2(){} -// @mixin hook-inverse-base-h3(){} -// @mixin hook-inverse-base-h4(){} -// @mixin hook-inverse-base-h5(){} -// @mixin hook-inverse-base-h6(){} - - - - -// @mixin hook-inverse-base-hr(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/breadcrumb.scss b/docs/_sass/uikit/theme/breadcrumb.scss deleted file mode 100644 index 40c04e5d9e..0000000000 --- a/docs/_sass/uikit/theme/breadcrumb.scss +++ /dev/null @@ -1,45 +0,0 @@ -// -// Component: Breadcrumb -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-breadcrumb(){} - - -// Items -// ======================================================================== - -// @mixin hook-breadcrumb-item(){} - -// @mixin hook-breadcrumb-item-hover(){} - -// @mixin hook-breadcrumb-item-disabled(){} - -// @mixin hook-breadcrumb-item-active(){} - -// @mixin hook-breadcrumb-divider(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-breadcrumb-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-breadcrumb-item(){} -// @mixin hook-inverse-breadcrumb-item-hover(){} -// @mixin hook-inverse-breadcrumb-item-disabled(){} -// @mixin hook-inverse-breadcrumb-item-active(){} - -// @mixin hook-inverse-breadcrumb-divider(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/button.scss b/docs/_sass/uikit/theme/button.scss deleted file mode 100644 index d78c38933f..0000000000 --- a/docs/_sass/uikit/theme/button.scss +++ /dev/null @@ -1,159 +0,0 @@ -// -// Component: Button -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$button-line-height: $global-control-height - ($button-border-width * 2) !default; -$button-small-line-height: $global-control-small-height - ($button-border-width * 2) !default; -$button-large-line-height: $global-control-large-height - ($button-border-width * 2) !default; - -$button-font-size: $global-small-font-size !default; -$button-large-font-size: $global-small-font-size !default; - -$button-default-background: transparent !default; -$button-default-hover-background: transparent !default; -$button-default-active-background: transparent !default; - -$button-disabled-background: transparent !default; - -$button-text-hover-color: $global-emphasis-color !default; - -// -// New -// - -$button-text-transform: uppercase !default; - -$button-border-width: $global-border-width !default; - -$button-default-border: $global-border !default; -$button-default-hover-border: darken($global-border, 20%) !default; -$button-default-active-border: darken($global-border, 30%) !default; - -$button-disabled-border: $global-border !default; - -$button-text-border-width: $global-border-width !default; -$button-text-border: $button-text-hover-color !default; - - -// Component -// ======================================================================== - - - -// @mixin hook-button-hover(){} - -// @mixin hook-button-focus(){} - -// @mixin hook-button-active(){} - - -// Style modifiers -// ======================================================================== - - - - - - - -// -// Primary -// - - - -// @mixin hook-button-primary-hover(){} - -// @mixin hook-button-primary-active(){} - -// -// Secondary -// - - - -// @mixin hook-button-secondary-hover(){} - -// @mixin hook-button-secondary-active(){} - -// -// Danger -// - - - -// @mixin hook-button-danger-hover(){} - -// @mixin hook-button-danger-active(){} - - -// Disabled -// ======================================================================== - - - - -// Size modifiers -// ======================================================================== - -// @mixin hook-button-small(){} - -// @mixin hook-button-large(){} - - -// Text modifier -// ======================================================================== - - - - - - - - -// Link modifier -// ======================================================================== - -// @mixin hook-button-link(){} - - -// Miscellaneous -// ======================================================================== - - - - -// Inverse -// ======================================================================== - -$inverse-button-default-background: transparent !default; -$inverse-button-default-color: $inverse-global-emphasis-color !default; -$inverse-button-default-hover-background: transparent !default; -$inverse-button-default-hover-color: $inverse-global-emphasis-color !default; -$inverse-button-default-active-background: transparent !default; -$inverse-button-default-active-color: $inverse-global-emphasis-color !default; - -$inverse-button-text-hover-color: $inverse-global-emphasis-color !default; - - - - - -// @mixin hook-inverse-button-primary(){} -// @mixin hook-inverse-button-primary-hover(){} -// @mixin hook-inverse-button-primary-active(){} - -// @mixin hook-inverse-button-secondary(){} -// @mixin hook-inverse-button-secondary-hover(){} -// @mixin hook-inverse-button-secondary-active(){} - - -// @mixin hook-inverse-button-text-hover(){} -// @mixin hook-inverse-button-text-disabled(){} - -// @mixin hook-inverse-button-link(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/card.scss b/docs/_sass/uikit/theme/card.scss deleted file mode 100644 index 7eb4deee98..0000000000 --- a/docs/_sass/uikit/theme/card.scss +++ /dev/null @@ -1,128 +0,0 @@ -// -// Component: Card -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$card-hover-background: $global-background !default; - -$card-default-background: $global-background !default; -$card-default-hover-background: $card-default-background !default; - -$card-primary-hover-background: $card-primary-background !default; - -$card-secondary-hover-background: $card-secondary-background !default; - -// -// New -// - -$card-badge-border-radius: 2px !default; -$card-badge-text-transform: uppercase !default; - -$card-hover-box-shadow: $global-large-box-shadow !default; - -$card-default-box-shadow: $global-medium-box-shadow !default; -$card-default-hover-box-shadow: $global-large-box-shadow !default; - -$card-default-header-border-width: $global-border-width !default; -$card-default-header-border: $global-border !default; - -$card-default-footer-border-width: $global-border-width !default; -$card-default-footer-border: $global-border !default; - -$card-primary-box-shadow: $global-medium-box-shadow !default; -$card-primary-hover-box-shadow: $global-large-box-shadow !default; - -$card-secondary-box-shadow: $global-medium-box-shadow !default; -$card-secondary-hover-box-shadow: $global-large-box-shadow !default; - - -// Component -// ======================================================================== - - - - -// Sections -// ======================================================================== - -// @mixin hook-card-body(){} - -// @mixin hook-card-header(){} - -// @mixin hook-card-footer(){} - - -// Media -// ======================================================================== - -// @mixin hook-card-media(){} - -// @mixin hook-card-media-top(){} - -// @mixin hook-card-media-bottom(){} - -// @mixin hook-card-media-left(){} - -// @mixin hook-card-media-right(){} - - -// Title -// ======================================================================== - -// @mixin hook-card-title(){} - - -// Badge -// ======================================================================== - - - - -// Hover modifier -// ======================================================================== - - - - -// Style modifiers -// ======================================================================== - - - -// @mixin hook-card-default-title(){} - - - - - - - -// -// Primary -// - - - -// @mixin hook-card-primary-title(){} - - - -// -// Secondary -// - - - -// @mixin hook-card-secondary-title(){} - - - - -// Miscellaneous -// ======================================================================== - diff --git a/docs/_sass/uikit/theme/close.scss b/docs/_sass/uikit/theme/close.scss deleted file mode 100644 index f0762942f8..0000000000 --- a/docs/_sass/uikit/theme/close.scss +++ /dev/null @@ -1,29 +0,0 @@ -// -// Component: Close -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - - - -// @mixin hook-close-hover(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-close-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-close(){} -// @mixin hook-inverse-close-hover(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/column.scss b/docs/_sass/uikit/theme/column.scss deleted file mode 100644 index 80be850572..0000000000 --- a/docs/_sass/uikit/theme/column.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Column -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-column-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/comment.scss b/docs/_sass/uikit/theme/comment.scss deleted file mode 100644 index a486c59142..0000000000 --- a/docs/_sass/uikit/theme/comment.scss +++ /dev/null @@ -1,69 +0,0 @@ -// -// Component: Comment -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$comment-primary-padding: $global-gutter !default; -$comment-primary-background: $global-muted-background !default; - - -// Component -// ======================================================================== - -// @mixin hook-comment(){} - - -// Sections -// ======================================================================== - -// @mixin hook-comment-body(){} - -// @mixin hook-comment-header(){} - - -// Title -// ======================================================================== - -// @mixin hook-comment-title(){} - - -// Meta -// ======================================================================== - -// @mixin hook-comment-meta(){} - - -// Avatar -// ======================================================================== - -// @mixin hook-comment-avatar(){} - - -// List -// ======================================================================== - -// @mixin hook-comment-list-adjacent(){} - -// @mixin hook-comment-list-sub(){} - -// @mixin hook-comment-list-sub-adjacent(){} - - -// Style modifier -// ======================================================================== - - - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-comment-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/container.scss b/docs/_sass/uikit/theme/container.scss deleted file mode 100644 index ba77ded72e..0000000000 --- a/docs/_sass/uikit/theme/container.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Container -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-container-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/countdown.scss b/docs/_sass/uikit/theme/countdown.scss deleted file mode 100644 index 01f1761ca3..0000000000 --- a/docs/_sass/uikit/theme/countdown.scss +++ /dev/null @@ -1,53 +0,0 @@ -// -// Component: Countdown -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-countdown(){} - - -// Item -// ======================================================================== - -// @mixin hook-countdown-item(){} - - -// Number -// ======================================================================== - -// @mixin hook-countdown-number(){} - - -// Separator -// ======================================================================== - -// @mixin hook-countdown-separator(){} - - -// Label -// ======================================================================== - -// @mixin hook-countdown-label(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-countdown-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-countdown-item(){} -// @mixin hook-inverse-countdown-number(){} -// @mixin hook-inverse-countdown-separator(){} -// @mixin hook-inverse-countdown-label(){} diff --git a/docs/_sass/uikit/theme/description-list.scss b/docs/_sass/uikit/theme/description-list.scss deleted file mode 100644 index 8f836d6321..0000000000 --- a/docs/_sass/uikit/theme/description-list.scss +++ /dev/null @@ -1,32 +0,0 @@ -// -// Component: Description list -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$description-list-term-font-size: $global-small-font-size !default; -$description-list-term-font-weight: normal !default; -$description-list-term-text-transform: uppercase !default; - - -// Component -// ======================================================================== - - - -// @mixin hook-description-list-description(){} - - -// Style modifier -// ======================================================================== - -// @mixin hook-description-list-divider-term(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-description-list-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/divider.scss b/docs/_sass/uikit/theme/divider.scss deleted file mode 100644 index 1273b2a9ec..0000000000 --- a/docs/_sass/uikit/theme/divider.scss +++ /dev/null @@ -1,49 +0,0 @@ -// -// Component: Divider -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Icon -// ======================================================================== - -// @mixin hook-divider-icon(){} - -// @mixin hook-divider-icon-line(){} - -// @mixin hook-divider-icon-line-left(){} - -// @mixin hook-divider-icon-line-right(){} - - -// Small -// ======================================================================== - -// @mixin hook-divider-small(){} - - -// Vertical -// ======================================================================== - -// @mixin hook-divider-vertical(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-divider-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-divider-icon(){} -// @mixin hook-inverse-divider-icon-line(){} - -// @mixin hook-inverse-divider-small(){} - -// @mixin hook-inverse-divider-vertical(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/dotnav.scss b/docs/_sass/uikit/theme/dotnav.scss deleted file mode 100644 index 1bc835970f..0000000000 --- a/docs/_sass/uikit/theme/dotnav.scss +++ /dev/null @@ -1,52 +0,0 @@ -// -// Component: Dotnav -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$dotnav-item-background: transparent !default; - -// -// New -// - -$dotnav-item-border-width: 1px !default; - -$dotnav-item-border: rgba($global-color, 0.4) !default; -$dotnav-item-hover-border: transparent !default; -$dotnav-item-onclick-border: transparent !default; -$dotnav-item-active-border: transparent !default; - - -// Component -// ======================================================================== - -// @mixin hook-dotnav(){} - - - - - - - - - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-dotnav-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-dotnav-item-background: transparent !default; - -// @mixin hook-inverse-dotnav(){} - - - diff --git a/docs/_sass/uikit/theme/drop.scss b/docs/_sass/uikit/theme/drop.scss deleted file mode 100644 index 6940984871..0000000000 --- a/docs/_sass/uikit/theme/drop.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Drop -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-drop-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/dropdown.scss b/docs/_sass/uikit/theme/dropdown.scss deleted file mode 100644 index c5aa02ef44..0000000000 --- a/docs/_sass/uikit/theme/dropdown.scss +++ /dev/null @@ -1,45 +0,0 @@ -// -// Component: Dropdown -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$dropdown-padding: 25px !default; -$dropdown-background: $global-background !default; - -// -// New -// - -$dropdown-nav-font-size: $global-small-font-size !default; - -$dropdown-box-shadow: 0 5px 12px rgba(0,0,0,0.15) !default; - - -// Component -// ======================================================================== - - - - -// Nav -// ======================================================================== - - - -// @mixin hook-dropdown-nav-item(){} - -// @mixin hook-dropdown-nav-item-hover(){} - -// @mixin hook-dropdown-nav-header(){} - -// @mixin hook-dropdown-nav-divider(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-dropdown-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/form-range.scss b/docs/_sass/uikit/theme/form-range.scss deleted file mode 100644 index ca424f30e3..0000000000 --- a/docs/_sass/uikit/theme/form-range.scss +++ /dev/null @@ -1,45 +0,0 @@ -// -// Component: Form Range -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$form-range-thumb-background: $global-background !default; - -// -// New -// - -$form-range-thumb-border-width: $global-border-width !default; -$form-range-thumb-border: darken($global-border, 10%) !default; - -$form-range-track-border-radius: 500px !default; - - -// Component -// ======================================================================== - -// @mixin hook-form-range(){} - - -// Thumb -// ======================================================================== - - - - -// Track -// ======================================================================== - - - -// @mixin hook-form-range-track-focus(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-form-range-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/form.scss b/docs/_sass/uikit/theme/form.scss deleted file mode 100644 index ef80695839..0000000000 --- a/docs/_sass/uikit/theme/form.scss +++ /dev/null @@ -1,131 +0,0 @@ -// -// Component: Form -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$form-line-height: $form-height - (2* $form-border-width) !default; - -$form-background: $global-background !default; -$form-focus-background: $global-background !default; - -$form-small-line-height: $form-small-height - (2* $form-border-width) !default; -$form-large-line-height: $form-large-height - (2* $form-border-width) !default; - -$form-radio-background: transparent !default; - -$form-stacked-margin-bottom: 5px !default; - -// -// New -// - -$form-border-width: $global-border-width !default; -$form-border: $global-border !default; - -$form-focus-border: $global-primary-background !default; - -$form-disabled-border: $global-border !default; - -$form-danger-border: $global-danger-background !default; -$form-success-border: $global-success-background !default; - -$form-blank-focus-border: $global-border !default; -$form-blank-focus-border-style: dashed !default; - -$form-radio-border-width: $global-border-width !default; -$form-radio-border: darken($global-border, 10%) !default; - -$form-radio-focus-border: $global-primary-background !default; - -$form-radio-checked-border: transparent !default; - -$form-radio-disabled-border: $global-border !default; - -$form-label-color: $global-emphasis-color !default; -$form-label-font-size: $global-small-font-size !default; - - -// Component -// ======================================================================== - - - -// @mixin hook-form-single-line(){} - -// @mixin hook-form-multi-line(){} - - - - - - -// Style modifiers -// ======================================================================== - - - - - - - - - - -// Radio and checkbox -// ======================================================================== - - - - - - - -// @mixin hook-form-radio-checked-focus(){} - - - - -// Legend -// ======================================================================== - -// @mixin hook-form-legend(){} - - -// Label -// ======================================================================== - - - - -// Layout -// ======================================================================== - -// @mixin hook-form-stacked-label(){} - -// @mixin hook-form-horizontal-label(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-form-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-form-label-color: $inverse-global-emphasis-color !default; - - - - - - - - -// @mixin hook-inverse-form-radio-checked-focus(){} - diff --git a/docs/_sass/uikit/theme/grid.scss b/docs/_sass/uikit/theme/grid.scss deleted file mode 100644 index 1b3779f809..0000000000 --- a/docs/_sass/uikit/theme/grid.scss +++ /dev/null @@ -1,28 +0,0 @@ -// -// Component: Grid -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Divider -// ======================================================================== - -// @mixin hook-grid-divider-horizontal(){} -// @mixin hook-grid-divider-vertical(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-grid-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-grid-divider-horizontal(){} -// @mixin hook-inverse-grid-divider-vertical(){} diff --git a/docs/_sass/uikit/theme/heading.scss b/docs/_sass/uikit/theme/heading.scss deleted file mode 100644 index 9ec067428a..0000000000 --- a/docs/_sass/uikit/theme/heading.scss +++ /dev/null @@ -1,67 +0,0 @@ -// -// Component: Heading -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-heading-small(){} - -// @mixin hook-heading-medium(){} - -// @mixin hook-heading-large(){} - -// @mixin hook-heading-xlarge(){} - -// @mixin hook-heading-2xlarge(){} - - -// Divider -// ======================================================================== - -// @mixin hook-heading-divider(){} - - -// Bullet -// ======================================================================== - -// @mixin hook-heading-bullet(){} - - -// Line -// ======================================================================== - -// @mixin hook-heading-line(){} - - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-heading-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-heading-small(){} - -// @mixin hook-inverse-heading-medium(){} - -// @mixin hook-inverse-heading-large(){} - -// @mixin hook-inverse-heading-xlarge(){} - -// @mixin hook-inverse-heading-2xlarge(){} - -// @mixin hook-inverse-heading-divider(){} - -// @mixin hook-inverse-heading-bullet(){} - -// @mixin hook-inverse-heading-line(){} diff --git a/docs/_sass/uikit/theme/height.scss b/docs/_sass/uikit/theme/height.scss deleted file mode 100644 index 37f2c2f84b..0000000000 --- a/docs/_sass/uikit/theme/height.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Height -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-height-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/icon.scss b/docs/_sass/uikit/theme/icon.scss deleted file mode 100644 index b81c79abd8..0000000000 --- a/docs/_sass/uikit/theme/icon.scss +++ /dev/null @@ -1,50 +0,0 @@ -// -// Component: Icon -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Style modifiers -// ======================================================================== - -// -// Link -// - -// @mixin hook-icon-link(){} - -// @mixin hook-icon-link-hover(){} - -// @mixin hook-icon-link-active(){} - -// -// Button -// - - - -// @mixin hook-icon-button-hover(){} - -// @mixin hook-icon-button-active(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-icon-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-icon-link(){} -// @mixin hook-inverse-icon-link-hover(){} -// @mixin hook-inverse-icon-link-active(){} - -// @mixin hook-inverse-icon-button(){} -// @mixin hook-inverse-icon-button-hover(){} -// @mixin hook-inverse-icon-button-active(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/iconnav.scss b/docs/_sass/uikit/theme/iconnav.scss deleted file mode 100644 index 376a0afabf..0000000000 --- a/docs/_sass/uikit/theme/iconnav.scss +++ /dev/null @@ -1,40 +0,0 @@ -// -// Component: Iconnav -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$subnav-item-font-size: $global-small-font-size !default; - - -// Component -// ======================================================================== - -// @mixin hook-iconnav(){} - - - -// @mixin hook-iconnav-item-hover(){} - -// @mixin hook-iconnav-item-active(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-iconnav-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-iconnav-item(){} -// @mixin hook-inverse-iconnav-item-hover(){} -// @mixin hook-inverse-iconnav-item-active(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/inverse.scss b/docs/_sass/uikit/theme/inverse.scss deleted file mode 100644 index 75a5a3b168..0000000000 --- a/docs/_sass/uikit/theme/inverse.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Inverse -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-inverse(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/label.scss b/docs/_sass/uikit/theme/label.scss deleted file mode 100644 index ff09ac92cf..0000000000 --- a/docs/_sass/uikit/theme/label.scss +++ /dev/null @@ -1,43 +0,0 @@ -// -// Component: Label -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$label-border-radius: 2px !default; -$label-text-transform: uppercase !default; - - -// Component -// ======================================================================== - - - - -// Color modifiers -// ======================================================================== - -// @mixin hook-label-success(){} - -// @mixin hook-label-warning(){} - -// @mixin hook-label-danger(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-label-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-label(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/leader.scss b/docs/_sass/uikit/theme/leader.scss deleted file mode 100644 index 6618325e82..0000000000 --- a/docs/_sass/uikit/theme/leader.scss +++ /dev/null @@ -1,26 +0,0 @@ -// -// Component: Leader -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-leader(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-leader-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-leader(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/lightbox.scss b/docs/_sass/uikit/theme/lightbox.scss deleted file mode 100644 index 6c9d115ab1..0000000000 --- a/docs/_sass/uikit/theme/lightbox.scss +++ /dev/null @@ -1,50 +0,0 @@ -// -// Component: Lightbox -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-lightbox(){} - - -// Item -// ======================================================================== - -// @mixin hook-lightbox-item(){} - - -// Toolbar -// ======================================================================== - -// @mixin hook-lightbox-toolbar(){} - - -// Toolbar Icon -// ======================================================================== - -// @mixin hook-lightbox-toolbar-icon(){} - -// @mixin hook-lightbox-toolbar-icon-hover(){} - - -// Button -// ======================================================================== - -// @mixin hook-lightbox-button(){} - -// @mixin hook-lightbox-button-hover(){} - -// @mixin hook-lightbox-button-active(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-lightbox-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/link.scss b/docs/_sass/uikit/theme/link.scss deleted file mode 100644 index 0658b58a6d..0000000000 --- a/docs/_sass/uikit/theme/link.scss +++ /dev/null @@ -1,55 +0,0 @@ -// -// Component: Link -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Muted -// ======================================================================== - -// @mixin hook-link-muted(){} - -// @mixin hook-link-muted-hover(){} - - -// Text -// ======================================================================== - -// @mixin hook-link-text(){} - -// @mixin hook-link-text-hover(){} - - -// Heading -// ======================================================================== - -// @mixin hook-link-heading(){} - -// @mixin hook-link-heading-hover(){} - - -// Reset -// ======================================================================== - -// @mixin hook-link-reset(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-link-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-link-muted(){} -// @mixin hook-inverse-link-muted-hover(){} - -// @mixin hook-inverse-link-text-hover(){} - -// @mixin hook-inverse-link-heading-hover(){} diff --git a/docs/_sass/uikit/theme/list.scss b/docs/_sass/uikit/theme/list.scss deleted file mode 100644 index 33804fa0eb..0000000000 --- a/docs/_sass/uikit/theme/list.scss +++ /dev/null @@ -1,36 +0,0 @@ -// -// Component: List -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$list-striped-border-width: $global-border-width !default; -$list-striped-border: $global-border !default; - - -// Style modifiers -// ======================================================================== - -// @mixin hook-list-divider(){} - - - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-list-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-list-divider(){} - diff --git a/docs/_sass/uikit/theme/margin.scss b/docs/_sass/uikit/theme/margin.scss deleted file mode 100644 index a2cdb5ec99..0000000000 --- a/docs/_sass/uikit/theme/margin.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Margin -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-margin-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/marker.scss b/docs/_sass/uikit/theme/marker.scss deleted file mode 100644 index 1e4fd5f379..0000000000 --- a/docs/_sass/uikit/theme/marker.scss +++ /dev/null @@ -1,29 +0,0 @@ -// -// Component: Marker -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - - - -// @mixin hook-marker-hover(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-marker-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-marker(){} -// @mixin hook-inverse-marker-hover(){} diff --git a/docs/_sass/uikit/theme/modal.scss b/docs/_sass/uikit/theme/modal.scss deleted file mode 100644 index adc2135808..0000000000 --- a/docs/_sass/uikit/theme/modal.scss +++ /dev/null @@ -1,84 +0,0 @@ -// -// Component: Modal -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$modal-header-background: $modal-dialog-background !default; -$modal-footer-background: $modal-dialog-background !default; - -// -// New -// - -$modal-header-border-width: $global-border-width !default; -$modal-header-border: $global-border !default; - -$modal-footer-border-width: $global-border-width !default; -$modal-footer-border: $global-border !default; - -$modal-close-full-padding: $global-margin !default; -$modal-close-full-background: $modal-dialog-background !default; - - -// Component -// ======================================================================== - -// @mixin hook-modal(){} - - -// Dialog -// ======================================================================== - -// @mixin hook-modal-dialog(){} - - -// Full -// ======================================================================== - -// @mixin hook-modal-full(){} - - -// Sections -// ======================================================================== - - - -// @mixin hook-modal-body(){} - - - - -// Title -// ======================================================================== - -// @mixin hook-modal-title(){} - - -// Close -// ======================================================================== - -// @mixin hook-modal-close(){} - -// @mixin hook-modal-close-hover(){} - -// @mixin hook-modal-close-default(){} - -// @mixin hook-modal-close-default-hover(){} - -// @mixin hook-modal-close-outside(){} - -// @mixin hook-modal-close-outside-hover(){} - - - -// @mixin hook-modal-close-full-hover(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-modal-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/nav.scss b/docs/_sass/uikit/theme/nav.scss deleted file mode 100644 index 191a539458..0000000000 --- a/docs/_sass/uikit/theme/nav.scss +++ /dev/null @@ -1,102 +0,0 @@ -// -// Component: Nav -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$nav-default-font-size: $global-small-font-size !default; - - -// Sublists -// ======================================================================== - -// @mixin hook-nav-sub(){} - - -// Parent icon modifier -// ======================================================================== - -// @mixin hook-nav-parent-icon(){} - - -// Header -// ======================================================================== - -// @mixin hook-nav-header(){} - - -// Divider -// ======================================================================== - -// @mixin hook-nav-divider(){} - - -// Default style modifier -// ======================================================================== - - - -// @mixin hook-nav-default-item(){} - -// @mixin hook-nav-default-item-hover(){} - -// @mixin hook-nav-default-item-active(){} - -// @mixin hook-nav-default-header(){} - -// @mixin hook-nav-default-divider(){} - - -// Primary style modifier -// ======================================================================== - -// @mixin hook-nav-primary(){} - -// @mixin hook-nav-primary-item(){} - -// @mixin hook-nav-primary-item-hover(){} - -// @mixin hook-nav-primary-item-active(){} - -// @mixin hook-nav-primary-header(){} - -// @mixin hook-nav-primary-divider(){} - - -// Style modifier -// ======================================================================== - -// @mixin hook-nav-dividers(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-nav-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-nav-parent-icon(){} - -// @mixin hook-inverse-nav-default-item(){} -// @mixin hook-inverse-nav-default-item-hover(){} -// @mixin hook-inverse-nav-default-item-active(){} -// @mixin hook-inverse-nav-default-header(){} -// @mixin hook-inverse-nav-default-divider(){} - -// @mixin hook-inverse-nav-primary-item(){} -// @mixin hook-inverse-nav-primary-item-hover(){} -// @mixin hook-inverse-nav-primary-item-active(){} -// @mixin hook-inverse-nav-primary-header(){} -// @mixin hook-inverse-nav-primary-divider(){} - -// @mixin hook-inverse-nav-dividers(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/navbar.scss b/docs/_sass/uikit/theme/navbar.scss deleted file mode 100644 index 43aa119f5a..0000000000 --- a/docs/_sass/uikit/theme/navbar.scss +++ /dev/null @@ -1,138 +0,0 @@ -// -// Component: Navbar -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$navbar-nav-item-font-size: $global-small-font-size !default; - -$navbar-dropdown-margin: 15px !default; -$navbar-dropdown-padding: 25px !default; -$navbar-dropdown-background: $global-background !default; -$navbar-dropdown-grid-gutter-horizontal: ($navbar-dropdown-padding * 2) !default; - -// -// New -// - -$navbar-nav-item-text-transform: uppercase !default; - -$navbar-dropdown-nav-font-size: $global-small-font-size !default; - -$navbar-dropdown-box-shadow: 0 5px 12px rgba(0,0,0,0.15) !default; - -$navbar-dropbar-box-shadow: 0 5px 7px rgba(0, 0, 0, 0.05) !default; - -$navbar-dropdown-grid-divider-border-width: $global-border-width !default; -$navbar-dropdown-grid-divider-border: $navbar-dropdown-nav-divider-border !default; - - -// Component -// ======================================================================== - -// @mixin hook-navbar(){} - - -// Container -// ======================================================================== - -// @mixin hook-navbar-container(){} - - -// Nav -// ======================================================================== - - - -// @mixin hook-navbar-nav-item-hover(){} - -// @mixin hook-navbar-nav-item-onclick(){} - -// @mixin hook-navbar-nav-item-active(){} - - -// Item -// ======================================================================== - -// @mixin hook-navbar-item(){} - - -// Toggle -// ======================================================================== - -// @mixin hook-navbar-toggle(){} - -// @mixin hook-navbar-toggle-hover(){} - -// @mixin hook-navbar-toggle-icon(){} - -// @mixin hook-navbar-toggle-icon-hover(){} - - -// Subtitle -// ======================================================================== - -// @mixin hook-navbar-subtitle(){} - - -// Style modifiers -// ======================================================================== - -// @mixin hook-navbar-primary(){} - -// @mixin hook-navbar-transparent(){} - -// @mixin hook-navbar-sticky(){} - - -// Dropdown -// ======================================================================== - - - - - - -// Dropdown nav -// ======================================================================== - - - -// @mixin hook-navbar-dropdown-nav-item(){} - -// @mixin hook-navbar-dropdown-nav-item-hover(){} - -// @mixin hook-navbar-dropdown-nav-header(){} - -// @mixin hook-navbar-dropdown-nav-divider(){} - - -// Dropbar -// ======================================================================== - -// @mixin hook-navbar-dropbar(){} - - - - -// Miscellaneous -// ======================================================================== - - - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-navbar-nav-item(){} -// @mixin hook-inverse-navbar-nav-item-hover(){} -// @mixin hook-inverse-navbar-nav-item-onclick(){} -// @mixin hook-inverse-navbar-nav-item-active(){} - -// @mixin hook-inverse-navbar-item(){} - -// @mixin hook-inverse-navbar-toggle(){} -// @mixin hook-inverse-navbar-toggle-hover(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/notification.scss b/docs/_sass/uikit/theme/notification.scss deleted file mode 100644 index 71c793dbe4..0000000000 --- a/docs/_sass/uikit/theme/notification.scss +++ /dev/null @@ -1,44 +0,0 @@ -// -// Component: Notification -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-notification(){} - - -// Message -// ======================================================================== - -// @mixin hook-notification-message(){} - - -// Close -// ======================================================================== - -// @mixin hook-notification-close(){} - - -// Style modifiers -// ======================================================================== - -// @mixin hook-notification-message-primary(){} - -// @mixin hook-notification-message-success(){} - -// @mixin hook-notification-message-warning(){} - -// @mixin hook-notification-message-danger(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-notification-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/offcanvas.scss b/docs/_sass/uikit/theme/offcanvas.scss deleted file mode 100644 index 283078ef36..0000000000 --- a/docs/_sass/uikit/theme/offcanvas.scss +++ /dev/null @@ -1,32 +0,0 @@ -// -// Component: Off-canvas -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Bar -// ======================================================================== - -// @mixin hook-offcanvas-bar(){} - - -// Close -// ======================================================================== - -// @mixin hook-offcanvas-close(){} - - -// Overlay -// ======================================================================== - -// @mixin hook-offcanvas-overlay(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-offcanvas-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/overlay.scss b/docs/_sass/uikit/theme/overlay.scss deleted file mode 100644 index 68cda45259..0000000000 --- a/docs/_sass/uikit/theme/overlay.scss +++ /dev/null @@ -1,33 +0,0 @@ -// -// Component: Overlay -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-overlay(){} - -// Icon -// ======================================================================== - -// @mixin hook-overlay-icon(){} - - -// Style modifiers -// ======================================================================== - -// @mixin hook-overlay-default(){} - -// @mixin hook-overlay-primary(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-overlay-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/padding.scss b/docs/_sass/uikit/theme/padding.scss deleted file mode 100644 index f0737b873a..0000000000 --- a/docs/_sass/uikit/theme/padding.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Padding -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-padding-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/pagination.scss b/docs/_sass/uikit/theme/pagination.scss deleted file mode 100644 index a777e0c900..0000000000 --- a/docs/_sass/uikit/theme/pagination.scss +++ /dev/null @@ -1,41 +0,0 @@ -// -// Component: Pagination -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-pagination(){} - - -// Items -// ======================================================================== - - - -// @mixin hook-pagination-item-hover(){} - -// @mixin hook-pagination-item-active(){} - -// @mixin hook-pagination-item-disabled(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-pagination-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-pagination-item(){} -// @mixin hook-inverse-pagination-item-hover(){} -// @mixin hook-inverse-pagination-item-active(){} -// @mixin hook-inverse-pagination-item-disabled(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/placeholder.scss b/docs/_sass/uikit/theme/placeholder.scss deleted file mode 100644 index 4ab662cb67..0000000000 --- a/docs/_sass/uikit/theme/placeholder.scss +++ /dev/null @@ -1,29 +0,0 @@ -// -// Component: Placeholder -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$placeholder-background: transparent !default; - -// -// New -// - -$placeholder-border-width: $global-border-width !default; -$placeholder-border: $global-border !default; - - -// Component -// ======================================================================== - - - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-placeholder-misc(){} diff --git a/docs/_sass/uikit/theme/position.scss b/docs/_sass/uikit/theme/position.scss deleted file mode 100644 index fc69520898..0000000000 --- a/docs/_sass/uikit/theme/position.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Position -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-position-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/progress.scss b/docs/_sass/uikit/theme/progress.scss deleted file mode 100644 index 9ca100a3e6..0000000000 --- a/docs/_sass/uikit/theme/progress.scss +++ /dev/null @@ -1,24 +0,0 @@ -// -// Component: Progress -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$progress-border-radius: 500px !default; - - -// Component -// ======================================================================== - - - -// @mixin hook-progress-bar(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-progress-misc(){} diff --git a/docs/_sass/uikit/theme/search.scss b/docs/_sass/uikit/theme/search.scss deleted file mode 100644 index 1cd2103d8a..0000000000 --- a/docs/_sass/uikit/theme/search.scss +++ /dev/null @@ -1,75 +0,0 @@ -// -// Component: Search -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$search-default-background: transparent !default; - -// -// New -// - -$search-default-border-width: $global-border-width !default; -$search-default-border: $global-border !default; - -$search-default-focus-border: $global-primary-background !default; - - -// Component -// ======================================================================== - -// @mixin hook-search-input(){} - - -// Default modifiers -// ======================================================================== - - - - - - -// Navbar modifiers -// ======================================================================== - -// @mixin hook-search-navbar-input(){} - - -// Large modifiers -// ======================================================================== - -// @mixin hook-search-large-input(){} - - -// Toggle -// ======================================================================== - -// @mixin hook-search-toggle(){} - -// @mixin hook-search-toggle-hover(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-search-misc(){} - - -// Inverse -// ======================================================================== - -$inverse-search-default-background: transparent !default; - - -// @mixin hook-inverse-search-default-input-focus(){} - -// @mixin hook-inverse-search-navbar-input(){} - -// @mixin hook-inverse-search-large-input(){} - -// @mixin hook-inverse-search-toggle(){} -// @mixin hook-inverse-search-toggle-hover(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/section.scss b/docs/_sass/uikit/theme/section.scss deleted file mode 100644 index 6d7f761b6e..0000000000 --- a/docs/_sass/uikit/theme/section.scss +++ /dev/null @@ -1,32 +0,0 @@ -// -// Component: Section -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-section(){} - - -// Style modifiers -// ======================================================================== - -// @mixin hook-section-default(){} - -// @mixin hook-section-muted(){} - -// @mixin hook-section-primary(){} - -// @mixin hook-section-secondary(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-section-misc(){} diff --git a/docs/_sass/uikit/theme/slidenav.scss b/docs/_sass/uikit/theme/slidenav.scss deleted file mode 100644 index 60dcb22249..0000000000 --- a/docs/_sass/uikit/theme/slidenav.scss +++ /dev/null @@ -1,52 +0,0 @@ -// -// Component: Slidenav -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - - - -// @mixin hook-slidenav-hover(){} - -// @mixin hook-slidenav-active(){} - - -// Icon modifier -// ======================================================================== - -// @mixin hook-slidenav-previous(){} - -// @mixin hook-slidenav-next(){} - - -// Size modifier -// ======================================================================== - -// @mixin hook-slidenav-large(){} - - -// Container -// ======================================================================== - -// @mixin hook-slidenav-container(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-slidenav-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-slidenav(){} -// @mixin hook-inverse-slidenav-hover(){} -// @mixin hook-inverse-slidenav-active(){} diff --git a/docs/_sass/uikit/theme/slider.scss b/docs/_sass/uikit/theme/slider.scss deleted file mode 100644 index b8d40fa124..0000000000 --- a/docs/_sass/uikit/theme/slider.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Slider -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-slider-misc(){} diff --git a/docs/_sass/uikit/theme/sortable.scss b/docs/_sass/uikit/theme/sortable.scss deleted file mode 100644 index 3ab18c3db1..0000000000 --- a/docs/_sass/uikit/theme/sortable.scss +++ /dev/null @@ -1,38 +0,0 @@ -// -// Component: Sortable -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-sortable(){} - - -// Drag -// ======================================================================== - -// @mixin hook-sortable-drag(){} - - -// Placeholder -// ======================================================================== - -// @mixin hook-sortable-placeholder(){} - - -// Empty -// ======================================================================== - -// @mixin hook-sortable-empty(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-sortable-misc(){} diff --git a/docs/_sass/uikit/theme/spinner.scss b/docs/_sass/uikit/theme/spinner.scss deleted file mode 100644 index d70e10fa81..0000000000 --- a/docs/_sass/uikit/theme/spinner.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Spinner -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-spinner-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/sticky.scss b/docs/_sass/uikit/theme/sticky.scss deleted file mode 100644 index 94e5ee69ee..0000000000 --- a/docs/_sass/uikit/theme/sticky.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Sticky -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-sticky-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/subnav.scss b/docs/_sass/uikit/theme/subnav.scss deleted file mode 100644 index f4d1c7fd06..0000000000 --- a/docs/_sass/uikit/theme/subnav.scss +++ /dev/null @@ -1,74 +0,0 @@ -// -// Component: Subnav -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$subnav-item-font-size: $global-small-font-size !default; -$subnav-item-text-transform: uppercase !default; - - -// Component -// ======================================================================== - -// @mixin hook-subnav(){} - - - -// @mixin hook-subnav-item-hover(){} - -// @mixin hook-subnav-item-active(){} - - -// Divider modifier -// ======================================================================== - -// @mixin hook-subnav-divider(){} - - -// Pill modifier -// ======================================================================== - -// @mixin hook-subnav-pill-item(){} - -// @mixin hook-subnav-pill-item-hover(){} - -// @mixin hook-subnav-pill-item-onclick(){} - -// @mixin hook-subnav-pill-item-active(){} - - -// Disabled -// ======================================================================== - -// @mixin hook-subnav-item-disabled(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-subnav-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-subnav-item(){} -// @mixin hook-inverse-subnav-item-hover(){} -// @mixin hook-inverse-subnav-item-active(){} - -// @mixin hook-inverse-subnav-divider(){} - -// @mixin hook-inverse-subnav-pill-item(){} -// @mixin hook-inverse-subnav-pill-item-hover(){} -// @mixin hook-inverse-subnav-pill-item-onclick(){} -// @mixin hook-inverse-subnav-pill-item-active(){} - -// @mixin hook-inverse-subnav-item-disabled(){} diff --git a/docs/_sass/uikit/theme/tab.scss b/docs/_sass/uikit/theme/tab.scss deleted file mode 100644 index 51c4ba2866..0000000000 --- a/docs/_sass/uikit/theme/tab.scss +++ /dev/null @@ -1,74 +0,0 @@ -// -// Component: Tab -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$tab-border-width: $global-border-width !default; -$tab-border: $global-border !default; - -$tab-item-border-width: $global-border-width !default; -$tab-item-font-size: $global-small-font-size !default; -$tab-item-text-transform: uppercase !default; - -$tab-item-active-border: $global-primary-background !default; - - -// Component -// ======================================================================== - - - - -// Items -// ======================================================================== - - - -// @mixin hook-tab-item-hover(){} - - - -// @mixin hook-tab-item-disabled(){} - - -// Position modifiers -// ======================================================================== - - - - - - - - - - - - - - -// Miscellaneous -// ======================================================================== - - - - -// Inverse -// ======================================================================== - -$inverse-tab-border: $inverse-global-border !default; - - - -// @mixin hook-inverse-tab-item(){} -// @mixin hook-inverse-tab-item-hover(){} - -// @mixin hook-inverse-tab-item-disabled(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/table.scss b/docs/_sass/uikit/theme/table.scss deleted file mode 100644 index d6a660793b..0000000000 --- a/docs/_sass/uikit/theme/table.scss +++ /dev/null @@ -1,68 +0,0 @@ -// -// Component: Table -// -// ======================================================================== - - -// Variables -// ======================================================================== - -$table-header-cell-font-size: $global-small-font-size !default; -$table-header-cell-font-weight: normal !default; -$table-header-cell-color: $global-muted-color !default; - -// -// New -// - -$table-striped-border-width: $global-border-width !default; -$table-striped-border: $global-border !default; - - -// Component -// ======================================================================== - - - -// @mixin hook-table-cell(){} - -// @mixin hook-table-footer(){} - -// @mixin hook-table-caption(){} - -// @mixin hook-table-row-active(){} - - -// Style modifiers -// ======================================================================== - -// @mixin hook-table-divider(){} - - - -// @mixin hook-table-hover(){} - - -// Size modifier -// ======================================================================== - -// @mixin hook-table-small(){} - -// @mixin hook-table-large(){} - - -// Miscellaneous -// ======================================================================== - - - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-table-header-cell(){} -// @mixin hook-inverse-table-caption(){} -// @mixin hook-inverse-table-row-active(){} -// @mixin hook-inverse-table-divider(){} - -// @mixin hook-inverse-table-hover(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/text.scss b/docs/_sass/uikit/theme/text.scss deleted file mode 100644 index b6e35c431f..0000000000 --- a/docs/_sass/uikit/theme/text.scss +++ /dev/null @@ -1,50 +0,0 @@ -// -// Component: Text -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$text-meta-link-color: $text-meta-color !default; -$text-meta-link-hover-color: $global-color !default; - - -// Style modifiers -// ======================================================================== - -// @mixin hook-text-lead(){} - - - - -// Size modifiers -// ======================================================================== - -// @mixin hook-text-small(){} - -// @mixin hook-text-large(){} - - -// Background modifier -// ======================================================================== - -// @mixin hook-text-background(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-text-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-text-lead(){} -// @mixin hook-inverse-text-meta(){} diff --git a/docs/_sass/uikit/theme/thumbnav.scss b/docs/_sass/uikit/theme/thumbnav.scss deleted file mode 100644 index 7f26c38aa8..0000000000 --- a/docs/_sass/uikit/theme/thumbnav.scss +++ /dev/null @@ -1,42 +0,0 @@ -// -// Component: Thumbnav -// -// ======================================================================== - - -// Variables -// ======================================================================== - -// -// New -// - -$thumbnav-item-background: rgba($global-background, 0.4) !default; -$thumbnav-item-hover-background: transparent !default; -$thumbnav-item-active-background: transparent !default; - - -// Component -// ======================================================================== - -// @mixin hook-thumbnav(){} - - - - - - - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-thumbnav-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-thumbnav-item(){} -// @mixin hook-inverse-thumbnav-item-hover(){} -// @mixin hook-inverse-thumbnav-item-active(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/tile.scss b/docs/_sass/uikit/theme/tile.scss deleted file mode 100644 index 2d043a6338..0000000000 --- a/docs/_sass/uikit/theme/tile.scss +++ /dev/null @@ -1,32 +0,0 @@ -// -// Component: Tile -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-tile(){} - - -// Style modifiers -// ======================================================================== - -// @mixin hook-tile-default(){} - -// @mixin hook-tile-muted(){} - -// @mixin hook-tile-primary(){} - -// @mixin hook-tile-secondary(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-tile-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/tooltip.scss b/docs/_sass/uikit/theme/tooltip.scss deleted file mode 100644 index 5115139c31..0000000000 --- a/docs/_sass/uikit/theme/tooltip.scss +++ /dev/null @@ -1,20 +0,0 @@ -// -// Component: Tooltip -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - -// @mixin hook-tooltip(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-tooltip-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/totop.scss b/docs/_sass/uikit/theme/totop.scss deleted file mode 100644 index feb7165a1d..0000000000 --- a/docs/_sass/uikit/theme/totop.scss +++ /dev/null @@ -1,32 +0,0 @@ -// -// Component: Totop -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Component -// ======================================================================== - - - -// @mixin hook-totop-hover(){} - -// @mixin hook-totop-active(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-icon-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-totop(){} -// @mixin hook-inverse-totop-hover(){} -// @mixin hook-inverse-totop-active(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/transition.scss b/docs/_sass/uikit/theme/transition.scss deleted file mode 100644 index fd7bdede45..0000000000 --- a/docs/_sass/uikit/theme/transition.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Transition -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-transition-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/utility.scss b/docs/_sass/uikit/theme/utility.scss deleted file mode 100644 index 69094998a0..0000000000 --- a/docs/_sass/uikit/theme/utility.scss +++ /dev/null @@ -1,49 +0,0 @@ -// -// Component: Utility -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Panel -// ======================================================================== - -// @mixin hook-panel-scrollable(){} - - -// Box-shadow bottom -// ======================================================================== - -// @mixin hook-box-shadow-bottom(){} - - -// Drop cap -// ======================================================================== - - - - -// Logo -// ======================================================================== - -// @mixin hook-logo(){} - -// @mixin hook-logo-hover(){} - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-utility-misc(){} - - -// Inverse -// ======================================================================== - -// @mixin hook-inverse-dropcap(){} - -// @mixin hook-inverse-logo(){} -// @mixin hook-inverse-logo-hover(){} \ No newline at end of file diff --git a/docs/_sass/uikit/theme/variables.scss b/docs/_sass/uikit/theme/variables.scss deleted file mode 100644 index d74b3a9971..0000000000 --- a/docs/_sass/uikit/theme/variables.scss +++ /dev/null @@ -1,36 +0,0 @@ -// -// Component: Variables -// -// ======================================================================== - - -// Global variables -// ======================================================================== - -// -// Typography -// - -// -// Colors -// - -// -// Backgrounds -// - -// -// Borders -// - -// -// Spacings -// - -// -// Controls -// - -// -// Z-index -// \ No newline at end of file diff --git a/docs/_sass/uikit/theme/width.scss b/docs/_sass/uikit/theme/width.scss deleted file mode 100644 index b67a7954ed..0000000000 --- a/docs/_sass/uikit/theme/width.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Component: Width -// -// ======================================================================== - - -// Variables -// ======================================================================== - - -// Miscellaneous -// ======================================================================== - -// @mixin hook-width-misc(){} \ No newline at end of file diff --git a/docs/_sass/uikit/uikit-theme.scss b/docs/_sass/uikit/uikit-theme.scss deleted file mode 100644 index d114210fba..0000000000 --- a/docs/_sass/uikit/uikit-theme.scss +++ /dev/null @@ -1,9 +0,0 @@ -// -// Theme -// - -@import "https://github.com/uikit/theme/import"; - -@import "https://github.com/uikit/components/import"; - - diff --git a/docs/_sass/uikit/uikit.scss b/docs/_sass/uikit/uikit.scss deleted file mode 100644 index d4a737e989..0000000000 --- a/docs/_sass/uikit/uikit.scss +++ /dev/null @@ -1,5 +0,0 @@ -// -// Core -// - -@import "https://github.com/uikit/components/import"; \ No newline at end of file diff --git a/docs/_sass/uikit/variables-theme.scss b/docs/_sass/uikit/variables-theme.scss deleted file mode 100644 index 2f0f90ef51..0000000000 --- a/docs/_sass/uikit/variables-theme.scss +++ /dev/null @@ -1,1172 +0,0 @@ -$global-margin: 20px !default; -$accordion-item-margin-top: $global-margin !default; -$global-medium-font-size: 1.25rem !default; -$accordion-title-font-size: $global-medium-font-size !default; -$accordion-title-line-height: 1.4 !default; -$global-emphasis-color: #333 !default; -$accordion-title-color: $global-emphasis-color !default; -$global-color: #666 !default; -$accordion-title-hover-color: $global-color !default; -$accordion-content-margin-top: $global-margin !default; -$global-inverse-color: #fff !default; -$inverse-global-emphasis-color: $global-inverse-color !default; -$inverse-accordion-title-color: $inverse-global-emphasis-color !default; -$inverse-global-color: rgba($global-inverse-color, 0.7) !default; -$inverse-accordion-title-hover-color: $inverse-global-color !default; -$alert-margin-vertical: $global-margin !default; -$alert-padding: 15px !default; -$alert-padding-right: $alert-padding + 14px !default; -$global-muted-background: #f8f8f8 !default; -$alert-background: $global-muted-background !default; -$alert-color: $global-color !default; -$alert-close-top: $alert-padding + 5px !default; -$alert-close-right: $alert-padding !default; -$global-primary-background: #1e87f0 !default; -$alert-primary-background: lighten(mix(white, $global-primary-background, 40%), 20%) !default; -$alert-primary-color: $global-primary-background !default; -$global-success-background: #32d296 !default; -$alert-success-background: lighten(mix(white, $global-success-background, 40%), 25%) !default; -$alert-success-color: $global-success-background !default; -$global-warning-background: #faa05a !default; -$alert-warning-background: lighten(mix(white, $global-warning-background, 45%), 15%) !default; -$alert-warning-color: $global-warning-background !default; -$global-danger-background: #f0506e !default; -$alert-danger-background: lighten(mix(white, $global-danger-background, 40%), 20%) !default; -$alert-danger-color: $global-danger-background !default; -$global-gutter: 30px !default; -$align-margin-horizontal: $global-gutter !default; -$align-margin-vertical: $global-gutter !default; -$global-medium-gutter: 40px !default; -$align-margin-horizontal-l: $global-medium-gutter !default; -$animation-duration: 0.5s !default; -$animation-fade-duration: 0.8s !default; -$animation-stroke-duration: 2s !default; -$animation-kenburns-duration: 15s !default; -$animation-fast-duration: 0.1s !default; -$animation-slide-small-translate: 10px !default; -$animation-slide-medium-translate: 50px !default; -$global-large-margin: 70px !default; -$article-margin-top: $global-large-margin !default; -$global-2xlarge-font-size: 2.625rem !default; -$article-title-font-size-m: $global-2xlarge-font-size !default; -$article-title-font-size: $article-title-font-size-m * 0.85 !default; -$article-title-line-height: 1.2 !default; -$global-small-font-size: 0.875rem !default; -$article-meta-font-size: $global-small-font-size !default; -$article-meta-line-height: 1.4 !default; -$global-muted-color: #999 !default; -$article-meta-color: $global-muted-color !default; -$inverse-global-muted-color: rgba($global-inverse-color, 0.5) !default; -$inverse-article-meta-color: $inverse-global-muted-color !default; -$global-background: #fff !default; -$background-default-background: $global-background !default; -$background-muted-background: $global-muted-background !default; -$background-primary-background: $global-primary-background !default; -$global-secondary-background: #222 !default; -$background-secondary-background: $global-secondary-background !default; -$badge-size: 18px !default; -$badge-padding-vertical: 0 !default; -$badge-padding-horizontal: 5px !default; -$badge-border-radius: 500px !default; -$badge-background: $global-primary-background !default; -$badge-color: $global-inverse-color !default; -$badge-font-size: 11px !default; -$inverse-global-primary-background: $global-inverse-color !default; -$inverse-badge-background: $inverse-global-primary-background !default; -$inverse-global-inverse-color: $global-color !default; -$inverse-badge-color: $inverse-global-inverse-color !default; -$base-body-background: $global-background !default; -$global-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; -$base-body-font-family: $global-font-family !default; -$base-body-font-weight: normal !default; -$global-font-size: 16px !default; -$base-body-font-size: $global-font-size !default; -$global-line-height: 1.5 !default; -$base-body-line-height: $global-line-height !default; -$base-body-color: $global-color !default; -$global-link-color: #1e87f0 !default; -$base-link-color: $global-link-color !default; -$base-link-text-decoration: none !default; -$global-link-hover-color: #0f6ecd !default; -$base-link-hover-color: $global-link-hover-color !default; -$base-link-hover-text-decoration: underline !default; -$base-strong-font-weight: bolder !default; -$base-code-font-size: $global-small-font-size !default; -$base-code-font-family: Consolas, monaco, monospace !default; -$base-code-color: $global-danger-background !default; -$base-em-color: $global-danger-background !default; -$base-ins-background: #ffd !default; -$base-ins-color: $global-color !default; -$base-mark-background: #ffd !default; -$base-mark-color: $global-color !default; -$base-quote-font-style: italic !default; -$base-small-font-size: 80% !default; -$base-margin-vertical: $global-margin !default; -$base-heading-font-family: $global-font-family !default; -$base-heading-font-weight: normal !default; -$base-heading-color: $global-emphasis-color !default; -$base-heading-text-transform: none !default; -$global-medium-margin: 40px !default; -$base-heading-margin-top: $global-medium-margin !default; -$base-h1-font-size-m: $global-2xlarge-font-size !default; -$base-h1-font-size: $base-h1-font-size-m * 0.85 !default; -$base-h1-line-height: 1.2 !default; -$global-xlarge-font-size: 2rem !default; -$base-h2-font-size-m: $global-xlarge-font-size !default; -$base-h2-font-size: $base-h2-font-size-m * 0.85 !default; -$base-h2-line-height: 1.3 !default; -$global-large-font-size: 1.5rem !default; -$base-h3-font-size: $global-large-font-size !default; -$base-h3-line-height: 1.4 !default; -$base-h4-font-size: $global-medium-font-size !default; -$base-h4-line-height: 1.4 !default; -$base-h5-font-size: $global-font-size !default; -$base-h5-line-height: 1.4 !default; -$base-h6-font-size: $global-small-font-size !default; -$base-h6-line-height: 1.4 !default; -$base-list-padding-left: 30px !default; -$base-hr-margin-vertical: $global-margin !default; -$global-border-width: 1px !default; -$base-hr-border-width: $global-border-width !default; -$global-border: #e5e5e5 !default; -$base-hr-border: $global-border !default; -$base-blockquote-font-size: $global-medium-font-size !default; -$base-blockquote-line-height: 1.5 !default; -$base-blockquote-font-style: italic !default; -$base-blockquote-margin-vertical: $global-margin !default; -$global-small-margin: 10px !default; -$base-blockquote-footer-margin-top: $global-small-margin !default; -$base-blockquote-footer-font-size: $global-small-font-size !default; -$base-blockquote-footer-line-height: 1.5 !default; -$base-pre-font-size: $global-small-font-size !default; -$base-pre-line-height: 1.5 !default; -$base-pre-font-family: $base-code-font-family !default; -$base-pre-color: $global-color !default; -$base-selection-background: #39f !default; -$base-selection-color: $global-inverse-color !default; -$inverse-base-color: $inverse-global-color !default; -$inverse-base-link-color: $inverse-global-emphasis-color !default; -$inverse-base-link-hover-color: $inverse-global-emphasis-color !default; -$inverse-base-code-color: $inverse-global-color !default; -$inverse-base-em-color: $inverse-global-emphasis-color !default; -$inverse-base-heading-color: $inverse-global-emphasis-color !default; -$inverse-global-border: rgba($global-inverse-color, 0.2) !default; -$inverse-base-hr-border: $inverse-global-border !default; -$breadcrumb-item-font-size: $global-small-font-size !default; -$breadcrumb-item-color: $global-muted-color !default; -$breadcrumb-item-hover-color: $global-color !default; -$breadcrumb-item-hover-text-decoration: none !default; -$breadcrumb-item-active-color: $global-color !default; -$breadcrumb-divider: "/" !default; -$breadcrumb-divider-margin-horizontal: 20px !default; -$breadcrumb-divider-font-size: $breadcrumb-item-font-size !default; -$breadcrumb-divider-color: $global-muted-color !default; -$inverse-breadcrumb-item-color: $inverse-global-muted-color !default; -$inverse-breadcrumb-item-hover-color: $inverse-global-color !default; -$inverse-breadcrumb-item-active-color: $inverse-global-color !default; -$inverse-breadcrumb-divider-color: $inverse-global-muted-color !default; -$global-control-height: 40px !default; -$button-border-width: $global-border-width !default; -$button-line-height: $global-control-height - ($button-border-width * 2) !default; -$global-control-small-height: 30px !default; -$button-small-line-height: $global-control-small-height - ($button-border-width * 2) !default; -$global-control-large-height: 55px !default; -$button-large-line-height: $global-control-large-height - ($button-border-width * 2) !default; -$button-font-size: $global-small-font-size !default; -$button-small-font-size: $global-small-font-size !default; -$button-large-font-size: $global-small-font-size !default; -$button-padding-horizontal: $global-gutter !default; -$global-small-gutter: 15px !default; -$button-small-padding-horizontal: $global-small-gutter !default; -$button-large-padding-horizontal: $global-medium-gutter !default; -$button-default-background: transparent !default; -$button-default-color: $global-emphasis-color !default; -$button-default-hover-background: transparent !default; -$button-default-hover-color: $global-emphasis-color !default; -$button-default-active-background: transparent !default; -$button-default-active-color: $global-emphasis-color !default; -$button-primary-background: $global-primary-background !default; -$button-primary-color: $global-inverse-color !default; -$button-primary-hover-background: darken($button-primary-background, 5%) !default; -$button-primary-hover-color: $global-inverse-color !default; -$button-primary-active-background: darken($button-primary-background, 10%) !default; -$button-primary-active-color: $global-inverse-color !default; -$button-secondary-background: $global-secondary-background !default; -$button-secondary-color: $global-inverse-color !default; -$button-secondary-hover-background: darken($button-secondary-background, 5%) !default; -$button-secondary-hover-color: $global-inverse-color !default; -$button-secondary-active-background: darken($button-secondary-background, 10%) !default; -$button-secondary-active-color: $global-inverse-color !default; -$button-danger-background: $global-danger-background !default; -$button-danger-color: $global-inverse-color !default; -$button-danger-hover-background: darken($button-danger-background, 5%) !default; -$button-danger-hover-color: $global-inverse-color !default; -$button-danger-active-background: darken($button-danger-background, 10%) !default; -$button-danger-active-color: $global-inverse-color !default; -$button-disabled-background: transparent !default; -$button-disabled-color: $global-muted-color !default; -$button-text-line-height: $global-line-height !default; -$button-text-color: $global-emphasis-color !default; -$button-text-hover-color: $global-emphasis-color !default; -$button-text-disabled-color: $global-muted-color !default; -$button-link-line-height: $global-line-height !default; -$button-link-color: $global-emphasis-color !default; -$button-link-hover-color: $global-muted-color !default; -$button-link-hover-text-decoration: none !default; -$button-link-disabled-color: $global-muted-color !default; -$inverse-button-default-background: transparent !default; -$inverse-button-default-color: $inverse-global-emphasis-color !default; -$inverse-button-default-hover-background: transparent !default; -$inverse-button-default-hover-color: $inverse-global-emphasis-color !default; -$inverse-button-default-active-background: transparent !default; -$inverse-button-default-active-color: $inverse-global-emphasis-color !default; -$inverse-button-primary-background: $inverse-global-primary-background !default; -$inverse-button-primary-color: $inverse-global-inverse-color !default; -$inverse-button-primary-hover-background: darken($inverse-button-primary-background, 5%) !default; -$inverse-button-primary-hover-color: $inverse-global-inverse-color !default; -$inverse-button-primary-active-background: darken($inverse-button-primary-background, 10%) !default; -$inverse-button-primary-active-color: $inverse-global-inverse-color !default; -$inverse-button-secondary-background: $inverse-global-primary-background !default; -$inverse-button-secondary-color: $inverse-global-inverse-color !default; -$inverse-button-secondary-hover-background: darken($inverse-button-secondary-background, 5%) !default; -$inverse-button-secondary-hover-color: $inverse-global-inverse-color !default; -$inverse-button-secondary-active-background: darken($inverse-button-secondary-background, 10%) !default; -$inverse-button-secondary-active-color: $inverse-global-inverse-color !default; -$inverse-button-text-color: $inverse-global-emphasis-color !default; -$inverse-button-text-hover-color: $inverse-global-emphasis-color !default; -$inverse-button-text-disabled-color: $inverse-global-muted-color !default; -$inverse-button-link-color: $inverse-global-emphasis-color !default; -$inverse-button-link-hover-color: $inverse-global-muted-color !default; -$card-body-padding-horizontal: $global-gutter !default; -$card-body-padding-vertical: $global-gutter !default; -$card-body-padding-horizontal-l: $global-medium-gutter !default; -$card-body-padding-vertical-l: $global-medium-gutter !default; -$card-header-padding-horizontal: $global-gutter !default; -$card-header-padding-vertical: round($global-gutter / 2) !default; -$card-header-padding-horizontal-l: $global-medium-gutter !default; -$card-header-padding-vertical-l: round($global-medium-gutter / 2) !default; -$card-footer-padding-horizontal: $global-gutter !default; -$card-footer-padding-vertical: ($global-gutter / 2) !default; -$card-footer-padding-horizontal-l: $global-medium-gutter !default; -$card-footer-padding-vertical-l: round($global-medium-gutter / 2) !default; -$card-title-font-size: $global-large-font-size !default; -$card-title-line-height: 1.4 !default; -$card-badge-top: 15px !default; -$card-badge-right: 15px !default; -$card-badge-height: 22px !default; -$card-badge-padding-horizontal: 10px !default; -$card-badge-background: $global-primary-background !default; -$card-badge-color: $global-inverse-color !default; -$card-badge-font-size: $global-small-font-size !default; -$card-hover-background: $global-background !default; -$card-default-background: $global-background !default; -$card-default-color: $global-color !default; -$card-default-title-color: $global-emphasis-color !default; -$card-default-hover-background: $card-default-background !default; -$card-primary-background: $global-primary-background !default; -$card-primary-color: $global-inverse-color !default; -$card-primary-title-color: $card-primary-color !default; -$card-primary-hover-background: $card-primary-background !default; -$card-primary-color-mode: light !default; -$card-secondary-background: $global-secondary-background !default; -$card-secondary-color: $global-inverse-color !default; -$card-secondary-title-color: $card-secondary-color !default; -$card-secondary-hover-background: $card-secondary-background !default; -$card-secondary-color-mode: light !default; -$card-small-body-padding-horizontal: $global-margin !default; -$card-small-body-padding-vertical: $global-margin !default; -$card-small-header-padding-horizontal: $global-margin !default; -$card-small-header-padding-vertical: round($global-margin / 1.5) !default; -$card-small-footer-padding-horizontal: $global-margin !default; -$card-small-footer-padding-vertical: round($global-margin / 1.5) !default; -$global-large-gutter: 70px !default; -$card-large-body-padding-horizontal-l: $global-large-gutter !default; -$card-large-body-padding-vertical-l: $global-large-gutter !default; -$card-large-header-padding-horizontal-l: $global-large-gutter !default; -$card-large-header-padding-vertical-l: round($global-large-gutter / 2) !default; -$card-large-footer-padding-horizontal-l: $global-large-gutter !default; -$card-large-footer-padding-vertical-l: round($global-large-gutter / 2) !default; -$inverse-card-badge-background: $inverse-global-primary-background !default; -$inverse-card-badge-color: $inverse-global-inverse-color !default; -$close-color: $global-muted-color !default; -$close-hover-color: $global-color !default; -$inverse-close-color: $inverse-global-muted-color !default; -$inverse-close-hover-color: $inverse-global-color !default; -$column-gutter: $global-gutter !default; -$column-gutter-l: $global-medium-gutter !default; -$column-divider-rule-color: $global-border !default; -$column-divider-rule-width: 1px !default; -$inverse-column-divider-rule-color: $inverse-global-border !default; -$comment-header-margin-bottom: $global-margin !default; -$comment-title-font-size: $global-medium-font-size !default; -$comment-title-line-height: 1.4 !default; -$comment-meta-font-size: $global-small-font-size !default; -$comment-meta-line-height: 1.4 !default; -$comment-meta-color: $global-muted-color !default; -$comment-list-margin-top: $global-large-margin !default; -$comment-list-padding-left: 30px !default; -$comment-list-padding-left-m: 100px !default; -$container-max-width: 1200px !default; -$container-xsmall-max-width: 750px !default; -$container-small-max-width: 900px !default; -$container-large-max-width: 1400px !default; -$container-xlarge-max-width: 1600px !default; -$container-padding-horizontal: 15px !default; -$container-padding-horizontal-s: $global-gutter !default; -$container-padding-horizontal-m: $global-medium-gutter !default; -$countdown-number-line-height: 0.8 !default; -$countdown-number-font-size: 2rem !default; -$countdown-number-font-size-s: 4rem !default; -$countdown-number-font-size-m: 6rem !default; -$countdown-separator-line-height: 1.6 !default; -$countdown-separator-font-size: 1rem !default; -$countdown-separator-font-size-s: 2rem !default; -$countdown-separator-font-size-m: 3rem !default; -$description-list-term-color: $global-emphasis-color !default; -$description-list-term-margin-top: $global-margin !default; -$description-list-divider-term-margin-top: $global-margin !default; -$description-list-divider-term-border-width: $global-border-width !default; -$description-list-divider-term-border: $global-border !default; -$divider-margin-vertical: $global-margin !default; -$divider-icon-width: 50px !default; -$divider-icon-height: 20px !default; -$divider-icon-color: $global-border !default; -$divider-icon-line-top: 50% !default; -$divider-icon-line-width: 100% !default; -$divider-icon-line-border-width: $global-border-width !default; -$divider-icon-line-border: $global-border !default; -$internal-divider-icon-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default; -$divider-small-width: 100px !default; -$divider-small-border-width: $global-border-width !default; -$divider-small-border: $global-border !default; -$divider-vertical-height: 100px !default; -$divider-vertical-border-width: $global-border-width !default; -$divider-vertical-border: $global-border !default; -$inverse-divider-icon-color: $inverse-global-border !default; -$inverse-divider-icon-line-border: $inverse-global-border !default; -$inverse-divider-small-border: $inverse-global-border !default; -$inverse-divider-vertical-border: $inverse-global-border !default; -$dotnav-margin-horizontal: 12px !default; -$dotnav-margin-vertical: $dotnav-margin-horizontal !default; -$dotnav-item-width: 10px !default; -$dotnav-item-height: $dotnav-item-width !default; -$dotnav-item-border-radius: 50% !default; -$dotnav-item-background: transparent !default; -$dotnav-item-hover-background: rgba($global-color, 0.6) !default; -$dotnav-item-onclick-background: rgba($global-color, 0.2) !default; -$dotnav-item-active-background: rgba($global-color, 0.6) !default; -$inverse-dotnav-item-background: transparent !default; -$inverse-dotnav-item-hover-background: rgba($inverse-global-color, 0.9) !default; -$inverse-dotnav-item-onclick-background: rgba($inverse-global-color, 0.5) !default; -$inverse-dotnav-item-active-background: rgba($inverse-global-color, 0.9) !default; -$global-z-index: 1000 !default; -$drop-z-index: $global-z-index + 20 !default; -$drop-width: 300px !default; -$drop-margin: $global-margin !default; -$dropdown-z-index: $global-z-index + 20 !default; -$dropdown-min-width: 200px !default; -$dropdown-padding: 25px !default; -$dropdown-background: $global-background !default; -$dropdown-color: $global-color !default; -$dropdown-margin: $global-small-margin !default; -$dropdown-nav-item-color: $global-muted-color !default; -$dropdown-nav-item-hover-color: $global-color !default; -$dropdown-nav-header-color: $global-emphasis-color !default; -$dropdown-nav-divider-border-width: $global-border-width !default; -$dropdown-nav-divider-border: $global-border !default; -$dropdown-nav-sublist-item-color: $global-muted-color !default; -$dropdown-nav-sublist-item-hover-color: $global-color !default; -$form-range-thumb-height: 15px !default; -$form-range-thumb-width: $form-range-thumb-height !default; -$form-range-thumb-border-radius: 500px !default; -$form-range-thumb-background: $global-background !default; -$form-range-track-height: 3px !default; -$form-range-track-background: darken($global-muted-background, 5%) !default; -$form-range-track-focus-background: darken($form-range-track-background, 5%) !default; -$form-height: $global-control-height !default; -$form-border-width: $global-border-width !default; -$form-line-height: $form-height - (2* $form-border-width) !default; -$form-padding-horizontal: 10px !default; -$form-padding-vertical: round($form-padding-horizontal * 0.6) !default; -$form-background: $global-background !default; -$form-color: $global-color !default; -$form-focus-background: $global-background !default; -$form-focus-color: $global-color !default; -$form-disabled-background: $global-muted-background !default; -$form-disabled-color: $global-muted-color !default; -$form-placeholder-color: $global-muted-color !default; -$form-small-height: $global-control-small-height !default; -$form-small-padding-horizontal: 8px !default; -$form-small-padding-vertical: round($form-small-padding-horizontal * 0.6) !default; -$form-small-line-height: $form-small-height - (2* $form-border-width) !default; -$form-small-font-size: $global-small-font-size !default; -$form-large-height: $global-control-large-height !default; -$form-large-padding-horizontal: 12px !default; -$form-large-padding-vertical: round($form-large-padding-horizontal * 0.6) !default; -$form-large-line-height: $form-large-height - (2* $form-border-width) !default; -$form-large-font-size: $global-medium-font-size !default; -$form-danger-color: $global-danger-background !default; -$form-success-color: $global-success-background !default; -$form-width-xsmall: 50px !default; -$form-width-small: 130px !default; -$form-width-medium: 200px !default; -$form-width-large: 500px !default; -$form-select-padding-right: 20px !default; -$form-select-icon-color: $global-color !default; -$form-select-option-color: #444 !default; -$form-select-disabled-icon-color: $global-muted-color !default; -$form-datalist-padding-right: 20px !default; -$form-datalist-icon-color: $global-color !default; -$form-radio-size: 16px !default; -$form-radio-margin-top: -4px !default; -$form-radio-background: transparent !default; -$form-radio-focus-background: darken($form-radio-background, 5%) !default; -$form-radio-checked-background: $global-primary-background !default; -$form-radio-checked-icon-color: $global-inverse-color !default; -$form-radio-checked-focus-background: darken($global-primary-background, 10%) !default; -$form-radio-disabled-background: $global-muted-background !default; -$form-radio-disabled-icon-color: $global-muted-color !default; -$form-legend-font-size: $global-large-font-size !default; -$form-legend-line-height: 1.4 !default; -$form-stacked-margin-bottom: 5px !default; -$form-horizontal-label-width: 200px !default; -$form-horizontal-label-margin-top: 7px !default; -$form-horizontal-controls-margin-left: 215px !default; -$form-horizontal-controls-text-padding-top: 7px !default; -$form-icon-width: $form-height !default; -$form-icon-color: $global-muted-color !default; -$form-icon-hover-color: $global-color !default; -$internal-form-select-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default; -$internal-form-datalist-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%2012%208%206%2016%206%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default; -$internal-form-radio-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22#000%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$internal-form-checkbox-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default; -$internal-form-checkbox-indeterminate-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$inverse-global-muted-background: rgba($global-inverse-color, 0.1) !default; -$inverse-form-background: $inverse-global-muted-background !default; -$inverse-form-color: $inverse-global-color !default; -$inverse-form-focus-background: fadein($inverse-form-background, 5%) !default; -$inverse-form-focus-color: $inverse-global-color !default; -$inverse-form-placeholder-color: $inverse-global-muted-color !default; -$inverse-form-select-icon-color: $inverse-global-color !default; -$inverse-form-datalist-icon-color: $inverse-global-color !default; -$inverse-form-radio-background: $inverse-global-muted-background !default; -$inverse-form-radio-focus-background: fadein($inverse-form-radio-background, 5%) !default; -$inverse-form-radio-checked-background: $inverse-global-primary-background !default; -$inverse-form-radio-checked-icon-color: $inverse-global-inverse-color !default; -$inverse-form-radio-checked-focus-background: fadein($inverse-global-primary-background, 10%) !default; -$inverse-form-icon-color: $inverse-global-muted-color !default; -$inverse-form-icon-hover-color: $inverse-global-color !default; -$grid-gutter-horizontal: $global-gutter !default; -$grid-gutter-vertical: $grid-gutter-horizontal !default; -$grid-gutter-horizontal-l: $global-medium-gutter !default; -$grid-gutter-vertical-l: $grid-gutter-horizontal-l !default; -$grid-small-gutter-horizontal: $global-small-gutter !default; -$grid-small-gutter-vertical: $grid-small-gutter-horizontal !default; -$grid-medium-gutter-horizontal: $global-gutter !default; -$grid-medium-gutter-vertical: $grid-medium-gutter-horizontal !default; -$grid-large-gutter-horizontal: $global-medium-gutter !default; -$grid-large-gutter-vertical: $grid-large-gutter-horizontal !default; -$grid-large-gutter-horizontal-l: $global-large-gutter !default; -$grid-large-gutter-vertical-l: $grid-large-gutter-horizontal-l !default; -$grid-divider-border-width: $global-border-width !default; -$grid-divider-border: $global-border !default; -$inverse-grid-divider-border: $inverse-global-border !default; -$heading-medium-font-size-l: 4rem !default; -$heading-small-font-size-m: $heading-medium-font-size-l * 0.8125 !default; -$heading-small-font-size: $heading-small-font-size-m * 0.8 !default; -$heading-medium-font-size-m: $heading-medium-font-size-l * 0.875 !default; -$heading-medium-font-size: $heading-medium-font-size-m * 0.825 !default; -$heading-large-font-size-m: $heading-medium-font-size-l !default; -$heading-large-font-size: $heading-large-font-size-m * 0.85 !default; -$heading-xlarge-font-size: $heading-large-font-size-m !default; -$heading-large-font-size-l: 6rem !default; -$heading-xlarge-font-size-m: $heading-large-font-size-l !default; -$heading-2xlarge-font-size: $heading-xlarge-font-size-m !default; -$heading-xlarge-font-size-l: 8rem !default; -$heading-2xlarge-font-size-m: $heading-xlarge-font-size-l !default; -$heading-2xlarge-font-size-l: 11rem !default; -$heading-small-line-height: 1.2 !default; -$heading-medium-line-height: 1.1 !default; -$heading-large-line-height: 1.1 !default; -$heading-xlarge-line-height: 1 !default; -$heading-2xlarge-line-height: 1 !default; -$heading-divider-padding-bottom: unquote('calc(5px + 0.1em)') !default; -$heading-divider-border-width: unquote('calc(0.2px + 0.05em)') !default; -$heading-divider-border: $global-border !default; -$heading-bullet-top: unquote('calc(-0.1 * 1em)') !default; -$heading-bullet-height: unquote('calc(4px + 0.7em)') !default; -$heading-bullet-margin-right: unquote('calc(5px + 0.2em)') !default; -$heading-bullet-border-width: unquote('calc(5px + 0.1em)') !default; -$heading-bullet-border: $global-border !default; -$heading-line-top: 50% !default; -$heading-line-border-width: unquote('calc(0.2px + 0.05em)') !default; -$heading-line-height: $heading-line-border-width !default; -$heading-line-width: 2000px !default; -$heading-line-border: $global-border !default; -$heading-line-margin-horizontal: unquote('calc(5px + 0.3em)') !default; -$heading-primary-font-size-l: 3.75rem !default; -$heading-primary-line-height-l: 1.1 !default; -$heading-primary-font-size-m: $heading-primary-font-size-l * 0.9 !default; -$heading-primary-font-size: $heading-primary-font-size-l * 0.8 !default; -$heading-primary-line-height: 1.2 !default; -$heading-hero-font-size-l: 8rem !default; -$heading-hero-line-height-l: 1 !default; -$heading-hero-font-size-m: $heading-hero-font-size-l * 0.75 !default; -$heading-hero-line-height-m: 1 !default; -$heading-hero-font-size: $heading-hero-font-size-l * 0.5 !default; -$heading-hero-line-height: 1.1 !default; -$inverse-heading-divider-border: $inverse-global-border !default; -$inverse-heading-bullet-border: $inverse-global-border !default; -$inverse-heading-line-border: $inverse-global-border !default; -$height-small-height: 150px !default; -$height-medium-height: 300px !default; -$height-large-height: 450px !default; -$icon-image-size: 20px !default; -$icon-link-color: $global-muted-color !default; -$icon-link-hover-color: $global-color !default; -$icon-link-active-color: darken($global-color, 5%) !default; -$icon-button-size: 36px !default; -$icon-button-border-radius: 500px !default; -$icon-button-background: $global-muted-background !default; -$icon-button-color: $global-muted-color !default; -$icon-button-hover-background: darken($icon-button-background, 5%) !default; -$icon-button-hover-color: $global-color !default; -$icon-button-active-background: darken($icon-button-background, 10%) !default; -$icon-button-active-color: $global-color !default; -$inverse-icon-link-color: $inverse-global-muted-color !default; -$inverse-icon-link-hover-color: $inverse-global-color !default; -$inverse-icon-link-active-color: $inverse-global-color !default; -$inverse-icon-button-background: $inverse-global-muted-background !default; -$inverse-icon-button-color: $inverse-global-muted-color !default; -$inverse-icon-button-hover-background: fadein($inverse-icon-button-background, 5%) !default; -$inverse-icon-button-hover-color: $inverse-global-color !default; -$inverse-icon-button-active-background: fadein($inverse-icon-button-background, 10%) !default; -$inverse-icon-button-active-color: $inverse-global-color !default; -$iconnav-margin-horizontal: $global-small-margin !default; -$iconnav-margin-vertical: $iconnav-margin-horizontal !default; -$iconnav-item-color: $global-muted-color !default; -$iconnav-item-hover-color: $global-color !default; -$iconnav-item-active-color: $global-color !default; -$inverse-iconnav-item-color: $inverse-global-muted-color !default; -$inverse-iconnav-item-hover-color: $inverse-global-color !default; -$inverse-iconnav-item-active-color: $inverse-global-color !default; -$inverse-global-color-mode: light !default; -$label-padding-vertical: 0 !default; -$label-padding-horizontal: $global-small-margin !default; -$label-background: $global-primary-background !default; -$label-line-height: $global-line-height !default; -$label-font-size: $global-small-font-size !default; -$label-color: $global-inverse-color !default; -$label-success-background: $global-success-background !default; -$label-success-color: $global-inverse-color !default; -$label-warning-background: $global-warning-background !default; -$label-warning-color: $global-inverse-color !default; -$label-danger-background: $global-danger-background !default; -$label-danger-color: $global-inverse-color !default; -$inverse-label-background: $inverse-global-primary-background !default; -$inverse-label-color: $inverse-global-inverse-color !default; -$leader-fill-content: unquote('.') !default; -$leader-fill-margin-left: $global-small-gutter !default; -$lightbox-z-index: $global-z-index + 10 !default; -$lightbox-background: #000 !default; -$lightbox-item-color: rgba(255,255,255,0.7) !default; -$lightbox-item-max-width: 100vw !default; -$lightbox-item-max-height: 100vh !default; -$lightbox-toolbar-padding-vertical: 10px !default; -$lightbox-toolbar-padding-horizontal: 10px !default; -$lightbox-toolbar-background: rgba(0,0,0,0.3) !default; -$lightbox-toolbar-color: rgba(255,255,255,0.7) !default; -$lightbox-toolbar-icon-padding: 5px !default; -$lightbox-toolbar-icon-color: rgba(255,255,255,0.7) !default; -$lightbox-toolbar-icon-hover-color: #fff !default; -$lightbox-button-size: 50px !default; -$lightbox-button-background: $lightbox-toolbar-background !default; -$lightbox-button-color: rgba(255,255,255,0.7) !default; -$lightbox-button-hover-color: #fff !default; -$link-muted-color: $global-muted-color !default; -$link-muted-hover-color: $global-color !default; -$link-text-hover-color: $global-muted-color !default; -$link-heading-hover-color: $global-primary-background !default; -$link-heading-hover-text-decoration: none !default; -$inverse-link-muted-color: $inverse-global-muted-color !default; -$inverse-link-muted-hover-color: $inverse-global-color !default; -$inverse-link-text-hover-color: $inverse-global-muted-color !default; -$inverse-link-heading-hover-color: $inverse-global-primary-background !default; -$list-margin-top: $global-small-margin !default; -$list-padding-left: 30px !default; -$list-marker-height: ($global-line-height * 1em) !default; -$list-muted-color: $global-muted-color !default; -$list-emphasis-color: $global-emphasis-color !default; -$list-primary-color: $global-primary-background !default; -$list-secondary-color: $global-secondary-background !default; -$list-bullet-icon-color: $global-color !default; -$list-divider-margin-top: $global-small-margin !default; -$list-divider-border-width: $global-border-width !default; -$list-divider-border: $global-border !default; -$list-striped-padding-vertical: $global-small-margin !default; -$list-striped-padding-horizontal: $global-small-margin !default; -$list-striped-background: $global-muted-background !default; -$list-large-margin-top: $global-margin !default; -$list-large-divider-margin-top: $global-margin !default; -$list-large-striped-padding-vertical: $global-margin !default; -$list-large-striped-padding-horizontal: $global-small-margin !default; -$internal-list-bullet-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22#000%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$inverse-list-muted-color: $inverse-global-muted-color !default; -$inverse-list-emphasis-color: $inverse-global-emphasis-color !default; -$inverse-list-primary-color: $inverse-global-primary-background !default; -$inverse-list-secondary-color: $inverse-global-primary-background !default; -$inverse-list-divider-border: $inverse-global-border !default; -$inverse-list-striped-background: $inverse-global-muted-background !default; -$inverse-list-bullet-icon-color: $inverse-global-color !default; -$margin-margin: $global-margin !default; -$margin-small-margin: $global-small-margin !default; -$margin-medium-margin: $global-medium-margin !default; -$margin-large-margin: $global-medium-margin !default; -$margin-large-margin-l: $global-large-margin !default; -$margin-xlarge-margin: $global-large-margin !default; -$global-xlarge-margin: 140px !default; -$margin-xlarge-margin-l: $global-xlarge-margin !default; -$marker-padding: 5px !default; -$marker-background: $global-secondary-background !default; -$marker-color: $global-inverse-color !default; -$marker-hover-color: $global-inverse-color !default; -$inverse-marker-background: $global-muted-background !default; -$inverse-marker-color: $global-color !default; -$inverse-marker-hover-color: $global-color !default; -$modal-z-index: $global-z-index + 10 !default; -$modal-background: rgba(0,0,0,0.6) !default; -$modal-padding-horizontal: 15px !default; -$modal-padding-horizontal-s: $global-gutter !default; -$modal-padding-horizontal-m: $global-medium-gutter !default; -$modal-padding-vertical: $modal-padding-horizontal !default; -$modal-padding-vertical-s: 50px !default; -$modal-dialog-width: 600px !default; -$modal-dialog-background: $global-background !default; -$modal-container-width: 1200px !default; -$modal-body-padding-horizontal: $global-gutter !default; -$modal-body-padding-vertical: $global-gutter !default; -$modal-header-padding-horizontal: $global-gutter !default; -$modal-header-padding-vertical: ($modal-header-padding-horizontal / 2) !default; -$modal-header-background: $modal-dialog-background !default; -$modal-footer-padding-horizontal: $global-gutter !default; -$modal-footer-padding-vertical: ($modal-footer-padding-horizontal / 2) !default; -$modal-footer-background: $modal-dialog-background !default; -$modal-title-font-size: $global-xlarge-font-size !default; -$modal-title-line-height: 1.3 !default; -$modal-close-position: $global-small-margin !default; -$modal-close-padding: 5px !default; -$modal-close-outside-position: 0 !default; -$modal-close-outside-translate: 100% !default; -$modal-close-outside-color: lighten($global-inverse-color, 20%) !default; -$modal-close-outside-hover-color: $global-inverse-color !default; -$nav-item-padding-vertical: 5px !default; -$nav-item-padding-horizontal: 0 !default; -$nav-sublist-padding-vertical: 5px !default; -$nav-sublist-padding-left: 15px !default; -$nav-sublist-deeper-padding-left: 15px !default; -$nav-sublist-item-padding-vertical: 2px !default; -$nav-parent-icon-width: ($global-line-height * 1em) !default; -$nav-parent-icon-height: $nav-parent-icon-width !default; -$nav-parent-icon-color: $global-color !default; -$nav-header-padding-vertical: $nav-item-padding-vertical !default; -$nav-header-padding-horizontal: $nav-item-padding-horizontal !default; -$nav-header-font-size: $global-small-font-size !default; -$nav-header-text-transform: uppercase !default; -$nav-header-margin-top: $global-margin !default; -$nav-divider-margin-vertical: 5px !default; -$nav-divider-margin-horizontal: 0 !default; -$nav-default-item-color: $global-muted-color !default; -$nav-default-item-hover-color: $global-color !default; -$nav-default-item-active-color: $global-emphasis-color !default; -$nav-default-header-color: $global-emphasis-color !default; -$nav-default-divider-border-width: $global-border-width !default; -$nav-default-divider-border: $global-border !default; -$nav-default-sublist-item-color: $global-muted-color !default; -$nav-default-sublist-item-hover-color: $global-color !default; -$nav-default-sublist-item-active-color: $global-emphasis-color !default; -$nav-primary-item-font-size: $global-large-font-size !default; -$nav-primary-item-line-height: $global-line-height !default; -$nav-primary-item-color: $global-muted-color !default; -$nav-primary-item-hover-color: $global-color !default; -$nav-primary-item-active-color: $global-emphasis-color !default; -$nav-primary-header-color: $global-emphasis-color !default; -$nav-primary-divider-border-width: $global-border-width !default; -$nav-primary-divider-border: $global-border !default; -$nav-primary-sublist-item-color: $global-muted-color !default; -$nav-primary-sublist-item-hover-color: $global-color !default; -$nav-primary-sublist-item-active-color: $global-emphasis-color !default; -$nav-dividers-margin-top: 0 !default; -$nav-dividers-border-width: $global-border-width !default; -$nav-dividers-border: $global-border !default; -$internal-nav-parent-close-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%221.1%22%20points%3D%2210%201%204%207%2010%2013%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$internal-nav-parent-open-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%221.1%22%20points%3D%221%204%207%2010%2013%204%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$inverse-nav-parent-icon-color: $inverse-global-color !default; -$inverse-nav-default-item-color: $inverse-global-muted-color !default; -$inverse-nav-default-item-hover-color: $inverse-global-color !default; -$inverse-nav-default-item-active-color: $inverse-global-emphasis-color !default; -$inverse-nav-default-header-color: $inverse-global-emphasis-color !default; -$inverse-nav-default-divider-border: $inverse-global-border !default; -$inverse-nav-default-sublist-item-color: $inverse-global-muted-color !default; -$inverse-nav-default-sublist-item-hover-color: $inverse-global-color !default; -$inverse-nav-default-sublist-item-active-color: $inverse-global-emphasis-color !default; -$inverse-nav-primary-item-color: $inverse-global-muted-color !default; -$inverse-nav-primary-item-hover-color: $inverse-global-color !default; -$inverse-nav-primary-item-active-color: $inverse-global-emphasis-color !default; -$inverse-nav-primary-header-color: $inverse-global-emphasis-color !default; -$inverse-nav-primary-divider-border: $inverse-global-border !default; -$inverse-nav-primary-sublist-item-color: $inverse-global-muted-color !default; -$inverse-nav-primary-sublist-item-hover-color: $inverse-global-color !default; -$inverse-nav-primary-sublist-item-active-color: $inverse-global-emphasis-color !default; -$inverse-nav-dividers-border: $inverse-global-border !default; -$navbar-background: $global-muted-background !default; -$navbar-color-mode: none !default; -$navbar-nav-item-height: 80px !default; -$navbar-nav-item-padding-horizontal: 15px !default; -$navbar-nav-item-color: $global-muted-color !default; -$navbar-nav-item-font-size: $global-small-font-size !default; -$navbar-nav-item-font-family: $global-font-family !default; -$navbar-nav-item-hover-color: $global-color !default; -$navbar-nav-item-onclick-color: $global-emphasis-color !default; -$navbar-nav-item-active-color: $global-emphasis-color !default; -$navbar-item-color: $global-color !default; -$navbar-toggle-color: $global-muted-color !default; -$navbar-toggle-hover-color: $global-color !default; -$navbar-subtitle-font-size: $global-small-font-size !default; -$navbar-dropdown-z-index: $global-z-index + 20 !default; -$navbar-dropdown-width: 200px !default; -$navbar-dropdown-margin: 15px !default; -$navbar-dropdown-padding: 25px !default; -$navbar-dropdown-background: $global-background !default; -$navbar-dropdown-color: $global-color !default; -$navbar-dropdown-grid-gutter-horizontal: ($navbar-dropdown-padding * 2) !default; -$navbar-dropdown-grid-gutter-vertical: $navbar-dropdown-grid-gutter-horizontal !default; -$navbar-dropdown-dropbar-margin-top: 0 !default; -$navbar-dropdown-dropbar-margin-bottom: $navbar-dropdown-dropbar-margin-top !default; -$navbar-dropdown-nav-item-color: $global-muted-color !default; -$navbar-dropdown-nav-item-hover-color: $global-color !default; -$navbar-dropdown-nav-item-active-color: $global-emphasis-color !default; -$navbar-dropdown-nav-header-color: $global-emphasis-color !default; -$navbar-dropdown-nav-divider-border-width: $global-border-width !default; -$navbar-dropdown-nav-divider-border: $global-border !default; -$navbar-dropdown-nav-sublist-item-color: $global-muted-color !default; -$navbar-dropdown-nav-sublist-item-hover-color: $global-color !default; -$navbar-dropdown-nav-sublist-item-active-color: $global-emphasis-color !default; -$navbar-dropbar-background: $navbar-dropdown-background !default; -$navbar-dropbar-z-index: $global-z-index - 20 !default; -$inverse-navbar-nav-item-color: $inverse-global-muted-color !default; -$inverse-navbar-nav-item-hover-color: $inverse-global-color !default; -$inverse-navbar-nav-item-onclick-color: $inverse-global-emphasis-color !default; -$inverse-navbar-nav-item-active-color: $inverse-global-emphasis-color !default; -$inverse-navbar-item-color: $inverse-global-color !default; -$inverse-navbar-toggle-color: $inverse-global-muted-color !default; -$inverse-navbar-toggle-hover-color: $inverse-global-color !default; -$notification-position: 10px !default; -$notification-z-index: $global-z-index + 40 !default; -$notification-width: 350px !default; -$notification-message-margin-top: 10px !default; -$notification-message-padding: $global-small-gutter !default; -$notification-message-background: $global-muted-background !default; -$notification-message-color: $global-color !default; -$notification-message-font-size: $global-medium-font-size !default; -$notification-message-line-height: 1.4 !default; -$notification-close-top: $notification-message-padding + 5px !default; -$notification-close-right: $notification-message-padding !default; -$notification-message-primary-color: $global-primary-background !default; -$notification-message-success-color: $global-success-background !default; -$notification-message-warning-color: $global-warning-background !default; -$notification-message-danger-color: $global-danger-background !default; -$offcanvas-z-index: $global-z-index !default; -$offcanvas-bar-width: 270px !default; -$offcanvas-bar-padding-vertical: $global-margin !default; -$offcanvas-bar-padding-horizontal: $global-margin !default; -$offcanvas-bar-background: $global-secondary-background !default; -$offcanvas-bar-color-mode: light !default; -$offcanvas-bar-width-m: 350px !default; -$offcanvas-bar-padding-vertical-m: $global-medium-gutter !default; -$offcanvas-bar-padding-horizontal-m: $global-medium-gutter !default; -$offcanvas-close-position: 20px !default; -$offcanvas-close-padding: 5px !default; -$offcanvas-overlay-background: rgba(0,0,0,0.1) !default; -$overlay-padding-horizontal: $global-gutter !default; -$overlay-padding-vertical: $global-gutter !default; -$overlay-default-background: rgba($global-background, 0.8) !default; -$overlay-primary-background: rgba($global-secondary-background, 0.8) !default; -$overlay-primary-color-mode: light !default; -$padding-padding: $global-gutter !default; -$padding-padding-l: $global-medium-gutter !default; -$padding-small-padding: $global-small-gutter !default; -$padding-large-padding: $global-gutter !default; -$padding-large-padding-l: $global-large-gutter !default; -$pagination-margin-horizontal: 0 !default; -$pagination-item-padding-vertical: 5px !default; -$pagination-item-padding-horizontal: 10px !default; -$pagination-item-color: $global-muted-color !default; -$pagination-item-hover-color: $global-color !default; -$pagination-item-hover-text-decoration: none !default; -$pagination-item-active-color: $global-color !default; -$pagination-item-disabled-color: $global-muted-color !default; -$inverse-pagination-item-color: $inverse-global-muted-color !default; -$inverse-pagination-item-hover-color: $inverse-global-color !default; -$inverse-pagination-item-active-color: $inverse-global-color !default; -$inverse-pagination-item-disabled-color: $inverse-global-muted-color !default; -$placeholder-margin-vertical: $global-margin !default; -$placeholder-padding-vertical: $global-gutter !default; -$placeholder-padding-horizontal: $global-gutter !default; -$placeholder-background: transparent !default; -$position-small-margin: $global-small-gutter !default; -$position-medium-margin: $global-gutter !default; -$position-large-margin: $global-gutter !default; -$position-large-margin-l: 50px !default; -$progress-height: 15px !default; -$progress-margin-vertical: $global-margin !default; -$progress-background: $global-muted-background !default; -$progress-bar-background: $global-primary-background !default; -$search-color: $global-color !default; -$search-placeholder-color: $global-muted-color !default; -$search-icon-color: $global-muted-color !default; -$search-default-width: 240px !default; -$search-default-height: $global-control-height !default; -$search-default-padding-horizontal: 10px !default; -$search-default-background: transparent !default; -$search-default-focus-background: darken($search-default-background, 5%) !default; -$search-default-icon-width: $global-control-height !default; -$search-navbar-width: 400px !default; -$search-navbar-height: 40px !default; -$search-navbar-background: transparent !default; -$search-navbar-font-size: $global-large-font-size !default; -$search-navbar-icon-width: 40px !default; -$search-large-width: 500px !default; -$search-large-height: 80px !default; -$search-large-background: transparent !default; -$search-large-font-size: $global-2xlarge-font-size !default; -$search-large-icon-width: 80px !default; -$search-toggle-color: $global-muted-color !default; -$search-toggle-hover-color: $global-color !default; -$inverse-search-color: $inverse-global-color !default; -$inverse-search-placeholder-color: $inverse-global-muted-color !default; -$inverse-search-icon-color: $inverse-global-muted-color !default; -$inverse-search-default-background: transparent !default; -$inverse-search-default-focus-background: fadein($inverse-search-default-background, 5%) !default; -$inverse-search-navbar-background: transparent !default; -$inverse-search-large-background: transparent !default; -$inverse-search-toggle-color: $inverse-global-muted-color !default; -$inverse-search-toggle-hover-color: $inverse-global-color !default; -$section-padding-vertical: $global-medium-margin !default; -$section-padding-vertical-m: $global-large-margin !default; -$section-xsmall-padding-vertical: $global-margin !default; -$section-small-padding-vertical: $global-medium-margin !default; -$section-large-padding-vertical: $global-large-margin !default; -$section-large-padding-vertical-m: $global-xlarge-margin !default; -$section-xlarge-padding-vertical: $global-xlarge-margin !default; -$section-xlarge-padding-vertical-m: ($global-large-margin + $global-xlarge-margin) !default; -$section-default-background: $global-background !default; -$section-muted-background: $global-muted-background !default; -$section-primary-background: $global-primary-background !default; -$section-primary-color-mode: light !default; -$section-secondary-background: $global-secondary-background !default; -$section-secondary-color-mode: light !default; -$slidenav-padding-vertical: 5px !default; -$slidenav-padding-horizontal: 10px !default; -$slidenav-color: rgba($global-color, 0.5) !default; -$slidenav-hover-color: rgba($global-color, 0.9) !default; -$slidenav-active-color: rgba($global-color, 0.5) !default; -$slidenav-large-padding-vertical: 10px !default; -$slidenav-large-padding-horizontal: $slidenav-large-padding-vertical !default; -$inverse-slidenav-color: rgba($inverse-global-color, 0.7) !default; -$inverse-slidenav-hover-color: rgba($inverse-global-color, 0.95) !default; -$inverse-slidenav-active-color: rgba($inverse-global-color, 0.7) !default; -$slider-container-margin-top: -11px !default; -$slider-container-margin-bottom: -39px !default; -$slider-container-margin-left: -25px !default; -$slider-container-margin-right: -25px !default; -$sortable-dragged-z-index: $global-z-index + 50 !default; -$sortable-placeholder-opacity: 0 !default; -$sortable-empty-height: 50px !default; -$spinner-size: 30px !default; -$spinner-stroke-width: 1 !default; -$spinner-radius: floor(($spinner-size - $spinner-stroke-width) / 2) !default; -$spinner-circumference: round(2 * 3.141 * $spinner-radius) !default; -$spinner-duration: 1.4s !default; -$sticky-z-index: $global-z-index - 20 !default; -$sticky-animation-duration: 0.2s !default; -$sticky-reverse-animation-duration: 0.2s !default; -$subnav-margin-horizontal: 20px !default; -$subnav-item-color: $global-muted-color !default; -$subnav-item-hover-color: $global-color !default; -$subnav-item-hover-text-decoration: none !default; -$subnav-item-active-color: $global-emphasis-color !default; -$subnav-divider-margin-horizontal: $subnav-margin-horizontal !default; -$subnav-divider-border-height: 1.5em !default; -$subnav-divider-border-width: $global-border-width !default; -$subnav-divider-border: $global-border !default; -$subnav-pill-item-padding-vertical: 5px !default; -$subnav-pill-item-padding-horizontal: 10px !default; -$subnav-pill-item-background: transparent !default; -$subnav-pill-item-color: $subnav-item-color !default; -$subnav-pill-item-hover-background: $global-muted-background !default; -$subnav-pill-item-hover-color: $global-color !default; -$subnav-pill-item-onclick-background: $subnav-pill-item-hover-background !default; -$subnav-pill-item-onclick-color: $subnav-pill-item-hover-color !default; -$subnav-pill-item-active-background: $global-primary-background !default; -$subnav-pill-item-active-color: $global-inverse-color !default; -$subnav-item-disabled-color: $global-muted-color !default; -$inverse-subnav-item-color: $inverse-global-muted-color !default; -$inverse-subnav-item-hover-color: $inverse-global-color !default; -$inverse-subnav-item-active-color: $inverse-global-emphasis-color !default; -$inverse-subnav-divider-border: $inverse-global-border !default; -$inverse-subnav-pill-item-background: transparent !default; -$inverse-subnav-pill-item-color: $inverse-global-muted-color !default; -$inverse-subnav-pill-item-hover-background: $inverse-global-muted-background !default; -$inverse-subnav-pill-item-hover-color: $inverse-global-color !default; -$inverse-subnav-pill-item-onclick-background: $inverse-subnav-pill-item-hover-background !default; -$inverse-subnav-pill-item-onclick-color: $inverse-subnav-pill-item-hover-color !default; -$inverse-subnav-pill-item-active-background: $inverse-global-primary-background !default; -$inverse-subnav-pill-item-active-color: $inverse-global-inverse-color !default; -$inverse-subnav-item-disabled-color: $inverse-global-muted-color !default; -$tab-margin-horizontal: 20px !default; -$tab-item-padding-horizontal: 10px !default; -$tab-item-padding-vertical: 5px !default; -$tab-item-color: $global-muted-color !default; -$tab-item-hover-color: $global-color !default; -$tab-item-hover-text-decoration: none !default; -$tab-item-active-color: $global-emphasis-color !default; -$tab-item-disabled-color: $global-muted-color !default; -$inverse-tab-item-color: $inverse-global-muted-color !default; -$inverse-tab-item-hover-color: $inverse-global-color !default; -$inverse-tab-item-active-color: $inverse-global-emphasis-color !default; -$inverse-tab-item-disabled-color: $inverse-global-muted-color !default; -$table-margin-vertical: $global-margin !default; -$table-cell-padding-vertical: 16px !default; -$table-cell-padding-horizontal: 12px !default; -$table-header-cell-font-size: $global-small-font-size !default; -$table-header-cell-font-weight: normal !default; -$table-header-cell-color: $global-muted-color !default; -$table-footer-font-size: $global-small-font-size !default; -$table-caption-font-size: $global-small-font-size !default; -$table-caption-color: $global-muted-color !default; -$table-row-active-background: #ffd !default; -$table-divider-border-width: $global-border-width !default; -$table-divider-border: $global-border !default; -$table-striped-row-background: $global-muted-background !default; -$table-hover-row-background: $table-row-active-background !default; -$table-small-cell-padding-vertical: 10px !default; -$table-small-cell-padding-horizontal: 12px !default; -$table-large-cell-padding-vertical: 22px !default; -$table-large-cell-padding-horizontal: 12px !default; -$table-expand-min-width: 150px !default; -$inverse-table-header-cell-color: $inverse-global-color !default; -$inverse-table-caption-color: $inverse-global-muted-color !default; -$inverse-table-row-active-background: fade-out($inverse-global-muted-background, 0.02) !default; -$inverse-table-divider-border: $inverse-global-border !default; -$inverse-table-striped-row-background: $inverse-global-muted-background !default; -$inverse-table-hover-row-background: $inverse-table-row-active-background !default; -$text-lead-font-size: $global-large-font-size !default; -$text-lead-line-height: 1.5 !default; -$text-lead-color: $global-emphasis-color !default; -$text-meta-font-size: $global-small-font-size !default; -$text-meta-line-height: 1.4 !default; -$text-meta-color: $global-muted-color !default; -$text-small-font-size: $global-small-font-size !default; -$text-small-line-height: 1.5 !default; -$text-large-font-size: $global-large-font-size !default; -$text-large-line-height: 1.5 !default; -$text-muted-color: $global-muted-color !default; -$text-emphasis-color: $global-emphasis-color !default; -$text-primary-color: $global-primary-background !default; -$text-secondary-color: $global-secondary-background !default; -$text-success-color: $global-success-background !default; -$text-warning-color: $global-warning-background !default; -$text-danger-color: $global-danger-background !default; -$text-background-color: $global-primary-background !default; -$inverse-text-lead-color: $inverse-global-color !default; -$inverse-text-meta-color: $inverse-global-muted-color !default; -$inverse-text-muted-color: $inverse-global-muted-color !default; -$inverse-text-emphasis-color: $inverse-global-emphasis-color !default; -$inverse-text-primary-color: $inverse-global-primary-background !default; -$inverse-text-secondary-color: $inverse-global-primary-background !default; -$thumbnav-margin-horizontal: 15px !default; -$thumbnav-margin-vertical: $thumbnav-margin-horizontal !default; -$tile-padding-horizontal: 15px !default; -$tile-padding-horizontal-s: $global-gutter !default; -$tile-padding-horizontal-m: $global-medium-gutter !default; -$tile-padding-vertical: $global-medium-margin !default; -$tile-padding-vertical-m: $global-large-margin !default; -$tile-xsmall-padding-vertical: $global-margin !default; -$tile-small-padding-vertical: $global-medium-margin !default; -$tile-large-padding-vertical: $global-large-margin !default; -$tile-large-padding-vertical-m: $global-xlarge-margin !default; -$tile-xlarge-padding-vertical: $global-xlarge-margin !default; -$tile-xlarge-padding-vertical-m: ($global-large-margin + $global-xlarge-margin) !default; -$tile-default-background: $global-background !default; -$tile-muted-background: $global-muted-background !default; -$tile-primary-background: $global-primary-background !default; -$tile-primary-color-mode: light !default; -$tile-secondary-background: $global-secondary-background !default; -$tile-secondary-color-mode: light !default; -$tooltip-z-index: $global-z-index + 30 !default; -$tooltip-max-width: 200px !default; -$tooltip-padding-vertical: 3px !default; -$tooltip-padding-horizontal: 6px !default; -$tooltip-background: #666 !default; -$tooltip-border-radius: 2px !default; -$tooltip-color: $global-inverse-color !default; -$tooltip-font-size: 12px !default; -$tooltip-margin: 10px !default; -$totop-padding: 5px !default; -$totop-color: $global-muted-color !default; -$totop-hover-color: $global-color !default; -$totop-active-color: $global-emphasis-color !default; -$inverse-totop-color: $inverse-global-muted-color !default; -$inverse-totop-hover-color: $inverse-global-color !default; -$inverse-totop-active-color: $inverse-global-emphasis-color !default; -$transition-duration: 0.3s !default; -$transition-scale: 1.03 !default; -$transition-slide-small-translate: 10px !default; -$transition-slide-medium-translate: 50px !default; -$transition-slow-duration: 0.7s !default; -$panel-scrollable-height: 170px !default; -$panel-scrollable-padding: 10px !default; -$panel-scrollable-border-width: $global-border-width !default; -$panel-scrollable-border: $global-border !default; -$border-rounded-border-radius: 5px !default; -$box-shadow-duration: 0.1s !default; -$box-shadow-bottom-height: 30px !default; -$box-shadow-bottom-border-radius: 100% !default; -$box-shadow-bottom-background: #444 !default; -$box-shadow-bottom-blur: 20px !default; -$dropcap-margin-right: 10px !default; -$dropcap-font-size: (($global-line-height * 3) * 1em) !default; -$logo-font-size: $global-large-font-size !default; -$logo-font-family: $global-font-family !default; -$logo-color: $global-color !default; -$logo-hover-color: $global-color !default; -$dragover-box-shadow: 0 0 20px rgba(100,100,100,0.3) !default; -$inverse-logo-color: $inverse-global-color !default; -$inverse-logo-hover-color: $inverse-global-color !default; -$deprecated: false !default; -$breakpoint-small: 640px !default; -$breakpoint-medium: 960px !default; -$breakpoint-large: 1200px !default; -$breakpoint-xlarge: 1600px !default; -$breakpoint-xsmall-max: ($breakpoint-small - 1) !default; -$breakpoint-small-max: ($breakpoint-medium - 1) !default; -$breakpoint-medium-max: ($breakpoint-large - 1) !default; -$breakpoint-large-max: ($breakpoint-xlarge - 1) !default; -$global-small-box-shadow: 0 2px 8px rgba(0,0,0,0.08) !default; -$global-medium-box-shadow: 0 5px 15px rgba(0,0,0,0.08) !default; -$global-large-box-shadow: 0 14px 25px rgba(0,0,0,0.16) !default; -$global-xlarge-box-shadow: 0 28px 50px rgba(0,0,0,0.16) !default; -$width-small-width: 150px !default; -$width-medium-width: 300px !default; -$width-large-width: 450px !default; -$width-xlarge-width: 600px !default; -$width-2xlarge-width: 750px !default; -$accordion-icon-margin-left: 10px !default; -$accordion-icon-color: $global-color !default; -$internal-accordion-open-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$internal-accordion-close-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20width%3D%2213%22%20height%3D%221%22%20x%3D%220%22%20y%3D%226%22%20%2F%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20width%3D%221%22%20height%3D%2213%22%20x%3D%226%22%20y%3D%220%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$alert-close-opacity: 0.4 !default; -$alert-close-hover-opacity: 0.8 !default; -$article-meta-link-color: $article-meta-color !default; -$article-meta-link-hover-color: $global-color !default; -$base-code-padding-horizontal: 6px !default; -$base-code-padding-vertical: 2px !default; -$base-code-background: $global-muted-background !default; -$base-blockquote-color: $global-emphasis-color !default; -$base-blockquote-footer-color: $global-color !default; -$base-pre-padding: 10px !default; -$base-pre-background: $global-background !default; -$base-pre-border-width: $global-border-width !default; -$base-pre-border: $global-border !default; -$base-pre-border-radius: 3px !default; -$inverse-base-blockquote-color: $inverse-global-emphasis-color !default; -$inverse-base-blockquote-footer-color: $inverse-global-color !default; -$button-text-transform: uppercase !default; -$button-default-border: $global-border !default; -$button-default-hover-border: darken($global-border, 20%) !default; -$button-default-active-border: darken($global-border, 30%) !default; -$button-disabled-border: $global-border !default; -$button-text-border-width: $global-border-width !default; -$button-text-border: $button-text-hover-color !default; -$card-badge-border-radius: 2px !default; -$card-badge-text-transform: uppercase !default; -$card-hover-box-shadow: $global-large-box-shadow !default; -$card-default-box-shadow: $global-medium-box-shadow !default; -$card-default-hover-box-shadow: $global-large-box-shadow !default; -$card-default-header-border-width: $global-border-width !default; -$card-default-header-border: $global-border !default; -$card-default-footer-border-width: $global-border-width !default; -$card-default-footer-border: $global-border !default; -$card-primary-box-shadow: $global-medium-box-shadow !default; -$card-primary-hover-box-shadow: $global-large-box-shadow !default; -$card-secondary-box-shadow: $global-medium-box-shadow !default; -$card-secondary-hover-box-shadow: $global-large-box-shadow !default; -$comment-primary-padding: $global-gutter !default; -$comment-primary-background: $global-muted-background !default; -$description-list-term-font-size: $global-small-font-size !default; -$description-list-term-font-weight: normal !default; -$description-list-term-text-transform: uppercase !default; -$dotnav-item-border-width: 1px !default; -$dotnav-item-border: rgba($global-color, 0.4) !default; -$dotnav-item-hover-border: transparent !default; -$dotnav-item-onclick-border: transparent !default; -$dotnav-item-active-border: transparent !default; -$dropdown-nav-font-size: $global-small-font-size !default; -$dropdown-box-shadow: 0 5px 12px rgba(0,0,0,0.15) !default; -$form-range-thumb-border-width: $global-border-width !default; -$form-range-thumb-border: darken($global-border, 10%) !default; -$form-range-track-border-radius: 500px !default; -$form-border: $global-border !default; -$form-focus-border: $global-primary-background !default; -$form-disabled-border: $global-border !default; -$form-danger-border: $global-danger-background !default; -$form-success-border: $global-success-background !default; -$form-blank-focus-border: $global-border !default; -$form-blank-focus-border-style: dashed !default; -$form-radio-border-width: $global-border-width !default; -$form-radio-border: darken($global-border, 10%) !default; -$form-radio-focus-border: $global-primary-background !default; -$form-radio-checked-border: transparent !default; -$form-radio-disabled-border: $global-border !default; -$form-label-color: $global-emphasis-color !default; -$form-label-font-size: $global-small-font-size !default; -$inverse-form-label-color: $inverse-global-emphasis-color !default; -$subnav-item-font-size: $global-small-font-size !default; -$label-border-radius: 2px !default; -$label-text-transform: uppercase !default; -$list-striped-border-width: $global-border-width !default; -$list-striped-border: $global-border !default; -$modal-header-border-width: $global-border-width !default; -$modal-header-border: $global-border !default; -$modal-footer-border-width: $global-border-width !default; -$modal-footer-border: $global-border !default; -$modal-close-full-padding: $global-margin !default; -$modal-close-full-background: $modal-dialog-background !default; -$nav-default-font-size: $global-small-font-size !default; -$navbar-nav-item-text-transform: uppercase !default; -$navbar-dropdown-nav-font-size: $global-small-font-size !default; -$navbar-dropdown-box-shadow: 0 5px 12px rgba(0,0,0,0.15) !default; -$navbar-dropbar-box-shadow: 0 5px 7px rgba(0, 0, 0, 0.05) !default; -$navbar-dropdown-grid-divider-border-width: $global-border-width !default; -$navbar-dropdown-grid-divider-border: $navbar-dropdown-nav-divider-border !default; -$placeholder-border-width: $global-border-width !default; -$placeholder-border: $global-border !default; -$progress-border-radius: 500px !default; -$search-default-border-width: $global-border-width !default; -$search-default-border: $global-border !default; -$search-default-focus-border: $global-primary-background !default; -$subnav-item-text-transform: uppercase !default; -$tab-border-width: $global-border-width !default; -$tab-border: $global-border !default; -$tab-item-border-width: $global-border-width !default; -$tab-item-font-size: $global-small-font-size !default; -$tab-item-text-transform: uppercase !default; -$tab-item-active-border: $global-primary-background !default; -$inverse-tab-border: $inverse-global-border !default; -$table-striped-border-width: $global-border-width !default; -$table-striped-border: $global-border !default; -$text-meta-link-color: $text-meta-color !default; -$text-meta-link-hover-color: $global-color !default; -$thumbnav-item-background: rgba($global-background, 0.4) !default; -$thumbnav-item-hover-background: transparent !default; -$thumbnav-item-active-background: transparent !default; \ No newline at end of file diff --git a/docs/_sass/uikit/variables.scss b/docs/_sass/uikit/variables.scss deleted file mode 100644 index ce7cf9a02d..0000000000 --- a/docs/_sass/uikit/variables.scss +++ /dev/null @@ -1,1061 +0,0 @@ -$global-margin: 20px !default; -$accordion-item-margin-top: $global-margin !default; -$global-medium-font-size: 1.25rem !default; -$accordion-title-font-size: $global-medium-font-size !default; -$accordion-title-line-height: 1.4 !default; -$global-emphasis-color: #333 !default; -$accordion-title-color: $global-emphasis-color !default; -$global-color: #666 !default; -$accordion-title-hover-color: $global-color !default; -$accordion-content-margin-top: $global-margin !default; -$global-inverse-color: #fff !default; -$inverse-global-emphasis-color: $global-inverse-color !default; -$inverse-accordion-title-color: $inverse-global-emphasis-color !default; -$inverse-global-color: rgba($global-inverse-color, 0.7) !default; -$inverse-accordion-title-hover-color: $inverse-global-color !default; -$alert-margin-vertical: $global-margin !default; -$alert-padding: 15px !default; -$alert-padding-right: $alert-padding + 14px !default; -$global-muted-background: #f8f8f8 !default; -$alert-background: $global-muted-background !default; -$alert-color: $global-color !default; -$alert-close-top: $alert-padding + 5px !default; -$alert-close-right: $alert-padding !default; -$global-primary-background: #1e87f0 !default; -$alert-primary-background: lighten(mix(white, $global-primary-background, 40%), 20%) !default; -$alert-primary-color: $global-primary-background !default; -$global-success-background: #32d296 !default; -$alert-success-background: lighten(mix(white, $global-success-background, 40%), 25%) !default; -$alert-success-color: $global-success-background !default; -$global-warning-background: #faa05a !default; -$alert-warning-background: lighten(mix(white, $global-warning-background, 45%), 15%) !default; -$alert-warning-color: $global-warning-background !default; -$global-danger-background: #f0506e !default; -$alert-danger-background: lighten(mix(white, $global-danger-background, 40%), 20%) !default; -$alert-danger-color: $global-danger-background !default; -$global-gutter: 30px !default; -$align-margin-horizontal: $global-gutter !default; -$align-margin-vertical: $global-gutter !default; -$global-medium-gutter: 40px !default; -$align-margin-horizontal-l: $global-medium-gutter !default; -$animation-duration: 0.5s !default; -$animation-fade-duration: 0.8s !default; -$animation-stroke-duration: 2s !default; -$animation-kenburns-duration: 15s !default; -$animation-fast-duration: 0.1s !default; -$animation-slide-small-translate: 10px !default; -$animation-slide-medium-translate: 50px !default; -$global-large-margin: 70px !default; -$article-margin-top: $global-large-margin !default; -$global-2xlarge-font-size: 2.625rem !default; -$article-title-font-size-m: $global-2xlarge-font-size !default; -$article-title-font-size: $article-title-font-size-m * 0.85 !default; -$article-title-line-height: 1.2 !default; -$global-small-font-size: 0.875rem !default; -$article-meta-font-size: $global-small-font-size !default; -$article-meta-line-height: 1.4 !default; -$global-muted-color: #999 !default; -$article-meta-color: $global-muted-color !default; -$inverse-global-muted-color: rgba($global-inverse-color, 0.5) !default; -$inverse-article-meta-color: $inverse-global-muted-color !default; -$global-background: #fff !default; -$background-default-background: $global-background !default; -$background-muted-background: $global-muted-background !default; -$background-primary-background: $global-primary-background !default; -$global-secondary-background: #222 !default; -$background-secondary-background: $global-secondary-background !default; -$badge-size: 18px !default; -$badge-padding-vertical: 0 !default; -$badge-padding-horizontal: 5px !default; -$badge-border-radius: 500px !default; -$badge-background: $global-primary-background !default; -$badge-color: $global-inverse-color !default; -$badge-font-size: 11px !default; -$inverse-global-primary-background: $global-inverse-color !default; -$inverse-badge-background: $inverse-global-primary-background !default; -$inverse-global-inverse-color: $global-color !default; -$inverse-badge-color: $inverse-global-inverse-color !default; -$base-body-background: $global-background !default; -$global-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; -$base-body-font-family: $global-font-family !default; -$base-body-font-weight: normal !default; -$global-font-size: 16px !default; -$base-body-font-size: $global-font-size !default; -$global-line-height: 1.5 !default; -$base-body-line-height: $global-line-height !default; -$base-body-color: $global-color !default; -$global-link-color: #1e87f0 !default; -$base-link-color: $global-link-color !default; -$base-link-text-decoration: none !default; -$global-link-hover-color: #0f6ecd !default; -$base-link-hover-color: $global-link-hover-color !default; -$base-link-hover-text-decoration: underline !default; -$base-strong-font-weight: bolder !default; -$base-code-font-size: $global-small-font-size !default; -$base-code-font-family: Consolas, monaco, monospace !default; -$base-code-color: $global-danger-background !default; -$base-em-color: $global-danger-background !default; -$base-ins-background: #ffd !default; -$base-ins-color: $global-color !default; -$base-mark-background: #ffd !default; -$base-mark-color: $global-color !default; -$base-quote-font-style: italic !default; -$base-small-font-size: 80% !default; -$base-margin-vertical: $global-margin !default; -$base-heading-font-family: $global-font-family !default; -$base-heading-font-weight: normal !default; -$base-heading-color: $global-emphasis-color !default; -$base-heading-text-transform: none !default; -$global-medium-margin: 40px !default; -$base-heading-margin-top: $global-medium-margin !default; -$base-h1-font-size-m: $global-2xlarge-font-size !default; -$base-h1-font-size: $base-h1-font-size-m * 0.85 !default; -$base-h1-line-height: 1.2 !default; -$global-xlarge-font-size: 2rem !default; -$base-h2-font-size-m: $global-xlarge-font-size !default; -$base-h2-font-size: $base-h2-font-size-m * 0.85 !default; -$base-h2-line-height: 1.3 !default; -$global-large-font-size: 1.5rem !default; -$base-h3-font-size: $global-large-font-size !default; -$base-h3-line-height: 1.4 !default; -$base-h4-font-size: $global-medium-font-size !default; -$base-h4-line-height: 1.4 !default; -$base-h5-font-size: $global-font-size !default; -$base-h5-line-height: 1.4 !default; -$base-h6-font-size: $global-small-font-size !default; -$base-h6-line-height: 1.4 !default; -$base-list-padding-left: 30px !default; -$base-hr-margin-vertical: $global-margin !default; -$global-border-width: 1px !default; -$base-hr-border-width: $global-border-width !default; -$global-border: #e5e5e5 !default; -$base-hr-border: $global-border !default; -$base-blockquote-font-size: $global-medium-font-size !default; -$base-blockquote-line-height: 1.5 !default; -$base-blockquote-font-style: italic !default; -$base-blockquote-margin-vertical: $global-margin !default; -$global-small-margin: 10px !default; -$base-blockquote-footer-margin-top: $global-small-margin !default; -$base-blockquote-footer-font-size: $global-small-font-size !default; -$base-blockquote-footer-line-height: 1.5 !default; -$base-pre-font-size: $global-small-font-size !default; -$base-pre-line-height: 1.5 !default; -$base-pre-font-family: $base-code-font-family !default; -$base-pre-color: $global-color !default; -$base-selection-background: #39f !default; -$base-selection-color: $global-inverse-color !default; -$inverse-base-color: $inverse-global-color !default; -$inverse-base-link-color: $inverse-global-emphasis-color !default; -$inverse-base-link-hover-color: $inverse-global-emphasis-color !default; -$inverse-base-code-color: $inverse-global-color !default; -$inverse-base-em-color: $inverse-global-emphasis-color !default; -$inverse-base-heading-color: $inverse-global-emphasis-color !default; -$inverse-global-border: rgba($global-inverse-color, 0.2) !default; -$inverse-base-hr-border: $inverse-global-border !default; -$breadcrumb-item-font-size: $global-small-font-size !default; -$breadcrumb-item-color: $global-muted-color !default; -$breadcrumb-item-hover-color: $global-color !default; -$breadcrumb-item-hover-text-decoration: none !default; -$breadcrumb-item-active-color: $global-color !default; -$breadcrumb-divider: "/" !default; -$breadcrumb-divider-margin-horizontal: 20px !default; -$breadcrumb-divider-font-size: $breadcrumb-item-font-size !default; -$breadcrumb-divider-color: $global-muted-color !default; -$inverse-breadcrumb-item-color: $inverse-global-muted-color !default; -$inverse-breadcrumb-item-hover-color: $inverse-global-color !default; -$inverse-breadcrumb-item-active-color: $inverse-global-color !default; -$inverse-breadcrumb-divider-color: $inverse-global-muted-color !default; -$global-control-height: 40px !default; -$button-line-height: $global-control-height !default; -$global-control-small-height: 30px !default; -$button-small-line-height: $global-control-small-height !default; -$global-control-large-height: 55px !default; -$button-large-line-height: $global-control-large-height !default; -$button-font-size: $global-font-size !default; -$button-small-font-size: $global-small-font-size !default; -$button-large-font-size: $global-medium-font-size !default; -$button-padding-horizontal: $global-gutter !default; -$global-small-gutter: 15px !default; -$button-small-padding-horizontal: $global-small-gutter !default; -$button-large-padding-horizontal: $global-medium-gutter !default; -$button-default-background: $global-muted-background !default; -$button-default-color: $global-emphasis-color !default; -$button-default-hover-background: darken($button-default-background, 5%) !default; -$button-default-hover-color: $global-emphasis-color !default; -$button-default-active-background: darken($button-default-background, 10%) !default; -$button-default-active-color: $global-emphasis-color !default; -$button-primary-background: $global-primary-background !default; -$button-primary-color: $global-inverse-color !default; -$button-primary-hover-background: darken($button-primary-background, 5%) !default; -$button-primary-hover-color: $global-inverse-color !default; -$button-primary-active-background: darken($button-primary-background, 10%) !default; -$button-primary-active-color: $global-inverse-color !default; -$button-secondary-background: $global-secondary-background !default; -$button-secondary-color: $global-inverse-color !default; -$button-secondary-hover-background: darken($button-secondary-background, 5%) !default; -$button-secondary-hover-color: $global-inverse-color !default; -$button-secondary-active-background: darken($button-secondary-background, 10%) !default; -$button-secondary-active-color: $global-inverse-color !default; -$button-danger-background: $global-danger-background !default; -$button-danger-color: $global-inverse-color !default; -$button-danger-hover-background: darken($button-danger-background, 5%) !default; -$button-danger-hover-color: $global-inverse-color !default; -$button-danger-active-background: darken($button-danger-background, 10%) !default; -$button-danger-active-color: $global-inverse-color !default; -$button-disabled-background: $global-muted-background !default; -$button-disabled-color: $global-muted-color !default; -$button-text-line-height: $global-line-height !default; -$button-text-color: $global-emphasis-color !default; -$button-text-hover-color: $global-muted-color !default; -$button-text-disabled-color: $global-muted-color !default; -$button-link-line-height: $global-line-height !default; -$button-link-color: $global-emphasis-color !default; -$button-link-hover-color: $global-muted-color !default; -$button-link-hover-text-decoration: none !default; -$button-link-disabled-color: $global-muted-color !default; -$inverse-button-default-background: $inverse-global-primary-background !default; -$inverse-button-default-color: $inverse-global-inverse-color !default; -$inverse-button-default-hover-background: darken($inverse-button-default-background, 5%) !default; -$inverse-button-default-hover-color: $inverse-global-inverse-color !default; -$inverse-button-default-active-background: darken($inverse-button-default-background, 10%) !default; -$inverse-button-default-active-color: $inverse-global-inverse-color !default; -$inverse-button-primary-background: $inverse-global-primary-background !default; -$inverse-button-primary-color: $inverse-global-inverse-color !default; -$inverse-button-primary-hover-background: darken($inverse-button-primary-background, 5%) !default; -$inverse-button-primary-hover-color: $inverse-global-inverse-color !default; -$inverse-button-primary-active-background: darken($inverse-button-primary-background, 10%) !default; -$inverse-button-primary-active-color: $inverse-global-inverse-color !default; -$inverse-button-secondary-background: $inverse-global-primary-background !default; -$inverse-button-secondary-color: $inverse-global-inverse-color !default; -$inverse-button-secondary-hover-background: darken($inverse-button-secondary-background, 5%) !default; -$inverse-button-secondary-hover-color: $inverse-global-inverse-color !default; -$inverse-button-secondary-active-background: darken($inverse-button-secondary-background, 10%) !default; -$inverse-button-secondary-active-color: $inverse-global-inverse-color !default; -$inverse-button-text-color: $inverse-global-emphasis-color !default; -$inverse-button-text-hover-color: $inverse-global-muted-color !default; -$inverse-button-text-disabled-color: $inverse-global-muted-color !default; -$inverse-button-link-color: $inverse-global-emphasis-color !default; -$inverse-button-link-hover-color: $inverse-global-muted-color !default; -$card-body-padding-horizontal: $global-gutter !default; -$card-body-padding-vertical: $global-gutter !default; -$card-body-padding-horizontal-l: $global-medium-gutter !default; -$card-body-padding-vertical-l: $global-medium-gutter !default; -$card-header-padding-horizontal: $global-gutter !default; -$card-header-padding-vertical: round($global-gutter / 2) !default; -$card-header-padding-horizontal-l: $global-medium-gutter !default; -$card-header-padding-vertical-l: round($global-medium-gutter / 2) !default; -$card-footer-padding-horizontal: $global-gutter !default; -$card-footer-padding-vertical: ($global-gutter / 2) !default; -$card-footer-padding-horizontal-l: $global-medium-gutter !default; -$card-footer-padding-vertical-l: round($global-medium-gutter / 2) !default; -$card-title-font-size: $global-large-font-size !default; -$card-title-line-height: 1.4 !default; -$card-badge-top: 15px !default; -$card-badge-right: 15px !default; -$card-badge-height: 22px !default; -$card-badge-padding-horizontal: 10px !default; -$card-badge-background: $global-primary-background !default; -$card-badge-color: $global-inverse-color !default; -$card-badge-font-size: $global-small-font-size !default; -$card-hover-background: $global-muted-background !default; -$card-default-background: $global-muted-background !default; -$card-default-color: $global-color !default; -$card-default-title-color: $global-emphasis-color !default; -$card-default-hover-background: darken($card-default-background, 5%) !default; -$card-primary-background: $global-primary-background !default; -$card-primary-color: $global-inverse-color !default; -$card-primary-title-color: $card-primary-color !default; -$card-primary-hover-background: darken($card-primary-background, 5%) !default; -$card-primary-color-mode: light !default; -$card-secondary-background: $global-secondary-background !default; -$card-secondary-color: $global-inverse-color !default; -$card-secondary-title-color: $card-secondary-color !default; -$card-secondary-hover-background: darken($card-secondary-background, 5%) !default; -$card-secondary-color-mode: light !default; -$card-small-body-padding-horizontal: $global-margin !default; -$card-small-body-padding-vertical: $global-margin !default; -$card-small-header-padding-horizontal: $global-margin !default; -$card-small-header-padding-vertical: round($global-margin / 1.5) !default; -$card-small-footer-padding-horizontal: $global-margin !default; -$card-small-footer-padding-vertical: round($global-margin / 1.5) !default; -$global-large-gutter: 70px !default; -$card-large-body-padding-horizontal-l: $global-large-gutter !default; -$card-large-body-padding-vertical-l: $global-large-gutter !default; -$card-large-header-padding-horizontal-l: $global-large-gutter !default; -$card-large-header-padding-vertical-l: round($global-large-gutter / 2) !default; -$card-large-footer-padding-horizontal-l: $global-large-gutter !default; -$card-large-footer-padding-vertical-l: round($global-large-gutter / 2) !default; -$inverse-card-badge-background: $inverse-global-primary-background !default; -$inverse-card-badge-color: $inverse-global-inverse-color !default; -$close-color: $global-muted-color !default; -$close-hover-color: $global-color !default; -$inverse-close-color: $inverse-global-muted-color !default; -$inverse-close-hover-color: $inverse-global-color !default; -$column-gutter: $global-gutter !default; -$column-gutter-l: $global-medium-gutter !default; -$column-divider-rule-color: $global-border !default; -$column-divider-rule-width: 1px !default; -$inverse-column-divider-rule-color: $inverse-global-border !default; -$comment-header-margin-bottom: $global-margin !default; -$comment-title-font-size: $global-medium-font-size !default; -$comment-title-line-height: 1.4 !default; -$comment-meta-font-size: $global-small-font-size !default; -$comment-meta-line-height: 1.4 !default; -$comment-meta-color: $global-muted-color !default; -$comment-list-margin-top: $global-large-margin !default; -$comment-list-padding-left: 30px !default; -$comment-list-padding-left-m: 100px !default; -$container-max-width: 1200px !default; -$container-xsmall-max-width: 750px !default; -$container-small-max-width: 900px !default; -$container-large-max-width: 1400px !default; -$container-xlarge-max-width: 1600px !default; -$container-padding-horizontal: 15px !default; -$container-padding-horizontal-s: $global-gutter !default; -$container-padding-horizontal-m: $global-medium-gutter !default; -$countdown-number-line-height: 0.8 !default; -$countdown-number-font-size: 2rem !default; -$countdown-number-font-size-s: 4rem !default; -$countdown-number-font-size-m: 6rem !default; -$countdown-separator-line-height: 1.6 !default; -$countdown-separator-font-size: 1rem !default; -$countdown-separator-font-size-s: 2rem !default; -$countdown-separator-font-size-m: 3rem !default; -$description-list-term-color: $global-emphasis-color !default; -$description-list-term-margin-top: $global-margin !default; -$description-list-divider-term-margin-top: $global-margin !default; -$description-list-divider-term-border-width: $global-border-width !default; -$description-list-divider-term-border: $global-border !default; -$divider-margin-vertical: $global-margin !default; -$divider-icon-width: 50px !default; -$divider-icon-height: 20px !default; -$divider-icon-color: $global-border !default; -$divider-icon-line-top: 50% !default; -$divider-icon-line-width: 100% !default; -$divider-icon-line-border-width: $global-border-width !default; -$divider-icon-line-border: $global-border !default; -$internal-divider-icon-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2020%2020%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%222%22%20cx%3D%2210%22%20cy%3D%2210%22%20r%3D%227%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default; -$divider-small-width: 100px !default; -$divider-small-border-width: $global-border-width !default; -$divider-small-border: $global-border !default; -$divider-vertical-height: 100px !default; -$divider-vertical-border-width: $global-border-width !default; -$divider-vertical-border: $global-border !default; -$inverse-divider-icon-color: $inverse-global-border !default; -$inverse-divider-icon-line-border: $inverse-global-border !default; -$inverse-divider-small-border: $inverse-global-border !default; -$inverse-divider-vertical-border: $inverse-global-border !default; -$dotnav-margin-horizontal: 12px !default; -$dotnav-margin-vertical: $dotnav-margin-horizontal !default; -$dotnav-item-width: 10px !default; -$dotnav-item-height: $dotnav-item-width !default; -$dotnav-item-border-radius: 50% !default; -$dotnav-item-background: rgba($global-color, 0.2) !default; -$dotnav-item-hover-background: rgba($global-color, 0.6) !default; -$dotnav-item-onclick-background: rgba($global-color, 0.2) !default; -$dotnav-item-active-background: rgba($global-color, 0.6) !default; -$inverse-dotnav-item-background: rgba($inverse-global-color, 0.5) !default; -$inverse-dotnav-item-hover-background: rgba($inverse-global-color, 0.9) !default; -$inverse-dotnav-item-onclick-background: rgba($inverse-global-color, 0.5) !default; -$inverse-dotnav-item-active-background: rgba($inverse-global-color, 0.9) !default; -$global-z-index: 1000 !default; -$drop-z-index: $global-z-index + 20 !default; -$drop-width: 300px !default; -$drop-margin: $global-margin !default; -$dropdown-z-index: $global-z-index + 20 !default; -$dropdown-min-width: 200px !default; -$dropdown-padding: 15px !default; -$dropdown-background: $global-muted-background !default; -$dropdown-color: $global-color !default; -$dropdown-margin: $global-small-margin !default; -$dropdown-nav-item-color: $global-muted-color !default; -$dropdown-nav-item-hover-color: $global-color !default; -$dropdown-nav-header-color: $global-emphasis-color !default; -$dropdown-nav-divider-border-width: $global-border-width !default; -$dropdown-nav-divider-border: $global-border !default; -$dropdown-nav-sublist-item-color: $global-muted-color !default; -$dropdown-nav-sublist-item-hover-color: $global-color !default; -$form-range-thumb-height: 15px !default; -$form-range-thumb-width: $form-range-thumb-height !default; -$form-range-thumb-border-radius: 500px !default; -$form-range-thumb-background: $global-color !default; -$form-range-track-height: 3px !default; -$form-range-track-background: darken($global-muted-background, 5%) !default; -$form-range-track-focus-background: darken($form-range-track-background, 5%) !default; -$form-height: $global-control-height !default; -$form-line-height: $form-height !default; -$form-padding-horizontal: 10px !default; -$form-padding-vertical: round($form-padding-horizontal * 0.6) !default; -$form-background: $global-muted-background !default; -$form-color: $global-color !default; -$form-focus-background: darken($form-background, 5%) !default; -$form-focus-color: $global-color !default; -$form-disabled-background: $global-muted-background !default; -$form-disabled-color: $global-muted-color !default; -$form-placeholder-color: $global-muted-color !default; -$form-small-height: $global-control-small-height !default; -$form-small-padding-horizontal: 8px !default; -$form-small-padding-vertical: round($form-small-padding-horizontal * 0.6) !default; -$form-small-line-height: $form-small-height !default; -$form-small-font-size: $global-small-font-size !default; -$form-large-height: $global-control-large-height !default; -$form-large-padding-horizontal: 12px !default; -$form-large-padding-vertical: round($form-large-padding-horizontal * 0.6) !default; -$form-large-line-height: $form-large-height !default; -$form-large-font-size: $global-medium-font-size !default; -$form-danger-color: $global-danger-background !default; -$form-success-color: $global-success-background !default; -$form-width-xsmall: 50px !default; -$form-width-small: 130px !default; -$form-width-medium: 200px !default; -$form-width-large: 500px !default; -$form-select-padding-right: 20px !default; -$form-select-icon-color: $global-color !default; -$form-select-option-color: #444 !default; -$form-select-disabled-icon-color: $global-muted-color !default; -$form-datalist-padding-right: 20px !default; -$form-datalist-icon-color: $global-color !default; -$form-radio-size: 16px !default; -$form-radio-margin-top: -4px !default; -$form-radio-background: darken($global-muted-background, 5%) !default; -$form-radio-focus-background: darken($form-radio-background, 5%) !default; -$form-radio-checked-background: $global-primary-background !default; -$form-radio-checked-icon-color: $global-inverse-color !default; -$form-radio-checked-focus-background: darken($global-primary-background, 10%) !default; -$form-radio-disabled-background: $global-muted-background !default; -$form-radio-disabled-icon-color: $global-muted-color !default; -$form-legend-font-size: $global-large-font-size !default; -$form-legend-line-height: 1.4 !default; -$form-stacked-margin-bottom: $global-small-margin !default; -$form-horizontal-label-width: 200px !default; -$form-horizontal-label-margin-top: 7px !default; -$form-horizontal-controls-margin-left: 215px !default; -$form-horizontal-controls-text-padding-top: 7px !default; -$form-icon-width: $form-height !default; -$form-icon-color: $global-muted-color !default; -$form-icon-hover-color: $global-color !default; -$internal-form-select-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%209%206%2015%206%22%20%2F%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%2013%209%208%2015%208%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default; -$internal-form-datalist-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2224%22%20height%3D%2216%22%20viewBox%3D%220%200%2024%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%2012%208%206%2016%206%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default; -$internal-form-radio-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22#000%22%20cx%3D%228%22%20cy%3D%228%22%20r%3D%222%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$internal-form-checkbox-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2211%22%20viewBox%3D%220%200%2014%2011%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolygon%20fill%3D%22#000%22%20points%3D%2212%201%205%207.5%202%205%201%205.5%205%2010%2013%201.5%22%20%2F%3E%0A%3C%2Fsvg%3E%0A" !default; -$internal-form-checkbox-indeterminate-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Crect%20fill%3D%22#000%22%20x%3D%223%22%20y%3D%228%22%20width%3D%2210%22%20height%3D%221%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$inverse-global-muted-background: rgba($global-inverse-color, 0.1) !default; -$inverse-form-background: $inverse-global-muted-background !default; -$inverse-form-color: $inverse-global-color !default; -$inverse-form-focus-background: fadein($inverse-form-background, 5%) !default; -$inverse-form-focus-color: $inverse-global-color !default; -$inverse-form-placeholder-color: $inverse-global-muted-color !default; -$inverse-form-select-icon-color: $inverse-global-color !default; -$inverse-form-datalist-icon-color: $inverse-global-color !default; -$inverse-form-radio-background: $inverse-global-muted-background !default; -$inverse-form-radio-focus-background: fadein($inverse-form-radio-background, 5%) !default; -$inverse-form-radio-checked-background: $inverse-global-primary-background !default; -$inverse-form-radio-checked-icon-color: $inverse-global-inverse-color !default; -$inverse-form-radio-checked-focus-background: fadein($inverse-global-primary-background, 10%) !default; -$inverse-form-icon-color: $inverse-global-muted-color !default; -$inverse-form-icon-hover-color: $inverse-global-color !default; -$grid-gutter-horizontal: $global-gutter !default; -$grid-gutter-vertical: $grid-gutter-horizontal !default; -$grid-gutter-horizontal-l: $global-medium-gutter !default; -$grid-gutter-vertical-l: $grid-gutter-horizontal-l !default; -$grid-small-gutter-horizontal: $global-small-gutter !default; -$grid-small-gutter-vertical: $grid-small-gutter-horizontal !default; -$grid-medium-gutter-horizontal: $global-gutter !default; -$grid-medium-gutter-vertical: $grid-medium-gutter-horizontal !default; -$grid-large-gutter-horizontal: $global-medium-gutter !default; -$grid-large-gutter-vertical: $grid-large-gutter-horizontal !default; -$grid-large-gutter-horizontal-l: $global-large-gutter !default; -$grid-large-gutter-vertical-l: $grid-large-gutter-horizontal-l !default; -$grid-divider-border-width: $global-border-width !default; -$grid-divider-border: $global-border !default; -$inverse-grid-divider-border: $inverse-global-border !default; -$heading-medium-font-size-l: 4rem !default; -$heading-small-font-size-m: $heading-medium-font-size-l * 0.8125 !default; -$heading-small-font-size: $heading-small-font-size-m * 0.8 !default; -$heading-medium-font-size-m: $heading-medium-font-size-l * 0.875 !default; -$heading-medium-font-size: $heading-medium-font-size-m * 0.825 !default; -$heading-large-font-size-m: $heading-medium-font-size-l !default; -$heading-large-font-size: $heading-large-font-size-m * 0.85 !default; -$heading-xlarge-font-size: $heading-large-font-size-m !default; -$heading-large-font-size-l: 6rem !default; -$heading-xlarge-font-size-m: $heading-large-font-size-l !default; -$heading-2xlarge-font-size: $heading-xlarge-font-size-m !default; -$heading-xlarge-font-size-l: 8rem !default; -$heading-2xlarge-font-size-m: $heading-xlarge-font-size-l !default; -$heading-2xlarge-font-size-l: 11rem !default; -$heading-small-line-height: 1.2 !default; -$heading-medium-line-height: 1.1 !default; -$heading-large-line-height: 1.1 !default; -$heading-xlarge-line-height: 1 !default; -$heading-2xlarge-line-height: 1 !default; -$heading-divider-padding-bottom: unquote('calc(5px + 0.1em)') !default; -$heading-divider-border-width: unquote('calc(0.2px + 0.05em)') !default; -$heading-divider-border: $global-border !default; -$heading-bullet-top: unquote('calc(-0.1 * 1em)') !default; -$heading-bullet-height: unquote('calc(4px + 0.7em)') !default; -$heading-bullet-margin-right: unquote('calc(5px + 0.2em)') !default; -$heading-bullet-border-width: unquote('calc(5px + 0.1em)') !default; -$heading-bullet-border: $global-border !default; -$heading-line-top: 50% !default; -$heading-line-border-width: unquote('calc(0.2px + 0.05em)') !default; -$heading-line-height: $heading-line-border-width !default; -$heading-line-width: 2000px !default; -$heading-line-border: $global-border !default; -$heading-line-margin-horizontal: unquote('calc(5px + 0.3em)') !default; -$heading-primary-font-size-l: 3.75rem !default; -$heading-primary-line-height-l: 1.1 !default; -$heading-primary-font-size-m: $heading-primary-font-size-l * 0.9 !default; -$heading-primary-font-size: $heading-primary-font-size-l * 0.8 !default; -$heading-primary-line-height: 1.2 !default; -$heading-hero-font-size-l: 8rem !default; -$heading-hero-line-height-l: 1 !default; -$heading-hero-font-size-m: $heading-hero-font-size-l * 0.75 !default; -$heading-hero-line-height-m: 1 !default; -$heading-hero-font-size: $heading-hero-font-size-l * 0.5 !default; -$heading-hero-line-height: 1.1 !default; -$inverse-heading-divider-border: $inverse-global-border !default; -$inverse-heading-bullet-border: $inverse-global-border !default; -$inverse-heading-line-border: $inverse-global-border !default; -$height-small-height: 150px !default; -$height-medium-height: 300px !default; -$height-large-height: 450px !default; -$icon-image-size: 20px !default; -$icon-link-color: $global-muted-color !default; -$icon-link-hover-color: $global-color !default; -$icon-link-active-color: darken($global-color, 5%) !default; -$icon-button-size: 36px !default; -$icon-button-border-radius: 500px !default; -$icon-button-background: $global-muted-background !default; -$icon-button-color: $global-muted-color !default; -$icon-button-hover-background: darken($icon-button-background, 5%) !default; -$icon-button-hover-color: $global-color !default; -$icon-button-active-background: darken($icon-button-background, 10%) !default; -$icon-button-active-color: $global-color !default; -$inverse-icon-link-color: $inverse-global-muted-color !default; -$inverse-icon-link-hover-color: $inverse-global-color !default; -$inverse-icon-link-active-color: $inverse-global-color !default; -$inverse-icon-button-background: $inverse-global-muted-background !default; -$inverse-icon-button-color: $inverse-global-muted-color !default; -$inverse-icon-button-hover-background: fadein($inverse-icon-button-background, 5%) !default; -$inverse-icon-button-hover-color: $inverse-global-color !default; -$inverse-icon-button-active-background: fadein($inverse-icon-button-background, 10%) !default; -$inverse-icon-button-active-color: $inverse-global-color !default; -$iconnav-margin-horizontal: $global-small-margin !default; -$iconnav-margin-vertical: $iconnav-margin-horizontal !default; -$iconnav-item-color: $global-muted-color !default; -$iconnav-item-hover-color: $global-color !default; -$iconnav-item-active-color: $global-color !default; -$inverse-iconnav-item-color: $inverse-global-muted-color !default; -$inverse-iconnav-item-hover-color: $inverse-global-color !default; -$inverse-iconnav-item-active-color: $inverse-global-color !default; -$inverse-global-color-mode: light !default; -$label-padding-vertical: 0 !default; -$label-padding-horizontal: $global-small-margin !default; -$label-background: $global-primary-background !default; -$label-line-height: $global-line-height !default; -$label-font-size: $global-small-font-size !default; -$label-color: $global-inverse-color !default; -$label-success-background: $global-success-background !default; -$label-success-color: $global-inverse-color !default; -$label-warning-background: $global-warning-background !default; -$label-warning-color: $global-inverse-color !default; -$label-danger-background: $global-danger-background !default; -$label-danger-color: $global-inverse-color !default; -$inverse-label-background: $inverse-global-primary-background !default; -$inverse-label-color: $inverse-global-inverse-color !default; -$leader-fill-content: unquote('.') !default; -$leader-fill-margin-left: $global-small-gutter !default; -$lightbox-z-index: $global-z-index + 10 !default; -$lightbox-background: #000 !default; -$lightbox-item-color: rgba(255,255,255,0.7) !default; -$lightbox-item-max-width: 100vw !default; -$lightbox-item-max-height: 100vh !default; -$lightbox-toolbar-padding-vertical: 10px !default; -$lightbox-toolbar-padding-horizontal: 10px !default; -$lightbox-toolbar-background: rgba(0,0,0,0.3) !default; -$lightbox-toolbar-color: rgba(255,255,255,0.7) !default; -$lightbox-toolbar-icon-padding: 5px !default; -$lightbox-toolbar-icon-color: rgba(255,255,255,0.7) !default; -$lightbox-toolbar-icon-hover-color: #fff !default; -$lightbox-button-size: 50px !default; -$lightbox-button-background: $lightbox-toolbar-background !default; -$lightbox-button-color: rgba(255,255,255,0.7) !default; -$lightbox-button-hover-color: #fff !default; -$link-muted-color: $global-muted-color !default; -$link-muted-hover-color: $global-color !default; -$link-text-hover-color: $global-muted-color !default; -$link-heading-hover-color: $global-primary-background !default; -$link-heading-hover-text-decoration: none !default; -$inverse-link-muted-color: $inverse-global-muted-color !default; -$inverse-link-muted-hover-color: $inverse-global-color !default; -$inverse-link-text-hover-color: $inverse-global-muted-color !default; -$inverse-link-heading-hover-color: $inverse-global-primary-background !default; -$list-margin-top: $global-small-margin !default; -$list-padding-left: 30px !default; -$list-marker-height: ($global-line-height * 1em) !default; -$list-muted-color: $global-muted-color !default; -$list-emphasis-color: $global-emphasis-color !default; -$list-primary-color: $global-primary-background !default; -$list-secondary-color: $global-secondary-background !default; -$list-bullet-icon-color: $global-color !default; -$list-divider-margin-top: $global-small-margin !default; -$list-divider-border-width: $global-border-width !default; -$list-divider-border: $global-border !default; -$list-striped-padding-vertical: $global-small-margin !default; -$list-striped-padding-horizontal: $global-small-margin !default; -$list-striped-background: $global-muted-background !default; -$list-large-margin-top: $global-margin !default; -$list-large-divider-margin-top: $global-margin !default; -$list-large-striped-padding-vertical: $global-margin !default; -$list-large-striped-padding-horizontal: $global-small-margin !default; -$internal-list-bullet-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Ccircle%20fill%3D%22#000%22%20cx%3D%223%22%20cy%3D%223%22%20r%3D%223%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$inverse-list-muted-color: $inverse-global-muted-color !default; -$inverse-list-emphasis-color: $inverse-global-emphasis-color !default; -$inverse-list-primary-color: $inverse-global-primary-background !default; -$inverse-list-secondary-color: $inverse-global-primary-background !default; -$inverse-list-divider-border: $inverse-global-border !default; -$inverse-list-striped-background: $inverse-global-muted-background !default; -$inverse-list-bullet-icon-color: $inverse-global-color !default; -$margin-margin: $global-margin !default; -$margin-small-margin: $global-small-margin !default; -$margin-medium-margin: $global-medium-margin !default; -$margin-large-margin: $global-medium-margin !default; -$margin-large-margin-l: $global-large-margin !default; -$margin-xlarge-margin: $global-large-margin !default; -$global-xlarge-margin: 140px !default; -$margin-xlarge-margin-l: $global-xlarge-margin !default; -$marker-padding: 5px !default; -$marker-background: $global-secondary-background !default; -$marker-color: $global-inverse-color !default; -$marker-hover-color: $global-inverse-color !default; -$inverse-marker-background: $global-muted-background !default; -$inverse-marker-color: $global-color !default; -$inverse-marker-hover-color: $global-color !default; -$modal-z-index: $global-z-index + 10 !default; -$modal-background: rgba(0,0,0,0.6) !default; -$modal-padding-horizontal: 15px !default; -$modal-padding-horizontal-s: $global-gutter !default; -$modal-padding-horizontal-m: $global-medium-gutter !default; -$modal-padding-vertical: $modal-padding-horizontal !default; -$modal-padding-vertical-s: 50px !default; -$modal-dialog-width: 600px !default; -$modal-dialog-background: $global-background !default; -$modal-container-width: 1200px !default; -$modal-body-padding-horizontal: $global-gutter !default; -$modal-body-padding-vertical: $global-gutter !default; -$modal-header-padding-horizontal: $global-gutter !default; -$modal-header-padding-vertical: ($modal-header-padding-horizontal / 2) !default; -$modal-header-background: $global-muted-background !default; -$modal-footer-padding-horizontal: $global-gutter !default; -$modal-footer-padding-vertical: ($modal-footer-padding-horizontal / 2) !default; -$modal-footer-background: $global-muted-background !default; -$modal-title-font-size: $global-xlarge-font-size !default; -$modal-title-line-height: 1.3 !default; -$modal-close-position: $global-small-margin !default; -$modal-close-padding: 5px !default; -$modal-close-outside-position: 0 !default; -$modal-close-outside-translate: 100% !default; -$modal-close-outside-color: lighten($global-inverse-color, 20%) !default; -$modal-close-outside-hover-color: $global-inverse-color !default; -$nav-item-padding-vertical: 5px !default; -$nav-item-padding-horizontal: 0 !default; -$nav-sublist-padding-vertical: 5px !default; -$nav-sublist-padding-left: 15px !default; -$nav-sublist-deeper-padding-left: 15px !default; -$nav-sublist-item-padding-vertical: 2px !default; -$nav-parent-icon-width: ($global-line-height * 1em) !default; -$nav-parent-icon-height: $nav-parent-icon-width !default; -$nav-parent-icon-color: $global-color !default; -$nav-header-padding-vertical: $nav-item-padding-vertical !default; -$nav-header-padding-horizontal: $nav-item-padding-horizontal !default; -$nav-header-font-size: $global-small-font-size !default; -$nav-header-text-transform: uppercase !default; -$nav-header-margin-top: $global-margin !default; -$nav-divider-margin-vertical: 5px !default; -$nav-divider-margin-horizontal: 0 !default; -$nav-default-item-color: $global-muted-color !default; -$nav-default-item-hover-color: $global-color !default; -$nav-default-item-active-color: $global-emphasis-color !default; -$nav-default-header-color: $global-emphasis-color !default; -$nav-default-divider-border-width: $global-border-width !default; -$nav-default-divider-border: $global-border !default; -$nav-default-sublist-item-color: $global-muted-color !default; -$nav-default-sublist-item-hover-color: $global-color !default; -$nav-default-sublist-item-active-color: $global-emphasis-color !default; -$nav-primary-item-font-size: $global-large-font-size !default; -$nav-primary-item-line-height: $global-line-height !default; -$nav-primary-item-color: $global-muted-color !default; -$nav-primary-item-hover-color: $global-color !default; -$nav-primary-item-active-color: $global-emphasis-color !default; -$nav-primary-header-color: $global-emphasis-color !default; -$nav-primary-divider-border-width: $global-border-width !default; -$nav-primary-divider-border: $global-border !default; -$nav-primary-sublist-item-color: $global-muted-color !default; -$nav-primary-sublist-item-hover-color: $global-color !default; -$nav-primary-sublist-item-active-color: $global-emphasis-color !default; -$nav-dividers-margin-top: 0 !default; -$nav-dividers-border-width: $global-border-width !default; -$nav-dividers-border: $global-border !default; -$internal-nav-parent-close-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%221.1%22%20points%3D%2210%201%204%207%2010%2013%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$internal-nav-parent-open-image: "data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20viewBox%3D%220%200%2014%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%3Cpolyline%20fill%3D%22none%22%20stroke%3D%22#000%22%20stroke-width%3D%221.1%22%20points%3D%221%204%207%2010%2013%204%22%20%2F%3E%0A%3C%2Fsvg%3E" !default; -$inverse-nav-parent-icon-color: $inverse-global-color !default; -$inverse-nav-default-item-color: $inverse-global-muted-color !default; -$inverse-nav-default-item-hover-color: $inverse-global-color !default; -$inverse-nav-default-item-active-color: $inverse-global-emphasis-color !default; -$inverse-nav-default-header-color: $inverse-global-emphasis-color !default; -$inverse-nav-default-divider-border: $inverse-global-border !default; -$inverse-nav-default-sublist-item-color: $inverse-global-muted-color !default; -$inverse-nav-default-sublist-item-hover-color: $inverse-global-color !default; -$inverse-nav-default-sublist-item-active-color: $inverse-global-emphasis-color !default; -$inverse-nav-primary-item-color: $inverse-global-muted-color !default; -$inverse-nav-primary-item-hover-color: $inverse-global-color !default; -$inverse-nav-primary-item-active-color: $inverse-global-emphasis-color !default; -$inverse-nav-primary-header-color: $inverse-global-emphasis-color !default; -$inverse-nav-primary-divider-border: $inverse-global-border !default; -$inverse-nav-primary-sublist-item-color: $inverse-global-muted-color !default; -$inverse-nav-primary-sublist-item-hover-color: $inverse-global-color !default; -$inverse-nav-primary-sublist-item-active-color: $inverse-global-emphasis-color !default; -$inverse-nav-dividers-border: $inverse-global-border !default; -$navbar-background: $global-muted-background !default; -$navbar-color-mode: none !default; -$navbar-nav-item-height: 80px !default; -$navbar-nav-item-padding-horizontal: 15px !default; -$navbar-nav-item-color: $global-muted-color !default; -$navbar-nav-item-font-size: $global-font-size !default; -$navbar-nav-item-font-family: $global-font-family !default; -$navbar-nav-item-hover-color: $global-color !default; -$navbar-nav-item-onclick-color: $global-emphasis-color !default; -$navbar-nav-item-active-color: $global-emphasis-color !default; -$navbar-item-color: $global-color !default; -$navbar-toggle-color: $global-muted-color !default; -$navbar-toggle-hover-color: $global-color !default; -$navbar-subtitle-font-size: $global-small-font-size !default; -$navbar-dropdown-z-index: $global-z-index + 20 !default; -$navbar-dropdown-width: 200px !default; -$navbar-dropdown-margin: 0 !default; -$navbar-dropdown-padding: 15px !default; -$navbar-dropdown-background: $global-muted-background !default; -$navbar-dropdown-color: $global-color !default; -$navbar-dropdown-grid-gutter-horizontal: $global-gutter !default; -$navbar-dropdown-grid-gutter-vertical: $navbar-dropdown-grid-gutter-horizontal !default; -$navbar-dropdown-dropbar-margin-top: 0 !default; -$navbar-dropdown-dropbar-margin-bottom: $navbar-dropdown-dropbar-margin-top !default; -$navbar-dropdown-nav-item-color: $global-muted-color !default; -$navbar-dropdown-nav-item-hover-color: $global-color !default; -$navbar-dropdown-nav-item-active-color: $global-emphasis-color !default; -$navbar-dropdown-nav-header-color: $global-emphasis-color !default; -$navbar-dropdown-nav-divider-border-width: $global-border-width !default; -$navbar-dropdown-nav-divider-border: $global-border !default; -$navbar-dropdown-nav-sublist-item-color: $global-muted-color !default; -$navbar-dropdown-nav-sublist-item-hover-color: $global-color !default; -$navbar-dropdown-nav-sublist-item-active-color: $global-emphasis-color !default; -$navbar-dropbar-background: $navbar-dropdown-background !default; -$navbar-dropbar-z-index: $global-z-index - 20 !default; -$inverse-navbar-nav-item-color: $inverse-global-muted-color !default; -$inverse-navbar-nav-item-hover-color: $inverse-global-color !default; -$inverse-navbar-nav-item-onclick-color: $inverse-global-emphasis-color !default; -$inverse-navbar-nav-item-active-color: $inverse-global-emphasis-color !default; -$inverse-navbar-item-color: $inverse-global-color !default; -$inverse-navbar-toggle-color: $inverse-global-muted-color !default; -$inverse-navbar-toggle-hover-color: $inverse-global-color !default; -$notification-position: 10px !default; -$notification-z-index: $global-z-index + 40 !default; -$notification-width: 350px !default; -$notification-message-margin-top: 10px !default; -$notification-message-padding: $global-small-gutter !default; -$notification-message-background: $global-muted-background !default; -$notification-message-color: $global-color !default; -$notification-message-font-size: $global-medium-font-size !default; -$notification-message-line-height: 1.4 !default; -$notification-close-top: $notification-message-padding + 5px !default; -$notification-close-right: $notification-message-padding !default; -$notification-message-primary-color: $global-primary-background !default; -$notification-message-success-color: $global-success-background !default; -$notification-message-warning-color: $global-warning-background !default; -$notification-message-danger-color: $global-danger-background !default; -$offcanvas-z-index: $global-z-index !default; -$offcanvas-bar-width: 270px !default; -$offcanvas-bar-padding-vertical: $global-margin !default; -$offcanvas-bar-padding-horizontal: $global-margin !default; -$offcanvas-bar-background: $global-secondary-background !default; -$offcanvas-bar-color-mode: light !default; -$offcanvas-bar-width-m: 350px !default; -$offcanvas-bar-padding-vertical-m: $global-medium-gutter !default; -$offcanvas-bar-padding-horizontal-m: $global-medium-gutter !default; -$offcanvas-close-position: 20px !default; -$offcanvas-close-padding: 5px !default; -$offcanvas-overlay-background: rgba(0,0,0,0.1) !default; -$overlay-padding-horizontal: $global-gutter !default; -$overlay-padding-vertical: $global-gutter !default; -$overlay-default-background: rgba($global-background, 0.8) !default; -$overlay-primary-background: rgba($global-secondary-background, 0.8) !default; -$overlay-primary-color-mode: light !default; -$padding-padding: $global-gutter !default; -$padding-padding-l: $global-medium-gutter !default; -$padding-small-padding: $global-small-gutter !default; -$padding-large-padding: $global-gutter !default; -$padding-large-padding-l: $global-large-gutter !default; -$pagination-margin-horizontal: 0 !default; -$pagination-item-padding-vertical: 5px !default; -$pagination-item-padding-horizontal: 10px !default; -$pagination-item-color: $global-muted-color !default; -$pagination-item-hover-color: $global-color !default; -$pagination-item-hover-text-decoration: none !default; -$pagination-item-active-color: $global-color !default; -$pagination-item-disabled-color: $global-muted-color !default; -$inverse-pagination-item-color: $inverse-global-muted-color !default; -$inverse-pagination-item-hover-color: $inverse-global-color !default; -$inverse-pagination-item-active-color: $inverse-global-color !default; -$inverse-pagination-item-disabled-color: $inverse-global-muted-color !default; -$placeholder-margin-vertical: $global-margin !default; -$placeholder-padding-vertical: $global-gutter !default; -$placeholder-padding-horizontal: $global-gutter !default; -$placeholder-background: $global-muted-background !default; -$position-small-margin: $global-small-gutter !default; -$position-medium-margin: $global-gutter !default; -$position-large-margin: $global-gutter !default; -$position-large-margin-l: 50px !default; -$progress-height: 15px !default; -$progress-margin-vertical: $global-margin !default; -$progress-background: $global-muted-background !default; -$progress-bar-background: $global-primary-background !default; -$search-color: $global-color !default; -$search-placeholder-color: $global-muted-color !default; -$search-icon-color: $global-muted-color !default; -$search-default-width: 240px !default; -$search-default-height: $global-control-height !default; -$search-default-padding-horizontal: 10px !default; -$search-default-background: $global-muted-background !default; -$search-default-focus-background: darken($search-default-background, 5%) !default; -$search-default-icon-width: $global-control-height !default; -$search-navbar-width: 400px !default; -$search-navbar-height: 40px !default; -$search-navbar-background: transparent !default; -$search-navbar-font-size: $global-large-font-size !default; -$search-navbar-icon-width: 40px !default; -$search-large-width: 500px !default; -$search-large-height: 80px !default; -$search-large-background: transparent !default; -$search-large-font-size: $global-2xlarge-font-size !default; -$search-large-icon-width: 80px !default; -$search-toggle-color: $global-muted-color !default; -$search-toggle-hover-color: $global-color !default; -$inverse-search-color: $inverse-global-color !default; -$inverse-search-placeholder-color: $inverse-global-muted-color !default; -$inverse-search-icon-color: $inverse-global-muted-color !default; -$inverse-search-default-background: $inverse-global-muted-background !default; -$inverse-search-default-focus-background: fadein($inverse-search-default-background, 5%) !default; -$inverse-search-navbar-background: transparent !default; -$inverse-search-large-background: transparent !default; -$inverse-search-toggle-color: $inverse-global-muted-color !default; -$inverse-search-toggle-hover-color: $inverse-global-color !default; -$section-padding-vertical: $global-medium-margin !default; -$section-padding-vertical-m: $global-large-margin !default; -$section-xsmall-padding-vertical: $global-margin !default; -$section-small-padding-vertical: $global-medium-margin !default; -$section-large-padding-vertical: $global-large-margin !default; -$section-large-padding-vertical-m: $global-xlarge-margin !default; -$section-xlarge-padding-vertical: $global-xlarge-margin !default; -$section-xlarge-padding-vertical-m: ($global-large-margin + $global-xlarge-margin) !default; -$section-default-background: $global-background !default; -$section-muted-background: $global-muted-background !default; -$section-primary-background: $global-primary-background !default; -$section-primary-color-mode: light !default; -$section-secondary-background: $global-secondary-background !default; -$section-secondary-color-mode: light !default; -$slidenav-padding-vertical: 5px !default; -$slidenav-padding-horizontal: 10px !default; -$slidenav-color: rgba($global-color, 0.5) !default; -$slidenav-hover-color: rgba($global-color, 0.9) !default; -$slidenav-active-color: rgba($global-color, 0.5) !default; -$slidenav-large-padding-vertical: 10px !default; -$slidenav-large-padding-horizontal: $slidenav-large-padding-vertical !default; -$inverse-slidenav-color: rgba($inverse-global-color, 0.7) !default; -$inverse-slidenav-hover-color: rgba($inverse-global-color, 0.95) !default; -$inverse-slidenav-active-color: rgba($inverse-global-color, 0.7) !default; -$slider-container-margin-top: -11px !default; -$slider-container-margin-bottom: -39px !default; -$slider-container-margin-left: -25px !default; -$slider-container-margin-right: -25px !default; -$sortable-dragged-z-index: $global-z-index + 50 !default; -$sortable-placeholder-opacity: 0 !default; -$sortable-empty-height: 50px !default; -$spinner-size: 30px !default; -$spinner-stroke-width: 1 !default; -$spinner-radius: floor(($spinner-size - $spinner-stroke-width) / 2) !default; -$spinner-circumference: round(2 * 3.141 * $spinner-radius) !default; -$spinner-duration: 1.4s !default; -$sticky-z-index: $global-z-index - 20 !default; -$sticky-animation-duration: 0.2s !default; -$sticky-reverse-animation-duration: 0.2s !default; -$subnav-margin-horizontal: 20px !default; -$subnav-item-color: $global-muted-color !default; -$subnav-item-hover-color: $global-color !default; -$subnav-item-hover-text-decoration: none !default; -$subnav-item-active-color: $global-emphasis-color !default; -$subnav-divider-margin-horizontal: $subnav-margin-horizontal !default; -$subnav-divider-border-height: 1.5em !default; -$subnav-divider-border-width: $global-border-width !default; -$subnav-divider-border: $global-border !default; -$subnav-pill-item-padding-vertical: 5px !default; -$subnav-pill-item-padding-horizontal: 10px !default; -$subnav-pill-item-background: transparent !default; -$subnav-pill-item-color: $subnav-item-color !default; -$subnav-pill-item-hover-background: $global-muted-background !default; -$subnav-pill-item-hover-color: $global-color !default; -$subnav-pill-item-onclick-background: $subnav-pill-item-hover-background !default; -$subnav-pill-item-onclick-color: $subnav-pill-item-hover-color !default; -$subnav-pill-item-active-background: $global-primary-background !default; -$subnav-pill-item-active-color: $global-inverse-color !default; -$subnav-item-disabled-color: $global-muted-color !default; -$inverse-subnav-item-color: $inverse-global-muted-color !default; -$inverse-subnav-item-hover-color: $inverse-global-color !default; -$inverse-subnav-item-active-color: $inverse-global-emphasis-color !default; -$inverse-subnav-divider-border: $inverse-global-border !default; -$inverse-subnav-pill-item-background: transparent !default; -$inverse-subnav-pill-item-color: $inverse-global-muted-color !default; -$inverse-subnav-pill-item-hover-background: $inverse-global-muted-background !default; -$inverse-subnav-pill-item-hover-color: $inverse-global-color !default; -$inverse-subnav-pill-item-onclick-background: $inverse-subnav-pill-item-hover-background !default; -$inverse-subnav-pill-item-onclick-color: $inverse-subnav-pill-item-hover-color !default; -$inverse-subnav-pill-item-active-background: $inverse-global-primary-background !default; -$inverse-subnav-pill-item-active-color: $inverse-global-inverse-color !default; -$inverse-subnav-item-disabled-color: $inverse-global-muted-color !default; -$tab-margin-horizontal: 20px !default; -$tab-item-padding-horizontal: 10px !default; -$tab-item-padding-vertical: 5px !default; -$tab-item-color: $global-muted-color !default; -$tab-item-hover-color: $global-color !default; -$tab-item-hover-text-decoration: none !default; -$tab-item-active-color: $global-emphasis-color !default; -$tab-item-disabled-color: $global-muted-color !default; -$inverse-tab-item-color: $inverse-global-muted-color !default; -$inverse-tab-item-hover-color: $inverse-global-color !default; -$inverse-tab-item-active-color: $inverse-global-emphasis-color !default; -$inverse-tab-item-disabled-color: $inverse-global-muted-color !default; -$table-margin-vertical: $global-margin !default; -$table-cell-padding-vertical: 16px !default; -$table-cell-padding-horizontal: 12px !default; -$table-header-cell-font-size: $global-font-size !default; -$table-header-cell-font-weight: bold !default; -$table-header-cell-color: $global-color !default; -$table-footer-font-size: $global-small-font-size !default; -$table-caption-font-size: $global-small-font-size !default; -$table-caption-color: $global-muted-color !default; -$table-row-active-background: #ffd !default; -$table-divider-border-width: $global-border-width !default; -$table-divider-border: $global-border !default; -$table-striped-row-background: $global-muted-background !default; -$table-hover-row-background: $table-row-active-background !default; -$table-small-cell-padding-vertical: 10px !default; -$table-small-cell-padding-horizontal: 12px !default; -$table-large-cell-padding-vertical: 22px !default; -$table-large-cell-padding-horizontal: 12px !default; -$table-expand-min-width: 150px !default; -$inverse-table-header-cell-color: $inverse-global-color !default; -$inverse-table-caption-color: $inverse-global-muted-color !default; -$inverse-table-row-active-background: fade-out($inverse-global-muted-background, 0.02) !default; -$inverse-table-divider-border: $inverse-global-border !default; -$inverse-table-striped-row-background: $inverse-global-muted-background !default; -$inverse-table-hover-row-background: $inverse-table-row-active-background !default; -$text-lead-font-size: $global-large-font-size !default; -$text-lead-line-height: 1.5 !default; -$text-lead-color: $global-emphasis-color !default; -$text-meta-font-size: $global-small-font-size !default; -$text-meta-line-height: 1.4 !default; -$text-meta-color: $global-muted-color !default; -$text-small-font-size: $global-small-font-size !default; -$text-small-line-height: 1.5 !default; -$text-large-font-size: $global-large-font-size !default; -$text-large-line-height: 1.5 !default; -$text-muted-color: $global-muted-color !default; -$text-emphasis-color: $global-emphasis-color !default; -$text-primary-color: $global-primary-background !default; -$text-secondary-color: $global-secondary-background !default; -$text-success-color: $global-success-background !default; -$text-warning-color: $global-warning-background !default; -$text-danger-color: $global-danger-background !default; -$text-background-color: $global-primary-background !default; -$inverse-text-lead-color: $inverse-global-color !default; -$inverse-text-meta-color: $inverse-global-muted-color !default; -$inverse-text-muted-color: $inverse-global-muted-color !default; -$inverse-text-emphasis-color: $inverse-global-emphasis-color !default; -$inverse-text-primary-color: $inverse-global-primary-background !default; -$inverse-text-secondary-color: $inverse-global-primary-background !default; -$thumbnav-margin-horizontal: 15px !default; -$thumbnav-margin-vertical: $thumbnav-margin-horizontal !default; -$tile-padding-horizontal: 15px !default; -$tile-padding-horizontal-s: $global-gutter !default; -$tile-padding-horizontal-m: $global-medium-gutter !default; -$tile-padding-vertical: $global-medium-margin !default; -$tile-padding-vertical-m: $global-large-margin !default; -$tile-xsmall-padding-vertical: $global-margin !default; -$tile-small-padding-vertical: $global-medium-margin !default; -$tile-large-padding-vertical: $global-large-margin !default; -$tile-large-padding-vertical-m: $global-xlarge-margin !default; -$tile-xlarge-padding-vertical: $global-xlarge-margin !default; -$tile-xlarge-padding-vertical-m: ($global-large-margin + $global-xlarge-margin) !default; -$tile-default-background: $global-background !default; -$tile-muted-background: $global-muted-background !default; -$tile-primary-background: $global-primary-background !default; -$tile-primary-color-mode: light !default; -$tile-secondary-background: $global-secondary-background !default; -$tile-secondary-color-mode: light !default; -$tooltip-z-index: $global-z-index + 30 !default; -$tooltip-max-width: 200px !default; -$tooltip-padding-vertical: 3px !default; -$tooltip-padding-horizontal: 6px !default; -$tooltip-background: #666 !default; -$tooltip-border-radius: 2px !default; -$tooltip-color: $global-inverse-color !default; -$tooltip-font-size: 12px !default; -$tooltip-margin: 10px !default; -$totop-padding: 5px !default; -$totop-color: $global-muted-color !default; -$totop-hover-color: $global-color !default; -$totop-active-color: $global-emphasis-color !default; -$inverse-totop-color: $inverse-global-muted-color !default; -$inverse-totop-hover-color: $inverse-global-color !default; -$inverse-totop-active-color: $inverse-global-emphasis-color !default; -$transition-duration: 0.3s !default; -$transition-scale: 1.03 !default; -$transition-slide-small-translate: 10px !default; -$transition-slide-medium-translate: 50px !default; -$transition-slow-duration: 0.7s !default; -$panel-scrollable-height: 170px !default; -$panel-scrollable-padding: 10px !default; -$panel-scrollable-border-width: $global-border-width !default; -$panel-scrollable-border: $global-border !default; -$border-rounded-border-radius: 5px !default; -$box-shadow-duration: 0.1s !default; -$box-shadow-bottom-height: 30px !default; -$box-shadow-bottom-border-radius: 100% !default; -$box-shadow-bottom-background: #444 !default; -$box-shadow-bottom-blur: 20px !default; -$dropcap-margin-right: 10px !default; -$dropcap-font-size: (($global-line-height * 3) * 1em) !default; -$logo-font-size: $global-large-font-size !default; -$logo-font-family: $global-font-family !default; -$logo-color: $global-color !default; -$logo-hover-color: $global-color !default; -$dragover-box-shadow: 0 0 20px rgba(100,100,100,0.3) !default; -$inverse-logo-color: $inverse-global-color !default; -$inverse-logo-hover-color: $inverse-global-color !default; -$deprecated: false !default; -$breakpoint-small: 640px !default; -$breakpoint-medium: 960px !default; -$breakpoint-large: 1200px !default; -$breakpoint-xlarge: 1600px !default; -$breakpoint-xsmall-max: ($breakpoint-small - 1) !default; -$breakpoint-small-max: ($breakpoint-medium - 1) !default; -$breakpoint-medium-max: ($breakpoint-large - 1) !default; -$breakpoint-large-max: ($breakpoint-xlarge - 1) !default; -$global-small-box-shadow: 0 2px 8px rgba(0,0,0,0.08) !default; -$global-medium-box-shadow: 0 5px 15px rgba(0,0,0,0.08) !default; -$global-large-box-shadow: 0 14px 25px rgba(0,0,0,0.16) !default; -$global-xlarge-box-shadow: 0 28px 50px rgba(0,0,0,0.16) !default; -$width-small-width: 150px !default; -$width-medium-width: 300px !default; -$width-large-width: 450px !default; -$width-xlarge-width: 600px !default; -$width-2xlarge-width: 750px !default; \ No newline at end of file diff --git a/docs/assets/css/prism.css b/docs/assets/css/prism.css deleted file mode 100644 index 5465ca64b9..0000000000 --- a/docs/assets/css/prism.css +++ /dev/null @@ -1,218 +0,0 @@ -/* PrismJS 1.24.1 -https://prismjs.com/download.html#themes=prism-solarizedlight&languages=markup+clike+bash+git+groovy+handlebars+java+javadoc+javadoclike+javastacktrace+json+kotlin+markup-templating+nginx+shell-session+xml-doc+yaml&plugins=normalize-whitespace+toolbar+copy-to-clipboard */ -/* - Solarized Color Schemes originally by Ethan Schoonover - http://ethanschoonover.com/solarized - - Ported for PrismJS by Hector Matos - Website: https://krakendev.io - Twitter Handle: https://twitter.com/allonsykraken) -*/ - -/* -SOLARIZED HEX ---------- ------- -base03 #002b36 -base02 #073642 -base01 #586e75 -base00 #657b83 -base0 #839496 -base1 #93a1a1 -base2 #eee8d5 -base3 #FEF6EB -yellow #b58900 -orange #cb4b16 -red #dc322f -magenta #d33682 -violet #6c71c4 -blue #268bd2 -cyan #2aa198 -green #859900 -*/ - -code[class*="language-"], -pre[class*="language-"] { - color: #657b83; /* base00 */ - font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; - font-size: 1em; - text-align: left; - white-space: pre; - word-spacing: normal; - word-break: normal; - word-wrap: normal; - - line-height: 1.5; - - -moz-tab-size: 4; - -o-tab-size: 4; - tab-size: 4; - - -webkit-hyphens: none; - -moz-hyphens: none; - -ms-hyphens: none; - hyphens: none; -} - -pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, -code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { - background: #073642; /* base02 */ -} - -pre[class*="language-"]::selection, pre[class*="language-"] ::selection, -code[class*="language-"]::selection, code[class*="language-"] ::selection { - background: #073642; /* base02 */ -} - -/* Code blocks */ -pre[class*="language-"] { - padding: 1em; - margin: .5em 0; - overflow: auto; - border-radius: 0.3em; -} - -:not(pre) > code[class*="language-"], -pre[class*="language-"] { - background-color: #FEF6EB; /* base3 */ -} - -/* Inline code */ -:not(pre) > code[class*="language-"] { - padding: .1em; - border-radius: .3em; -} - -.token.comment, -.token.prolog, -.token.doctype, -.token.cdata { - color: #93a1a1; /* base1 */ -} - -.token.punctuation { - color: #586e75; /* base01 */ -} - -.token.namespace { - opacity: .7; -} - -.token.property, -.token.tag, -.token.boolean, -.token.number, -.token.constant, -.token.symbol, -.token.deleted { - color: #268bd2; /* blue */ -} - -.token.selector, -.token.attr-name, -.token.string, -.token.char, -.token.builtin, -.token.url, -.token.inserted { - color: #2aa198; /* cyan */ -} - -.token.entity { - color: #657b83; /* base00 */ - background: #eee8d5; /* base2 */ -} - -.token.atrule, -.token.attr-value, -.token.keyword { - color: #859900; /* green */ -} - -.token.function, -.token.class-name { - color: #b58900; /* yellow */ -} - -.token.regex, -.token.important, -.token.variable { - color: #cb4b16; /* orange */ -} - -.token.important, -.token.bold { - font-weight: bold; -} -.token.italic { - font-style: italic; -} - -.token.entity { - cursor: help; -} - -div.code-toolbar { - position: relative; -} - -div.code-toolbar > .toolbar { - position: absolute; - top: .3em; - right: .2em; - transition: opacity 0.3s ease-in-out; - opacity: 0; -} - -div.code-toolbar:hover > .toolbar { - opacity: 1; -} - -/* Separate line b/c rules are thrown out if selector is invalid. - IE11 and old Edge versions don't support :focus-within. */ -div.code-toolbar:focus-within > .toolbar { - opacity: 1; -} - -div.code-toolbar > .toolbar > .toolbar-item { - display: inline-block; -} - -div.code-toolbar > .toolbar > .toolbar-item > a { - cursor: pointer; -} - -div.code-toolbar > .toolbar > .toolbar-item > button { - background: none; - border: 0; - color: inherit; - font: inherit; - line-height: normal; - overflow: visible; - padding: 0; - -webkit-user-select: none; /* for button */ - -moz-user-select: none; - -ms-user-select: none; -} - -div.code-toolbar > .toolbar > .toolbar-item > a, -div.code-toolbar > .toolbar > .toolbar-item > button, -div.code-toolbar > .toolbar > .toolbar-item > span { - color: #bbb; - font-size: .8em; - padding: 0 .5em; - background: #f5f2f0; - background: rgba(224, 224, 224, 0.2); - box-shadow: 0 2px 0 0 rgba(0,0,0,0.2); - border-radius: .5em; -} - -div.code-toolbar > .toolbar > .toolbar-item > a:hover, -div.code-toolbar > .toolbar > .toolbar-item > a:focus, -div.code-toolbar > .toolbar > .toolbar-item > button:hover, -div.code-toolbar > .toolbar > .toolbar-item > button:focus, -div.code-toolbar > .toolbar > .toolbar-item > span:hover, -div.code-toolbar > .toolbar > .toolbar-item > span:focus { - color: inherit; - text-decoration: none; -} - diff --git a/docs/assets/css/style.scss b/docs/assets/css/style.scss deleted file mode 100644 index 3930cb46ac..0000000000 --- a/docs/assets/css/style.scss +++ /dev/null @@ -1,18 +0,0 @@ ---- -# this ensures Jekyll reads the file to be transformed into CSS later ---- - -$baseurl: "{{ site.baseurl }}"; - -// 1. Custom variables and variable overwrites. -@import "https://github.com/theme/variables"; - - -// 2. Import default variables and available mixins. -@import "https://github.com/uikit/variables-theme"; -@import "https://github.com/uikit/mixins-theme"; - -// 3. Import Custom theme for UIkit. -@import "https://github.com/theme/uikit"; -@import "https://github.com/theme/mixins"; - diff --git a/docs/assets/images/architecture.svg b/docs/assets/images/architecture.svg deleted file mode 100644 index 0f5a97da0d..0000000000 --- a/docs/assets/images/architecture.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
Operator
Operator
Controller
Controller
EventSourceManager
EventSourceManager
EventProcessor
EventProcessor
ReconcilerDispatcher
ReconcilerDispatcher
EventSource
EventSource
Propagate Event
Propagate Event
0..*
0..*
1..*
1..*
ControllerResourceEventSource
ControllerResourceEventSource
Propagate Event
Propagate Event
Reconciler
Reconciler
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/assets/images/cs-logo.svg b/docs/assets/images/cs-logo.svg deleted file mode 100644 index ebf87d6c4b..0000000000 --- a/docs/assets/images/cs-logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/assets/images/cs.png b/docs/assets/images/cs.png deleted file mode 100644 index 9b68819645d8f469789b46abc286c4e5580d9feb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5544 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 diff --git a/docs/assets/images/event-sources.png b/docs/assets/images/event-sources.png deleted file mode 100644 index 773eaeb106e32f33d7047ad158bf8e5436237c27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46120 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 diff --git a/docs/assets/images/favicon.ico b/docs/assets/images/favicon.ico deleted file mode 100644 index de4cda66116d07d8385d960f6411eca53c59570d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmbVMT}xD95PpO1x{)rr?y_G~5LDZTsriw85SiTwQKngzmXvOg67&fn+EOZEP;FTo zMP*b_5#0p4=bT;FJ?^f%n$pueb9|RY0xOm|@9wM?P6PN0$Yv;w)I2;yE`1c ztCbkW5<{%w1w&u$*#LK-$HS$e3~r8RaqD3g;fRl>-lXPa4aEzlgqK|O?`(H)V|)g0 zzRqFzX%77(KCayNG59!(*Pn}sJj-cs)l#dW%PZmcc6*we^`h?!nk&@mVEak2HU}X& zD^EEXd6CCxERT?IBc@bedSUOePetuv^Ra|tiK8(OHQ3Y=$Ha#M4ht9dTf#5t*VLCp z=k00bJrvC$GLgf*=XvEq9lGyKqdA;XY<(GjYF;PxC%?@hI$6Mg@b0^tLGN$|J%hn{ zb!-L?Ud`gmk9i!rxU9b5+0WR^JYpYz zG3HP6r;i*shZ;GVKjklCe&LtaC7ySTQGEISE$PoYYvl7i{!?}2E>K^4w-TPQ \ No newline at end of file diff --git a/docs/assets/images/logo-white.svg b/docs/assets/images/logo-white.svg deleted file mode 100644 index 87a3378dff..0000000000 --- a/docs/assets/images/logo-white.svg +++ /dev/null @@ -1 +0,0 @@ -JAVA OPERATOR SDK \ No newline at end of file diff --git a/docs/assets/images/logo.png b/docs/assets/images/logo.png deleted file mode 100644 index 220129ae892c7d6b7de2303a07438a4e96494bc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35366 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�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

TBTA@g$M=YsOk+Di5yA7)e*7_?}=;x4EChv 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 diff --git a/docs/assets/js/mermaid.min.js b/docs/assets/js/mermaid.min.js deleted file mode 100644 index 8f8ef35651..0000000000 --- a/docs/assets/js/mermaid.min.js +++ /dev/null @@ -1,3 +0,0 @@ -/*! For license information please see mermaid.min.js.LICENSE.txt */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.mermaid=e():t.mermaid=e()}("undefined"!=typeof self?self:this,(function(){return(()=>{var t={1362:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,6],n=[1,7],r=[1,8],i=[1,9],a=[1,12],o=[1,11],s=[1,15,24],c=[1,19],u=[1,31],l=[1,34],h=[1,32],f=[1,33],d=[1,35],p=[1,36],y=[1,37],g=[1,38],m=[1,41],v=[1,42],b=[1,43],_=[1,44],x=[15,24],w=[1,56],k=[1,57],T=[1,58],E=[1,59],C=[1,60],S=[1,61],A=[15,24,31,38,39,47,50,51,52,53,54,55,60,62],M=[15,24,29,31,38,39,43,47,50,51,52,53,54,55,60,62,77,78,79,80],N=[7,8,9,10,15,18,22,24],D=[47,77,78,79,80],O=[47,54,55,77,78,79,80],B=[47,50,51,52,53,77,78,79,80],L=[15,24,31],I=[1,93],R={trace:function(){},yy:{},symbols_:{error:2,start:3,mermaidDoc:4,direction:5,directive:6,direction_tb:7,direction_bt:8,direction_rl:9,direction_lr:10,graphConfig:11,openDirective:12,typeDirective:13,closeDirective:14,NEWLINE:15,":":16,argDirective:17,open_directive:18,type_directive:19,arg_directive:20,close_directive:21,CLASS_DIAGRAM:22,statements:23,EOF:24,statement:25,className:26,alphaNumToken:27,classLiteralName:28,GENERICTYPE:29,relationStatement:30,LABEL:31,classStatement:32,methodStatement:33,annotationStatement:34,clickStatement:35,cssClassStatement:36,CLASS:37,STYLE_SEPARATOR:38,STRUCT_START:39,members:40,STRUCT_STOP:41,ANNOTATION_START:42,ANNOTATION_END:43,MEMBER:44,SEPARATOR:45,relation:46,STR:47,relationType:48,lineType:49,AGGREGATION:50,EXTENSION:51,COMPOSITION:52,DEPENDENCY:53,LINE:54,DOTTED_LINE:55,CALLBACK:56,LINK:57,LINK_TARGET:58,CLICK:59,CALLBACK_NAME:60,CALLBACK_ARGS:61,HREF:62,CSSCLASS:63,commentToken:64,textToken:65,graphCodeTokens:66,textNoTagsToken:67,TAGSTART:68,TAGEND:69,"==":70,"--":71,PCT:72,DEFAULT:73,SPACE:74,MINUS:75,keywords:76,UNICODE_TEXT:77,NUM:78,ALPHA:79,BQUOTE_STR:80,$accept:0,$end:1},terminals_:{2:"error",7:"direction_tb",8:"direction_bt",9:"direction_rl",10:"direction_lr",15:"NEWLINE",16:":",18:"open_directive",19:"type_directive",20:"arg_directive",21:"close_directive",22:"CLASS_DIAGRAM",24:"EOF",29:"GENERICTYPE",31:"LABEL",37:"CLASS",38:"STYLE_SEPARATOR",39:"STRUCT_START",41:"STRUCT_STOP",42:"ANNOTATION_START",43:"ANNOTATION_END",44:"MEMBER",45:"SEPARATOR",47:"STR",50:"AGGREGATION",51:"EXTENSION",52:"COMPOSITION",53:"DEPENDENCY",54:"LINE",55:"DOTTED_LINE",56:"CALLBACK",57:"LINK",58:"LINK_TARGET",59:"CLICK",60:"CALLBACK_NAME",61:"CALLBACK_ARGS",62:"HREF",63:"CSSCLASS",66:"graphCodeTokens",68:"TAGSTART",69:"TAGEND",70:"==",71:"--",72:"PCT",73:"DEFAULT",74:"SPACE",75:"MINUS",76:"keywords",77:"UNICODE_TEXT",78:"NUM",79:"ALPHA",80:"BQUOTE_STR"},productions_:[0,[3,1],[3,1],[3,2],[5,1],[5,1],[5,1],[5,1],[4,1],[6,4],[6,6],[12,1],[13,1],[17,1],[14,1],[11,4],[23,1],[23,2],[23,3],[26,1],[26,1],[26,2],[26,2],[26,2],[25,1],[25,2],[25,1],[25,1],[25,1],[25,1],[25,1],[25,1],[25,1],[32,2],[32,4],[32,5],[32,7],[34,4],[40,1],[40,2],[33,1],[33,2],[33,1],[33,1],[30,3],[30,4],[30,4],[30,5],[46,3],[46,2],[46,2],[46,1],[48,1],[48,1],[48,1],[48,1],[49,1],[49,1],[35,3],[35,4],[35,3],[35,4],[35,4],[35,5],[35,3],[35,4],[35,4],[35,5],[35,3],[35,4],[35,4],[35,5],[36,3],[64,1],[64,1],[65,1],[65,1],[65,1],[65,1],[65,1],[65,1],[65,1],[67,1],[67,1],[67,1],[67,1],[27,1],[27,1],[27,1],[28,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:r.setDirection("TB");break;case 5:r.setDirection("BT");break;case 6:r.setDirection("RL");break;case 7:r.setDirection("LR");break;case 11:r.parseDirective("%%{","open_directive");break;case 12:r.parseDirective(a[s],"type_directive");break;case 13:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 14:r.parseDirective("}%%","close_directive","class");break;case 19:case 20:this.$=a[s];break;case 21:this.$=a[s-1]+a[s];break;case 22:case 23:this.$=a[s-1]+"~"+a[s];break;case 24:r.addRelation(a[s]);break;case 25:a[s-1].title=r.cleanupLabel(a[s]),r.addRelation(a[s-1]);break;case 33:r.addClass(a[s]);break;case 34:r.addClass(a[s-2]),r.setCssClass(a[s-2],a[s]);break;case 35:r.addClass(a[s-3]),r.addMembers(a[s-3],a[s-1]);break;case 36:r.addClass(a[s-5]),r.setCssClass(a[s-5],a[s-3]),r.addMembers(a[s-5],a[s-1]);break;case 37:r.addAnnotation(a[s],a[s-2]);break;case 38:this.$=[a[s]];break;case 39:a[s].push(a[s-1]),this.$=a[s];break;case 40:case 42:case 43:break;case 41:r.addMember(a[s-1],r.cleanupLabel(a[s]));break;case 44:this.$={id1:a[s-2],id2:a[s],relation:a[s-1],relationTitle1:"none",relationTitle2:"none"};break;case 45:this.$={id1:a[s-3],id2:a[s],relation:a[s-1],relationTitle1:a[s-2],relationTitle2:"none"};break;case 46:this.$={id1:a[s-3],id2:a[s],relation:a[s-2],relationTitle1:"none",relationTitle2:a[s-1]};break;case 47:this.$={id1:a[s-4],id2:a[s],relation:a[s-2],relationTitle1:a[s-3],relationTitle2:a[s-1]};break;case 48:this.$={type1:a[s-2],type2:a[s],lineType:a[s-1]};break;case 49:this.$={type1:"none",type2:a[s],lineType:a[s-1]};break;case 50:this.$={type1:a[s-1],type2:"none",lineType:a[s]};break;case 51:this.$={type1:"none",type2:"none",lineType:a[s]};break;case 52:this.$=r.relationType.AGGREGATION;break;case 53:this.$=r.relationType.EXTENSION;break;case 54:this.$=r.relationType.COMPOSITION;break;case 55:this.$=r.relationType.DEPENDENCY;break;case 56:this.$=r.lineType.LINE;break;case 57:this.$=r.lineType.DOTTED_LINE;break;case 58:case 64:this.$=a[s-2],r.setClickEvent(a[s-1],a[s]);break;case 59:case 65:this.$=a[s-3],r.setClickEvent(a[s-2],a[s-1]),r.setTooltip(a[s-2],a[s]);break;case 60:case 68:this.$=a[s-2],r.setLink(a[s-1],a[s]);break;case 61:case 69:this.$=a[s-3],r.setLink(a[s-2],a[s-1],a[s]);break;case 62:case 70:this.$=a[s-3],r.setLink(a[s-2],a[s-1]),r.setTooltip(a[s-2],a[s]);break;case 63:case 71:this.$=a[s-4],r.setLink(a[s-3],a[s-2],a[s]),r.setTooltip(a[s-3],a[s-1]);break;case 66:this.$=a[s-3],r.setClickEvent(a[s-2],a[s-1],a[s]);break;case 67:this.$=a[s-4],r.setClickEvent(a[s-3],a[s-2],a[s-1]),r.setTooltip(a[s-3],a[s]);break;case 72:r.setCssClass(a[s-1],a[s])}},table:[{3:1,4:2,5:3,6:4,7:e,8:n,9:r,10:i,11:5,12:10,18:a,22:o},{1:[3]},{1:[2,1]},{1:[2,2]},{3:13,4:2,5:3,6:4,7:e,8:n,9:r,10:i,11:5,12:10,18:a,22:o},{1:[2,8]},t(s,[2,4]),t(s,[2,5]),t(s,[2,6]),t(s,[2,7]),{13:14,19:[1,15]},{15:[1,16]},{19:[2,11]},{1:[2,3]},{14:17,16:[1,18],21:c},t([16,21],[2,12]),{5:29,6:28,7:e,8:n,9:r,10:i,12:10,18:a,23:20,25:21,26:30,27:39,28:40,30:22,32:23,33:24,34:25,35:26,36:27,37:u,42:l,44:h,45:f,56:d,57:p,59:y,63:g,77:m,78:v,79:b,80:_},{15:[1,45]},{17:46,20:[1,47]},{15:[2,14]},{24:[1,48]},{15:[1,49],24:[2,16]},t(x,[2,24],{31:[1,50]}),t(x,[2,26]),t(x,[2,27]),t(x,[2,28]),t(x,[2,29]),t(x,[2,30]),t(x,[2,31]),t(x,[2,32]),t(x,[2,40],{46:51,48:54,49:55,31:[1,53],47:[1,52],50:w,51:k,52:T,53:E,54:C,55:S}),{26:62,27:39,28:40,77:m,78:v,79:b,80:_},t(x,[2,42]),t(x,[2,43]),{27:63,77:m,78:v,79:b},{26:64,27:39,28:40,77:m,78:v,79:b,80:_},{26:65,27:39,28:40,77:m,78:v,79:b,80:_},{26:66,27:39,28:40,77:m,78:v,79:b,80:_},{47:[1,67]},t(A,[2,19],{27:39,28:40,26:68,29:[1,69],77:m,78:v,79:b,80:_}),t(A,[2,20],{29:[1,70]}),t(M,[2,86]),t(M,[2,87]),t(M,[2,88]),t([15,24,29,31,38,39,47,50,51,52,53,54,55,60,62],[2,89]),t(N,[2,9]),{14:71,21:c},{21:[2,13]},{1:[2,15]},{5:29,6:28,7:e,8:n,9:r,10:i,12:10,18:a,23:72,24:[2,17],25:21,26:30,27:39,28:40,30:22,32:23,33:24,34:25,35:26,36:27,37:u,42:l,44:h,45:f,56:d,57:p,59:y,63:g,77:m,78:v,79:b,80:_},t(x,[2,25]),{26:73,27:39,28:40,47:[1,74],77:m,78:v,79:b,80:_},{46:75,48:54,49:55,50:w,51:k,52:T,53:E,54:C,55:S},t(x,[2,41]),{49:76,54:C,55:S},t(D,[2,51],{48:77,50:w,51:k,52:T,53:E}),t(O,[2,52]),t(O,[2,53]),t(O,[2,54]),t(O,[2,55]),t(B,[2,56]),t(B,[2,57]),t(x,[2,33],{38:[1,78],39:[1,79]}),{43:[1,80]},{47:[1,81]},{47:[1,82]},{60:[1,83],62:[1,84]},{27:85,77:m,78:v,79:b},t(A,[2,21]),t(A,[2,22]),t(A,[2,23]),{15:[1,86]},{24:[2,18]},t(L,[2,44]),{26:87,27:39,28:40,77:m,78:v,79:b,80:_},{26:88,27:39,28:40,47:[1,89],77:m,78:v,79:b,80:_},t(D,[2,50],{48:90,50:w,51:k,52:T,53:E}),t(D,[2,49]),{27:91,77:m,78:v,79:b},{40:92,44:I},{26:94,27:39,28:40,77:m,78:v,79:b,80:_},t(x,[2,58],{47:[1,95]}),t(x,[2,60],{47:[1,97],58:[1,96]}),t(x,[2,64],{47:[1,98],61:[1,99]}),t(x,[2,68],{47:[1,101],58:[1,100]}),t(x,[2,72]),t(N,[2,10]),t(L,[2,46]),t(L,[2,45]),{26:102,27:39,28:40,77:m,78:v,79:b,80:_},t(D,[2,48]),t(x,[2,34],{39:[1,103]}),{41:[1,104]},{40:105,41:[2,38],44:I},t(x,[2,37]),t(x,[2,59]),t(x,[2,61]),t(x,[2,62],{58:[1,106]}),t(x,[2,65]),t(x,[2,66],{47:[1,107]}),t(x,[2,69]),t(x,[2,70],{58:[1,108]}),t(L,[2,47]),{40:109,44:I},t(x,[2,35]),{41:[2,39]},t(x,[2,63]),t(x,[2,67]),t(x,[2,71]),{41:[1,110]},t(x,[2,36])],defaultActions:{2:[2,1],3:[2,2],5:[2,8],12:[2,11],13:[2,3],19:[2,14],47:[2,13],48:[2,15],72:[2,18],105:[2,39]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},F={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),18;case 1:return 7;case 2:return 8;case 3:return 9;case 4:return 10;case 5:return this.begin("type_directive"),19;case 6:return this.popState(),this.begin("arg_directive"),16;case 7:return this.popState(),this.popState(),21;case 8:return 20;case 9:case 10:case 12:case 19:break;case 11:return 15;case 13:case 14:return 22;case 15:return this.begin("struct"),39;case 16:return"EOF_IN_STRUCT";case 17:return"OPEN_IN_STRUCT";case 18:return this.popState(),41;case 20:return"MEMBER";case 21:return 37;case 22:return 63;case 23:return 56;case 24:return 57;case 25:return 59;case 26:return 42;case 27:return 43;case 28:this.begin("generic");break;case 29:case 32:case 35:case 38:case 41:case 44:this.popState();break;case 30:return"GENERICTYPE";case 31:this.begin("string");break;case 33:return"STR";case 34:this.begin("bqstring");break;case 36:return"BQUOTE_STR";case 37:this.begin("href");break;case 39:return 62;case 40:this.begin("callback_name");break;case 42:this.popState(),this.begin("callback_args");break;case 43:return 60;case 45:return 61;case 46:case 47:case 48:case 49:return 58;case 50:case 51:return 51;case 52:case 53:return 53;case 54:return 52;case 55:return 50;case 56:return 54;case 57:return 55;case 58:return 31;case 59:return 38;case 60:return 75;case 61:return"DOT";case 62:return"PLUS";case 63:return 72;case 64:case 65:return"EQUALS";case 66:return 79;case 67:return"PUNCTUATION";case 68:return 78;case 69:return 77;case 70:return 74;case 71:return 24}},rules:[/^(?:%%\{)/,/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:((?:(?!\}%%)[^:.])*))/,/^(?::)/,/^(?:\}%%)/,/^(?:((?:(?!\}%%).|\n)*))/,/^(?:%%(?!\{)*[^\n]*(\r?\n?)+)/,/^(?:%%[^\n]*(\r?\n)*)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:classDiagram-v2\b)/,/^(?:classDiagram\b)/,/^(?:[{])/,/^(?:$)/,/^(?:[{])/,/^(?:[}])/,/^(?:[\n])/,/^(?:[^{}\n]*)/,/^(?:class\b)/,/^(?:cssClass\b)/,/^(?:callback\b)/,/^(?:link\b)/,/^(?:click\b)/,/^(?:<<)/,/^(?:>>)/,/^(?:[~])/,/^(?:[~])/,/^(?:[^~]*)/,/^(?:["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:[`])/,/^(?:[`])/,/^(?:[^`]+)/,/^(?:href[\s]+["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:\s*<\|)/,/^(?:\s*\|>)/,/^(?:\s*>)/,/^(?:\s*<)/,/^(?:\s*\*)/,/^(?:\s*o\b)/,/^(?:--)/,/^(?:\.\.)/,/^(?::{1}[^:\n;]+)/,/^(?::{3})/,/^(?:-)/,/^(?:\.)/,/^(?:\+)/,/^(?:%)/,/^(?:=)/,/^(?:=)/,/^(?:\w+)/,/^(?:[!"#$%&'*+,-.`?\\/])/,/^(?:[0-9]+)/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/,/^(?:\s)/,/^(?:$)/],conditions:{arg_directive:{rules:[7,8],inclusive:!1},type_directive:{rules:[6,7],inclusive:!1},open_directive:{rules:[5],inclusive:!1},callback_args:{rules:[44,45],inclusive:!1},callback_name:{rules:[41,42,43],inclusive:!1},href:{rules:[38,39],inclusive:!1},struct:{rules:[16,17,18,19,20],inclusive:!1},generic:{rules:[29,30],inclusive:!1},bqstring:{rules:[35,36],inclusive:!1},string:{rules:[32,33],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,9,10,11,12,13,14,15,21,22,23,24,25,26,27,28,31,34,37,40,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71],inclusive:!0}}};function P(){this.yy={}}return R.lexer=F,P.prototype=R,R.Parser=P,new P}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(8218).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},5890:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,5],r=[6,9,11,23,41],i=[1,17],a=[1,20],o=[1,25],s=[1,26],c=[1,27],u=[1,28],l=[1,37],h=[23,38,39],f=[4,6,9,11,23,41],d=[34,35,36,37],p=[22,29],y=[1,55],g={trace:function(){},yy:{},symbols_:{error:2,start:3,ER_DIAGRAM:4,document:5,EOF:6,directive:7,line:8,SPACE:9,statement:10,NEWLINE:11,openDirective:12,typeDirective:13,closeDirective:14,":":15,argDirective:16,entityName:17,relSpec:18,role:19,BLOCK_START:20,attributes:21,BLOCK_STOP:22,ALPHANUM:23,attribute:24,attributeType:25,attributeName:26,attributeKeyType:27,attributeComment:28,ATTRIBUTE_WORD:29,ATTRIBUTE_KEY:30,COMMENT:31,cardinality:32,relType:33,ZERO_OR_ONE:34,ZERO_OR_MORE:35,ONE_OR_MORE:36,ONLY_ONE:37,NON_IDENTIFYING:38,IDENTIFYING:39,WORD:40,open_directive:41,type_directive:42,arg_directive:43,close_directive:44,$accept:0,$end:1},terminals_:{2:"error",4:"ER_DIAGRAM",6:"EOF",9:"SPACE",11:"NEWLINE",15:":",20:"BLOCK_START",22:"BLOCK_STOP",23:"ALPHANUM",29:"ATTRIBUTE_WORD",30:"ATTRIBUTE_KEY",31:"COMMENT",34:"ZERO_OR_ONE",35:"ZERO_OR_MORE",36:"ONE_OR_MORE",37:"ONLY_ONE",38:"NON_IDENTIFYING",39:"IDENTIFYING",40:"WORD",41:"open_directive",42:"type_directive",43:"arg_directive",44:"close_directive"},productions_:[0,[3,3],[3,2],[5,0],[5,2],[8,2],[8,1],[8,1],[8,1],[7,4],[7,6],[10,1],[10,5],[10,4],[10,3],[10,1],[17,1],[21,1],[21,2],[24,2],[24,3],[24,3],[24,4],[25,1],[26,1],[27,1],[28,1],[18,3],[32,1],[32,1],[32,1],[32,1],[33,1],[33,1],[19,1],[19,1],[12,1],[13,1],[16,1],[14,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 1:break;case 3:case 7:case 8:this.$=[];break;case 4:a[s-1].push(a[s]),this.$=a[s-1];break;case 5:case 6:case 16:case 23:case 24:case 25:case 35:this.$=a[s];break;case 12:r.addEntity(a[s-4]),r.addEntity(a[s-2]),r.addRelationship(a[s-4],a[s],a[s-2],a[s-3]);break;case 13:r.addEntity(a[s-3]),r.addAttributes(a[s-3],a[s-1]);break;case 14:r.addEntity(a[s-2]);break;case 15:r.addEntity(a[s]);break;case 17:this.$=[a[s]];break;case 18:a[s].push(a[s-1]),this.$=a[s];break;case 19:this.$={attributeType:a[s-1],attributeName:a[s]};break;case 20:this.$={attributeType:a[s-2],attributeName:a[s-1],attributeKeyType:a[s]};break;case 21:this.$={attributeType:a[s-2],attributeName:a[s-1],attributeComment:a[s]};break;case 22:this.$={attributeType:a[s-3],attributeName:a[s-2],attributeKeyType:a[s-1],attributeComment:a[s]};break;case 26:case 34:this.$=a[s].replace(/"/g,"");break;case 27:this.$={cardA:a[s],relType:a[s-1],cardB:a[s-2]};break;case 28:this.$=r.Cardinality.ZERO_OR_ONE;break;case 29:this.$=r.Cardinality.ZERO_OR_MORE;break;case 30:this.$=r.Cardinality.ONE_OR_MORE;break;case 31:this.$=r.Cardinality.ONLY_ONE;break;case 32:this.$=r.Identification.NON_IDENTIFYING;break;case 33:this.$=r.Identification.IDENTIFYING;break;case 36:r.parseDirective("%%{","open_directive");break;case 37:r.parseDirective(a[s],"type_directive");break;case 38:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 39:r.parseDirective("}%%","close_directive","er")}},table:[{3:1,4:e,7:3,12:4,41:n},{1:[3]},t(r,[2,3],{5:6}),{3:7,4:e,7:3,12:4,41:n},{13:8,42:[1,9]},{42:[2,36]},{6:[1,10],7:15,8:11,9:[1,12],10:13,11:[1,14],12:4,17:16,23:i,41:n},{1:[2,2]},{14:18,15:[1,19],44:a},t([15,44],[2,37]),t(r,[2,8],{1:[2,1]}),t(r,[2,4]),{7:15,10:21,12:4,17:16,23:i,41:n},t(r,[2,6]),t(r,[2,7]),t(r,[2,11]),t(r,[2,15],{18:22,32:24,20:[1,23],34:o,35:s,36:c,37:u}),t([6,9,11,15,20,23,34,35,36,37,41],[2,16]),{11:[1,29]},{16:30,43:[1,31]},{11:[2,39]},t(r,[2,5]),{17:32,23:i},{21:33,22:[1,34],24:35,25:36,29:l},{33:38,38:[1,39],39:[1,40]},t(h,[2,28]),t(h,[2,29]),t(h,[2,30]),t(h,[2,31]),t(f,[2,9]),{14:41,44:a},{44:[2,38]},{15:[1,42]},{22:[1,43]},t(r,[2,14]),{21:44,22:[2,17],24:35,25:36,29:l},{26:45,29:[1,46]},{29:[2,23]},{32:47,34:o,35:s,36:c,37:u},t(d,[2,32]),t(d,[2,33]),{11:[1,48]},{19:49,23:[1,51],40:[1,50]},t(r,[2,13]),{22:[2,18]},t(p,[2,19],{27:52,28:53,30:[1,54],31:y}),t([22,29,30,31],[2,24]),{23:[2,27]},t(f,[2,10]),t(r,[2,12]),t(r,[2,34]),t(r,[2,35]),t(p,[2,20],{28:56,31:y}),t(p,[2,21]),t([22,29,31],[2,25]),t(p,[2,26]),t(p,[2,22])],defaultActions:{5:[2,36],7:[2,2],20:[2,39],31:[2,38],37:[2,23],44:[2,18],47:[2,27]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},m={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),41;case 1:return this.begin("type_directive"),42;case 2:return this.popState(),this.begin("arg_directive"),15;case 3:return this.popState(),this.popState(),44;case 4:return 43;case 5:case 6:case 8:case 13:case 17:break;case 7:return 11;case 9:return 9;case 10:return 40;case 11:return 4;case 12:return this.begin("block"),20;case 14:return 30;case 15:return 29;case 16:return 31;case 18:return this.popState(),22;case 19:case 32:return e.yytext[0];case 20:case 24:return 34;case 21:case 25:return 35;case 22:case 26:return 36;case 23:return 37;case 27:case 29:case 30:return 38;case 28:return 39;case 31:return 23;case 33:return 6}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:[\s]+)/i,/^(?:"[^"]*")/i,/^(?:erDiagram\b)/i,/^(?:\{)/i,/^(?:\s+)/i,/^(?:(?:PK)|(?:FK))/i,/^(?:[A-Za-z][A-Za-z0-9\-_]*)/i,/^(?:"[^"]*")/i,/^(?:[\n]+)/i,/^(?:\})/i,/^(?:.)/i,/^(?:\|o\b)/i,/^(?:\}o\b)/i,/^(?:\}\|)/i,/^(?:\|\|)/i,/^(?:o\|)/i,/^(?:o\{)/i,/^(?:\|\{)/i,/^(?:\.\.)/i,/^(?:--)/i,/^(?:\.-)/i,/^(?:-\.)/i,/^(?:[A-Za-z][A-Za-z0-9\-_]*)/i,/^(?:.)/i,/^(?:$)/i],conditions:{open_directive:{rules:[1],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},block:{rules:[13,14,15,16,17,18,19],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,12,20,21,22,23,24,25,26,27,28,29,30,31,32,33],inclusive:!0}}};function v(){this.yy={}}return g.lexer=m,v.prototype=g,g.Parser=v,new v}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(8009).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},3602:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,9],n=[1,7],r=[1,6],i=[1,8],a=[1,20,21,22,23,38,47,59,60,79,80,81,82,83,84,88,98,99,102,104,105,111,112,113,114,115,116,117,118,119,120],o=[2,10],s=[1,20],c=[1,21],u=[1,22],l=[1,23],h=[1,30],f=[1,59],d=[1,45],p=[1,49],y=[1,33],g=[1,34],m=[1,35],v=[1,36],b=[1,37],_=[1,53],x=[1,60],w=[1,48],k=[1,50],T=[1,52],E=[1,56],C=[1,57],S=[1,38],A=[1,39],M=[1,40],N=[1,41],D=[1,58],O=[1,47],B=[1,51],L=[1,54],I=[1,55],R=[1,46],F=[1,63],P=[1,68],j=[1,20,21,22,23,38,42,47,59,60,79,80,81,82,83,84,88,98,99,102,104,105,111,112,113,114,115,116,117,118,119,120],Y=[1,72],z=[1,71],U=[1,73],q=[20,21,23,74,75],H=[1,94],$=[1,99],W=[1,102],V=[1,103],G=[1,96],X=[1,101],Z=[1,104],Q=[1,97],K=[1,109],J=[1,108],tt=[1,98],et=[1,100],nt=[1,105],rt=[1,106],it=[1,107],at=[1,110],ot=[20,21,22,23,74,75],st=[20,21,22,23,48,74,75],ct=[20,21,22,23,40,47,48,50,52,54,56,58,59,60,62,64,66,67,69,74,75,84,88,98,99,102,104,105,115,116,117,118,119,120],ut=[20,21,23],lt=[20,21,23,47,59,60,74,75,84,88,98,99,102,104,105,115,116,117,118,119,120],ht=[1,12,20,21,22,23,24,38,42,47,59,60,79,80,81,82,83,84,88,98,99,102,104,105,111,112,113,114,115,116,117,118,119,120],ft=[47,59,60,84,88,98,99,102,104,105,115,116,117,118,119,120],dt=[1,143],pt=[1,151],yt=[1,152],gt=[1,153],mt=[1,154],vt=[1,138],bt=[1,139],_t=[1,135],xt=[1,146],wt=[1,147],kt=[1,148],Tt=[1,149],Et=[1,150],Ct=[1,155],St=[1,156],At=[1,141],Mt=[1,144],Nt=[1,140],Dt=[1,137],Ot=[20,21,22,23,38,42,47,59,60,79,80,81,82,83,84,88,98,99,102,104,105,111,112,113,114,115,116,117,118,119,120],Bt=[1,159],Lt=[20,21,22,23,26,47,59,60,84,98,99,102,104,105,115,116,117,118,119,120],It=[20,21,22,23,24,26,38,40,41,42,47,51,53,55,57,59,60,61,63,65,66,68,70,74,75,79,80,81,82,83,84,85,88,98,99,102,104,105,106,107,115,116,117,118,119,120],Rt=[12,21,22,24],Ft=[22,99],Pt=[1,242],jt=[1,237],Yt=[1,238],zt=[1,246],Ut=[1,243],qt=[1,240],Ht=[1,239],$t=[1,241],Wt=[1,244],Vt=[1,245],Gt=[1,247],Xt=[1,265],Zt=[20,21,23,99],Qt=[20,21,22,23,59,60,79,95,98,99,102,103,104,105,106],Kt={trace:function(){},yy:{},symbols_:{error:2,start:3,mermaidDoc:4,directive:5,openDirective:6,typeDirective:7,closeDirective:8,separator:9,":":10,argDirective:11,open_directive:12,type_directive:13,arg_directive:14,close_directive:15,graphConfig:16,document:17,line:18,statement:19,SEMI:20,NEWLINE:21,SPACE:22,EOF:23,GRAPH:24,NODIR:25,DIR:26,FirstStmtSeperator:27,ending:28,endToken:29,spaceList:30,spaceListNewline:31,verticeStatement:32,styleStatement:33,linkStyleStatement:34,classDefStatement:35,classStatement:36,clickStatement:37,subgraph:38,text:39,SQS:40,SQE:41,end:42,direction:43,link:44,node:45,vertex:46,AMP:47,STYLE_SEPARATOR:48,idString:49,PS:50,PE:51,"(-":52,"-)":53,STADIUMSTART:54,STADIUMEND:55,SUBROUTINESTART:56,SUBROUTINEEND:57,VERTEX_WITH_PROPS_START:58,ALPHA:59,COLON:60,PIPE:61,CYLINDERSTART:62,CYLINDEREND:63,DIAMOND_START:64,DIAMOND_STOP:65,TAGEND:66,TRAPSTART:67,TRAPEND:68,INVTRAPSTART:69,INVTRAPEND:70,linkStatement:71,arrowText:72,TESTSTR:73,START_LINK:74,LINK:75,textToken:76,STR:77,keywords:78,STYLE:79,LINKSTYLE:80,CLASSDEF:81,CLASS:82,CLICK:83,DOWN:84,UP:85,textNoTags:86,textNoTagsToken:87,DEFAULT:88,stylesOpt:89,alphaNum:90,CALLBACKNAME:91,CALLBACKARGS:92,HREF:93,LINK_TARGET:94,HEX:95,numList:96,INTERPOLATE:97,NUM:98,COMMA:99,style:100,styleComponent:101,MINUS:102,UNIT:103,BRKT:104,DOT:105,PCT:106,TAGSTART:107,alphaNumToken:108,idStringToken:109,alphaNumStatement:110,direction_tb:111,direction_bt:112,direction_rl:113,direction_lr:114,PUNCTUATION:115,UNICODE_TEXT:116,PLUS:117,EQUALS:118,MULT:119,UNDERSCORE:120,graphCodeTokens:121,ARROW_CROSS:122,ARROW_POINT:123,ARROW_CIRCLE:124,ARROW_OPEN:125,QUOTE:126,$accept:0,$end:1},terminals_:{2:"error",10:":",12:"open_directive",13:"type_directive",14:"arg_directive",15:"close_directive",20:"SEMI",21:"NEWLINE",22:"SPACE",23:"EOF",24:"GRAPH",25:"NODIR",26:"DIR",38:"subgraph",40:"SQS",41:"SQE",42:"end",47:"AMP",48:"STYLE_SEPARATOR",50:"PS",51:"PE",52:"(-",53:"-)",54:"STADIUMSTART",55:"STADIUMEND",56:"SUBROUTINESTART",57:"SUBROUTINEEND",58:"VERTEX_WITH_PROPS_START",59:"ALPHA",60:"COLON",61:"PIPE",62:"CYLINDERSTART",63:"CYLINDEREND",64:"DIAMOND_START",65:"DIAMOND_STOP",66:"TAGEND",67:"TRAPSTART",68:"TRAPEND",69:"INVTRAPSTART",70:"INVTRAPEND",73:"TESTSTR",74:"START_LINK",75:"LINK",77:"STR",79:"STYLE",80:"LINKSTYLE",81:"CLASSDEF",82:"CLASS",83:"CLICK",84:"DOWN",85:"UP",88:"DEFAULT",91:"CALLBACKNAME",92:"CALLBACKARGS",93:"HREF",94:"LINK_TARGET",95:"HEX",97:"INTERPOLATE",98:"NUM",99:"COMMA",102:"MINUS",103:"UNIT",104:"BRKT",105:"DOT",106:"PCT",107:"TAGSTART",111:"direction_tb",112:"direction_bt",113:"direction_rl",114:"direction_lr",115:"PUNCTUATION",116:"UNICODE_TEXT",117:"PLUS",118:"EQUALS",119:"MULT",120:"UNDERSCORE",122:"ARROW_CROSS",123:"ARROW_POINT",124:"ARROW_CIRCLE",125:"ARROW_OPEN",126:"QUOTE"},productions_:[0,[3,1],[3,2],[5,4],[5,6],[6,1],[7,1],[11,1],[8,1],[4,2],[17,0],[17,2],[18,1],[18,1],[18,1],[18,1],[18,1],[16,2],[16,2],[16,2],[16,3],[28,2],[28,1],[29,1],[29,1],[29,1],[27,1],[27,1],[27,2],[31,2],[31,2],[31,1],[31,1],[30,2],[30,1],[19,2],[19,2],[19,2],[19,2],[19,2],[19,2],[19,9],[19,6],[19,4],[19,1],[9,1],[9,1],[9,1],[32,3],[32,4],[32,2],[32,1],[45,1],[45,5],[45,3],[46,4],[46,6],[46,4],[46,4],[46,4],[46,8],[46,4],[46,4],[46,4],[46,6],[46,4],[46,4],[46,4],[46,4],[46,4],[46,1],[44,2],[44,3],[44,3],[44,1],[44,3],[71,1],[72,3],[39,1],[39,2],[39,1],[78,1],[78,1],[78,1],[78,1],[78,1],[78,1],[78,1],[78,1],[78,1],[78,1],[78,1],[86,1],[86,2],[35,5],[35,5],[36,5],[37,2],[37,4],[37,3],[37,5],[37,2],[37,4],[37,4],[37,6],[37,2],[37,4],[37,2],[37,4],[37,4],[37,6],[33,5],[33,5],[34,5],[34,5],[34,9],[34,9],[34,7],[34,7],[96,1],[96,3],[89,1],[89,3],[100,1],[100,2],[101,1],[101,1],[101,1],[101,1],[101,1],[101,1],[101,1],[101,1],[101,1],[101,1],[101,1],[76,1],[76,1],[76,1],[76,1],[76,1],[76,1],[87,1],[87,1],[87,1],[87,1],[49,1],[49,2],[90,1],[90,2],[110,1],[110,1],[110,1],[110,1],[43,1],[43,1],[43,1],[43,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[108,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[109,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1],[121,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 5:r.parseDirective("%%{","open_directive");break;case 6:r.parseDirective(a[s],"type_directive");break;case 7:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 8:r.parseDirective("}%%","close_directive","flowchart");break;case 10:case 36:case 37:case 38:case 39:case 40:this.$=[];break;case 11:a[s]!==[]&&a[s-1].push(a[s]),this.$=a[s-1];break;case 12:case 78:case 80:case 92:case 148:case 150:case 151:case 74:case 146:this.$=a[s];break;case 19:r.setDirection("TB"),this.$="TB";break;case 20:r.setDirection(a[s-1]),this.$=a[s-1];break;case 35:this.$=a[s-1].nodes;break;case 41:this.$=r.addSubGraph(a[s-6],a[s-1],a[s-4]);break;case 42:this.$=r.addSubGraph(a[s-3],a[s-1],a[s-3]);break;case 43:this.$=r.addSubGraph(void 0,a[s-1],void 0);break;case 48:r.addLink(a[s-2].stmt,a[s],a[s-1]),this.$={stmt:a[s],nodes:a[s].concat(a[s-2].nodes)};break;case 49:r.addLink(a[s-3].stmt,a[s-1],a[s-2]),this.$={stmt:a[s-1],nodes:a[s-1].concat(a[s-3].nodes)};break;case 50:this.$={stmt:a[s-1],nodes:a[s-1]};break;case 51:this.$={stmt:a[s],nodes:a[s]};break;case 52:case 119:case 121:this.$=[a[s]];break;case 53:this.$=a[s-4].concat(a[s]);break;case 54:this.$=[a[s-2]],r.setClass(a[s-2],a[s]);break;case 55:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"square");break;case 56:this.$=a[s-5],r.addVertex(a[s-5],a[s-2],"circle");break;case 57:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"ellipse");break;case 58:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"stadium");break;case 59:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"subroutine");break;case 60:this.$=a[s-7],r.addVertex(a[s-7],a[s-1],"rect",void 0,void 0,void 0,Object.fromEntries([[a[s-5],a[s-3]]]));break;case 61:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"cylinder");break;case 62:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"round");break;case 63:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"diamond");break;case 64:this.$=a[s-5],r.addVertex(a[s-5],a[s-2],"hexagon");break;case 65:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"odd");break;case 66:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"trapezoid");break;case 67:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"inv_trapezoid");break;case 68:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"lean_right");break;case 69:this.$=a[s-3],r.addVertex(a[s-3],a[s-1],"lean_left");break;case 70:this.$=a[s],r.addVertex(a[s]);break;case 71:a[s-1].text=a[s],this.$=a[s-1];break;case 72:case 73:a[s-2].text=a[s-1],this.$=a[s-2];break;case 75:var c=r.destructLink(a[s],a[s-2]);this.$={type:c.type,stroke:c.stroke,length:c.length,text:a[s-1]};break;case 76:c=r.destructLink(a[s]),this.$={type:c.type,stroke:c.stroke,length:c.length};break;case 77:this.$=a[s-1];break;case 79:case 93:case 149:case 147:this.$=a[s-1]+""+a[s];break;case 94:case 95:this.$=a[s-4],r.addClass(a[s-2],a[s]);break;case 96:this.$=a[s-4],r.setClass(a[s-2],a[s]);break;case 97:case 105:this.$=a[s-1],r.setClickEvent(a[s-1],a[s]);break;case 98:case 106:this.$=a[s-3],r.setClickEvent(a[s-3],a[s-2]),r.setTooltip(a[s-3],a[s]);break;case 99:this.$=a[s-2],r.setClickEvent(a[s-2],a[s-1],a[s]);break;case 100:this.$=a[s-4],r.setClickEvent(a[s-4],a[s-3],a[s-2]),r.setTooltip(a[s-4],a[s]);break;case 101:case 107:this.$=a[s-1],r.setLink(a[s-1],a[s]);break;case 102:case 108:this.$=a[s-3],r.setLink(a[s-3],a[s-2]),r.setTooltip(a[s-3],a[s]);break;case 103:case 109:this.$=a[s-3],r.setLink(a[s-3],a[s-2],a[s]);break;case 104:case 110:this.$=a[s-5],r.setLink(a[s-5],a[s-4],a[s]),r.setTooltip(a[s-5],a[s-2]);break;case 111:this.$=a[s-4],r.addVertex(a[s-2],void 0,void 0,a[s]);break;case 112:case 114:this.$=a[s-4],r.updateLink(a[s-2],a[s]);break;case 113:this.$=a[s-4],r.updateLink([a[s-2]],a[s]);break;case 115:this.$=a[s-8],r.updateLinkInterpolate([a[s-6]],a[s-2]),r.updateLink([a[s-6]],a[s]);break;case 116:this.$=a[s-8],r.updateLinkInterpolate(a[s-6],a[s-2]),r.updateLink(a[s-6],a[s]);break;case 117:this.$=a[s-6],r.updateLinkInterpolate([a[s-4]],a[s]);break;case 118:this.$=a[s-6],r.updateLinkInterpolate(a[s-4],a[s]);break;case 120:case 122:a[s-2].push(a[s]),this.$=a[s-2];break;case 124:this.$=a[s-1]+a[s];break;case 152:this.$="v";break;case 153:this.$="-";break;case 154:this.$={stmt:"dir",value:"TB"};break;case 155:this.$={stmt:"dir",value:"BT"};break;case 156:this.$={stmt:"dir",value:"RL"};break;case 157:this.$={stmt:"dir",value:"LR"}}},table:[{3:1,4:2,5:3,6:5,12:e,16:4,21:n,22:r,24:i},{1:[3]},{1:[2,1]},{3:10,4:2,5:3,6:5,12:e,16:4,21:n,22:r,24:i},t(a,o,{17:11}),{7:12,13:[1,13]},{16:14,21:n,22:r,24:i},{16:15,21:n,22:r,24:i},{25:[1,16],26:[1,17]},{13:[2,5]},{1:[2,2]},{1:[2,9],18:18,19:19,20:s,21:c,22:u,23:l,32:24,33:25,34:26,35:27,36:28,37:29,38:h,43:31,45:32,46:42,47:f,49:43,59:d,60:p,79:y,80:g,81:m,82:v,83:b,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,111:S,112:A,113:M,114:N,115:D,116:O,117:B,118:L,119:I,120:R},{8:61,10:[1,62],15:F},t([10,15],[2,6]),t(a,[2,17]),t(a,[2,18]),t(a,[2,19]),{20:[1,65],21:[1,66],22:P,27:64,30:67},t(j,[2,11]),t(j,[2,12]),t(j,[2,13]),t(j,[2,14]),t(j,[2,15]),t(j,[2,16]),{9:69,20:Y,21:z,23:U,44:70,71:74,74:[1,75],75:[1,76]},{9:77,20:Y,21:z,23:U},{9:78,20:Y,21:z,23:U},{9:79,20:Y,21:z,23:U},{9:80,20:Y,21:z,23:U},{9:81,20:Y,21:z,23:U},{9:83,20:Y,21:z,22:[1,82],23:U},t(j,[2,44]),t(q,[2,51],{30:84,22:P}),{22:[1,85]},{22:[1,86]},{22:[1,87]},{22:[1,88]},{26:H,47:$,59:W,60:V,77:[1,92],84:G,90:91,91:[1,89],93:[1,90],98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(j,[2,154]),t(j,[2,155]),t(j,[2,156]),t(j,[2,157]),t(ot,[2,52],{48:[1,111]}),t(st,[2,70],{109:123,40:[1,112],47:f,50:[1,113],52:[1,114],54:[1,115],56:[1,116],58:[1,117],59:d,60:p,62:[1,118],64:[1,119],66:[1,120],67:[1,121],69:[1,122],84:_,88:x,98:w,99:k,102:T,104:E,105:C,115:D,116:O,117:B,118:L,119:I,120:R}),t(ct,[2,146]),t(ct,[2,171]),t(ct,[2,172]),t(ct,[2,173]),t(ct,[2,174]),t(ct,[2,175]),t(ct,[2,176]),t(ct,[2,177]),t(ct,[2,178]),t(ct,[2,179]),t(ct,[2,180]),t(ct,[2,181]),t(ct,[2,182]),t(ct,[2,183]),t(ct,[2,184]),t(ct,[2,185]),t(ct,[2,186]),{9:124,20:Y,21:z,23:U},{11:125,14:[1,126]},t(ut,[2,8]),t(a,[2,20]),t(a,[2,26]),t(a,[2,27]),{21:[1,127]},t(lt,[2,34],{30:128,22:P}),t(j,[2,35]),{45:129,46:42,47:f,49:43,59:d,60:p,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,115:D,116:O,117:B,118:L,119:I,120:R},t(ht,[2,45]),t(ht,[2,46]),t(ht,[2,47]),t(ft,[2,74],{72:130,61:[1,132],73:[1,131]}),{22:dt,24:pt,26:yt,38:gt,39:133,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t([47,59,60,61,73,84,88,98,99,102,104,105,115,116,117,118,119,120],[2,76]),t(j,[2,36]),t(j,[2,37]),t(j,[2,38]),t(j,[2,39]),t(j,[2,40]),{22:dt,24:pt,26:yt,38:gt,39:157,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(Ot,o,{17:158}),t(q,[2,50],{47:Bt}),{26:H,47:$,59:W,60:V,84:G,90:160,95:[1,161],98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},{88:[1,162],96:163,98:[1,164]},{26:H,47:$,59:W,60:V,84:G,88:[1,165],90:166,98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},{26:H,47:$,59:W,60:V,84:G,90:167,98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(ut,[2,97],{22:[1,168],92:[1,169]}),t(ut,[2,101],{22:[1,170]}),t(ut,[2,105],{108:95,110:172,22:[1,171],26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,115:tt,116:et,117:nt,118:rt,119:it,120:at}),t(ut,[2,107],{22:[1,173]}),t(Lt,[2,148]),t(Lt,[2,150]),t(Lt,[2,151]),t(Lt,[2,152]),t(Lt,[2,153]),t(It,[2,158]),t(It,[2,159]),t(It,[2,160]),t(It,[2,161]),t(It,[2,162]),t(It,[2,163]),t(It,[2,164]),t(It,[2,165]),t(It,[2,166]),t(It,[2,167]),t(It,[2,168]),t(It,[2,169]),t(It,[2,170]),{47:f,49:174,59:d,60:p,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,115:D,116:O,117:B,118:L,119:I,120:R},{22:dt,24:pt,26:yt,38:gt,39:175,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:177,42:mt,47:$,50:[1,176],59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:178,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:179,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:180,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{59:[1,181]},{22:dt,24:pt,26:yt,38:gt,39:182,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:183,42:mt,47:$,59:W,60:V,64:[1,184],66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:185,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:186,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:187,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(ct,[2,147]),t(Rt,[2,3]),{8:188,15:F},{15:[2,7]},t(a,[2,28]),t(lt,[2,33]),t(q,[2,48],{30:189,22:P}),t(ft,[2,71],{22:[1,190]}),{22:[1,191]},{22:dt,24:pt,26:yt,38:gt,39:192,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,66:vt,74:bt,75:[1,193],76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(It,[2,78]),t(It,[2,80]),t(It,[2,136]),t(It,[2,137]),t(It,[2,138]),t(It,[2,139]),t(It,[2,140]),t(It,[2,141]),t(It,[2,142]),t(It,[2,143]),t(It,[2,144]),t(It,[2,145]),t(It,[2,81]),t(It,[2,82]),t(It,[2,83]),t(It,[2,84]),t(It,[2,85]),t(It,[2,86]),t(It,[2,87]),t(It,[2,88]),t(It,[2,89]),t(It,[2,90]),t(It,[2,91]),{9:196,20:Y,21:z,22:dt,23:U,24:pt,26:yt,38:gt,40:[1,195],42:mt,47:$,59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{18:18,19:19,20:s,21:c,22:u,23:l,32:24,33:25,34:26,35:27,36:28,37:29,38:h,42:[1,197],43:31,45:32,46:42,47:f,49:43,59:d,60:p,79:y,80:g,81:m,82:v,83:b,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,111:S,112:A,113:M,114:N,115:D,116:O,117:B,118:L,119:I,120:R},{22:P,30:198},{22:[1,199],26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,108:95,110:172,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:[1,200]},{22:[1,201]},{22:[1,202],99:[1,203]},t(Ft,[2,119]),{22:[1,204]},{22:[1,205],26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,108:95,110:172,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:[1,206],26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,108:95,110:172,115:tt,116:et,117:nt,118:rt,119:it,120:at},{77:[1,207]},t(ut,[2,99],{22:[1,208]}),{77:[1,209],94:[1,210]},{77:[1,211]},t(Lt,[2,149]),{77:[1,212],94:[1,213]},t(ot,[2,54],{109:123,47:f,59:d,60:p,84:_,88:x,98:w,99:k,102:T,104:E,105:C,115:D,116:O,117:B,118:L,119:I,120:R}),{22:dt,24:pt,26:yt,38:gt,41:[1,214],42:mt,47:$,59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:215,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,51:[1,216],59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,53:[1,217],59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,55:[1,218],59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,57:[1,219],59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{60:[1,220]},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,63:[1,221],66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,65:[1,222],66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,39:223,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,41:[1,224],42:mt,47:$,59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,66:vt,68:[1,225],70:[1,226],74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,66:vt,68:[1,228],70:[1,227],74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{9:229,20:Y,21:z,23:U},t(q,[2,49],{47:Bt}),t(ft,[2,73]),t(ft,[2,72]),{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,61:[1,230],66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(ft,[2,75]),t(It,[2,79]),{22:dt,24:pt,26:yt,38:gt,39:231,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(Ot,o,{17:232}),t(j,[2,43]),{46:233,47:f,49:43,59:d,60:p,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,115:D,116:O,117:B,118:L,119:I,120:R},{22:Pt,59:jt,60:Yt,79:zt,89:234,95:Ut,98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{22:Pt,59:jt,60:Yt,79:zt,89:248,95:Ut,98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{22:Pt,59:jt,60:Yt,79:zt,89:249,95:Ut,97:[1,250],98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{22:Pt,59:jt,60:Yt,79:zt,89:251,95:Ut,97:[1,252],98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{98:[1,253]},{22:Pt,59:jt,60:Yt,79:zt,89:254,95:Ut,98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{22:Pt,59:jt,60:Yt,79:zt,89:255,95:Ut,98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{26:H,47:$,59:W,60:V,84:G,90:256,98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(ut,[2,98]),{77:[1,257]},t(ut,[2,102],{22:[1,258]}),t(ut,[2,103]),t(ut,[2,106]),t(ut,[2,108],{22:[1,259]}),t(ut,[2,109]),t(st,[2,55]),{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,51:[1,260],59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(st,[2,62]),t(st,[2,57]),t(st,[2,58]),t(st,[2,59]),{59:[1,261]},t(st,[2,61]),t(st,[2,63]),{22:dt,24:pt,26:yt,38:gt,42:mt,47:$,59:W,60:V,65:[1,262],66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(st,[2,65]),t(st,[2,66]),t(st,[2,68]),t(st,[2,67]),t(st,[2,69]),t(Rt,[2,4]),t([22,47,59,60,84,88,98,99,102,104,105,115,116,117,118,119,120],[2,77]),{22:dt,24:pt,26:yt,38:gt,41:[1,263],42:mt,47:$,59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{18:18,19:19,20:s,21:c,22:u,23:l,32:24,33:25,34:26,35:27,36:28,37:29,38:h,42:[1,264],43:31,45:32,46:42,47:f,49:43,59:d,60:p,79:y,80:g,81:m,82:v,83:b,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,111:S,112:A,113:M,114:N,115:D,116:O,117:B,118:L,119:I,120:R},t(ot,[2,53]),t(ut,[2,111],{99:Xt}),t(Zt,[2,121],{101:266,22:Pt,59:jt,60:Yt,79:zt,95:Ut,98:qt,102:Ht,103:$t,104:Wt,105:Vt,106:Gt}),t(Qt,[2,123]),t(Qt,[2,125]),t(Qt,[2,126]),t(Qt,[2,127]),t(Qt,[2,128]),t(Qt,[2,129]),t(Qt,[2,130]),t(Qt,[2,131]),t(Qt,[2,132]),t(Qt,[2,133]),t(Qt,[2,134]),t(Qt,[2,135]),t(ut,[2,112],{99:Xt}),t(ut,[2,113],{99:Xt}),{22:[1,267]},t(ut,[2,114],{99:Xt}),{22:[1,268]},t(Ft,[2,120]),t(ut,[2,94],{99:Xt}),t(ut,[2,95],{99:Xt}),t(ut,[2,96],{108:95,110:172,26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,115:tt,116:et,117:nt,118:rt,119:it,120:at}),t(ut,[2,100]),{94:[1,269]},{94:[1,270]},{51:[1,271]},{61:[1,272]},{65:[1,273]},{9:274,20:Y,21:z,23:U},t(j,[2,42]),{22:Pt,59:jt,60:Yt,79:zt,95:Ut,98:qt,100:275,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},t(Qt,[2,124]),{26:H,47:$,59:W,60:V,84:G,90:276,98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},{26:H,47:$,59:W,60:V,84:G,90:277,98:X,99:Z,102:Q,104:K,105:J,108:95,110:93,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(ut,[2,104]),t(ut,[2,110]),t(st,[2,56]),{22:dt,24:pt,26:yt,38:gt,39:278,42:mt,47:$,59:W,60:V,66:vt,74:bt,76:134,77:_t,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},t(st,[2,64]),t(Ot,o,{17:279}),t(Zt,[2,122],{101:266,22:Pt,59:jt,60:Yt,79:zt,95:Ut,98:qt,102:Ht,103:$t,104:Wt,105:Vt,106:Gt}),t(ut,[2,117],{108:95,110:172,22:[1,280],26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,115:tt,116:et,117:nt,118:rt,119:it,120:at}),t(ut,[2,118],{108:95,110:172,22:[1,281],26:H,47:$,59:W,60:V,84:G,98:X,99:Z,102:Q,104:K,105:J,115:tt,116:et,117:nt,118:rt,119:it,120:at}),{22:dt,24:pt,26:yt,38:gt,41:[1,282],42:mt,47:$,59:W,60:V,66:vt,74:bt,76:194,78:145,79:xt,80:wt,81:kt,82:Tt,83:Et,84:Ct,85:St,87:136,88:At,98:X,99:Z,102:Mt,104:K,105:J,106:Nt,107:Dt,108:142,115:tt,116:et,117:nt,118:rt,119:it,120:at},{18:18,19:19,20:s,21:c,22:u,23:l,32:24,33:25,34:26,35:27,36:28,37:29,38:h,42:[1,283],43:31,45:32,46:42,47:f,49:43,59:d,60:p,79:y,80:g,81:m,82:v,83:b,84:_,88:x,98:w,99:k,102:T,104:E,105:C,109:44,111:S,112:A,113:M,114:N,115:D,116:O,117:B,118:L,119:I,120:R},{22:Pt,59:jt,60:Yt,79:zt,89:284,95:Ut,98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},{22:Pt,59:jt,60:Yt,79:zt,89:285,95:Ut,98:qt,100:235,101:236,102:Ht,103:$t,104:Wt,105:Vt,106:Gt},t(st,[2,60]),t(j,[2,41]),t(ut,[2,115],{99:Xt}),t(ut,[2,116],{99:Xt})],defaultActions:{2:[2,1],9:[2,5],10:[2,2],126:[2,7]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},Jt={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),12;case 1:return this.begin("type_directive"),13;case 2:return this.popState(),this.begin("arg_directive"),10;case 3:return this.popState(),this.popState(),15;case 4:return 14;case 5:case 6:break;case 7:this.begin("string");break;case 8:case 17:case 20:case 23:case 26:this.popState();break;case 9:return"STR";case 10:return 79;case 11:return 88;case 12:return 80;case 13:return 97;case 14:return 81;case 15:return 82;case 16:this.begin("href");break;case 18:return 93;case 19:this.begin("callbackname");break;case 21:this.popState(),this.begin("callbackargs");break;case 22:return 91;case 24:return 92;case 25:this.begin("click");break;case 27:return 83;case 28:case 29:return t.lex.firstGraph()&&this.begin("dir"),24;case 30:return 38;case 31:return 42;case 32:case 33:case 34:case 35:return 94;case 36:return this.popState(),25;case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:return this.popState(),26;case 47:return 111;case 48:return 112;case 49:return 113;case 50:return 114;case 51:return 98;case 52:return 104;case 53:return 48;case 54:return 60;case 55:return 47;case 56:return 20;case 57:return 99;case 58:return 119;case 59:case 60:case 61:return 75;case 62:case 63:case 64:return 74;case 65:return 52;case 66:return 53;case 67:return 54;case 68:return 55;case 69:return 56;case 70:return 57;case 71:return 58;case 72:return 62;case 73:return 63;case 74:return 102;case 75:return 105;case 76:return 120;case 77:return 117;case 78:return 106;case 79:case 80:return 118;case 81:return 107;case 82:return 66;case 83:return 85;case 84:return"SEP";case 85:return 84;case 86:return 59;case 87:return 68;case 88:return 67;case 89:return 70;case 90:return 69;case 91:return 115;case 92:return 116;case 93:return 61;case 94:return 50;case 95:return 51;case 96:return 40;case 97:return 41;case 98:return 64;case 99:return 65;case 100:return 126;case 101:return 21;case 102:return 22;case 103:return 23}},rules:[/^(?:%%\{)/,/^(?:((?:(?!\}%%)[^:.])*))/,/^(?::)/,/^(?:\}%%)/,/^(?:((?:(?!\}%%).|\n)*))/,/^(?:%%(?!\{)[^\n]*)/,/^(?:[^\}]%%[^\n]*)/,/^(?:["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:style\b)/,/^(?:default\b)/,/^(?:linkStyle\b)/,/^(?:interpolate\b)/,/^(?:classDef\b)/,/^(?:class\b)/,/^(?:href[\s]+["])/,/^(?:["])/,/^(?:[^"]*)/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:click[\s]+)/,/^(?:[\s\n])/,/^(?:[^\s\n]*)/,/^(?:graph\b)/,/^(?:flowchart\b)/,/^(?:subgraph\b)/,/^(?:end\b\s*)/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:(\r?\n)*\s*\n)/,/^(?:\s*LR\b)/,/^(?:\s*RL\b)/,/^(?:\s*TB\b)/,/^(?:\s*BT\b)/,/^(?:\s*TD\b)/,/^(?:\s*BR\b)/,/^(?:\s*<)/,/^(?:\s*>)/,/^(?:\s*\^)/,/^(?:\s*v\b)/,/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:[0-9]+)/,/^(?:#)/,/^(?::::)/,/^(?::)/,/^(?:&)/,/^(?:;)/,/^(?:,)/,/^(?:\*)/,/^(?:\s*[xo<]?--+[-xo>]\s*)/,/^(?:\s*[xo<]?==+[=xo>]\s*)/,/^(?:\s*[xo<]?-?\.+-[xo>]?\s*)/,/^(?:\s*[xo<]?--\s*)/,/^(?:\s*[xo<]?==\s*)/,/^(?:\s*[xo<]?-\.\s*)/,/^(?:\(-)/,/^(?:-\))/,/^(?:\(\[)/,/^(?:\]\))/,/^(?:\[\[)/,/^(?:\]\])/,/^(?:\[\|)/,/^(?:\[\()/,/^(?:\)\])/,/^(?:-)/,/^(?:\.)/,/^(?:[\_])/,/^(?:\+)/,/^(?:%)/,/^(?:=)/,/^(?:=)/,/^(?:<)/,/^(?:>)/,/^(?:\^)/,/^(?:\\\|)/,/^(?:v\b)/,/^(?:[A-Za-z]+)/,/^(?:\\\])/,/^(?:\[\/)/,/^(?:\/\])/,/^(?:\[\\)/,/^(?:[!"#$%&'*+,-.`?\\_/])/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE]|[\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA]|[\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0]|[\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977]|[\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2]|[\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A]|[\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39]|[\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8]|[\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C]|[\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C]|[\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99]|[\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0]|[\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D]|[\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3]|[\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10]|[\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1]|[\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81]|[\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3]|[\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6]|[\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A]|[\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081]|[\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D]|[\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0]|[\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310]|[\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C]|[\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711]|[\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7]|[\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C]|[\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16]|[\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF]|[\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC]|[\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D]|[\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D]|[\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3]|[\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F]|[\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128]|[\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184]|[\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3]|[\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6]|[\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE]|[\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C]|[\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D]|[\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC]|[\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B]|[\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788]|[\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805]|[\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB]|[\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28]|[\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5]|[\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4]|[\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E]|[\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D]|[\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36]|[\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D]|[\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC]|[\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF]|[\uFFD2-\uFFD7\uFFDA-\uFFDC])/,/^(?:\|)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\{)/,/^(?:\})/,/^(?:")/,/^(?:(\r?\n)+)/,/^(?:\s)/,/^(?:$)/],conditions:{close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},callbackargs:{rules:[23,24],inclusive:!1},callbackname:{rules:[20,21,22],inclusive:!1},href:{rules:[17,18],inclusive:!1},click:{rules:[26,27],inclusive:!1},vertex:{rules:[],inclusive:!1},dir:{rules:[36,37,38,39,40,41,42,43,44,45,46],inclusive:!1},string:{rules:[8,9],inclusive:!1},INITIAL:{rules:[0,5,6,7,10,11,12,13,14,15,16,19,25,28,29,30,31,32,33,34,35,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103],inclusive:!0}}};function te(){this.yy={}}return Kt.lexer=Jt,te.prototype=Kt,Kt.Parser=te,new te}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(5354).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},9959:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,3],n=[1,5],r=[7,9,11,12,13,14,15,16,17,18,19,20,22,29,34],i=[1,15],a=[1,16],o=[1,17],s=[1,18],c=[1,19],u=[1,20],l=[1,21],h=[1,22],f=[1,23],d=[1,25],p=[1,27],y=[1,30],g=[5,7,9,11,12,13,14,15,16,17,18,19,20,22,29,34],m={trace:function(){},yy:{},symbols_:{error:2,start:3,directive:4,gantt:5,document:6,EOF:7,line:8,SPACE:9,statement:10,NL:11,dateFormat:12,inclusiveEndDates:13,topAxis:14,axisFormat:15,excludes:16,includes:17,todayMarker:18,title:19,section:20,clickStatement:21,taskTxt:22,taskData:23,openDirective:24,typeDirective:25,closeDirective:26,":":27,argDirective:28,click:29,callbackname:30,callbackargs:31,href:32,clickStatementDebug:33,open_directive:34,type_directive:35,arg_directive:36,close_directive:37,$accept:0,$end:1},terminals_:{2:"error",5:"gantt",7:"EOF",9:"SPACE",11:"NL",12:"dateFormat",13:"inclusiveEndDates",14:"topAxis",15:"axisFormat",16:"excludes",17:"includes",18:"todayMarker",19:"title",20:"section",22:"taskTxt",23:"taskData",27:":",29:"click",30:"callbackname",31:"callbackargs",32:"href",34:"open_directive",35:"type_directive",36:"arg_directive",37:"close_directive"},productions_:[0,[3,2],[3,3],[6,0],[6,2],[8,2],[8,1],[8,1],[8,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,2],[10,1],[4,4],[4,6],[21,2],[21,3],[21,3],[21,4],[21,3],[21,4],[21,2],[33,2],[33,3],[33,3],[33,4],[33,3],[33,4],[33,2],[24,1],[25,1],[28,1],[26,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 2:return a[s-1];case 3:case 7:case 8:this.$=[];break;case 4:a[s-1].push(a[s]),this.$=a[s-1];break;case 5:case 6:this.$=a[s];break;case 9:r.setDateFormat(a[s].substr(11)),this.$=a[s].substr(11);break;case 10:r.enableInclusiveEndDates(),this.$=a[s].substr(18);break;case 11:r.TopAxis(),this.$=a[s].substr(8);break;case 12:r.setAxisFormat(a[s].substr(11)),this.$=a[s].substr(11);break;case 13:r.setExcludes(a[s].substr(9)),this.$=a[s].substr(9);break;case 14:r.setIncludes(a[s].substr(9)),this.$=a[s].substr(9);break;case 15:r.setTodayMarker(a[s].substr(12)),this.$=a[s].substr(12);break;case 16:r.setTitle(a[s].substr(6)),this.$=a[s].substr(6);break;case 17:r.addSection(a[s].substr(8)),this.$=a[s].substr(8);break;case 19:r.addTask(a[s-1],a[s]),this.$="task";break;case 23:this.$=a[s-1],r.setClickEvent(a[s-1],a[s],null);break;case 24:this.$=a[s-2],r.setClickEvent(a[s-2],a[s-1],a[s]);break;case 25:this.$=a[s-2],r.setClickEvent(a[s-2],a[s-1],null),r.setLink(a[s-2],a[s]);break;case 26:this.$=a[s-3],r.setClickEvent(a[s-3],a[s-2],a[s-1]),r.setLink(a[s-3],a[s]);break;case 27:this.$=a[s-2],r.setClickEvent(a[s-2],a[s],null),r.setLink(a[s-2],a[s-1]);break;case 28:this.$=a[s-3],r.setClickEvent(a[s-3],a[s-1],a[s]),r.setLink(a[s-3],a[s-2]);break;case 29:this.$=a[s-1],r.setLink(a[s-1],a[s]);break;case 30:case 36:this.$=a[s-1]+" "+a[s];break;case 31:case 32:case 34:this.$=a[s-2]+" "+a[s-1]+" "+a[s];break;case 33:case 35:this.$=a[s-3]+" "+a[s-2]+" "+a[s-1]+" "+a[s];break;case 37:r.parseDirective("%%{","open_directive");break;case 38:r.parseDirective(a[s],"type_directive");break;case 39:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 40:r.parseDirective("}%%","close_directive","gantt")}},table:[{3:1,4:2,5:e,24:4,34:n},{1:[3]},{3:6,4:2,5:e,24:4,34:n},t(r,[2,3],{6:7}),{25:8,35:[1,9]},{35:[2,37]},{1:[2,1]},{4:26,7:[1,10],8:11,9:[1,12],10:13,11:[1,14],12:i,13:a,14:o,15:s,16:c,17:u,18:l,19:h,20:f,21:24,22:d,24:4,29:p,34:n},{26:28,27:[1,29],37:y},t([27,37],[2,38]),t(r,[2,8],{1:[2,2]}),t(r,[2,4]),{4:26,10:31,12:i,13:a,14:o,15:s,16:c,17:u,18:l,19:h,20:f,21:24,22:d,24:4,29:p,34:n},t(r,[2,6]),t(r,[2,7]),t(r,[2,9]),t(r,[2,10]),t(r,[2,11]),t(r,[2,12]),t(r,[2,13]),t(r,[2,14]),t(r,[2,15]),t(r,[2,16]),t(r,[2,17]),t(r,[2,18]),{23:[1,32]},t(r,[2,20]),{30:[1,33],32:[1,34]},{11:[1,35]},{28:36,36:[1,37]},{11:[2,40]},t(r,[2,5]),t(r,[2,19]),t(r,[2,23],{31:[1,38],32:[1,39]}),t(r,[2,29],{30:[1,40]}),t(g,[2,21]),{26:41,37:y},{37:[2,39]},t(r,[2,24],{32:[1,42]}),t(r,[2,25]),t(r,[2,27],{31:[1,43]}),{11:[1,44]},t(r,[2,26]),t(r,[2,28]),t(g,[2,22])],defaultActions:{5:[2,37],6:[2,1],30:[2,40],37:[2,39]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},v={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),34;case 1:return this.begin("type_directive"),35;case 2:return this.popState(),this.begin("arg_directive"),27;case 3:return this.popState(),this.popState(),37;case 4:return 36;case 5:case 6:case 7:case 9:case 10:case 11:break;case 8:return 11;case 12:this.begin("href");break;case 13:case 16:case 19:case 22:this.popState();break;case 14:return 32;case 15:this.begin("callbackname");break;case 17:this.popState(),this.begin("callbackargs");break;case 18:return 30;case 20:return 31;case 21:this.begin("click");break;case 23:return 29;case 24:return 5;case 25:return 12;case 26:return 13;case 27:return 14;case 28:return 15;case 29:return 17;case 30:return 16;case 31:return 18;case 32:return"date";case 33:return 19;case 34:return 20;case 35:return 22;case 36:return 23;case 37:return 27;case 38:return 7;case 39:return"INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%%(?!\{)*[^\n]*)/i,/^(?:[^\}]%%*[^\n]*)/i,/^(?:%%*[^\n]*[\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:href[\s]+["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:call[\s]+)/i,/^(?:\([\s]*\))/i,/^(?:\()/i,/^(?:[^(]*)/i,/^(?:\))/i,/^(?:[^)]*)/i,/^(?:click[\s]+)/i,/^(?:[\s\n])/i,/^(?:[^\s\n]*)/i,/^(?:gantt\b)/i,/^(?:dateFormat\s[^#\n;]+)/i,/^(?:inclusiveEndDates\b)/i,/^(?:topAxis\b)/i,/^(?:axisFormat\s[^#\n;]+)/i,/^(?:includes\s[^#\n;]+)/i,/^(?:excludes\s[^#\n;]+)/i,/^(?:todayMarker\s[^\n;]+)/i,/^(?:\d\d\d\d-\d\d-\d\d\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},callbackargs:{rules:[19,20],inclusive:!1},callbackname:{rules:[16,17,18],inclusive:!1},href:{rules:[13,14],inclusive:!1},click:{rules:[22,23],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,12,15,21,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39],inclusive:!0}}};function b(){this.yy={}}return m.lexer=v,b.prototype=m,m.Parser=b,new b}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(6878).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},2553:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[2,3],n=[1,7],r=[7,12,15,17,19,20,21],i=[7,11,12,15,17,19,20,21],a=[2,20],o=[1,32],s={trace:function(){},yy:{},symbols_:{error:2,start:3,GG:4,":":5,document:6,EOF:7,DIR:8,options:9,body:10,OPT:11,NL:12,line:13,statement:14,COMMIT:15,commit_arg:16,BRANCH:17,ID:18,CHECKOUT:19,MERGE:20,RESET:21,reset_arg:22,STR:23,HEAD:24,reset_parents:25,CARET:26,$accept:0,$end:1},terminals_:{2:"error",4:"GG",5:":",7:"EOF",8:"DIR",11:"OPT",12:"NL",15:"COMMIT",17:"BRANCH",18:"ID",19:"CHECKOUT",20:"MERGE",21:"RESET",23:"STR",24:"HEAD",26:"CARET"},productions_:[0,[3,4],[3,5],[6,0],[6,2],[9,2],[9,1],[10,0],[10,2],[13,2],[13,1],[14,2],[14,2],[14,2],[14,2],[14,2],[16,0],[16,1],[22,2],[22,2],[25,0],[25,2]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 1:return a[s-1];case 2:return r.setDirection(a[s-3]),a[s-1];case 4:r.setOptions(a[s-1]),this.$=a[s];break;case 5:a[s-1]+=a[s],this.$=a[s-1];break;case 7:this.$=[];break;case 8:a[s-1].push(a[s]),this.$=a[s-1];break;case 9:this.$=a[s-1];break;case 11:r.commit(a[s]);break;case 12:r.branch(a[s]);break;case 13:r.checkout(a[s]);break;case 14:r.merge(a[s]);break;case 15:r.reset(a[s]);break;case 16:this.$="";break;case 17:this.$=a[s];break;case 18:this.$=a[s-1]+":"+a[s];break;case 19:this.$=a[s-1]+":"+r.count,r.count=0;break;case 20:r.count=0;break;case 21:r.count+=1}},table:[{3:1,4:[1,2]},{1:[3]},{5:[1,3],8:[1,4]},{6:5,7:e,9:6,12:n},{5:[1,8]},{7:[1,9]},t(r,[2,7],{10:10,11:[1,11]}),t(i,[2,6]),{6:12,7:e,9:6,12:n},{1:[2,1]},{7:[2,4],12:[1,15],13:13,14:14,15:[1,16],17:[1,17],19:[1,18],20:[1,19],21:[1,20]},t(i,[2,5]),{7:[1,21]},t(r,[2,8]),{12:[1,22]},t(r,[2,10]),{12:[2,16],16:23,23:[1,24]},{18:[1,25]},{18:[1,26]},{18:[1,27]},{18:[1,30],22:28,24:[1,29]},{1:[2,2]},t(r,[2,9]),{12:[2,11]},{12:[2,17]},{12:[2,12]},{12:[2,13]},{12:[2,14]},{12:[2,15]},{12:a,25:31,26:o},{12:a,25:33,26:o},{12:[2,18]},{12:a,25:34,26:o},{12:[2,19]},{12:[2,21]}],defaultActions:{9:[2,1],21:[2,2],23:[2,11],24:[2,17],25:[2,12],26:[2,13],27:[2,14],28:[2,15],31:[2,18],33:[2,19],34:[2,21]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},c={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return 12;case 1:case 2:case 3:break;case 4:return 4;case 5:return 15;case 6:return 17;case 7:return 20;case 8:return 21;case 9:return 19;case 10:case 11:return 8;case 12:return 5;case 13:return 26;case 14:this.begin("options");break;case 15:case 18:this.popState();break;case 16:return 11;case 17:this.begin("string");break;case 19:return 23;case 20:return 18;case 21:return 7}},rules:[/^(?:(\r?\n)+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:gitGraph\b)/i,/^(?:commit\b)/i,/^(?:branch\b)/i,/^(?:merge\b)/i,/^(?:reset\b)/i,/^(?:checkout\b)/i,/^(?:LR\b)/i,/^(?:BT\b)/i,/^(?::)/i,/^(?:\^)/i,/^(?:options\r?\n)/i,/^(?:end\r?\n)/i,/^(?:[^\n]+\r?\n)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[a-zA-Z][-_\.a-zA-Z0-9]*[-_a-zA-Z0-9])/i,/^(?:$)/i],conditions:{options:{rules:[15,16],inclusive:!1},string:{rules:[18,19],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,17,20,21],inclusive:!0}}};function u(){this.yy={}}return s.lexer=c,u.prototype=s,s.Parser=u,new u}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(8183).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},6765:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[6,9,10],n={trace:function(){},yy:{},symbols_:{error:2,start:3,info:4,document:5,EOF:6,line:7,statement:8,NL:9,showInfo:10,$accept:0,$end:1},terminals_:{2:"error",4:"info",6:"EOF",9:"NL",10:"showInfo"},productions_:[0,[3,3],[5,0],[5,2],[7,1],[7,1],[8,1]],performAction:function(t,e,n,r,i,a,o){switch(a.length,i){case 1:return r;case 4:break;case 6:r.setInfo(!0)}},table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:6,9:[1,7],10:[1,8]},{1:[2,1]},t(e,[2,3]),t(e,[2,4]),t(e,[2,5]),t(e,[2,6])],defaultActions:{4:[2,1]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},r={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return 4;case 1:return 9;case 2:return"space";case 3:return 10;case 4:return 6;case 5:return"TXT"}},rules:[/^(?:info\b)/i,/^(?:[\s\n\r]+)/i,/^(?:[\s]+)/i,/^(?:showInfo\b)/i,/^(?:$)/i,/^(?:.)/i],conditions:{INITIAL:{rules:[0,1,2,3,4,5],inclusive:!0}}};function i(){this.yy={}}return n.lexer=r,i.prototype=n,n.Parser=i,new i}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(1428).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},7062:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,4],n=[1,5],r=[1,6],i=[1,7],a=[1,9],o=[1,11,13,20,21,22,23],s=[2,5],c=[1,6,11,13,20,21,22,23],u=[20,21,22],l=[2,8],h=[1,18],f=[1,19],d=[1,24],p=[6,20,21,22,23],y={trace:function(){},yy:{},symbols_:{error:2,start:3,eol:4,directive:5,PIE:6,document:7,showData:8,line:9,statement:10,txt:11,value:12,title:13,title_value:14,openDirective:15,typeDirective:16,closeDirective:17,":":18,argDirective:19,NEWLINE:20,";":21,EOF:22,open_directive:23,type_directive:24,arg_directive:25,close_directive:26,$accept:0,$end:1},terminals_:{2:"error",6:"PIE",8:"showData",11:"txt",12:"value",13:"title",14:"title_value",18:":",20:"NEWLINE",21:";",22:"EOF",23:"open_directive",24:"type_directive",25:"arg_directive",26:"close_directive"},productions_:[0,[3,2],[3,2],[3,2],[3,3],[7,0],[7,2],[9,2],[10,0],[10,2],[10,2],[10,1],[5,3],[5,5],[4,1],[4,1],[4,1],[15,1],[16,1],[19,1],[17,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:r.setShowData(!0);break;case 7:this.$=a[s-1];break;case 9:r.addSection(a[s-1],r.cleanupValue(a[s]));break;case 10:this.$=a[s].trim(),r.setTitle(this.$);break;case 17:r.parseDirective("%%{","open_directive");break;case 18:r.parseDirective(a[s],"type_directive");break;case 19:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 20:r.parseDirective("}%%","close_directive","pie")}},table:[{3:1,4:2,5:3,6:e,15:8,20:n,21:r,22:i,23:a},{1:[3]},{3:10,4:2,5:3,6:e,15:8,20:n,21:r,22:i,23:a},{3:11,4:2,5:3,6:e,15:8,20:n,21:r,22:i,23:a},t(o,s,{7:12,8:[1,13]}),t(c,[2,14]),t(c,[2,15]),t(c,[2,16]),{16:14,24:[1,15]},{24:[2,17]},{1:[2,1]},{1:[2,2]},t(u,l,{15:8,9:16,10:17,5:20,1:[2,3],11:h,13:f,23:a}),t(o,s,{7:21}),{17:22,18:[1,23],26:d},t([18,26],[2,18]),t(o,[2,6]),{4:25,20:n,21:r,22:i},{12:[1,26]},{14:[1,27]},t(u,[2,11]),t(u,l,{15:8,9:16,10:17,5:20,1:[2,4],11:h,13:f,23:a}),t(p,[2,12]),{19:28,25:[1,29]},t(p,[2,20]),t(o,[2,7]),t(u,[2,9]),t(u,[2,10]),{17:30,26:d},{26:[2,19]},t(p,[2,13])],defaultActions:{9:[2,17],10:[2,1],11:[2,2],29:[2,19]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},g={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),23;case 1:return this.begin("type_directive"),24;case 2:return this.popState(),this.begin("arg_directive"),18;case 3:return this.popState(),this.popState(),26;case 4:return 25;case 5:case 6:case 8:case 9:break;case 7:return 20;case 10:return this.begin("title"),13;case 11:return this.popState(),"title_value";case 12:this.begin("string");break;case 13:this.popState();break;case 14:return"txt";case 15:return 6;case 16:return 8;case 17:return"value";case 18:return 22}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n\r]+)/i,/^(?:%%[^\n]*)/i,/^(?:[\s]+)/i,/^(?:title\b)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:pie\b)/i,/^(?:showData\b)/i,/^(?::[\s]*[\d]+(?:\.[\d]+)?)/i,/^(?:$)/i],conditions:{close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},title:{rules:[11],inclusive:!1},string:{rules:[13,14],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,12,15,16,17,18],inclusive:!0}}};function m(){this.yy={}}return y.lexer=g,m.prototype=y,y.Parser=m,new m}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(4551).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},3176:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,3],n=[1,5],r=[1,17],i=[2,10],a=[1,21],o=[1,22],s=[1,23],c=[1,24],u=[1,25],l=[1,26],h=[1,19],f=[1,27],d=[1,28],p=[1,31],y=[66,67],g=[5,8,14,35,36,37,38,39,40,48,55,57,66,67],m=[5,6,8,14,35,36,37,38,39,40,48,66,67],v=[1,51],b=[1,52],_=[1,53],x=[1,54],w=[1,55],k=[1,56],T=[1,57],E=[57,58],C=[1,69],S=[1,65],A=[1,66],M=[1,67],N=[1,68],D=[1,70],O=[1,74],B=[1,75],L=[1,72],I=[1,73],R=[5,8,14,35,36,37,38,39,40,48,66,67],F={trace:function(){},yy:{},symbols_:{error:2,start:3,directive:4,NEWLINE:5,RD:6,diagram:7,EOF:8,openDirective:9,typeDirective:10,closeDirective:11,":":12,argDirective:13,open_directive:14,type_directive:15,arg_directive:16,close_directive:17,requirementDef:18,elementDef:19,relationshipDef:20,requirementType:21,requirementName:22,STRUCT_START:23,requirementBody:24,ID:25,COLONSEP:26,id:27,TEXT:28,text:29,RISK:30,riskLevel:31,VERIFYMTHD:32,verifyType:33,STRUCT_STOP:34,REQUIREMENT:35,FUNCTIONAL_REQUIREMENT:36,INTERFACE_REQUIREMENT:37,PERFORMANCE_REQUIREMENT:38,PHYSICAL_REQUIREMENT:39,DESIGN_CONSTRAINT:40,LOW_RISK:41,MED_RISK:42,HIGH_RISK:43,VERIFY_ANALYSIS:44,VERIFY_DEMONSTRATION:45,VERIFY_INSPECTION:46,VERIFY_TEST:47,ELEMENT:48,elementName:49,elementBody:50,TYPE:51,type:52,DOCREF:53,ref:54,END_ARROW_L:55,relationship:56,LINE:57,END_ARROW_R:58,CONTAINS:59,COPIES:60,DERIVES:61,SATISFIES:62,VERIFIES:63,REFINES:64,TRACES:65,unqString:66,qString:67,$accept:0,$end:1},terminals_:{2:"error",5:"NEWLINE",6:"RD",8:"EOF",12:":",14:"open_directive",15:"type_directive",16:"arg_directive",17:"close_directive",23:"STRUCT_START",25:"ID",26:"COLONSEP",28:"TEXT",30:"RISK",32:"VERIFYMTHD",34:"STRUCT_STOP",35:"REQUIREMENT",36:"FUNCTIONAL_REQUIREMENT",37:"INTERFACE_REQUIREMENT",38:"PERFORMANCE_REQUIREMENT",39:"PHYSICAL_REQUIREMENT",40:"DESIGN_CONSTRAINT",41:"LOW_RISK",42:"MED_RISK",43:"HIGH_RISK",44:"VERIFY_ANALYSIS",45:"VERIFY_DEMONSTRATION",46:"VERIFY_INSPECTION",47:"VERIFY_TEST",48:"ELEMENT",51:"TYPE",53:"DOCREF",55:"END_ARROW_L",57:"LINE",58:"END_ARROW_R",59:"CONTAINS",60:"COPIES",61:"DERIVES",62:"SATISFIES",63:"VERIFIES",64:"REFINES",65:"TRACES",66:"unqString",67:"qString"},productions_:[0,[3,3],[3,2],[3,4],[4,3],[4,5],[9,1],[10,1],[13,1],[11,1],[7,0],[7,2],[7,2],[7,2],[7,2],[7,2],[18,5],[24,5],[24,5],[24,5],[24,5],[24,2],[24,1],[21,1],[21,1],[21,1],[21,1],[21,1],[21,1],[31,1],[31,1],[31,1],[33,1],[33,1],[33,1],[33,1],[19,5],[50,5],[50,5],[50,2],[50,1],[20,5],[20,5],[56,1],[56,1],[56,1],[56,1],[56,1],[56,1],[56,1],[22,1],[22,1],[27,1],[27,1],[29,1],[29,1],[49,1],[49,1],[52,1],[52,1],[54,1],[54,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 6:r.parseDirective("%%{","open_directive");break;case 7:r.parseDirective(a[s],"type_directive");break;case 8:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 9:r.parseDirective("}%%","close_directive","pie");break;case 10:this.$=[];break;case 16:r.addRequirement(a[s-3],a[s-4]);break;case 17:r.setNewReqId(a[s-2]);break;case 18:r.setNewReqText(a[s-2]);break;case 19:r.setNewReqRisk(a[s-2]);break;case 20:r.setNewReqVerifyMethod(a[s-2]);break;case 23:this.$=r.RequirementType.REQUIREMENT;break;case 24:this.$=r.RequirementType.FUNCTIONAL_REQUIREMENT;break;case 25:this.$=r.RequirementType.INTERFACE_REQUIREMENT;break;case 26:this.$=r.RequirementType.PERFORMANCE_REQUIREMENT;break;case 27:this.$=r.RequirementType.PHYSICAL_REQUIREMENT;break;case 28:this.$=r.RequirementType.DESIGN_CONSTRAINT;break;case 29:this.$=r.RiskLevel.LOW_RISK;break;case 30:this.$=r.RiskLevel.MED_RISK;break;case 31:this.$=r.RiskLevel.HIGH_RISK;break;case 32:this.$=r.VerifyType.VERIFY_ANALYSIS;break;case 33:this.$=r.VerifyType.VERIFY_DEMONSTRATION;break;case 34:this.$=r.VerifyType.VERIFY_INSPECTION;break;case 35:this.$=r.VerifyType.VERIFY_TEST;break;case 36:r.addElement(a[s-3]);break;case 37:r.setNewElementType(a[s-2]);break;case 38:r.setNewElementDocRef(a[s-2]);break;case 41:r.addRelationship(a[s-2],a[s],a[s-4]);break;case 42:r.addRelationship(a[s-2],a[s-4],a[s]);break;case 43:this.$=r.Relationships.CONTAINS;break;case 44:this.$=r.Relationships.COPIES;break;case 45:this.$=r.Relationships.DERIVES;break;case 46:this.$=r.Relationships.SATISFIES;break;case 47:this.$=r.Relationships.VERIFIES;break;case 48:this.$=r.Relationships.REFINES;break;case 49:this.$=r.Relationships.TRACES}},table:[{3:1,4:2,6:e,9:4,14:n},{1:[3]},{3:7,4:2,5:[1,6],6:e,9:4,14:n},{5:[1,8]},{10:9,15:[1,10]},{15:[2,6]},{3:11,4:2,6:e,9:4,14:n},{1:[2,2]},{4:16,5:r,7:12,8:i,9:4,14:n,18:13,19:14,20:15,21:18,27:20,35:a,36:o,37:s,38:c,39:u,40:l,48:h,66:f,67:d},{11:29,12:[1,30],17:p},t([12,17],[2,7]),{1:[2,1]},{8:[1,32]},{4:16,5:r,7:33,8:i,9:4,14:n,18:13,19:14,20:15,21:18,27:20,35:a,36:o,37:s,38:c,39:u,40:l,48:h,66:f,67:d},{4:16,5:r,7:34,8:i,9:4,14:n,18:13,19:14,20:15,21:18,27:20,35:a,36:o,37:s,38:c,39:u,40:l,48:h,66:f,67:d},{4:16,5:r,7:35,8:i,9:4,14:n,18:13,19:14,20:15,21:18,27:20,35:a,36:o,37:s,38:c,39:u,40:l,48:h,66:f,67:d},{4:16,5:r,7:36,8:i,9:4,14:n,18:13,19:14,20:15,21:18,27:20,35:a,36:o,37:s,38:c,39:u,40:l,48:h,66:f,67:d},{4:16,5:r,7:37,8:i,9:4,14:n,18:13,19:14,20:15,21:18,27:20,35:a,36:o,37:s,38:c,39:u,40:l,48:h,66:f,67:d},{22:38,66:[1,39],67:[1,40]},{49:41,66:[1,42],67:[1,43]},{55:[1,44],57:[1,45]},t(y,[2,23]),t(y,[2,24]),t(y,[2,25]),t(y,[2,26]),t(y,[2,27]),t(y,[2,28]),t(g,[2,52]),t(g,[2,53]),t(m,[2,4]),{13:46,16:[1,47]},t(m,[2,9]),{1:[2,3]},{8:[2,11]},{8:[2,12]},{8:[2,13]},{8:[2,14]},{8:[2,15]},{23:[1,48]},{23:[2,50]},{23:[2,51]},{23:[1,49]},{23:[2,56]},{23:[2,57]},{56:50,59:v,60:b,61:_,62:x,63:w,64:k,65:T},{56:58,59:v,60:b,61:_,62:x,63:w,64:k,65:T},{11:59,17:p},{17:[2,8]},{5:[1,60]},{5:[1,61]},{57:[1,62]},t(E,[2,43]),t(E,[2,44]),t(E,[2,45]),t(E,[2,46]),t(E,[2,47]),t(E,[2,48]),t(E,[2,49]),{58:[1,63]},t(m,[2,5]),{5:C,24:64,25:S,28:A,30:M,32:N,34:D},{5:O,34:B,50:71,51:L,53:I},{27:76,66:f,67:d},{27:77,66:f,67:d},t(R,[2,16]),{26:[1,78]},{26:[1,79]},{26:[1,80]},{26:[1,81]},{5:C,24:82,25:S,28:A,30:M,32:N,34:D},t(R,[2,22]),t(R,[2,36]),{26:[1,83]},{26:[1,84]},{5:O,34:B,50:85,51:L,53:I},t(R,[2,40]),t(R,[2,41]),t(R,[2,42]),{27:86,66:f,67:d},{29:87,66:[1,88],67:[1,89]},{31:90,41:[1,91],42:[1,92],43:[1,93]},{33:94,44:[1,95],45:[1,96],46:[1,97],47:[1,98]},t(R,[2,21]),{52:99,66:[1,100],67:[1,101]},{54:102,66:[1,103],67:[1,104]},t(R,[2,39]),{5:[1,105]},{5:[1,106]},{5:[2,54]},{5:[2,55]},{5:[1,107]},{5:[2,29]},{5:[2,30]},{5:[2,31]},{5:[1,108]},{5:[2,32]},{5:[2,33]},{5:[2,34]},{5:[2,35]},{5:[1,109]},{5:[2,58]},{5:[2,59]},{5:[1,110]},{5:[2,60]},{5:[2,61]},{5:C,24:111,25:S,28:A,30:M,32:N,34:D},{5:C,24:112,25:S,28:A,30:M,32:N,34:D},{5:C,24:113,25:S,28:A,30:M,32:N,34:D},{5:C,24:114,25:S,28:A,30:M,32:N,34:D},{5:O,34:B,50:115,51:L,53:I},{5:O,34:B,50:116,51:L,53:I},t(R,[2,17]),t(R,[2,18]),t(R,[2,19]),t(R,[2,20]),t(R,[2,37]),t(R,[2,38])],defaultActions:{5:[2,6],7:[2,2],11:[2,1],32:[2,3],33:[2,11],34:[2,12],35:[2,13],36:[2,14],37:[2,15],39:[2,50],40:[2,51],42:[2,56],43:[2,57],47:[2,8],88:[2,54],89:[2,55],91:[2,29],92:[2,30],93:[2,31],95:[2,32],96:[2,33],97:[2,34],98:[2,35],100:[2,58],101:[2,59],103:[2,60],104:[2,61]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},P={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),14;case 1:return this.begin("type_directive"),15;case 2:return this.popState(),this.begin("arg_directive"),12;case 3:return this.popState(),this.popState(),17;case 4:return 16;case 5:return 5;case 6:case 7:case 8:break;case 9:return 8;case 10:return 6;case 11:return 23;case 12:return 34;case 13:return 26;case 14:return 25;case 15:return 28;case 16:return 30;case 17:return 32;case 18:return 35;case 19:return 36;case 20:return 37;case 21:return 38;case 22:return 39;case 23:return 40;case 24:return 41;case 25:return 42;case 26:return 43;case 27:return 44;case 28:return 45;case 29:return 46;case 30:return 47;case 31:return 48;case 32:return 59;case 33:return 60;case 34:return 61;case 35:return 62;case 36:return 63;case 37:return 64;case 38:return 65;case 39:return 51;case 40:return 53;case 41:return 55;case 42:return 58;case 43:return 57;case 44:this.begin("string");break;case 45:this.popState();break;case 46:return"qString";case 47:return e.yytext=e.yytext.trim(),66}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:(\r?\n)+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:$)/i,/^(?:requirementDiagram\b)/i,/^(?:\{)/i,/^(?:\})/i,/^(?::)/i,/^(?:id\b)/i,/^(?:text\b)/i,/^(?:risk\b)/i,/^(?:verifyMethod\b)/i,/^(?:requirement\b)/i,/^(?:functionalRequirement\b)/i,/^(?:interfaceRequirement\b)/i,/^(?:performanceRequirement\b)/i,/^(?:physicalRequirement\b)/i,/^(?:designConstraint\b)/i,/^(?:low\b)/i,/^(?:medium\b)/i,/^(?:high\b)/i,/^(?:analysis\b)/i,/^(?:demonstration\b)/i,/^(?:inspection\b)/i,/^(?:test\b)/i,/^(?:element\b)/i,/^(?:contains\b)/i,/^(?:copies\b)/i,/^(?:derives\b)/i,/^(?:satisfies\b)/i,/^(?:verifies\b)/i,/^(?:refines\b)/i,/^(?:traces\b)/i,/^(?:type\b)/i,/^(?:docref\b)/i,/^(?:<-)/i,/^(?:->)/i,/^(?:-)/i,/^(?:["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[\w][^\r\n\{\<\>\-\=]*)/i],conditions:{close_directive:{rules:[],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},open_directive:{rules:[1],inclusive:!1},unqString:{rules:[],inclusive:!1},token:{rules:[],inclusive:!1},string:{rules:[45,46],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,47],inclusive:!0}}};function j(){this.yy={}}return F.lexer=P,j.prototype=F,F.Parser=j,new j}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(8800).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},6876:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,3],r=[1,5],i=[1,7],a=[2,5],o=[1,15],s=[1,17],c=[1,18],u=[1,19],l=[1,21],h=[1,22],f=[1,23],d=[1,29],p=[1,30],y=[1,31],g=[1,32],m=[1,33],v=[1,34],b=[1,37],_=[1,38],x=[1,39],w=[1,40],k=[1,41],T=[1,42],E=[1,45],C=[1,4,5,16,20,22,23,24,30,32,33,34,35,36,38,40,41,42,46,47,48,49,57,67],S=[1,58],A=[4,5,16,20,22,23,24,30,32,33,34,35,36,38,42,46,47,48,49,57,67],M=[4,5,16,20,22,23,24,30,32,33,34,35,36,38,41,42,46,47,48,49,57,67],N=[4,5,16,20,22,23,24,30,32,33,34,35,36,38,40,42,46,47,48,49,57,67],D=[55,56,57],O=[1,4,5,7,16,20,22,23,24,30,32,33,34,35,36,38,40,41,42,46,47,48,49,57,67],B={trace:function(){},yy:{},symbols_:{error:2,start:3,SPACE:4,NEWLINE:5,directive:6,SD:7,document:8,line:9,statement:10,openDirective:11,typeDirective:12,closeDirective:13,":":14,argDirective:15,participant:16,actor:17,AS:18,restOfLine:19,participant_actor:20,signal:21,autonumber:22,activate:23,deactivate:24,note_statement:25,links_statement:26,link_statement:27,properties_statement:28,details_statement:29,title:30,text2:31,loop:32,end:33,rect:34,opt:35,alt:36,else_sections:37,par:38,par_sections:39,and:40,else:41,note:42,placement:43,over:44,actor_pair:45,links:46,link:47,properties:48,details:49,spaceList:50,",":51,left_of:52,right_of:53,signaltype:54,"+":55,"-":56,ACTOR:57,SOLID_OPEN_ARROW:58,DOTTED_OPEN_ARROW:59,SOLID_ARROW:60,DOTTED_ARROW:61,SOLID_CROSS:62,DOTTED_CROSS:63,SOLID_POINT:64,DOTTED_POINT:65,TXT:66,open_directive:67,type_directive:68,arg_directive:69,close_directive:70,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NEWLINE",7:"SD",14:":",16:"participant",18:"AS",19:"restOfLine",20:"participant_actor",22:"autonumber",23:"activate",24:"deactivate",30:"title",32:"loop",33:"end",34:"rect",35:"opt",36:"alt",38:"par",40:"and",41:"else",42:"note",44:"over",46:"links",47:"link",48:"properties",49:"details",51:",",52:"left_of",53:"right_of",55:"+",56:"-",57:"ACTOR",58:"SOLID_OPEN_ARROW",59:"DOTTED_OPEN_ARROW",60:"SOLID_ARROW",61:"DOTTED_ARROW",62:"SOLID_CROSS",63:"DOTTED_CROSS",64:"SOLID_POINT",65:"DOTTED_POINT",66:"TXT",67:"open_directive",68:"type_directive",69:"arg_directive",70:"close_directive"},productions_:[0,[3,2],[3,2],[3,2],[3,2],[8,0],[8,2],[9,2],[9,1],[9,1],[6,4],[6,6],[10,5],[10,3],[10,5],[10,3],[10,2],[10,1],[10,3],[10,3],[10,2],[10,2],[10,2],[10,2],[10,2],[10,3],[10,4],[10,4],[10,4],[10,4],[10,4],[10,1],[39,1],[39,4],[37,1],[37,4],[25,4],[25,4],[26,3],[27,3],[28,3],[29,3],[50,2],[50,1],[45,3],[45,1],[43,1],[43,1],[21,5],[21,5],[21,4],[17,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[31,1],[11,1],[12,1],[15,1],[13,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:return r.apply(a[s]),a[s];case 5:case 9:this.$=[];break;case 6:a[s-1].push(a[s]),this.$=a[s-1];break;case 7:case 8:case 45:this.$=a[s];break;case 12:a[s-3].type="addParticipant",a[s-3].description=r.parseMessage(a[s-1]),this.$=a[s-3];break;case 13:a[s-1].type="addParticipant",this.$=a[s-1];break;case 14:a[s-3].type="addActor",a[s-3].description=r.parseMessage(a[s-1]),this.$=a[s-3];break;case 15:a[s-1].type="addActor",this.$=a[s-1];break;case 17:r.enableSequenceNumbers();break;case 18:this.$={type:"activeStart",signalType:r.LINETYPE.ACTIVE_START,actor:a[s-1]};break;case 19:this.$={type:"activeEnd",signalType:r.LINETYPE.ACTIVE_END,actor:a[s-1]};break;case 25:this.$=[{type:"setTitle",text:a[s-1]}];break;case 26:a[s-1].unshift({type:"loopStart",loopText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.LOOP_START}),a[s-1].push({type:"loopEnd",loopText:a[s-2],signalType:r.LINETYPE.LOOP_END}),this.$=a[s-1];break;case 27:a[s-1].unshift({type:"rectStart",color:r.parseMessage(a[s-2]),signalType:r.LINETYPE.RECT_START}),a[s-1].push({type:"rectEnd",color:r.parseMessage(a[s-2]),signalType:r.LINETYPE.RECT_END}),this.$=a[s-1];break;case 28:a[s-1].unshift({type:"optStart",optText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.OPT_START}),a[s-1].push({type:"optEnd",optText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.OPT_END}),this.$=a[s-1];break;case 29:a[s-1].unshift({type:"altStart",altText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.ALT_START}),a[s-1].push({type:"altEnd",signalType:r.LINETYPE.ALT_END}),this.$=a[s-1];break;case 30:a[s-1].unshift({type:"parStart",parText:r.parseMessage(a[s-2]),signalType:r.LINETYPE.PAR_START}),a[s-1].push({type:"parEnd",signalType:r.LINETYPE.PAR_END}),this.$=a[s-1];break;case 33:this.$=a[s-3].concat([{type:"and",parText:r.parseMessage(a[s-1]),signalType:r.LINETYPE.PAR_AND},a[s]]);break;case 35:this.$=a[s-3].concat([{type:"else",altText:r.parseMessage(a[s-1]),signalType:r.LINETYPE.ALT_ELSE},a[s]]);break;case 36:this.$=[a[s-1],{type:"addNote",placement:a[s-2],actor:a[s-1].actor,text:a[s]}];break;case 37:a[s-2]=[].concat(a[s-1],a[s-1]).slice(0,2),a[s-2][0]=a[s-2][0].actor,a[s-2][1]=a[s-2][1].actor,this.$=[a[s-1],{type:"addNote",placement:r.PLACEMENT.OVER,actor:a[s-2].slice(0,2),text:a[s]}];break;case 38:this.$=[a[s-1],{type:"addLinks",actor:a[s-1].actor,text:a[s]}];break;case 39:this.$=[a[s-1],{type:"addALink",actor:a[s-1].actor,text:a[s]}];break;case 40:this.$=[a[s-1],{type:"addProperties",actor:a[s-1].actor,text:a[s]}];break;case 41:this.$=[a[s-1],{type:"addDetails",actor:a[s-1].actor,text:a[s]}];break;case 44:this.$=[a[s-2],a[s]];break;case 46:this.$=r.PLACEMENT.LEFTOF;break;case 47:this.$=r.PLACEMENT.RIGHTOF;break;case 48:this.$=[a[s-4],a[s-1],{type:"addMessage",from:a[s-4].actor,to:a[s-1].actor,signalType:a[s-3],msg:a[s]},{type:"activeStart",signalType:r.LINETYPE.ACTIVE_START,actor:a[s-1]}];break;case 49:this.$=[a[s-4],a[s-1],{type:"addMessage",from:a[s-4].actor,to:a[s-1].actor,signalType:a[s-3],msg:a[s]},{type:"activeEnd",signalType:r.LINETYPE.ACTIVE_END,actor:a[s-4]}];break;case 50:this.$=[a[s-3],a[s-1],{type:"addMessage",from:a[s-3].actor,to:a[s-1].actor,signalType:a[s-2],msg:a[s]}];break;case 51:this.$={type:"addParticipant",actor:a[s]};break;case 52:this.$=r.LINETYPE.SOLID_OPEN;break;case 53:this.$=r.LINETYPE.DOTTED_OPEN;break;case 54:this.$=r.LINETYPE.SOLID;break;case 55:this.$=r.LINETYPE.DOTTED;break;case 56:this.$=r.LINETYPE.SOLID_CROSS;break;case 57:this.$=r.LINETYPE.DOTTED_CROSS;break;case 58:this.$=r.LINETYPE.SOLID_POINT;break;case 59:this.$=r.LINETYPE.DOTTED_POINT;break;case 60:this.$=r.parseMessage(a[s].trim().substring(1));break;case 61:r.parseDirective("%%{","open_directive");break;case 62:r.parseDirective(a[s],"type_directive");break;case 63:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 64:r.parseDirective("}%%","close_directive","sequence")}},table:[{3:1,4:e,5:n,6:4,7:r,11:6,67:i},{1:[3]},{3:8,4:e,5:n,6:4,7:r,11:6,67:i},{3:9,4:e,5:n,6:4,7:r,11:6,67:i},{3:10,4:e,5:n,6:4,7:r,11:6,67:i},t([1,4,5,16,20,22,23,24,30,32,34,35,36,38,42,46,47,48,49,57,67],a,{8:11}),{12:12,68:[1,13]},{68:[2,61]},{1:[2,1]},{1:[2,2]},{1:[2,3]},{1:[2,4],4:o,5:s,6:35,9:14,10:16,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,34:y,35:g,36:m,38:v,42:b,46:_,47:x,48:w,49:k,57:T,67:i},{13:43,14:[1,44],70:E},t([14,70],[2,62]),t(C,[2,6]),{6:35,10:46,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,34:y,35:g,36:m,38:v,42:b,46:_,47:x,48:w,49:k,57:T,67:i},t(C,[2,8]),t(C,[2,9]),{17:47,57:T},{17:48,57:T},{5:[1,49]},t(C,[2,17]),{17:50,57:T},{17:51,57:T},{5:[1,52]},{5:[1,53]},{5:[1,54]},{5:[1,55]},{5:[1,56]},{31:57,66:S},{19:[1,59]},{19:[1,60]},{19:[1,61]},{19:[1,62]},{19:[1,63]},t(C,[2,31]),{54:64,58:[1,65],59:[1,66],60:[1,67],61:[1,68],62:[1,69],63:[1,70],64:[1,71],65:[1,72]},{43:73,44:[1,74],52:[1,75],53:[1,76]},{17:77,57:T},{17:78,57:T},{17:79,57:T},{17:80,57:T},t([5,18,51,58,59,60,61,62,63,64,65,66],[2,51]),{5:[1,81]},{15:82,69:[1,83]},{5:[2,64]},t(C,[2,7]),{5:[1,85],18:[1,84]},{5:[1,87],18:[1,86]},t(C,[2,16]),{5:[1,88]},{5:[1,89]},t(C,[2,20]),t(C,[2,21]),t(C,[2,22]),t(C,[2,23]),t(C,[2,24]),{5:[1,90]},{5:[2,60]},t(A,a,{8:91}),t(A,a,{8:92}),t(A,a,{8:93}),t(M,a,{37:94,8:95}),t(N,a,{39:96,8:97}),{17:100,55:[1,98],56:[1,99],57:T},t(D,[2,52]),t(D,[2,53]),t(D,[2,54]),t(D,[2,55]),t(D,[2,56]),t(D,[2,57]),t(D,[2,58]),t(D,[2,59]),{17:101,57:T},{17:103,45:102,57:T},{57:[2,46]},{57:[2,47]},{31:104,66:S},{31:105,66:S},{31:106,66:S},{31:107,66:S},t(O,[2,10]),{13:108,70:E},{70:[2,63]},{19:[1,109]},t(C,[2,13]),{19:[1,110]},t(C,[2,15]),t(C,[2,18]),t(C,[2,19]),t(C,[2,25]),{4:o,5:s,6:35,9:14,10:16,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,33:[1,111],34:y,35:g,36:m,38:v,42:b,46:_,47:x,48:w,49:k,57:T,67:i},{4:o,5:s,6:35,9:14,10:16,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,33:[1,112],34:y,35:g,36:m,38:v,42:b,46:_,47:x,48:w,49:k,57:T,67:i},{4:o,5:s,6:35,9:14,10:16,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,33:[1,113],34:y,35:g,36:m,38:v,42:b,46:_,47:x,48:w,49:k,57:T,67:i},{33:[1,114]},{4:o,5:s,6:35,9:14,10:16,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,33:[2,34],34:y,35:g,36:m,38:v,41:[1,115],42:b,46:_,47:x,48:w,49:k,57:T,67:i},{33:[1,116]},{4:o,5:s,6:35,9:14,10:16,11:6,16:c,17:36,20:u,21:20,22:l,23:h,24:f,25:24,26:25,27:26,28:27,29:28,30:d,32:p,33:[2,32],34:y,35:g,36:m,38:v,40:[1,117],42:b,46:_,47:x,48:w,49:k,57:T,67:i},{17:118,57:T},{17:119,57:T},{31:120,66:S},{31:121,66:S},{31:122,66:S},{51:[1,123],66:[2,45]},{5:[2,38]},{5:[2,39]},{5:[2,40]},{5:[2,41]},{5:[1,124]},{5:[1,125]},{5:[1,126]},t(C,[2,26]),t(C,[2,27]),t(C,[2,28]),t(C,[2,29]),{19:[1,127]},t(C,[2,30]),{19:[1,128]},{31:129,66:S},{31:130,66:S},{5:[2,50]},{5:[2,36]},{5:[2,37]},{17:131,57:T},t(O,[2,11]),t(C,[2,12]),t(C,[2,14]),t(M,a,{8:95,37:132}),t(N,a,{8:97,39:133}),{5:[2,48]},{5:[2,49]},{66:[2,44]},{33:[2,35]},{33:[2,33]}],defaultActions:{7:[2,61],8:[2,1],9:[2,2],10:[2,3],45:[2,64],58:[2,60],75:[2,46],76:[2,47],83:[2,63],104:[2,38],105:[2,39],106:[2,40],107:[2,41],120:[2,50],121:[2,36],122:[2,37],129:[2,48],130:[2,49],131:[2,44],132:[2,35],133:[2,33]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},L={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),67;case 1:return this.begin("type_directive"),68;case 2:return this.popState(),this.begin("arg_directive"),14;case 3:return this.popState(),this.popState(),70;case 4:return 69;case 5:case 39:case 52:return 5;case 6:case 7:case 8:case 9:case 10:break;case 11:return this.begin("ID"),16;case 12:return this.begin("ID"),20;case 13:return e.yytext=e.yytext.trim(),this.begin("ALIAS"),57;case 14:return this.popState(),this.popState(),this.begin("LINE"),18;case 15:return this.popState(),this.popState(),5;case 16:return this.begin("LINE"),32;case 17:return this.begin("LINE"),34;case 18:return this.begin("LINE"),35;case 19:return this.begin("LINE"),36;case 20:return this.begin("LINE"),41;case 21:return this.begin("LINE"),38;case 22:return this.begin("LINE"),40;case 23:return this.popState(),19;case 24:return 33;case 25:return 52;case 26:return 53;case 27:return 46;case 28:return 47;case 29:return 48;case 30:return 49;case 31:return 44;case 32:return 42;case 33:return this.begin("ID"),23;case 34:return this.begin("ID"),24;case 35:return 30;case 36:return 7;case 37:return 22;case 38:return 51;case 40:return e.yytext=e.yytext.trim(),57;case 41:return 60;case 42:return 61;case 43:return 58;case 44:return 59;case 45:return 62;case 46:return 63;case 47:return 64;case 48:return 65;case 49:return 66;case 50:return 55;case 51:return 56;case 53:return"INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:participant\b)/i,/^(?:actor\b)/i,/^(?:[^\->:\n,;]+?(?=((?!\n)\s)+as(?!\n)\s|[#\n;]|$))/i,/^(?:as\b)/i,/^(?:(?:))/i,/^(?:loop\b)/i,/^(?:rect\b)/i,/^(?:opt\b)/i,/^(?:alt\b)/i,/^(?:else\b)/i,/^(?:par\b)/i,/^(?:and\b)/i,/^(?:(?:[:]?(?:no)?wrap)?[^#\n;]*)/i,/^(?:end\b)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:links\b)/i,/^(?:link\b)/i,/^(?:properties\b)/i,/^(?:details\b)/i,/^(?:over\b)/i,/^(?:note\b)/i,/^(?:activate\b)/i,/^(?:deactivate\b)/i,/^(?:title\b)/i,/^(?:sequenceDiagram\b)/i,/^(?:autonumber\b)/i,/^(?:,)/i,/^(?:;)/i,/^(?:[^\+\->:\n,;]+((?!(-x|--x|-\)|--\)))[\-]*[^\+\->:\n,;]+)*)/i,/^(?:->>)/i,/^(?:-->>)/i,/^(?:->)/i,/^(?:-->)/i,/^(?:-[x])/i,/^(?:--[x])/i,/^(?:-[\)])/i,/^(?:--[\)])/i,/^(?::(?:(?:no)?wrap)?[^#\n;]+)/i,/^(?:\+)/i,/^(?:-)/i,/^(?:$)/i,/^(?:.)/i],conditions:{open_directive:{rules:[1,8],inclusive:!1},type_directive:{rules:[2,3,8],inclusive:!1},arg_directive:{rules:[3,4,8],inclusive:!1},ID:{rules:[7,8,13],inclusive:!1},ALIAS:{rules:[7,8,14,15],inclusive:!1},LINE:{rules:[7,8,23],inclusive:!1},INITIAL:{rules:[0,5,6,8,9,10,11,12,16,17,18,19,20,21,22,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53],inclusive:!0}}};function I(){this.yy={}}return B.lexer=L,I.prototype=B,B.Parser=I,new I}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(1993).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},3584:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,3],r=[1,5],i=[1,7],a=[2,5],o=[1,15],s=[1,17],c=[1,19],u=[1,20],l=[1,21],h=[1,22],f=[1,30],d=[1,23],p=[1,24],y=[1,25],g=[1,26],m=[1,27],v=[1,32],b=[1,33],_=[1,34],x=[1,35],w=[1,31],k=[1,38],T=[1,4,5,14,15,17,19,20,22,23,24,25,26,27,36,37,38,39,42,45],E=[1,4,5,12,13,14,15,17,19,20,22,23,24,25,26,27,36,37,38,39,42,45],C=[1,4,5,7,14,15,17,19,20,22,23,24,25,26,27,36,37,38,39,42,45],S=[4,5,14,15,17,19,20,22,23,24,25,26,27,36,37,38,39,42,45],A={trace:function(){},yy:{},symbols_:{error:2,start:3,SPACE:4,NL:5,directive:6,SD:7,document:8,line:9,statement:10,idStatement:11,DESCR:12,"--\x3e":13,HIDE_EMPTY:14,scale:15,WIDTH:16,COMPOSIT_STATE:17,STRUCT_START:18,STRUCT_STOP:19,STATE_DESCR:20,AS:21,ID:22,FORK:23,JOIN:24,CHOICE:25,CONCURRENT:26,note:27,notePosition:28,NOTE_TEXT:29,direction:30,openDirective:31,typeDirective:32,closeDirective:33,":":34,argDirective:35,direction_tb:36,direction_bt:37,direction_rl:38,direction_lr:39,eol:40,";":41,EDGE_STATE:42,left_of:43,right_of:44,open_directive:45,type_directive:46,arg_directive:47,close_directive:48,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NL",7:"SD",12:"DESCR",13:"--\x3e",14:"HIDE_EMPTY",15:"scale",16:"WIDTH",17:"COMPOSIT_STATE",18:"STRUCT_START",19:"STRUCT_STOP",20:"STATE_DESCR",21:"AS",22:"ID",23:"FORK",24:"JOIN",25:"CHOICE",26:"CONCURRENT",27:"note",29:"NOTE_TEXT",34:":",36:"direction_tb",37:"direction_bt",38:"direction_rl",39:"direction_lr",41:";",42:"EDGE_STATE",43:"left_of",44:"right_of",45:"open_directive",46:"type_directive",47:"arg_directive",48:"close_directive"},productions_:[0,[3,2],[3,2],[3,2],[3,2],[8,0],[8,2],[9,2],[9,1],[9,1],[10,1],[10,2],[10,3],[10,4],[10,1],[10,2],[10,1],[10,4],[10,3],[10,6],[10,1],[10,1],[10,1],[10,1],[10,4],[10,4],[10,1],[10,1],[6,3],[6,5],[30,1],[30,1],[30,1],[30,1],[40,1],[40,1],[11,1],[11,1],[28,1],[28,1],[31,1],[32,1],[35,1],[33,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 4:return r.setRootDoc(a[s]),a[s];case 5:this.$=[];break;case 6:"nl"!=a[s]&&(a[s-1].push(a[s]),this.$=a[s-1]);break;case 7:case 8:case 36:case 37:this.$=a[s];break;case 9:this.$="nl";break;case 10:this.$={stmt:"state",id:a[s],type:"default",description:""};break;case 11:this.$={stmt:"state",id:a[s-1],type:"default",description:r.trimColon(a[s])};break;case 12:this.$={stmt:"relation",state1:{stmt:"state",id:a[s-2],type:"default",description:""},state2:{stmt:"state",id:a[s],type:"default",description:""}};break;case 13:this.$={stmt:"relation",state1:{stmt:"state",id:a[s-3],type:"default",description:""},state2:{stmt:"state",id:a[s-1],type:"default",description:""},description:a[s].substr(1).trim()};break;case 17:this.$={stmt:"state",id:a[s-3],type:"default",description:"",doc:a[s-1]};break;case 18:var c=a[s],u=a[s-2].trim();if(a[s].match(":")){var l=a[s].split(":");c=l[0],u=[u,l[1]]}this.$={stmt:"state",id:c,type:"default",description:u};break;case 19:this.$={stmt:"state",id:a[s-3],type:"default",description:a[s-5],doc:a[s-1]};break;case 20:this.$={stmt:"state",id:a[s],type:"fork"};break;case 21:this.$={stmt:"state",id:a[s],type:"join"};break;case 22:this.$={stmt:"state",id:a[s],type:"choice"};break;case 23:this.$={stmt:"state",id:r.getDividerId(),type:"divider"};break;case 24:this.$={stmt:"state",id:a[s-1].trim(),note:{position:a[s-2].trim(),text:a[s].trim()}};break;case 30:r.setDirection("TB"),this.$={stmt:"dir",value:"TB"};break;case 31:r.setDirection("BT"),this.$={stmt:"dir",value:"BT"};break;case 32:r.setDirection("RL"),this.$={stmt:"dir",value:"RL"};break;case 33:r.setDirection("LR"),this.$={stmt:"dir",value:"LR"};break;case 40:r.parseDirective("%%{","open_directive");break;case 41:r.parseDirective(a[s],"type_directive");break;case 42:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 43:r.parseDirective("}%%","close_directive","state")}},table:[{3:1,4:e,5:n,6:4,7:r,31:6,45:i},{1:[3]},{3:8,4:e,5:n,6:4,7:r,31:6,45:i},{3:9,4:e,5:n,6:4,7:r,31:6,45:i},{3:10,4:e,5:n,6:4,7:r,31:6,45:i},t([1,4,5,14,15,17,20,22,23,24,25,26,27,36,37,38,39,42,45],a,{8:11}),{32:12,46:[1,13]},{46:[2,40]},{1:[2,1]},{1:[2,2]},{1:[2,3]},{1:[2,4],4:o,5:s,6:28,9:14,10:16,11:18,14:c,15:u,17:l,20:h,22:f,23:d,24:p,25:y,26:g,27:m,30:29,31:6,36:v,37:b,38:_,39:x,42:w,45:i},{33:36,34:[1,37],48:k},t([34,48],[2,41]),t(T,[2,6]),{6:28,10:39,11:18,14:c,15:u,17:l,20:h,22:f,23:d,24:p,25:y,26:g,27:m,30:29,31:6,36:v,37:b,38:_,39:x,42:w,45:i},t(T,[2,8]),t(T,[2,9]),t(T,[2,10],{12:[1,40],13:[1,41]}),t(T,[2,14]),{16:[1,42]},t(T,[2,16],{18:[1,43]}),{21:[1,44]},t(T,[2,20]),t(T,[2,21]),t(T,[2,22]),t(T,[2,23]),{28:45,29:[1,46],43:[1,47],44:[1,48]},t(T,[2,26]),t(T,[2,27]),t(E,[2,36]),t(E,[2,37]),t(T,[2,30]),t(T,[2,31]),t(T,[2,32]),t(T,[2,33]),t(C,[2,28]),{35:49,47:[1,50]},t(C,[2,43]),t(T,[2,7]),t(T,[2,11]),{11:51,22:f,42:w},t(T,[2,15]),t(S,a,{8:52}),{22:[1,53]},{22:[1,54]},{21:[1,55]},{22:[2,38]},{22:[2,39]},{33:56,48:k},{48:[2,42]},t(T,[2,12],{12:[1,57]}),{4:o,5:s,6:28,9:14,10:16,11:18,14:c,15:u,17:l,19:[1,58],20:h,22:f,23:d,24:p,25:y,26:g,27:m,30:29,31:6,36:v,37:b,38:_,39:x,42:w,45:i},t(T,[2,18],{18:[1,59]}),{29:[1,60]},{22:[1,61]},t(C,[2,29]),t(T,[2,13]),t(T,[2,17]),t(S,a,{8:62}),t(T,[2,24]),t(T,[2,25]),{4:o,5:s,6:28,9:14,10:16,11:18,14:c,15:u,17:l,19:[1,63],20:h,22:f,23:d,24:p,25:y,26:g,27:m,30:29,31:6,36:v,37:b,38:_,39:x,42:w,45:i},t(T,[2,19])],defaultActions:{7:[2,40],8:[2,1],9:[2,2],10:[2,3],47:[2,38],48:[2,39],50:[2,42]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},M={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:case 26:return 36;case 1:case 27:return 37;case 2:case 28:return 38;case 3:case 29:return 39;case 4:return this.begin("open_directive"),45;case 5:return this.begin("type_directive"),46;case 6:return this.popState(),this.begin("arg_directive"),34;case 7:return this.popState(),this.popState(),48;case 8:return 47;case 9:case 10:case 12:case 13:case 14:case 15:case 39:case 45:break;case 11:case 59:return 5;case 16:return this.pushState("SCALE"),15;case 17:return 16;case 18:case 33:case 36:this.popState();break;case 19:this.pushState("STATE");break;case 20:case 23:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),23;case 21:case 24:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),24;case 22:case 25:return this.popState(),e.yytext=e.yytext.slice(0,-10).trim(),25;case 30:this.begin("STATE_STRING");break;case 31:return this.popState(),this.pushState("STATE_ID"),"AS";case 32:case 47:return this.popState(),"ID";case 34:return"STATE_DESCR";case 35:return 17;case 37:return this.popState(),this.pushState("struct"),18;case 38:return this.popState(),19;case 40:return this.begin("NOTE"),27;case 41:return this.popState(),this.pushState("NOTE_ID"),43;case 42:return this.popState(),this.pushState("NOTE_ID"),44;case 43:this.popState(),this.pushState("FLOATING_NOTE");break;case 44:return this.popState(),this.pushState("FLOATING_NOTE_ID"),"AS";case 46:return"NOTE_TEXT";case 48:return this.popState(),this.pushState("NOTE_TEXT"),22;case 49:return this.popState(),e.yytext=e.yytext.substr(2).trim(),29;case 50:return this.popState(),e.yytext=e.yytext.slice(0,-8).trim(),29;case 51:case 52:return 7;case 53:return 14;case 54:return 42;case 55:return 22;case 56:return e.yytext=e.yytext.trim(),12;case 57:return 13;case 58:return 26;case 60:return"INVALID"}},rules:[/^(?:.*direction\s+TB[^\n]*)/i,/^(?:.*direction\s+BT[^\n]*)/i,/^(?:.*direction\s+RL[^\n]*)/i,/^(?:.*direction\s+LR[^\n]*)/i,/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:[\s]+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%[^\n]*)/i,/^(?:scale\s+)/i,/^(?:\d+)/i,/^(?:\s+width\b)/i,/^(?:state\s+)/i,/^(?:.*<>)/i,/^(?:.*<>)/i,/^(?:.*<>)/i,/^(?:.*\[\[fork\]\])/i,/^(?:.*\[\[join\]\])/i,/^(?:.*\[\[choice\]\])/i,/^(?:.*direction\s+TB[^\n]*)/i,/^(?:.*direction\s+BT[^\n]*)/i,/^(?:.*direction\s+RL[^\n]*)/i,/^(?:.*direction\s+LR[^\n]*)/i,/^(?:["])/i,/^(?:\s*as\s+)/i,/^(?:[^\n\{]*)/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[^\n\s\{]+)/i,/^(?:\n)/i,/^(?:\{)/i,/^(?:\})/i,/^(?:[\n])/i,/^(?:note\s+)/i,/^(?:left of\b)/i,/^(?:right of\b)/i,/^(?:")/i,/^(?:\s*as\s*)/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:[^\n]*)/i,/^(?:\s*[^:\n\s\-]+)/i,/^(?:\s*:[^:\n;]+)/i,/^(?:[\s\S]*?end note\b)/i,/^(?:stateDiagram\s+)/i,/^(?:stateDiagram-v2\s+)/i,/^(?:hide empty description\b)/i,/^(?:\[\*\])/i,/^(?:[^:\n\s\-\{]+)/i,/^(?:\s*:[^:\n;]+)/i,/^(?:-->)/i,/^(?:--)/i,/^(?:$)/i,/^(?:.)/i],conditions:{LINE:{rules:[13,14],inclusive:!1},close_directive:{rules:[13,14],inclusive:!1},arg_directive:{rules:[7,8,13,14],inclusive:!1},type_directive:{rules:[6,7,13,14],inclusive:!1},open_directive:{rules:[5,13,14],inclusive:!1},struct:{rules:[13,14,19,26,27,28,29,38,39,40,54,55,56,57,58],inclusive:!1},FLOATING_NOTE_ID:{rules:[47],inclusive:!1},FLOATING_NOTE:{rules:[44,45,46],inclusive:!1},NOTE_TEXT:{rules:[49,50],inclusive:!1},NOTE_ID:{rules:[48],inclusive:!1},NOTE:{rules:[41,42,43],inclusive:!1},SCALE:{rules:[17,18],inclusive:!1},ALIAS:{rules:[],inclusive:!1},STATE_ID:{rules:[32],inclusive:!1},STATE_STRING:{rules:[33,34],inclusive:!1},FORK_STATE:{rules:[],inclusive:!1},STATE:{rules:[13,14,20,21,22,23,24,25,30,31,35,36,37],inclusive:!1},ID:{rules:[13,14],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,9,10,11,12,14,15,16,19,37,40,51,52,53,54,55,56,57,59,60],inclusive:!0}}};function N(){this.yy={}}return A.lexer=M,N.prototype=A,A.Parser=N,new N}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(3069).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},9763:(t,e,n)=>{t=n.nmd(t);var r=function(){var t=function(t,e,n,r){for(n=n||{},r=t.length;r--;n[t[r]]=e);return n},e=[1,2],n=[1,5],r=[6,9,11,17,18,19,21],i=[1,15],a=[1,16],o=[1,17],s=[1,21],c=[4,6,9,11,17,18,19,21],u={trace:function(){},yy:{},symbols_:{error:2,start:3,journey:4,document:5,EOF:6,directive:7,line:8,SPACE:9,statement:10,NEWLINE:11,openDirective:12,typeDirective:13,closeDirective:14,":":15,argDirective:16,title:17,section:18,taskName:19,taskData:20,open_directive:21,type_directive:22,arg_directive:23,close_directive:24,$accept:0,$end:1},terminals_:{2:"error",4:"journey",6:"EOF",9:"SPACE",11:"NEWLINE",15:":",17:"title",18:"section",19:"taskName",20:"taskData",21:"open_directive",22:"type_directive",23:"arg_directive",24:"close_directive"},productions_:[0,[3,3],[3,2],[5,0],[5,2],[8,2],[8,1],[8,1],[8,1],[7,4],[7,6],[10,1],[10,1],[10,2],[10,1],[12,1],[13,1],[16,1],[14,1]],performAction:function(t,e,n,r,i,a,o){var s=a.length-1;switch(i){case 1:return a[s-1];case 3:case 7:case 8:this.$=[];break;case 4:a[s-1].push(a[s]),this.$=a[s-1];break;case 5:case 6:this.$=a[s];break;case 11:r.setTitle(a[s].substr(6)),this.$=a[s].substr(6);break;case 12:r.addSection(a[s].substr(8)),this.$=a[s].substr(8);break;case 13:r.addTask(a[s-1],a[s]),this.$="task";break;case 15:r.parseDirective("%%{","open_directive");break;case 16:r.parseDirective(a[s],"type_directive");break;case 17:a[s]=a[s].trim().replace(/'/g,'"'),r.parseDirective(a[s],"arg_directive");break;case 18:r.parseDirective("}%%","close_directive","journey")}},table:[{3:1,4:e,7:3,12:4,21:n},{1:[3]},t(r,[2,3],{5:6}),{3:7,4:e,7:3,12:4,21:n},{13:8,22:[1,9]},{22:[2,15]},{6:[1,10],7:18,8:11,9:[1,12],10:13,11:[1,14],12:4,17:i,18:a,19:o,21:n},{1:[2,2]},{14:19,15:[1,20],24:s},t([15,24],[2,16]),t(r,[2,8],{1:[2,1]}),t(r,[2,4]),{7:18,10:22,12:4,17:i,18:a,19:o,21:n},t(r,[2,6]),t(r,[2,7]),t(r,[2,11]),t(r,[2,12]),{20:[1,23]},t(r,[2,14]),{11:[1,24]},{16:25,23:[1,26]},{11:[2,18]},t(r,[2,5]),t(r,[2,13]),t(c,[2,9]),{14:27,24:s},{24:[2,17]},{11:[1,28]},t(c,[2,10])],defaultActions:{5:[2,15],7:[2,2],21:[2,18],26:[2,17]},parseError:function(t,e){if(!e.recoverable){var n=new Error(t);throw n.hash=e,n}this.trace(t)},parse:function(t){var e=this,n=[0],r=[],i=[null],a=[],o=this.table,s="",c=0,u=0,l=0,h=2,f=1,d=a.slice.call(arguments,1),p=Object.create(this.lexer),y={yy:{}};for(var g in this.yy)Object.prototype.hasOwnProperty.call(this.yy,g)&&(y.yy[g]=this.yy[g]);p.setInput(t,y.yy),y.yy.lexer=p,y.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var m=p.yylloc;a.push(m);var v=p.options&&p.options.ranges;function b(){var t;return"number"!=typeof(t=r.pop()||p.lex()||f)&&(t instanceof Array&&(t=(r=t).pop()),t=e.symbols_[t]||t),t}"function"==typeof y.yy.parseError?this.parseError=y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,x,w,k,T,E,C,S,A,M={};;){if(w=n[n.length-1],this.defaultActions[w]?k=this.defaultActions[w]:(null==_&&(_=b()),k=o[w]&&o[w][_]),void 0===k||!k.length||!k[0]){var N="";for(E in A=[],o[w])this.terminals_[E]&&E>h&&A.push("'"+this.terminals_[E]+"'");N=p.showPosition?"Parse error on line "+(c+1)+":\n"+p.showPosition()+"\nExpecting "+A.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(c+1)+": Unexpected "+(_==f?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError(N,{text:p.match,token:this.terminals_[_]||_,line:p.yylineno,loc:m,expected:A})}if(k[0]instanceof Array&&k.length>1)throw new Error("Parse Error: multiple actions possible at state: "+w+", token: "+_);switch(k[0]){case 1:n.push(_),i.push(p.yytext),a.push(p.yylloc),n.push(k[1]),_=null,x?(_=x,x=null):(u=p.yyleng,s=p.yytext,c=p.yylineno,m=p.yylloc,l>0&&l--);break;case 2:if(C=this.productions_[k[1]][1],M.$=i[i.length-C],M._$={first_line:a[a.length-(C||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(C||1)].first_column,last_column:a[a.length-1].last_column},v&&(M._$.range=[a[a.length-(C||1)].range[0],a[a.length-1].range[1]]),void 0!==(T=this.performAction.apply(M,[s,u,c,y.yy,k[1],i,a].concat(d))))return T;C&&(n=n.slice(0,-1*C*2),i=i.slice(0,-1*C),a=a.slice(0,-1*C)),n.push(this.productions_[k[1]][0]),i.push(M.$),a.push(M._$),S=o[n[n.length-2]][n[n.length-1]],n.push(S);break;case 3:return!0}}return!0}},l={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,n=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var r=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),n.length-1&&(this.yylineno-=n.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:n?(n.length===r.length?this.yylloc.first_column:0)+r[r.length-n.length].length-n[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var n,r,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(r=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=r.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:r?r[r.length-1].length-r[r.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],n=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),n)return n;if(this._backtrack){for(var a in i)this[a]=i[a];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,n,r;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),a=0;ae[0].length)){if(e=n,r=a,this.options.backtrack_lexer){if(!1!==(t=this.test_match(n,i[a])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[r]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){return this.next()||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{"case-insensitive":!0},performAction:function(t,e,n,r){switch(n){case 0:return this.begin("open_directive"),21;case 1:return this.begin("type_directive"),22;case 2:return this.popState(),this.begin("arg_directive"),15;case 3:return this.popState(),this.popState(),24;case 4:return 23;case 5:case 6:case 8:case 9:break;case 7:return 11;case 10:return 4;case 11:return 17;case 12:return 18;case 13:return 19;case 14:return 20;case 15:return 15;case 16:return 6;case 17:return"INVALID"}},rules:[/^(?:%%\{)/i,/^(?:((?:(?!\}%%)[^:.])*))/i,/^(?::)/i,/^(?:\}%%)/i,/^(?:((?:(?!\}%%).|\n)*))/i,/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:journey\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{open_directive:{rules:[1],inclusive:!1},type_directive:{rules:[2,3],inclusive:!1},arg_directive:{rules:[3,4],inclusive:!1},INITIAL:{rules:[0,5,6,7,8,9,10,11,12,13,14,15,16,17],inclusive:!0}}};function h(){this.yy={}}return u.lexer=l,h.prototype=u,u.Parser=h,new h}();e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var r=n(9143).readFileSync(n(6470).normalize(t[1]),"utf8");return e.parser.parse(r)},n.c[n.s]===t&&e.main(process.argv.slice(1))},9609:t=>{"use strict";var e=/^(%20|\s)*(javascript|data)/im,n=/[^\x20-\x7E]/gim,r=/^([^:]+):/gm,i=[".","/"];t.exports={sanitizeUrl:function(t){if(!t)return"about:blank";var a,o,s=t.replace(n,"").trim();return function(t){return i.indexOf(t[0])>-1}(s)?s:(o=s.match(r))?(a=o[0],e.test(a)?"about:blank":s):"about:blank"}}},3841:t=>{t.exports=function(t,e){return t.intersect(e)}},7458:(t,e,n)=>{"use strict";n.d(e,{default:()=>fC});var r=n(1941),i=n.n(r),a={debug:1,info:2,warn:3,error:4,fatal:5},o={debug:function(){},info:function(){},warn:function(){},error:function(){},fatal:function(){}},s=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"fatal";isNaN(t)&&(t=t.toLowerCase(),void 0!==a[t]&&(t=a[t])),o.trace=function(){},o.debug=function(){},o.info=function(){},o.warn=function(){},o.error=function(){},o.fatal=function(){},t<=a.fatal&&(o.fatal=console.error?console.error.bind(console,c("FATAL"),"color: orange"):console.log.bind(console,"",c("FATAL"))),t<=a.error&&(o.error=console.error?console.error.bind(console,c("ERROR"),"color: orange"):console.log.bind(console,"",c("ERROR"))),t<=a.warn&&(o.warn=console.warn?console.warn.bind(console,c("WARN"),"color: orange"):console.log.bind(console,"",c("WARN"))),t<=a.info&&(o.info=console.info?console.info.bind(console,c("INFO"),"color: lightblue"):console.log.bind(console,"",c("INFO"))),t<=a.debug&&(o.debug=console.debug?console.debug.bind(console,c("DEBUG"),"color: lightgreen"):console.log.bind(console,"",c("DEBUG")))},c=function(t){var e=i()().format("ss.SSS");return"%c".concat(e," : ").concat(t," : ")};function u(t,e){let n;if(void 0===e)for(const e of t)null!=e&&(n=e)&&(n=e);else{let r=-1;for(let i of t)null!=(i=e(i,++r,t))&&(n=i)&&(n=i)}return n}function l(t,e){let n;if(void 0===e)for(const e of t)null!=e&&(n>e||void 0===n&&e>=e)&&(n=e);else{let r=-1;for(let i of t)null!=(i=e(i,++r,t))&&(n>i||void 0===n&&i>=i)&&(n=i)}return n}function h(t){return t}var f=1e-6;function d(t){return"translate("+t+",0)"}function p(t){return"translate(0,"+t+")"}function y(t){return e=>+t(e)}function g(t,e){return e=Math.max(0,t.bandwidth()-2*e)/2,t.round()&&(e=Math.round(e)),n=>+t(n)+e}function m(){return!this.__axis}function v(t,e){var n=[],r=null,i=null,a=6,o=6,s=3,c="undefined"!=typeof window&&window.devicePixelRatio>1?0:.5,u=1===t||4===t?-1:1,l=4===t||2===t?"x":"y",v=1===t||3===t?d:p;function b(d){var p=null==r?e.ticks?e.ticks.apply(e,n):e.domain():r,b=null==i?e.tickFormat?e.tickFormat.apply(e,n):h:i,_=Math.max(a,0)+s,x=e.range(),w=+x[0]+c,k=+x[x.length-1]+c,T=(e.bandwidth?g:y)(e.copy(),c),E=d.selection?d.selection():d,C=E.selectAll(".domain").data([null]),S=E.selectAll(".tick").data(p,e).order(),A=S.exit(),M=S.enter().append("g").attr("class","tick"),N=S.select("line"),D=S.select("text");C=C.merge(C.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),S=S.merge(M),N=N.merge(M.append("line").attr("stroke","currentColor").attr(l+"2",u*a)),D=D.merge(M.append("text").attr("fill","currentColor").attr(l,u*_).attr("dy",1===t?"0em":3===t?"0.71em":"0.32em")),d!==E&&(C=C.transition(d),S=S.transition(d),N=N.transition(d),D=D.transition(d),A=A.transition(d).attr("opacity",f).attr("transform",(function(t){return isFinite(t=T(t))?v(t+c):this.getAttribute("transform")})),M.attr("opacity",f).attr("transform",(function(t){var e=this.parentNode.__axis;return v((e&&isFinite(e=e(t))?e:T(t))+c)}))),A.remove(),C.attr("d",4===t||2===t?o?"M"+u*o+","+w+"H"+c+"V"+k+"H"+u*o:"M"+c+","+w+"V"+k:o?"M"+w+","+u*o+"V"+c+"H"+k+"V"+u*o:"M"+w+","+c+"H"+k),S.attr("opacity",1).attr("transform",(function(t){return v(T(t)+c)})),N.attr(l+"2",u*a),D.attr(l,u*_).text(b),E.filter(m).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",2===t?"start":4===t?"end":"middle"),E.each((function(){this.__axis=T}))}return b.scale=function(t){return arguments.length?(e=t,b):e},b.ticks=function(){return n=Array.from(arguments),b},b.tickArguments=function(t){return arguments.length?(n=null==t?[]:Array.from(t),b):n.slice()},b.tickValues=function(t){return arguments.length?(r=null==t?null:Array.from(t),b):r&&r.slice()},b.tickFormat=function(t){return arguments.length?(i=t,b):i},b.tickSize=function(t){return arguments.length?(a=o=+t,b):a},b.tickSizeInner=function(t){return arguments.length?(a=+t,b):a},b.tickSizeOuter=function(t){return arguments.length?(o=+t,b):o},b.tickPadding=function(t){return arguments.length?(s=+t,b):s},b.offset=function(t){return arguments.length?(c=+t,b):c},b}function b(){}function _(t){return null==t?b:function(){return this.querySelector(t)}}function x(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}function w(){return[]}function k(t){return null==t?w:function(){return this.querySelectorAll(t)}}function T(t){return function(){return this.matches(t)}}function E(t){return function(e){return e.matches(t)}}var C=Array.prototype.find;function S(){return this.firstElementChild}var A=Array.prototype.filter;function M(){return Array.from(this.children)}function N(t){return new Array(t.length)}function D(t,e){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=e}function O(t){return function(){return t}}function B(t,e,n,r,i,a){for(var o,s=0,c=e.length,u=a.length;se?1:t>=e?0:NaN}D.prototype={constructor:D,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,e){return this._parent.insertBefore(t,e)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var P="http://www.w3.org/1999/xhtml";const j={svg:"http://www.w3.org/2000/svg",xhtml:P,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function Y(t){var e=t+="",n=e.indexOf(":");return n>=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),j.hasOwnProperty(e)?{space:j[e],local:t}:t}function z(t){return function(){this.removeAttribute(t)}}function U(t){return function(){this.removeAttributeNS(t.space,t.local)}}function q(t,e){return function(){this.setAttribute(t,e)}}function H(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function $(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttribute(t):this.setAttribute(t,n)}}function W(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}function V(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function G(t){return function(){this.style.removeProperty(t)}}function X(t,e,n){return function(){this.style.setProperty(t,e,n)}}function Z(t,e,n){return function(){var r=e.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,n)}}function Q(t,e){return t.style.getPropertyValue(e)||V(t).getComputedStyle(t,null).getPropertyValue(e)}function K(t){return function(){delete this[t]}}function J(t,e){return function(){this[t]=e}}function tt(t,e){return function(){var n=e.apply(this,arguments);null==n?delete this[t]:this[t]=n}}function et(t){return t.trim().split(/^|\s+/)}function nt(t){return t.classList||new rt(t)}function rt(t){this._node=t,this._names=et(t.getAttribute("class")||"")}function it(t,e){for(var n=nt(t),r=-1,i=e.length;++r=0&&(e=t.slice(n+1),t=t.slice(0,n)),{type:t,name:e}}))}function Et(t){return function(){var e=this.__on;if(e){for(var n,r=0,i=-1,a=e.length;r=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Nt=[null];function Dt(t,e){this._groups=t,this._parents=e}function Ot(){return new Dt([[document.documentElement]],Nt)}Dt.prototype=Ot.prototype={constructor:Dt,select:function(t){"function"!=typeof t&&(t=_(t));for(var e=this._groups,n=e.length,r=new Array(n),i=0;i=x&&(x=_+1);!(b=g[x])&&++x=0;)(r=i[a])&&(o&&4^r.compareDocumentPosition(o)&&o.parentNode.insertBefore(r,o),o=r);return this},sort:function(t){function e(e,n){return e&&n?t(e.__data__,n.__data__):!e-!n}t||(t=F);for(var n=this._groups,r=n.length,i=new Array(r),a=0;a1?this.each((null==e?G:"function"==typeof e?Z:X)(t,e,null==n?"":n)):Q(this.node(),t)},property:function(t,e){return arguments.length>1?this.each((null==e?K:"function"==typeof e?tt:J)(t,e)):this.node()[t]},classed:function(t,e){var n=et(t+"");if(arguments.length<2){for(var r=nt(this.node()),i=-1,a=n.length;++i{}};function It(){for(var t,e=0,n=arguments.length,r={};e=0&&(n=t.slice(r+1),t=t.slice(0,r)),t&&!e.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))}function Pt(t,e){for(var n,r=0,i=t.length;r0)for(var n,r,i=new Array(n),a=0;a=0&&e._call.call(void 0,t),e=e._next;--qt}()}finally{qt=0,function(){for(var t,e,n=zt,r=1/0;n;)n._call?(r>n._time&&(r=n._time),t=n,n=n._next):(e=n._next,n._next=null,n=t?t._next=e:zt=e);Ut=t,re(r)}(),Vt=0}}function ne(){var t=Xt.now(),e=t-Wt;e>1e3&&(Gt-=e,Wt=t)}function re(t){qt||(Ht&&(Ht=clearTimeout(Ht)),t-Vt>24?(t<1/0&&(Ht=setTimeout(ee,t-Xt.now()-Gt)),$t&&($t=clearInterval($t))):($t||(Wt=Xt.now(),$t=setInterval(ne,1e3)),qt=1,Zt(ee)))}function ie(t,e,n){var r=new Jt;return e=null==e?0:+e,r.restart((n=>{r.stop(),t(n+e)}),e,n),r}Jt.prototype=te.prototype={constructor:Jt,restart:function(t,e,n){if("function"!=typeof t)throw new TypeError("callback is not a function");n=(null==n?Qt():+n)+(null==e?0:+e),this._next||Ut===this||(Ut?Ut._next=this:zt=this,Ut=this),this._call=t,this._time=n,re()},stop:function(){this._call&&(this._call=null,this._time=1/0,re())}};var ae=Yt("start","end","cancel","interrupt"),oe=[];function se(t,e,n,r,i,a){var o=t.__transition;if(o){if(n in o)return}else t.__transition={};!function(t,e,n){var r,i=t.__transition;function a(c){var u,l,h,f;if(1!==n.state)return s();for(u in i)if((f=i[u]).name===n.name){if(3===f.state)return ie(a);4===f.state?(f.state=6,f.timer.stop(),f.on.call("interrupt",t,t.__data__,f.index,f.group),delete i[u]):+u0)throw new Error("too late; already scheduled");return n}function ue(t,e){var n=le(t,e);if(n.state>3)throw new Error("too late; already running");return n}function le(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}function he(t,e){return t=+t,e=+e,function(n){return t*(1-n)+e*n}}var fe,de=180/Math.PI,pe={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function ye(t,e,n,r,i,a){var o,s,c;return(o=Math.sqrt(t*t+e*e))&&(t/=o,e/=o),(c=t*n+e*r)&&(n-=t*c,r-=e*c),(s=Math.sqrt(n*n+r*r))&&(n/=s,r/=s,c/=s),t*r180?e+=360:e-t>180&&(t+=360),a.push({i:n.push(i(n)+"rotate(",null,r)-2,x:he(t,e)})):e&&n.push(i(n)+"rotate("+e+r)}(a.rotate,o.rotate,s,c),function(t,e,n,a){t!==e?a.push({i:n.push(i(n)+"skewX(",null,r)-2,x:he(t,e)}):e&&n.push(i(n)+"skewX("+e+r)}(a.skewX,o.skewX,s,c),function(t,e,n,r,a,o){if(t!==n||e!==r){var s=a.push(i(a)+"scale(",null,",",null,")");o.push({i:s-4,x:he(t,n)},{i:s-2,x:he(e,r)})}else 1===n&&1===r||a.push(i(a)+"scale("+n+","+r+")")}(a.scaleX,a.scaleY,o.scaleX,o.scaleY,s,c),a=o=null,function(t){for(var e,n=-1,r=c.length;++n>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?Ue(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?Ue(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=De.exec(t))?new $e(e[1],e[2],e[3],1):(e=Oe.exec(t))?new $e(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=Be.exec(t))?Ue(e[1],e[2],e[3],e[4]):(e=Le.exec(t))?Ue(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=Ie.exec(t))?Xe(e[1],e[2]/100,e[3]/100,1):(e=Re.exec(t))?Xe(e[1],e[2]/100,e[3]/100,e[4]):Fe.hasOwnProperty(t)?ze(Fe[t]):"transparent"===t?new $e(NaN,NaN,NaN,0):null}function ze(t){return new $e(t>>16&255,t>>8&255,255&t,1)}function Ue(t,e,n,r){return r<=0&&(t=e=n=NaN),new $e(t,e,n,r)}function qe(t){return t instanceof Te||(t=Ye(t)),t?new $e((t=t.rgb()).r,t.g,t.b,t.opacity):new $e}function He(t,e,n,r){return 1===arguments.length?qe(t):new $e(t,e,n,null==r?1:r)}function $e(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function We(){return"#"+Ge(this.r)+Ge(this.g)+Ge(this.b)}function Ve(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function Ge(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Xe(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new Qe(t,e,n,r)}function Ze(t){if(t instanceof Qe)return new Qe(t.h,t.s,t.l,t.opacity);if(t instanceof Te||(t=Ye(t)),!t)return new Qe;if(t instanceof Qe)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),a=Math.max(e,n,r),o=NaN,s=a-i,c=(a+i)/2;return s?(o=e===a?(n-r)/s+6*(n0&&c<1?0:o,new Qe(o,s,c,t.opacity)}function Qe(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function Ke(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}function Je(t,e,n,r,i){var a=t*t,o=a*t;return((1-3*t+3*a-o)*e+(4-6*a+3*o)*n+(1+3*t+3*a-3*o)*r+o*i)/6}we(Te,Ye,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:Pe,formatHex:Pe,formatHsl:function(){return Ze(this).formatHsl()},formatRgb:je,toString:je}),we($e,He,ke(Te,{brighter:function(t){return t=null==t?Ce:Math.pow(Ce,t),new $e(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?Ee:Math.pow(Ee,t),new $e(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:We,formatHex:We,formatRgb:Ve,toString:Ve})),we(Qe,(function(t,e,n,r){return 1===arguments.length?Ze(t):new Qe(t,e,n,null==r?1:r)}),ke(Te,{brighter:function(t){return t=null==t?Ce:Math.pow(Ce,t),new Qe(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?Ee:Math.pow(Ee,t),new Qe(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new $e(Ke(t>=240?t-240:t+120,i,r),Ke(t,i,r),Ke(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const tn=t=>()=>t;function en(t,e){var n=e-t;return n?function(t,e){return function(n){return t+n*e}}(t,n):tn(isNaN(t)?e:t)}const nn=function t(e){var n=function(t){return 1==(t=+t)?en:function(e,n){return n-e?function(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(r){return Math.pow(t+r*e,n)}}(e,n,t):tn(isNaN(e)?n:e)}}(e);function r(t,e){var r=n((t=He(t)).r,(e=He(e)).r),i=n(t.g,e.g),a=n(t.b,e.b),o=en(t.opacity,e.opacity);return function(e){return t.r=r(e),t.g=i(e),t.b=a(e),t.opacity=o(e),t+""}}return r.gamma=t,r}(1);function rn(t){return function(e){var n,r,i=e.length,a=new Array(i),o=new Array(i),s=new Array(i);for(n=0;n=1?(n=1,e-1):Math.floor(n*e),i=t[r],a=t[r+1],o=r>0?t[r-1]:2*i-a,s=ra&&(i=e.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(n=n[0])===(r=r[0])?s[o]?s[o]+=r:s[++o]=r:(s[++o]=null,c.push({i:o,x:he(n,r)})),a=on.lastIndex;return a=0&&(t=t.slice(0,e)),!t||"start"===t}))}(e)?ce:ue;return function(){var o=a(this,t),s=o.on;s!==r&&(i=(r=s).copy()).on(e,n),o.on=i}}var En=Bt.prototype.constructor;function Cn(t){return function(){this.style.removeProperty(t)}}function Sn(t,e,n){return function(r){this.style.setProperty(t,e.call(this,r),n)}}function An(t,e,n){var r,i;function a(){var a=e.apply(this,arguments);return a!==i&&(r=(i=a)&&Sn(t,a,n)),r}return a._value=e,a}function Mn(t){return function(e){this.textContent=t.call(this,e)}}function Nn(t){var e,n;function r(){var r=t.apply(this,arguments);return r!==n&&(e=(n=r)&&Mn(r)),e}return r._value=t,r}var Dn=0;function On(t,e,n,r){this._groups=t,this._parents=e,this._name=n,this._id=r}function Bn(){return++Dn}var Ln=Bt.prototype;On.prototype=function(t){return Bt().transition(t)}.prototype={constructor:On,select:function(t){var e=this._name,n=this._id;"function"!=typeof t&&(t=_(t));for(var r=this._groups,i=r.length,a=new Array(i),o=0;o2&&n.state<5,n.state=6,n.timer.stop(),n.on.call(r?"interrupt":"cancel",t,t.__data__,n.index,n.group),delete a[i]):o=!1;o&&delete t.__transition}}(this,t)}))},Bt.prototype.transition=function(t){var e,n;t instanceof On?(e=t._id,t=t._name):(e=Bn(),(n=In).time=Qt(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,a=0;a>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?sr(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?sr(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=Zn.exec(t))?new lr(e[1],e[2],e[3],1):(e=Qn.exec(t))?new lr(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=Kn.exec(t))?sr(e[1],e[2],e[3],e[4]):(e=Jn.exec(t))?sr(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=tr.exec(t))?pr(e[1],e[2]/100,e[3]/100,1):(e=er.exec(t))?pr(e[1],e[2]/100,e[3]/100,e[4]):nr.hasOwnProperty(t)?or(nr[t]):"transparent"===t?new lr(NaN,NaN,NaN,0):null}function or(t){return new lr(t>>16&255,t>>8&255,255&t,1)}function sr(t,e,n,r){return r<=0&&(t=e=n=NaN),new lr(t,e,n,r)}function cr(t){return t instanceof qn||(t=ar(t)),t?new lr((t=t.rgb()).r,t.g,t.b,t.opacity):new lr}function ur(t,e,n,r){return 1===arguments.length?cr(t):new lr(t,e,n,null==r?1:r)}function lr(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function hr(){return"#"+dr(this.r)+dr(this.g)+dr(this.b)}function fr(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function dr(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function pr(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new gr(t,e,n,r)}function yr(t){if(t instanceof gr)return new gr(t.h,t.s,t.l,t.opacity);if(t instanceof qn||(t=ar(t)),!t)return new gr;if(t instanceof gr)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),a=Math.max(e,n,r),o=NaN,s=a-i,c=(a+i)/2;return s?(o=e===a?(n-r)/s+6*(n0&&c<1?0:o,new gr(o,s,c,t.opacity)}function gr(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function mr(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}zn(qn,ar,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:rr,formatHex:rr,formatHsl:function(){return yr(this).formatHsl()},formatRgb:ir,toString:ir}),zn(lr,ur,Un(qn,{brighter:function(t){return t=null==t?$n:Math.pow($n,t),new lr(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?Hn:Math.pow(Hn,t),new lr(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:hr,formatHex:hr,formatRgb:fr,toString:fr})),zn(gr,(function(t,e,n,r){return 1===arguments.length?yr(t):new gr(t,e,n,null==r?1:r)}),Un(qn,{brighter:function(t){return t=null==t?$n:Math.pow($n,t),new gr(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?Hn:Math.pow(Hn,t),new gr(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new lr(mr(t>=240?t-240:t+120,i,r),mr(t,i,r),mr(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const vr=Math.PI/180,br=180/Math.PI,_r=.96422,xr=.82521,wr=4/29,kr=6/29,Tr=3*kr*kr;function Er(t){if(t instanceof Cr)return new Cr(t.l,t.a,t.b,t.opacity);if(t instanceof Br)return Lr(t);t instanceof lr||(t=cr(t));var e,n,r=Nr(t.r),i=Nr(t.g),a=Nr(t.b),o=Sr((.2225045*r+.7168786*i+.0606169*a)/1);return r===i&&i===a?e=n=o:(e=Sr((.4360747*r+.3850649*i+.1430804*a)/_r),n=Sr((.0139322*r+.0971045*i+.7141733*a)/xr)),new Cr(116*o-16,500*(e-o),200*(o-n),t.opacity)}function Cr(t,e,n,r){this.l=+t,this.a=+e,this.b=+n,this.opacity=+r}function Sr(t){return t>.008856451679035631?Math.pow(t,1/3):t/Tr+wr}function Ar(t){return t>kr?t*t*t:Tr*(t-wr)}function Mr(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Nr(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Dr(t){if(t instanceof Br)return new Br(t.h,t.c,t.l,t.opacity);if(t instanceof Cr||(t=Er(t)),0===t.a&&0===t.b)return new Br(NaN,0()=>t;function Rr(t,e){return function(n){return t+n*e}}function Fr(t,e){var n=e-t;return n?Rr(t,n):Ir(isNaN(t)?e:t)}function Pr(t){return function(e,n){var r=t((e=Or(e)).h,(n=Or(n)).h),i=Fr(e.c,n.c),a=Fr(e.l,n.l),o=Fr(e.opacity,n.opacity);return function(t){return e.h=r(t),e.c=i(t),e.l=a(t),e.opacity=o(t),e+""}}}const jr=Pr((function(t,e){var n=e-t;return n?Rr(t,n>180||n<-180?n-360*Math.round(n/360):n):Ir(isNaN(t)?e:t)}));Pr(Fr);var Yr=Math.sqrt(50),zr=Math.sqrt(10),Ur=Math.sqrt(2);function qr(t,e,n){var r=(e-t)/Math.max(0,n),i=Math.floor(Math.log(r)/Math.LN10),a=r/Math.pow(10,i);return i>=0?(a>=Yr?10:a>=zr?5:a>=Ur?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(a>=Yr?10:a>=zr?5:a>=Ur?2:1)}function Hr(t,e,n){var r=Math.abs(e-t)/Math.max(0,n),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),a=r/i;return a>=Yr?i*=10:a>=zr?i*=5:a>=Ur&&(i*=2),ee?1:t>=e?0:NaN}function Wr(t){let e=t,n=t,r=t;function i(t,e,i=0,a=t.length){if(i>>1;r(t[n],e)<0?i=n+1:a=n}while(it(e)-n,n=$r,r=(e,n)=>$r(t(e),n)),{left:i,center:function(t,n,r=0,a=t.length){const o=i(t,n,r,a-1);return o>r&&e(t[o-1],n)>-e(t[o],n)?o-1:o},right:function(t,e,i=0,a=t.length){if(i>>1;r(t[n],e)<=0?i=n+1:a=n}while(i>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?gi(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?gi(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=ai.exec(t))?new bi(e[1],e[2],e[3],1):(e=oi.exec(t))?new bi(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=si.exec(t))?gi(e[1],e[2],e[3],e[4]):(e=ci.exec(t))?gi(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=ui.exec(t))?ki(e[1],e[2]/100,e[3]/100,1):(e=li.exec(t))?ki(e[1],e[2]/100,e[3]/100,e[4]):hi.hasOwnProperty(t)?yi(hi[t]):"transparent"===t?new bi(NaN,NaN,NaN,0):null}function yi(t){return new bi(t>>16&255,t>>8&255,255&t,1)}function gi(t,e,n,r){return r<=0&&(t=e=n=NaN),new bi(t,e,n,r)}function mi(t){return t instanceof Kr||(t=pi(t)),t?new bi((t=t.rgb()).r,t.g,t.b,t.opacity):new bi}function vi(t,e,n,r){return 1===arguments.length?mi(t):new bi(t,e,n,null==r?1:r)}function bi(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function _i(){return"#"+wi(this.r)+wi(this.g)+wi(this.b)}function xi(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function wi(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function ki(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new Ei(t,e,n,r)}function Ti(t){if(t instanceof Ei)return new Ei(t.h,t.s,t.l,t.opacity);if(t instanceof Kr||(t=pi(t)),!t)return new Ei;if(t instanceof Ei)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),a=Math.max(e,n,r),o=NaN,s=a-i,c=(a+i)/2;return s?(o=e===a?(n-r)/s+6*(n0&&c<1?0:o,new Ei(o,s,c,t.opacity)}function Ei(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function Ci(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}function Si(t,e,n,r,i){var a=t*t,o=a*t;return((1-3*t+3*a-o)*e+(4-6*a+3*o)*n+(1+3*t+3*a-3*o)*r+o*i)/6}Zr(Kr,pi,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:fi,formatHex:fi,formatHsl:function(){return Ti(this).formatHsl()},formatRgb:di,toString:di}),Zr(bi,vi,Qr(Kr,{brighter:function(t){return t=null==t?ti:Math.pow(ti,t),new bi(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?Jr:Math.pow(Jr,t),new bi(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:_i,formatHex:_i,formatRgb:xi,toString:xi})),Zr(Ei,(function(t,e,n,r){return 1===arguments.length?Ti(t):new Ei(t,e,n,null==r?1:r)}),Qr(Kr,{brighter:function(t){return t=null==t?ti:Math.pow(ti,t),new Ei(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?Jr:Math.pow(Jr,t),new Ei(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new bi(Ci(t>=240?t-240:t+120,i,r),Ci(t,i,r),Ci(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const Ai=t=>()=>t;function Mi(t,e){var n=e-t;return n?function(t,e){return function(n){return t+n*e}}(t,n):Ai(isNaN(t)?e:t)}const Ni=function t(e){var n=function(t){return 1==(t=+t)?Mi:function(e,n){return n-e?function(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(r){return Math.pow(t+r*e,n)}}(e,n,t):Ai(isNaN(e)?n:e)}}(e);function r(t,e){var r=n((t=vi(t)).r,(e=vi(e)).r),i=n(t.g,e.g),a=n(t.b,e.b),o=Mi(t.opacity,e.opacity);return function(e){return t.r=r(e),t.g=i(e),t.b=a(e),t.opacity=o(e),t+""}}return r.gamma=t,r}(1);function Di(t){return function(e){var n,r,i=e.length,a=new Array(i),o=new Array(i),s=new Array(i);for(n=0;n=1?(n=1,e-1):Math.floor(n*e),i=t[r],a=t[r+1],o=r>0?t[r-1]:2*i-a,s=ra&&(i=e.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(n=n[0])===(r=r[0])?s[o]?s[o]+=r:s[++o]=r:(s[++o]=null,c.push({i:o,x:Li(n,r)})),a=Fi.lastIndex;return ae&&(n=t,t=e,e=n),u=function(n){return Math.max(t,Math.min(e,n))}),r=c>2?Vi:Wi,i=a=null,h}function h(e){return null==e||isNaN(e=+e)?n:(i||(i=r(o.map(t),s,c)))(t(u(e)))}return h.invert=function(n){return u(e((a||(a=r(s,o.map(t),Li)))(n)))},h.domain=function(t){return arguments.length?(o=Array.from(t,Ui),l()):o.slice()},h.range=function(t){return arguments.length?(s=Array.from(t),l()):s.slice()},h.rangeRound=function(t){return s=Array.from(t),c=zi,l()},h.clamp=function(t){return arguments.length?(u=!!t||Hi,l()):u!==Hi},h.interpolate=function(t){return arguments.length?(c=t,l()):c},h.unknown=function(t){return arguments.length?(n=t,h):n},function(n,r){return t=n,e=r,l()}}()(Hi,Hi)}function Zi(t,e){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(e).domain(t)}return this}var Qi,Ki=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Ji(t){if(!(e=Ki.exec(t)))throw new Error("invalid format: "+t);var e;return new ta({fill:e[1],align:e[2],sign:e[3],symbol:e[4],zero:e[5],width:e[6],comma:e[7],precision:e[8]&&e[8].slice(1),trim:e[9],type:e[10]})}function ta(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function ea(t,e){if((n=(t=e?t.toExponential(e-1):t.toExponential()).indexOf("e"))<0)return null;var n,r=t.slice(0,n);return[r.length>1?r[0]+r.slice(2):r,+t.slice(n+1)]}function na(t){return(t=ea(Math.abs(t)))?t[1]:NaN}function ra(t,e){var n=ea(t,e);if(!n)return t+"";var r=n[0],i=n[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}Ji.prototype=ta.prototype,ta.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};const ia={"%":(t,e)=>(100*t).toFixed(e),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,e)=>t.toExponential(e),f:(t,e)=>t.toFixed(e),g:(t,e)=>t.toPrecision(e),o:t=>Math.round(t).toString(8),p:(t,e)=>ra(100*t,e),r:ra,s:function(t,e){var n=ea(t,e);if(!n)return t+"";var r=n[0],i=n[1],a=i-(Qi=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,o=r.length;return a===o?r:a>o?r+new Array(a-o+1).join("0"):a>0?r.slice(0,a)+"."+r.slice(a):"0."+new Array(1-a).join("0")+ea(t,Math.max(0,e+a-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function aa(t){return t}var oa,sa,ca,ua=Array.prototype.map,la=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function ha(t){var e=t.domain;return t.ticks=function(t){var n=e();return function(t,e,n){var r,i,a,o,s=-1;if(n=+n,(t=+t)==(e=+e)&&n>0)return[t];if((r=e0){let n=Math.round(t/o),r=Math.round(e/o);for(n*oe&&--r,a=new Array(i=r-n+1);++se&&--r,a=new Array(i=r-n+1);++s0;){if((i=qr(c,u,n))===r)return a[o]=c,a[s]=u,e(a);if(i>0)c=Math.floor(c/i)*i,u=Math.ceil(u/i)*i;else{if(!(i<0))break;c=Math.ceil(c*i)/i,u=Math.floor(u*i)/i}r=i}return t},t}function fa(){var t=Xi();return t.copy=function(){return Gi(t,fa())},Zi.apply(t,arguments),ha(t)}oa=function(t){var e,n,r=void 0===t.grouping||void 0===t.thousands?aa:(e=ua.call(t.grouping,Number),n=t.thousands+"",function(t,r){for(var i=t.length,a=[],o=0,s=e[0],c=0;i>0&&s>0&&(c+s+1>r&&(s=Math.max(1,r-c)),a.push(t.substring(i-=s,i+s)),!((c+=s+1)>r));)s=e[o=(o+1)%e.length];return a.reverse().join(n)}),i=void 0===t.currency?"":t.currency[0]+"",a=void 0===t.currency?"":t.currency[1]+"",o=void 0===t.decimal?".":t.decimal+"",s=void 0===t.numerals?aa:function(t){return function(e){return e.replace(/[0-9]/g,(function(e){return t[+e]}))}}(ua.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",u=void 0===t.minus?"−":t.minus+"",l=void 0===t.nan?"NaN":t.nan+"";function h(t){var e=(t=Ji(t)).fill,n=t.align,h=t.sign,f=t.symbol,d=t.zero,p=t.width,y=t.comma,g=t.precision,m=t.trim,v=t.type;"n"===v?(y=!0,v="g"):ia[v]||(void 0===g&&(g=12),m=!0,v="g"),(d||"0"===e&&"="===n)&&(d=!0,e="0",n="=");var b="$"===f?i:"#"===f&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",_="$"===f?a:/[%p]/.test(v)?c:"",x=ia[v],w=/[defgprs%]/.test(v);function k(t){var i,a,c,f=b,k=_;if("c"===v)k=x(t)+k,t="";else{var T=(t=+t)<0||1/t<0;if(t=isNaN(t)?l:x(Math.abs(t),g),m&&(t=function(t){t:for(var e,n=t.length,r=1,i=-1;r0&&(i=0)}return i>0?t.slice(0,i)+t.slice(e+1):t}(t)),T&&0==+t&&"+"!==h&&(T=!1),f=(T?"("===h?h:u:"-"===h||"("===h?"":h)+f,k=("s"===v?la[8+Qi/3]:"")+k+(T&&"("===h?")":""),w)for(i=-1,a=t.length;++i(c=t.charCodeAt(i))||c>57){k=(46===c?o+t.slice(i+1):t.slice(i))+k,t=t.slice(0,i);break}}y&&!d&&(t=r(t,1/0));var E=f.length+t.length+k.length,C=E>1)+f+t+k+C.slice(E);break;default:t=C+f+t+k}return s(t)}return g=void 0===g?6:/[gprs]/.test(v)?Math.max(1,Math.min(21,g)):Math.max(0,Math.min(20,g)),k.toString=function(){return t+""},k}return{format:h,formatPrefix:function(t,e){var n=h(((t=Ji(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(na(e)/3))),i=Math.pow(10,-r),a=la[8+r/3];return function(t){return n(i*t)+a}}}}({thousands:",",grouping:[3],currency:["$",""]}),sa=oa.format,ca=oa.formatPrefix;class da extends Map{constructor(t,e=ya){if(super(),Object.defineProperties(this,{_intern:{value:new Map},_key:{value:e}}),null!=t)for(const[e,n]of t)this.set(e,n)}get(t){return super.get(pa(this,t))}has(t){return super.has(pa(this,t))}set(t,e){return super.set(function({_intern:t,_key:e},n){const r=e(n);return t.has(r)?t.get(r):(t.set(r,n),n)}(this,t),e)}delete(t){return super.delete(function({_intern:t,_key:e},n){const r=e(n);return t.has(r)&&(n=t.get(r),t.delete(r)),n}(this,t))}}function pa({_intern:t,_key:e},n){const r=e(n);return t.has(r)?t.get(r):n}function ya(t){return null!==t&&"object"==typeof t?t.valueOf():t}Set;const ga=Symbol("implicit");function ma(){var t=new da,e=[],n=[],r=ga;function i(i){let a=t.get(i);if(void 0===a){if(r!==ga)return r;t.set(i,a=e.push(i)-1)}return n[a%n.length]}return i.domain=function(n){if(!arguments.length)return e.slice();e=[],t=new da;for(const r of n)t.has(r)||t.set(r,e.push(r)-1);return i},i.range=function(t){return arguments.length?(n=Array.from(t),i):n.slice()},i.unknown=function(t){return arguments.length?(r=t,i):r},i.copy=function(){return ma(e,n).unknown(r)},Zi.apply(i,arguments),i}const va=1e3,ba=6e4,_a=36e5,xa=864e5,wa=6048e5,ka=31536e6;var Ta=new Date,Ea=new Date;function Ca(t,e,n,r){function i(e){return t(e=0===arguments.length?new Date:new Date(+e)),e}return i.floor=function(e){return t(e=new Date(+e)),e},i.ceil=function(n){return t(n=new Date(n-1)),e(n,1),t(n),n},i.round=function(t){var e=i(t),n=i.ceil(t);return t-e0))return s;do{s.push(o=new Date(+n)),e(n,a),t(n)}while(o=e)for(;t(e),!n(e);)e.setTime(e-1)}),(function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;e(t,-1),!n(t););else for(;--r>=0;)for(;e(t,1),!n(t););}))},n&&(i.count=function(e,r){return Ta.setTime(+e),Ea.setTime(+r),t(Ta),t(Ea),Math.floor(n(Ta,Ea))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(e){return r(e)%t==0}:function(e){return i.count(0,e)%t==0}):i:null}),i}var Sa=Ca((function(){}),(function(t,e){t.setTime(+t+e)}),(function(t,e){return e-t}));Sa.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Ca((function(e){e.setTime(Math.floor(e/t)*t)}),(function(e,n){e.setTime(+e+n*t)}),(function(e,n){return(n-e)/t})):Sa:null};const Aa=Sa;Sa.range;var Ma=Ca((function(t){t.setTime(t-t.getMilliseconds())}),(function(t,e){t.setTime(+t+e*va)}),(function(t,e){return(e-t)/va}),(function(t){return t.getUTCSeconds()}));const Na=Ma;Ma.range;var Da=Ca((function(t){t.setTime(t-t.getMilliseconds()-t.getSeconds()*va)}),(function(t,e){t.setTime(+t+e*ba)}),(function(t,e){return(e-t)/ba}),(function(t){return t.getMinutes()}));const Oa=Da;Da.range;var Ba=Ca((function(t){t.setTime(t-t.getMilliseconds()-t.getSeconds()*va-t.getMinutes()*ba)}),(function(t,e){t.setTime(+t+e*_a)}),(function(t,e){return(e-t)/_a}),(function(t){return t.getHours()}));const La=Ba;Ba.range;var Ia=Ca((t=>t.setHours(0,0,0,0)),((t,e)=>t.setDate(t.getDate()+e)),((t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*ba)/xa),(t=>t.getDate()-1));const Ra=Ia;function Fa(t){return Ca((function(e){e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)}),(function(t,e){t.setDate(t.getDate()+7*e)}),(function(t,e){return(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*ba)/wa}))}Ia.range;var Pa=Fa(0),ja=Fa(1),Ya=Fa(2),za=Fa(3),Ua=Fa(4),qa=Fa(5),Ha=Fa(6),$a=(Pa.range,ja.range,Ya.range,za.range,Ua.range,qa.range,Ha.range,Ca((function(t){t.setDate(1),t.setHours(0,0,0,0)}),(function(t,e){t.setMonth(t.getMonth()+e)}),(function(t,e){return e.getMonth()-t.getMonth()+12*(e.getFullYear()-t.getFullYear())}),(function(t){return t.getMonth()})));const Wa=$a;$a.range;var Va=Ca((function(t){t.setMonth(0,1),t.setHours(0,0,0,0)}),(function(t,e){t.setFullYear(t.getFullYear()+e)}),(function(t,e){return e.getFullYear()-t.getFullYear()}),(function(t){return t.getFullYear()}));Va.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Ca((function(e){e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)}),(function(e,n){e.setFullYear(e.getFullYear()+n*t)})):null};const Ga=Va;Va.range;var Xa=Ca((function(t){t.setUTCSeconds(0,0)}),(function(t,e){t.setTime(+t+e*ba)}),(function(t,e){return(e-t)/ba}),(function(t){return t.getUTCMinutes()}));const Za=Xa;Xa.range;var Qa=Ca((function(t){t.setUTCMinutes(0,0,0)}),(function(t,e){t.setTime(+t+e*_a)}),(function(t,e){return(e-t)/_a}),(function(t){return t.getUTCHours()}));const Ka=Qa;Qa.range;var Ja=Ca((function(t){t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+e)}),(function(t,e){return(e-t)/xa}),(function(t){return t.getUTCDate()-1}));const to=Ja;function eo(t){return Ca((function(e){e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+7*e)}),(function(t,e){return(e-t)/wa}))}Ja.range;var no=eo(0),ro=eo(1),io=eo(2),ao=eo(3),oo=eo(4),so=eo(5),co=eo(6),uo=(no.range,ro.range,io.range,ao.range,oo.range,so.range,co.range,Ca((function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCMonth(t.getUTCMonth()+e)}),(function(t,e){return e.getUTCMonth()-t.getUTCMonth()+12*(e.getUTCFullYear()-t.getUTCFullYear())}),(function(t){return t.getUTCMonth()})));const lo=uo;uo.range;var ho=Ca((function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCFullYear(t.getUTCFullYear()+e)}),(function(t,e){return e.getUTCFullYear()-t.getUTCFullYear()}),(function(t){return t.getUTCFullYear()}));ho.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Ca((function(e){e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)}),(function(e,n){e.setUTCFullYear(e.getUTCFullYear()+n*t)})):null};const fo=ho;function po(t,e,n,r,i,a){const o=[[Na,1,va],[Na,5,5e3],[Na,15,15e3],[Na,30,3e4],[a,1,ba],[a,5,3e5],[a,15,9e5],[a,30,18e5],[i,1,_a],[i,3,108e5],[i,6,216e5],[i,12,432e5],[r,1,xa],[r,2,1728e5],[n,1,wa],[e,1,2592e6],[e,3,7776e6],[t,1,ka]];function s(e,n,r){const i=Math.abs(n-e)/r,a=Wr((([,,t])=>t)).right(o,i);if(a===o.length)return t.every(Hr(e/ka,n/ka,r));if(0===a)return Aa.every(Math.max(Hr(e,n,r),1));const[s,c]=o[i/o[a-1][2][t.toLowerCase(),e])))}function Oo(t,e,n){var r=Eo.exec(e.slice(n,n+1));return r?(t.w=+r[0],n+r[0].length):-1}function Bo(t,e,n){var r=Eo.exec(e.slice(n,n+1));return r?(t.u=+r[0],n+r[0].length):-1}function Lo(t,e,n){var r=Eo.exec(e.slice(n,n+2));return r?(t.U=+r[0],n+r[0].length):-1}function Io(t,e,n){var r=Eo.exec(e.slice(n,n+2));return r?(t.V=+r[0],n+r[0].length):-1}function Ro(t,e,n){var r=Eo.exec(e.slice(n,n+2));return r?(t.W=+r[0],n+r[0].length):-1}function Fo(t,e,n){var r=Eo.exec(e.slice(n,n+4));return r?(t.y=+r[0],n+r[0].length):-1}function Po(t,e,n){var r=Eo.exec(e.slice(n,n+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),n+r[0].length):-1}function jo(t,e,n){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),n+r[0].length):-1}function Yo(t,e,n){var r=Eo.exec(e.slice(n,n+1));return r?(t.q=3*r[0]-3,n+r[0].length):-1}function zo(t,e,n){var r=Eo.exec(e.slice(n,n+2));return r?(t.m=r[0]-1,n+r[0].length):-1}function Uo(t,e,n){var r=Eo.exec(e.slice(n,n+2));return r?(t.d=+r[0],n+r[0].length):-1}function qo(t,e,n){var r=Eo.exec(e.slice(n,n+3));return r?(t.m=0,t.d=+r[0],n+r[0].length):-1}function Ho(t,e,n){var r=Eo.exec(e.slice(n,n+2));return r?(t.H=+r[0],n+r[0].length):-1}function $o(t,e,n){var r=Eo.exec(e.slice(n,n+2));return r?(t.M=+r[0],n+r[0].length):-1}function Wo(t,e,n){var r=Eo.exec(e.slice(n,n+2));return r?(t.S=+r[0],n+r[0].length):-1}function Vo(t,e,n){var r=Eo.exec(e.slice(n,n+3));return r?(t.L=+r[0],n+r[0].length):-1}function Go(t,e,n){var r=Eo.exec(e.slice(n,n+6));return r?(t.L=Math.floor(r[0]/1e3),n+r[0].length):-1}function Xo(t,e,n){var r=Co.exec(e.slice(n,n+1));return r?n+r[0].length:-1}function Zo(t,e,n){var r=Eo.exec(e.slice(n));return r?(t.Q=+r[0],n+r[0].length):-1}function Qo(t,e,n){var r=Eo.exec(e.slice(n));return r?(t.s=+r[0],n+r[0].length):-1}function Ko(t,e){return Ao(t.getDate(),e,2)}function Jo(t,e){return Ao(t.getHours(),e,2)}function ts(t,e){return Ao(t.getHours()%12||12,e,2)}function es(t,e){return Ao(1+Ra.count(Ga(t),t),e,3)}function ns(t,e){return Ao(t.getMilliseconds(),e,3)}function rs(t,e){return ns(t,e)+"000"}function is(t,e){return Ao(t.getMonth()+1,e,2)}function as(t,e){return Ao(t.getMinutes(),e,2)}function os(t,e){return Ao(t.getSeconds(),e,2)}function ss(t){var e=t.getDay();return 0===e?7:e}function cs(t,e){return Ao(Pa.count(Ga(t)-1,t),e,2)}function us(t){var e=t.getDay();return e>=4||0===e?Ua(t):Ua.ceil(t)}function ls(t,e){return t=us(t),Ao(Ua.count(Ga(t),t)+(4===Ga(t).getDay()),e,2)}function hs(t){return t.getDay()}function fs(t,e){return Ao(ja.count(Ga(t)-1,t),e,2)}function ds(t,e){return Ao(t.getFullYear()%100,e,2)}function ps(t,e){return Ao((t=us(t)).getFullYear()%100,e,2)}function ys(t,e){return Ao(t.getFullYear()%1e4,e,4)}function gs(t,e){var n=t.getDay();return Ao((t=n>=4||0===n?Ua(t):Ua.ceil(t)).getFullYear()%1e4,e,4)}function ms(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+Ao(e/60|0,"0",2)+Ao(e%60,"0",2)}function vs(t,e){return Ao(t.getUTCDate(),e,2)}function bs(t,e){return Ao(t.getUTCHours(),e,2)}function _s(t,e){return Ao(t.getUTCHours()%12||12,e,2)}function xs(t,e){return Ao(1+to.count(fo(t),t),e,3)}function ws(t,e){return Ao(t.getUTCMilliseconds(),e,3)}function ks(t,e){return ws(t,e)+"000"}function Ts(t,e){return Ao(t.getUTCMonth()+1,e,2)}function Es(t,e){return Ao(t.getUTCMinutes(),e,2)}function Cs(t,e){return Ao(t.getUTCSeconds(),e,2)}function Ss(t){var e=t.getUTCDay();return 0===e?7:e}function As(t,e){return Ao(no.count(fo(t)-1,t),e,2)}function Ms(t){var e=t.getUTCDay();return e>=4||0===e?oo(t):oo.ceil(t)}function Ns(t,e){return t=Ms(t),Ao(oo.count(fo(t),t)+(4===fo(t).getUTCDay()),e,2)}function Ds(t){return t.getUTCDay()}function Os(t,e){return Ao(ro.count(fo(t)-1,t),e,2)}function Bs(t,e){return Ao(t.getUTCFullYear()%100,e,2)}function Ls(t,e){return Ao((t=Ms(t)).getUTCFullYear()%100,e,2)}function Is(t,e){return Ao(t.getUTCFullYear()%1e4,e,4)}function Rs(t,e){var n=t.getUTCDay();return Ao((t=n>=4||0===n?oo(t):oo.ceil(t)).getUTCFullYear()%1e4,e,4)}function Fs(){return"+0000"}function Ps(){return"%"}function js(t){return+t}function Ys(t){return Math.floor(+t/1e3)}function zs(t){return new Date(t)}function Us(t){return t instanceof Date?+t:+new Date(+t)}function qs(t,e,n,r,i,a,o,s,c,u){var l=Xi(),h=l.invert,f=l.domain,d=u(".%L"),p=u(":%S"),y=u("%I:%M"),g=u("%I %p"),m=u("%a %d"),v=u("%b %d"),b=u("%B"),_=u("%Y");function x(t){return(c(t)=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:js,s:Ys,S:os,u:ss,U:cs,V:ls,w:hs,W:fs,x:null,X:null,y:ds,Y:ys,Z:ms,"%":Ps},_={a:function(t){return o[t.getUTCDay()]},A:function(t){return a[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return s[t.getUTCMonth()]},c:null,d:vs,e:vs,f:ks,g:Ls,G:Rs,H:bs,I:_s,j:xs,L:ws,m:Ts,M:Es,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:js,s:Ys,S:Cs,u:Ss,U:As,V:Ns,w:Ds,W:Os,x:null,X:null,y:Bs,Y:Is,Z:Fs,"%":Ps},x={a:function(t,e,n){var r=d.exec(e.slice(n));return r?(t.w=p.get(r[0].toLowerCase()),n+r[0].length):-1},A:function(t,e,n){var r=h.exec(e.slice(n));return r?(t.w=f.get(r[0].toLowerCase()),n+r[0].length):-1},b:function(t,e,n){var r=m.exec(e.slice(n));return r?(t.m=v.get(r[0].toLowerCase()),n+r[0].length):-1},B:function(t,e,n){var r=y.exec(e.slice(n));return r?(t.m=g.get(r[0].toLowerCase()),n+r[0].length):-1},c:function(t,n,r){return T(t,e,n,r)},d:Uo,e:Uo,f:Go,g:Po,G:Fo,H:Ho,I:Ho,j:qo,L:Vo,m:zo,M:$o,p:function(t,e,n){var r=u.exec(e.slice(n));return r?(t.p=l.get(r[0].toLowerCase()),n+r[0].length):-1},q:Yo,Q:Zo,s:Qo,S:Wo,u:Bo,U:Lo,V:Io,w:Oo,W:Ro,x:function(t,e,r){return T(t,n,e,r)},X:function(t,e,n){return T(t,r,e,n)},y:Po,Y:Fo,Z:jo,"%":Xo};function w(t,e){return function(n){var r,i,a,o=[],s=-1,c=0,u=t.length;for(n instanceof Date||(n=new Date(+n));++s53)return null;"w"in a||(a.w=1),"Z"in a?(i=(r=_o(xo(a.y,0,1))).getUTCDay(),r=i>4||0===i?ro.ceil(r):ro(r),r=to.offset(r,7*(a.V-1)),a.y=r.getUTCFullYear(),a.m=r.getUTCMonth(),a.d=r.getUTCDate()+(a.w+6)%7):(i=(r=bo(xo(a.y,0,1))).getDay(),r=i>4||0===i?ja.ceil(r):ja(r),r=Ra.offset(r,7*(a.V-1)),a.y=r.getFullYear(),a.m=r.getMonth(),a.d=r.getDate()+(a.w+6)%7)}else("W"in a||"U"in a)&&("w"in a||(a.w="u"in a?a.u%7:"W"in a?1:0),i="Z"in a?_o(xo(a.y,0,1)).getUTCDay():bo(xo(a.y,0,1)).getDay(),a.m=0,a.d="W"in a?(a.w+6)%7+7*a.W-(i+5)%7:a.w+7*a.U-(i+6)%7);return"Z"in a?(a.H+=a.Z/100|0,a.M+=a.Z%100,_o(a)):bo(a)}}function T(t,e,n,r){for(var i,a,o=0,s=e.length,c=n.length;o=c)return-1;if(37===(i=e.charCodeAt(o++))){if(i=e.charAt(o++),!(a=x[i in To?e.charAt(o++):i])||(r=a(t,n,r))<0)return-1}else if(i!=n.charCodeAt(r++))return-1}return r}return b.x=w(n,b),b.X=w(r,b),b.c=w(e,b),_.x=w(n,_),_.X=w(r,_),_.c=w(e,_),{format:function(t){var e=w(t+="",b);return e.toString=function(){return t},e},parse:function(t){var e=k(t+="",!1);return e.toString=function(){return t},e},utcFormat:function(t){var e=w(t+="",_);return e.toString=function(){return t},e},utcParse:function(t){var e=k(t+="",!0);return e.toString=function(){return t},e}}}({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}),ko=wo.format,wo.parse,wo.utcFormat,wo.utcParse;var Qs=Array.prototype.find;function Ks(){return this.firstElementChild}var Js=Array.prototype.filter;function tc(){return Array.from(this.children)}function ec(t){return new Array(t.length)}function nc(t,e){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=e}function rc(t){return function(){return t}}function ic(t,e,n,r,i,a){for(var o,s=0,c=e.length,u=a.length;se?1:t>=e?0:NaN}nc.prototype={constructor:nc,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,e){return this._parent.insertBefore(t,e)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var uc="http://www.w3.org/1999/xhtml";const lc={svg:"http://www.w3.org/2000/svg",xhtml:uc,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function hc(t){var e=t+="",n=e.indexOf(":");return n>=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),lc.hasOwnProperty(e)?{space:lc[e],local:t}:t}function fc(t){return function(){this.removeAttribute(t)}}function dc(t){return function(){this.removeAttributeNS(t.space,t.local)}}function pc(t,e){return function(){this.setAttribute(t,e)}}function yc(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function gc(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttribute(t):this.setAttribute(t,n)}}function mc(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}function vc(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function bc(t){return function(){this.style.removeProperty(t)}}function _c(t,e,n){return function(){this.style.setProperty(t,e,n)}}function xc(t,e,n){return function(){var r=e.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,n)}}function wc(t,e){return t.style.getPropertyValue(e)||vc(t).getComputedStyle(t,null).getPropertyValue(e)}function kc(t){return function(){delete this[t]}}function Tc(t,e){return function(){this[t]=e}}function Ec(t,e){return function(){var n=e.apply(this,arguments);null==n?delete this[t]:this[t]=n}}function Cc(t){return t.trim().split(/^|\s+/)}function Sc(t){return t.classList||new Ac(t)}function Ac(t){this._node=t,this._names=Cc(t.getAttribute("class")||"")}function Mc(t,e){for(var n=Sc(t),r=-1,i=e.length;++r=0&&(e=t.slice(n+1),t=t.slice(0,n)),{type:t,name:e}}))}function Zc(t){return function(){var e=this.__on;if(e){for(var n,r=0,i=-1,a=e.length;r=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var eu=[null];function nu(t,e){this._groups=t,this._parents=e}function ru(){return new nu([[document.documentElement]],eu)}nu.prototype=ru.prototype={constructor:nu,select:function(t){"function"!=typeof t&&(t=$s(t));for(var e=this._groups,n=e.length,r=new Array(n),i=0;i=x&&(x=_+1);!(b=g[x])&&++x=0;)(r=i[a])&&(o&&4^r.compareDocumentPosition(o)&&o.parentNode.insertBefore(r,o),o=r);return this},sort:function(t){function e(e,n){return e&&n?t(e.__data__,n.__data__):!e-!n}t||(t=cc);for(var n=this._groups,r=n.length,i=new Array(r),a=0;a1?this.each((null==e?bc:"function"==typeof e?xc:_c)(t,e,null==n?"":n)):wc(this.node(),t)},property:function(t,e){return arguments.length>1?this.each((null==e?kc:"function"==typeof e?Ec:Tc)(t,e)):this.node()[t]},classed:function(t,e){var n=Cc(t+"");if(arguments.length<2){for(var r=Sc(this.node()),i=-1,a=n.length;++iuu)if(Math.abs(l*s-c*u)>uu&&i){var f=n-a,d=r-o,p=s*s+c*c,y=f*f+d*d,g=Math.sqrt(p),m=Math.sqrt(h),v=i*Math.tan((su-Math.acos((p+h-y)/(2*g*m)))/2),b=v/m,_=v/g;Math.abs(b-1)>uu&&(this._+="L"+(t+b*u)+","+(e+b*l)),this._+="A"+i+","+i+",0,0,"+ +(l*f>u*d)+","+(this._x1=t+_*s)+","+(this._y1=e+_*c)}else this._+="L"+(this._x1=t)+","+(this._y1=e)},arc:function(t,e,n,r,i,a){t=+t,e=+e,a=!!a;var o=(n=+n)*Math.cos(r),s=n*Math.sin(r),c=t+o,u=e+s,l=1^a,h=a?r-i:i-r;if(n<0)throw new Error("negative radius: "+n);null===this._x1?this._+="M"+c+","+u:(Math.abs(this._x1-c)>uu||Math.abs(this._y1-u)>uu)&&(this._+="L"+c+","+u),n&&(h<0&&(h=h%cu+cu),h>lu?this._+="A"+n+","+n+",0,1,"+l+","+(t-o)+","+(e-s)+"A"+n+","+n+",0,1,"+l+","+(this._x1=c)+","+(this._y1=u):h>uu&&(this._+="A"+n+","+n+",0,"+ +(h>=su)+","+l+","+(this._x1=t+n*Math.cos(i))+","+(this._y1=e+n*Math.sin(i))))},rect:function(t,e,n,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)+"h"+ +n+"v"+ +r+"h"+-n+"Z"},toString:function(){return this._}};const du=fu;function pu(t){return function(){return t}}var yu=Math.abs,gu=Math.atan2,mu=Math.cos,vu=Math.max,bu=Math.min,_u=Math.sin,xu=Math.sqrt,wu=1e-12,ku=Math.PI,Tu=ku/2,Eu=2*ku;function Cu(t){return t>1?0:t<-1?ku:Math.acos(t)}function Su(t){return t>=1?Tu:t<=-1?-Tu:Math.asin(t)}function Au(t){return t.innerRadius}function Mu(t){return t.outerRadius}function Nu(t){return t.startAngle}function Du(t){return t.endAngle}function Ou(t){return t&&t.padAngle}function Bu(t,e,n,r,i,a,o,s){var c=n-t,u=r-e,l=o-i,h=s-a,f=h*c-l*u;if(!(f*fN*N+D*D&&(T=C,E=S),{cx:T,cy:E,x01:-l,y01:-h,x11:T*(i/x-1),y11:E*(i/x-1)}}function Iu(){var t=Au,e=Mu,n=pu(0),r=null,i=Nu,a=Du,o=Ou,s=null;function c(){var c,u,l=+t.apply(this,arguments),h=+e.apply(this,arguments),f=i.apply(this,arguments)-Tu,d=a.apply(this,arguments)-Tu,p=yu(d-f),y=d>f;if(s||(s=c=du()),hwu)if(p>Eu-wu)s.moveTo(h*mu(f),h*_u(f)),s.arc(0,0,h,f,d,!y),l>wu&&(s.moveTo(l*mu(d),l*_u(d)),s.arc(0,0,l,d,f,y));else{var g,m,v=f,b=d,_=f,x=d,w=p,k=p,T=o.apply(this,arguments)/2,E=T>wu&&(r?+r.apply(this,arguments):xu(l*l+h*h)),C=bu(yu(h-l)/2,+n.apply(this,arguments)),S=C,A=C;if(E>wu){var M=Su(E/l*_u(T)),N=Su(E/h*_u(T));(w-=2*M)>wu?(_+=M*=y?1:-1,x-=M):(w=0,_=x=(f+d)/2),(k-=2*N)>wu?(v+=N*=y?1:-1,b-=N):(k=0,v=b=(f+d)/2)}var D=h*mu(v),O=h*_u(v),B=l*mu(x),L=l*_u(x);if(C>wu){var I,R=h*mu(b),F=h*_u(b),P=l*mu(_),j=l*_u(_);if(pwu?A>wu?(g=Lu(P,j,D,O,h,A,y),m=Lu(R,F,B,L,h,A,y),s.moveTo(g.cx+g.x01,g.cy+g.y01),Awu&&w>wu?S>wu?(g=Lu(B,L,R,F,l,-S,y),m=Lu(D,O,P,j,l,-S,y),s.lineTo(g.cx+g.x01,g.cy+g.y01),St?1:e>=t?0:NaN}function qu(t){return t}function Hu(){}function $u(t,e,n){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+e)/6,(t._y0+4*t._y1+n)/6)}function Wu(t){this._context=t}function Vu(t){return new Wu(t)}function Gu(t){this._context=t}function Xu(t){this._context=t}function Zu(t){this._context=t}function Qu(t){return t<0?-1:1}function Ku(t,e,n){var r=t._x1-t._x0,i=e-t._x1,a=(t._y1-t._y0)/(r||i<0&&-0),o=(n-t._y1)/(i||r<0&&-0),s=(a*i+o*r)/(r+i);return(Qu(a)+Qu(o))*Math.min(Math.abs(a),Math.abs(o),.5*Math.abs(s))||0}function Ju(t,e){var n=t._x1-t._x0;return n?(3*(t._y1-t._y0)/n-e)/2:e}function tl(t,e,n){var r=t._x0,i=t._y0,a=t._x1,o=t._y1,s=(a-r)/3;t._context.bezierCurveTo(r+s,i+s*e,a-s,o-s*n,a,o)}function el(t){this._context=t}function nl(t){this._context=new rl(t)}function rl(t){this._context=t}function il(t){this._context=t}function al(t){var e,n,r=t.length-1,i=new Array(r),a=new Array(r),o=new Array(r);for(i[0]=0,a[0]=2,o[0]=t[0]+2*t[1],e=1;e=0;--e)i[e]=(o[e]-i[e+1])/a[e];for(a[r-1]=(t[r]+i[r-1])/2,e=0;e=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,e),this._context.lineTo(t,e);else{var n=this._x*(1-this._t)+t*this._t;this._context.lineTo(n,this._y),this._context.lineTo(n,e)}}this._x=t,this._y=e}};var sl=new Date,cl=new Date;function ul(t,e,n,r){function i(e){return t(e=0===arguments.length?new Date:new Date(+e)),e}return i.floor=function(e){return t(e=new Date(+e)),e},i.ceil=function(n){return t(n=new Date(n-1)),e(n,1),t(n),n},i.round=function(t){var e=i(t),n=i.ceil(t);return t-e0))return s;do{s.push(o=new Date(+n)),e(n,a),t(n)}while(o=e)for(;t(e),!n(e);)e.setTime(e-1)}),(function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;e(t,-1),!n(t););else for(;--r>=0;)for(;e(t,1),!n(t););}))},n&&(i.count=function(e,r){return sl.setTime(+e),cl.setTime(+r),t(sl),t(cl),Math.floor(n(sl,cl))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(e){return r(e)%t==0}:function(e){return i.count(0,e)%t==0}):i:null}),i}const ll=864e5,hl=6048e5;function fl(t){return ul((function(e){e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+7*e)}),(function(t,e){return(e-t)/hl}))}var dl=fl(0),pl=fl(1),yl=fl(2),gl=fl(3),ml=fl(4),vl=fl(5),bl=fl(6),_l=(dl.range,pl.range,yl.range,gl.range,ml.range,vl.range,bl.range,ul((function(t){t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+e)}),(function(t,e){return(e-t)/ll}),(function(t){return t.getUTCDate()-1})));const xl=_l;function wl(t){return ul((function(e){e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)}),(function(t,e){t.setDate(t.getDate()+7*e)}),(function(t,e){return(e-t-6e4*(e.getTimezoneOffset()-t.getTimezoneOffset()))/hl}))}_l.range;var kl=wl(0),Tl=wl(1),El=wl(2),Cl=wl(3),Sl=wl(4),Al=wl(5),Ml=wl(6),Nl=(kl.range,Tl.range,El.range,Cl.range,Sl.range,Al.range,Ml.range,ul((t=>t.setHours(0,0,0,0)),((t,e)=>t.setDate(t.getDate()+e)),((t,e)=>(e-t-6e4*(e.getTimezoneOffset()-t.getTimezoneOffset()))/ll),(t=>t.getDate()-1)));const Dl=Nl;Nl.range;var Ol=ul((function(t){t.setMonth(0,1),t.setHours(0,0,0,0)}),(function(t,e){t.setFullYear(t.getFullYear()+e)}),(function(t,e){return e.getFullYear()-t.getFullYear()}),(function(t){return t.getFullYear()}));Ol.every=function(t){return isFinite(t=Math.floor(t))&&t>0?ul((function(e){e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)}),(function(e,n){e.setFullYear(e.getFullYear()+n*t)})):null};const Bl=Ol;Ol.range;var Ll=ul((function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCFullYear(t.getUTCFullYear()+e)}),(function(t,e){return e.getUTCFullYear()-t.getUTCFullYear()}),(function(t){return t.getUTCFullYear()}));Ll.every=function(t){return isFinite(t=Math.floor(t))&&t>0?ul((function(e){e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)}),(function(e,n){e.setUTCFullYear(e.getUTCFullYear()+n*t)})):null};const Il=Ll;function Rl(t){if(0<=t.y&&t.y<100){var e=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return e.setFullYear(t.y),e}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function Fl(t){if(0<=t.y&&t.y<100){var e=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return e.setUTCFullYear(t.y),e}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Pl(t,e,n){return{y:t,m:e,d:n,H:0,M:0,S:0,L:0}}Ll.range;var jl,Yl,zl={"-":"",_:" ",0:"0"},Ul=/^\s*\d+/,ql=/^%/,Hl=/[\\^$*+?|[\]().{}]/g;function $l(t,e,n){var r=t<0?"-":"",i=(r?-t:t)+"",a=i.length;return r+(a[t.toLowerCase(),e])))}function Xl(t,e,n){var r=Ul.exec(e.slice(n,n+1));return r?(t.w=+r[0],n+r[0].length):-1}function Zl(t,e,n){var r=Ul.exec(e.slice(n,n+1));return r?(t.u=+r[0],n+r[0].length):-1}function Ql(t,e,n){var r=Ul.exec(e.slice(n,n+2));return r?(t.U=+r[0],n+r[0].length):-1}function Kl(t,e,n){var r=Ul.exec(e.slice(n,n+2));return r?(t.V=+r[0],n+r[0].length):-1}function Jl(t,e,n){var r=Ul.exec(e.slice(n,n+2));return r?(t.W=+r[0],n+r[0].length):-1}function th(t,e,n){var r=Ul.exec(e.slice(n,n+4));return r?(t.y=+r[0],n+r[0].length):-1}function eh(t,e,n){var r=Ul.exec(e.slice(n,n+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),n+r[0].length):-1}function nh(t,e,n){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),n+r[0].length):-1}function rh(t,e,n){var r=Ul.exec(e.slice(n,n+1));return r?(t.q=3*r[0]-3,n+r[0].length):-1}function ih(t,e,n){var r=Ul.exec(e.slice(n,n+2));return r?(t.m=r[0]-1,n+r[0].length):-1}function ah(t,e,n){var r=Ul.exec(e.slice(n,n+2));return r?(t.d=+r[0],n+r[0].length):-1}function oh(t,e,n){var r=Ul.exec(e.slice(n,n+3));return r?(t.m=0,t.d=+r[0],n+r[0].length):-1}function sh(t,e,n){var r=Ul.exec(e.slice(n,n+2));return r?(t.H=+r[0],n+r[0].length):-1}function ch(t,e,n){var r=Ul.exec(e.slice(n,n+2));return r?(t.M=+r[0],n+r[0].length):-1}function uh(t,e,n){var r=Ul.exec(e.slice(n,n+2));return r?(t.S=+r[0],n+r[0].length):-1}function lh(t,e,n){var r=Ul.exec(e.slice(n,n+3));return r?(t.L=+r[0],n+r[0].length):-1}function hh(t,e,n){var r=Ul.exec(e.slice(n,n+6));return r?(t.L=Math.floor(r[0]/1e3),n+r[0].length):-1}function fh(t,e,n){var r=ql.exec(e.slice(n,n+1));return r?n+r[0].length:-1}function dh(t,e,n){var r=Ul.exec(e.slice(n));return r?(t.Q=+r[0],n+r[0].length):-1}function ph(t,e,n){var r=Ul.exec(e.slice(n));return r?(t.s=+r[0],n+r[0].length):-1}function yh(t,e){return $l(t.getDate(),e,2)}function gh(t,e){return $l(t.getHours(),e,2)}function mh(t,e){return $l(t.getHours()%12||12,e,2)}function vh(t,e){return $l(1+Dl.count(Bl(t),t),e,3)}function bh(t,e){return $l(t.getMilliseconds(),e,3)}function _h(t,e){return bh(t,e)+"000"}function xh(t,e){return $l(t.getMonth()+1,e,2)}function wh(t,e){return $l(t.getMinutes(),e,2)}function kh(t,e){return $l(t.getSeconds(),e,2)}function Th(t){var e=t.getDay();return 0===e?7:e}function Eh(t,e){return $l(kl.count(Bl(t)-1,t),e,2)}function Ch(t){var e=t.getDay();return e>=4||0===e?Sl(t):Sl.ceil(t)}function Sh(t,e){return t=Ch(t),$l(Sl.count(Bl(t),t)+(4===Bl(t).getDay()),e,2)}function Ah(t){return t.getDay()}function Mh(t,e){return $l(Tl.count(Bl(t)-1,t),e,2)}function Nh(t,e){return $l(t.getFullYear()%100,e,2)}function Dh(t,e){return $l((t=Ch(t)).getFullYear()%100,e,2)}function Oh(t,e){return $l(t.getFullYear()%1e4,e,4)}function Bh(t,e){var n=t.getDay();return $l((t=n>=4||0===n?Sl(t):Sl.ceil(t)).getFullYear()%1e4,e,4)}function Lh(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+$l(e/60|0,"0",2)+$l(e%60,"0",2)}function Ih(t,e){return $l(t.getUTCDate(),e,2)}function Rh(t,e){return $l(t.getUTCHours(),e,2)}function Fh(t,e){return $l(t.getUTCHours()%12||12,e,2)}function Ph(t,e){return $l(1+xl.count(Il(t),t),e,3)}function jh(t,e){return $l(t.getUTCMilliseconds(),e,3)}function Yh(t,e){return jh(t,e)+"000"}function zh(t,e){return $l(t.getUTCMonth()+1,e,2)}function Uh(t,e){return $l(t.getUTCMinutes(),e,2)}function qh(t,e){return $l(t.getUTCSeconds(),e,2)}function Hh(t){var e=t.getUTCDay();return 0===e?7:e}function $h(t,e){return $l(dl.count(Il(t)-1,t),e,2)}function Wh(t){var e=t.getUTCDay();return e>=4||0===e?ml(t):ml.ceil(t)}function Vh(t,e){return t=Wh(t),$l(ml.count(Il(t),t)+(4===Il(t).getUTCDay()),e,2)}function Gh(t){return t.getUTCDay()}function Xh(t,e){return $l(pl.count(Il(t)-1,t),e,2)}function Zh(t,e){return $l(t.getUTCFullYear()%100,e,2)}function Qh(t,e){return $l((t=Wh(t)).getUTCFullYear()%100,e,2)}function Kh(t,e){return $l(t.getUTCFullYear()%1e4,e,4)}function Jh(t,e){var n=t.getUTCDay();return $l((t=n>=4||0===n?ml(t):ml.ceil(t)).getUTCFullYear()%1e4,e,4)}function tf(){return"+0000"}function ef(){return"%"}function nf(t){return+t}function rf(t){return Math.floor(+t/1e3)}jl=function(t){var e=t.dateTime,n=t.date,r=t.time,i=t.periods,a=t.days,o=t.shortDays,s=t.months,c=t.shortMonths,u=Vl(i),l=Gl(i),h=Vl(a),f=Gl(a),d=Vl(o),p=Gl(o),y=Vl(s),g=Gl(s),m=Vl(c),v=Gl(c),b={a:function(t){return o[t.getDay()]},A:function(t){return a[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return s[t.getMonth()]},c:null,d:yh,e:yh,f:_h,g:Dh,G:Bh,H:gh,I:mh,j:vh,L:bh,m:xh,M:wh,p:function(t){return i[+(t.getHours()>=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:nf,s:rf,S:kh,u:Th,U:Eh,V:Sh,w:Ah,W:Mh,x:null,X:null,y:Nh,Y:Oh,Z:Lh,"%":ef},_={a:function(t){return o[t.getUTCDay()]},A:function(t){return a[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return s[t.getUTCMonth()]},c:null,d:Ih,e:Ih,f:Yh,g:Qh,G:Jh,H:Rh,I:Fh,j:Ph,L:jh,m:zh,M:Uh,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:nf,s:rf,S:qh,u:Hh,U:$h,V:Vh,w:Gh,W:Xh,x:null,X:null,y:Zh,Y:Kh,Z:tf,"%":ef},x={a:function(t,e,n){var r=d.exec(e.slice(n));return r?(t.w=p.get(r[0].toLowerCase()),n+r[0].length):-1},A:function(t,e,n){var r=h.exec(e.slice(n));return r?(t.w=f.get(r[0].toLowerCase()),n+r[0].length):-1},b:function(t,e,n){var r=m.exec(e.slice(n));return r?(t.m=v.get(r[0].toLowerCase()),n+r[0].length):-1},B:function(t,e,n){var r=y.exec(e.slice(n));return r?(t.m=g.get(r[0].toLowerCase()),n+r[0].length):-1},c:function(t,n,r){return T(t,e,n,r)},d:ah,e:ah,f:hh,g:eh,G:th,H:sh,I:sh,j:oh,L:lh,m:ih,M:ch,p:function(t,e,n){var r=u.exec(e.slice(n));return r?(t.p=l.get(r[0].toLowerCase()),n+r[0].length):-1},q:rh,Q:dh,s:ph,S:uh,u:Zl,U:Ql,V:Kl,w:Xl,W:Jl,x:function(t,e,r){return T(t,n,e,r)},X:function(t,e,n){return T(t,r,e,n)},y:eh,Y:th,Z:nh,"%":fh};function w(t,e){return function(n){var r,i,a,o=[],s=-1,c=0,u=t.length;for(n instanceof Date||(n=new Date(+n));++s53)return null;"w"in a||(a.w=1),"Z"in a?(i=(r=Fl(Pl(a.y,0,1))).getUTCDay(),r=i>4||0===i?pl.ceil(r):pl(r),r=xl.offset(r,7*(a.V-1)),a.y=r.getUTCFullYear(),a.m=r.getUTCMonth(),a.d=r.getUTCDate()+(a.w+6)%7):(i=(r=Rl(Pl(a.y,0,1))).getDay(),r=i>4||0===i?Tl.ceil(r):Tl(r),r=Dl.offset(r,7*(a.V-1)),a.y=r.getFullYear(),a.m=r.getMonth(),a.d=r.getDate()+(a.w+6)%7)}else("W"in a||"U"in a)&&("w"in a||(a.w="u"in a?a.u%7:"W"in a?1:0),i="Z"in a?Fl(Pl(a.y,0,1)).getUTCDay():Rl(Pl(a.y,0,1)).getDay(),a.m=0,a.d="W"in a?(a.w+6)%7+7*a.W-(i+5)%7:a.w+7*a.U-(i+6)%7);return"Z"in a?(a.H+=a.Z/100|0,a.M+=a.Z%100,Fl(a)):Rl(a)}}function T(t,e,n,r){for(var i,a,o=0,s=e.length,c=n.length;o=c)return-1;if(37===(i=e.charCodeAt(o++))){if(i=e.charAt(o++),!(a=x[i in zl?e.charAt(o++):i])||(r=a(t,n,r))<0)return-1}else if(i!=n.charCodeAt(r++))return-1}return r}return b.x=w(n,b),b.X=w(r,b),b.c=w(e,b),_.x=w(n,_),_.X=w(r,_),_.c=w(e,_),{format:function(t){var e=w(t+="",b);return e.toString=function(){return t},e},parse:function(t){var e=k(t+="",!1);return e.toString=function(){return t},e},utcFormat:function(t){var e=w(t+="",_);return e.toString=function(){return t},e},utcParse:function(t){var e=k(t+="",!0);return e.toString=function(){return t},e}}}({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}),Yl=jl.format,jl.parse,jl.utcFormat,jl.utcParse;var af={value:()=>{}};function of(){for(var t,e=0,n=arguments.length,r={};e=0&&(n=t.slice(r+1),t=t.slice(0,r)),t&&!e.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))}function uf(t,e){for(var n,r=0,i=t.length;r0)for(var n,r,i=new Array(n),a=0;a=0&&e._call.call(void 0,t),e=e._next;--pf}()}finally{pf=0,function(){for(var t,e,n=ff,r=1/0;n;)n._call?(r>n._time&&(r=n._time),t=n,n=n._next):(e=n._next,n._next=null,n=t?t._next=e:ff=e);df=t,Af(r)}(),vf=0}}function Sf(){var t=_f.now(),e=t-mf;e>1e3&&(bf-=e,mf=t)}function Af(t){pf||(yf&&(yf=clearTimeout(yf)),t-vf>24?(t<1/0&&(yf=setTimeout(Cf,t-_f.now()-bf)),gf&&(gf=clearInterval(gf))):(gf||(mf=_f.now(),gf=setInterval(Sf,1e3)),pf=1,xf(Cf)))}function Mf(t,e,n){var r=new Tf;return e=null==e?0:+e,r.restart((n=>{r.stop(),t(n+e)}),e,n),r}Tf.prototype=Ef.prototype={constructor:Tf,restart:function(t,e,n){if("function"!=typeof t)throw new TypeError("callback is not a function");n=(null==n?wf():+n)+(null==e?0:+e),this._next||df===this||(df?df._next=this:ff=this,df=this),this._call=t,this._time=n,Af()},stop:function(){this._call&&(this._call=null,this._time=1/0,Af())}};var Nf=hf("start","end","cancel","interrupt"),Df=[];function Of(t,e,n,r,i,a){var o=t.__transition;if(o){if(n in o)return}else t.__transition={};!function(t,e,n){var r,i=t.__transition;function a(c){var u,l,h,f;if(1!==n.state)return s();for(u in i)if((f=i[u]).name===n.name){if(3===f.state)return Mf(a);4===f.state?(f.state=6,f.timer.stop(),f.on.call("interrupt",t,t.__data__,f.index,f.group),delete i[u]):+u0)throw new Error("too late; already scheduled");return n}function Lf(t,e){var n=If(t,e);if(n.state>3)throw new Error("too late; already running");return n}function If(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}function Rf(t,e){return t=+t,e=+e,function(n){return t*(1-n)+e*n}}var Ff,Pf=180/Math.PI,jf={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function Yf(t,e,n,r,i,a){var o,s,c;return(o=Math.sqrt(t*t+e*e))&&(t/=o,e/=o),(c=t*n+e*r)&&(n-=t*c,r-=e*c),(s=Math.sqrt(n*n+r*r))&&(n/=s,r/=s,c/=s),t*r180?e+=360:e-t>180&&(t+=360),a.push({i:n.push(i(n)+"rotate(",null,r)-2,x:Rf(t,e)})):e&&n.push(i(n)+"rotate("+e+r)}(a.rotate,o.rotate,s,c),function(t,e,n,a){t!==e?a.push({i:n.push(i(n)+"skewX(",null,r)-2,x:Rf(t,e)}):e&&n.push(i(n)+"skewX("+e+r)}(a.skewX,o.skewX,s,c),function(t,e,n,r,a,o){if(t!==n||e!==r){var s=a.push(i(a)+"scale(",null,",",null,")");o.push({i:s-4,x:Rf(t,n)},{i:s-2,x:Rf(e,r)})}else 1===n&&1===r||a.push(i(a)+"scale("+n+","+r+")")}(a.scaleX,a.scaleY,o.scaleX,o.scaleY,s,c),a=o=null,function(t){for(var e,n=-1,r=c.length;++n=1?(n=1,e-1):Math.floor(n*e),i=t[r],a=t[r+1],o=r>0?t[r-1]:2*i-a,s=ra&&(i=e.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(n=n[0])===(r=r[0])?s[o]?s[o]+=r:s[++o]=r:(s[++o]=null,c.push({i:o,x:Rf(n,r)})),a=Qf.lastIndex;return a=0&&(t=t.slice(0,e)),!t||"start"===t}))}(e)?Bf:Lf;return function(){var o=a(this,t),s=o.on;s!==r&&(i=(r=s).copy()).on(e,n),o.on=i}}var gd=iu.prototype.constructor;function md(t){return function(){this.style.removeProperty(t)}}function vd(t,e,n){return function(r){this.style.setProperty(t,e.call(this,r),n)}}function bd(t,e,n){var r,i;function a(){var a=e.apply(this,arguments);return a!==i&&(r=(i=a)&&vd(t,a,n)),r}return a._value=e,a}function _d(t){return function(e){this.textContent=t.call(this,e)}}function xd(t){var e,n;function r(){var r=t.apply(this,arguments);return r!==n&&(e=(n=r)&&_d(r)),e}return r._value=t,r}var wd=0;function kd(t,e,n,r){this._groups=t,this._parents=e,this._name=n,this._id=r}function Td(){return++wd}var Ed=iu.prototype;kd.prototype=function(t){return iu().transition(t)}.prototype={constructor:kd,select:function(t){var e=this._name,n=this._id;"function"!=typeof t&&(t=$s(t));for(var r=this._groups,i=r.length,a=new Array(i),o=0;o2&&n.state<5,n.state=6,n.timer.stop(),n.on.call(r?"interrupt":"cancel",t,t.__data__,n.index,n.group),delete a[i]):o=!1;o&&delete t.__transition}}(this,t)}))},iu.prototype.transition=function(t){var e,n;t instanceof kd?(e=t._id,t=t._name):(e=Td(),(n=Cd).time=wf(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,a=0;ae?1:t>=e?0:NaN}Yd.prototype={constructor:Yd,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,e){return this._parent.insertBefore(t,e)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var Vd="http://www.w3.org/1999/xhtml";const Gd={svg:"http://www.w3.org/2000/svg",xhtml:Vd,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function Xd(t){var e=t+="",n=e.indexOf(":");return n>=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),Gd.hasOwnProperty(e)?{space:Gd[e],local:t}:t}function Zd(t){return function(){this.removeAttribute(t)}}function Qd(t){return function(){this.removeAttributeNS(t.space,t.local)}}function Kd(t,e){return function(){this.setAttribute(t,e)}}function Jd(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function tp(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttribute(t):this.setAttribute(t,n)}}function ep(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}function np(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function rp(t){return function(){this.style.removeProperty(t)}}function ip(t,e,n){return function(){this.style.setProperty(t,e,n)}}function ap(t,e,n){return function(){var r=e.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,n)}}function op(t,e){return t.style.getPropertyValue(e)||np(t).getComputedStyle(t,null).getPropertyValue(e)}function sp(t){return function(){delete this[t]}}function cp(t,e){return function(){this[t]=e}}function up(t,e){return function(){var n=e.apply(this,arguments);null==n?delete this[t]:this[t]=n}}function lp(t){return t.trim().split(/^|\s+/)}function hp(t){return t.classList||new fp(t)}function fp(t){this._node=t,this._names=lp(t.getAttribute("class")||"")}function dp(t,e){for(var n=hp(t),r=-1,i=e.length;++r=0&&(e=t.slice(n+1),t=t.slice(0,n)),{type:t,name:e}}))}function Lp(t){return function(){var e=this.__on;if(e){for(var n,r=0,i=-1,a=e.length;r=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var jp=[null];function Yp(t,e){this._groups=t,this._parents=e}function zp(){return new Yp([[document.documentElement]],jp)}Yp.prototype=zp.prototype={constructor:Yp,select:function(t){"function"!=typeof t&&(t=Md(t));for(var e=this._groups,n=e.length,r=new Array(n),i=0;i=x&&(x=_+1);!(b=g[x])&&++x=0;)(r=i[a])&&(o&&4^r.compareDocumentPosition(o)&&o.parentNode.insertBefore(r,o),o=r);return this},sort:function(t){function e(e,n){return e&&n?t(e.__data__,n.__data__):!e-!n}t||(t=Wd);for(var n=this._groups,r=n.length,i=new Array(r),a=0;a1?this.each((null==e?rp:"function"==typeof e?ap:ip)(t,e,null==n?"":n)):op(this.node(),t)},property:function(t,e){return arguments.length>1?this.each((null==e?sp:"function"==typeof e?up:cp)(t,e)):this.node()[t]},classed:function(t,e){var n=lp(t+"");if(arguments.length<2){for(var r=hp(this.node()),i=-1,a=n.length;++i{}};function Hp(){for(var t,e=0,n=arguments.length,r={};e=0&&(n=t.slice(r+1),t=t.slice(0,r)),t&&!e.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))}function Vp(t,e){for(var n,r=0,i=t.length;r0)for(var n,r,i=new Array(n),a=0;a=0&&e._call.call(void 0,t),e=e._next;--Kp}()}finally{Kp=0,function(){for(var t,e,n=Zp,r=1/0;n;)n._call?(r>n._time&&(r=n._time),t=n,n=n._next):(e=n._next,n._next=null,n=t?t._next=e:Zp=e);Qp=t,fy(r)}(),ny=0}}function hy(){var t=iy.now(),e=t-ey;e>1e3&&(ry-=e,ey=t)}function fy(t){Kp||(Jp&&(Jp=clearTimeout(Jp)),t-ny>24?(t<1/0&&(Jp=setTimeout(ly,t-iy.now()-ry)),ty&&(ty=clearInterval(ty))):(ty||(ey=iy.now(),ty=setInterval(hy,1e3)),Kp=1,ay(ly)))}function dy(t,e,n){var r=new cy;return e=null==e?0:+e,r.restart((n=>{r.stop(),t(n+e)}),e,n),r}cy.prototype=uy.prototype={constructor:cy,restart:function(t,e,n){if("function"!=typeof t)throw new TypeError("callback is not a function");n=(null==n?oy():+n)+(null==e?0:+e),this._next||Qp===this||(Qp?Qp._next=this:Zp=this,Qp=this),this._call=t,this._time=n,fy()},stop:function(){this._call&&(this._call=null,this._time=1/0,fy())}};var py=Xp("start","end","cancel","interrupt"),yy=[];function gy(t,e,n,r,i,a){var o=t.__transition;if(o){if(n in o)return}else t.__transition={};!function(t,e,n){var r,i=t.__transition;function a(c){var u,l,h,f;if(1!==n.state)return s();for(u in i)if((f=i[u]).name===n.name){if(3===f.state)return dy(a);4===f.state?(f.state=6,f.timer.stop(),f.on.call("interrupt",t,t.__data__,f.index,f.group),delete i[u]):+u0)throw new Error("too late; already scheduled");return n}function vy(t,e){var n=by(t,e);if(n.state>3)throw new Error("too late; already running");return n}function by(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}function _y(t,e){return t=+t,e=+e,function(n){return t*(1-n)+e*n}}var xy,wy=180/Math.PI,ky={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function Ty(t,e,n,r,i,a){var o,s,c;return(o=Math.sqrt(t*t+e*e))&&(t/=o,e/=o),(c=t*n+e*r)&&(n-=t*c,r-=e*c),(s=Math.sqrt(n*n+r*r))&&(n/=s,r/=s,c/=s),t*r180?e+=360:e-t>180&&(t+=360),a.push({i:n.push(i(n)+"rotate(",null,r)-2,x:_y(t,e)})):e&&n.push(i(n)+"rotate("+e+r)}(a.rotate,o.rotate,s,c),function(t,e,n,a){t!==e?a.push({i:n.push(i(n)+"skewX(",null,r)-2,x:_y(t,e)}):e&&n.push(i(n)+"skewX("+e+r)}(a.skewX,o.skewX,s,c),function(t,e,n,r,a,o){if(t!==n||e!==r){var s=a.push(i(a)+"scale(",null,",",null,")");o.push({i:s-4,x:_y(t,n)},{i:s-2,x:_y(e,r)})}else 1===n&&1===r||a.push(i(a)+"scale("+n+","+r+")")}(a.scaleX,a.scaleY,o.scaleX,o.scaleY,s,c),a=o=null,function(t){for(var e,n=-1,r=c.length;++n>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?Qy(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?Qy(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=Yy.exec(t))?new tg(e[1],e[2],e[3],1):(e=zy.exec(t))?new tg(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=Uy.exec(t))?Qy(e[1],e[2],e[3],e[4]):(e=qy.exec(t))?Qy(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=Hy.exec(t))?ig(e[1],e[2]/100,e[3]/100,1):(e=$y.exec(t))?ig(e[1],e[2]/100,e[3]/100,e[4]):Wy.hasOwnProperty(t)?Zy(Wy[t]):"transparent"===t?new tg(NaN,NaN,NaN,0):null}function Zy(t){return new tg(t>>16&255,t>>8&255,255&t,1)}function Qy(t,e,n,r){return r<=0&&(t=e=n=NaN),new tg(t,e,n,r)}function Ky(t){return t instanceof By||(t=Xy(t)),t?new tg((t=t.rgb()).r,t.g,t.b,t.opacity):new tg}function Jy(t,e,n,r){return 1===arguments.length?Ky(t):new tg(t,e,n,null==r?1:r)}function tg(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function eg(){return"#"+rg(this.r)+rg(this.g)+rg(this.b)}function ng(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function rg(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function ig(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new og(t,e,n,r)}function ag(t){if(t instanceof og)return new og(t.h,t.s,t.l,t.opacity);if(t instanceof By||(t=Xy(t)),!t)return new og;if(t instanceof og)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),a=Math.max(e,n,r),o=NaN,s=a-i,c=(a+i)/2;return s?(o=e===a?(n-r)/s+6*(n0&&c<1?0:o,new og(o,s,c,t.opacity)}function og(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function sg(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}function cg(t,e,n,r,i){var a=t*t,o=a*t;return((1-3*t+3*a-o)*e+(4-6*a+3*o)*n+(1+3*t+3*a-3*o)*r+o*i)/6}Dy(By,Xy,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:Vy,formatHex:Vy,formatHsl:function(){return ag(this).formatHsl()},formatRgb:Gy,toString:Gy}),Dy(tg,Jy,Oy(By,{brighter:function(t){return t=null==t?Iy:Math.pow(Iy,t),new tg(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?Ly:Math.pow(Ly,t),new tg(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:eg,formatHex:eg,formatRgb:ng,toString:ng})),Dy(og,(function(t,e,n,r){return 1===arguments.length?ag(t):new og(t,e,n,null==r?1:r)}),Oy(By,{brighter:function(t){return t=null==t?Iy:Math.pow(Iy,t),new og(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?Ly:Math.pow(Ly,t),new og(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new tg(sg(t>=240?t-240:t+120,i,r),sg(t,i,r),sg(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const ug=t=>()=>t;function lg(t,e){var n=e-t;return n?function(t,e){return function(n){return t+n*e}}(t,n):ug(isNaN(t)?e:t)}const hg=function t(e){var n=function(t){return 1==(t=+t)?lg:function(e,n){return n-e?function(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(r){return Math.pow(t+r*e,n)}}(e,n,t):ug(isNaN(e)?n:e)}}(e);function r(t,e){var r=n((t=Jy(t)).r,(e=Jy(e)).r),i=n(t.g,e.g),a=n(t.b,e.b),o=lg(t.opacity,e.opacity);return function(e){return t.r=r(e),t.g=i(e),t.b=a(e),t.opacity=o(e),t+""}}return r.gamma=t,r}(1);function fg(t){return function(e){var n,r,i=e.length,a=new Array(i),o=new Array(i),s=new Array(i);for(n=0;n=1?(n=1,e-1):Math.floor(n*e),i=t[r],a=t[r+1],o=r>0?t[r-1]:2*i-a,s=ra&&(i=e.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(n=n[0])===(r=r[0])?s[o]?s[o]+=r:s[++o]=r:(s[++o]=null,c.push({i:o,x:_y(n,r)})),a=pg.lastIndex;return a=0&&(t=t.slice(0,e)),!t||"start"===t}))}(e)?my:vy;return function(){var o=a(this,t),s=o.on;s!==r&&(i=(r=s).copy()).on(e,n),o.on=i}}var Bg=Up.prototype.constructor;function Lg(t){return function(){this.style.removeProperty(t)}}function Ig(t,e,n){return function(r){this.style.setProperty(t,e.call(this,r),n)}}function Rg(t,e,n){var r,i;function a(){var a=e.apply(this,arguments);return a!==i&&(r=(i=a)&&Ig(t,a,n)),r}return a._value=e,a}function Fg(t){return function(e){this.textContent=t.call(this,e)}}function Pg(t){var e,n;function r(){var r=t.apply(this,arguments);return r!==n&&(e=(n=r)&&Fg(r)),e}return r._value=t,r}var jg=0;function Yg(t,e,n,r){this._groups=t,this._parents=e,this._name=n,this._id=r}function zg(){return++jg}var Ug=Up.prototype;Yg.prototype=function(t){return Up().transition(t)}.prototype={constructor:Yg,select:function(t){var e=this._name,n=this._id;"function"!=typeof t&&(t=Md(t));for(var r=this._groups,i=r.length,a=new Array(i),o=0;o2&&n.state<5,n.state=6,n.timer.stop(),n.on.call(r?"interrupt":"cancel",t,t.__data__,n.index,n.group),delete a[i]):o=!1;o&&delete t.__transition}}(this,t)}))},Up.prototype.transition=function(t){var e,n;t instanceof Yg?(e=t._id,t=t._name):(e=zg(),(n=qg).time=oy(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,a=0;a0?tm(fm,--lm):0,cm--,10===hm&&(cm=1,sm--),hm}function ym(){return hm=lm2||bm(hm)>3?"":" "}function wm(t,e){for(;--e&&ym()&&!(hm<48||hm>102||hm>57&&hm<65||hm>70&&hm<97););return vm(t,mm()+(e<6&&32==gm()&&32==ym()))}function km(t){for(;ym();)switch(hm){case t:return lm;case 34:case 39:34!==t&&39!==t&&km(hm);break;case 40:41===t&&km(t);break;case 92:ym()}return lm}function Tm(t,e){for(;ym()&&t+hm!==57&&(t+hm!==84||47!==gm()););return"/*"+vm(e,lm-1)+"*"+Zg(47===t?t:ym())}function Em(t){for(;!bm(gm());)ym();return vm(t,lm)}function Cm(t){return function(t){return fm="",t}(Sm("",null,null,null,[""],t=function(t){return sm=cm=1,um=nm(fm=t),lm=0,[]}(t),0,[0],t))}function Sm(t,e,n,r,i,a,o,s,c){for(var u=0,l=0,h=o,f=0,d=0,p=0,y=1,g=1,m=1,v=0,b="",_=i,x=a,w=r,k=b;g;)switch(p=v,v=ym()){case 40:if(108!=p&&58==k.charCodeAt(h-1)){-1!=Jg(k+=Kg(_m(v),"&","&\f"),"&\f")&&(m=-1);break}case 34:case 39:case 91:k+=_m(v);break;case 9:case 10:case 13:case 32:k+=xm(p);break;case 92:k+=wm(mm()-1,7);continue;case 47:switch(gm()){case 42:case 47:im(Mm(Tm(ym(),mm()),e,n),c);break;default:k+="/"}break;case 123*y:s[u++]=nm(k)*m;case 125*y:case 59:case 0:switch(v){case 0:case 125:g=0;case 59+l:d>0&&nm(k)-h&&im(d>32?Nm(k+";",r,n,h-1):Nm(Kg(k," ","")+";",r,n,h-2),c);break;case 59:k+=";";default:if(im(w=Am(k,e,n,u,l,i,s,b,_=[],x=[],h),a),123===v)if(0===l)Sm(k,e,w,w,_,a,h,s,x);else switch(f){case 100:case 109:case 115:Sm(t,w,w,r&&im(Am(t,w,w,0,0,i,s,b,i,_=[],h),x),i,x,h,s,r?_:x);break;default:Sm(k,w,w,w,[""],x,0,s,x)}}u=l=d=0,y=m=1,b=k="",h=o;break;case 58:h=1+nm(k),d=p;default:if(y<1)if(123==v)--y;else if(125==v&&0==y++&&125==pm())continue;switch(k+=Zg(v),v*y){case 38:m=l>0?1:(k+="\f",-1);break;case 44:s[u++]=(nm(k)-1)*m,m=1;break;case 64:45===gm()&&(k+=_m(ym())),f=gm(),l=h=nm(b=k+=Em(mm())),v++;break;case 45:45===p&&2==nm(k)&&(y=0)}}return a}function Am(t,e,n,r,i,a,o,s,c,u,l){for(var h=i-1,f=0===i?a:[""],d=rm(f),p=0,y=0,g=0;p0?f[m]+" "+v:Kg(v,/&\f/g,f[m])))&&(c[g++]=b);return dm(t,e,n,0===i?Vg:s,c,u,l)}function Mm(t,e,n){return dm(t,e,n,Wg,Zg(hm),em(t,2,-2),0)}function Nm(t,e,n,r){return dm(t,e,n,Gg,em(t,0,r),em(t,r+1,-1),r)}const Dm="8.14.0";var Om=n(9609),Bm=n(7856),Lm=n.n(Bm),Im=function(t){var e=t.replace(/\\u[\dA-F]{4}/gi,(function(t){return String.fromCharCode(parseInt(t.replace(/\\u/g,""),16))}));return e=(e=(e=e.replace(/\\x([0-9a-f]{2})/gi,(function(t,e){return String.fromCharCode(parseInt(e,16))}))).replace(/\\[\d\d\d]{3}/gi,(function(t){return String.fromCharCode(parseInt(t.replace(/\\/g,""),8))}))).replace(/\\[\d\d\d]{2}/gi,(function(t){return String.fromCharCode(parseInt(t.replace(/\\/g,""),8))}))},Rm=function(t){for(var e="",n=0;n>=0;){if(!((n=t.indexOf("=0)){e+=t,n=-1;break}e+=t.substr(0,n),(n=(t=t.substr(n+1)).indexOf("<\/script>"))>=0&&(n+=9,t=t.substr(n))}var r=Im(e);return(r=(r=(r=r.replace(/script>/gi,"#")).replace(/javascript:/gi,"#")).replace(/onerror=/gi,"onerror:")).replace(/')}if(void 0!==n)switch(y){case"flowchart":case"flowchart-v2":n(T,gx.bindFunctions);break;case"gantt":n(T,_w.bindFunctions);break;case"class":case"classDiagram":n(T,bb.bindFunctions);break;default:n(T)}else o.debug("CB = undefined!");nT.forEach((function(t){t()})),nT=[];var S="sandbox"===s.securityLevel?"#i"+t:"#d"+t,A=au(S).node();return null!==A&&"function"==typeof A.remove&&au(S).node().remove(),T},parse:function(t){var e=Jv(),n=Hv.detectInit(t,e);n&&o.debug("reinit ",n);var r,i=Hv.detectType(t,e);switch(o.debug("Type "+i),i){case"git":(r=zw()).parser.yy=Pw;break;case"flowchart":case"flowchart-v2":gx.clear(),(r=vx()).parser.yy=gx;break;case"sequence":(r=Bk()).parser.yy=eT;break;case"gantt":(r=Tw()).parser.yy=_w;break;case"class":case"classDiagram":(r=Eb()).parser.yy=bb;break;case"state":case"stateDiagram":(r=VT()).parser.yy=cE;break;case"info":o.debug("info info info"),(r=nk()).parser.yy=tk;break;case"pie":o.debug("pie"),(r=ok()).parser.yy=lk;break;case"er":o.debug("er"),(r=R_()).parser.yy=L_;break;case"journey":o.debug("Journey"),(r=RE()).parser.yy=LE;break;case"requirement":case"requirementDiagram":o.debug("RequirementDiagram"),(r=yk()).parser.yy=xk}return r.parser.yy.graphType=i,r.parser.yy.parseError=function(t,e){throw{str:t,hash:e}},r.parse(t),r},parseDirective:function(t,e,n,r){try{if(void 0!==e)switch(e=e.trim(),n){case"open_directive":oC={};break;case"type_directive":oC.type=e.toLowerCase();break;case"arg_directive":oC.args=JSON.parse(e);break;case"close_directive":(function(t,e,n){switch(o.debug("Directive type=".concat(e.type," with args:"),e.args),e.type){case"init":case"initialize":["config"].forEach((function(t){void 0!==e.args[t]&&("flowchart-v2"===n&&(n="flowchart"),e.args[n]=e.args[t],delete e.args[t])})),o.debug("sanitize in handleDirective",e.args),Uv(e.args),o.debug("sanitize in handleDirective (done)",e.args),e.args,eb(e.args);break;case"wrap":case"nowrap":t&&t.setWrap&&t.setWrap("wrap"===e.type);break;case"themeCss":o.warn("themeCss encountered");break;default:o.warn("Unhandled directive: source: '%%{".concat(e.type,": ").concat(JSON.stringify(e.args?e.args:{}),"}%%"),e)}})(t,oC,r),oC=null}}catch(t){o.error("Error while rendering sequenceDiagram directive: ".concat(e," jison context: ").concat(n)),o.error(t.message)}},initialize:function(t){t&&t.fontFamily&&(t.themeVariables&&t.themeVariables.fontFamily||(t.themeVariables={fontFamily:t.fontFamily})),function(t){Wv=Lv({},t)}(t),t&&t.theme&&ov[t.theme]?t.themeVariables=ov[t.theme].getThemeVariables(t.themeVariables):t&&(t.themeVariables=ov.default.getThemeVariables(t.themeVariables));var e="object"===iC(t)?function(t){return Gv=Lv({},Vv),Gv=Lv(Gv,t),t.theme&&(Gv.themeVariables=ov[t.theme].getThemeVariables(t.themeVariables)),Zv=Qv(Gv,Xv),Gv}(t):Kv();sC(e),s(e.logLevel)},reinitialize:function(){},getConfig:Jv,setConfig:function(t){return Lv(Zv,t),Jv()},getSiteConfig:Kv,updateSiteConfig:function(t){return Gv=Lv(Gv,t),Qv(Gv,Xv),Gv},reset:function(){nb()},globalReset:function(){nb(),sC(Jv())},defaultConfig:Vv});s(Jv().logLevel),nb(Jv());const uC=cC;var lC=function(){hC.startOnLoad?uC.getConfig().startOnLoad&&hC.init():void 0===hC.startOnLoad&&(o.debug("In start, no config"),uC.getConfig().startOnLoad&&hC.init())};"undefined"!=typeof document&&window.addEventListener("load",(function(){lC()}),!1);var hC={startOnLoad:!0,htmlLabels:!0,mermaidAPI:uC,parse:uC.parse,render:uC.render,init:function(){var t,e,n=this,r=uC.getConfig();arguments.length>=2?(void 0!==arguments[0]&&(hC.sequenceConfig=arguments[0]),t=arguments[1]):t=arguments[0],"function"==typeof arguments[arguments.length-1]?(e=arguments[arguments.length-1],o.debug("Callback function found")):void 0!==r.mermaid&&("function"==typeof r.mermaid.callback?(e=r.mermaid.callback,o.debug("Callback function found")):o.debug("No Callback function found")),t=void 0===t?document.querySelectorAll(".mermaid"):"string"==typeof t?document.querySelectorAll(t):t instanceof window.Node?[t]:t,o.debug("Start On Load before: "+hC.startOnLoad),void 0!==hC.startOnLoad&&(o.debug("Start On Load inner: "+hC.startOnLoad),uC.updateSiteConfig({startOnLoad:hC.startOnLoad})),void 0!==hC.ganttConfig&&uC.updateSiteConfig({gantt:hC.ganttConfig});for(var i,a=new Hv.initIdGeneratior(r.deterministicIds,r.deterministicIDSeed),s=function(r){var s=t[r];if(s.getAttribute("data-processed"))return"continue";s.setAttribute("data-processed",!0);var c="mermaid-".concat(a.next());i=s.innerHTML,i=Hv.entityDecode(i).trim().replace(//gi,"
");var u=Hv.detectInit(i);u&&o.debug("Detected early reinit: ",u);try{uC.render(c,i,(function(t,n){s.innerHTML=t,void 0!==e&&e(c),n&&n(s)}),s)}catch(t){o.warn("Syntax Error rendering"),o.warn(t),n.parseError&&n.parseError(t)}},c=0;c{t.exports={graphlib:n(6614),dagre:n(1463),intersect:n(8114),render:n(5787),util:n(8355),version:n(5689)}},9144:(t,e,n)=>{var r=n(8355);function i(t,e,n,i){var a=t.append("marker").attr("id",e).attr("viewBox","0 0 10 10").attr("refX",9).attr("refY",5).attr("markerUnits","strokeWidth").attr("markerWidth",8).attr("markerHeight",6).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z").style("stroke-width",1).style("stroke-dasharray","1,0");r.applyStyle(a,n[i+"Style"]),n[i+"Class"]&&a.attr("class",n[i+"Class"])}t.exports={default:i,normal:i,vee:function(t,e,n,i){var a=t.append("marker").attr("id",e).attr("viewBox","0 0 10 10").attr("refX",9).attr("refY",5).attr("markerUnits","strokeWidth").attr("markerWidth",8).attr("markerHeight",6).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 L 4 5 z").style("stroke-width",1).style("stroke-dasharray","1,0");r.applyStyle(a,n[i+"Style"]),n[i+"Class"]&&a.attr("class",n[i+"Class"])},undirected:function(t,e,n,i){var a=t.append("marker").attr("id",e).attr("viewBox","0 0 10 10").attr("refX",9).attr("refY",5).attr("markerUnits","strokeWidth").attr("markerWidth",8).attr("markerHeight",6).attr("orient","auto").append("path").attr("d","M 0 5 L 10 5").style("stroke-width",1).style("stroke-dasharray","1,0");r.applyStyle(a,n[i+"Style"]),n[i+"Class"]&&a.attr("class",n[i+"Class"])}}},5632:(t,e,n)=>{var r=n(8355),i=n(4322),a=n(1322);t.exports=function(t,e){var n,o=e.nodes().filter((function(t){return r.isSubgraph(e,t)})),s=t.selectAll("g.cluster").data(o,(function(t){return t}));return s.selectAll("*").remove(),s.enter().append("g").attr("class","cluster").attr("id",(function(t){return e.node(t).id})).style("opacity",0),s=t.selectAll("g.cluster"),r.applyTransition(s,e).style("opacity",1),s.each((function(t){var n=e.node(t),r=i.select(this);i.select(this).append("rect");var o=r.append("g").attr("class","label");a(o,n,n.clusterLabelPos)})),s.selectAll("rect").each((function(t){var n=e.node(t),a=i.select(this);r.applyStyle(a,n.style)})),n=s.exit?s.exit():s.selectAll(null),r.applyTransition(n,e).style("opacity",0).remove(),s}},6315:(t,e,n)=>{"use strict";var r=n(1034),i=n(1322),a=n(8355),o=n(4322);t.exports=function(t,e){var n,s=t.selectAll("g.edgeLabel").data(e.edges(),(function(t){return a.edgeToId(t)})).classed("update",!0);return s.exit().remove(),s.enter().append("g").classed("edgeLabel",!0).style("opacity",0),(s=t.selectAll("g.edgeLabel")).each((function(t){var n=o.select(this);n.select(".label").remove();var a=e.edge(t),s=i(n,e.edge(t),0,0).classed("label",!0),c=s.node().getBBox();a.labelId&&s.attr("id",a.labelId),r.has(a,"width")||(a.width=c.width),r.has(a,"height")||(a.height=c.height)})),n=s.exit?s.exit():s.selectAll(null),a.applyTransition(n,e).style("opacity",0).remove(),s}},940:(t,e,n)=>{"use strict";var r=n(1034),i=n(7584),a=n(8355),o=n(4322);function s(t,e){var n=(o.line||o.svg.line)().x((function(t){return t.x})).y((function(t){return t.y}));return(n.curve||n.interpolate)(t.curve),n(e)}t.exports=function(t,e,n){var c=t.selectAll("g.edgePath").data(e.edges(),(function(t){return a.edgeToId(t)})).classed("update",!0),u=function(t,e){var n=t.enter().append("g").attr("class","edgePath").style("opacity",0);return n.append("path").attr("class","path").attr("d",(function(t){var n=e.edge(t),i=e.node(t.v).elem;return s(n,r.range(n.points.length).map((function(){return e=(t=i).getBBox(),{x:(n=t.ownerSVGElement.getScreenCTM().inverse().multiply(t.getScreenCTM()).translate(e.width/2,e.height/2)).e,y:n.f};var t,e,n})))})),n.append("defs"),n}(c,e);!function(t,e){var n=t.exit();a.applyTransition(n,e).style("opacity",0).remove()}(c,e);var l=void 0!==c.merge?c.merge(u):c;return a.applyTransition(l,e).style("opacity",1),l.each((function(t){var n=o.select(this),r=e.edge(t);r.elem=this,r.id&&n.attr("id",r.id),a.applyClass(n,r.class,(n.classed("update")?"update ":"")+"edgePath")})),l.selectAll("path.path").each((function(t){var n=e.edge(t);n.arrowheadId=r.uniqueId("arrowhead");var c=o.select(this).attr("marker-end",(function(){return"url("https://github.com/+(t=location.href,e=n.arrowheadId,t.split(%22#")[0]+"#"+e+")");var t,e})).style("fill","none");a.applyTransition(c,e).attr("d",(function(t){return function(t,e){var n=t.edge(e),r=t.node(e.v),a=t.node(e.w),o=n.points.slice(1,n.points.length-1);return o.unshift(i(r,o[0])),o.push(i(a,o[o.length-1])),s(n,o)}(e,t)})),a.applyStyle(c,n.style)})),l.selectAll("defs *").remove(),l.selectAll("defs").each((function(t){var r=e.edge(t);(0,n[r.arrowhead])(o.select(this),r.arrowheadId,r,"arrowhead")})),l}},607:(t,e,n)=>{"use strict";var r=n(1034),i=n(1322),a=n(8355),o=n(4322);t.exports=function(t,e,n){var s,c=e.nodes().filter((function(t){return!a.isSubgraph(e,t)})),u=t.selectAll("g.node").data(c,(function(t){return t})).classed("update",!0);return u.exit().remove(),u.enter().append("g").attr("class","node").style("opacity",0),(u=t.selectAll("g.node")).each((function(t){var s=e.node(t),c=o.select(this);a.applyClass(c,s.class,(c.classed("update")?"update ":"")+"node"),c.select("g.label").remove();var u=c.append("g").attr("class","label"),l=i(u,s),h=n[s.shape],f=r.pick(l.node().getBBox(),"width","height");s.elem=this,s.id&&c.attr("id",s.id),s.labelId&&u.attr("id",s.labelId),r.has(s,"width")&&(f.width=s.width),r.has(s,"height")&&(f.height=s.height),f.width+=s.paddingLeft+s.paddingRight,f.height+=s.paddingTop+s.paddingBottom,u.attr("transform","translate("+(s.paddingLeft-s.paddingRight)/2+","+(s.paddingTop-s.paddingBottom)/2+")");var d=o.select(this);d.select(".label-container").remove();var p=h(d,f,s).classed("label-container",!0);a.applyStyle(p,s.style);var y=p.node().getBBox();s.width=y.width,s.height=y.height})),s=u.exit?u.exit():u.selectAll(null),a.applyTransition(s,e).style("opacity",0).remove(),u}},4322:(t,e,n)=>{var r;if(!r)try{r=n(7188)}catch(t){}r||(r=window.d3),t.exports=r},1463:(t,e,n)=>{var r;try{r=n(681)}catch(t){}r||(r=window.dagre),t.exports=r},6614:(t,e,n)=>{var r;try{r=n(8282)}catch(t){}r||(r=window.graphlib),t.exports=r},8114:(t,e,n)=>{t.exports={node:n(7584),circle:n(6587),ellipse:n(3260),polygon:n(5337),rect:n(8049)}},6587:(t,e,n)=>{var r=n(3260);t.exports=function(t,e,n){return r(t,e,e,n)}},3260:t=>{t.exports=function(t,e,n,r){var i=t.x,a=t.y,o=i-r.x,s=a-r.y,c=Math.sqrt(e*e*s*s+n*n*o*o),u=Math.abs(e*n*o/c);r.x{function e(t,e){return t*e>0}t.exports=function(t,n,r,i){var a,o,s,c,u,l,h,f,d,p,y,g,m;if(!(a=n.y-t.y,s=t.x-n.x,u=n.x*t.y-t.x*n.y,d=a*r.x+s*r.y+u,p=a*i.x+s*i.y+u,0!==d&&0!==p&&e(d,p)||(o=i.y-r.y,c=r.x-i.x,l=i.x*r.y-r.x*i.y,h=o*t.x+c*t.y+l,f=o*n.x+c*n.y+l,0!==h&&0!==f&&e(h,f)||0==(y=a*c-o*s))))return g=Math.abs(y/2),{x:(m=s*l-c*u)<0?(m-g)/y:(m+g)/y,y:(m=o*u-a*l)<0?(m-g)/y:(m+g)/y}}},7584:t=>{t.exports=function(t,e){return t.intersect(e)}},5337:(t,e,n)=>{var r=n(6808);t.exports=function(t,e,n){var i=t.x,a=t.y,o=[],s=Number.POSITIVE_INFINITY,c=Number.POSITIVE_INFINITY;e.forEach((function(t){s=Math.min(s,t.x),c=Math.min(c,t.y)}));for(var u=i-t.width/2-s,l=a-t.height/2-c,h=0;h1&&o.sort((function(t,e){var r=t.x-n.x,i=t.y-n.y,a=Math.sqrt(r*r+i*i),o=e.x-n.x,s=e.y-n.y,c=Math.sqrt(o*o+s*s);return a{t.exports=function(t,e){var n,r,i=t.x,a=t.y,o=e.x-i,s=e.y-a,c=t.width/2,u=t.height/2;return Math.abs(s)*c>Math.abs(o)*u?(s<0&&(u=-u),n=0===s?0:u*o/s,r=u):(o<0&&(c=-c),n=c,r=0===o?0:c*s/o),{x:i+n,y:a+r}}},8284:(t,e,n)=>{var r=n(8355);t.exports=function(t,e){var n=t.append("foreignObject").attr("width","100000"),i=n.append("xhtml:div");i.attr("xmlns","http://www.w3.org/1999/xhtml");var a=e.label;switch(typeof a){case"function":i.insert(a);break;case"object":i.insert((function(){return a}));break;default:i.html(a)}r.applyStyle(i,e.labelStyle),i.style("display","inline-block"),i.style("white-space","nowrap");var o=i.node().getBoundingClientRect();return n.attr("width",o.width).attr("height",o.height),n}},1322:(t,e,n)=>{var r=n(7318),i=n(8284),a=n(8287);t.exports=function(t,e,n){var o=e.label,s=t.append("g");"svg"===e.labelType?a(s,e):"string"!=typeof o||"html"===e.labelType?i(s,e):r(s,e);var c,u=s.node().getBBox();switch(n){case"top":c=-e.height/2;break;case"bottom":c=e.height/2-u.height;break;default:c=-u.height/2}return s.attr("transform","translate("+-u.width/2+","+c+")"),s}},8287:(t,e,n)=>{var r=n(8355);t.exports=function(t,e){var n=t;return n.node().appendChild(e.label),r.applyStyle(n,e.labelStyle),n}},7318:(t,e,n)=>{var r=n(8355);t.exports=function(t,e){for(var n=t.append("text"),i=function(t){for(var e,n="",r=!1,i=0;i{var r;try{r={defaults:n(1747),each:n(6073),isFunction:n(3560),isPlainObject:n(8630),pick:n(9722),has:n(8721),range:n(6026),uniqueId:n(3955)}}catch(t){}r||(r=window._),t.exports=r},6381:(t,e,n)=>{"use strict";var r=n(8355),i=n(4322);t.exports=function(t,e){var n=t.filter((function(){return!i.select(this).classed("update")}));function a(t){var n=e.node(t);return"translate("+n.x+","+n.y+")"}n.attr("transform",a),r.applyTransition(t,e).style("opacity",1).attr("transform",a),r.applyTransition(n.selectAll("rect"),e).attr("width",(function(t){return e.node(t).width})).attr("height",(function(t){return e.node(t).height})).attr("x",(function(t){return-e.node(t).width/2})).attr("y",(function(t){return-e.node(t).height/2}))}},4577:(t,e,n)=>{"use strict";var r=n(8355),i=n(4322),a=n(1034);t.exports=function(t,e){function n(t){var n=e.edge(t);return a.has(n,"x")?"translate("+n.x+","+n.y+")":""}t.filter((function(){return!i.select(this).classed("update")})).attr("transform",n),r.applyTransition(t,e).style("opacity",1).attr("transform",n)}},4849:(t,e,n)=>{"use strict";var r=n(8355),i=n(4322);t.exports=function(t,e){function n(t){var n=e.node(t);return"translate("+n.x+","+n.y+")"}t.filter((function(){return!i.select(this).classed("update")})).attr("transform",n),r.applyTransition(t,e).style("opacity",1).attr("transform",n)}},5787:(t,e,n)=>{var r=n(1034),i=n(4322),a=n(1463).layout;t.exports=function(){var t=n(607),e=n(5632),i=n(6315),u=n(940),l=n(4849),h=n(4577),f=n(6381),d=n(4418),p=n(9144),y=function(n,y){!function(t){t.nodes().forEach((function(e){var n=t.node(e);r.has(n,"label")||t.children(e).length||(n.label=e),r.has(n,"paddingX")&&r.defaults(n,{paddingLeft:n.paddingX,paddingRight:n.paddingX}),r.has(n,"paddingY")&&r.defaults(n,{paddingTop:n.paddingY,paddingBottom:n.paddingY}),r.has(n,"padding")&&r.defaults(n,{paddingLeft:n.padding,paddingRight:n.padding,paddingTop:n.padding,paddingBottom:n.padding}),r.defaults(n,o),r.each(["paddingLeft","paddingRight","paddingTop","paddingBottom"],(function(t){n[t]=Number(n[t])})),r.has(n,"width")&&(n._prevWidth=n.width),r.has(n,"height")&&(n._prevHeight=n.height)})),t.edges().forEach((function(e){var n=t.edge(e);r.has(n,"label")||(n.label=""),r.defaults(n,s)}))}(y);var g=c(n,"output"),m=c(g,"clusters"),v=c(g,"edgePaths"),b=i(c(g,"edgeLabels"),y),_=t(c(g,"nodes"),y,d);a(y),l(_,y),h(b,y),u(v,y,p);var x=e(m,y);f(x,y),function(t){r.each(t.nodes(),(function(e){var n=t.node(e);r.has(n,"_prevWidth")?n.width=n._prevWidth:delete n.width,r.has(n,"_prevHeight")?n.height=n._prevHeight:delete n.height,delete n._prevWidth,delete n._prevHeight}))}(y)};return y.createNodes=function(e){return arguments.length?(t=e,y):t},y.createClusters=function(t){return arguments.length?(e=t,y):e},y.createEdgeLabels=function(t){return arguments.length?(i=t,y):i},y.createEdgePaths=function(t){return arguments.length?(u=t,y):u},y.shapes=function(t){return arguments.length?(d=t,y):d},y.arrows=function(t){return arguments.length?(p=t,y):p},y};var o={paddingLeft:10,paddingRight:10,paddingTop:10,paddingBottom:10,rx:0,ry:0,shape:"rect"},s={arrowhead:"normal",curve:i.curveLinear};function c(t,e){var n=t.select("g."+e);return n.empty()&&(n=t.append("g").attr("class",e)),n}},4418:(t,e,n)=>{"use strict";var r=n(8049),i=n(3260),a=n(6587),o=n(5337);t.exports={rect:function(t,e,n){var i=t.insert("rect",":first-child").attr("rx",n.rx).attr("ry",n.ry).attr("x",-e.width/2).attr("y",-e.height/2).attr("width",e.width).attr("height",e.height);return n.intersect=function(t){return r(n,t)},i},ellipse:function(t,e,n){var r=e.width/2,a=e.height/2,o=t.insert("ellipse",":first-child").attr("x",-e.width/2).attr("y",-e.height/2).attr("rx",r).attr("ry",a);return n.intersect=function(t){return i(n,r,a,t)},o},circle:function(t,e,n){var r=Math.max(e.width,e.height)/2,i=t.insert("circle",":first-child").attr("x",-e.width/2).attr("y",-e.height/2).attr("r",r);return n.intersect=function(t){return a(n,r,t)},i},diamond:function(t,e,n){var r=e.width*Math.SQRT2/2,i=e.height*Math.SQRT2/2,a=[{x:0,y:-i},{x:-r,y:0},{x:0,y:i},{x:r,y:0}],s=t.insert("polygon",":first-child").attr("points",a.map((function(t){return t.x+","+t.y})).join(" "));return n.intersect=function(t){return o(n,a,t)},s}}},8355:(t,e,n)=>{var r=n(1034);t.exports={isSubgraph:function(t,e){return!!t.children(e).length},edgeToId:function(t){return a(t.v)+":"+a(t.w)+":"+a(t.name)},applyStyle:function(t,e){e&&t.attr("style",e)},applyClass:function(t,e,n){e&&t.attr("class",e).attr("class",n+" "+t.attr("class"))},applyTransition:function(t,e){var n=e.graph();if(r.isPlainObject(n)){var i=n.transition;if(r.isFunction(i))return i(t)}return t}};var i=/:/g;function a(t){return t?String(t).replace(i,"\\:"):""}},5689:t=>{t.exports="0.6.4"},7188:(t,e,n)=>{"use strict";n.r(e),n.d(e,{FormatSpecifier:()=>uc,active:()=>Jr,arc:()=>fx,area:()=>vx,areaRadial:()=>Sx,ascending:()=>i,autoType:()=>Fo,axisBottom:()=>it,axisLeft:()=>at,axisRight:()=>rt,axisTop:()=>nt,bisect:()=>u,bisectLeft:()=>c,bisectRight:()=>s,bisector:()=>a,blob:()=>ms,brush:()=>Ai,brushSelection:()=>Ei,brushX:()=>Ci,brushY:()=>Si,buffer:()=>bs,chord:()=>Fi,clientPoint:()=>Dn,cluster:()=>Sd,color:()=>Ve,contourDensity:()=>oo,contours:()=>to,create:()=>j_,creator:()=>ie,cross:()=>f,csv:()=>Ts,csvFormat:()=>To,csvFormatBody:()=>Eo,csvFormatRow:()=>So,csvFormatRows:()=>Co,csvFormatValue:()=>Ao,csvParse:()=>wo,csvParseRows:()=>ko,cubehelix:()=>Ha,curveBasis:()=>sw,curveBasisClosed:()=>uw,curveBasisOpen:()=>hw,curveBundle:()=>dw,curveCardinal:()=>gw,curveCardinalClosed:()=>vw,curveCardinalOpen:()=>_w,curveCatmullRom:()=>kw,curveCatmullRomClosed:()=>Ew,curveCatmullRomOpen:()=>Sw,curveLinear:()=>px,curveLinearClosed:()=>Mw,curveMonotoneX:()=>Fw,curveMonotoneY:()=>Pw,curveNatural:()=>zw,curveStep:()=>qw,curveStepAfter:()=>$w,curveStepBefore:()=>Hw,customEvent:()=>ge,descending:()=>d,deviation:()=>g,dispatch:()=>ft,drag:()=>po,dragDisable:()=>Se,dragEnable:()=>Ae,dsv:()=>ks,dsvFormat:()=>_o,easeBack:()=>hs,easeBackIn:()=>us,easeBackInOut:()=>hs,easeBackOut:()=>ls,easeBounce:()=>os,easeBounceIn:()=>as,easeBounceInOut:()=>ss,easeBounceOut:()=>os,easeCircle:()=>rs,easeCircleIn:()=>es,easeCircleInOut:()=>rs,easeCircleOut:()=>ns,easeCubic:()=>Xr,easeCubicIn:()=>Vr,easeCubicInOut:()=>Xr,easeCubicOut:()=>Gr,easeElastic:()=>ps,easeElasticIn:()=>ds,easeElasticInOut:()=>ys,easeElasticOut:()=>ps,easeExp:()=>ts,easeExpIn:()=>Ko,easeExpInOut:()=>ts,easeExpOut:()=>Jo,easeLinear:()=>jo,easePoly:()=>$o,easePolyIn:()=>qo,easePolyInOut:()=>$o,easePolyOut:()=>Ho,easeQuad:()=>Uo,easeQuadIn:()=>Yo,easeQuadInOut:()=>Uo,easeQuadOut:()=>zo,easeSin:()=>Zo,easeSinIn:()=>Go,easeSinInOut:()=>Zo,easeSinOut:()=>Xo,entries:()=>pa,event:()=>le,extent:()=>m,forceCenter:()=>Bs,forceCollide:()=>Ws,forceLink:()=>Xs,forceManyBody:()=>tc,forceRadial:()=>ec,forceSimulation:()=>Js,forceX:()=>nc,forceY:()=>rc,format:()=>pc,formatDefaultLocale:()=>bc,formatLocale:()=>vc,formatPrefix:()=>yc,formatSpecifier:()=>cc,geoAlbers:()=>Uf,geoAlbersUsa:()=>qf,geoArea:()=>yu,geoAzimuthalEqualArea:()=>Vf,geoAzimuthalEqualAreaRaw:()=>Wf,geoAzimuthalEquidistant:()=>Xf,geoAzimuthalEquidistantRaw:()=>Gf,geoBounds:()=>sl,geoCentroid:()=>bl,geoCircle:()=>Nl,geoClipAntimeridian:()=>Ul,geoClipCircle:()=>ql,geoClipExtent:()=>Vl,geoClipRectangle:()=>Wl,geoConicConformal:()=>ed,geoConicConformalRaw:()=>td,geoConicEqualArea:()=>zf,geoConicEqualAreaRaw:()=>Yf,geoConicEquidistant:()=>ad,geoConicEquidistantRaw:()=>id,geoContains:()=>ph,geoDistance:()=>ah,geoEqualEarth:()=>fd,geoEqualEarthRaw:()=>hd,geoEquirectangular:()=>rd,geoEquirectangularRaw:()=>nd,geoGnomonic:()=>pd,geoGnomonicRaw:()=>dd,geoGraticule:()=>mh,geoGraticule10:()=>vh,geoIdentity:()=>yd,geoInterpolate:()=>bh,geoLength:()=>nh,geoMercator:()=>Qf,geoMercatorRaw:()=>Zf,geoNaturalEarth1:()=>md,geoNaturalEarth1Raw:()=>gd,geoOrthographic:()=>bd,geoOrthographicRaw:()=>vd,geoPath:()=>kf,geoProjection:()=>Ff,geoProjectionMutator:()=>Pf,geoRotation:()=>Sl,geoStereographic:()=>xd,geoStereographicRaw:()=>_d,geoStream:()=>nu,geoTransform:()=>Tf,geoTransverseMercator:()=>kd,geoTransverseMercatorRaw:()=>wd,gray:()=>ka,hcl:()=>Oa,hierarchy:()=>Md,histogram:()=>D,hsl:()=>an,html:()=>Ds,image:()=>Cs,interpolate:()=>Mn,interpolateArray:()=>xn,interpolateBasis:()=>un,interpolateBasisClosed:()=>ln,interpolateBlues:()=>f_,interpolateBrBG:()=>Tb,interpolateBuGn:()=>Ub,interpolateBuPu:()=>Hb,interpolateCividis:()=>k_,interpolateCool:()=>C_,interpolateCubehelix:()=>zp,interpolateCubehelixDefault:()=>T_,interpolateCubehelixLong:()=>Up,interpolateDate:()=>kn,interpolateDiscrete:()=>Sp,interpolateGnBu:()=>Wb,interpolateGreens:()=>p_,interpolateGreys:()=>g_,interpolateHcl:()=>Pp,interpolateHclLong:()=>jp,interpolateHsl:()=>Lp,interpolateHslLong:()=>Ip,interpolateHue:()=>Ap,interpolateInferno:()=>F_,interpolateLab:()=>Rp,interpolateMagma:()=>R_,interpolateNumber:()=>Tn,interpolateNumberArray:()=>bn,interpolateObject:()=>En,interpolateOrRd:()=>Gb,interpolateOranges:()=>w_,interpolatePRGn:()=>Cb,interpolatePiYG:()=>Ab,interpolatePlasma:()=>P_,interpolatePuBu:()=>Kb,interpolatePuBuGn:()=>Zb,interpolatePuOr:()=>Nb,interpolatePuRd:()=>t_,interpolatePurples:()=>v_,interpolateRainbow:()=>A_,interpolateRdBu:()=>Ob,interpolateRdGy:()=>Lb,interpolateRdPu:()=>n_,interpolateRdYlBu:()=>Rb,interpolateRdYlGn:()=>Pb,interpolateReds:()=>__,interpolateRgb:()=>yn,interpolateRgbBasis:()=>mn,interpolateRgbBasisClosed:()=>vn,interpolateRound:()=>Mp,interpolateSinebow:()=>O_,interpolateSpectral:()=>Yb,interpolateString:()=>An,interpolateTransformCss:()=>pr,interpolateTransformSvg:()=>yr,interpolateTurbo:()=>B_,interpolateViridis:()=>I_,interpolateWarm:()=>E_,interpolateYlGn:()=>o_,interpolateYlGnBu:()=>i_,interpolateYlOrBr:()=>c_,interpolateYlOrRd:()=>l_,interpolateZoom:()=>Op,interrupt:()=>ar,interval:()=>fk,isoFormat:()=>uk,isoParse:()=>hk,json:()=>As,keys:()=>fa,lab:()=>Ta,lch:()=>Da,line:()=>mx,lineRadial:()=>Cx,linkHorizontal:()=>Rx,linkRadial:()=>Px,linkVertical:()=>Fx,local:()=>z_,map:()=>na,matcher:()=>mt,max:()=>I,mean:()=>R,median:()=>F,merge:()=>P,min:()=>j,mouse:()=>Bn,namespace:()=>Et,namespaces:()=>Tt,nest:()=>ra,now:()=>Hn,pack:()=>tp,packEnclose:()=>Id,packSiblings:()=>Gd,pairs:()=>l,partition:()=>op,path:()=>Wi,permute:()=>Y,pie:()=>xx,piecewise:()=>qp,pointRadial:()=>Ax,polygonArea:()=>$p,polygonCentroid:()=>Wp,polygonContains:()=>Qp,polygonHull:()=>Zp,polygonLength:()=>Kp,precisionFixed:()=>_c,precisionPrefix:()=>xc,precisionRound:()=>wc,quadtree:()=>Ys,quantile:()=>O,quantize:()=>Hp,radialArea:()=>Sx,radialLine:()=>Cx,randomBates:()=>iy,randomExponential:()=>ay,randomIrwinHall:()=>ry,randomLogNormal:()=>ny,randomNormal:()=>ey,randomUniform:()=>ty,range:()=>k,rgb:()=>Qe,ribbon:()=>Ki,scaleBand:()=>dy,scaleDiverging:()=>ob,scaleDivergingLog:()=>sb,scaleDivergingPow:()=>ub,scaleDivergingSqrt:()=>lb,scaleDivergingSymlog:()=>cb,scaleIdentity:()=>My,scaleImplicit:()=>hy,scaleLinear:()=>Ay,scaleLog:()=>Py,scaleOrdinal:()=>fy,scalePoint:()=>yy,scalePow:()=>Vy,scaleQuantile:()=>Xy,scaleQuantize:()=>Zy,scaleSequential:()=>Jv,scaleSequentialLog:()=>tb,scaleSequentialPow:()=>nb,scaleSequentialQuantile:()=>ib,scaleSequentialSqrt:()=>rb,scaleSequentialSymlog:()=>eb,scaleSqrt:()=>Gy,scaleSymlog:()=>Uy,scaleThreshold:()=>Qy,scaleTime:()=>Yv,scaleUtc:()=>Zv,scan:()=>z,schemeAccent:()=>db,schemeBlues:()=>h_,schemeBrBG:()=>kb,schemeBuGn:()=>zb,schemeBuPu:()=>qb,schemeCategory10:()=>fb,schemeDark2:()=>pb,schemeGnBu:()=>$b,schemeGreens:()=>d_,schemeGreys:()=>y_,schemeOrRd:()=>Vb,schemeOranges:()=>x_,schemePRGn:()=>Eb,schemePaired:()=>yb,schemePastel1:()=>gb,schemePastel2:()=>mb,schemePiYG:()=>Sb,schemePuBu:()=>Qb,schemePuBuGn:()=>Xb,schemePuOr:()=>Mb,schemePuRd:()=>Jb,schemePurples:()=>m_,schemeRdBu:()=>Db,schemeRdGy:()=>Bb,schemeRdPu:()=>e_,schemeRdYlBu:()=>Ib,schemeRdYlGn:()=>Fb,schemeReds:()=>b_,schemeSet1:()=>vb,schemeSet2:()=>bb,schemeSet3:()=>_b,schemeSpectral:()=>jb,schemeTableau10:()=>xb,schemeYlGn:()=>a_,schemeYlGnBu:()=>r_,schemeYlOrBr:()=>s_,schemeYlOrRd:()=>u_,select:()=>Te,selectAll:()=>q_,selection:()=>ke,selector:()=>pt,selectorAll:()=>gt,set:()=>ha,shuffle:()=>U,stack:()=>Xw,stackOffsetDiverging:()=>Qw,stackOffsetExpand:()=>Zw,stackOffsetNone:()=>Ww,stackOffsetSilhouette:()=>Kw,stackOffsetWiggle:()=>Jw,stackOrderAppearance:()=>tk,stackOrderAscending:()=>nk,stackOrderDescending:()=>ik,stackOrderInsideOut:()=>ak,stackOrderNone:()=>Vw,stackOrderReverse:()=>ok,stratify:()=>hp,style:()=>Rt,sum:()=>q,svg:()=>Os,symbol:()=>rw,symbolCircle:()=>jx,symbolCross:()=>Yx,symbolDiamond:()=>qx,symbolSquare:()=>Gx,symbolStar:()=>Vx,symbolTriangle:()=>Zx,symbolWye:()=>ew,symbols:()=>nw,text:()=>xs,thresholdFreedmanDiaconis:()=>B,thresholdScott:()=>L,thresholdSturges:()=>N,tickFormat:()=>Cy,tickIncrement:()=>A,tickStep:()=>M,ticks:()=>S,timeDay:()=>Ag,timeDays:()=>Mg,timeFormat:()=>pm,timeFormatDefaultLocale:()=>Iv,timeFormatLocale:()=>fm,timeFriday:()=>vg,timeFridays:()=>Eg,timeHour:()=>Dg,timeHours:()=>Og,timeInterval:()=>tg,timeMillisecond:()=>Yg,timeMilliseconds:()=>zg,timeMinute:()=>Lg,timeMinutes:()=>Ig,timeMonday:()=>pg,timeMondays:()=>xg,timeMonth:()=>ag,timeMonths:()=>og,timeParse:()=>ym,timeSaturday:()=>bg,timeSaturdays:()=>Cg,timeSecond:()=>Fg,timeSeconds:()=>Pg,timeSunday:()=>dg,timeSundays:()=>_g,timeThursday:()=>mg,timeThursdays:()=>Tg,timeTuesday:()=>yg,timeTuesdays:()=>wg,timeWednesday:()=>gg,timeWednesdays:()=>kg,timeWeek:()=>dg,timeWeeks:()=>_g,timeYear:()=>ng,timeYears:()=>rg,timeout:()=>Kn,timer:()=>Vn,timerFlush:()=>Gn,touch:()=>On,touches:()=>H_,transition:()=>Hr,transpose:()=>H,tree:()=>vp,treemap:()=>kp,treemapBinary:()=>Tp,treemapDice:()=>ap,treemapResquarify:()=>Cp,treemapSlice:()=>bp,treemapSliceDice:()=>Ep,treemapSquarify:()=>wp,tsv:()=>Es,tsvFormat:()=>Oo,tsvFormatBody:()=>Bo,tsvFormatRow:()=>Io,tsvFormatRows:()=>Lo,tsvFormatValue:()=>Ro,tsvParse:()=>No,tsvParseRows:()=>Do,utcDay:()=>im,utcDays:()=>am,utcFormat:()=>gm,utcFriday:()=>Gg,utcFridays:()=>em,utcHour:()=>$v,utcHours:()=>Wv,utcMillisecond:()=>Yg,utcMilliseconds:()=>zg,utcMinute:()=>Gv,utcMinutes:()=>Xv,utcMonday:()=>Hg,utcMondays:()=>Qg,utcMonth:()=>Uv,utcMonths:()=>qv,utcParse:()=>mm,utcSaturday:()=>Xg,utcSaturdays:()=>nm,utcSecond:()=>Fg,utcSeconds:()=>Pg,utcSunday:()=>qg,utcSundays:()=>Zg,utcThursday:()=>Vg,utcThursdays:()=>tm,utcTuesday:()=>$g,utcTuesdays:()=>Kg,utcWednesday:()=>Wg,utcWednesdays:()=>Jg,utcWeek:()=>qg,utcWeeks:()=>Zg,utcYear:()=>sm,utcYears:()=>cm,values:()=>da,variance:()=>y,version:()=>r,voronoi:()=>Kk,window:()=>Ot,xml:()=>Ns,zip:()=>W,zoom:()=>fT,zoomIdentity:()=>nT,zoomTransform:()=>rT});var r="5.16.0";function i(t,e){return te?1:t>=e?0:NaN}function a(t){var e;return 1===t.length&&(e=t,t=function(t,n){return i(e(t),n)}),{left:function(e,n,r,i){for(null==r&&(r=0),null==i&&(i=e.length);r>>1;t(e[a],n)<0?r=a+1:i=a}return r},right:function(e,n,r,i){for(null==r&&(r=0),null==i&&(i=e.length);r>>1;t(e[a],n)>0?i=a:r=a+1}return r}}}var o=a(i),s=o.right,c=o.left;const u=s;function l(t,e){null==e&&(e=h);for(var n=0,r=t.length-1,i=t[0],a=new Array(r<0?0:r);nt?1:e>=t?0:NaN}function p(t){return null===t?NaN:+t}function y(t,e){var n,r,i=t.length,a=0,o=-1,s=0,c=0;if(null==e)for(;++o1)return c/(a-1)}function g(t,e){var n=y(t,e);return n?Math.sqrt(n):n}function m(t,e){var n,r,i,a=t.length,o=-1;if(null==e){for(;++o=n)for(r=i=n;++on&&(r=n),i=n)for(r=i=n;++on&&(r=n),i0)return[t];if((r=e0)for(t=Math.ceil(t/o),e=Math.floor(e/o),a=new Array(i=Math.ceil(e-t+1));++s=0?(a>=T?10:a>=E?5:a>=C?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(a>=T?10:a>=E?5:a>=C?2:1)}function M(t,e,n){var r=Math.abs(e-t)/Math.max(0,n),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),a=r/i;return a>=T?i*=10:a>=E?i*=5:a>=C&&(i*=2),eh;)f.pop(),--d;var p,y=new Array(d+1);for(i=0;i<=d;++i)(p=y[i]=[]).x0=i>0?f[i-1]:l,p.x1=i=1)return+n(t[r-1],r-1,t);var r,i=(r-1)*e,a=Math.floor(i),o=+n(t[a],a,t);return o+(+n(t[a+1],a+1,t)-o)*(i-a)}}function B(t,e,n){return t=_.call(t,p).sort(i),Math.ceil((n-e)/(2*(O(t,.75)-O(t,.25))*Math.pow(t.length,-1/3)))}function L(t,e,n){return Math.ceil((n-e)/(3.5*g(t)*Math.pow(t.length,-1/3)))}function I(t,e){var n,r,i=t.length,a=-1;if(null==e){for(;++a=n)for(r=n;++ar&&(r=n)}else for(;++a=n)for(r=n;++ar&&(r=n);return r}function R(t,e){var n,r=t.length,i=r,a=-1,o=0;if(null==e)for(;++a=0;)for(e=(r=t[i]).length;--e>=0;)n[--o]=r[e];return n}function j(t,e){var n,r,i=t.length,a=-1;if(null==e){for(;++a=n)for(r=n;++an&&(r=n)}else for(;++a=n)for(r=n;++an&&(r=n);return r}function Y(t,e){for(var n=e.length,r=new Array(n);n--;)r[n]=t[e[n]];return r}function z(t,e){if(n=t.length){var n,r,a=0,o=0,s=t[o];for(null==e&&(e=i);++a=0&&(n=t.slice(r+1),t=t.slice(0,r)),t&&!e.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))}function lt(t,e){for(var n,r=0,i=t.length;r0)for(var n,r,i=new Array(n),a=0;ae?1:t>=e?0:NaN}bt.prototype={constructor:bt,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,e){return this._parent.insertBefore(t,e)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var kt="http://www.w3.org/1999/xhtml";const Tt={svg:"http://www.w3.org/2000/svg",xhtml:kt,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function Et(t){var e=t+="",n=e.indexOf(":");return n>=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),Tt.hasOwnProperty(e)?{space:Tt[e],local:t}:t}function Ct(t){return function(){this.removeAttribute(t)}}function St(t){return function(){this.removeAttributeNS(t.space,t.local)}}function At(t,e){return function(){this.setAttribute(t,e)}}function Mt(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function Nt(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttribute(t):this.setAttribute(t,n)}}function Dt(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}function Ot(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function Bt(t){return function(){this.style.removeProperty(t)}}function Lt(t,e,n){return function(){this.style.setProperty(t,e,n)}}function It(t,e,n){return function(){var r=e.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,n)}}function Rt(t,e){return t.style.getPropertyValue(e)||Ot(t).getComputedStyle(t,null).getPropertyValue(e)}function Ft(t){return function(){delete this[t]}}function Pt(t,e){return function(){this[t]=e}}function jt(t,e){return function(){var n=e.apply(this,arguments);null==n?delete this[t]:this[t]=n}}function Yt(t){return t.trim().split(/^|\s+/)}function zt(t){return t.classList||new Ut(t)}function Ut(t){this._node=t,this._names=Yt(t.getAttribute("class")||"")}function qt(t,e){for(var n=zt(t),r=-1,i=e.length;++r=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var ue={},le=null;function he(t,e,n){return t=fe(t,e,n),function(e){var n=e.relatedTarget;n&&(n===this||8&n.compareDocumentPosition(this))||t.call(this,e)}}function fe(t,e,n){return function(r){var i=le;le=r;try{t.call(this,this.__data__,e,n)}finally{le=i}}}function de(t){return t.trim().split(/^|\s+/).map((function(t){var e="",n=t.indexOf(".");return n>=0&&(e=t.slice(n+1),t=t.slice(0,n)),{type:t,name:e}}))}function pe(t){return function(){var e=this.__on;if(e){for(var n,r=0,i=-1,a=e.length;r=x&&(x=_+1);!(b=m[x])&&++x=0;)(r=i[a])&&(o&&4^r.compareDocumentPosition(o)&&o.parentNode.insertBefore(r,o),o=r);return this},sort:function(t){function e(e,n){return e&&n?t(e.__data__,n.__data__):!e-!n}t||(t=wt);for(var n=this._groups,r=n.length,i=new Array(r),a=0;a1?this.each((null==e?Bt:"function"==typeof e?It:Lt)(t,e,null==n?"":n)):Rt(this.node(),t)},property:function(t,e){return arguments.length>1?this.each((null==e?Ft:"function"==typeof e?jt:Pt)(t,e)):this.node()[t]},classed:function(t,e){var n=Yt(t+"");if(arguments.length<2){for(var r=zt(this.node()),i=-1,a=n.length;++i>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?Xe(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?Xe(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=Pe.exec(t))?new Ke(e[1],e[2],e[3],1):(e=je.exec(t))?new Ke(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=Ye.exec(t))?Xe(e[1],e[2],e[3],e[4]):(e=ze.exec(t))?Xe(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=Ue.exec(t))?nn(e[1],e[2]/100,e[3]/100,1):(e=qe.exec(t))?nn(e[1],e[2]/100,e[3]/100,e[4]):He.hasOwnProperty(t)?Ge(He[t]):"transparent"===t?new Ke(NaN,NaN,NaN,0):null}function Ge(t){return new Ke(t>>16&255,t>>8&255,255&t,1)}function Xe(t,e,n,r){return r<=0&&(t=e=n=NaN),new Ke(t,e,n,r)}function Ze(t){return t instanceof De||(t=Ve(t)),t?new Ke((t=t.rgb()).r,t.g,t.b,t.opacity):new Ke}function Qe(t,e,n,r){return 1===arguments.length?Ze(t):new Ke(t,e,n,null==r?1:r)}function Ke(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function Je(){return"#"+en(this.r)+en(this.g)+en(this.b)}function tn(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function en(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function nn(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new on(t,e,n,r)}function rn(t){if(t instanceof on)return new on(t.h,t.s,t.l,t.opacity);if(t instanceof De||(t=Ve(t)),!t)return new on;if(t instanceof on)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),a=Math.max(e,n,r),o=NaN,s=a-i,c=(a+i)/2;return s?(o=e===a?(n-r)/s+6*(n0&&c<1?0:o,new on(o,s,c,t.opacity)}function an(t,e,n,r){return 1===arguments.length?rn(t):new on(t,e,n,null==r?1:r)}function on(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function sn(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}function cn(t,e,n,r,i){var a=t*t,o=a*t;return((1-3*t+3*a-o)*e+(4-6*a+3*o)*n+(1+3*t+3*a-3*o)*r+o*i)/6}function un(t){var e=t.length-1;return function(n){var r=n<=0?n=0:n>=1?(n=1,e-1):Math.floor(n*e),i=t[r],a=t[r+1],o=r>0?t[r-1]:2*i-a,s=r180||n<-180?n-360*Math.round(n/360):n):hn(isNaN(t)?e:t)}function pn(t,e){var n=e-t;return n?fn(t,n):hn(isNaN(t)?e:t)}Me(De,Ve,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:$e,formatHex:$e,formatHsl:function(){return rn(this).formatHsl()},formatRgb:We,toString:We}),Me(Ke,Qe,Ne(De,{brighter:function(t){return t=null==t?Be:Math.pow(Be,t),new Ke(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?Oe:Math.pow(Oe,t),new Ke(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Je,formatHex:Je,formatRgb:tn,toString:tn})),Me(on,an,Ne(De,{brighter:function(t){return t=null==t?Be:Math.pow(Be,t),new on(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?Oe:Math.pow(Oe,t),new on(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new Ke(sn(t>=240?t-240:t+120,i,r),sn(t,i,r),sn(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const yn=function t(e){var n=function(t){return 1==(t=+t)?pn:function(e,n){return n-e?function(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(r){return Math.pow(t+r*e,n)}}(e,n,t):hn(isNaN(e)?n:e)}}(e);function r(t,e){var r=n((t=Qe(t)).r,(e=Qe(e)).r),i=n(t.g,e.g),a=n(t.b,e.b),o=pn(t.opacity,e.opacity);return function(e){return t.r=r(e),t.g=i(e),t.b=a(e),t.opacity=o(e),t+""}}return r.gamma=t,r}(1);function gn(t){return function(e){var n,r,i=e.length,a=new Array(i),o=new Array(i),s=new Array(i);for(n=0;na&&(i=e.slice(a,i),s[o]?s[o]+=i:s[++o]=i),(n=n[0])===(r=r[0])?s[o]?s[o]+=r:s[++o]=r:(s[++o]=null,c.push({i:o,x:Tn(n,r)})),a=Sn.lastIndex;return a=0&&e._call.call(null,t),e=e._next;--Rn}function Xn(){Yn=(jn=Un.now())+zn,Rn=Fn=0;try{Gn()}finally{Rn=0,function(){for(var t,e,n=Ln,r=1/0;n;)n._call?(r>n._time&&(r=n._time),t=n,n=n._next):(e=n._next,n._next=null,n=t?t._next=e:Ln=e);In=t,Qn(r)}(),Yn=0}}function Zn(){var t=Un.now(),e=t-jn;e>1e3&&(zn-=e,jn=t)}function Qn(t){Rn||(Fn&&(Fn=clearTimeout(Fn)),t-Yn>24?(t<1/0&&(Fn=setTimeout(Xn,t-Un.now()-zn)),Pn&&(Pn=clearInterval(Pn))):(Pn||(jn=Un.now(),Pn=setInterval(Zn,1e3)),Rn=1,qn(Xn)))}function Kn(t,e,n){var r=new Wn;return e=null==e?0:+e,r.restart((function(n){r.stop(),t(n+e)}),e,n),r}Wn.prototype=Vn.prototype={constructor:Wn,restart:function(t,e,n){if("function"!=typeof t)throw new TypeError("callback is not a function");n=(null==n?Hn():+n)+(null==e?0:+e),this._next||In===this||(In?In._next=this:Ln=this,In=this),this._call=t,this._time=n,Qn()},stop:function(){this._call&&(this._call=null,this._time=1/0,Qn())}};var Jn=ft("start","end","cancel","interrupt"),tr=[];function er(t,e,n,r,i,a){var o=t.__transition;if(o){if(n in o)return}else t.__transition={};!function(t,e,n){var r,i=t.__transition;function a(c){var u,l,h,f;if(1!==n.state)return s();for(u in i)if((f=i[u]).name===n.name){if(3===f.state)return Kn(a);4===f.state?(f.state=6,f.timer.stop(),f.on.call("interrupt",t,t.__data__,f.index,f.group),delete i[u]):+u0)throw new Error("too late; already scheduled");return n}function rr(t,e){var n=ir(t,e);if(n.state>3)throw new Error("too late; already running");return n}function ir(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}function ar(t,e){var n,r,i,a=t.__transition,o=!0;if(a){for(i in e=null==e?null:e+"",a)(n=a[i]).name===e?(r=n.state>2&&n.state<5,n.state=6,n.timer.stop(),n.on.call(r?"interrupt":"cancel",t,t.__data__,n.index,n.group),delete a[i]):o=!1;o&&delete t.__transition}}var or,sr,cr,ur,lr=180/Math.PI,hr={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function fr(t,e,n,r,i,a){var o,s,c;return(o=Math.sqrt(t*t+e*e))&&(t/=o,e/=o),(c=t*n+e*r)&&(n-=t*c,r-=e*c),(s=Math.sqrt(n*n+r*r))&&(n/=s,r/=s,c/=s),t*r180?e+=360:e-t>180&&(t+=360),a.push({i:n.push(i(n)+"rotate(",null,r)-2,x:Tn(t,e)})):e&&n.push(i(n)+"rotate("+e+r)}(a.rotate,o.rotate,s,c),function(t,e,n,a){t!==e?a.push({i:n.push(i(n)+"skewX(",null,r)-2,x:Tn(t,e)}):e&&n.push(i(n)+"skewX("+e+r)}(a.skewX,o.skewX,s,c),function(t,e,n,r,a,o){if(t!==n||e!==r){var s=a.push(i(a)+"scale(",null,",",null,")");o.push({i:s-4,x:Tn(t,n)},{i:s-2,x:Tn(e,r)})}else 1===n&&1===r||a.push(i(a)+"scale("+n+","+r+")")}(a.scaleX,a.scaleY,o.scaleX,o.scaleY,s,c),a=o=null,function(t){for(var e,n=-1,r=c.length;++n=0&&(t=t.slice(0,e)),!t||"start"===t}))}(e)?nr:rr;return function(){var o=a(this,t),s=o.on;s!==r&&(i=(r=s).copy()).on(e,n),o.on=i}}var Rr=ke.prototype.constructor;function Fr(t){return function(){this.style.removeProperty(t)}}function Pr(t,e,n){return function(r){this.style.setProperty(t,e.call(this,r),n)}}function jr(t,e,n){var r,i;function a(){var a=e.apply(this,arguments);return a!==i&&(r=(i=a)&&Pr(t,a,n)),r}return a._value=e,a}function Yr(t){return function(e){this.textContent=t.call(this,e)}}function zr(t){var e,n;function r(){var r=t.apply(this,arguments);return r!==n&&(e=(n=r)&&Yr(r)),e}return r._value=t,r}var Ur=0;function qr(t,e,n,r){this._groups=t,this._parents=e,this._name=n,this._id=r}function Hr(t){return ke().transition(t)}function $r(){return++Ur}var Wr=ke.prototype;function Vr(t){return t*t*t}function Gr(t){return--t*t*t+1}function Xr(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}qr.prototype=Hr.prototype={constructor:qr,select:function(t){var e=this._name,n=this._id;"function"!=typeof t&&(t=pt(t));for(var r=this._groups,i=r.length,a=new Array(i),o=0;o1&&n.name===e)return new qr([[t]],Kr,e,+r);return null}function ti(t){return function(){return t}}function ei(t,e,n){this.target=t,this.type=e,this.selection=n}function ni(){le.stopImmediatePropagation()}function ri(){le.preventDefault(),le.stopImmediatePropagation()}var ii={name:"drag"},ai={name:"space"},oi={name:"handle"},si={name:"center"};function ci(t){return[+t[0],+t[1]]}function ui(t){return[ci(t[0]),ci(t[1])]}function li(t){return function(e){return On(e,le.touches,t)}}var hi={name:"x",handles:["w","e"].map(bi),input:function(t,e){return null==t?null:[[+t[0],e[0][1]],[+t[1],e[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},fi={name:"y",handles:["n","s"].map(bi),input:function(t,e){return null==t?null:[[e[0][0],+t[0]],[e[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},di={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(bi),input:function(t){return null==t?null:ui(t)},output:function(t){return t}},pi={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},yi={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},gi={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},mi={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},vi={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function bi(t){return{type:t}}function _i(){return!le.ctrlKey&&!le.button}function xi(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function wi(){return navigator.maxTouchPoints||"ontouchstart"in this}function ki(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function Ti(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function Ei(t){var e=t.__brush;return e?e.dim.output(e.selection):null}function Ci(){return Mi(hi)}function Si(){return Mi(fi)}function Ai(){return Mi(di)}function Mi(t){var e,n=xi,r=_i,i=wi,a=!0,o=ft("start","brush","end"),s=6;function c(e){var n=e.property("__brush",y).selectAll(".overlay").data([bi("overlay")]);n.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",pi.overlay).merge(n).each((function(){var t=ki(this).extent;Te(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])})),e.selectAll(".selection").data([bi("selection")]).enter().append("rect").attr("class","selection").attr("cursor",pi.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=e.selectAll(".handle").data(t.handles,(function(t){return t.type}));r.exit().remove(),r.enter().append("rect").attr("class",(function(t){return"handle handle--"+t.type})).attr("cursor",(function(t){return pi[t.type]})),e.each(u).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",f).filter(i).on("touchstart.brush",f).on("touchmove.brush",d).on("touchend.brush touchcancel.brush",p).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function u(){var t=Te(this),e=ki(this).selection;e?(t.selectAll(".selection").style("display",null).attr("x",e[0][0]).attr("y",e[0][1]).attr("width",e[1][0]-e[0][0]).attr("height",e[1][1]-e[0][1]),t.selectAll(".handle").style("display",null).attr("x",(function(t){return"e"===t.type[t.type.length-1]?e[1][0]-s/2:e[0][0]-s/2})).attr("y",(function(t){return"s"===t.type[0]?e[1][1]-s/2:e[0][1]-s/2})).attr("width",(function(t){return"n"===t.type||"s"===t.type?e[1][0]-e[0][0]+s:s})).attr("height",(function(t){return"e"===t.type||"w"===t.type?e[1][1]-e[0][1]+s:s}))):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function l(t,e,n){var r=t.__brush.emitter;return!r||n&&r.clean?new h(t,e,n):r}function h(t,e,n){this.that=t,this.args=e,this.state=t.__brush,this.active=0,this.clean=n}function f(){if((!e||le.touches)&&r.apply(this,arguments)){var n,i,o,s,c,h,f,d,p,y,g,m=this,v=le.target.__data__.type,b="selection"===(a&&le.metaKey?v="overlay":v)?ii:a&&le.altKey?si:oi,_=t===fi?null:mi[v],x=t===hi?null:vi[v],w=ki(m),k=w.extent,T=w.selection,E=k[0][0],C=k[0][1],S=k[1][0],A=k[1][1],M=0,N=0,D=_&&x&&a&&le.shiftKey,O=le.touches?li(le.changedTouches[0].identifier):Bn,B=O(m),L=B,I=l(m,arguments,!0).beforestart();"overlay"===v?(T&&(p=!0),w.selection=T=[[n=t===fi?E:B[0],o=t===hi?C:B[1]],[c=t===fi?S:n,f=t===hi?A:o]]):(n=T[0][0],o=T[0][1],c=T[1][0],f=T[1][1]),i=n,s=o,h=c,d=f;var R=Te(m).attr("pointer-events","none"),F=R.selectAll(".overlay").attr("cursor",pi[v]);if(le.touches)I.moved=j,I.ended=z;else{var P=Te(le.view).on("mousemove.brush",j,!0).on("mouseup.brush",z,!0);a&&P.on("keydown.brush",U,!0).on("keyup.brush",q,!0),Se(le.view)}ni(),ar(m),u.call(m),I.start()}function j(){var t=O(m);!D||y||g||(Math.abs(t[0]-L[0])>Math.abs(t[1]-L[1])?g=!0:y=!0),L=t,p=!0,ri(),Y()}function Y(){var t;switch(M=L[0]-B[0],N=L[1]-B[1],b){case ai:case ii:_&&(M=Math.max(E-n,Math.min(S-c,M)),i=n+M,h=c+M),x&&(N=Math.max(C-o,Math.min(A-f,N)),s=o+N,d=f+N);break;case oi:_<0?(M=Math.max(E-n,Math.min(S-n,M)),i=n+M,h=c):_>0&&(M=Math.max(E-c,Math.min(S-c,M)),i=n,h=c+M),x<0?(N=Math.max(C-o,Math.min(A-o,N)),s=o+N,d=f):x>0&&(N=Math.max(C-f,Math.min(A-f,N)),s=o,d=f+N);break;case si:_&&(i=Math.max(E,Math.min(S,n-M*_)),h=Math.max(E,Math.min(S,c+M*_))),x&&(s=Math.max(C,Math.min(A,o-N*x)),d=Math.max(C,Math.min(A,f+N*x)))}h0&&(n=i-M),x<0?f=d-N:x>0&&(o=s-N),b=ai,F.attr("cursor",pi.selection),Y());break;default:return}ri()}function q(){switch(le.keyCode){case 16:D&&(y=g=D=!1,Y());break;case 18:b===si&&(_<0?c=h:_>0&&(n=i),x<0?f=d:x>0&&(o=s),b=oi,Y());break;case 32:b===ai&&(le.altKey?(_&&(c=h-M*_,n=i+M*_),x&&(f=d-N*x,o=s+N*x),b=si):(_<0?c=h:_>0&&(n=i),x<0?f=d:x>0&&(o=s),b=oi),F.attr("cursor",pi[v]),Y());break;default:return}ri()}}function d(){l(this,arguments).moved()}function p(){l(this,arguments).ended()}function y(){var e=this.__brush||{selection:null};return e.extent=ui(n.apply(this,arguments)),e.dim=t,e}return c.move=function(e,n){e.selection?e.on("start.brush",(function(){l(this,arguments).beforestart().start()})).on("interrupt.brush end.brush",(function(){l(this,arguments).end()})).tween("brush",(function(){var e=this,r=e.__brush,i=l(e,arguments),a=r.selection,o=t.input("function"==typeof n?n.apply(this,arguments):n,r.extent),s=Mn(a,o);function c(t){r.selection=1===t&&null===o?null:s(t),u.call(e),i.brush()}return null!==a&&null!==o?c:c(1)})):e.each((function(){var e=this,r=arguments,i=e.__brush,a=t.input("function"==typeof n?n.apply(e,r):n,i.extent),o=l(e,r).beforestart();ar(e),i.selection=null===a?null:a,u.call(e),o.start().brush().end()}))},c.clear=function(t){c.move(t,null)},h.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting?(this.starting=!1,this.emit("start")):this.emit("brush"),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(e){ge(new ei(c,e,t.output(this.state.selection)),o.apply,o,[e,this.that,this.args])}},c.extent=function(t){return arguments.length?(n="function"==typeof t?t:ti(ui(t)),c):n},c.filter=function(t){return arguments.length?(r="function"==typeof t?t:ti(!!t),c):r},c.touchable=function(t){return arguments.length?(i="function"==typeof t?t:ti(!!t),c):i},c.handleSize=function(t){return arguments.length?(s=+t,c):s},c.keyModifiers=function(t){return arguments.length?(a=!!t,c):a},c.on=function(){var t=o.on.apply(o,arguments);return t===o?c:t},c}var Ni=Math.cos,Di=Math.sin,Oi=Math.PI,Bi=Oi/2,Li=2*Oi,Ii=Math.max;function Ri(t){return function(e,n){return t(e.source.value+e.target.value,n.source.value+n.target.value)}}function Fi(){var t=0,e=null,n=null,r=null;function i(i){var a,o,s,c,u,l,h=i.length,f=[],d=k(h),p=[],y=[],g=y.groups=new Array(h),m=new Array(h*h);for(a=0,u=-1;++uUi)if(Math.abs(l*s-c*u)>Ui&&i){var f=n-a,d=r-o,p=s*s+c*c,y=f*f+d*d,g=Math.sqrt(p),m=Math.sqrt(h),v=i*Math.tan((Yi-Math.acos((p+h-y)/(2*g*m)))/2),b=v/m,_=v/g;Math.abs(b-1)>Ui&&(this._+="L"+(t+b*u)+","+(e+b*l)),this._+="A"+i+","+i+",0,0,"+ +(l*f>u*d)+","+(this._x1=t+_*s)+","+(this._y1=e+_*c)}else this._+="L"+(this._x1=t)+","+(this._y1=e)},arc:function(t,e,n,r,i,a){t=+t,e=+e,a=!!a;var o=(n=+n)*Math.cos(r),s=n*Math.sin(r),c=t+o,u=e+s,l=1^a,h=a?r-i:i-r;if(n<0)throw new Error("negative radius: "+n);null===this._x1?this._+="M"+c+","+u:(Math.abs(this._x1-c)>Ui||Math.abs(this._y1-u)>Ui)&&(this._+="L"+c+","+u),n&&(h<0&&(h=h%zi+zi),h>qi?this._+="A"+n+","+n+",0,1,"+l+","+(t-o)+","+(e-s)+"A"+n+","+n+",0,1,"+l+","+(this._x1=c)+","+(this._y1=u):h>Ui&&(this._+="A"+n+","+n+",0,"+ +(h>=Yi)+","+l+","+(this._x1=t+n*Math.cos(i))+","+(this._y1=e+n*Math.sin(i))))},rect:function(t,e,n,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+e)+"h"+ +n+"v"+ +r+"h"+-n+"Z"},toString:function(){return this._}};const Wi=$i;function Vi(t){return t.source}function Gi(t){return t.target}function Xi(t){return t.radius}function Zi(t){return t.startAngle}function Qi(t){return t.endAngle}function Ki(){var t=Vi,e=Gi,n=Xi,r=Zi,i=Qi,a=null;function o(){var o,s=Pi.call(arguments),c=t.apply(this,s),u=e.apply(this,s),l=+n.apply(this,(s[0]=c,s)),h=r.apply(this,s)-Bi,f=i.apply(this,s)-Bi,d=l*Ni(h),p=l*Di(h),y=+n.apply(this,(s[0]=u,s)),g=r.apply(this,s)-Bi,m=i.apply(this,s)-Bi;if(a||(a=o=Wi()),a.moveTo(d,p),a.arc(0,0,l,h,f),h===g&&f===m||(a.quadraticCurveTo(0,0,y*Ni(g),y*Di(g)),a.arc(0,0,y,g,m)),a.quadraticCurveTo(0,0,d,p),a.closePath(),o)return a=null,o+""||null}return o.radius=function(t){return arguments.length?(n="function"==typeof t?t:ji(+t),o):n},o.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:ji(+t),o):r},o.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:ji(+t),o):i},o.source=function(e){return arguments.length?(t=e,o):t},o.target=function(t){return arguments.length?(e=t,o):e},o.context=function(t){return arguments.length?(a=null==t?null:t,o):a},o}var Ji="$";function ta(){}function ea(t,e){var n=new ta;if(t instanceof ta)t.each((function(t,e){n.set(e,t)}));else if(Array.isArray(t)){var r,i=-1,a=t.length;if(null==e)for(;++i=r.length)return null!=t&&n.sort(t),null!=e?e(n):n;for(var c,u,l,h=-1,f=n.length,d=r[i++],p=na(),y=o();++hr.length)return t;var a,s=i[n-1];return null!=e&&n>=r.length?a=t.entries():(a=[],t.each((function(t,e){a.push({key:e,values:o(t,n)})}))),null!=s?a.sort((function(t,e){return s(t.key,e.key)})):a}return n={object:function(t){return a(t,0,ia,aa)},map:function(t){return a(t,0,oa,sa)},entries:function(t){return o(a(t,0,oa,sa),0)},key:function(t){return r.push(t),n},sortKeys:function(t){return i[r.length-1]=t,n},sortValues:function(e){return t=e,n},rollup:function(t){return e=t,n}}}function ia(){return{}}function aa(t,e,n){t[e]=n}function oa(){return na()}function sa(t,e,n){t.set(e,n)}function ca(){}var ua=na.prototype;function la(t,e){var n=new ca;if(t instanceof ca)t.each((function(t){n.add(t)}));else if(t){var r=-1,i=t.length;if(null==e)for(;++r.008856451679035631?Math.pow(t,1/3):t/xa+ba}function Sa(t){return t>_a?t*t*t:xa*(t-ba)}function Aa(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Ma(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Na(t){if(t instanceof Ba)return new Ba(t.h,t.c,t.l,t.opacity);if(t instanceof Ea||(t=wa(t)),0===t.a&&0===t.b)return new Ba(NaN,0r!=d>r&&n<(f-u)*(r-l)/(d-l)+u&&(i=-i)}return i}function Qa(t,e,n){var r,i,a,o;return function(t,e,n){return(e[0]-t[0])*(n[1]-t[1])==(n[0]-t[0])*(e[1]-t[1])}(t,e,n)&&(i=t[r=+(t[0]===e[0])],a=n[r],o=e[r],i<=a&&a<=o||o<=a&&a<=i)}function Ka(){}var Ja=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function to(){var t=1,e=1,n=N,r=s;function i(t){var e=n(t);if(Array.isArray(e))e=e.slice().sort(Va);else{var r=m(t),i=r[0],o=r[1];e=M(i,o,e),e=k(Math.floor(i/e)*e,Math.floor(o/e)*e,e)}return e.map((function(e){return a(t,e)}))}function a(n,i){var a=[],s=[];return function(n,r,i){var a,s,c,u,l,h,f=new Array,d=new Array;for(a=s=-1,u=n[0]>=r,Ja[u<<1].forEach(p);++a=r,Ja[c|u<<1].forEach(p);for(Ja[u<<0].forEach(p);++s=r,l=n[s*t]>=r,Ja[u<<1|l<<2].forEach(p);++a=r,h=l,l=n[s*t+a+1]>=r,Ja[c|u<<1|l<<2|h<<3].forEach(p);Ja[u|l<<3].forEach(p)}for(a=-1,l=n[s*t]>=r,Ja[l<<2].forEach(p);++a=r,Ja[l<<2|h<<3].forEach(p);function p(t){var e,n,r=[t[0][0]+a,t[0][1]+s],c=[t[1][0]+a,t[1][1]+s],u=o(r),l=o(c);(e=d[u])?(n=f[l])?(delete d[e.end],delete f[n.start],e===n?(e.ring.push(c),i(e.ring)):f[e.start]=d[n.end]={start:e.start,end:n.end,ring:e.ring.concat(n.ring)}):(delete d[e.end],e.ring.push(c),d[e.end=l]=e):(e=f[l])?(n=d[u])?(delete f[e.start],delete d[n.end],e===n?(e.ring.push(c),i(e.ring)):f[n.start]=d[e.end]={start:n.start,end:e.end,ring:n.ring.concat(e.ring)}):(delete f[e.start],e.ring.unshift(r),f[e.start=u]=e):f[u]=d[l]={start:u,end:l,ring:[r,c]}}Ja[l<<3].forEach(p)}(n,i,(function(t){r(t,n,i),function(t){for(var e=0,n=t.length,r=t[n-1][1]*t[0][0]-t[n-1][0]*t[0][1];++e0?a.push([t]):s.push(t)})),s.forEach((function(t){for(var e,n=0,r=a.length;n0&&o0&&s0&&a>0))throw new Error("invalid size");return t=r,e=a,i},i.thresholds=function(t){return arguments.length?(n="function"==typeof t?t:Array.isArray(t)?Ga(Wa.call(t)):Ga(t),i):n},i.smooth=function(t){return arguments.length?(r=t?s:Ka,i):r===s},i}function eo(t,e,n){for(var r=t.width,i=t.height,a=1+(n<<1),o=0;o=n&&(s>=a&&(c-=t.data[s-a+o*r]),e.data[s-n+o*r]=c/Math.min(s+1,r-1+a-s,a))}function no(t,e,n){for(var r=t.width,i=t.height,a=1+(n<<1),o=0;o=n&&(s>=a&&(c-=t.data[o+(s-a)*r]),e.data[o+(s-n)*r]=c/Math.min(s+1,i-1+a-s,a))}function ro(t){return t[0]}function io(t){return t[1]}function ao(){return 1}function oo(){var t=ro,e=io,n=ao,r=960,i=500,a=20,o=2,s=3*a,c=r+2*s>>o,u=i+2*s>>o,l=Ga(20);function h(r){var i=new Float32Array(c*u),h=new Float32Array(c*u);r.forEach((function(r,a,l){var h=+t(r,a,l)+s>>o,f=+e(r,a,l)+s>>o,d=+n(r,a,l);h>=0&&h=0&&f>o),no({width:c,height:u,data:h},{width:c,height:u,data:i},a>>o),eo({width:c,height:u,data:i},{width:c,height:u,data:h},a>>o),no({width:c,height:u,data:h},{width:c,height:u,data:i},a>>o),eo({width:c,height:u,data:i},{width:c,height:u,data:h},a>>o),no({width:c,height:u,data:h},{width:c,height:u,data:i},a>>o);var d=l(i);if(!Array.isArray(d)){var p=I(i);d=M(0,p,d),(d=k(0,Math.floor(p/d)*d,d)).shift()}return to().thresholds(d).size([c,u])(i).map(f)}function f(t){return t.value*=Math.pow(2,-2*o),t.coordinates.forEach(d),t}function d(t){t.forEach(p)}function p(t){t.forEach(y)}function y(t){t[0]=t[0]*Math.pow(2,o)-s,t[1]=t[1]*Math.pow(2,o)-s}function g(){return c=r+2*(s=3*a)>>o,u=i+2*s>>o,h}return h.x=function(e){return arguments.length?(t="function"==typeof e?e:Ga(+e),h):t},h.y=function(t){return arguments.length?(e="function"==typeof t?t:Ga(+t),h):e},h.weight=function(t){return arguments.length?(n="function"==typeof t?t:Ga(+t),h):n},h.size=function(t){if(!arguments.length)return[r,i];var e=Math.ceil(t[0]),n=Math.ceil(t[1]);if(!(e>=0||e>=0))throw new Error("invalid size");return r=e,i=n,g()},h.cellSize=function(t){if(!arguments.length)return 1<=1))throw new Error("invalid cell size");return o=Math.floor(Math.log(t)/Math.LN2),g()},h.thresholds=function(t){return arguments.length?(l="function"==typeof t?t:Array.isArray(t)?Ga(Wa.call(t)):Ga(t),h):l},h.bandwidth=function(t){if(!arguments.length)return Math.sqrt(a*(a+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return a=Math.round((Math.sqrt(4*t*t+1)-1)/2),g()},h}function so(t){return function(){return t}}function co(t,e,n,r,i,a,o,s,c,u){this.target=t,this.type=e,this.subject=n,this.identifier=r,this.active=i,this.x=a,this.y=o,this.dx=s,this.dy=c,this._=u}function uo(){return!le.ctrlKey&&!le.button}function lo(){return this.parentNode}function ho(t){return null==t?{x:le.x,y:le.y}:t}function fo(){return navigator.maxTouchPoints||"ontouchstart"in this}function po(){var t,e,n,r,i=uo,a=lo,o=ho,s=fo,c={},u=ft("start","drag","end"),l=0,h=0;function f(t){t.on("mousedown.drag",d).filter(s).on("touchstart.drag",g).on("touchmove.drag",m).on("touchend.drag touchcancel.drag",v).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function d(){if(!r&&i.apply(this,arguments)){var o=b("mouse",a.apply(this,arguments),Bn,this,arguments);o&&(Te(le.view).on("mousemove.drag",p,!0).on("mouseup.drag",y,!0),Se(le.view),Ee(),n=!1,t=le.clientX,e=le.clientY,o("start"))}}function p(){if(Ce(),!n){var r=le.clientX-t,i=le.clientY-e;n=r*r+i*i>h}c.mouse("drag")}function y(){Te(le.view).on("mousemove.drag mouseup.drag",null),Ae(le.view,n),Ce(),c.mouse("end")}function g(){if(i.apply(this,arguments)){var t,e,n=le.changedTouches,r=a.apply(this,arguments),o=n.length;for(t=0;t=a?c=!0:10===(r=t.charCodeAt(o++))?u=!0:13===r&&(u=!0,10===t.charCodeAt(o)&&++o),t.slice(i+1,e-1).replace(/""/g,'"')}for(;o9999?"+"+bo(t,6):bo(t,4)}(t.getUTCFullYear())+"-"+bo(t.getUTCMonth()+1,2)+"-"+bo(t.getUTCDate(),2)+(i?"T"+bo(e,2)+":"+bo(n,2)+":"+bo(r,2)+"."+bo(i,3)+"Z":r?"T"+bo(e,2)+":"+bo(n,2)+":"+bo(r,2)+"Z":n||e?"T"+bo(e,2)+":"+bo(n,2)+"Z":"")}(t):e.test(t+="")?'"'+t.replace(/"/g,'""')+'"':t}return{parse:function(t,e){var n,i,a=r(t,(function(t,r){if(n)return n(t,r-1);i=t,n=e?function(t,e){var n=mo(t);return function(r,i){return e(n(r),i,t)}}(t,e):mo(t)}));return a.columns=i||[],a},parseRows:r,format:function(e,n){return null==n&&(n=vo(e)),[n.map(o).join(t)].concat(i(e,n)).join("\n")},formatBody:function(t,e){return null==e&&(e=vo(t)),i(t,e).join("\n")},formatRows:function(t){return t.map(a).join("\n")},formatRow:a,formatValue:o}}var xo=_o(","),wo=xo.parse,ko=xo.parseRows,To=xo.format,Eo=xo.formatBody,Co=xo.formatRows,So=xo.formatRow,Ao=xo.formatValue,Mo=_o("\t"),No=Mo.parse,Do=Mo.parseRows,Oo=Mo.format,Bo=Mo.formatBody,Lo=Mo.formatRows,Io=Mo.formatRow,Ro=Mo.formatValue;function Fo(t){for(var e in t){var n,r,i=t[e].trim();if(i)if("true"===i)i=!0;else if("false"===i)i=!1;else if("NaN"===i)i=NaN;else if(isNaN(n=+i)){if(!(r=i.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)))continue;Po&&r[4]&&!r[7]&&(i=i.replace(/-/g,"/").replace(/T/," ")),i=new Date(i)}else i=n;else i=null;t[e]=i}return t}var Po=new Date("2019-01-01T00:00").getHours()||new Date("2019-07-01T00:00").getHours();function jo(t){return+t}function Yo(t){return t*t}function zo(t){return t*(2-t)}function Uo(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}var qo=function t(e){function n(t){return Math.pow(t,e)}return e=+e,n.exponent=t,n}(3),Ho=function t(e){function n(t){return 1-Math.pow(1-t,e)}return e=+e,n.exponent=t,n}(3),$o=function t(e){function n(t){return((t*=2)<=1?Math.pow(t,e):2-Math.pow(2-t,e))/2}return e=+e,n.exponent=t,n}(3),Wo=Math.PI,Vo=Wo/2;function Go(t){return 1==+t?1:1-Math.cos(t*Vo)}function Xo(t){return Math.sin(t*Vo)}function Zo(t){return(1-Math.cos(Wo*t))/2}function Qo(t){return 1.0009775171065494*(Math.pow(2,-10*t)-.0009765625)}function Ko(t){return Qo(1-+t)}function Jo(t){return 1-Qo(t)}function ts(t){return((t*=2)<=1?Qo(1-t):2-Qo(t-1))/2}function es(t){return 1-Math.sqrt(1-t*t)}function ns(t){return Math.sqrt(1- --t*t)}function rs(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}var is=7.5625;function as(t){return 1-os(1-t)}function os(t){return(t=+t)<.36363636363636365?is*t*t:t<.7272727272727273?is*(t-=.5454545454545454)*t+.75:t<.9090909090909091?is*(t-=.8181818181818182)*t+.9375:is*(t-=.9545454545454546)*t+.984375}function ss(t){return((t*=2)<=1?1-os(1-t):os(t-1)+1)/2}var cs=1.70158,us=function t(e){function n(t){return(t=+t)*t*(e*(t-1)+t)}return e=+e,n.overshoot=t,n}(cs),ls=function t(e){function n(t){return--t*t*((t+1)*e+t)+1}return e=+e,n.overshoot=t,n}(cs),hs=function t(e){function n(t){return((t*=2)<1?t*t*((e+1)*t-e):(t-=2)*t*((e+1)*t+e)+2)/2}return e=+e,n.overshoot=t,n}(cs),fs=2*Math.PI,ds=function t(e,n){var r=Math.asin(1/(e=Math.max(1,e)))*(n/=fs);function i(t){return e*Qo(- --t)*Math.sin((r-t)/n)}return i.amplitude=function(e){return t(e,n*fs)},i.period=function(n){return t(e,n)},i}(1,.3),ps=function t(e,n){var r=Math.asin(1/(e=Math.max(1,e)))*(n/=fs);function i(t){return 1-e*Qo(t=+t)*Math.sin((t+r)/n)}return i.amplitude=function(e){return t(e,n*fs)},i.period=function(n){return t(e,n)},i}(1,.3),ys=function t(e,n){var r=Math.asin(1/(e=Math.max(1,e)))*(n/=fs);function i(t){return((t=2*t-1)<0?e*Qo(-t)*Math.sin((r-t)/n):2-e*Qo(t)*Math.sin((r+t)/n))/2}return i.amplitude=function(e){return t(e,n*fs)},i.period=function(n){return t(e,n)},i}(1,.3);function gs(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.blob()}function ms(t,e){return fetch(t,e).then(gs)}function vs(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.arrayBuffer()}function bs(t,e){return fetch(t,e).then(vs)}function _s(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.text()}function xs(t,e){return fetch(t,e).then(_s)}function ws(t){return function(e,n,r){return 2===arguments.length&&"function"==typeof n&&(r=n,n=void 0),xs(e,n).then((function(e){return t(e,r)}))}}function ks(t,e,n,r){3===arguments.length&&"function"==typeof n&&(r=n,n=void 0);var i=_o(t);return xs(e,n).then((function(t){return i.parse(t,r)}))}var Ts=ws(wo),Es=ws(No);function Cs(t,e){return new Promise((function(n,r){var i=new Image;for(var a in e)i[a]=e[a];i.onerror=r,i.onload=function(){n(i)},i.src=t}))}function Ss(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);if(204!==t.status&&205!==t.status)return t.json()}function As(t,e){return fetch(t,e).then(Ss)}function Ms(t){return function(e,n){return xs(e,n).then((function(e){return(new DOMParser).parseFromString(e,t)}))}}const Ns=Ms("application/xml");var Ds=Ms("text/html"),Os=Ms("image/svg+xml");function Bs(t,e){var n;function r(){var r,i,a=n.length,o=0,s=0;for(r=0;r=(a=(y+m)/2))?y=a:m=a,(l=n>=(o=(g+v)/2))?g=o:v=o,i=d,!(d=d[h=l<<1|u]))return i[h]=p,t;if(s=+t._x.call(null,d.data),c=+t._y.call(null,d.data),e===s&&n===c)return p.next=d,i?i[h]=p:t._root=p,t;do{i=i?i[h]=new Array(4):t._root=new Array(4),(u=e>=(a=(y+m)/2))?y=a:m=a,(l=n>=(o=(g+v)/2))?g=o:v=o}while((h=l<<1|u)==(f=(c>=o)<<1|s>=a));return i[f]=d,i[h]=p,t}function Fs(t,e,n,r,i){this.node=t,this.x0=e,this.y0=n,this.x1=r,this.y1=i}function Ps(t){return t[0]}function js(t){return t[1]}function Ys(t,e,n){var r=new zs(null==e?Ps:e,null==n?js:n,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function zs(t,e,n,r,i,a){this._x=t,this._y=e,this._x0=n,this._y0=r,this._x1=i,this._y1=a,this._root=void 0}function Us(t){for(var e={data:t.data},n=e;t=t.next;)n=n.next={data:t.data};return e}var qs=Ys.prototype=zs.prototype;function Hs(t){return t.x+t.vx}function $s(t){return t.y+t.vy}function Ws(t){var e,n,r=1,i=1;function a(){for(var t,a,s,c,u,l,h,f=e.length,d=0;dc+d||iu+d||as.index){var p=c-o.x-o.vx,y=u-o.y-o.vy,g=p*p+y*y;gt.r&&(t.r=t[e].r)}function s(){if(e){var r,i,a=e.length;for(n=new Array(a),r=0;rl&&(l=r),ih&&(h=i));if(c>l||u>h)return this;for(this.cover(c,u).cover(l,h),n=0;nt||t>=i||r>e||e>=a;)switch(s=(ef||(a=c.y0)>d||(o=c.x1)=m)<<1|t>=g)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-u],p[p.length-1-u]=c)}else{var v=t-+this._x.call(null,y.data),b=e-+this._y.call(null,y.data),_=v*v+b*b;if(_=(s=(p+g)/2))?p=s:g=s,(l=o>=(c=(y+m)/2))?y=c:m=c,e=d,!(d=d[h=l<<1|u]))return this;if(!d.length)break;(e[h+1&3]||e[h+2&3]||e[h+3&3])&&(n=e,f=h)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):e?(i?e[h]=i:delete e[h],(d=e[0]||e[1]||e[2]||e[3])&&d===(e[3]||e[2]||e[1]||e[0])&&!d.length&&(n?n[f]=d:this._root=d),this):(this._root=i,this)},qs.removeAll=function(t){for(var e=0,n=t.length;e1?(null==n?s.remove(t):s.set(t,d(n)),e):s.get(t)},find:function(e,n,r){var i,a,o,s,c,u=0,l=t.length;for(null==r?r=1/0:r*=r,u=0;u1?(u.on(t,n),e):u.on(t)}}}function tc(){var t,e,n,r,i=Ls(-30),a=1,o=1/0,s=.81;function c(r){var i,a=t.length,o=Ys(t,Zs,Qs).visitAfter(l);for(n=r,i=0;i=o)){(t.data!==e||t.next)&&(0===l&&(d+=(l=Is())*l),0===h&&(d+=(h=Is())*h),d1?r[0]+r.slice(2):r,+t.slice(n+1)]}function ac(t){return(t=ic(Math.abs(t)))?t[1]:NaN}var oc,sc=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function cc(t){if(!(e=sc.exec(t)))throw new Error("invalid format: "+t);var e;return new uc({fill:e[1],align:e[2],sign:e[3],symbol:e[4],zero:e[5],width:e[6],comma:e[7],precision:e[8]&&e[8].slice(1),trim:e[9],type:e[10]})}function uc(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function lc(t,e){var n=ic(t,e);if(!n)return t+"";var r=n[0],i=n[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}cc.prototype=uc.prototype,uc.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};const hc={"%":function(t,e){return(100*t).toFixed(e)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:function(t,e){return t.toExponential(e)},f:function(t,e){return t.toFixed(e)},g:function(t,e){return t.toPrecision(e)},o:function(t){return Math.round(t).toString(8)},p:function(t,e){return lc(100*t,e)},r:lc,s:function(t,e){var n=ic(t,e);if(!n)return t+"";var r=n[0],i=n[1],a=i-(oc=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,o=r.length;return a===o?r:a>o?r+new Array(a-o+1).join("0"):a>0?r.slice(0,a)+"."+r.slice(a):"0."+new Array(1-a).join("0")+ic(t,Math.max(0,e+a-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}};function fc(t){return t}var dc,pc,yc,gc=Array.prototype.map,mc=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function vc(t){var e,n,r=void 0===t.grouping||void 0===t.thousands?fc:(e=gc.call(t.grouping,Number),n=t.thousands+"",function(t,r){for(var i=t.length,a=[],o=0,s=e[0],c=0;i>0&&s>0&&(c+s+1>r&&(s=Math.max(1,r-c)),a.push(t.substring(i-=s,i+s)),!((c+=s+1)>r));)s=e[o=(o+1)%e.length];return a.reverse().join(n)}),i=void 0===t.currency?"":t.currency[0]+"",a=void 0===t.currency?"":t.currency[1]+"",o=void 0===t.decimal?".":t.decimal+"",s=void 0===t.numerals?fc:function(t){return function(e){return e.replace(/[0-9]/g,(function(e){return t[+e]}))}}(gc.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",u=void 0===t.minus?"-":t.minus+"",l=void 0===t.nan?"NaN":t.nan+"";function h(t){var e=(t=cc(t)).fill,n=t.align,h=t.sign,f=t.symbol,d=t.zero,p=t.width,y=t.comma,g=t.precision,m=t.trim,v=t.type;"n"===v?(y=!0,v="g"):hc[v]||(void 0===g&&(g=12),m=!0,v="g"),(d||"0"===e&&"="===n)&&(d=!0,e="0",n="=");var b="$"===f?i:"#"===f&&/[boxX]/.test(v)?"0"+v.toLowerCase():"",_="$"===f?a:/[%p]/.test(v)?c:"",x=hc[v],w=/[defgprs%]/.test(v);function k(t){var i,a,c,f=b,k=_;if("c"===v)k=x(t)+k,t="";else{var T=(t=+t)<0||1/t<0;if(t=isNaN(t)?l:x(Math.abs(t),g),m&&(t=function(t){t:for(var e,n=t.length,r=1,i=-1;r0&&(i=0)}return i>0?t.slice(0,i)+t.slice(e+1):t}(t)),T&&0==+t&&"+"!==h&&(T=!1),f=(T?"("===h?h:u:"-"===h||"("===h?"":h)+f,k=("s"===v?mc[8+oc/3]:"")+k+(T&&"("===h?")":""),w)for(i=-1,a=t.length;++i(c=t.charCodeAt(i))||c>57){k=(46===c?o+t.slice(i+1):t.slice(i))+k,t=t.slice(0,i);break}}y&&!d&&(t=r(t,1/0));var E=f.length+t.length+k.length,C=E>1)+f+t+k+C.slice(E);break;default:t=C+f+t+k}return s(t)}return g=void 0===g?6:/[gprs]/.test(v)?Math.max(1,Math.min(21,g)):Math.max(0,Math.min(20,g)),k.toString=function(){return t+""},k}return{format:h,formatPrefix:function(t,e){var n=h(((t=cc(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(ac(e)/3))),i=Math.pow(10,-r),a=mc[8+r/3];return function(t){return n(i*t)+a}}}}function bc(t){return dc=vc(t),pc=dc.format,yc=dc.formatPrefix,dc}function _c(t){return Math.max(0,-ac(Math.abs(t)))}function xc(t,e){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(ac(e)/3)))-ac(Math.abs(t)))}function wc(t,e){return t=Math.abs(t),e=Math.abs(e)-t,Math.max(0,ac(e)-ac(t))+1}function kc(){return new Tc}function Tc(){this.reset()}bc({decimal:".",thousands:",",grouping:[3],currency:["$",""],minus:"-"}),Tc.prototype={constructor:Tc,reset:function(){this.s=this.t=0},add:function(t){Cc(Ec,t,this.t),Cc(this,Ec.s,this.s),this.s?this.t+=Ec.t:this.s=Ec.t},valueOf:function(){return this.s}};var Ec=new Tc;function Cc(t,e,n){var r=t.s=e+n,i=r-e,a=r-i;t.t=e-a+(n-i)}var Sc=1e-6,Ac=1e-12,Mc=Math.PI,Nc=Mc/2,Dc=Mc/4,Oc=2*Mc,Bc=180/Mc,Lc=Mc/180,Ic=Math.abs,Rc=Math.atan,Fc=Math.atan2,Pc=Math.cos,jc=Math.ceil,Yc=Math.exp,zc=(Math.floor,Math.log),Uc=Math.pow,qc=Math.sin,Hc=Math.sign||function(t){return t>0?1:t<0?-1:0},$c=Math.sqrt,Wc=Math.tan;function Vc(t){return t>1?0:t<-1?Mc:Math.acos(t)}function Gc(t){return t>1?Nc:t<-1?-Nc:Math.asin(t)}function Xc(t){return(t=qc(t/2))*t}function Zc(){}function Qc(t,e){t&&Jc.hasOwnProperty(t.type)&&Jc[t.type](t,e)}var Kc={Feature:function(t,e){Qc(t.geometry,e)},FeatureCollection:function(t,e){for(var n=t.features,r=-1,i=n.length;++r=0?1:-1,i=r*n,a=Pc(e=(e*=Lc)/2+Dc),o=qc(e),s=su*o,c=ou*a+s*Pc(i),u=s*r*qc(i);cu.add(Fc(u,c)),au=t,ou=a,su=o}function yu(t){return uu.reset(),nu(t,lu),2*uu}function gu(t){return[Fc(t[1],t[0]),Gc(t[2])]}function mu(t){var e=t[0],n=t[1],r=Pc(n);return[r*Pc(e),r*qc(e),qc(n)]}function vu(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function bu(t,e){return[t[1]*e[2]-t[2]*e[1],t[2]*e[0]-t[0]*e[2],t[0]*e[1]-t[1]*e[0]]}function _u(t,e){t[0]+=e[0],t[1]+=e[1],t[2]+=e[2]}function xu(t,e){return[t[0]*e,t[1]*e,t[2]*e]}function wu(t){var e=$c(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=e,t[1]/=e,t[2]/=e}var ku,Tu,Eu,Cu,Su,Au,Mu,Nu,Du,Ou,Bu,Lu,Iu,Ru,Fu,Pu,ju,Yu,zu,Uu,qu,Hu,$u,Wu,Vu,Gu,Xu=kc(),Zu={point:Qu,lineStart:Ju,lineEnd:tl,polygonStart:function(){Zu.point=el,Zu.lineStart=nl,Zu.lineEnd=rl,Xu.reset(),lu.polygonStart()},polygonEnd:function(){lu.polygonEnd(),Zu.point=Qu,Zu.lineStart=Ju,Zu.lineEnd=tl,cu<0?(ku=-(Eu=180),Tu=-(Cu=90)):Xu>Sc?Cu=90:Xu<-1e-6&&(Tu=-90),Ou[0]=ku,Ou[1]=Eu},sphere:function(){ku=-(Eu=180),Tu=-(Cu=90)}};function Qu(t,e){Du.push(Ou=[ku=t,Eu=t]),eCu&&(Cu=e)}function Ku(t,e){var n=mu([t*Lc,e*Lc]);if(Nu){var r=bu(Nu,n),i=bu([r[1],-r[0],0],r);wu(i),i=gu(i);var a,o=t-Su,s=o>0?1:-1,c=i[0]*Bc*s,u=Ic(o)>180;u^(s*SuCu&&(Cu=a):u^(s*Su<(c=(c+360)%360-180)&&cCu&&(Cu=e)),u?til(ku,Eu)&&(Eu=t):il(t,Eu)>il(ku,Eu)&&(ku=t):Eu>=ku?(tEu&&(Eu=t)):t>Su?il(ku,t)>il(ku,Eu)&&(Eu=t):il(t,Eu)>il(ku,Eu)&&(ku=t)}else Du.push(Ou=[ku=t,Eu=t]);eCu&&(Cu=e),Nu=n,Su=t}function Ju(){Zu.point=Ku}function tl(){Ou[0]=ku,Ou[1]=Eu,Zu.point=Qu,Nu=null}function el(t,e){if(Nu){var n=t-Su;Xu.add(Ic(n)>180?n+(n>0?360:-360):n)}else Au=t,Mu=e;lu.point(t,e),Ku(t,e)}function nl(){lu.lineStart()}function rl(){el(Au,Mu),lu.lineEnd(),Ic(Xu)>Sc&&(ku=-(Eu=180)),Ou[0]=ku,Ou[1]=Eu,Nu=null}function il(t,e){return(e-=t)<0?e+360:e}function al(t,e){return t[0]-e[0]}function ol(t,e){return t[0]<=t[1]?t[0]<=e&&e<=t[1]:eil(r[0],r[1])&&(r[1]=i[1]),il(i[0],r[1])>il(r[0],r[1])&&(r[0]=i[0])):a.push(r=i);for(o=-1/0,e=0,r=a[n=a.length-1];e<=n;r=i,++e)i=a[e],(s=il(r[1],i[0]))>o&&(o=s,ku=i[0],Eu=r[1])}return Du=Ou=null,ku===1/0||Tu===1/0?[[NaN,NaN],[NaN,NaN]]:[[ku,Tu],[Eu,Cu]]}var cl={sphere:Zc,point:ul,lineStart:hl,lineEnd:pl,polygonStart:function(){cl.lineStart=yl,cl.lineEnd=gl},polygonEnd:function(){cl.lineStart=hl,cl.lineEnd=pl}};function ul(t,e){t*=Lc;var n=Pc(e*=Lc);ll(n*Pc(t),n*qc(t),qc(e))}function ll(t,e,n){++Bu,Iu+=(t-Iu)/Bu,Ru+=(e-Ru)/Bu,Fu+=(n-Fu)/Bu}function hl(){cl.point=fl}function fl(t,e){t*=Lc;var n=Pc(e*=Lc);Wu=n*Pc(t),Vu=n*qc(t),Gu=qc(e),cl.point=dl,ll(Wu,Vu,Gu)}function dl(t,e){t*=Lc;var n=Pc(e*=Lc),r=n*Pc(t),i=n*qc(t),a=qc(e),o=Fc($c((o=Vu*a-Gu*i)*o+(o=Gu*r-Wu*a)*o+(o=Wu*i-Vu*r)*o),Wu*r+Vu*i+Gu*a);Lu+=o,Pu+=o*(Wu+(Wu=r)),ju+=o*(Vu+(Vu=i)),Yu+=o*(Gu+(Gu=a)),ll(Wu,Vu,Gu)}function pl(){cl.point=ul}function yl(){cl.point=ml}function gl(){vl(Hu,$u),cl.point=ul}function ml(t,e){Hu=t,$u=e,t*=Lc,e*=Lc,cl.point=vl;var n=Pc(e);Wu=n*Pc(t),Vu=n*qc(t),Gu=qc(e),ll(Wu,Vu,Gu)}function vl(t,e){t*=Lc;var n=Pc(e*=Lc),r=n*Pc(t),i=n*qc(t),a=qc(e),o=Vu*a-Gu*i,s=Gu*r-Wu*a,c=Wu*i-Vu*r,u=$c(o*o+s*s+c*c),l=Gc(u),h=u&&-l/u;zu+=h*o,Uu+=h*s,qu+=h*c,Lu+=l,Pu+=l*(Wu+(Wu=r)),ju+=l*(Vu+(Vu=i)),Yu+=l*(Gu+(Gu=a)),ll(Wu,Vu,Gu)}function bl(t){Bu=Lu=Iu=Ru=Fu=Pu=ju=Yu=zu=Uu=qu=0,nu(t,cl);var e=zu,n=Uu,r=qu,i=e*e+n*n+r*r;return iMc?t+Math.round(-t/Oc)*Oc:t,e]}function kl(t,e,n){return(t%=Oc)?e||n?xl(El(t),Cl(e,n)):El(t):e||n?Cl(e,n):wl}function Tl(t){return function(e,n){return[(e+=t)>Mc?e-Oc:e<-Mc?e+Oc:e,n]}}function El(t){var e=Tl(t);return e.invert=Tl(-t),e}function Cl(t,e){var n=Pc(t),r=qc(t),i=Pc(e),a=qc(e);function o(t,e){var o=Pc(e),s=Pc(t)*o,c=qc(t)*o,u=qc(e),l=u*n+s*r;return[Fc(c*i-l*a,s*n-u*r),Gc(l*i+c*a)]}return o.invert=function(t,e){var o=Pc(e),s=Pc(t)*o,c=qc(t)*o,u=qc(e),l=u*i-c*a;return[Fc(c*i+u*a,s*n+l*r),Gc(l*n-s*r)]},o}function Sl(t){function e(e){return(e=t(e[0]*Lc,e[1]*Lc))[0]*=Bc,e[1]*=Bc,e}return t=kl(t[0]*Lc,t[1]*Lc,t.length>2?t[2]*Lc:0),e.invert=function(e){return(e=t.invert(e[0]*Lc,e[1]*Lc))[0]*=Bc,e[1]*=Bc,e},e}function Al(t,e,n,r,i,a){if(n){var o=Pc(e),s=qc(e),c=r*n;null==i?(i=e+r*Oc,a=e-c/2):(i=Ml(o,i),a=Ml(o,a),(r>0?ia)&&(i+=r*Oc));for(var u,l=i;r>0?l>a:l1&&e.push(e.pop().concat(e.shift()))},result:function(){var n=e;return e=[],t=null,n}}}function Ol(t,e){return Ic(t[0]-e[0])=0;--a)i.point((l=u[a])[0],l[1]);else r(f.x,f.p.x,-1,i);f=f.p}u=(f=f.o).z,d=!d}while(!f.v);i.lineEnd()}}}function Il(t){if(e=t.length){for(var e,n,r=0,i=t[0];++r=0?1:-1,E=T*k,C=E>Mc,S=y*x;if(Rl.add(Fc(S*T*qc(E),g*w+S*Pc(E))),o+=C?k+T*Oc:k,C^d>=n^b>=n){var A=bu(mu(f),mu(v));wu(A);var M=bu(a,A);wu(M);var N=(C^k>=0?-1:1)*Gc(M[2]);(r>N||r===N&&(A[0]||A[1]))&&(s+=C^k>=0?1:-1)}}return(o<-1e-6||o0){for(h||(i.polygonStart(),h=!0),i.lineStart(),t=0;t1&&2&c&&f.push(f.pop().concat(f.shift())),o.push(f.filter(Yl))}return f}}function Yl(t){return t.length>1}function zl(t,e){return((t=t.x)[0]<0?t[1]-Nc-Sc:Nc-t[1])-((e=e.x)[0]<0?e[1]-Nc-Sc:Nc-e[1])}const Ul=jl((function(){return!0}),(function(t){var e,n=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),e=1},point:function(a,o){var s=a>0?Mc:-Mc,c=Ic(a-n);Ic(c-Mc)0?Nc:-Nc),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(s,r),t.point(a,r),e=0):i!==s&&c>=Mc&&(Ic(n-i)Sc?Rc((qc(e)*(a=Pc(r))*qc(n)-qc(r)*(i=Pc(e))*qc(t))/(i*a*o)):(e+r)/2}(n,r,a,o),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(s,r),e=0),t.point(n=a,r=o),i=s},lineEnd:function(){t.lineEnd(),n=r=NaN},clean:function(){return 2-e}}}),(function(t,e,n,r){var i;if(null==t)i=n*Nc,r.point(-Mc,i),r.point(0,i),r.point(Mc,i),r.point(Mc,0),r.point(Mc,-i),r.point(0,-i),r.point(-Mc,-i),r.point(-Mc,0),r.point(-Mc,i);else if(Ic(t[0]-e[0])>Sc){var a=t[0]0,i=Ic(e)>Sc;function a(t,n){return Pc(t)*Pc(n)>e}function o(t,n,r){var i=[1,0,0],a=bu(mu(t),mu(n)),o=vu(a,a),s=a[0],c=o-s*s;if(!c)return!r&&t;var u=e*o/c,l=-e*s/c,h=bu(i,a),f=xu(i,u);_u(f,xu(a,l));var d=h,p=vu(f,d),y=vu(d,d),g=p*p-y*(vu(f,f)-1);if(!(g<0)){var m=$c(g),v=xu(d,(-p-m)/y);if(_u(v,f),v=gu(v),!r)return v;var b,_=t[0],x=n[0],w=t[1],k=n[1];x<_&&(b=_,_=x,x=b);var T=x-_,E=Ic(T-Mc)0^v[1]<(Ic(v[0]-_)Mc^(_<=v[0]&&v[0]<=x)){var C=xu(d,(-p+m)/y);return _u(C,f),[v,gu(C)]}}}function s(e,n){var i=r?t:Mc-t,a=0;return e<-i?a|=1:e>i&&(a|=2),n<-i?a|=4:n>i&&(a|=8),a}return jl(a,(function(t){var e,n,c,u,l;return{lineStart:function(){u=c=!1,l=1},point:function(h,f){var d,p=[h,f],y=a(h,f),g=r?y?0:s(h,f):y?s(h+(h<0?Mc:-Mc),f):0;if(!e&&(u=c=y)&&t.lineStart(),y!==c&&(!(d=o(e,p))||Ol(e,d)||Ol(p,d))&&(p[2]=1),y!==c)l=0,y?(t.lineStart(),d=o(p,e),t.point(d[0],d[1])):(d=o(e,p),t.point(d[0],d[1],2),t.lineEnd()),e=d;else if(i&&e&&r^y){var m;g&n||!(m=o(p,e,!0))||(l=0,r?(t.lineStart(),t.point(m[0][0],m[0][1]),t.point(m[1][0],m[1][1]),t.lineEnd()):(t.point(m[1][0],m[1][1]),t.lineEnd(),t.lineStart(),t.point(m[0][0],m[0][1],3)))}!y||e&&Ol(e,p)||t.point(p[0],p[1]),e=p,c=y,n=g},lineEnd:function(){c&&t.lineEnd(),e=null},clean:function(){return l|(u&&c)<<1}}}),(function(e,r,i,a){Al(a,t,n,i,e,r)}),r?[0,-t]:[-Mc,t-Mc])}var Hl=1e9,$l=-Hl;function Wl(t,e,n,r){function i(i,a){return t<=i&&i<=n&&e<=a&&a<=r}function a(i,a,s,u){var l=0,h=0;if(null==i||(l=o(i,s))!==(h=o(a,s))||c(i,a)<0^s>0)do{u.point(0===l||3===l?t:n,l>1?r:e)}while((l=(l+s+4)%4)!==h);else u.point(a[0],a[1])}function o(r,i){return Ic(r[0]-t)0?0:3:Ic(r[0]-n)0?2:1:Ic(r[1]-e)0?1:0:i>0?3:2}function s(t,e){return c(t.x,e.x)}function c(t,e){var n=o(t,1),r=o(e,1);return n!==r?n-r:0===n?e[1]-t[1]:1===n?t[0]-e[0]:2===n?t[1]-e[1]:e[0]-t[0]}return function(o){var c,u,l,h,f,d,p,y,g,m,v,b=o,_=Dl(),x={point:w,lineStart:function(){x.point=k,u&&u.push(l=[]),m=!0,g=!1,p=y=NaN},lineEnd:function(){c&&(k(h,f),d&&g&&_.rejoin(),c.push(_.result())),x.point=w,g&&b.lineEnd()},polygonStart:function(){b=_,c=[],u=[],v=!0},polygonEnd:function(){var e=function(){for(var e=0,n=0,i=u.length;nr&&(f-a)*(r-o)>(d-o)*(t-a)&&++e:d<=r&&(f-a)*(r-o)<(d-o)*(t-a)&&--e;return e}(),n=v&&e,i=(c=P(c)).length;(n||i)&&(o.polygonStart(),n&&(o.lineStart(),a(null,null,1,o),o.lineEnd()),i&&Ll(c,s,e,a,o),o.polygonEnd()),b=o,c=u=l=null}};function w(t,e){i(t,e)&&b.point(t,e)}function k(a,o){var s=i(a,o);if(u&&l.push([a,o]),m)h=a,f=o,d=s,m=!1,s&&(b.lineStart(),b.point(a,o));else if(s&&g)b.point(a,o);else{var c=[p=Math.max($l,Math.min(Hl,p)),y=Math.max($l,Math.min(Hl,y))],_=[a=Math.max($l,Math.min(Hl,a)),o=Math.max($l,Math.min(Hl,o))];!function(t,e,n,r,i,a){var o,s=t[0],c=t[1],u=0,l=1,h=e[0]-s,f=e[1]-c;if(o=n-s,h||!(o>0)){if(o/=h,h<0){if(o0){if(o>l)return;o>u&&(u=o)}if(o=i-s,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>u&&(u=o)}else if(h>0){if(o0)){if(o/=f,f<0){if(o0){if(o>l)return;o>u&&(u=o)}if(o=a-c,f||!(o<0)){if(o/=f,f<0){if(o>l)return;o>u&&(u=o)}else if(f>0){if(o0&&(t[0]=s+u*h,t[1]=c+u*f),l<1&&(e[0]=s+l*h,e[1]=c+l*f),!0}}}}}(c,_,t,e,n,r)?s&&(b.lineStart(),b.point(a,o),v=!1):(g||(b.lineStart(),b.point(c[0],c[1])),b.point(_[0],_[1]),s||b.lineEnd(),v=!1)}p=a,y=o,g=s}return x}}function Vl(){var t,e,n,r=0,i=0,a=960,o=500;return n={stream:function(n){return t&&e===n?t:t=Wl(r,i,a,o)(e=n)},extent:function(s){return arguments.length?(r=+s[0][0],i=+s[0][1],a=+s[1][0],o=+s[1][1],t=e=null,n):[[r,i],[a,o]]}}}var Gl,Xl,Zl,Ql=kc(),Kl={sphere:Zc,point:Zc,lineStart:function(){Kl.point=th,Kl.lineEnd=Jl},lineEnd:Zc,polygonStart:Zc,polygonEnd:Zc};function Jl(){Kl.point=Kl.lineEnd=Zc}function th(t,e){Gl=t*=Lc,Xl=qc(e*=Lc),Zl=Pc(e),Kl.point=eh}function eh(t,e){t*=Lc;var n=qc(e*=Lc),r=Pc(e),i=Ic(t-Gl),a=Pc(i),o=r*qc(i),s=Zl*n-Xl*r*a,c=Xl*n+Zl*r*a;Ql.add(Fc($c(o*o+s*s),c)),Gl=t,Xl=n,Zl=r}function nh(t){return Ql.reset(),nu(t,Kl),+Ql}var rh=[null,null],ih={type:"LineString",coordinates:rh};function ah(t,e){return rh[0]=t,rh[1]=e,nh(ih)}var oh={Feature:function(t,e){return ch(t.geometry,e)},FeatureCollection:function(t,e){for(var n=t.features,r=-1,i=n.length;++r0&&(i=ah(t[a],t[a-1]))>0&&n<=i&&r<=i&&(n+r-i)*(1-Math.pow((n-r)/i,2))Sc})).map(c)).concat(k(jc(a/d)*d,i,d).filter((function(t){return Ic(t%y)>Sc})).map(u))}return m.lines=function(){return v().map((function(t){return{type:"LineString",coordinates:t}}))},m.outline=function(){return{type:"Polygon",coordinates:[l(r).concat(h(o).slice(1),l(n).reverse().slice(1),h(s).reverse().slice(1))]}},m.extent=function(t){return arguments.length?m.extentMajor(t).extentMinor(t):m.extentMinor()},m.extentMajor=function(t){return arguments.length?(r=+t[0][0],n=+t[1][0],s=+t[0][1],o=+t[1][1],r>n&&(t=r,r=n,n=t),s>o&&(t=s,s=o,o=t),m.precision(g)):[[r,s],[n,o]]},m.extentMinor=function(n){return arguments.length?(e=+n[0][0],t=+n[1][0],a=+n[0][1],i=+n[1][1],e>t&&(n=e,e=t,t=n),a>i&&(n=a,a=i,i=n),m.precision(g)):[[e,a],[t,i]]},m.step=function(t){return arguments.length?m.stepMajor(t).stepMinor(t):m.stepMinor()},m.stepMajor=function(t){return arguments.length?(p=+t[0],y=+t[1],m):[p,y]},m.stepMinor=function(t){return arguments.length?(f=+t[0],d=+t[1],m):[f,d]},m.precision=function(f){return arguments.length?(g=+f,c=yh(a,i,90),u=gh(e,t,g),l=yh(s,o,90),h=gh(r,n,g),m):g},m.extentMajor([[-180,-89.999999],[180,89.999999]]).extentMinor([[-180,-80.000001],[180,80.000001]])}function vh(){return mh()()}function bh(t,e){var n=t[0]*Lc,r=t[1]*Lc,i=e[0]*Lc,a=e[1]*Lc,o=Pc(r),s=qc(r),c=Pc(a),u=qc(a),l=o*Pc(n),h=o*qc(n),f=c*Pc(i),d=c*qc(i),p=2*Gc($c(Xc(a-r)+o*c*Xc(i-n))),y=qc(p),g=p?function(t){var e=qc(t*=p)/y,n=qc(p-t)/y,r=n*l+e*f,i=n*h+e*d,a=n*s+e*u;return[Fc(i,r)*Bc,Fc(a,$c(r*r+i*i))*Bc]}:function(){return[n*Bc,r*Bc]};return g.distance=p,g}function _h(t){return t}var xh,wh,kh,Th,Eh=kc(),Ch=kc(),Sh={point:Zc,lineStart:Zc,lineEnd:Zc,polygonStart:function(){Sh.lineStart=Ah,Sh.lineEnd=Dh},polygonEnd:function(){Sh.lineStart=Sh.lineEnd=Sh.point=Zc,Eh.add(Ic(Ch)),Ch.reset()},result:function(){var t=Eh/2;return Eh.reset(),t}};function Ah(){Sh.point=Mh}function Mh(t,e){Sh.point=Nh,xh=kh=t,wh=Th=e}function Nh(t,e){Ch.add(Th*t-kh*e),kh=t,Th=e}function Dh(){Nh(xh,wh)}const Oh=Sh;var Bh=1/0,Lh=Bh,Ih=-Bh,Rh=Ih,Fh={point:function(t,e){tIh&&(Ih=t),eRh&&(Rh=e)},lineStart:Zc,lineEnd:Zc,polygonStart:Zc,polygonEnd:Zc,result:function(){var t=[[Bh,Lh],[Ih,Rh]];return Ih=Rh=-(Lh=Bh=1/0),t}};const Ph=Fh;var jh,Yh,zh,Uh,qh=0,Hh=0,$h=0,Wh=0,Vh=0,Gh=0,Xh=0,Zh=0,Qh=0,Kh={point:Jh,lineStart:tf,lineEnd:rf,polygonStart:function(){Kh.lineStart=af,Kh.lineEnd=of},polygonEnd:function(){Kh.point=Jh,Kh.lineStart=tf,Kh.lineEnd=rf},result:function(){var t=Qh?[Xh/Qh,Zh/Qh]:Gh?[Wh/Gh,Vh/Gh]:$h?[qh/$h,Hh/$h]:[NaN,NaN];return qh=Hh=$h=Wh=Vh=Gh=Xh=Zh=Qh=0,t}};function Jh(t,e){qh+=t,Hh+=e,++$h}function tf(){Kh.point=ef}function ef(t,e){Kh.point=nf,Jh(zh=t,Uh=e)}function nf(t,e){var n=t-zh,r=e-Uh,i=$c(n*n+r*r);Wh+=i*(zh+t)/2,Vh+=i*(Uh+e)/2,Gh+=i,Jh(zh=t,Uh=e)}function rf(){Kh.point=Jh}function af(){Kh.point=sf}function of(){cf(jh,Yh)}function sf(t,e){Kh.point=cf,Jh(jh=zh=t,Yh=Uh=e)}function cf(t,e){var n=t-zh,r=e-Uh,i=$c(n*n+r*r);Wh+=i*(zh+t)/2,Vh+=i*(Uh+e)/2,Gh+=i,Xh+=(i=Uh*t-zh*e)*(zh+t),Zh+=i*(Uh+e),Qh+=3*i,Jh(zh=t,Uh=e)}const uf=Kh;function lf(t){this._context=t}lf.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,e){switch(this._point){case 0:this._context.moveTo(t,e),this._point=1;break;case 1:this._context.lineTo(t,e);break;default:this._context.moveTo(t+this._radius,e),this._context.arc(t,e,this._radius,0,Oc)}},result:Zc};var hf,ff,df,pf,yf,gf=kc(),mf={point:Zc,lineStart:function(){mf.point=vf},lineEnd:function(){hf&&bf(ff,df),mf.point=Zc},polygonStart:function(){hf=!0},polygonEnd:function(){hf=null},result:function(){var t=+gf;return gf.reset(),t}};function vf(t,e){mf.point=bf,ff=pf=t,df=yf=e}function bf(t,e){pf-=t,yf-=e,gf.add($c(pf*pf+yf*yf)),pf=t,yf=e}const _f=mf;function xf(){this._string=[]}function wf(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function kf(t,e){var n,r,i=4.5;function a(t){return t&&("function"==typeof i&&r.pointRadius(+i.apply(this,arguments)),nu(t,n(r))),r.result()}return a.area=function(t){return nu(t,n(Oh)),Oh.result()},a.measure=function(t){return nu(t,n(_f)),_f.result()},a.bounds=function(t){return nu(t,n(Ph)),Ph.result()},a.centroid=function(t){return nu(t,n(uf)),uf.result()},a.projection=function(e){return arguments.length?(n=null==e?(t=null,_h):(t=e).stream,a):t},a.context=function(t){return arguments.length?(r=null==t?(e=null,new xf):new lf(e=t),"function"!=typeof i&&r.pointRadius(i),a):e},a.pointRadius=function(t){return arguments.length?(i="function"==typeof t?t:(r.pointRadius(+t),+t),a):i},a.projection(t).context(e)}function Tf(t){return{stream:Ef(t)}}function Ef(t){return function(e){var n=new Cf;for(var r in t)n[r]=t[r];return n.stream=e,n}}function Cf(){}function Sf(t,e,n){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),nu(n,t.stream(Ph)),e(Ph.result()),null!=r&&t.clipExtent(r),t}function Af(t,e,n){return Sf(t,(function(n){var r=e[1][0]-e[0][0],i=e[1][1]-e[0][1],a=Math.min(r/(n[1][0]-n[0][0]),i/(n[1][1]-n[0][1])),o=+e[0][0]+(r-a*(n[1][0]+n[0][0]))/2,s=+e[0][1]+(i-a*(n[1][1]+n[0][1]))/2;t.scale(150*a).translate([o,s])}),n)}function Mf(t,e,n){return Af(t,[[0,0],e],n)}function Nf(t,e,n){return Sf(t,(function(n){var r=+e,i=r/(n[1][0]-n[0][0]),a=(r-i*(n[1][0]+n[0][0]))/2,o=-i*n[0][1];t.scale(150*i).translate([a,o])}),n)}function Df(t,e,n){return Sf(t,(function(n){var r=+e,i=r/(n[1][1]-n[0][1]),a=-i*n[0][0],o=(r-i*(n[1][1]+n[0][1]))/2;t.scale(150*i).translate([a,o])}),n)}xf.prototype={_radius:4.5,_circle:wf(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,e){switch(this._point){case 0:this._string.push("M",t,",",e),this._point=1;break;case 1:this._string.push("L",t,",",e);break;default:null==this._circle&&(this._circle=wf(this._radius)),this._string.push("M",t,",",e,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}},Cf.prototype={constructor:Cf,point:function(t,e){this.stream.point(t,e)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var Of=Pc(30*Lc);function Bf(t,e){return+e?function(t,e){function n(r,i,a,o,s,c,u,l,h,f,d,p,y,g){var m=u-r,v=l-i,b=m*m+v*v;if(b>4*e&&y--){var _=o+f,x=s+d,w=c+p,k=$c(_*_+x*x+w*w),T=Gc(w/=k),E=Ic(Ic(w)-1)e||Ic((m*M+v*N)/b-.5)>.3||o*f+s*d+c*p2?t[2]%360*Lc:0,M()):[g*Bc,m*Bc,v*Bc]},S.angle=function(t){return arguments.length?(b=t%360*Lc,M()):b*Bc},S.reflectX=function(t){return arguments.length?(_=t?-1:1,M()):_<0},S.reflectY=function(t){return arguments.length?(x=t?-1:1,M()):x<0},S.precision=function(t){return arguments.length?(o=Bf(s,C=t*t),N()):$c(C)},S.fitExtent=function(t,e){return Af(S,t,e)},S.fitSize=function(t,e){return Mf(S,t,e)},S.fitWidth=function(t,e){return Nf(S,t,e)},S.fitHeight=function(t,e){return Df(S,t,e)},function(){return e=t.apply(this,arguments),S.invert=e.invert&&A,M()}}function jf(t){var e=0,n=Mc/3,r=Pf(t),i=r(e,n);return i.parallels=function(t){return arguments.length?r(e=t[0]*Lc,n=t[1]*Lc):[e*Bc,n*Bc]},i}function Yf(t,e){var n=qc(t),r=(n+qc(e))/2;if(Ic(r)=.12&&i<.234&&r>=-.425&&r<-.214?s:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:o).invert(t)},l.stream=function(n){return t&&e===n?t:(r=[o.stream(e=n),s.stream(n),c.stream(n)],i=r.length,t={point:function(t,e){for(var n=-1;++n0?e<-Nc+Sc&&(e=-Nc+Sc):e>Nc-Sc&&(e=Nc-Sc);var n=i/Uc(Jf(e),r);return[n*qc(r*t),i-n*Pc(r*t)]}return a.invert=function(t,e){var n=i-e,a=Hc(r)*$c(t*t+n*n),o=Fc(t,Ic(n))*Hc(n);return n*r<0&&(o-=Mc*Hc(t)*Hc(n)),[o/r,2*Rc(Uc(i/a,1/r))-Nc]},a}function ed(){return jf(td).scale(109.5).parallels([30,30])}function nd(t,e){return[t,e]}function rd(){return Ff(nd).scale(152.63)}function id(t,e){var n=Pc(t),r=t===e?qc(t):(n-Pc(e))/(e-t),i=n/r+t;if(Ic(r)2?t[2]+90:90]):[(t=n())[0],t[1],t[2]-90]},n([0,0,90]).scale(159.155)}function Td(t,e){return t.parent===e.parent?1:2}function Ed(t,e){return t+e.x}function Cd(t,e){return Math.max(t,e.y)}function Sd(){var t=Td,e=1,n=1,r=!1;function i(i){var a,o=0;i.eachAfter((function(e){var n=e.children;n?(e.x=function(t){return t.reduce(Ed,0)/t.length}(n),e.y=function(t){return 1+t.reduce(Cd,0)}(n)):(e.x=a?o+=t(e,a):0,e.y=0,a=e)}));var s=function(t){for(var e;e=t.children;)t=e[0];return t}(i),c=function(t){for(var e;e=t.children;)t=e[e.length-1];return t}(i),u=s.x-t(s,c)/2,l=c.x+t(c,s)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*e,t.y=(i.y-t.y)*n}:function(t){t.x=(t.x-u)/(l-u)*e,t.y=(1-(i.y?t.y/i.y:1))*n})}return i.separation=function(e){return arguments.length?(t=e,i):t},i.size=function(t){return arguments.length?(r=!1,e=+t[0],n=+t[1],i):r?null:[e,n]},i.nodeSize=function(t){return arguments.length?(r=!0,e=+t[0],n=+t[1],i):r?[e,n]:null},i}function Ad(t){var e=0,n=t.children,r=n&&n.length;if(r)for(;--r>=0;)e+=n[r].value;else e=1;t.value=e}function Md(t,e){var n,r,i,a,o,s=new Bd(t),c=+t.value&&(s.value=t.value),u=[s];for(null==e&&(e=Nd);n=u.pop();)if(c&&(n.value=+n.data.value),(i=e(n.data))&&(o=i.length))for(n.children=new Array(o),a=o-1;a>=0;--a)u.push(r=n.children[a]=new Bd(i[a])),r.parent=n,r.depth=n.depth+1;return s.eachBefore(Od)}function Nd(t){return t.children}function Dd(t){t.data=t.data.data}function Od(t){var e=0;do{t.height=e}while((t=t.parent)&&t.height<++e)}function Bd(t){this.data=t,this.depth=this.height=0,this.parent=null}hd.invert=function(t,e){for(var n,r=e,i=r*r,a=i*i*i,o=0;o<12&&(a=(i=(r-=n=(r*(od+sd*i+a*(cd+ud*i))-e)/(od+3*sd*i+a*(7*cd+9*ud*i)))*r)*i*i,!(Ic(n)Sc&&--i>0);return[t/(.8707+(a=r*r)*(a*(a*a*a*(.003971-.001529*a)-.013791)-.131979)),r]},vd.invert=$f(Gc),_d.invert=$f((function(t){return 2*Rc(t)})),wd.invert=function(t,e){return[-e,2*Rc(Yc(t))-Nc]},Bd.prototype=Md.prototype={constructor:Bd,count:function(){return this.eachAfter(Ad)},each:function(t){var e,n,r,i,a=this,o=[a];do{for(e=o.reverse(),o=[];a=e.pop();)if(t(a),n=a.children)for(r=0,i=n.length;r=0;--n)i.push(e[n]);return this},sum:function(t){return this.eachAfter((function(e){for(var n=+t(e.data)||0,r=e.children,i=r&&r.length;--i>=0;)n+=r[i].value;e.value=n}))},sort:function(t){return this.eachBefore((function(e){e.children&&e.children.sort(t)}))},path:function(t){for(var e=this,n=function(t,e){if(t===e)return t;var n=t.ancestors(),r=e.ancestors(),i=null;for(t=n.pop(),e=r.pop();t===e;)i=t,t=n.pop(),e=r.pop();return i}(e,t),r=[e];e!==n;)e=e.parent,r.push(e);for(var i=r.length;t!==n;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,e=[t];t=t.parent;)e.push(t);return e},descendants:function(){var t=[];return this.each((function(e){t.push(e)})),t},leaves:function(){var t=[];return this.eachBefore((function(e){e.children||t.push(e)})),t},links:function(){var t=this,e=[];return t.each((function(n){n!==t&&e.push({source:n.parent,target:n})})),e},copy:function(){return Md(this).eachBefore(Dd)}};var Ld=Array.prototype.slice;function Id(t){for(var e,n,r=0,i=(t=function(t){for(var e,n,r=t.length;r;)n=Math.random()*r--|0,e=t[r],t[r]=t[n],t[n]=e;return t}(Ld.call(t))).length,a=[];r0&&n*n>r*r+i*i}function jd(t,e){for(var n=0;n(o*=o)?(r=(u+o-i)/(2*u),a=Math.sqrt(Math.max(0,o/u-r*r)),n.x=t.x-r*s-a*c,n.y=t.y-r*c+a*s):(r=(u+i-o)/(2*u),a=Math.sqrt(Math.max(0,i/u-r*r)),n.x=e.x+r*s-a*c,n.y=e.y+r*c+a*s)):(n.x=e.x+n.r,n.y=e.y)}function Hd(t,e){var n=t.r+e.r-1e-6,r=e.x-t.x,i=e.y-t.y;return n>0&&n*n>r*r+i*i}function $d(t){var e=t._,n=t.next._,r=e.r+n.r,i=(e.x*n.r+n.x*e.r)/r,a=(e.y*n.r+n.y*e.r)/r;return i*i+a*a}function Wd(t){this._=t,this.next=null,this.previous=null}function Vd(t){if(!(i=t.length))return 0;var e,n,r,i,a,o,s,c,u,l,h;if((e=t[0]).x=0,e.y=0,!(i>1))return e.r;if(n=t[1],e.x=-n.r,n.x=e.r,n.y=0,!(i>2))return e.r+n.r;qd(n,e,r=t[2]),e=new Wd(e),n=new Wd(n),r=new Wd(r),e.next=r.previous=n,n.next=e.previous=r,r.next=n.previous=e;t:for(s=3;s0)throw new Error("cycle");return a}return n.id=function(e){return arguments.length?(t=Zd(e),n):t},n.parentId=function(t){return arguments.length?(e=Zd(t),n):e},n}function fp(t,e){return t.parent===e.parent?1:2}function dp(t){var e=t.children;return e?e[0]:t.t}function pp(t){var e=t.children;return e?e[e.length-1]:t.t}function yp(t,e,n){var r=n/(e.i-t.i);e.c-=r,e.s+=n,t.c+=r,e.z+=n,e.m+=n}function gp(t,e,n){return t.a.parent===e.parent?t.a:n}function mp(t,e){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=e}function vp(){var t=fp,e=1,n=1,r=null;function i(i){var c=function(t){for(var e,n,r,i,a,o=new mp(t,0),s=[o];e=s.pop();)if(r=e._.children)for(e.children=new Array(a=r.length),i=a-1;i>=0;--i)s.push(n=e.children[i]=new mp(r[i],i)),n.parent=e;return(o.parent=new mp(null,0)).children=[o],o}(i);if(c.eachAfter(a),c.parent.m=-c.z,c.eachBefore(o),r)i.eachBefore(s);else{var u=i,l=i,h=i;i.eachBefore((function(t){t.xl.x&&(l=t),t.depth>h.depth&&(h=t)}));var f=u===l?1:t(u,l)/2,d=f-u.x,p=e/(l.x+f+d),y=n/(h.depth||1);i.eachBefore((function(t){t.x=(t.x+d)*p,t.y=t.depth*y}))}return i}function a(e){var n=e.children,r=e.parent.children,i=e.i?r[e.i-1]:null;if(n){!function(t){for(var e,n=0,r=0,i=t.children,a=i.length;--a>=0;)(e=i[a]).z+=n,e.m+=n,n+=e.s+(r+=e.c)}(e);var a=(n[0].z+n[n.length-1].z)/2;i?(e.z=i.z+t(e._,i._),e.m=e.z-a):e.z=a}else i&&(e.z=i.z+t(e._,i._));e.parent.A=function(e,n,r){if(n){for(var i,a=e,o=e,s=n,c=a.parent.children[0],u=a.m,l=o.m,h=s.m,f=c.m;s=pp(s),a=dp(a),s&&a;)c=dp(c),(o=pp(o)).a=e,(i=s.z+h-a.z-u+t(s._,a._))>0&&(yp(gp(s,e,r),e,i),u+=i,l+=i),h+=s.m,u+=a.m,f+=c.m,l+=o.m;s&&!pp(o)&&(o.t=s,o.m+=h-l),a&&!dp(c)&&(c.t=a,c.m+=u-f,r=e)}return r}(e,i,e.parent.A||r[0])}function o(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function s(t){t.x*=e,t.y=t.depth*n}return i.separation=function(e){return arguments.length?(t=e,i):t},i.size=function(t){return arguments.length?(r=!1,e=+t[0],n=+t[1],i):r?null:[e,n]},i.nodeSize=function(t){return arguments.length?(r=!0,e=+t[0],n=+t[1],i):r?[e,n]:null},i}function bp(t,e,n,r,i){for(var a,o=t.children,s=-1,c=o.length,u=t.value&&(i-n)/t.value;++sf&&(f=s),g=l*l*y,(d=Math.max(f/g,g/h))>p){l-=s;break}p=d}m.push(o={value:l,dice:c1?e:1)},n}(_p);function kp(){var t=wp,e=!1,n=1,r=1,i=[0],a=Qd,o=Qd,s=Qd,c=Qd,u=Qd;function l(t){return t.x0=t.y0=0,t.x1=n,t.y1=r,t.eachBefore(h),i=[0],e&&t.eachBefore(ip),t}function h(e){var n=i[e.depth],r=e.x0+n,l=e.y0+n,h=e.x1-n,f=e.y1-n;h=n-1){var l=s[e];return l.x0=i,l.y0=a,l.x1=o,void(l.y1=c)}for(var h=u[e],f=r/2+h,d=e+1,p=n-1;d>>1;u[y]c-a){var v=(i*m+o*g)/r;t(e,d,g,i,a,v,c),t(d,n,m,v,a,o,c)}else{var b=(a*m+c*g)/r;t(e,d,g,i,a,o,b),t(d,n,m,i,b,o,c)}}(0,c,t.value,e,n,r,i)}function Ep(t,e,n,r,i){(1&t.depth?bp:ap)(t,e,n,r,i)}const Cp=function t(e){function n(t,n,r,i,a){if((o=t._squarify)&&o.ratio===e)for(var o,s,c,u,l,h=-1,f=o.length,d=t.value;++h1?e:1)},n}(_p);function Sp(t){var e=t.length;return function(n){return t[Math.max(0,Math.min(e-1,Math.floor(n*e)))]}}function Ap(t,e){var n=dn(+t,+e);return function(t){var e=n(t);return e-360*Math.floor(e/360)}}function Mp(t,e){return t=+t,e=+e,function(n){return Math.round(t*(1-n)+e*n)}}var Np=Math.SQRT2;function Dp(t){return((t=Math.exp(t))+1/t)/2}function Op(t,e){var n,r,i=t[0],a=t[1],o=t[2],s=e[0],c=e[1],u=e[2],l=s-i,h=c-a,f=l*l+h*h;if(f<1e-12)r=Math.log(u/o)/Np,n=function(t){return[i+t*l,a+t*h,o*Math.exp(Np*t*r)]};else{var d=Math.sqrt(f),p=(u*u-o*o+4*f)/(2*o*2*d),y=(u*u-o*o-4*f)/(2*u*2*d),g=Math.log(Math.sqrt(p*p+1)-p),m=Math.log(Math.sqrt(y*y+1)-y);r=(m-g)/Np,n=function(t){var e,n=t*r,s=Dp(g),c=o/(2*d)*(s*(e=Np*n+g,((e=Math.exp(2*e))-1)/(e+1))-function(t){return((t=Math.exp(t))-1/t)/2}(g));return[i+c*l,a+c*h,o*s/Dp(Np*n+g)]}}return n.duration=1e3*r,n}function Bp(t){return function(e,n){var r=t((e=an(e)).h,(n=an(n)).h),i=pn(e.s,n.s),a=pn(e.l,n.l),o=pn(e.opacity,n.opacity);return function(t){return e.h=r(t),e.s=i(t),e.l=a(t),e.opacity=o(t),e+""}}}const Lp=Bp(dn);var Ip=Bp(pn);function Rp(t,e){var n=pn((t=Ta(t)).l,(e=Ta(e)).l),r=pn(t.a,e.a),i=pn(t.b,e.b),a=pn(t.opacity,e.opacity);return function(e){return t.l=n(e),t.a=r(e),t.b=i(e),t.opacity=a(e),t+""}}function Fp(t){return function(e,n){var r=t((e=Oa(e)).h,(n=Oa(n)).h),i=pn(e.c,n.c),a=pn(e.l,n.l),o=pn(e.opacity,n.opacity);return function(t){return e.h=r(t),e.c=i(t),e.l=a(t),e.opacity=o(t),e+""}}}const Pp=Fp(dn);var jp=Fp(pn);function Yp(t){return function e(n){function r(e,r){var i=t((e=Ha(e)).h,(r=Ha(r)).h),a=pn(e.s,r.s),o=pn(e.l,r.l),s=pn(e.opacity,r.opacity);return function(t){return e.h=i(t),e.s=a(t),e.l=o(Math.pow(t,n)),e.opacity=s(t),e+""}}return n=+n,r.gamma=e,r}(1)}const zp=Yp(dn);var Up=Yp(pn);function qp(t,e){for(var n=0,r=e.length-1,i=e[0],a=new Array(r<0?0:r);n1&&Vp(t[n[r-2]],t[n[r-1]],t[i])<=0;)--r;n[r++]=i}return n.slice(0,r)}function Zp(t){if((n=t.length)<3)return null;var e,n,r=new Array(n),i=new Array(n);for(e=0;e=0;--e)u.push(t[r[a[e]][2]]);for(e=+s;es!=u>s&&o<(c-n)*(s-r)/(u-r)+n&&(l=!l),c=n,u=r;return l}function Kp(t){for(var e,n,r=-1,i=t.length,a=t[i-1],o=a[0],s=a[1],c=0;++r1);return t+n*a*Math.sqrt(-2*Math.log(i)/i)}}return n.source=t,n}(Jp),ny=function t(e){function n(){var t=ey.source(e).apply(this,arguments);return function(){return Math.exp(t())}}return n.source=t,n}(Jp),ry=function t(e){function n(t){return function(){for(var n=0,r=0;rr&&(e=n,n=r,r=e),function(t){return Math.max(n,Math.min(r,t))}}function xy(t,e,n){var r=t[0],i=t[1],a=e[0],o=e[1];return i2?wy:xy,i=a=null,h}function h(e){return isNaN(e=+e)?n:(i||(i=r(o.map(t),s,c)))(t(u(e)))}return h.invert=function(n){return u(e((a||(a=r(s,o.map(t),Tn)))(n)))},h.domain=function(t){return arguments.length?(o=uy.call(t,gy),u===vy||(u=_y(o)),l()):o.slice()},h.range=function(t){return arguments.length?(s=ly.call(t),l()):s.slice()},h.rangeRound=function(t){return s=ly.call(t),c=Mp,l()},h.clamp=function(t){return arguments.length?(u=t?_y(o):vy,h):u!==vy},h.interpolate=function(t){return arguments.length?(c=t,l()):c},h.unknown=function(t){return arguments.length?(n=t,h):n},function(n,r){return t=n,e=r,l()}}function Ey(t,e){return Ty()(t,e)}function Cy(t,e,n,r){var i,a=M(t,e,n);switch((r=cc(null==r?",f":r)).type){case"s":var o=Math.max(Math.abs(t),Math.abs(e));return null!=r.precision||isNaN(i=xc(a,o))||(r.precision=i),yc(r,o);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(i=wc(a,Math.max(Math.abs(t),Math.abs(e))))||(r.precision=i-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(i=_c(a))||(r.precision=i-2*("%"===r.type))}return pc(r)}function Sy(t){var e=t.domain;return t.ticks=function(t){var n=e();return S(n[0],n[n.length-1],null==t?10:t)},t.tickFormat=function(t,n){var r=e();return Cy(r[0],r[r.length-1],null==t?10:t,n)},t.nice=function(n){null==n&&(n=10);var r,i=e(),a=0,o=i.length-1,s=i[a],c=i[o];return c0?r=A(s=Math.floor(s/r)*r,c=Math.ceil(c/r)*r,n):r<0&&(r=A(s=Math.ceil(s*r)/r,c=Math.floor(c*r)/r,n)),r>0?(i[a]=Math.floor(s/r)*r,i[o]=Math.ceil(c/r)*r,e(i)):r<0&&(i[a]=Math.ceil(s*r)/r,i[o]=Math.floor(c*r)/r,e(i)),t},t}function Ay(){var t=Ey(vy,vy);return t.copy=function(){return ky(t,Ay())},oy.apply(t,arguments),Sy(t)}function My(t){var e;function n(t){return isNaN(t=+t)?e:t}return n.invert=n,n.domain=n.range=function(e){return arguments.length?(t=uy.call(e,gy),n):t.slice()},n.unknown=function(t){return arguments.length?(e=t,n):e},n.copy=function(){return My(t).unknown(e)},t=arguments.length?uy.call(t,gy):[0,1],Sy(n)}function Ny(t,e){var n,r=0,i=(t=t.slice()).length-1,a=t[r],o=t[i];return o0){for(;fc)break;y.push(h)}}else for(;f=1;--l)if(!((h=u*l)c)break;y.push(h)}}else y=S(f,d,Math.min(d-f,p)).map(n);return r?y.reverse():y},r.tickFormat=function(t,i){if(null==i&&(i=10===a?".0e":","),"function"!=typeof i&&(i=pc(i)),t===1/0)return i;null==t&&(t=10);var o=Math.max(1,a*t/r.ticks().length);return function(t){var r=t/n(Math.round(e(t)));return r*a0?r[i-1]:e[0],i=r?[i[r-1],n]:[i[o-1],i[o]]},o.unknown=function(e){return arguments.length?(t=e,o):o},o.thresholds=function(){return i.slice()},o.copy=function(){return Zy().domain([e,n]).range(a).unknown(t)},oy.apply(Sy(o),arguments)}function Qy(){var t,e=[.5],n=[0,1],r=1;function i(i){return i<=i?n[u(e,i,0,r)]:t}return i.domain=function(t){return arguments.length?(e=ly.call(t),r=Math.min(e.length,n.length-1),i):e.slice()},i.range=function(t){return arguments.length?(n=ly.call(t),r=Math.min(e.length,n.length-1),i):n.slice()},i.invertExtent=function(t){var r=n.indexOf(t);return[e[r-1],e[r]]},i.unknown=function(e){return arguments.length?(t=e,i):t},i.copy=function(){return Qy().domain(e).range(n).unknown(t)},oy.apply(i,arguments)}var Ky=new Date,Jy=new Date;function tg(t,e,n,r){function i(e){return t(e=0===arguments.length?new Date:new Date(+e)),e}return i.floor=function(e){return t(e=new Date(+e)),e},i.ceil=function(n){return t(n=new Date(n-1)),e(n,1),t(n),n},i.round=function(t){var e=i(t),n=i.ceil(t);return t-e0))return s;do{s.push(o=new Date(+n)),e(n,a),t(n)}while(o=e)for(;t(e),!n(e);)e.setTime(e-1)}),(function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;e(t,-1),!n(t););else for(;--r>=0;)for(;e(t,1),!n(t););}))},n&&(i.count=function(e,r){return Ky.setTime(+e),Jy.setTime(+r),t(Ky),t(Jy),Math.floor(n(Ky,Jy))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(e){return r(e)%t==0}:function(e){return i.count(0,e)%t==0}):i:null}),i}var eg=tg((function(t){t.setMonth(0,1),t.setHours(0,0,0,0)}),(function(t,e){t.setFullYear(t.getFullYear()+e)}),(function(t,e){return e.getFullYear()-t.getFullYear()}),(function(t){return t.getFullYear()}));eg.every=function(t){return isFinite(t=Math.floor(t))&&t>0?tg((function(e){e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)}),(function(e,n){e.setFullYear(e.getFullYear()+n*t)})):null};const ng=eg;var rg=eg.range,ig=tg((function(t){t.setDate(1),t.setHours(0,0,0,0)}),(function(t,e){t.setMonth(t.getMonth()+e)}),(function(t,e){return e.getMonth()-t.getMonth()+12*(e.getFullYear()-t.getFullYear())}),(function(t){return t.getMonth()}));const ag=ig;var og=ig.range,sg=1e3,cg=6e4,ug=36e5,lg=864e5,hg=6048e5;function fg(t){return tg((function(e){e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)}),(function(t,e){t.setDate(t.getDate()+7*e)}),(function(t,e){return(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*cg)/hg}))}var dg=fg(0),pg=fg(1),yg=fg(2),gg=fg(3),mg=fg(4),vg=fg(5),bg=fg(6),_g=dg.range,xg=pg.range,wg=yg.range,kg=gg.range,Tg=mg.range,Eg=vg.range,Cg=bg.range,Sg=tg((function(t){t.setHours(0,0,0,0)}),(function(t,e){t.setDate(t.getDate()+e)}),(function(t,e){return(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*cg)/lg}),(function(t){return t.getDate()-1}));const Ag=Sg;var Mg=Sg.range,Ng=tg((function(t){t.setTime(t-t.getMilliseconds()-t.getSeconds()*sg-t.getMinutes()*cg)}),(function(t,e){t.setTime(+t+e*ug)}),(function(t,e){return(e-t)/ug}),(function(t){return t.getHours()}));const Dg=Ng;var Og=Ng.range,Bg=tg((function(t){t.setTime(t-t.getMilliseconds()-t.getSeconds()*sg)}),(function(t,e){t.setTime(+t+e*cg)}),(function(t,e){return(e-t)/cg}),(function(t){return t.getMinutes()}));const Lg=Bg;var Ig=Bg.range,Rg=tg((function(t){t.setTime(t-t.getMilliseconds())}),(function(t,e){t.setTime(+t+e*sg)}),(function(t,e){return(e-t)/sg}),(function(t){return t.getUTCSeconds()}));const Fg=Rg;var Pg=Rg.range,jg=tg((function(){}),(function(t,e){t.setTime(+t+e)}),(function(t,e){return e-t}));jg.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?tg((function(e){e.setTime(Math.floor(e/t)*t)}),(function(e,n){e.setTime(+e+n*t)}),(function(e,n){return(n-e)/t})):jg:null};const Yg=jg;var zg=jg.range;function Ug(t){return tg((function(e){e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+7*e)}),(function(t,e){return(e-t)/hg}))}var qg=Ug(0),Hg=Ug(1),$g=Ug(2),Wg=Ug(3),Vg=Ug(4),Gg=Ug(5),Xg=Ug(6),Zg=qg.range,Qg=Hg.range,Kg=$g.range,Jg=Wg.range,tm=Vg.range,em=Gg.range,nm=Xg.range,rm=tg((function(t){t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCDate(t.getUTCDate()+e)}),(function(t,e){return(e-t)/lg}),(function(t){return t.getUTCDate()-1}));const im=rm;var am=rm.range,om=tg((function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),(function(t,e){t.setUTCFullYear(t.getUTCFullYear()+e)}),(function(t,e){return e.getUTCFullYear()-t.getUTCFullYear()}),(function(t){return t.getUTCFullYear()}));om.every=function(t){return isFinite(t=Math.floor(t))&&t>0?tg((function(e){e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)}),(function(e,n){e.setUTCFullYear(e.getUTCFullYear()+n*t)})):null};const sm=om;var cm=om.range;function um(t){if(0<=t.y&&t.y<100){var e=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return e.setFullYear(t.y),e}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function lm(t){if(0<=t.y&&t.y<100){var e=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return e.setUTCFullYear(t.y),e}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function hm(t,e,n){return{y:t,m:e,d:n,H:0,M:0,S:0,L:0}}function fm(t){var e=t.dateTime,n=t.date,r=t.time,i=t.periods,a=t.days,o=t.shortDays,s=t.months,c=t.shortMonths,u=Tm(i),l=Em(i),h=Tm(a),f=Em(a),d=Tm(o),p=Em(o),y=Tm(s),g=Em(s),m=Tm(c),v=Em(c),b={a:function(t){return o[t.getDay()]},A:function(t){return a[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return s[t.getMonth()]},c:null,d:Wm,e:Wm,f:Qm,g:cv,G:lv,H:Vm,I:Gm,j:Xm,L:Zm,m:Km,M:Jm,p:function(t){return i[+(t.getHours()>=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:Bv,s:Lv,S:tv,u:ev,U:nv,V:iv,w:av,W:ov,x:null,X:null,y:sv,Y:uv,Z:hv,"%":Ov},_={a:function(t){return o[t.getUTCDay()]},A:function(t){return a[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return s[t.getUTCMonth()]},c:null,d:fv,e:fv,f:mv,g:Av,G:Nv,H:dv,I:pv,j:yv,L:gv,m:vv,M:bv,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:Bv,s:Lv,S:_v,u:xv,U:wv,V:Tv,w:Ev,W:Cv,x:null,X:null,y:Sv,Y:Mv,Z:Dv,"%":Ov},x={a:function(t,e,n){var r=d.exec(e.slice(n));return r?(t.w=p[r[0].toLowerCase()],n+r[0].length):-1},A:function(t,e,n){var r=h.exec(e.slice(n));return r?(t.w=f[r[0].toLowerCase()],n+r[0].length):-1},b:function(t,e,n){var r=m.exec(e.slice(n));return r?(t.m=v[r[0].toLowerCase()],n+r[0].length):-1},B:function(t,e,n){var r=y.exec(e.slice(n));return r?(t.m=g[r[0].toLowerCase()],n+r[0].length):-1},c:function(t,n,r){return T(t,e,n,r)},d:Rm,e:Rm,f:Um,g:Om,G:Dm,H:Pm,I:Pm,j:Fm,L:zm,m:Im,M:jm,p:function(t,e,n){var r=u.exec(e.slice(n));return r?(t.p=l[r[0].toLowerCase()],n+r[0].length):-1},q:Lm,Q:Hm,s:$m,S:Ym,u:Sm,U:Am,V:Mm,w:Cm,W:Nm,x:function(t,e,r){return T(t,n,e,r)},X:function(t,e,n){return T(t,r,e,n)},y:Om,Y:Dm,Z:Bm,"%":qm};function w(t,e){return function(n){var r,i,a,o=[],s=-1,c=0,u=t.length;for(n instanceof Date||(n=new Date(+n));++s53)return null;"w"in a||(a.w=1),"Z"in a?(i=(r=lm(hm(a.y,0,1))).getUTCDay(),r=i>4||0===i?Hg.ceil(r):Hg(r),r=im.offset(r,7*(a.V-1)),a.y=r.getUTCFullYear(),a.m=r.getUTCMonth(),a.d=r.getUTCDate()+(a.w+6)%7):(i=(r=um(hm(a.y,0,1))).getDay(),r=i>4||0===i?pg.ceil(r):pg(r),r=Ag.offset(r,7*(a.V-1)),a.y=r.getFullYear(),a.m=r.getMonth(),a.d=r.getDate()+(a.w+6)%7)}else("W"in a||"U"in a)&&("w"in a||(a.w="u"in a?a.u%7:"W"in a?1:0),i="Z"in a?lm(hm(a.y,0,1)).getUTCDay():um(hm(a.y,0,1)).getDay(),a.m=0,a.d="W"in a?(a.w+6)%7+7*a.W-(i+5)%7:a.w+7*a.U-(i+6)%7);return"Z"in a?(a.H+=a.Z/100|0,a.M+=a.Z%100,lm(a)):um(a)}}function T(t,e,n,r){for(var i,a,o=0,s=e.length,c=n.length;o=c)return-1;if(37===(i=e.charCodeAt(o++))){if(i=e.charAt(o++),!(a=x[i in vm?e.charAt(o++):i])||(r=a(t,n,r))<0)return-1}else if(i!=n.charCodeAt(r++))return-1}return r}return b.x=w(n,b),b.X=w(r,b),b.c=w(e,b),_.x=w(n,_),_.X=w(r,_),_.c=w(e,_),{format:function(t){var e=w(t+="",b);return e.toString=function(){return t},e},parse:function(t){var e=k(t+="",!1);return e.toString=function(){return t},e},utcFormat:function(t){var e=w(t+="",_);return e.toString=function(){return t},e},utcParse:function(t){var e=k(t+="",!0);return e.toString=function(){return t},e}}}var dm,pm,ym,gm,mm,vm={"-":"",_:" ",0:"0"},bm=/^\s*\d+/,_m=/^%/,xm=/[\\^$*+?|[\]().{}]/g;function wm(t,e,n){var r=t<0?"-":"",i=(r?-t:t)+"",a=i.length;return r+(a68?1900:2e3),n+r[0].length):-1}function Bm(t,e,n){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),n+r[0].length):-1}function Lm(t,e,n){var r=bm.exec(e.slice(n,n+1));return r?(t.q=3*r[0]-3,n+r[0].length):-1}function Im(t,e,n){var r=bm.exec(e.slice(n,n+2));return r?(t.m=r[0]-1,n+r[0].length):-1}function Rm(t,e,n){var r=bm.exec(e.slice(n,n+2));return r?(t.d=+r[0],n+r[0].length):-1}function Fm(t,e,n){var r=bm.exec(e.slice(n,n+3));return r?(t.m=0,t.d=+r[0],n+r[0].length):-1}function Pm(t,e,n){var r=bm.exec(e.slice(n,n+2));return r?(t.H=+r[0],n+r[0].length):-1}function jm(t,e,n){var r=bm.exec(e.slice(n,n+2));return r?(t.M=+r[0],n+r[0].length):-1}function Ym(t,e,n){var r=bm.exec(e.slice(n,n+2));return r?(t.S=+r[0],n+r[0].length):-1}function zm(t,e,n){var r=bm.exec(e.slice(n,n+3));return r?(t.L=+r[0],n+r[0].length):-1}function Um(t,e,n){var r=bm.exec(e.slice(n,n+6));return r?(t.L=Math.floor(r[0]/1e3),n+r[0].length):-1}function qm(t,e,n){var r=_m.exec(e.slice(n,n+1));return r?n+r[0].length:-1}function Hm(t,e,n){var r=bm.exec(e.slice(n));return r?(t.Q=+r[0],n+r[0].length):-1}function $m(t,e,n){var r=bm.exec(e.slice(n));return r?(t.s=+r[0],n+r[0].length):-1}function Wm(t,e){return wm(t.getDate(),e,2)}function Vm(t,e){return wm(t.getHours(),e,2)}function Gm(t,e){return wm(t.getHours()%12||12,e,2)}function Xm(t,e){return wm(1+Ag.count(ng(t),t),e,3)}function Zm(t,e){return wm(t.getMilliseconds(),e,3)}function Qm(t,e){return Zm(t,e)+"000"}function Km(t,e){return wm(t.getMonth()+1,e,2)}function Jm(t,e){return wm(t.getMinutes(),e,2)}function tv(t,e){return wm(t.getSeconds(),e,2)}function ev(t){var e=t.getDay();return 0===e?7:e}function nv(t,e){return wm(dg.count(ng(t)-1,t),e,2)}function rv(t){var e=t.getDay();return e>=4||0===e?mg(t):mg.ceil(t)}function iv(t,e){return t=rv(t),wm(mg.count(ng(t),t)+(4===ng(t).getDay()),e,2)}function av(t){return t.getDay()}function ov(t,e){return wm(pg.count(ng(t)-1,t),e,2)}function sv(t,e){return wm(t.getFullYear()%100,e,2)}function cv(t,e){return wm((t=rv(t)).getFullYear()%100,e,2)}function uv(t,e){return wm(t.getFullYear()%1e4,e,4)}function lv(t,e){var n=t.getDay();return wm((t=n>=4||0===n?mg(t):mg.ceil(t)).getFullYear()%1e4,e,4)}function hv(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+wm(e/60|0,"0",2)+wm(e%60,"0",2)}function fv(t,e){return wm(t.getUTCDate(),e,2)}function dv(t,e){return wm(t.getUTCHours(),e,2)}function pv(t,e){return wm(t.getUTCHours()%12||12,e,2)}function yv(t,e){return wm(1+im.count(sm(t),t),e,3)}function gv(t,e){return wm(t.getUTCMilliseconds(),e,3)}function mv(t,e){return gv(t,e)+"000"}function vv(t,e){return wm(t.getUTCMonth()+1,e,2)}function bv(t,e){return wm(t.getUTCMinutes(),e,2)}function _v(t,e){return wm(t.getUTCSeconds(),e,2)}function xv(t){var e=t.getUTCDay();return 0===e?7:e}function wv(t,e){return wm(qg.count(sm(t)-1,t),e,2)}function kv(t){var e=t.getUTCDay();return e>=4||0===e?Vg(t):Vg.ceil(t)}function Tv(t,e){return t=kv(t),wm(Vg.count(sm(t),t)+(4===sm(t).getUTCDay()),e,2)}function Ev(t){return t.getUTCDay()}function Cv(t,e){return wm(Hg.count(sm(t)-1,t),e,2)}function Sv(t,e){return wm(t.getUTCFullYear()%100,e,2)}function Av(t,e){return wm((t=kv(t)).getUTCFullYear()%100,e,2)}function Mv(t,e){return wm(t.getUTCFullYear()%1e4,e,4)}function Nv(t,e){var n=t.getUTCDay();return wm((t=n>=4||0===n?Vg(t):Vg.ceil(t)).getUTCFullYear()%1e4,e,4)}function Dv(){return"+0000"}function Ov(){return"%"}function Bv(t){return+t}function Lv(t){return Math.floor(+t/1e3)}function Iv(t){return dm=fm(t),pm=dm.format,ym=dm.parse,gm=dm.utcFormat,mm=dm.utcParse,dm}Iv({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Rv=31536e6;function Fv(t){return new Date(t)}function Pv(t){return t instanceof Date?+t:+new Date(+t)}function jv(t,e,n,r,i,o,s,c,u){var l=Ey(vy,vy),h=l.invert,f=l.domain,d=u(".%L"),p=u(":%S"),y=u("%I:%M"),g=u("%I %p"),m=u("%a %d"),v=u("%b %d"),b=u("%B"),_=u("%Y"),x=[[s,1,1e3],[s,5,5e3],[s,15,15e3],[s,30,3e4],[o,1,6e4],[o,5,3e5],[o,15,9e5],[o,30,18e5],[i,1,36e5],[i,3,108e5],[i,6,216e5],[i,12,432e5],[r,1,864e5],[r,2,1728e5],[n,1,6048e5],[e,1,2592e6],[e,3,7776e6],[t,1,Rv]];function w(a){return(s(a)1)&&(t-=Math.floor(t));var e=Math.abs(t-.5);return S_.h=360*t-100,S_.s=1.5-1.5*e,S_.l=.8-.9*e,S_+""}var M_=Qe(),N_=Math.PI/3,D_=2*Math.PI/3;function O_(t){var e;return t=(.5-t)*Math.PI,M_.r=255*(e=Math.sin(t))*e,M_.g=255*(e=Math.sin(t+N_))*e,M_.b=255*(e=Math.sin(t+D_))*e,M_+""}function B_(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+t*(1172.33-t*(10793.56-t*(33300.12-t*(38394.49-14825.05*t)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+t*(557.33+t*(1225.33-t*(3574.96-t*(1073.77+707.56*t)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+t*(3211.1-t*(15327.97-t*(27814-t*(22569.18-6838.66*t)))))))+")"}function L_(t){var e=t.length;return function(n){return t[Math.max(0,Math.min(e-1,Math.floor(n*e)))]}}const I_=L_(hb("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));var R_=L_(hb("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),F_=L_(hb("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),P_=L_(hb("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function j_(t){return Te(ie(t).call(document.documentElement))}var Y_=0;function z_(){return new U_}function U_(){this._="@"+(++Y_).toString(36)}function q_(t){return"string"==typeof t?new xe([document.querySelectorAll(t)],[document.documentElement]):new xe([null==t?[]:t],_e)}function H_(t,e){null==e&&(e=Nn().touches);for(var n=0,r=e?e.length:0,i=new Array(r);n1?0:t<-1?tx:Math.acos(t)}function ix(t){return t>=1?ex:t<=-1?-ex:Math.asin(t)}function ax(t){return t.innerRadius}function ox(t){return t.outerRadius}function sx(t){return t.startAngle}function cx(t){return t.endAngle}function ux(t){return t&&t.padAngle}function lx(t,e,n,r,i,a,o,s){var c=n-t,u=r-e,l=o-i,h=s-a,f=h*c-l*u;if(!(f*fN*N+D*D&&(T=C,E=S),{cx:T,cy:E,x01:-l,y01:-h,x11:T*(i/x-1),y11:E*(i/x-1)}}function fx(){var t=ax,e=ox,n=$_(0),r=null,i=sx,a=cx,o=ux,s=null;function c(){var c,u,l=+t.apply(this,arguments),h=+e.apply(this,arguments),f=i.apply(this,arguments)-ex,d=a.apply(this,arguments)-ex,p=W_(d-f),y=d>f;if(s||(s=c=Wi()),hJ_)if(p>nx-J_)s.moveTo(h*G_(f),h*Q_(f)),s.arc(0,0,h,f,d,!y),l>J_&&(s.moveTo(l*G_(d),l*Q_(d)),s.arc(0,0,l,d,f,y));else{var g,m,v=f,b=d,_=f,x=d,w=p,k=p,T=o.apply(this,arguments)/2,E=T>J_&&(r?+r.apply(this,arguments):K_(l*l+h*h)),C=Z_(W_(h-l)/2,+n.apply(this,arguments)),S=C,A=C;if(E>J_){var M=ix(E/l*Q_(T)),N=ix(E/h*Q_(T));(w-=2*M)>J_?(_+=M*=y?1:-1,x-=M):(w=0,_=x=(f+d)/2),(k-=2*N)>J_?(v+=N*=y?1:-1,b-=N):(k=0,v=b=(f+d)/2)}var D=h*G_(v),O=h*Q_(v),B=l*G_(x),L=l*Q_(x);if(C>J_){var I,R=h*G_(b),F=h*Q_(b),P=l*G_(_),j=l*Q_(_);if(pJ_?A>J_?(g=hx(P,j,D,O,h,A,y),m=hx(R,F,B,L,h,A,y),s.moveTo(g.cx+g.x01,g.cy+g.y01),AJ_&&w>J_?S>J_?(g=hx(B,L,R,F,l,-S,y),m=hx(D,O,P,j,l,-S,y),s.lineTo(g.cx+g.x01,g.cy+g.y01),S=l;--h)s.point(g[h],m[h]);s.lineEnd(),s.areaEnd()}y&&(g[u]=+t(f,u,c),m[u]=+n(f,u,c),s.point(e?+e(f,u,c):g[u],r?+r(f,u,c):m[u]))}if(d)return s=null,d+""||null}function u(){return mx().defined(i).curve(o).context(a)}return c.x=function(n){return arguments.length?(t="function"==typeof n?n:$_(+n),e=null,c):t},c.x0=function(e){return arguments.length?(t="function"==typeof e?e:$_(+e),c):t},c.x1=function(t){return arguments.length?(e=null==t?null:"function"==typeof t?t:$_(+t),c):e},c.y=function(t){return arguments.length?(n="function"==typeof t?t:$_(+t),r=null,c):n},c.y0=function(t){return arguments.length?(n="function"==typeof t?t:$_(+t),c):n},c.y1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:$_(+t),c):r},c.lineX0=c.lineY0=function(){return u().x(t).y(n)},c.lineY1=function(){return u().x(t).y(r)},c.lineX1=function(){return u().x(e).y(n)},c.defined=function(t){return arguments.length?(i="function"==typeof t?t:$_(!!t),c):i},c.curve=function(t){return arguments.length?(o=t,null!=a&&(s=o(a)),c):o},c.context=function(t){return arguments.length?(null==t?a=s=null:s=o(a=t),c):a},c}function bx(t,e){return et?1:e>=t?0:NaN}function _x(t){return t}function xx(){var t=_x,e=bx,n=null,r=$_(0),i=$_(nx),a=$_(0);function o(o){var s,c,u,l,h,f=o.length,d=0,p=new Array(f),y=new Array(f),g=+r.apply(this,arguments),m=Math.min(nx,Math.max(-nx,i.apply(this,arguments)-g)),v=Math.min(Math.abs(m)/f,a.apply(this,arguments)),b=v*(m<0?-1:1);for(s=0;s0&&(d+=h);for(null!=e?p.sort((function(t,n){return e(y[t],y[n])})):null!=n&&p.sort((function(t,e){return n(o[t],o[e])})),s=0,u=d?(m-f*b)/d:0;s0?h*u:0)+b,y[c]={data:o[c],index:s,value:h,startAngle:g,endAngle:l,padAngle:v};return y}return o.value=function(e){return arguments.length?(t="function"==typeof e?e:$_(+e),o):t},o.sortValues=function(t){return arguments.length?(e=t,n=null,o):e},o.sort=function(t){return arguments.length?(n=t,e=null,o):n},o.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:$_(+t),o):r},o.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:$_(+t),o):i},o.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:$_(+t),o):a},o}dx.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:this._context.lineTo(t,e)}}};var wx=Tx(px);function kx(t){this._curve=t}function Tx(t){function e(e){return new kx(t(e))}return e._curve=t,e}function Ex(t){var e=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?e(Tx(t)):e()._curve},t}function Cx(){return Ex(mx().curve(wx))}function Sx(){var t=vx().curve(wx),e=t.curve,n=t.lineX0,r=t.lineX1,i=t.lineY0,a=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return Ex(n())},delete t.lineX0,t.lineEndAngle=function(){return Ex(r())},delete t.lineX1,t.lineInnerRadius=function(){return Ex(i())},delete t.lineY0,t.lineOuterRadius=function(){return Ex(a())},delete t.lineY1,t.curve=function(t){return arguments.length?e(Tx(t)):e()._curve},t}function Ax(t,e){return[(e=+e)*Math.cos(t-=Math.PI/2),e*Math.sin(t)]}kx.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,e){this._curve.point(e*Math.sin(t),e*-Math.cos(t))}};var Mx=Array.prototype.slice;function Nx(t){return t.source}function Dx(t){return t.target}function Ox(t){var e=Nx,n=Dx,r=yx,i=gx,a=null;function o(){var o,s=Mx.call(arguments),c=e.apply(this,s),u=n.apply(this,s);if(a||(a=o=Wi()),t(a,+r.apply(this,(s[0]=c,s)),+i.apply(this,s),+r.apply(this,(s[0]=u,s)),+i.apply(this,s)),o)return a=null,o+""||null}return o.source=function(t){return arguments.length?(e=t,o):e},o.target=function(t){return arguments.length?(n=t,o):n},o.x=function(t){return arguments.length?(r="function"==typeof t?t:$_(+t),o):r},o.y=function(t){return arguments.length?(i="function"==typeof t?t:$_(+t),o):i},o.context=function(t){return arguments.length?(a=null==t?null:t,o):a},o}function Bx(t,e,n,r,i){t.moveTo(e,n),t.bezierCurveTo(e=(e+r)/2,n,e,i,r,i)}function Lx(t,e,n,r,i){t.moveTo(e,n),t.bezierCurveTo(e,n=(n+i)/2,r,n,r,i)}function Ix(t,e,n,r,i){var a=Ax(e,n),o=Ax(e,n=(n+i)/2),s=Ax(r,n),c=Ax(r,i);t.moveTo(a[0],a[1]),t.bezierCurveTo(o[0],o[1],s[0],s[1],c[0],c[1])}function Rx(){return Ox(Bx)}function Fx(){return Ox(Lx)}function Px(){var t=Ox(Ix);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t}const jx={draw:function(t,e){var n=Math.sqrt(e/tx);t.moveTo(n,0),t.arc(0,0,n,0,nx)}},Yx={draw:function(t,e){var n=Math.sqrt(e/5)/2;t.moveTo(-3*n,-n),t.lineTo(-n,-n),t.lineTo(-n,-3*n),t.lineTo(n,-3*n),t.lineTo(n,-n),t.lineTo(3*n,-n),t.lineTo(3*n,n),t.lineTo(n,n),t.lineTo(n,3*n),t.lineTo(-n,3*n),t.lineTo(-n,n),t.lineTo(-3*n,n),t.closePath()}};var zx=Math.sqrt(1/3),Ux=2*zx;const qx={draw:function(t,e){var n=Math.sqrt(e/Ux),r=n*zx;t.moveTo(0,-n),t.lineTo(r,0),t.lineTo(0,n),t.lineTo(-r,0),t.closePath()}};var Hx=Math.sin(tx/10)/Math.sin(7*tx/10),$x=Math.sin(nx/10)*Hx,Wx=-Math.cos(nx/10)*Hx;const Vx={draw:function(t,e){var n=Math.sqrt(.8908130915292852*e),r=$x*n,i=Wx*n;t.moveTo(0,-n),t.lineTo(r,i);for(var a=1;a<5;++a){var o=nx*a/5,s=Math.cos(o),c=Math.sin(o);t.lineTo(c*n,-s*n),t.lineTo(s*r-c*i,c*r+s*i)}t.closePath()}},Gx={draw:function(t,e){var n=Math.sqrt(e),r=-n/2;t.rect(r,r,n,n)}};var Xx=Math.sqrt(3);const Zx={draw:function(t,e){var n=-Math.sqrt(e/(3*Xx));t.moveTo(0,2*n),t.lineTo(-Xx*n,-n),t.lineTo(Xx*n,-n),t.closePath()}};var Qx=-.5,Kx=Math.sqrt(3)/2,Jx=1/Math.sqrt(12),tw=3*(Jx/2+1);const ew={draw:function(t,e){var n=Math.sqrt(e/tw),r=n/2,i=n*Jx,a=r,o=n*Jx+n,s=-a,c=o;t.moveTo(r,i),t.lineTo(a,o),t.lineTo(s,c),t.lineTo(Qx*r-Kx*i,Kx*r+Qx*i),t.lineTo(Qx*a-Kx*o,Kx*a+Qx*o),t.lineTo(Qx*s-Kx*c,Kx*s+Qx*c),t.lineTo(Qx*r+Kx*i,Qx*i-Kx*r),t.lineTo(Qx*a+Kx*o,Qx*o-Kx*a),t.lineTo(Qx*s+Kx*c,Qx*c-Kx*s),t.closePath()}};var nw=[jx,Yx,qx,Gx,Vx,Zx,ew];function rw(){var t=$_(jx),e=$_(64),n=null;function r(){var r;if(n||(n=r=Wi()),t.apply(this,arguments).draw(n,+e.apply(this,arguments)),r)return n=null,r+""||null}return r.type=function(e){return arguments.length?(t="function"==typeof e?e:$_(e),r):t},r.size=function(t){return arguments.length?(e="function"==typeof t?t:$_(+t),r):e},r.context=function(t){return arguments.length?(n=null==t?null:t,r):n},r}function iw(){}function aw(t,e,n){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+e)/6,(t._y0+4*t._y1+n)/6)}function ow(t){this._context=t}function sw(t){return new ow(t)}function cw(t){this._context=t}function uw(t){return new cw(t)}function lw(t){this._context=t}function hw(t){return new lw(t)}function fw(t,e){this._basis=new ow(t),this._beta=e}ow.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:aw(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:aw(this,t,e)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}},cw.prototype={areaStart:iw,areaEnd:iw,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x2=t,this._y2=e;break;case 1:this._point=2,this._x3=t,this._y3=e;break;case 2:this._point=3,this._x4=t,this._y4=e,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+e)/6);break;default:aw(this,t,e)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}},lw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var n=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+e)/6;this._line?this._context.lineTo(n,r):this._context.moveTo(n,r);break;case 3:this._point=4;default:aw(this,t,e)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e}},fw.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,e=this._y,n=t.length-1;if(n>0)for(var r,i=t[0],a=e[0],o=t[n]-i,s=e[n]-a,c=-1;++c<=n;)r=c/n,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*o),this._beta*e[c]+(1-this._beta)*(a+r*s));this._x=this._y=null,this._basis.lineEnd()},point:function(t,e){this._x.push(+t),this._y.push(+e)}};const dw=function t(e){function n(t){return 1===e?new ow(t):new fw(t,e)}return n.beta=function(e){return t(+e)},n}(.85);function pw(t,e,n){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-e),t._y2+t._k*(t._y1-n),t._x2,t._y2)}function yw(t,e){this._context=t,this._k=(1-e)/6}yw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:pw(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2,this._x1=t,this._y1=e;break;case 2:this._point=3;default:pw(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const gw=function t(e){function n(t){return new yw(t,e)}return n.tension=function(e){return t(+e)},n}(0);function mw(t,e){this._context=t,this._k=(1-e)/6}mw.prototype={areaStart:iw,areaEnd:iw,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:pw(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const vw=function t(e){function n(t){return new mw(t,e)}return n.tension=function(e){return t(+e)},n}(0);function bw(t,e){this._context=t,this._k=(1-e)/6}bw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:pw(this,t,e)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const _w=function t(e){function n(t){return new bw(t,e)}return n.tension=function(e){return t(+e)},n}(0);function xw(t,e,n){var r=t._x1,i=t._y1,a=t._x2,o=t._y2;if(t._l01_a>J_){var s=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*s-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*s-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>J_){var u=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,l=3*t._l23_a*(t._l23_a+t._l12_a);a=(a*u+t._x1*t._l23_2a-e*t._l12_2a)/l,o=(o*u+t._y1*t._l23_2a-n*t._l12_2a)/l}t._context.bezierCurveTo(r,i,a,o,t._x2,t._y2)}function ww(t,e){this._context=t,this._alpha=e}ww.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,r=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3;default:xw(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const kw=function t(e){function n(t){return e?new ww(t,e):new yw(t,0)}return n.alpha=function(e){return t(+e)},n}(.5);function Tw(t,e){this._context=t,this._alpha=e}Tw.prototype={areaStart:iw,areaEnd:iw,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,r=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=e;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=e);break;case 2:this._point=3,this._x5=t,this._y5=e;break;default:xw(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const Ew=function t(e){function n(t){return e?new Tw(t,e):new mw(t,0)}return n.alpha=function(e){return t(+e)},n}(.5);function Cw(t,e){this._context=t,this._alpha=e}Cw.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){if(t=+t,e=+e,this._point){var n=this._x2-t,r=this._y2-e;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(n*n+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:xw(this,t,e)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=e}};const Sw=function t(e){function n(t){return e?new Cw(t,e):new bw(t,0)}return n.alpha=function(e){return t(+e)},n}(.5);function Aw(t){this._context=t}function Mw(t){return new Aw(t)}function Nw(t){return t<0?-1:1}function Dw(t,e,n){var r=t._x1-t._x0,i=e-t._x1,a=(t._y1-t._y0)/(r||i<0&&-0),o=(n-t._y1)/(i||r<0&&-0),s=(a*i+o*r)/(r+i);return(Nw(a)+Nw(o))*Math.min(Math.abs(a),Math.abs(o),.5*Math.abs(s))||0}function Ow(t,e){var n=t._x1-t._x0;return n?(3*(t._y1-t._y0)/n-e)/2:e}function Bw(t,e,n){var r=t._x0,i=t._y0,a=t._x1,o=t._y1,s=(a-r)/3;t._context.bezierCurveTo(r+s,i+s*e,a-s,o-s*n,a,o)}function Lw(t){this._context=t}function Iw(t){this._context=new Rw(t)}function Rw(t){this._context=t}function Fw(t){return new Lw(t)}function Pw(t){return new Iw(t)}function jw(t){this._context=t}function Yw(t){var e,n,r=t.length-1,i=new Array(r),a=new Array(r),o=new Array(r);for(i[0]=0,a[0]=2,o[0]=t[0]+2*t[1],e=1;e=0;--e)i[e]=(o[e]-i[e+1])/a[e];for(a[r-1]=(t[r]+i[r-1])/2,e=0;e1)for(var n,r,i,a=1,o=t[e[0]],s=o.length;a=0;)n[e]=e;return n}function Gw(t,e){return t[e]}function Xw(){var t=$_([]),e=Vw,n=Ww,r=Gw;function i(i){var a,o,s=t.apply(this,arguments),c=i.length,u=s.length,l=new Array(u);for(a=0;a0){for(var n,r,i,a=0,o=t[0].length;a0)for(var n,r,i,a,o,s,c=0,u=t[e[0]].length;c0?(r[0]=a,r[1]=a+=i):i<0?(r[1]=o,r[0]=o+=i):(r[0]=0,r[1]=i)}function Kw(t,e){if((n=t.length)>0){for(var n,r=0,i=t[e[0]],a=i.length;r0&&(r=(n=t[e[0]]).length)>0){for(var n,r,i,a=0,o=1;oa&&(a=e,r=n);return r}function nk(t){var e=t.map(rk);return Vw(t).sort((function(t,n){return e[t]-e[n]}))}function rk(t){for(var e,n=0,r=-1,i=t.length;++r=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,e),this._context.lineTo(t,e);else{var n=this._x*(1-this._t)+t*this._t;this._context.lineTo(n,this._y),this._context.lineTo(n,e)}}this._x=t,this._y=e}};var sk="%Y-%m-%dT%H:%M:%S.%LZ",ck=Date.prototype.toISOString?function(t){return t.toISOString()}:gm(sk);const uk=ck;var lk=+new Date("2000-01-01T00:00:00.000Z")?function(t){var e=new Date(t);return isNaN(e)?null:e}:mm(sk);const hk=lk;function fk(t,e,n){var r=new Wn,i=e;return null==e?(r.restart(t,e,n),r):(e=+e,n=null==n?Hn():+n,r.restart((function a(o){o+=i,r.restart(a,i+=e,n),t(o)}),e,n),r)}function dk(t){return function(){return t}}function pk(t){return t[0]}function yk(t){return t[1]}function gk(){this._=null}function mk(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function vk(t,e){var n=e,r=e.R,i=n.U;i?i.L===n?i.L=r:i.R=r:t._=r,r.U=i,n.U=r,n.R=r.L,n.R&&(n.R.U=n),r.L=n}function bk(t,e){var n=e,r=e.L,i=n.U;i?i.L===n?i.L=r:i.R=r:t._=r,r.U=i,n.U=r,n.L=r.R,n.L&&(n.L.U=n),r.R=n}function _k(t){for(;t.L;)t=t.L;return t}gk.prototype={constructor:gk,insert:function(t,e){var n,r,i;if(t){if(e.P=t,e.N=t.N,t.N&&(t.N.P=e),t.N=e,t.R){for(t=t.R;t.L;)t=t.L;t.L=e}else t.R=e;n=t}else this._?(t=_k(this._),e.P=null,e.N=t,t.P=t.L=e,n=t):(e.P=e.N=null,this._=e,n=null);for(e.L=e.R=null,e.U=n,e.C=!0,t=e;n&&n.C;)n===(r=n.U).L?(i=r.R)&&i.C?(n.C=i.C=!1,r.C=!0,t=r):(t===n.R&&(vk(this,n),n=(t=n).U),n.C=!1,r.C=!0,bk(this,r)):(i=r.L)&&i.C?(n.C=i.C=!1,r.C=!0,t=r):(t===n.L&&(bk(this,n),n=(t=n).U),n.C=!1,r.C=!0,vk(this,r)),n=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var e,n,r,i=t.U,a=t.L,o=t.R;if(n=a?o?_k(o):a:o,i?i.L===t?i.L=n:i.R=n:this._=n,a&&o?(r=n.C,n.C=t.C,n.L=a,a.U=n,n!==o?(i=n.U,n.U=t.U,t=n.R,i.L=t,n.R=o,o.U=n):(n.U=i,i=n,t=n.R)):(r=t.C,t=n),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((e=i.R).C&&(e.C=!1,i.C=!0,vk(this,i),e=i.R),e.L&&e.L.C||e.R&&e.R.C){e.R&&e.R.C||(e.L.C=!1,e.C=!0,bk(this,e),e=i.R),e.C=i.C,i.C=e.R.C=!1,vk(this,i),t=this._;break}}else if((e=i.L).C&&(e.C=!1,i.C=!0,bk(this,i),e=i.L),e.L&&e.L.C||e.R&&e.R.C){e.L&&e.L.C||(e.R.C=!1,e.C=!0,vk(this,e),e=i.L),e.C=i.C,i.C=e.L.C=!1,bk(this,i),t=this._;break}e.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};const xk=gk;function wk(t,e,n,r){var i=[null,null],a=Wk.push(i)-1;return i.left=t,i.right=e,n&&Tk(i,t,e,n),r&&Tk(i,e,t,r),Hk[t.index].halfedges.push(a),Hk[e.index].halfedges.push(a),i}function kk(t,e,n){var r=[e,n];return r.left=t,r}function Tk(t,e,n,r){t[0]||t[1]?t.left===n?t[1]=r:t[0]=r:(t[0]=r,t.left=e,t.right=n)}function Ek(t,e,n,r,i){var a,o=t[0],s=t[1],c=o[0],u=o[1],l=0,h=1,f=s[0]-c,d=s[1]-u;if(a=e-c,f||!(a>0)){if(a/=f,f<0){if(a0){if(a>h)return;a>l&&(l=a)}if(a=r-c,f||!(a<0)){if(a/=f,f<0){if(a>h)return;a>l&&(l=a)}else if(f>0){if(a0)){if(a/=d,d<0){if(a0){if(a>h)return;a>l&&(l=a)}if(a=i-u,d||!(a<0)){if(a/=d,d<0){if(a>h)return;a>l&&(l=a)}else if(d>0){if(a0||h<1)||(l>0&&(t[0]=[c+l*f,u+l*d]),h<1&&(t[1]=[c+h*f,u+h*d]),!0)}}}}}function Ck(t,e,n,r,i){var a=t[1];if(a)return!0;var o,s,c=t[0],u=t.left,l=t.right,h=u[0],f=u[1],d=l[0],p=l[1],y=(h+d)/2,g=(f+p)/2;if(p===f){if(y=r)return;if(h>d){if(c){if(c[1]>=i)return}else c=[y,n];a=[y,i]}else{if(c){if(c[1]1)if(h>d){if(c){if(c[1]>=i)return}else c=[(n-s)/o,n];a=[(i-s)/o,i]}else{if(c){if(c[1]=r)return}else c=[e,o*e+s];a=[r,o*r+s]}else{if(c){if(c[0]=-Gk)){var d=c*c+u*u,p=l*l+h*h,y=(h*d-u*p)/f,g=(c*p-l*d)/f,m=Dk.pop()||new Ok;m.arc=t,m.site=i,m.x=y+o,m.y=(m.cy=g+s)+Math.sqrt(y*y+g*g),t.circle=m;for(var v=null,b=$k._;b;)if(m.yVk)s=s.L;else{if(!((i=a-Uk(s,o))>Vk)){r>-Vk?(e=s.P,n=s):i>-Vk?(e=s,n=s.N):e=n=s;break}if(!s.R){e=s;break}s=s.R}!function(t){Hk[t.index]={site:t,halfedges:[]}}(t);var c=Fk(t);if(qk.insert(e,c),e||n){if(e===n)return Lk(e),n=Fk(e.site),qk.insert(c,n),c.edge=n.edge=wk(e.site,c.site),Bk(e),void Bk(n);if(n){Lk(e),Lk(n);var u=e.site,l=u[0],h=u[1],f=t[0]-l,d=t[1]-h,p=n.site,y=p[0]-l,g=p[1]-h,m=2*(f*g-d*y),v=f*f+d*d,b=y*y+g*g,_=[(g*v-d*b)/m+l,(f*b-y*v)/m+h];Tk(n.edge,u,p,_),c.edge=wk(u,t,null,_),n.edge=wk(t,p,null,_),Bk(e),Bk(n)}else c.edge=wk(e.site,c.site)}}function zk(t,e){var n=t.site,r=n[0],i=n[1],a=i-e;if(!a)return r;var o=t.P;if(!o)return-1/0;var s=(n=o.site)[0],c=n[1],u=c-e;if(!u)return s;var l=s-r,h=1/a-1/u,f=l/u;return h?(-f+Math.sqrt(f*f-2*h*(l*l/(-2*u)-c+u/2+i-a/2)))/h+r:(r+s)/2}function Uk(t,e){var n=t.N;if(n)return zk(n,e);var r=t.site;return r[1]===e?r[0]:1/0}var qk,Hk,$k,Wk,Vk=1e-6,Gk=1e-12;function Xk(t,e,n){return(t[0]-n[0])*(e[1]-t[1])-(t[0]-e[0])*(n[1]-t[1])}function Zk(t,e){return e[1]-t[1]||e[0]-t[0]}function Qk(t,e){var n,r,i,a=t.sort(Zk).pop();for(Wk=[],Hk=new Array(t.length),qk=new xk,$k=new xk;;)if(i=Nk,a&&(!i||a[1]Vk||Math.abs(i[0][1]-i[1][1])>Vk)||delete Wk[a]}(o,s,c,u),function(t,e,n,r){var i,a,o,s,c,u,l,h,f,d,p,y,g=Hk.length,m=!0;for(i=0;iVk||Math.abs(y-f)>Vk)&&(c.splice(s,0,Wk.push(kk(o,d,Math.abs(p-t)Vk?[t,Math.abs(h-t)Vk?[Math.abs(f-r)Vk?[n,Math.abs(h-n)Vk?[Math.abs(f-e)=s)return null;var c=t-i.site[0],u=e-i.site[1],l=c*c+u*u;do{i=a.cells[r=o],o=null,i.halfedges.forEach((function(n){var r=a.edges[n],s=r.left;if(s!==i.site&&s||(s=r.right)){var c=t-s[0],u=e-s[1],h=c*c+u*u;hr?(r+i)/2:Math.min(0,r)||Math.max(0,i),o>a?(a+o)/2:Math.min(0,a)||Math.max(0,o))}function fT(){var t,e,n=oT,r=sT,i=hT,a=uT,o=lT,s=[0,1/0],c=[[-1/0,-1/0],[1/0,1/0]],u=250,l=Op,h=ft("start","zoom","end"),f=500,d=0;function p(t){t.property("__zoom",cT).on("wheel.zoom",x).on("mousedown.zoom",w).on("dblclick.zoom",k).filter(o).on("touchstart.zoom",T).on("touchmove.zoom",E).on("touchend.zoom touchcancel.zoom",C).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function y(t,e){return(e=Math.max(s[0],Math.min(s[1],e)))===t.k?t:new eT(e,t.x,t.y)}function g(t,e,n){var r=e[0]-n[0]*t.k,i=e[1]-n[1]*t.k;return r===t.x&&i===t.y?t:new eT(t.k,r,i)}function m(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function v(t,e,n){t.on("start.zoom",(function(){b(this,arguments).start()})).on("interrupt.zoom end.zoom",(function(){b(this,arguments).end()})).tween("zoom",(function(){var t=this,i=arguments,a=b(t,i),o=r.apply(t,i),s=null==n?m(o):"function"==typeof n?n.apply(t,i):n,c=Math.max(o[1][0]-o[0][0],o[1][1]-o[0][1]),u=t.__zoom,h="function"==typeof e?e.apply(t,i):e,f=l(u.invert(s).concat(c/u.k),h.invert(s).concat(c/h.k));return function(t){if(1===t)t=h;else{var e=f(t),n=c/e[2];t=new eT(n,s[0]-e[0]*n,s[1]-e[1]*n)}a.zoom(null,t)}}))}function b(t,e,n){return!n&&t.__zooming||new _(t,e)}function _(t,e){this.that=t,this.args=e,this.active=0,this.extent=r.apply(t,e),this.taps=0}function x(){if(n.apply(this,arguments)){var t=b(this,arguments),e=this.__zoom,r=Math.max(s[0],Math.min(s[1],e.k*Math.pow(2,a.apply(this,arguments)))),o=Bn(this);if(t.wheel)t.mouse[0][0]===o[0]&&t.mouse[0][1]===o[1]||(t.mouse[1]=e.invert(t.mouse[0]=o)),clearTimeout(t.wheel);else{if(e.k===r)return;t.mouse=[o,e.invert(o)],ar(this),t.start()}aT(),t.wheel=setTimeout(u,150),t.zoom("mouse",i(g(y(e,r),t.mouse[0],t.mouse[1]),t.extent,c))}function u(){t.wheel=null,t.end()}}function w(){if(!e&&n.apply(this,arguments)){var t=b(this,arguments,!0),r=Te(le.view).on("mousemove.zoom",u,!0).on("mouseup.zoom",l,!0),a=Bn(this),o=le.clientX,s=le.clientY;Se(le.view),iT(),t.mouse=[a,this.__zoom.invert(a)],ar(this),t.start()}function u(){if(aT(),!t.moved){var e=le.clientX-o,n=le.clientY-s;t.moved=e*e+n*n>d}t.zoom("mouse",i(g(t.that.__zoom,t.mouse[0]=Bn(t.that),t.mouse[1]),t.extent,c))}function l(){r.on("mousemove.zoom mouseup.zoom",null),Ae(le.view,t.moved),aT(),t.end()}}function k(){if(n.apply(this,arguments)){var t=this.__zoom,e=Bn(this),a=t.invert(e),o=t.k*(le.shiftKey?.5:2),s=i(g(y(t,o),e,a),r.apply(this,arguments),c);aT(),u>0?Te(this).transition().duration(u).call(v,s,e):Te(this).call(p.transform,s)}}function T(){if(n.apply(this,arguments)){var e,r,i,a,o=le.touches,s=o.length,c=b(this,arguments,le.changedTouches.length===s);for(iT(),r=0;r{t.exports={graphlib:n(574),layout:n(8123),debug:n(7570),util:{time:n(1138).time,notime:n(1138).notime},version:n(8177)}},1207:(t,e,n)=>{"use strict";var r=n(8436),i=n(4079);t.exports={run:function(t){var e="greedy"===t.graph().acyclicer?i(t,function(t){return function(e){return t.edge(e).weight}}(t)):function(t){var e=[],n={},i={};return r.forEach(t.nodes(),(function a(o){r.has(i,o)||(i[o]=!0,n[o]=!0,r.forEach(t.outEdges(o),(function(t){r.has(n,t.w)?e.push(t):a(t.w)})),delete n[o])})),e}(t);r.forEach(e,(function(e){var n=t.edge(e);t.removeEdge(e),n.forwardName=e.name,n.reversed=!0,t.setEdge(e.w,e.v,n,r.uniqueId("rev"))}))},undo:function(t){r.forEach(t.edges(),(function(e){var n=t.edge(e);if(n.reversed){t.removeEdge(e);var r=n.forwardName;delete n.reversed,delete n.forwardName,t.setEdge(e.w,e.v,n,r)}}))}}},1133:(t,e,n)=>{var r=n(8436),i=n(1138);function a(t,e,n,r,a,o){var s={width:0,height:0,rank:o,borderType:e},c=a[e][o-1],u=i.addDummyNode(t,"border",s,n);a[e][o]=u,t.setParent(u,r),c&&t.setEdge(c,u,{weight:1})}t.exports=function(t){r.forEach(t.children(),(function e(n){var i=t.children(n),o=t.node(n);if(i.length&&r.forEach(i,e),r.has(o,"minRank")){o.borderLeft=[],o.borderRight=[];for(var s=o.minRank,c=o.maxRank+1;s{"use strict";var r=n(8436);function i(t){r.forEach(t.nodes(),(function(e){a(t.node(e))})),r.forEach(t.edges(),(function(e){a(t.edge(e))}))}function a(t){var e=t.width;t.width=t.height,t.height=e}function o(t){t.y=-t.y}function s(t){var e=t.x;t.x=t.y,t.y=e}t.exports={adjust:function(t){var e=t.graph().rankdir.toLowerCase();"lr"!==e&&"rl"!==e||i(t)},undo:function(t){var e=t.graph().rankdir.toLowerCase();"bt"!==e&&"rl"!==e||function(t){r.forEach(t.nodes(),(function(e){o(t.node(e))})),r.forEach(t.edges(),(function(e){var n=t.edge(e);r.forEach(n.points,o),r.has(n,"y")&&o(n)}))}(t),"lr"!==e&&"rl"!==e||(function(t){r.forEach(t.nodes(),(function(e){s(t.node(e))})),r.forEach(t.edges(),(function(e){var n=t.edge(e);r.forEach(n.points,s),r.has(n,"x")&&s(n)}))}(t),i(t))}}},7822:t=>{function e(){var t={};t._next=t._prev=t,this._sentinel=t}function n(t){t._prev._next=t._next,t._next._prev=t._prev,delete t._next,delete t._prev}function r(t,e){if("_next"!==t&&"_prev"!==t)return e}t.exports=e,e.prototype.dequeue=function(){var t=this._sentinel,e=t._prev;if(e!==t)return n(e),e},e.prototype.enqueue=function(t){var e=this._sentinel;t._prev&&t._next&&n(t),t._next=e._next,e._next._prev=t,e._next=t,t._prev=e},e.prototype.toString=function(){for(var t=[],e=this._sentinel,n=e._prev;n!==e;)t.push(JSON.stringify(n,r)),n=n._prev;return"["+t.join(", ")+"]"}},7570:(t,e,n)=>{var r=n(8436),i=n(1138),a=n(574).Graph;t.exports={debugOrdering:function(t){var e=i.buildLayerMatrix(t),n=new a({compound:!0,multigraph:!0}).setGraph({});return r.forEach(t.nodes(),(function(e){n.setNode(e,{label:e}),n.setParent(e,"layer"+t.node(e).rank)})),r.forEach(t.edges(),(function(t){n.setEdge(t.v,t.w,{},t.name)})),r.forEach(e,(function(t,e){var i="layer"+e;n.setNode(i,{rank:"same"}),r.reduce(t,(function(t,e){return n.setEdge(t,e,{style:"invis"}),e}))})),n}}},574:(t,e,n)=>{var r;try{r=n(8282)}catch(t){}r||(r=window.graphlib),t.exports=r},4079:(t,e,n)=>{var r=n(8436),i=n(574).Graph,a=n(7822);t.exports=function(t,e){if(t.nodeCount()<=1)return[];var n=function(t,e){var n=new i,o=0,s=0;r.forEach(t.nodes(),(function(t){n.setNode(t,{v:t,in:0,out:0})})),r.forEach(t.edges(),(function(t){var r=n.edge(t.v,t.w)||0,i=e(t),a=r+i;n.setEdge(t.v,t.w,a),s=Math.max(s,n.node(t.v).out+=i),o=Math.max(o,n.node(t.w).in+=i)}));var u=r.range(s+o+3).map((function(){return new a})),l=o+1;return r.forEach(n.nodes(),(function(t){c(u,l,n.node(t))})),{graph:n,buckets:u,zeroIdx:l}}(t,e||o),u=function(t,e,n){for(var r,i=[],a=e[e.length-1],o=e[0];t.nodeCount();){for(;r=o.dequeue();)s(t,e,n,r);for(;r=a.dequeue();)s(t,e,n,r);if(t.nodeCount())for(var c=e.length-2;c>0;--c)if(r=e[c].dequeue()){i=i.concat(s(t,e,n,r,!0));break}}return i}(n.graph,n.buckets,n.zeroIdx);return r.flatten(r.map(u,(function(e){return t.outEdges(e.v,e.w)})),!0)};var o=r.constant(1);function s(t,e,n,i,a){var o=a?[]:void 0;return r.forEach(t.inEdges(i.v),(function(r){var i=t.edge(r),s=t.node(r.v);a&&o.push({v:r.v,w:r.w}),s.out-=i,c(e,n,s)})),r.forEach(t.outEdges(i.v),(function(r){var i=t.edge(r),a=r.w,o=t.node(a);o.in-=i,c(e,n,o)})),t.removeNode(i.v),o}function c(t,e,n){n.out?n.in?t[n.out-n.in+e].enqueue(n):t[t.length-1].enqueue(n):t[0].enqueue(n)}},8123:(t,e,n)=>{"use strict";var r=n(8436),i=n(1207),a=n(5995),o=n(8093),s=n(1138).normalizeRanks,c=n(4219),u=n(1138).removeEmptyRanks,l=n(2981),h=n(1133),f=n(3258),d=n(3408),p=n(7873),y=n(1138),g=n(574).Graph;t.exports=function(t,e){var n=e&&e.debugTiming?y.time:y.notime;n("layout",(function(){var e=n(" buildLayoutGraph",(function(){return function(t){var e=new g({multigraph:!0,compound:!0}),n=C(t.graph());return e.setGraph(r.merge({},v,E(n,m),r.pick(n,b))),r.forEach(t.nodes(),(function(n){var i=C(t.node(n));e.setNode(n,r.defaults(E(i,_),x)),e.setParent(n,t.parent(n))})),r.forEach(t.edges(),(function(n){var i=C(t.edge(n));e.setEdge(n,r.merge({},k,E(i,w),r.pick(i,T)))})),e}(t)}));n(" runLayout",(function(){!function(t,e){e(" makeSpaceForEdgeLabels",(function(){!function(t){var e=t.graph();e.ranksep/=2,r.forEach(t.edges(),(function(n){var r=t.edge(n);r.minlen*=2,"c"!==r.labelpos.toLowerCase()&&("TB"===e.rankdir||"BT"===e.rankdir?r.width+=r.labeloffset:r.height+=r.labeloffset)}))}(t)})),e(" removeSelfEdges",(function(){!function(t){r.forEach(t.edges(),(function(e){if(e.v===e.w){var n=t.node(e.v);n.selfEdges||(n.selfEdges=[]),n.selfEdges.push({e,label:t.edge(e)}),t.removeEdge(e)}}))}(t)})),e(" acyclic",(function(){i.run(t)})),e(" nestingGraph.run",(function(){l.run(t)})),e(" rank",(function(){o(y.asNonCompoundGraph(t))})),e(" injectEdgeLabelProxies",(function(){!function(t){r.forEach(t.edges(),(function(e){var n=t.edge(e);if(n.width&&n.height){var r=t.node(e.v),i={rank:(t.node(e.w).rank-r.rank)/2+r.rank,e};y.addDummyNode(t,"edge-proxy",i,"_ep")}}))}(t)})),e(" removeEmptyRanks",(function(){u(t)})),e(" nestingGraph.cleanup",(function(){l.cleanup(t)})),e(" normalizeRanks",(function(){s(t)})),e(" assignRankMinMax",(function(){!function(t){var e=0;r.forEach(t.nodes(),(function(n){var i=t.node(n);i.borderTop&&(i.minRank=t.node(i.borderTop).rank,i.maxRank=t.node(i.borderBottom).rank,e=r.max(e,i.maxRank))})),t.graph().maxRank=e}(t)})),e(" removeEdgeLabelProxies",(function(){!function(t){r.forEach(t.nodes(),(function(e){var n=t.node(e);"edge-proxy"===n.dummy&&(t.edge(n.e).labelRank=n.rank,t.removeNode(e))}))}(t)})),e(" normalize.run",(function(){a.run(t)})),e(" parentDummyChains",(function(){c(t)})),e(" addBorderSegments",(function(){h(t)})),e(" order",(function(){d(t)})),e(" insertSelfEdges",(function(){!function(t){var e=y.buildLayerMatrix(t);r.forEach(e,(function(e){var n=0;r.forEach(e,(function(e,i){var a=t.node(e);a.order=i+n,r.forEach(a.selfEdges,(function(e){y.addDummyNode(t,"selfedge",{width:e.label.width,height:e.label.height,rank:a.rank,order:i+ ++n,e:e.e,label:e.label},"_se")})),delete a.selfEdges}))}))}(t)})),e(" adjustCoordinateSystem",(function(){f.adjust(t)})),e(" position",(function(){p(t)})),e(" positionSelfEdges",(function(){!function(t){r.forEach(t.nodes(),(function(e){var n=t.node(e);if("selfedge"===n.dummy){var r=t.node(n.e.v),i=r.x+r.width/2,a=r.y,o=n.x-i,s=r.height/2;t.setEdge(n.e,n.label),t.removeNode(e),n.label.points=[{x:i+2*o/3,y:a-s},{x:i+5*o/6,y:a-s},{x:i+o,y:a},{x:i+5*o/6,y:a+s},{x:i+2*o/3,y:a+s}],n.label.x=n.x,n.label.y=n.y}}))}(t)})),e(" removeBorderNodes",(function(){!function(t){r.forEach(t.nodes(),(function(e){if(t.children(e).length){var n=t.node(e),i=t.node(n.borderTop),a=t.node(n.borderBottom),o=t.node(r.last(n.borderLeft)),s=t.node(r.last(n.borderRight));n.width=Math.abs(s.x-o.x),n.height=Math.abs(a.y-i.y),n.x=o.x+n.width/2,n.y=i.y+n.height/2}})),r.forEach(t.nodes(),(function(e){"border"===t.node(e).dummy&&t.removeNode(e)}))}(t)})),e(" normalize.undo",(function(){a.undo(t)})),e(" fixupEdgeLabelCoords",(function(){!function(t){r.forEach(t.edges(),(function(e){var n=t.edge(e);if(r.has(n,"x"))switch("l"!==n.labelpos&&"r"!==n.labelpos||(n.width-=n.labeloffset),n.labelpos){case"l":n.x-=n.width/2+n.labeloffset;break;case"r":n.x+=n.width/2+n.labeloffset}}))}(t)})),e(" undoCoordinateSystem",(function(){f.undo(t)})),e(" translateGraph",(function(){!function(t){var e=Number.POSITIVE_INFINITY,n=0,i=Number.POSITIVE_INFINITY,a=0,o=t.graph(),s=o.marginx||0,c=o.marginy||0;function u(t){var r=t.x,o=t.y,s=t.width,c=t.height;e=Math.min(e,r-s/2),n=Math.max(n,r+s/2),i=Math.min(i,o-c/2),a=Math.max(a,o+c/2)}r.forEach(t.nodes(),(function(e){u(t.node(e))})),r.forEach(t.edges(),(function(e){var n=t.edge(e);r.has(n,"x")&&u(n)})),e-=s,i-=c,r.forEach(t.nodes(),(function(n){var r=t.node(n);r.x-=e,r.y-=i})),r.forEach(t.edges(),(function(n){var a=t.edge(n);r.forEach(a.points,(function(t){t.x-=e,t.y-=i})),r.has(a,"x")&&(a.x-=e),r.has(a,"y")&&(a.y-=i)})),o.width=n-e+s,o.height=a-i+c}(t)})),e(" assignNodeIntersects",(function(){!function(t){r.forEach(t.edges(),(function(e){var n,r,i=t.edge(e),a=t.node(e.v),o=t.node(e.w);i.points?(n=i.points[0],r=i.points[i.points.length-1]):(i.points=[],n=o,r=a),i.points.unshift(y.intersectRect(a,n)),i.points.push(y.intersectRect(o,r))}))}(t)})),e(" reversePoints",(function(){!function(t){r.forEach(t.edges(),(function(e){var n=t.edge(e);n.reversed&&n.points.reverse()}))}(t)})),e(" acyclic.undo",(function(){i.undo(t)}))}(e,n)})),n(" updateInputGraph",(function(){!function(t,e){r.forEach(t.nodes(),(function(n){var r=t.node(n),i=e.node(n);r&&(r.x=i.x,r.y=i.y,e.children(n).length&&(r.width=i.width,r.height=i.height))})),r.forEach(t.edges(),(function(n){var i=t.edge(n),a=e.edge(n);i.points=a.points,r.has(a,"x")&&(i.x=a.x,i.y=a.y)})),t.graph().width=e.graph().width,t.graph().height=e.graph().height}(t,e)}))}))};var m=["nodesep","edgesep","ranksep","marginx","marginy"],v={ranksep:50,edgesep:20,nodesep:50,rankdir:"tb"},b=["acyclicer","ranker","rankdir","align"],_=["width","height"],x={width:0,height:0},w=["minlen","weight","width","height","labeloffset"],k={minlen:1,weight:1,width:0,height:0,labeloffset:10,labelpos:"r"},T=["labelpos"];function E(t,e){return r.mapValues(r.pick(t,e),Number)}function C(t){var e={};return r.forEach(t,(function(t,n){e[n.toLowerCase()]=t})),e}},8436:(t,e,n)=>{var r;try{r={cloneDeep:n(361),constant:n(5703),defaults:n(1747),each:n(6073),filter:n(3105),find:n(3311),flatten:n(5564),forEach:n(4486),forIn:n(2620),has:n(8721),isUndefined:n(2353),last:n(928),map:n(5161),mapValues:n(6604),max:n(6162),merge:n(3857),min:n(3632),minBy:n(2762),now:n(7771),pick:n(9722),range:n(6026),reduce:n(4061),sortBy:n(9734),uniqueId:n(3955),values:n(2628),zipObject:n(7287)}}catch(t){}r||(r=window._),t.exports=r},2981:(t,e,n)=>{var r=n(8436),i=n(1138);function a(t,e,n,o,s,c,u){var l=t.children(u);if(l.length){var h=i.addBorderNode(t,"_bt"),f=i.addBorderNode(t,"_bb"),d=t.node(u);t.setParent(h,u),d.borderTop=h,t.setParent(f,u),d.borderBottom=f,r.forEach(l,(function(r){a(t,e,n,o,s,c,r);var i=t.node(r),l=i.borderTop?i.borderTop:r,d=i.borderBottom?i.borderBottom:r,p=i.borderTop?o:2*o,y=l!==d?1:s-c[u]+1;t.setEdge(h,l,{weight:p,minlen:y,nestingEdge:!0}),t.setEdge(d,f,{weight:p,minlen:y,nestingEdge:!0})})),t.parent(u)||t.setEdge(e,h,{weight:0,minlen:s+c[u]})}else u!==e&&t.setEdge(e,u,{weight:0,minlen:n})}t.exports={run:function(t){var e=i.addDummyNode(t,"root",{},"_root"),n=function(t){var e={};function n(i,a){var o=t.children(i);o&&o.length&&r.forEach(o,(function(t){n(t,a+1)})),e[i]=a}return r.forEach(t.children(),(function(t){n(t,1)})),e}(t),o=r.max(r.values(n))-1,s=2*o+1;t.graph().nestingRoot=e,r.forEach(t.edges(),(function(e){t.edge(e).minlen*=s}));var c=function(t){return r.reduce(t.edges(),(function(e,n){return e+t.edge(n).weight}),0)}(t)+1;r.forEach(t.children(),(function(r){a(t,e,s,c,o,n,r)})),t.graph().nodeRankFactor=s},cleanup:function(t){var e=t.graph();t.removeNode(e.nestingRoot),delete e.nestingRoot,r.forEach(t.edges(),(function(e){t.edge(e).nestingEdge&&t.removeEdge(e)}))}}},5995:(t,e,n)=>{"use strict";var r=n(8436),i=n(1138);t.exports={run:function(t){t.graph().dummyChains=[],r.forEach(t.edges(),(function(e){!function(t,e){var n,r,a,o=e.v,s=t.node(o).rank,c=e.w,u=t.node(c).rank,l=e.name,h=t.edge(e),f=h.labelRank;if(u!==s+1){for(t.removeEdge(e),a=0,++s;s{var r=n(8436);t.exports=function(t,e,n){var i,a={};r.forEach(n,(function(n){for(var r,o,s=t.parent(n);s;){if((r=t.parent(s))?(o=a[r],a[r]=s):(o=i,i=s),o&&o!==s)return void e.setEdge(o,s);s=r}}))}},5439:(t,e,n)=>{var r=n(8436);t.exports=function(t,e){return r.map(e,(function(e){var n=t.inEdges(e);if(n.length){var i=r.reduce(n,(function(e,n){var r=t.edge(n),i=t.node(n.v);return{sum:e.sum+r.weight*i.order,weight:e.weight+r.weight}}),{sum:0,weight:0});return{v:e,barycenter:i.sum/i.weight,weight:i.weight}}return{v:e}}))}},3128:(t,e,n)=>{var r=n(8436),i=n(574).Graph;t.exports=function(t,e,n){var a=function(t){for(var e;t.hasNode(e=r.uniqueId("_root")););return e}(t),o=new i({compound:!0}).setGraph({root:a}).setDefaultNodeLabel((function(e){return t.node(e)}));return r.forEach(t.nodes(),(function(i){var s=t.node(i),c=t.parent(i);(s.rank===e||s.minRank<=e&&e<=s.maxRank)&&(o.setNode(i),o.setParent(i,c||a),r.forEach(t[n](i),(function(e){var n=e.v===i?e.w:e.v,a=o.edge(n,i),s=r.isUndefined(a)?0:a.weight;o.setEdge(n,i,{weight:t.edge(e).weight+s})})),r.has(s,"minRank")&&o.setNode(i,{borderLeft:s.borderLeft[e],borderRight:s.borderRight[e]}))})),o}},6630:(t,e,n)=>{"use strict";var r=n(8436);function i(t,e,n){for(var i=r.zipObject(n,r.map(n,(function(t,e){return e}))),a=r.flatten(r.map(e,(function(e){return r.sortBy(r.map(t.outEdges(e),(function(e){return{pos:i[e.w],weight:t.edge(e).weight}})),"pos")})),!0),o=1;o0;)e%2&&(n+=c[e+1]),c[e=e-1>>1]+=t.weight;u+=t.weight*n}))),u}t.exports=function(t,e){for(var n=0,r=1;r{"use strict";var r=n(8436),i=n(2588),a=n(6630),o=n(1026),s=n(3128),c=n(5093),u=n(574).Graph,l=n(1138);function h(t,e,n){return r.map(e,(function(e){return s(t,e,n)}))}function f(t,e){var n=new u;r.forEach(t,(function(t){var i=t.graph().root,a=o(t,i,n,e);r.forEach(a.vs,(function(e,n){t.node(e).order=n})),c(t,n,a.vs)}))}function d(t,e){r.forEach(e,(function(e){r.forEach(e,(function(e,n){t.node(e).order=n}))}))}t.exports=function(t){var e=l.maxRank(t),n=h(t,r.range(1,e+1),"inEdges"),o=h(t,r.range(e-1,-1,-1),"outEdges"),s=i(t);d(t,s);for(var c,u=Number.POSITIVE_INFINITY,p=0,y=0;y<4;++p,++y){f(p%2?n:o,p%4>=2),s=l.buildLayerMatrix(t);var g=a(t,s);g{"use strict";var r=n(8436);t.exports=function(t){var e={},n=r.filter(t.nodes(),(function(e){return!t.children(e).length})),i=r.max(r.map(n,(function(e){return t.node(e).rank}))),a=r.map(r.range(i+1),(function(){return[]})),o=r.sortBy(n,(function(e){return t.node(e).rank}));return r.forEach(o,(function n(i){if(!r.has(e,i)){e[i]=!0;var o=t.node(i);a[o.rank].push(i),r.forEach(t.successors(i),n)}})),a}},9567:(t,e,n)=>{"use strict";var r=n(8436);t.exports=function(t,e){var n={};return r.forEach(t,(function(t,e){var i=n[t.v]={indegree:0,in:[],out:[],vs:[t.v],i:e};r.isUndefined(t.barycenter)||(i.barycenter=t.barycenter,i.weight=t.weight)})),r.forEach(e.edges(),(function(t){var e=n[t.v],i=n[t.w];r.isUndefined(e)||r.isUndefined(i)||(i.indegree++,e.out.push(n[t.w]))})),function(t){var e=[];function n(t){return function(e){var n,i,a,o;e.merged||(r.isUndefined(e.barycenter)||r.isUndefined(t.barycenter)||e.barycenter>=t.barycenter)&&(i=e,a=0,o=0,(n=t).weight&&(a+=n.barycenter*n.weight,o+=n.weight),i.weight&&(a+=i.barycenter*i.weight,o+=i.weight),n.vs=i.vs.concat(n.vs),n.barycenter=a/o,n.weight=o,n.i=Math.min(i.i,n.i),i.merged=!0)}}function i(e){return function(n){n.in.push(e),0==--n.indegree&&t.push(n)}}for(;t.length;){var a=t.pop();e.push(a),r.forEach(a.in.reverse(),n(a)),r.forEach(a.out,i(a))}return r.map(r.filter(e,(function(t){return!t.merged})),(function(t){return r.pick(t,["vs","i","barycenter","weight"])}))}(r.filter(n,(function(t){return!t.indegree})))}},1026:(t,e,n)=>{var r=n(8436),i=n(5439),a=n(9567),o=n(7304);t.exports=function t(e,n,s,c){var u=e.children(n),l=e.node(n),h=l?l.borderLeft:void 0,f=l?l.borderRight:void 0,d={};h&&(u=r.filter(u,(function(t){return t!==h&&t!==f})));var p=i(e,u);r.forEach(p,(function(n){if(e.children(n.v).length){var i=t(e,n.v,s,c);d[n.v]=i,r.has(i,"barycenter")&&(a=n,o=i,r.isUndefined(a.barycenter)?(a.barycenter=o.barycenter,a.weight=o.weight):(a.barycenter=(a.barycenter*a.weight+o.barycenter*o.weight)/(a.weight+o.weight),a.weight+=o.weight))}var a,o}));var y=a(p,s);!function(t,e){r.forEach(t,(function(t){t.vs=r.flatten(t.vs.map((function(t){return e[t]?e[t].vs:t})),!0)}))}(y,d);var g=o(y,c);if(h&&(g.vs=r.flatten([h,g.vs,f],!0),e.predecessors(h).length)){var m=e.node(e.predecessors(h)[0]),v=e.node(e.predecessors(f)[0]);r.has(g,"barycenter")||(g.barycenter=0,g.weight=0),g.barycenter=(g.barycenter*g.weight+m.order+v.order)/(g.weight+2),g.weight+=2}return g}},7304:(t,e,n)=>{var r=n(8436),i=n(1138);function a(t,e,n){for(var i;e.length&&(i=r.last(e)).i<=n;)e.pop(),t.push(i.vs),n++;return n}t.exports=function(t,e){var n,o=i.partition(t,(function(t){return r.has(t,"barycenter")})),s=o.lhs,c=r.sortBy(o.rhs,(function(t){return-t.i})),u=[],l=0,h=0,f=0;s.sort((n=!!e,function(t,e){return t.barycentere.barycenter?1:n?e.i-t.i:t.i-e.i})),f=a(u,c,f),r.forEach(s,(function(t){f+=t.vs.length,u.push(t.vs),l+=t.barycenter*t.weight,h+=t.weight,f=a(u,c,f)}));var d={vs:r.flatten(u,!0)};return h&&(d.barycenter=l/h,d.weight=h),d}},4219:(t,e,n)=>{var r=n(8436);t.exports=function(t){var e=function(t){var e={},n=0;return r.forEach(t.children(),(function i(a){var o=n;r.forEach(t.children(a),i),e[a]={low:o,lim:n++}})),e}(t);r.forEach(t.graph().dummyChains,(function(n){for(var r=t.node(n),i=r.edgeObj,a=function(t,e,n,r){var i,a,o=[],s=[],c=Math.min(e[n].low,e[r].low),u=Math.max(e[n].lim,e[r].lim);i=n;do{i=t.parent(i),o.push(i)}while(i&&(e[i].low>c||u>e[i].lim));for(a=i,i=r;(i=t.parent(i))!==a;)s.push(i);return{path:o.concat(s.reverse()),lca:a}}(t,e,i.v,i.w),o=a.path,s=a.lca,c=0,u=o[c],l=!0;n!==i.w;){if(r=t.node(n),l){for(;(u=o[c])!==s&&t.node(u).maxRank{"use strict";var r=n(8436),i=n(574).Graph,a=n(1138);function o(t,e){var n={};return r.reduce(e,(function(e,i){var a=0,o=0,s=e.length,u=r.last(i);return r.forEach(i,(function(e,l){var h=function(t,e){if(t.node(e).dummy)return r.find(t.predecessors(e),(function(e){return t.node(e).dummy}))}(t,e),f=h?t.node(h).order:s;(h||e===u)&&(r.forEach(i.slice(o,l+1),(function(e){r.forEach(t.predecessors(e),(function(r){var i=t.node(r),o=i.order;!(os)&&c(n,e,u)}))}))}return r.reduce(e,(function(e,n){var a,o=-1,s=0;return r.forEach(n,(function(r,c){if("border"===t.node(r).dummy){var u=t.predecessors(r);u.length&&(a=t.node(u[0]).order,i(n,s,c,o,a),s=c,o=a)}i(n,s,n.length,a,e.length)})),n})),n}function c(t,e,n){if(e>n){var r=e;e=n,n=r}var i=t[e];i||(t[e]=i={}),i[n]=!0}function u(t,e,n){if(e>n){var i=e;e=n,n=i}return r.has(t[e],n)}function l(t,e,n,i){var a={},o={},s={};return r.forEach(e,(function(t){r.forEach(t,(function(t,e){a[t]=t,o[t]=t,s[t]=e}))})),r.forEach(e,(function(t){var e=-1;r.forEach(t,(function(t){var c=i(t);if(c.length){c=r.sortBy(c,(function(t){return s[t]}));for(var l=(c.length-1)/2,h=Math.floor(l),f=Math.ceil(l);h<=f;++h){var d=c[h];o[t]===t&&e{"use strict";var r=n(8436),i=n(1138),a=n(3573).positionX;t.exports=function(t){(function(t){var e=i.buildLayerMatrix(t),n=t.graph().ranksep,a=0;r.forEach(e,(function(e){var i=r.max(r.map(e,(function(e){return t.node(e).height})));r.forEach(e,(function(e){t.node(e).y=a+i/2})),a+=i+n}))})(t=i.asNonCompoundGraph(t)),r.forEach(a(t),(function(e,n){t.node(n).x=e}))}},300:(t,e,n)=>{"use strict";var r=n(8436),i=n(574).Graph,a=n(6681).slack;function o(t,e){return r.forEach(t.nodes(),(function n(i){r.forEach(e.nodeEdges(i),(function(r){var o=r.v,s=i===o?r.w:o;t.hasNode(s)||a(e,r)||(t.setNode(s,{}),t.setEdge(i,s,{}),n(s))}))})),t.nodeCount()}function s(t,e){return r.minBy(e.edges(),(function(n){if(t.hasNode(n.v)!==t.hasNode(n.w))return a(e,n)}))}function c(t,e,n){r.forEach(t.nodes(),(function(t){e.node(t).rank+=n}))}t.exports=function(t){var e,n,r=new i({directed:!1}),u=t.nodes()[0],l=t.nodeCount();for(r.setNode(u,{});o(r,t){"use strict";var r=n(6681).longestPath,i=n(300),a=n(2472);t.exports=function(t){switch(t.graph().ranker){case"network-simplex":default:!function(t){a(t)}(t);break;case"tight-tree":!function(t){r(t),i(t)}(t);break;case"longest-path":o(t)}};var o=r},2472:(t,e,n)=>{"use strict";var r=n(8436),i=n(300),a=n(6681).slack,o=n(6681).longestPath,s=n(574).alg.preorder,c=n(574).alg.postorder,u=n(1138).simplify;function l(t){t=u(t),o(t);var e,n=i(t);for(d(n),h(n,t);e=y(n);)m(n,t,e,g(n,t,e))}function h(t,e){var n=c(t,t.nodes());n=n.slice(0,n.length-1),r.forEach(n,(function(n){!function(t,e,n){var r=t.node(n).parent;t.edge(n,r).cutvalue=f(t,e,n)}(t,e,n)}))}function f(t,e,n){var i=t.node(n).parent,a=!0,o=e.edge(n,i),s=0;return o||(a=!1,o=e.edge(i,n)),s=o.weight,r.forEach(e.nodeEdges(n),(function(r){var o,c,u=r.v===n,l=u?r.w:r.v;if(l!==i){var h=u===a,f=e.edge(r).weight;if(s+=h?f:-f,o=n,c=l,t.hasEdge(o,c)){var d=t.edge(n,l).cutvalue;s+=h?-d:d}}})),s}function d(t,e){arguments.length<2&&(e=t.nodes()[0]),p(t,{},1,e)}function p(t,e,n,i,a){var o=n,s=t.node(i);return e[i]=!0,r.forEach(t.neighbors(i),(function(a){r.has(e,a)||(n=p(t,e,n,a,i))})),s.low=o,s.lim=n++,a?s.parent=a:delete s.parent,n}function y(t){return r.find(t.edges(),(function(e){return t.edge(e).cutvalue<0}))}function g(t,e,n){var i=n.v,o=n.w;e.hasEdge(i,o)||(i=n.w,o=n.v);var s=t.node(i),c=t.node(o),u=s,l=!1;s.lim>c.lim&&(u=c,l=!0);var h=r.filter(e.edges(),(function(e){return l===v(0,t.node(e.v),u)&&l!==v(0,t.node(e.w),u)}));return r.minBy(h,(function(t){return a(e,t)}))}function m(t,e,n,i){var a=n.v,o=n.w;t.removeEdge(a,o),t.setEdge(i.v,i.w,{}),d(t),h(t,e),function(t,e){var n=r.find(t.nodes(),(function(t){return!e.node(t).parent})),i=s(t,n);i=i.slice(1),r.forEach(i,(function(n){var r=t.node(n).parent,i=e.edge(n,r),a=!1;i||(i=e.edge(r,n),a=!0),e.node(n).rank=e.node(r).rank+(a?i.minlen:-i.minlen)}))}(t,e)}function v(t,e,n){return n.low<=e.lim&&e.lim<=n.lim}t.exports=l,l.initLowLimValues=d,l.initCutValues=h,l.calcCutValue=f,l.leaveEdge=y,l.enterEdge=g,l.exchangeEdges=m},6681:(t,e,n)=>{"use strict";var r=n(8436);t.exports={longestPath:function(t){var e={};r.forEach(t.sources(),(function n(i){var a=t.node(i);if(r.has(e,i))return a.rank;e[i]=!0;var o=r.min(r.map(t.outEdges(i),(function(e){return n(e.w)-t.edge(e).minlen})));return o!==Number.POSITIVE_INFINITY&&null!=o||(o=0),a.rank=o}))},slack:function(t,e){return t.node(e.w).rank-t.node(e.v).rank-t.edge(e).minlen}}},1138:(t,e,n)=>{"use strict";var r=n(8436),i=n(574).Graph;function a(t,e,n,i){var a;do{a=r.uniqueId(i)}while(t.hasNode(a));return n.dummy=e,t.setNode(a,n),a}function o(t){return r.max(r.map(t.nodes(),(function(e){var n=t.node(e).rank;if(!r.isUndefined(n))return n})))}t.exports={addDummyNode:a,simplify:function(t){var e=(new i).setGraph(t.graph());return r.forEach(t.nodes(),(function(n){e.setNode(n,t.node(n))})),r.forEach(t.edges(),(function(n){var r=e.edge(n.v,n.w)||{weight:0,minlen:1},i=t.edge(n);e.setEdge(n.v,n.w,{weight:r.weight+i.weight,minlen:Math.max(r.minlen,i.minlen)})})),e},asNonCompoundGraph:function(t){var e=new i({multigraph:t.isMultigraph()}).setGraph(t.graph());return r.forEach(t.nodes(),(function(n){t.children(n).length||e.setNode(n,t.node(n))})),r.forEach(t.edges(),(function(n){e.setEdge(n,t.edge(n))})),e},successorWeights:function(t){var e=r.map(t.nodes(),(function(e){var n={};return r.forEach(t.outEdges(e),(function(e){n[e.w]=(n[e.w]||0)+t.edge(e).weight})),n}));return r.zipObject(t.nodes(),e)},predecessorWeights:function(t){var e=r.map(t.nodes(),(function(e){var n={};return r.forEach(t.inEdges(e),(function(e){n[e.v]=(n[e.v]||0)+t.edge(e).weight})),n}));return r.zipObject(t.nodes(),e)},intersectRect:function(t,e){var n,r,i=t.x,a=t.y,o=e.x-i,s=e.y-a,c=t.width/2,u=t.height/2;if(!o&&!s)throw new Error("Not possible to find intersection inside of the rectangle");return Math.abs(s)*c>Math.abs(o)*u?(s<0&&(u=-u),n=u*o/s,r=u):(o<0&&(c=-c),n=c,r=c*s/o),{x:i+n,y:a+r}},buildLayerMatrix:function(t){var e=r.map(r.range(o(t)+1),(function(){return[]}));return r.forEach(t.nodes(),(function(n){var i=t.node(n),a=i.rank;r.isUndefined(a)||(e[a][i.order]=n)})),e},normalizeRanks:function(t){var e=r.min(r.map(t.nodes(),(function(e){return t.node(e).rank})));r.forEach(t.nodes(),(function(n){var i=t.node(n);r.has(i,"rank")&&(i.rank-=e)}))},removeEmptyRanks:function(t){var e=r.min(r.map(t.nodes(),(function(e){return t.node(e).rank}))),n=[];r.forEach(t.nodes(),(function(r){var i=t.node(r).rank-e;n[i]||(n[i]=[]),n[i].push(r)}));var i=0,a=t.graph().nodeRankFactor;r.forEach(n,(function(e,n){r.isUndefined(e)&&n%a!=0?--i:i&&r.forEach(e,(function(e){t.node(e).rank+=i}))}))},addBorderNode:function(t,e,n,r){var i={width:0,height:0};return arguments.length>=4&&(i.rank=n,i.order=r),a(t,"border",i,e)},maxRank:o,partition:function(t,e){var n={lhs:[],rhs:[]};return r.forEach(t,(function(t){e(t)?n.lhs.push(t):n.rhs.push(t)})),n},time:function(t,e){var n=r.now();try{return e()}finally{console.log(t+" time: "+(r.now()-n)+"ms")}},notime:function(t,e){return e()}}},8177:t=>{t.exports="0.8.5"},7856:function(t){t.exports=function(){"use strict";var t=Object.hasOwnProperty,e=Object.setPrototypeOf,n=Object.isFrozen,r=Object.getPrototypeOf,i=Object.getOwnPropertyDescriptor,a=Object.freeze,o=Object.seal,s=Object.create,c="undefined"!=typeof Reflect&&Reflect,u=c.apply,l=c.construct;u||(u=function(t,e,n){return t.apply(e,n)}),a||(a=function(t){return t}),o||(o=function(t){return t}),l||(l=function(t,e){return new(Function.prototype.bind.apply(t,[null].concat(function(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e1?n-1:0),i=1;i/gm),j=o(/^data-[\-\w.\u00B7-\uFFFF]/),Y=o(/^aria-[\-\w]+$/),z=o(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),U=o(/^(?:\w+script|data):/i),q=o(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),H="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};function $(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e0&&void 0!==arguments[0]?arguments[0]:W(),n=function(e){return t(e)};if(n.version="2.3.5",n.removed=[],!e||!e.document||9!==e.document.nodeType)return n.isSupported=!1,n;var r=e.document,i=e.document,o=e.DocumentFragment,s=e.HTMLTemplateElement,c=e.Node,u=e.Element,l=e.NodeFilter,h=e.NamedNodeMap,w=void 0===h?e.NamedNodeMap||e.MozNamedAttrMap:h,G=e.HTMLFormElement,X=e.DOMParser,Z=e.trustedTypes,Q=u.prototype,K=E(Q,"cloneNode"),J=E(Q,"nextSibling"),tt=E(Q,"childNodes"),et=E(Q,"parentNode");if("function"==typeof s){var nt=i.createElement("template");nt.content&&nt.content.ownerDocument&&(i=nt.content.ownerDocument)}var rt=V(Z,r),it=rt?rt.createHTML(""):"",at=i,ot=at.implementation,st=at.createNodeIterator,ct=at.createDocumentFragment,ut=at.getElementsByTagName,lt=r.importNode,ht={};try{ht=T(i).documentMode?i.documentMode:{}}catch(t){}var ft={};n.isSupported="function"==typeof et&&ot&&void 0!==ot.createHTMLDocument&&9!==ht;var dt=F,pt=P,yt=j,gt=Y,mt=U,vt=q,bt=z,_t=null,xt=k({},[].concat($(C),$(S),$(A),$(N),$(O))),wt=null,kt=k({},[].concat($(B),$(L),$(I),$(R))),Tt=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Et=null,Ct=null,St=!0,At=!0,Mt=!1,Nt=!1,Dt=!1,Ot=!1,Bt=!1,Lt=!1,It=!1,Rt=!1,Ft=!0,Pt=!0,jt=!1,Yt={},zt=null,Ut=k({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),qt=null,Ht=k({},["audio","video","img","source","image","track"]),$t=null,Wt=k({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Vt="http://www.w3.org/1998/Math/MathML",Gt="http://www.w3.org/2000/svg",Xt="http://www.w3.org/1999/xhtml",Zt=Xt,Qt=!1,Kt=void 0,Jt=["application/xhtml+xml","text/html"],te="text/html",ee=void 0,ne=null,re=i.createElement("form"),ie=function(t){return t instanceof RegExp||t instanceof Function},ae=function(t){ne&&ne===t||(t&&"object"===(void 0===t?"undefined":H(t))||(t={}),t=T(t),_t="ALLOWED_TAGS"in t?k({},t.ALLOWED_TAGS):xt,wt="ALLOWED_ATTR"in t?k({},t.ALLOWED_ATTR):kt,$t="ADD_URI_SAFE_ATTR"in t?k(T(Wt),t.ADD_URI_SAFE_ATTR):Wt,qt="ADD_DATA_URI_TAGS"in t?k(T(Ht),t.ADD_DATA_URI_TAGS):Ht,zt="FORBID_CONTENTS"in t?k({},t.FORBID_CONTENTS):Ut,Et="FORBID_TAGS"in t?k({},t.FORBID_TAGS):{},Ct="FORBID_ATTR"in t?k({},t.FORBID_ATTR):{},Yt="USE_PROFILES"in t&&t.USE_PROFILES,St=!1!==t.ALLOW_ARIA_ATTR,At=!1!==t.ALLOW_DATA_ATTR,Mt=t.ALLOW_UNKNOWN_PROTOCOLS||!1,Nt=t.SAFE_FOR_TEMPLATES||!1,Dt=t.WHOLE_DOCUMENT||!1,Lt=t.RETURN_DOM||!1,It=t.RETURN_DOM_FRAGMENT||!1,Rt=t.RETURN_TRUSTED_TYPE||!1,Bt=t.FORCE_BODY||!1,Ft=!1!==t.SANITIZE_DOM,Pt=!1!==t.KEEP_CONTENT,jt=t.IN_PLACE||!1,bt=t.ALLOWED_URI_REGEXP||bt,Zt=t.NAMESPACE||Xt,t.CUSTOM_ELEMENT_HANDLING&&ie(t.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(Tt.tagNameCheck=t.CUSTOM_ELEMENT_HANDLING.tagNameCheck),t.CUSTOM_ELEMENT_HANDLING&&ie(t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(Tt.attributeNameCheck=t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),t.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(Tt.allowCustomizedBuiltInElements=t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Kt=Kt=-1===Jt.indexOf(t.PARSER_MEDIA_TYPE)?te:t.PARSER_MEDIA_TYPE,ee="application/xhtml+xml"===Kt?function(t){return t}:y,Nt&&(At=!1),It&&(Lt=!0),Yt&&(_t=k({},[].concat($(O))),wt=[],!0===Yt.html&&(k(_t,C),k(wt,B)),!0===Yt.svg&&(k(_t,S),k(wt,L),k(wt,R)),!0===Yt.svgFilters&&(k(_t,A),k(wt,L),k(wt,R)),!0===Yt.mathMl&&(k(_t,N),k(wt,I),k(wt,R))),t.ADD_TAGS&&(_t===xt&&(_t=T(_t)),k(_t,t.ADD_TAGS)),t.ADD_ATTR&&(wt===kt&&(wt=T(wt)),k(wt,t.ADD_ATTR)),t.ADD_URI_SAFE_ATTR&&k($t,t.ADD_URI_SAFE_ATTR),t.FORBID_CONTENTS&&(zt===Ut&&(zt=T(zt)),k(zt,t.FORBID_CONTENTS)),Pt&&(_t["#text"]=!0),Dt&&k(_t,["html","head","body"]),_t.table&&(k(_t,["tbody"]),delete Et.tbody),a&&a(t),ne=t)},oe=k({},["mi","mo","mn","ms","mtext"]),se=k({},["foreignobject","desc","title","annotation-xml"]),ce=k({},S);k(ce,A),k(ce,M);var ue=k({},N);k(ue,D);var le=function(t){var e=et(t);e&&e.tagName||(e={namespaceURI:Xt,tagName:"template"});var n=y(t.tagName),r=y(e.tagName);if(t.namespaceURI===Gt)return e.namespaceURI===Xt?"svg"===n:e.namespaceURI===Vt?"svg"===n&&("annotation-xml"===r||oe[r]):Boolean(ce[n]);if(t.namespaceURI===Vt)return e.namespaceURI===Xt?"math"===n:e.namespaceURI===Gt?"math"===n&&se[r]:Boolean(ue[n]);if(t.namespaceURI===Xt){if(e.namespaceURI===Gt&&!se[r])return!1;if(e.namespaceURI===Vt&&!oe[r])return!1;var i=k({},["title","style","font","a","script"]);return!ue[n]&&(i[n]||!ce[n])}return!1},he=function(t){p(n.removed,{element:t});try{t.parentNode.removeChild(t)}catch(e){try{t.outerHTML=it}catch(e){t.remove()}}},fe=function(t,e){try{p(n.removed,{attribute:e.getAttributeNode(t),from:e})}catch(t){p(n.removed,{attribute:null,from:e})}if(e.removeAttribute(t),"is"===t&&!wt[t])if(Lt||It)try{he(e)}catch(t){}else try{e.setAttribute(t,"")}catch(t){}},de=function(t){var e=void 0,n=void 0;if(Bt)t=""+t;else{var r=g(t,/^[\r\n\t ]+/);n=r&&r[0]}"application/xhtml+xml"===Kt&&(t=''+t+"");var a=rt?rt.createHTML(t):t;if(Zt===Xt)try{e=(new X).parseFromString(a,Kt)}catch(t){}if(!e||!e.documentElement){e=ot.createDocument(Zt,"template",null);try{e.documentElement.innerHTML=Qt?"":a}catch(t){}}var o=e.body||e.documentElement;return t&&n&&o.insertBefore(i.createTextNode(n),o.childNodes[0]||null),Zt===Xt?ut.call(e,Dt?"html":"body")[0]:Dt?e.documentElement:o},pe=function(t){return st.call(t.ownerDocument||t,t,l.SHOW_ELEMENT|l.SHOW_COMMENT|l.SHOW_TEXT,null,!1)},ye=function(t){return t instanceof G&&("string"!=typeof t.nodeName||"string"!=typeof t.textContent||"function"!=typeof t.removeChild||!(t.attributes instanceof w)||"function"!=typeof t.removeAttribute||"function"!=typeof t.setAttribute||"string"!=typeof t.namespaceURI||"function"!=typeof t.insertBefore)},ge=function(t){return"object"===(void 0===c?"undefined":H(c))?t instanceof c:t&&"object"===(void 0===t?"undefined":H(t))&&"number"==typeof t.nodeType&&"string"==typeof t.nodeName},me=function(t,e,r){ft[t]&&f(ft[t],(function(t){t.call(n,e,r,ne)}))},ve=function(t){var e=void 0;if(me("beforeSanitizeElements",t,null),ye(t))return he(t),!0;if(g(t.nodeName,/[\u0080-\uFFFF]/))return he(t),!0;var r=ee(t.nodeName);if(me("uponSanitizeElement",t,{tagName:r,allowedTags:_t}),!ge(t.firstElementChild)&&(!ge(t.content)||!ge(t.content.firstElementChild))&&_(/<[/\w]/g,t.innerHTML)&&_(/<[/\w]/g,t.textContent))return he(t),!0;if("select"===r&&_(/