Repository: incubator-slider Updated Branches: refs/heads/feature/packaging_improvements a31d20eed -> 82dd48373
Package simplification poc-II Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/82dd4837 Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/82dd4837 Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/82dd4837 Branch: refs/heads/feature/packaging_improvements Commit: 82dd48373134a17fba55a48f3f3928dfce3f8680 Parents: a31d20e Author: Sumit Mohanty <[email protected]> Authored: Wed Feb 25 13:25:15 2015 -0800 Committer: Sumit Mohanty <[email protected]> Committed: Wed Feb 25 13:25:15 2015 -0800 ---------------------------------------------------------------------- .../providers/agent/AgentProviderService.java | 5 ++ .../application/metadata/json/Component.java | 15 ++++ .../application/metadata/json/Container.java | 79 +++++++++++++++++++ .../metadata/json/ContainerMount.java | 53 +++++++++++++ .../metadata/json/ContainerPort.java | 53 +++++++++++++ .../appmaster/web/rest/agent/Container.java | 82 ++++++++++++++++++++ .../web/rest/agent/ContainerMount.java | 58 ++++++++++++++ .../appmaster/web/rest/agent/ContainerPort.java | 57 ++++++++++++++ .../web/rest/agent/ExecutionCommand.java | 56 ++++++++++++- .../metadata/json/TestMetaInfoParser.java | 19 +++++ 10 files changed, 475 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/82dd4837/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java index 4104cdd..d4bb0f4 100644 --- a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java +++ b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java @@ -1643,6 +1643,8 @@ public class AgentProviderService extends AbstractProviderService implements cmd.setCommandParams(setCommandParameters(scriptPath, timeout, false)); cmd.setHostname(getClusterInfoPropertyValue(StatusKeys.INFO_AM_HOSTNAME)); + + cmd.addContainerDetails(componentName, getMetaInfo()); response.addExecutionCommand(cmd); } @@ -1682,6 +1684,7 @@ public class AgentProviderService extends AbstractProviderService implements configurations.get("global").put("exec_cmd", effectiveCommand.getExec()); cmd.setHostname(getClusterInfoPropertyValue(StatusKeys.INFO_AM_HOSTNAME)); + cmd.addContainerDetails(componentName, getMetaInfo()); response.addExecutionCommand(cmd); } @@ -1824,6 +1827,7 @@ public class AgentProviderService extends AbstractProviderService implements Map<String, Map<String, String>> configurations = buildCommandConfigurations(appConf, containerId, componentName); cmd.setConfigurations(configurations); + cmd.addContainerDetails(componentName, getMetaInfo()); response.addExecutionCommand(cmd); // With start command, the corresponding command for graceful stop needs to @@ -1891,6 +1895,7 @@ public class AgentProviderService extends AbstractProviderService implements cmd.setConfigurations(configurations); configurations.get("global").put("exec_cmd", startCommand.getExec()); + cmd.addContainerDetails(componentName, getMetaInfo()); response.addExecutionCommand(cmd); } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/82dd4837/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/Component.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/Component.java b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/Component.java index 8697e48..84147a3 100644 --- a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/Component.java +++ b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/Component.java @@ -40,12 +40,14 @@ public class Component { private String compExports; private String category = "MASTER"; private String publishConfig; + private String type; private int minInstanceCount = 1; private int maxInstanceCount = Integer.MAX_VALUE; private Boolean autoStartOnFailure = false; private String appExports; private CommandScript commandScript; private List<ComponentCommand> commands = new ArrayList<ComponentCommand>(); + private List<Container> containers = new ArrayList<Container>(); public Component() { } @@ -55,6 +57,11 @@ public class Component { return this.commands; } + @JsonProperty("containers") + public List<Container> getContainers() { + return this.containers; + } + public CommandScript getCommandScript() { return commandScript; } @@ -126,4 +133,12 @@ public class Component { public void setAppExports(String appExports) { this.appExports = appExports; } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/82dd4837/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/Container.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/Container.java b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/Container.java new file mode 100644 index 0000000..e95406e --- /dev/null +++ b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/Container.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.slider.providers.agent.application.metadata.json; + +import org.codehaus.jackson.annotate.JsonProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a docker container + */ +public class Container { + protected static final Logger + log = LoggerFactory.getLogger(Container.class); + + + private String name; + private String image; + private String options; + private List<ContainerMount> mounts = new ArrayList<>(); + private List<ContainerPort> ports = new ArrayList<>(); + + + public Container() { + } + + @JsonProperty("mounts") + public List<ContainerMount> getMounts() { + return this.mounts; + } + + @JsonProperty("ports") + public List<ContainerPort> getPorts() { + return this.ports; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + public String getOptions() { + return options; + } + + public void setOptions(String options) { + this.options = options; + } +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/82dd4837/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/ContainerMount.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/ContainerMount.java b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/ContainerMount.java new file mode 100644 index 0000000..b31b602 --- /dev/null +++ b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/ContainerMount.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.slider.providers.agent.application.metadata.json; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Represents a docker container mount + */ +public class ContainerMount { + protected static final Logger + log = LoggerFactory.getLogger(ContainerMount.class); + + + private String containerMount; + private String hostMount; + + public ContainerMount() { + } + + public String getContainerMount() { + return containerMount; + } + + public void setContainerMount(String containerMount) { + this.containerMount = containerMount; + } + + public String getHostMount() { + return hostMount; + } + + public void setHostMount(String hostMount) { + this.hostMount = hostMount; + } +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/82dd4837/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/ContainerPort.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/ContainerPort.java b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/ContainerPort.java new file mode 100644 index 0000000..d2dcb09 --- /dev/null +++ b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/json/ContainerPort.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.slider.providers.agent.application.metadata.json; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Represents a docker container port + */ +public class ContainerPort { + protected static final Logger + log = LoggerFactory.getLogger(ContainerPort.class); + + + private String containerPort; + private String hostPort; + + public ContainerPort() { + } + + public String getContainerPort() { + return containerPort; + } + + public void setContainerPort(String containerPort) { + this.containerPort = containerPort; + } + + public String getHostPort() { + return hostPort; + } + + public void setHostPort(String hostPort) { + this.hostPort = hostPort; + } +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/82dd4837/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/Container.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/Container.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/Container.java new file mode 100644 index 0000000..ef58920 --- /dev/null +++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/Container.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.slider.server.appmaster.web.rest.agent; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.annotate.JsonSerialize; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a docker container + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) +public class Container { + protected static final Logger + log = LoggerFactory.getLogger(Container.class); + + private String name; + private String image; + private String options; + private List<ContainerMount> mounts = new ArrayList<>(); + private List<ContainerPort> ports = new ArrayList<>(); + + + public Container() { + } + + @JsonProperty("mounts") + public List<ContainerMount> getMounts() { + return this.mounts; + } + + @JsonProperty("ports") + public List<ContainerPort> getPorts() { + return this.ports; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + public String getOptions() { + return options; + } + + public void setOptions(String options) { + this.options = options; + } +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/82dd4837/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ContainerMount.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ContainerMount.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ContainerMount.java new file mode 100644 index 0000000..c2670c7 --- /dev/null +++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ContainerMount.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.slider.server.appmaster.web.rest.agent; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.codehaus.jackson.map.annotate.JsonSerialize; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Represents a docker container mount + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) +public class ContainerMount { + protected static final Logger + log = LoggerFactory.getLogger(ContainerMount.class); + + + // TODO: Rename + private String containerMount; + private String hostMount; + + public ContainerMount() { + } + + public String getContainerMount() { + return containerMount; + } + + public void setContainerMount(String containerMount) { + this.containerMount = containerMount; + } + + public String getHostMount() { + return hostMount; + } + + public void setHostMount(String hostMount) { + this.hostMount = hostMount; + } +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/82dd4837/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ContainerPort.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ContainerPort.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ContainerPort.java new file mode 100644 index 0000000..a36194c --- /dev/null +++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ContainerPort.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.slider.server.appmaster.web.rest.agent; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.codehaus.jackson.map.annotate.JsonSerialize; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Represents a docker container port + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) +public class ContainerPort { + protected static final Logger + log = LoggerFactory.getLogger(ContainerPort.class); + + + private String containerPort; + private String hostPort; + + public ContainerPort() { + } + + public String getContainerPort() { + return containerPort; + } + + public void setContainerPort(String containerPort) { + this.containerPort = containerPort; + } + + public String getHostPort() { + return hostPort; + } + + public void setHostPort(String hostPort) { + this.hostPort = hostPort; + } +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/82dd4837/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ExecutionCommand.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ExecutionCommand.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ExecutionCommand.java index 5fb3b5e..054bc46 100644 --- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ExecutionCommand.java +++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ExecutionCommand.java @@ -18,11 +18,17 @@ package org.apache.slider.server.appmaster.web.rest.agent; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.slider.providers.agent.application.metadata.json.Component; +import org.apache.slider.providers.agent.application.metadata.json.MetaInfo; import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.annotate.JsonSerialize; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -31,7 +37,8 @@ import java.util.Map; @JsonIgnoreProperties(ignoreUnknown = true) @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) public class ExecutionCommand { - private static Log LOG = LogFactory.getLog(ExecutionCommand.class); + protected static final Logger log = + LoggerFactory.getLogger(ExecutionCommand.class); private AgentCommandType commandType = AgentCommandType.EXECUTION_COMMAND; private String clusterName; private long taskId; @@ -46,11 +53,18 @@ public class ExecutionCommand { private Map<String, String> commandParams; private String serviceName; private String componentName; + private String componentType; + private List<Container> containers = new ArrayList<>(); public ExecutionCommand(AgentCommandType commandType) { this.commandType = commandType; } + @JsonProperty("containers") + public List<Container> getContainers() { + return containers; + } + @JsonProperty("commandType") public AgentCommandType getCommandType() { return commandType; @@ -121,6 +135,16 @@ public class ExecutionCommand { this.clusterName = clusterName; } + @JsonProperty("componentType") + public String getComponentType() { + return componentType; + } + + @JsonProperty("componentType") + public void setComponentType(String componentType) { + this.componentType = componentType; + } + @JsonProperty("hostname") public String getHostname() { return hostname; @@ -130,7 +154,6 @@ public class ExecutionCommand { public void setHostname(String hostname) { this.hostname = hostname; } - @JsonProperty("hostLevelParams") public Map<String, String> getHostLevelParams() { return hostLevelParams; @@ -196,4 +219,33 @@ public class ExecutionCommand { .append(", componentName=").append(componentName).append("]"); return builder.toString(); } + + public void addContainerDetails(String componentName, MetaInfo metaInfo) { + Component component = metaInfo.getApplicationComponent(componentName); + this.setComponentType(component.getType()); + log.info("Adding container details for {}", componentName); + for(org.apache.slider.providers.agent.application.metadata.json.Container metaContainer: component.getContainers()) { + Container container = new Container(); + container.setImage(metaContainer.getImage()); + container.setName(metaContainer.getName()); + container.setOptions(metaContainer.getOptions()); + if(metaContainer.getMounts().size() > 0) { + for(org.apache.slider.providers.agent.application.metadata.json.ContainerMount metaContMount : metaContainer.getMounts()) { + ContainerMount contMnt = new ContainerMount(); + contMnt.setContainerMount(metaContMount.getContainerMount()); + contMnt.setHostMount(metaContMount.getHostMount()); + container.getMounts().add(contMnt); + } + } + if(metaContainer.getPorts().size() > 0) { + for(org.apache.slider.providers.agent.application.metadata.json.ContainerPort metaCntPort : metaContainer.getPorts()) { + ContainerPort cntPort = new ContainerPort(); + cntPort.setContainerPort(metaCntPort.getContainerPort()); + cntPort.setHostPort(metaCntPort.getHostPort()); + container.getPorts().add(cntPort); + } + } + this.getContainers().add(container); + } + } } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/82dd4837/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/json/TestMetaInfoParser.java ---------------------------------------------------------------------- diff --git a/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/json/TestMetaInfoParser.java b/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/json/TestMetaInfoParser.java index 3648a29..83a87a4 100644 --- a/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/json/TestMetaInfoParser.java +++ b/slider-core/src/test/java/org/apache/slider/providers/agent/application/metadata/json/TestMetaInfoParser.java @@ -66,6 +66,19 @@ public class TestMetaInfoParser { + "\"type\": \"PYTHON\"," + "\"name\": \"CONFIGURE\"" + "}" + + "]," + + "\"containers\": [" + + "{" + + "\"name\": \"redis\"," + + "\"image\": \"dockerhub/redis\"," + + "\"options\": \"-net=bridge\"," + + "\"mounts\": [" + + "{" + + "\"containerMount\": \"/tmp/conf\"," + + "\"hostMount\": \"{$conf:@//site/global/app_root}/conf\"" + + "}" + + "]" + + "}" + "]" + "}" + "]" @@ -111,5 +124,11 @@ public class TestMetaInfoParser { Assert.assertEquals("CONFIGURE", cmd.getName()); Assert.assertEquals("PYTHON", cmd.getType()); Assert.assertEquals("scripts/config.py", cmd.getExec()); + Assert.assertEquals(1, c2.getContainers().size()); + Container cont = c2.getContainers().get(0); + Assert.assertEquals("redis", cont.getName()); + Assert.assertEquals(1, cont.getMounts().size()); + ContainerMount mount = cont.getMounts().get(0); + Assert.assertEquals("{$conf:@//site/global/app_root}/conf", mount.getHostMount()); } }
