1

So I've been following this pull request to integrate redis onto jhipster generator: https://github.com/jhipster/generator-jhipster/pull/10057/commits/cd2f2865d35dfd77624dd3a38ed32822e895539d

Here's what I configured:

ApplicationProperties.java:

package com.xxx.xxx.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

import io.github.jhipster.config.JHipsterDefaults;

/**
 * <p>
 * Properties are configured in the {@code application.yml} file.
 * See {@link io.github.jhipster.config.JHipsterProperties} for a good example.
 */
@ConfigurationProperties(prefix = "application", ignoreUnknownFields = false)
public class ApplicationProperties {

     private final Redis redis = new Redis();

     public Redis getRedis() {
          return redis;
      }

      public static class Redis {
          private String server = JHipsterDefaults.Cache.Redis.server;
          private int expiration = JHipsterDefaults.Cache.Redis.expiration;

          public String getServer() {
              return server;
          }

          public void setServer(String server) {
              this.server = server;
          }

          public int getExpiration() {
              return expiration;
          }

          public void setExpiration(int expiration) {
              this.expiration = expiration;
          }
      }

}

CacheConfiguration.java.ejs:

<%_ if (cacheProvider === 'redis') { _%>
        private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration;

            public CacheConfiguration(JHipsterProperties jHipsterProperties, ApplicationProperties applicationProperties) {
                MutableConfiguration<Object, Object> jcacheConfig = new MutableConfiguration<>();
                Config config = new Config();
                config.useSingleServer()
                    .setAddress(applicationProperties.getRedis().getServer())
                    .setSubscriptionConnectionMinimumIdleSize(1)
                    .setSubscriptionConnectionPoolSize(50)
                    .setConnectionMinimumIdleSize(24)
                    .setConnectionPoolSize(64)
                    .setDnsMonitoringInterval(5000)
                    .setIdleConnectionTimeout(10000)
                    .setConnectTimeout(10000)
                    .setTimeout(3000)
                    .setRetryAttempts(3)
                    .setRetryInterval(1500)
                    .setDatabase(0)
                    .setPassword(null)
                    .setSubscriptionsPerConnection(5)
                    .setClientName(null)
                    .setSslEnableEndpointIdentification(true)
                    .setSslProvider(SslProvider.JDK)
                    .setSslTruststore(null)
                    .setSslTruststorePassword(null)
                    .setSslKeystore(null)
                    .setSslKeystorePassword(null)
                    .setPingConnectionInterval(0)
                    .setKeepAlive(false)
                    .setTcpNoDelay(false);
                jcacheConfig.setStatisticsEnabled(true);
                jcacheConfig.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.SECONDS, applicationProperties.getRedis().getExpiration())));
                jcacheConfiguration = RedissonConfiguration.fromInstance(Redisson.create(config), jcacheConfig);
            }


            <%_ if (enableHibernateCache) { _%>
            @Bean
            public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(javax.cache.CacheManager cm) {
                return hibernateProperties -> hibernateProperties.put(ConfigSettings.CACHE_MANAGER, cm);
            }
            <%_ } _%>

            @Bean
            public JCacheManagerCustomizer cacheManagerCustomizer() {
                return cm -> {
                    <%_ if (!skipUserManagement || (authenticationType === 'oauth2' && databaseType !== 'no')) { _%>
                    createCache(cm, <%=packageName%>.repository<% if (reactive) { %>.reactive<% } %>.UserRepository.USERS_BY_LOGIN_CACHE);
                    createCache(cm, <%=packageName%>.repository<% if (reactive) { %>.reactive<% } %>.UserRepository.USERS_BY_EMAIL_CACHE);
                        <%_ if (enableHibernateCache) { _%>
                    createCache(cm, <%=packageName%>.domain.<%= asEntity('User') %>.class.getName());
                    createCache(cm, <%=packageName%>.domain.Authority.class.getName());
                    createCache(cm, <%=packageName%>.domain.<%= asEntity('User') %>.class.getName() + ".authorities");
                            <%_ if (authenticationType === 'session') { _%>
                    createCache(cm, <%=packageName%>.domain.PersistentToken.class.getName());
                    createCache(cm, <%=packageName%>.domain.<%= asEntity('User') %>.class.getName() + ".persistentTokens");
                            <%_ } _%>
                        <%_ } _%>
                    <%_ } _%>
                    // jhipster-needle-redis-add-entry
                };
            }

            private void createCache(javax.cache.CacheManager cm, String cacheName) {
                javax.cache.Cache<Object, Object> cache = cm.getCache(cacheName);
                if (cache != null) {
                    cm.destroyCache(cacheName);
                }
                cm.createCache(cacheName, jcacheConfiguration);
            }
        <%_ } _%>

application.yml:

# ===================================================================
# Application specific properties
# Add your own application properties here, see the ApplicationProperties class
# to have type-safe configuration, like in the JHipsterProperties above
#
# More documentation is available at:
# https://www.jhipster.tech/common-application-properties/
# ===================================================================

application:
application.redis.server: redis://localhost:6379
application.redis.expiration: 300

My final problem is in ApplicationProperties.java, specifically:

