diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
commit | 72231250ed81e10d66bfe70701e64fa5fe50f712 (patch) | |
tree | 2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /config-model-api/src/main/java/com/yahoo/config/model/api |
Publish
Diffstat (limited to 'config-model-api/src/main/java/com/yahoo/config/model/api')
18 files changed, 608 insertions, 0 deletions
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeAction.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeAction.java new file mode 100644 index 00000000000..30e2df9acf9 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeAction.java @@ -0,0 +1,42 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import java.util.List; + +/** + * Contains the action to be performed on the given services to handle a config change + * between the current active model and the next model to prepare. + * + * @author geirst + * @since 5.40 + */ +public interface ConfigChangeAction { + + enum Type { + RESTART("restart"), REFEED("refeed"); + + private final String type; + + Type(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } + } + + /** Returns what type of action is required to handle this config change */ + Type getType(); + + /** Returns a message describing the config change in detail */ + String getMessage(); + + /** Returns the list of services where the action must be performed */ + List<ServiceInfo> getServices(); + + /** Returns whether this change should be allowed */ + boolean allowed(); + +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRefeedAction.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRefeedAction.java new file mode 100644 index 00000000000..7f70733fb8c --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRefeedAction.java @@ -0,0 +1,22 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +/** + * Represents an action to re-feed a document type in order to handle a config change. + * + * @author geirst + * @since 5.43 + */ +public interface ConfigChangeRefeedAction extends ConfigChangeAction { + + @Override + default Type getType() { return Type.REFEED; } + + /** Returns the name identifying this kind of change, used to identify names which should be allowed */ + // Remove this default implementation when model versions earlier than 5.125 are gone + default String name() { return ""; } + + /** Returns the name of the document type that one must re-feed to handle this config change */ + String getDocumentType(); + +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRestartAction.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRestartAction.java new file mode 100644 index 00000000000..3add3ef1519 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigChangeRestartAction.java @@ -0,0 +1,19 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +/** + * Represents an action to restart services in order to handle a config change. + * + * @author geirst + * @since 5.43 + */ +public interface ConfigChangeRestartAction extends ConfigChangeAction { + + @Override + default Type getType() { return Type.RESTART; } + + /** Restarts are handled automatically so they are allowed */ + @Override + default boolean allowed() { return true; } + +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionRepo.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionRepo.java new file mode 100644 index 00000000000..69dc3f08d64 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionRepo.java @@ -0,0 +1,23 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import com.yahoo.config.codegen.InnerCNode; +import com.yahoo.vespa.config.ConfigDefinitionKey; +import com.yahoo.vespa.config.buildergen.ConfigDefinition; + +import java.util.Map; + +/** + * Represents a repository of config definitions. + * + * @author lulf + * @since 5.10 + */ +public interface ConfigDefinitionRepo { + + /** + * Retrieve a map with all configdefinitions in this repo. + */ + Map<ConfigDefinitionKey, ConfigDefinition> getConfigDefinitions(); + +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionStore.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionStore.java new file mode 100644 index 00000000000..ca2064ed363 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigDefinitionStore.java @@ -0,0 +1,13 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import com.yahoo.vespa.config.ConfigDefinition; +import com.yahoo.vespa.config.ConfigDefinitionKey; + +/** + * @author lulf + * @since 5.1 + */ +public interface ConfigDefinitionStore { + ConfigDefinition getConfigDefinition(ConfigDefinitionKey defKey); +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigModelPlugin.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigModelPlugin.java new file mode 100644 index 00000000000..3cebcb6e71b --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigModelPlugin.java @@ -0,0 +1,10 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +/** + * Interface of config model plugins. + * + * @author lulf + */ +public interface ConfigModelPlugin { +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigServerSpec.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigServerSpec.java new file mode 100644 index 00000000000..0a43f190675 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ConfigServerSpec.java @@ -0,0 +1,14 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +/** + * Provides information about a configserver instance. + * + * @author tonytv + */ +public interface ConfigServerSpec { + public String getHostName(); + public int getConfigServerPort(); + public int getHttpPort(); + public int getZooKeeperPort(); +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/FileDistribution.java b/config-model-api/src/main/java/com/yahoo/config/model/api/FileDistribution.java new file mode 100644 index 00000000000..604a9edf003 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/FileDistribution.java @@ -0,0 +1,28 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import com.yahoo.config.FileReference; +import com.yahoo.vespa.defaults.Defaults; + +import java.io.File; +import java.util.Collection; +import java.util.Set; + +/** + * Interface for models towards filedistribution. + * + * @author lulf + * @since 5.1 + */ +public interface FileDistribution { + + void sendDeployedFiles(String hostName, Set<FileReference> fileReferences); + void reloadDeployFileDistributor(); + void limitSendingOfDeployedFilesTo(Collection<String> hostNames); + void removeDeploymentsThatHaveDifferentApplicationId(Collection<String> targetHostnames); + + static File getDefaultFileDBPath() { + return new File(Defaults.getDefaults().vespaHome() + "var/db/vespa/filedistribution"); + } + +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/HostInfo.java b/config-model-api/src/main/java/com/yahoo/config/model/api/HostInfo.java new file mode 100644 index 00000000000..dbb2a1a07a9 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/HostInfo.java @@ -0,0 +1,48 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import java.util.Collection; + +/* + * Contains information about a host and what services are running on it. + * + * @author lulf + * @since 5.37 + */ +public class HostInfo { + private final String hostname; + private final Collection<ServiceInfo> services; + + public HostInfo(String hostName, Collection<ServiceInfo> services) { + this.hostname = hostName; + this.services = services; + } + + public String getHostname() { + return hostname; + } + + public Collection<ServiceInfo> getServices() { + return services; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + HostInfo hostInfo = (HostInfo) o; + + if (!hostname.equals(hostInfo.hostname)) return false; + if (services != null ? !services.equals(hostInfo.services) : hostInfo.services != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = hostname.hashCode(); + result = 31 * result + (services != null ? services.hashCode() : 0); + return result; + } +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/HostProvisioner.java b/config-model-api/src/main/java/com/yahoo/config/model/api/HostProvisioner.java new file mode 100644 index 00000000000..3e14485dd5a --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/HostProvisioner.java @@ -0,0 +1,33 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import com.yahoo.config.provision.*; + +import java.util.List; +import java.util.logging.Level; + +/** + * Interface towards the host provisioner used to build a {@link Model}. The difference between this provisioner + * and {@link com.yahoo.config.provision.Provisioner}, is that this interface only exposes methods needed + * to build the model. + * + * @author lulf + */ +public interface HostProvisioner { + + /** Allocates a single host for a service */ + // TODO: Remove + HostSpec allocateHost(String alias); + + /** + * Prepares allocation of a set of hosts with a given type, common id and the amount. + * + * @param cluster the cluster to allocate nodes to + * @param capacity the capacity describing the capacity requested + * @param groups the number of groups to divide the nodes into + * @param logger a logger to which messages to the deployer may be written + * @return the specification of the allocated hosts + */ + List<HostSpec> prepare(ClusterSpec cluster, Capacity capacity, int groups, ProvisionLogger logger); + +}
\ No newline at end of file diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java b/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java new file mode 100644 index 00000000000..998ca6cb53c --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java @@ -0,0 +1,99 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import com.yahoo.config.codegen.InnerCNode; +import com.yahoo.config.provision.ProvisionInfo; +import com.yahoo.vespa.config.ConfigKey; +import com.yahoo.vespa.config.ConfigPayload; +import com.yahoo.vespa.config.buildergen.ConfigDefinition; + +import java.io.IOException; +import java.util.Optional; +import java.util.Set; +import java.util.Collection; + +/** + * A {@link Model} represents the interface towards the model of an entire tenant, and defines methods + * for querying this model. + * + * @author lulf + * @since 5.1 + */ +public interface Model { + + /** + * Resolves a config using a given def file, apply overrides and returns it. + * + * @param configKey The key of the config to retrieve. + * @param targetDef The config definition to use for applying defaults. + * @return override The global override to apply to the generated config. + */ + ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition targetDef, ConfigPayload override) throws IOException; + + /** + * TODO: Remove this method once no fat bundles implementing it anymore. + * Use {@link Model#getConfig(ConfigKey, ConfigDefinition, ConfigPayload)} instead. + * + * Resolves a config using a given def file, apply overrides and returns it. + * + * @param configKey The key of the config to retrieve. + * @param targetDef The config definition to use for applying defaults. + * @return override The global override to apply to the generated config. + */ + ConfigPayload getConfig(ConfigKey<?> configKey, InnerCNode targetDef, ConfigPayload override) throws IOException; + + /** + * Produces a set of the valid config keys for this model. + */ + Set<ConfigKey<?>> allConfigsProduced(); + + /** + * Returns information about all hosts used in this model. + */ + Collection<HostInfo> getHosts(); + + /** + * Returns all the config ids available for this model. + */ + Set<String> allConfigIds(); + + /** + * Asks the {@link Model} instance to distribute files using provided filedistribution instance. + * @param fileDistribution {@link com.yahoo.config.model.api.FileDistribution} instance that can be called to distribute files. + */ + void distributeFiles(FileDistribution fileDistribution); + + + /** + * Tells file distributor to rescan all files. At the moment this is a very expensive operation, so should only be done + * once per deployment. + * @param fileDistribution {@link com.yahoo.config.model.api.FileDistribution} instance. + */ + default void reloadDeployFileDistributor(FileDistribution fileDistribution) { } + + /** + * Get the provisioning info for this model. + * @return {@link ProvisionInfo} instance, if available. + */ + Optional<ProvisionInfo> getProvisionInfo(); + + /** + * Returns whether this application allows serving config request for a different version. + * This is a validation override which is useful when we skip loading old config models + * due to some problem, or when we need to try a newer version of the platform on some node. + */ + default boolean allowModelVersionMismatch() { return false; } + + /** + * Returns whether old config models should be loaded (default) or not. + * Skipping old config models is a validation override which is useful when the old model + * version is known to contain some incompatibility with the application package + * and it is believed that the latest model version will deliver usable config for old versions + * requesting config. + * <p> + * If a model returns true to this it should also return true to {@link #allowModelVersionMismatch} + * or clients requesting config for those old models will not get config at all. + */ + default boolean skipOldConfigModels() { return false; } + +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java new file mode 100644 index 00000000000..9226e3bbe11 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java @@ -0,0 +1,43 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import com.yahoo.config.application.api.ApplicationPackage; +import com.yahoo.config.application.api.DeployLogger; +import com.yahoo.config.application.api.FileRegistry; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.Rotation; +import com.yahoo.config.provision.Version; +import com.yahoo.config.provision.Zone; + +import java.io.File; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * Model context containing state provided to model factories. + * + * @author lulf + */ +public interface ModelContext { + + ApplicationPackage applicationPackage(); + Optional<Model> previousModel(); + Optional<ApplicationPackage> permanentApplicationPackage(); + Optional<HostProvisioner> hostProvisioner(); + DeployLogger deployLogger(); + ConfigDefinitionRepo configDefinitionRepo(); + FileRegistry getFileRegistry(); + Properties properties(); + default Optional<File> appDir() { return Optional.empty();} + default Optional<Version> vespaVersion() { return Optional.empty(); } + + interface Properties { + boolean multitenant(); + ApplicationId applicationId(); + List<ConfigServerSpec> configServerSpecs(); + boolean hostedVespa(); + Zone zone(); + Set<Rotation> rotations(); + } +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelCreateResult.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelCreateResult.java new file mode 100644 index 00000000000..10738653129 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelCreateResult.java @@ -0,0 +1,28 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import java.util.List; + +/** + * The result after creating and validating a Model. + * + * @author geirst + * @since 5.39 + */ +public class ModelCreateResult { + + private final Model model; + private final List<ConfigChangeAction> configChangeActions; + + public ModelCreateResult(Model model, List<ConfigChangeAction> configChangeActions) { + this.model = model; + this.configChangeActions = configChangeActions; + } + + /** The model these changes apply to */ + public Model getModel() { return model; } + + /** Returns the actions that needs to be done to successfully start using the new model */ + public List<ConfigChangeAction> getConfigChangeActions() { return configChangeActions; } + +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelFactory.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelFactory.java new file mode 100644 index 00000000000..a6f7b8096ea --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelFactory.java @@ -0,0 +1,39 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import com.yahoo.config.provision.Version; + +/** + * Factory for config models. + */ +public interface ModelFactory { + + /** + * Gets version of this {@link ModelFactory}. The version will be used to dispatch deployments to the correct + * {@link ModelFactory}. + * + * @return The version of a {@link Model} instance that this factory can create. + */ + Version getVersion(); + + /** + * Creates an instance of a {@link Model}. The resulting instance will be used to serve config. No model + * validation will be done, calling this method presupposes that {@link #createAndValidateModel} has already + * been called. + * + * @param modelContext An instance of {@link ModelContext}, containing dependencies for creating a {@link Model}. + * @return a {@link Model} instance. + */ + Model createModel(ModelContext modelContext); + + /** + * Creates an instance of a {@link Model}. The resulting instance will be used to serve config. Any validation + * of a {@link Model} and the {@link ModelContext} can be done in this method. + * + * @param modelContext An instance of {@link ModelContext}, containing dependencies for creating a {@link Model}. + * @param ignoreValidationErrors true if validation errors should not trigger exceptions. + * @return a {@link ModelCreateResult} instance. + */ + ModelCreateResult createAndValidateModel(ModelContext modelContext, boolean ignoreValidationErrors); + +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelState.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelState.java new file mode 100644 index 00000000000..236f951e4d3 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelState.java @@ -0,0 +1,9 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +/** + * @author lulf + */ +public interface ModelState { + Model getModel(); +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/PortInfo.java b/config-model-api/src/main/java/com/yahoo/config/model/api/PortInfo.java new file mode 100644 index 00000000000..99f6ae469f3 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/PortInfo.java @@ -0,0 +1,46 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import java.util.Collection; + +/** + * Contains information about a port (port number and a collection of tags). + * + */ +public class PortInfo { + private final int port; + private final Collection<String> tags; + + public PortInfo(int port, Collection<String> tags) { + this.port = port; + this.tags = tags; + } + + public int getPort() { + return port; + } + + public Collection<String> getTags() { + return tags; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + PortInfo portInfo = (PortInfo) o; + + if (port != portInfo.port) return false; + if (tags != null ? !tags.equals(portInfo.tags) : portInfo.tags != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = port; + result = 31 * result + (tags != null ? tags.hashCode() : 0); + return result; + } +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ServiceInfo.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ServiceInfo.java new file mode 100644 index 00000000000..6d72da7df6f --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ServiceInfo.java @@ -0,0 +1,87 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Collection; + +/** + * Contains information about a service. + * + * @author lulf + * @since 5.37 + */ +public class ServiceInfo { + private final String serviceName; + private final String serviceType; + private final Collection<PortInfo> ports; + private final Map<String, String> properties; + private final String configId; + private final String hostName; + + public ServiceInfo(String serviceName, String serviceType, Collection<PortInfo> ports, Map<String, String> properties, + String configId, String hostName) { + + Objects.requireNonNull(configId); + + this.serviceName = serviceName; + this.serviceType = serviceType; + this.ports = ports; + this.properties = properties; + this.configId = configId; + this.hostName = hostName; + } + + public String getServiceName() { + return serviceName; + } + + public String getConfigId() { + return configId; + } + + public String getServiceType() { + return serviceType; + } + + public Optional<String> getProperty(String propertyName) { + return Optional.ofNullable(properties.get(propertyName)); + } + + public Collection<PortInfo> getPorts() { + return ports; + } + + public String getHostName() { + return hostName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ServiceInfo that = (ServiceInfo) o; + + if (ports != null ? !ports.equals(that.ports) : that.ports != null) return false; + if (properties != null ? !properties.equals(that.properties) : that.properties != null) return false; + if (!serviceName.equals(that.serviceName)) return false; + if (!serviceType.equals(that.serviceType)) return false; + if (!configId.equals(that.configId)) return false; + if (!hostName.equals(that.hostName)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = serviceName.hashCode(); + result = 31 * result + serviceType.hashCode(); + result = 31 * result + (ports != null ? ports.hashCode() : 0); + result = 31 * result + (properties != null ? properties.hashCode() : 0); + result = 31 * result + configId.hashCode(); + result = 31 * result + hostName.hashCode(); + return result; + } +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/package-info.java b/config-model-api/src/main/java/com/yahoo/config/model/api/package-info.java new file mode 100644 index 00000000000..730d23f5086 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/package-info.java @@ -0,0 +1,5 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +@ExportPackage +package com.yahoo.config.model.api; + +import com.yahoo.osgi.annotation.ExportPackage; |