+
+Java Operator SDK is a CNCF project as part of [Operator Framework](https://github.com/operator-framework).
+
## Documentation
Documentation can be found on the **[JOSDK WebSite](https://javaoperatorsdk.io/)**.
-It's getting better every day! :)
-
## Contact us
Join us on [Discord](https://discord.gg/DacEhAy) or feel free to ask any question on
[Kubernetes Slack Operator Channel](https://kubernetes.slack.com/archives/CAW0GV7A5)
-**Meet us** every Thursday (17:00 CET) at our **community meeting** on [Zoom](https://zoom.us/j/8415370125)
+**Meet us** every other Tuesday 15:00 CEST (from 29.10.2024) at our **community meeting** on [Zoom](https://zoom.us/j/8415370125)
(Password in the Discord channel, or just ask for it there!)
## How to Contribute
@@ -26,23 +38,48 @@ See the [contribution](https://javaoperatorsdk.io/docs/contributing) guide on th
## What is Java Operator SDK
Java Operator SDK is a higher level framework and related tooling to support writing Kubernetes Operators in Java.
-It makes it easy to implement best practices and patters for an Operator. Features include:
+It makes it easy to implement best practices and patterns for an Operator. Features include:
* Optimal handling Kubernetes API events
-* Handling dependent resources, related events, caching.
+* Handling dependent resources, related events, and caching.
* Automatic Retries
* Smart event scheduling
-* Handling Observed Generations automatically
* Easy to use Error Handling
* ... and everything that a batteries included framework needs
-For all features and their usage see the [related section on the website](https://javaoperatorsdk.io/docs/features).
+For all features and their usage see the [related sections on the website](https://javaoperatorsdk.io/docs/documentation/).
## Related Projects
-Operator SDK plugin: https://github.com/operator-framework/java-operator-plugins
-
-Quarkus Extension: https://github.com/quarkiverse/quarkus-operator-sdk
-
-Spring Boot Starter: https://github.com/java-operator-sdk/operator-framework-spring-boot-starter
-
+* Quarkus Extension: https://github.com/quarkiverse/quarkus-operator-sdk
+* Spring Boot Starter: https://github.com/java-operator-sdk/operator-framework-spring-boot-starter
+* Kubernetes Glue Operator: https://github.com/java-operator-sdk/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
+
+## Projects using JOSDK
+
+While we know of multiple projects using JOSDK in production, we don't want to presume these
+projects want to advertise that fact here. For this reason, we ask that if you'd like your project
+to be featured in this section, please open a PR, adding a link to and short description of your
+project, as shown below:
+
+- [kroxylicious](https://github.com/kroxylicious/kroxylicious/tree/main/kroxylicious-operator) Kafka proxy operator
+- [ExposedApp operator](https://github.com/halkyonio/exposedapp-rhdblog): a sample operator
+ written to illustrate JOSDK concepts and its Quarkus extension in the ["Write Kubernetes
+ Operators in Java with the Java Operator SDK" blog series](https://developers.redhat.com/articles/2022/02/15/write-kubernetes-java-java-operator-sdk#).
+- [Keycloak operator](https://github.com/keycloak/keycloak/tree/main/operator): the official
+ Keycloak operator, built with Quarkus and JOSDK.
+- [Apache Flink Kubernetes operator](https://github.com/apache/flink-kubernetes-operator) is the market leader among Flink operators.
+- [Apache Spark Kubernetes Operator](https://github.com/apache/spark-kubernetes-operator) emerging operator for Spark.
+- [Strimzi Access operator](https://github.com/strimzi/kafka-access-operator). While the core Strimzi operator development predates
+ JOSDK, but new components like the Access operator is using the framework.
+- [EureKubeOperator](https://medium.com/@heesuk.dev/implementing-kubernetes-operator-for-eureka-service-discovery-integration-by-java-operator-sdk-d21d8087c38e): integrates service discovery of Eureka and Kubernetes using the framework - developed by 11street. It is not released as an open source yet but is very interesting to read about this problem and how it is solved by an operator written with JOSDK.
+- [Locust k8s operator](https://github.com/AbdelrhmanHamouda/locust-k8s-operator): Cloud native solution to run performance tests on any Kubernetes cluster.
+- [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.
diff --git a/adr/001-Introducing-ADRs.md b/adr/001-Introducing-ADRs.md
new file mode 100644
index 0000000000..3a432e8094
--- /dev/null
+++ b/adr/001-Introducing-ADRs.md
@@ -0,0 +1,29 @@
+# Using Architectural Decision Records
+
+In order to into to document and facilitate discussion over architecture and other design question of the project
+we introduce usage of [ADR](https://adr.github.io/).
+
+In each ADR file, write these sections:
+
+# Title
+
+## Status
+
+What is the status, such as proposed, accepted, rejected, deprecated, superseded, etc.?
+
+## Context
+
+What is the issue that we're seeing that is motivating this decision or change?
+
+## Decision
+
+What is the change that we're proposing and/or doing?
+
+## Consequences
+
+What becomes easier or more difficult to do because of this change?
+
+## Notes
+
+Other notes optionally added to the ADR.
+Soo other good materials for the ADRs:
\ No newline at end of file
diff --git a/adr/002-Custom-Resource-Deserialization-Problem.md b/adr/002-Custom-Resource-Deserialization-Problem.md
new file mode 100644
index 0000000000..0f648105fc
--- /dev/null
+++ b/adr/002-Custom-Resource-Deserialization-Problem.md
@@ -0,0 +1,44 @@
+# Multi Version Custom Resources Deserialization Problem
+
+## Status
+
+accepted
+
+## Context
+
+In case there are multiple versions of a custom resource it can happen that a controller/informer tracking
+such a resource might run into deserialization problem as shown
+in [this integration test](https://github.com/operator-framework/java-operator-sdk/blob/07aab1a9914d865364d7236e496ef9ba5b50699e/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultiVersionCRDIT.java#L55-L55)
+.
+Such case is possible (as seen in the test) if there are no conversion hooks in place, so the two custom resources
+which have different version are stored in the original form (not converted) and are not compatible.
+In this case, if there is no further filtering (by labels) informer receives both, but naturally not able to deserialize
+one of them.
+
+How should the framework or the underlying informer behave?
+
+Alternatives:
+
+1. The informer should skip the resource and should continue to process the resources with the correct version.
+2. Informer stops and makes a notification callback.
+
+## Decision
+
+From the JOSDK perspective, it is fine if the informer stops, and the users decides if the whole operator should stop
+(usually the preferred way). The reason, that this is an obvious issue on platform level (not on operator/controller
+level). Thus, the controller should not receive such custom resources in the first place, so the problem should be
+addressed at the platform level. Possibly introducing conversion hooks, or labeling for the target resource.
+
+## Consequences
+
+If an Informer stops on such deserialization error, even explicitly restarting it won't solve the problem, since
+would fail again on the same error.
+
+## Notes
+
+- The informer implementation in fabric8 client changed in this regard, before it was not stopping on deserialization
+ error, but as described this change in behavior is completely acceptable.
+
+- the deserializer can be set to be more lenient by configuring the Serialization Unmatched Field Type module:
+ `Serialization.UNMATCHED_FIELD_TYPE_MODULE.setRestrictToTemplates(true);`. In general is not desired to
+ process custom resources that are not deserialized correctly.
\ No newline at end of file
diff --git a/bootstrapper-maven-plugin/pom.xml b/bootstrapper-maven-plugin/pom.xml
new file mode 100644
index 0000000000..a55636840b
--- /dev/null
+++ b/bootstrapper-maven-plugin/pom.xml
@@ -0,0 +1,100 @@
+
+Note that if a resource is reconciled and is not present anymore in cache, it will
+ * transparently be fetched again from the API server. Similarly, since associated secondary
+ * resources are usually reconciled too, they might need to be fetched and populated to the cache,
+ * and will remain there for some time, for subsequent reconciliations.
+ */
+public class CaffeineBoundedItemStores {
+
+ private CaffeineBoundedItemStores() {}
+
+ /**
+ * @param client Kubernetes Client
+ * @param rClass resource class
+ * @param accessExpireDuration the duration after resources is evicted from cache if not accessed.
+ * @return the ItemStore implementation
+ * @param customResourceClass();
+
+ abstract LocallyRunOperatorExtension extension();
+}
diff --git a/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/CaffeineBoundedCacheClusterScopeIT.java b/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/CaffeineBoundedCacheClusterScopeIT.java
new file mode 100644
index 0000000000..0c16c1227b
--- /dev/null
+++ b/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/CaffeineBoundedCacheClusterScopeIT.java
@@ -0,0 +1,53 @@
+package io.javaoperatorsdk.operator.processing.event.source.cache;
+
+import java.time.Duration;
+
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
+import io.fabric8.kubernetes.client.KubernetesClientBuilder;
+import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
+import io.javaoperatorsdk.operator.processing.event.source.cache.sample.clusterscope.BoundedCacheClusterScopeTestCustomResource;
+import io.javaoperatorsdk.operator.processing.event.source.cache.sample.clusterscope.BoundedCacheClusterScopeTestReconciler;
+import io.javaoperatorsdk.operator.processing.event.source.cache.sample.namespacescope.BoundedCacheTestSpec;
+
+import static io.javaoperatorsdk.operator.processing.event.source.cache.sample.AbstractTestReconciler.boundedItemStore;
+
+public class CaffeineBoundedCacheClusterScopeIT
+ extends BoundedCacheTestBase {
+
+ private static final Logger log =
+ LoggerFactory.getLogger(BoundedCacheClusterScopeTestReconciler.class);
+
+ public static final String DATA_KEY = "dataKey";
+
+ @Override
+ public UpdateControl reconcile(P resource, Context context) {
+ var maybeConfigMap = context.getSecondaryResource(ConfigMap.class);
+ maybeConfigMap.ifPresentOrElse(
+ 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, 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()));
+ context.getClient().configMaps().resource(cm).replace();
+ }
+ }
+
+ protected void createConfigMap(P resource, Context context) {
+ var cm =
+ new ConfigMapBuilder()
+ .withMetadata(
+ new ObjectMetaBuilder()
+ .withName(resource.getMetadata().getName())
+ .withNamespace(resource.getSpec().getTargetNamespace())
+ .build())
+ .withData(Map.of(DATA_KEY, resource.getSpec().getData()))
+ .build();
+ cm.addOwnerReference(resource);
+ context.getClient().configMaps().resource(cm).create();
+ }
+
+ @Override
+ public List context) {
+
+ var boundedItemStore =
+ boundedItemStore(
+ new KubernetesClientBuilder().build(),
+ ConfigMap.class,
+ Duration.ofMinutes(1),
+ 1); // setting max size for testing purposes
+
+ var es =
+ new InformerEventSource<>(
+ InformerEventSourceConfiguration.from(ConfigMap.class, primaryClass())
+ .withItemStore(boundedItemStore)
+ .withSecondaryToPrimaryMapper(
+ Mappers.fromOwnerReferences(
+ context.getPrimaryResourceClass(),
+ this instanceof BoundedCacheClusterScopeTestReconciler))
+ .build(),
+ context);
+
+ return List.of(es);
+ }
+
+ private void ensureStatus(P resource) {
+ if (resource.getStatus() == null) {
+ resource.setStatus(new BoundedCacheTestStatus());
+ }
+ }
+
+ public static primaryClass();
+}
diff --git a/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/clusterscope/BoundedCacheClusterScopeTestCustomResource.java b/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/clusterscope/BoundedCacheClusterScopeTestCustomResource.java
new file mode 100644
index 0000000000..6fc9a5babc
--- /dev/null
+++ b/caffeine-bounded-cache-support/src/test/java/io/javaoperatorsdk/operator/processing/event/source/cache/sample/clusterscope/BoundedCacheClusterScopeTestCustomResource.java
@@ -0,0 +1,14 @@
+package io.javaoperatorsdk.operator.processing.event.source.cache.sample.clusterscope;
+
+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.processing.event.source.cache.sample.namespacescope.BoundedCacheTestSpec;
+import io.javaoperatorsdk.operator.processing.event.source.cache.sample.namespacescope.BoundedCacheTestStatus;
+
+@Group("sample.javaoperatorsdk")
+@Version("v1")
+@ShortNames("bccs")
+public class BoundedCacheClusterScopeTestCustomResource
+ extends CustomResource =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;a >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-e =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;a
- {% endif %}
-
[ {{ site.title }} ]
-
- [ {{ page.title }} ]
- =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=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