private String server = JHipsterDefaults.Cache.Redis.server;
private int expiration = JHipsterDefaults.Cache.Redis.expiration;

which states: Redis cannot be resolved or is not a fieldJava:

[ERROR]   symbol:   variable Redis
[ERROR]   location: interface io.github.jhipster.config.JHipsterDefaults.Cache

UPDATE: invalid field resolved-- Solution:

private String server = "redis://localhost:6379";
private int expiration = 300;

ISSUE NOW (element [] unbound):

***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target [Bindable@77574136 type = io.github.jhipster.config.JHipsterProperties, value = 'provided', annotations = array<Annotation>[@org.springframework.boot.context.properties.ConfigurationProperties(value=jhipster, prefix=jhipster, ignoreInvalidFields=false, ignoreUnknownFields=false)]] failed:

    Property: jhipster.cache.redis.expiration
    Value: 3600
    Origin: class path resource [config/application-dev.yml]:101:19
    Reason: The elements [jhipster.cache.redis.expiration] were left unbound.

Action:

Update your application's configuration

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  13.591 s

UPDATE: element [] unbound resolved --Solution:

application:
    redis: # Redis configuration
      expiration: 300 # time
jhipster:
  # CORS is disabled by default on microservices, as you should access them through a gateway.
  # If you want to enable it, please uncomment the configuration below.
  # cors:
  #     allowed-origins: "*"
  #     allowed-methods: "*"
  #     allowed-headers: "*"
  #     exposed-headers: "Authorization,Link,X-Total-Count"
  #     allow-credentials: true
  #     max-age: 1800
  mail: # specific JHipster mail property, for standard properties see MailProperties
    from: appname@localhost
    base-url: http://127.0.0.1:8081
  metrics:
    logs: # Reports metrics in the logs
      enabled: false
      report-frequency: 60 # in seconds
  logging:
    use-json-format: false # By default, logs are not in Json format
    logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration
      enabled: false
      host: localhost
      port: 5000
      queue-size: 512

  # ===================================================================
  # Application specific properties
  # Add your own application properties here, see the ApplicationProperties class
  # to have type-safe configuration, like in the JHipsterProperties above
  #
  # More documentation is available at:
  # https://www.jhipster.tech/common-application-properties/
  # ===================================================================

application:
    redis:
      expiration: 300

More Detailed StackTrace:

2019-07-17 10:58:35.205 ERROR 87330 --- [  restartedMain] o.s.boot.SpringApplication               : Application run failed

org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'servletEndpointRegistrar' defined in class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/web/ServletEndpointManagementContextConfiguration$WebMvcServletEndpointManagementContextConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar]: Factory method 'servletEndpointRegistrar' threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cachesEndpoint' defined in class path resource [org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.class]: Unsatisfied dependency expressed through method 'cachesEndpoint' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Unsatisfied dependency expressed through method 'cacheManager' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jCacheCacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.cache.CacheManager]: Factory method 'jCacheCacheManager' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheConfiguration' defined in file [../config/CacheConfiguration.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.package.project.config.CacheConfiguration$$EnhancerBySpringCGLIB$$2ce84f38]: Constructor threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379

Caused by: java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'servletEndpointRegistrar' defined in class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/web/ServletEndpointManagementContextConfiguration$WebMvcServletEndpointManagementContextConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar]: Factory method 'servletEndpointRegistrar' threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cachesEndpoint' defined in class path resource [org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.class]: Unsatisfied dependency expressed through method 'cachesEndpoint' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Unsatisfied dependency expressed through method 'cacheManager' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jCacheCacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.cache.CacheManager]: Factory method 'jCacheCacheManager' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheConfiguration' defined in file [../config/CacheConfiguration.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.package.project.config.CacheConfiguration$$EnhancerBySpringCGLIB$$2ce84f38]: Constructor threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'servletEndpointRegistrar' defined in class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/web/ServletEndpointManagementContextConfiguration$WebMvcServletEndpointManagementContextConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar]: Factory method 'servletEndpointRegistrar' threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cachesEndpoint' defined in class path resource [org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.class]: Unsatisfied dependency expressed through method 'cachesEndpoint' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Unsatisfied dependency expressed through method 'cacheManager' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jCacheCacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.cache.CacheManager]: Factory method 'jCacheCacheManager' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheConfiguration' defined in file [../config/CacheConfiguration.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.package.project.config.CacheConfiguration$$EnhancerBySpringCGLIB$$2ce84f38]: Constructor threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar]: Factory method 'servletEndpointRegistrar' threw exception; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cachesEndpoint' defined in class path resource [org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.class]: Unsatisfied dependency expressed through method 'cachesEndpoint' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Unsatisfied dependency expressed through method 'cacheManager' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jCacheCacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.cache.CacheManager]: Factory method 'jCacheCacheManager' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheConfiguration' defined in file [../config/CacheConfiguration.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.package.project.config.CacheConfiguration$$EnhancerBySpringCGLIB$$2ce84f38]: Constructor threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cachesEndpoint' defined in class path resource [org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.class]: Unsatisfied dependency expressed through method 'cachesEndpoint' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Unsatisfied dependency expressed through method 'cacheManager' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jCacheCacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.cache.CacheManager]: Factory method 'jCacheCacheManager' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheConfiguration' defined in file [../config/CacheConfiguration.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.package.project.config.CacheConfiguration$$EnhancerBySpringCGLIB$$2ce84f38]: Constructor threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Unsatisfied dependency expressed through method 'cacheManager' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jCacheCacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.cache.CacheManager]: Factory method 'jCacheCacheManager' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheConfiguration' defined in file [../config/CacheConfiguration.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.package.project.config.CacheConfiguration$$EnhancerBySpringCGLIB$$2ce84f38]: Constructor threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jCacheCacheManager' defined in class path resource [org/springframework/boot/autoconfigure/cache/JCacheCacheConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.cache.CacheManager]: Factory method 'jCacheCacheManager' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheConfiguration' defined in file [../config/CacheConfiguration.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.package.project.config.CacheConfiguration$$EnhancerBySpringCGLIB$$2ce84f38]: Constructor threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.cache.CacheManager]: Factory method 'jCacheCacheManager' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheConfiguration' defined in file [../config/CacheConfiguration.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.package.project.config.CacheConfiguration$$EnhancerBySpringCGLIB$$2ce84f38]: Constructor threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheConfiguration' defined in file [../config/CacheConfiguration.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.package.project.config.CacheConfiguration$$EnhancerBySpringCGLIB$$2ce84f38]: Constructor threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.package.project.config.CacheConfiguration$$EnhancerBySpringCGLIB$$2ce84f38]: Constructor threw exception; nested exception is org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379

