Apologies for the lack of feedback. Looking at the code I can't find anything that is wrong. My bet is that it might be something on your OpenStack deployment, but I don't have the knowledge to diagnose that.
Let's see if some of our rackers can give a hand here. In any case, mind opening a JIRA issue so this doesn't remain unattended and receives the proper attention? Thanks, I. On 13 July 2015 at 12:43, Higginbottom Mark <[email protected]> wrote: > Hi Ignasi, > > Just wondered if there is any update on this topic. Have you managed to > recreate the issue? Is it a problem in my code or is it a bug? > > Thanks, > > Mark. > > -----Original Message----- > From: Higginbottom Mark > Sent: 01 July 2015 15:24 > To: '[email protected]' > Subject: RE: jClouds with https > > > Run time values are injected by Spring: > Code runs with no errors when contacting a http endpoint. > Same construct is used to contact the port 5000 endoint. > > > package com.fujitsu.fs.mh.genericharness.actions; > > import java.util.Properties; > > import org.jclouds.Constants; > import org.jclouds.ContextBuilder; > import org.jclouds.collect.PagedIterable; > import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; > import org.jclouds.openstack.keystone.v2_0.KeystoneApi; > import org.jclouds.openstack.keystone.v2_0.domain.Tenant; > import org.jclouds.openstack.keystone.v2_0.features.TenantApi; > import org.slf4j.Logger; > import org.slf4j.LoggerFactory; > > import com.fujitsu.fs.mh.genericharness.data.RouteBean; > import com.google.common.base.Optional; > import com.google.common.collect.ImmutableSet; > import com.google.inject.Module; > > /** > * > * > * @author HigginbottomM > */ > public class ListTenantsAction implements IAction { > /** > * logger. > */ > private static final Logger LOG = > LoggerFactory.getLogger(ListTenantsAction.class); > > /** > * System independent newline. > */ > public static final String NEWLINE = > System.getProperty("line.separator"); > > /** > * Connection to the Keystone admin endpoint > */ > private KeystoneApi keystoneApi = null; > /** > * Endpoint. > */ > private String endpoint; > > /** > * Provider > */ > private String provider; > > /** > * Sets the route property postEndpoint. > * > * @param endpoint the end point location > */ > public void setEndpoint(String endpoint) { > this.endpoint = endpoint; > } > > /** > * gets the route property endpoint. > * > * @return endpoint the end point location > */ > public String getEndpoint() { > return endpoint; > } > > /** > * gets the service provider > * > * @return provider > */ > public String getProvider() > { > return provider; > } > > /** > * set the provider > * > * @param provider the service provider > */ > public void setProvider(String provider) > { > this.provider = provider; > } > > /** > * This action is > * > * execute method for this action. > * > * @param route > * the route being processed > */ > > public void execute(RouteBean route) > { > LOG.info("Executing ListTenantsAction with routeBean: " + > route.toString() + " and endpoint " + this.endpoint + " provider " + > this.provider); > > keystoneApi = setUpConnection(route); > listTenants(); > } > > public KeystoneApi setUpConnection(RouteBean route) > { > LOG.debug("Setting up connection to " + this.getEndpoint() + > " using " + route.getIdentity() + " and " > + route.getCredential() + " over provider " + > this.getProvider()); > //Accept all certificates > Properties props = new Properties(); > props.put(Constants.PROPERTY_TRUST_ALL_CERTS, "true"); > props.put(Constants.PROPERTY_RELAX_HOSTNAME, "true"); > > Iterable<Module> modules = ImmutableSet.<Module> of(new > SLF4JLoggingModule()); > LOG.debug("Available models=" + modules); > > return > ContextBuilder.newBuilder(this.getProvider()).endpoint(this.getEndpoint()) > .credentials(route.getIdentity(), > route.getCredential()).modules(modules).overrides(props).buildApi(KeystoneApi.class); > } > > private void listTenants() > { > // List all Tenants > > Optional<? extends TenantApi> tenantApiExtension = keystoneApi > .getTenantApi(); > > if (tenantApiExtension.isPresent()) > { > LOG.debug(" TenantApi is present%n"); > > TenantApi tenantApi = tenantApiExtension.get(); > PagedIterable<Tenant> tenants = tenantApi.list(); > if (tenants.concat().isEmpty()) > { > LOG.info(" There are no tenants available"); > } > else > { > LOG.info(" There are " + > tenants.concat().size() + " tenants available"); > for (Tenant tenant : tenants.concat()) > { > LOG.info(" " + tenant.toString()); > } > } > } > else > { > LOG.error(" TenantApi is *not* present%n"); > } > > } > > > } > > > -----Original Message----- > From: Ignasi Barrera [mailto:[email protected]] > Sent: 01 July 2015 15:17 > To: [email protected] > Subject: Re: jClouds with https > > And can you share a minimal part of your code so we can try to reproduce it? > > On 1 July 2015 at 16:10, Higginbottom Mark <[email protected]> > wrote: >> //Accept all certificates >> Properties props = new Properties(); >> props.put(Constants.PROPERTY_TRUST_ALL_CERTS, "true"); >> props.put(Constants.PROPERTY_RELAX_HOSTNAME, "true"); >> >> Iterable<Module> modules = ImmutableSet.<Module> of(new >> SLF4JLoggingModule()); >> LOG.debug("Available models=" + modules); >> >> return >> ContextBuilder.newBuilder(this.getProvider()).endpoint(this.getEndpoin >> t()) >> >> .credentials(route.getIdentity(),route.getCredential()).modules(module >> s).overrides(props).buildApi(KeystoneApi.class); >> >> -----Original Message----- >> From: Ignasi Barrera [mailto:[email protected]] >> Sent: 01 July 2015 15:02 >> To: [email protected] >> Subject: Re: jClouds with https >> >> It is a SSL validation error. could you share how you have configured >> jclouds to deal with SSL? >> >> On 1 July 2015 at 15:59, Higginbottom Mark >> <[email protected]> wrote: >>> Thanks for the help. I have had partial success: >>> >>> I have two endpoints I have to access: >>> >>> https://xxx.xxx.xxx.xxx:5000/v2.0 with a provider of openstack-nova to list >>> servers, flavors, start stop instances etc. This now works perfectly. >>> >>> However, the other endpoint I have to access is: >>> >>> https://xxx.xxx.xxx.xxx:35357/v2.0 with a provider of openstack-keystone to >>> list tenants etc. This endpoint attempts the connection a numer of times >>> before failing with the following error: >>> >>> 2015-07-01 14:11:42,975 DEBUG [main] >>> org.jclouds.http.internal.JavaUrlHttpComman >>> dExecutorService - Sending request 637739138: POST >>> https://xxx.xxx.xxx.xxx:35357/v2 .0/tokens HTTP/1.1 >>> 2015-07-01 14:11:42,975 DEBUG [main] jclouds.wire - >> >>> "{"auth":{"passwordCrede >>> ntials":{"username":"testuser","password":"Xxxxx"},"tenantName":"TENA >>> N >>> T1 >>> "}}" >>> 2015-07-01 14:11:42,975 DEBUG [main] jclouds.headers - >> POST >>> https://10.108.6 .12:35357/v2.0/tokens HTTP/1.1 >>> 2015-07-01 14:11:42,975 DEBUG [main] jclouds.headers - >> Accept: >>> application/j son >>> 2015-07-01 14:11:42,975 DEBUG [main] jclouds.headers - >> >>> Content-Type: applica tion/json >>> 2015-07-01 14:11:42,975 DEBUG [main] jclouds.headers - >> >>> Content-Length: 106 >>> 2015-07-01 14:11:42,991 ERROR [main] >>> org.jclouds.http.handlers.BackoffLimitedRet >>> ryHandler - Cannot retry after server error, command has exceeded >>> retry limit 5 >>> : >>> [method=org.jclouds.openstack.keystone.v2_0.AuthenticationApi.public >>> abstract org.jclouds.openstack.keystone.v2_0.domain.Access >>> org.jclouds.openstack.keystone >>> .v2_0.AuthenticationApi.authenticateWithTenantNameAndCredentials(java. >>> lang.Strin >>> g,org.jclouds.openstack.keystone.v2_0.domain.PasswordCredentials)[TEN >>> A NT1, Password Credentials{username=testuser, password=*****}], >>> request=POST https://xxx.xxx.xxx.xxx :35357/v2.0/tokens HTTP/1.1] >>> Exception in thread "main" org.jclouds.http.HttpResponseException: >>> sun.security. >>> validator.ValidatorException: PKIX path building failed: >>> sun.security.provider.c >>> ertpath.SunCertPathBuilderException: unable to find valid >>> certification path to requested target connecting to POST >>> https://xxx.xxx.xxx.xxx:35357/v2.0/tokens HTTP/1 >>> .1 >>> at >>> org.jclouds.http.internal.BaseHttpCommandExecutorService.invoke(BaseH >>> ttpCommandExecutorService.java:113) >>> at >>> org.jclouds.rest.internal.InvokeHttpMethod.invoke(InvokeHttpMethod.ja >>> va:90) >>> at >>> org.jclouds.rest.internal.InvokeHttpMethod.apply(InvokeHttpMethod.jav >>> a:73) >>> at >>> org.jclouds.rest.internal.InvokeHttpMethod.apply(InvokeHttpMethod.jav >>> a:44) >>> at >>> org.jclouds.rest.internal.DelegatesToInvocationFunction.handle(Delega >>> tesToInvocationFunction.java:156) >>> at >>> org.jclouds.rest.internal.DelegatesToInvocationFunction.invoke(Delega >>> tesToInvocationFunction.java:123) >>> at >>> com.sun.proxy.$Proxy55.authenticateWithTenantNameAndCredentials(Unkno >>> wn Source) >>> at >>> org.jclouds.openstack.keystone.v2_0.functions.AuthenticatePasswordCre >>> dentials.authenticateWithTenantName(AuthenticatePasswordCredentials.java:43) >>> at >>> org.jclouds.openstack.keystone.v2_0.functions.AuthenticatePasswordCre >>> dentials.authenticateWithTenantName(AuthenticatePasswordCredentials.java:31) >>> at >>> org.jclouds.openstack.keystone.v2_0.functions.internal.BaseAuthentica >>> tor.apply(BaseAuthenticator.java:79) >>> at >>> org.jclouds.openstack.keystone.v2_0.functions.internal.BaseAuthentica >>> tor.apply(BaseAuthenticator.java:36) >>> at >>> com.google.common.cache.CacheLoader$FunctionToCacheLoader.load(CacheL >>> oader.java:148) >>> at >>> com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(L >>> ocalCache.java:3524) >>> at >>> com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2 >>> 317) >>> at >>> com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache >>> .java:2280) >>> at >>> com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2195) >>> at com.google.common.cache.LocalCache.get(LocalCache.java:3934) >>> at >>> com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3938) >>> at >>> com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.j >>> ava:4821) >>> at >>> com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(Loc >>> alCache.java:4827) >>> at >>> org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModu >>> le$2.get(KeystoneAuthenticationModule.java:234) >>> at >>> org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModu >>> le$2.get(KeystoneAuthenticationModule.java:231) >>> at >>> org.jclouds.openstack.keystone.v2_0.suppliers.LocationIdToURIFromAcce >>> ssForTypeAndVersion.get(LocationIdToURIFromAccessForTypeAndVersion.java:94) >>> at >>> org.jclouds.openstack.keystone.v2_0.suppliers.LocationIdToURIFromAcce >>> ssForTypeAndVersion.get(LocationIdToURIFromAccessForTypeAndVersion.java:54) >>> at org.jclouds.util.Suppliers2$1.get(Suppliers2.java:35) >>> at org.jclouds.util.Suppliers2$5.get(Suppliers2.java:110) >>> at org.jclouds.util.Suppliers2$4.get(Suppliers2.java:86) >>> at >>> org.jclouds.rest.internal.RestAnnotationProcessor.getEndpointFor(Rest >>> AnnotationProcessor.java:529) >>> at >>> org.jclouds.rest.internal.RestAnnotationProcessor.findEndpoint(RestAn >>> notationProcessor.java:370) >>> at >>> org.jclouds.rest.internal.RestAnnotationProcessor.apply(RestAnnotatio >>> nProcessor.java:192) >>> at >>> org.jclouds.rest.internal.RestAnnotationProcessor.apply(RestAnnotatio >>> nProcessor.java:129) >>> at >>> org.jclouds.rest.internal.InvokeHttpMethod.toCommand(InvokeHttpMethod >>> .java:188) >>> at >>> org.jclouds.rest.internal.InvokeHttpMethod.invoke(InvokeHttpMethod.ja >>> va:84) >>> at >>> org.jclouds.rest.internal.InvokeHttpMethod.apply(InvokeHttpMethod.jav >>> a:73) >>> at >>> org.jclouds.rest.internal.InvokeHttpMethod.apply(InvokeHttpMethod.jav >>> a:44) >>> at >>> org.jclouds.reflect.FunctionalReflection$FunctionalInvocationHandler. >>> handleInvocation(FunctionalReflection.java:117) >>> at >>> com.google.common.reflect.AbstractInvocationHandler.invoke(AbstractIn >>> vocationHandler.java:87) >>> at com.sun.proxy.$Proxy83.list(Unknown Source) >>> at >>> com.fujitsu.fs.mh.genericharness.actions.ListTenantsAction.listTenant >>> s(ListTenantsAction.java:140) >>> at >>> com.fujitsu.fs.mh.genericharness.actions.ListTenantsAction.execute(Li >>> stTenantsAction.java:113) >>> at >>> com.fujitsu.fs.mh.genericharness.GenericHarnessProcess.executeProcess >>> (GenericHarnessProcess.java:51) >>> at >>> com.fujitsu.fs.mh.genericharness.GenericHarness.start(GenericHarness. >>> java:169) >>> at >>> com.fujitsu.fs.mh.genericharness.GenericHarness.main(GenericHarness.j >>> ava:90) >>> Caused by: javax.net.ssl.SSLHandshakeException: >>> sun.security.validator.Validator >>> Exception: PKIX path building failed: >>> sun.security.provider.certpath.SunCertPath >>> BuilderException: unable to find valid certification path to requested >>> target >>> at sun.security.ssl.Alerts.getSSLException(Unknown Source) >>> at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source) >>> at sun.security.ssl.Handshaker.fatalSE(Unknown Source) >>> at sun.security.ssl.Handshaker.fatalSE(Unknown Source) >>> at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown >>> Source) >>> at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source) >>> at sun.security.ssl.Handshaker.processLoop(Unknown Source) >>> at sun.security.ssl.Handshaker.process_record(Unknown Source) >>> at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source) >>> at >>> sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source >>> ) >>> at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source) >>> at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source) >>> at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown >>> Source) >>> at >>> sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect >>> (Unknown Source) >>> at >>> sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(Unknown >>> Source) >>> at >>> sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown S >>> ource) >>> at >>> sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unk >>> nown Source) >>> at >>> org.jclouds.http.internal.JavaUrlHttpCommandExecutorService.writePayl >>> oadToConnection(JavaUrlHttpCommandExecutorService.java:294) >>> at >>> org.jclouds.http.internal.JavaUrlHttpCommandExecutorService.convert(J >>> avaUrlHttpCommandExecutorService.java:170) >>> at >>> org.jclouds.http.internal.JavaUrlHttpCommandExecutorService.convert(J >>> avaUrlHttpCommandExecutorService.java:64) >>> at >>> org.jclouds.http.internal.BaseHttpCommandExecutorService.invoke(BaseH >>> ttpCommandExecutorService.java:91) >>> ... 42 more >>> Caused by: sun.security.validator.ValidatorException: PKIX path building >>> failed: >>> sun.security.provider.certpath.SunCertPathBuilderException: unable >>> to find vali d certification path to requested target >>> at sun.security.validator.PKIXValidator.doBuild(Unknown Source) >>> at sun.security.validator.PKIXValidator.engineValidate(Unknown >>> Source) >>> at sun.security.validator.Validator.validate(Unknown Source) >>> at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source) >>> at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown >>> Source) >>> at >>> sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Sour >>> ce) >>> ... 59 more >>> Caused by: sun.security.provider.certpath.SunCertPathBuilderException: >>> unable to find valid certification path to requested target >>> at >>> sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Sourc >>> e) >>> at >>> sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown >>> Source) >>> at java.security.cert.CertPathBuilder.build(Unknown Source) >>> ... 65 more >>> >>> >>> Is this a certificate error or a user permission error (or something else >>> entirely)? >>> >>> >>> Thanks >>> >>> Mark. >>> >>> >>> >>> -----Original Message----- >>> From: Ignasi Barrera [mailto:[email protected]] >>> Sent: 29 June 2015 22:00 >>> To: [email protected] >>> Subject: Re: jClouds with https >>> >>> You can also provide a custom SSLContext supplier if you have the >>> certificates and don't want to blindly trust them all. Take a look at this >>> comment: >>> https://issues.apache.org/jira/browse/JCLOUDS-816?focusedCommentId=14 >>> 2 >>> 96666 >>> >>> On 29 June 2015 at 21:08, Rashid Rashidov <[email protected]> wrote: >>>> Hi Mark, >>>> >>>> >>>> >>>> Here is the problem that I had with https endpoints: >>>> >>>> >>>> >>>> I am using jClouds 1.8.1 against OpenStack Juno. My nova endpoint >>>> URL is setup on HTTPS and I don't have server certificate installed. >>>> >>>> >>>> >>>> The native OpenStack clients can not connect to the HTTPS endpoint. >>>> However, the native client has an "--insecure" parameter which let's >>>> me workaround the problem. Unfortunately, I was not able to find >>>> such an option in jclouds. Do you know any workaround of this problem? >>>> >>>> >>>> >>>> And here is the solution provided by Ignasi Barrera: >>>> >>>> >>>> >>>> Try configuring the following properties when creating the context: >>>> >>>> >>>> >>>> Properties overrides = new Properties(); >>>> >>>> overrides.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, "true"); >>>> >>>> overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "true"); >>>> >>>> >>>> >>>> I hope it helps. >>>> >>>> >>>> >>>> Regards, >>>> >>>> Rashid >>>> >>>> >>>> >>>> From: Higginbottom Mark [mailto:[email protected]] >>>> Sent: Monday, June 29, 2015 6:01 PM >>>> To: [email protected] >>>> Subject: jClouds with https >>>> >>>> >>>> >>>> Hi All, >>>> >>>> >>>> >>>> How does jClouds cope with https endpoints. Do I have to set up >>>> anything in the client to make a https connection? >>>> >>>> >>>> >>>> Does anyone have any example code to share? I am trying to connect >>>> to an OpenStack endpoint. >>>> >>>> >>>> >>>> >>>> >>>> >>>> >>>> Thanks for your help. >>>> >>>> >>>> >>>> >>>> >>>> Mark Higginbottom >>>> >>>> >>>> >>>> >>>> Unless otherwise stated, this email has been sent from Fujitsu >>>> Services Limited, from Fujitsu (FTS) Limited, or from Fujitsu >>>> Telecommunications Europe Limited, together "Fujitsu". >>>> >>>> This email is only for the use of its intended recipient. Its >>>> contents are subject to a duty of confidence and may be privileged. >>>> Fujitsu does not guarantee that this email has not been intercepted >>>> and amended or that it is virus-free. >>>> >>>> Fujitsu Services Limited, registered in England No 96056, registered >>>> office >>>> 22 Baker Street, London W1U 3BW. >>>> >>>> Fujitsu (FTS) Limited, registered in England No 03808613, registered >>>> office >>>> 22 Baker Street, London W1U 3BW. >>>> >>>> PFU Imaging Solutions Europe Limited, registered in England No >>>> 1578652, registered office Hayes Park Central, Hayes End Road, >>>> Hayes, Middlesex, UB4 8FE. >>>> >>>> Fujitsu Telecommunications Europe Limited, registered in England No >>>> 2548187, registered office Solihull Parkway, Birmingham Business >>>> Park, Birmingham, >>>> B37 7YU. >>> >>> Unless otherwise stated, this email has been sent from Fujitsu Services >>> Limited, from Fujitsu (FTS) Limited, or from Fujitsu Telecommunications >>> Europe Limited, together "Fujitsu". >>> >>> This email is only for the use of its intended recipient. Its contents are >>> subject to a duty of confidence and may be privileged. Fujitsu does not >>> guarantee that this email has not been intercepted and amended or that it >>> is virus-free. >>> >>> Fujitsu Services Limited, registered in England No 96056, registered office >>> 22 Baker Street, London W1U 3BW. >>> >>> Fujitsu (FTS) Limited, registered in England No 03808613, registered office >>> 22 Baker Street, London W1U 3BW. >>> >>> PFU Imaging Solutions Europe Limited, registered in England No 1578652, >>> registered office Hayes Park Central, Hayes End Road, Hayes, Middlesex, UB4 >>> 8FE. >>> >>> Fujitsu Telecommunications Europe Limited, registered in England No >>> 2548187, registered office Solihull Parkway, Birmingham Business Park, >>> Birmingham, B37 7YU. >> >> Unless otherwise stated, this email has been sent from Fujitsu Services >> Limited, from Fujitsu (FTS) Limited, or from Fujitsu Telecommunications >> Europe Limited, together "Fujitsu". >> >> This email is only for the use of its intended recipient. Its contents are >> subject to a duty of confidence and may be privileged. Fujitsu does not >> guarantee that this email has not been intercepted and amended or that it is >> virus-free. >> >> Fujitsu Services Limited, registered in England No 96056, registered office >> 22 Baker Street, London W1U 3BW. >> >> Fujitsu (FTS) Limited, registered in England No 03808613, registered office >> 22 Baker Street, London W1U 3BW. >> >> PFU Imaging Solutions Europe Limited, registered in England No 1578652, >> registered office Hayes Park Central, Hayes End Road, Hayes, Middlesex, UB4 >> 8FE. >> >> Fujitsu Telecommunications Europe Limited, registered in England No 2548187, >> registered office Solihull Parkway, Birmingham Business Park, Birmingham, >> B37 7YU. > > Unless otherwise stated, this email has been sent from Fujitsu Services > Limited, from Fujitsu (FTS) Limited, or from Fujitsu Telecommunications > Europe Limited, together "Fujitsu". > > This email is only for the use of its intended recipient. Its contents are > subject to a duty of confidence and may be privileged. Fujitsu does not > guarantee that this email has not been intercepted and amended or that it is > virus-free. > > Fujitsu Services Limited, registered in England No 96056, registered office > 22 Baker Street, London W1U 3BW. > > Fujitsu (FTS) Limited, registered in England No 03808613, registered office > 22 Baker Street, London W1U 3BW. > > PFU Imaging Solutions Europe Limited, registered in England No 1578652, > registered office Hayes Park Central, Hayes End Road, Hayes, Middlesex, UB4 > 8FE. > > Fujitsu Telecommunications Europe Limited, registered in England No 2548187, > registered office Solihull Parkway, Birmingham Business Park, Birmingham, B37 > 7YU.