Caused by: org.redisson.client.RedisConnectionException: Unable to connect to Redis server: localhost/127.0.0.1:6379

Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: localhost/127.0.0.1:6379

Caused by: java.net.ConnectException: Connection refused
    ... 12 common frames omitted

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  17.977 s
[INFO] Finished at: 2019-07-17T10:58:36-07:00
[INFO] ------------------------------------------------------------------------

FINAL UPDATE: REDIS INTEGRATED SUCCESSFULLY

redis-server
./mvnw
jche
  • 129
  • 2
  • 16
  • "Unable to connect to Redis server: localhost/127.0.0.1:6379" means you did not start redis server. It's the same as for your other question about postgresql, you can also start it from docker using src/main/docker/redis.yml docker file. – Gaël Marziou Jul 17 '19 at 09:28
  • Although my postgresql server wasn't started, I was able to connect to localhost. But this time, the redis error triggered spring beans errors and build failure. – jche Jul 17 '19 at 17:17
  • Mind sharing how you learn efficiently? – jche Jul 17 '19 at 19:45
  • Read official docs, books, online tutorials about the major components of the technology stack used by JHipster: spring, spring boot, spring-security, JPA, Hibernate, docker, liquibase, h2, posgresql, mvn, etc.... for backend and angular, npm, webpack for frontend. After few weeks, you should be more comfortable. – Gaël Marziou Jul 17 '19 at 20:29
  • Alright, i'll do that, appreciate your advices. – jche Jul 17 '19 at 20:36

1 Answers1

2

The message says The elements [jhipster.cache.redis.expiration] were left unbound because that property does not exist in JhipsterProperties. You should remove that value and configure application.redis.expiration instead

Jon Ruddell
  • 6,244
  • 1
  • 22
  • 40
  • Do I remove jhipster.cache.redis.expiration altogether and add application.redis.expiration? – jche Jul 17 '19 at 00:25
  • Yes, only add it if you need to customize it for that profile – Jon Ruddell Jul 17 '19 at 00:27
  • I posted a section of my application-dev.yml above. Could you please check if I'm structuring it correctly? because i'm getting spring beans errors after adding application:redis:expiration:300 – jche Jul 17 '19 at 04:10
  • The new error is because you don't have redis running and connectable on 127.0.0.1:6379 – Jon Ruddell Jul 17 '19 at 16:28
  • What might have caused spring beans error and build failure? I encountered this error previously when I didn't start my postgresql server, but my application was running fine. But this time, it led to complete build failure which prevents the application from running. – jche Jul 17 '19 at 17:20
  • I posted a more detailed stacktrace if you don't mind going over it. – jche Jul 17 '19 at 18:09
  • If the answer is also because I did not start redis server, then why was I able to connect to localhost without starting a database server? Is there a difference between database and cache server in terms of running the application? – jche Jul 17 '19 at 18:21
  • I don't know which database you chose, but if it was the default (H2), then it is an embedded database. In production, you will have to deploy externally the database you chose – Jon Ruddell Jul 17 '19 at 18:50
  • Ok, so the "updated" stacktrace is also caused by not starting redis server? Why are there errors from org.springframework.beans.factory? – jche Jul 17 '19 at 19:44
  • 1
    Those errors appear because the other classes depend on the cache configuration beans, which can't load correctly since the connection to redis fails. You can see the actual error at the end of each line – Jon Ruddell Jul 17 '19 at 20:06
  • Appreciate your help, I have a better understanding of what these errors are telling me now. – jche Jul 17 '19 at 20:41