Skip to content

Commit

Permalink
option function - chat
Browse files Browse the repository at this point in the history
  • Loading branch information
ntut-ben committed Nov 9, 2019
1 parent 80ee9d5 commit e3571fd
Show file tree
Hide file tree
Showing 141 changed files with 291 additions and 13 deletions.
1 change: 1 addition & 0 deletions .settings/org.eclipse.jdt.core.prefs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
Expand Down
26 changes: 17 additions & 9 deletions .settings/org.eclipse.wst.common.component
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">




<wb-module deploy-name="git_ezfit-0.0.1-SNAPSHOT">




<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>




<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>




<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>




<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/resources"/>


<property name="java-output-path" value="/ezfit/target/classes"/>

<property name="context-root" value="git_ezfit"/>




</wb-module>




</project-modules>
26 changes: 25 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
<hibernate.version>5.4.6.Final</hibernate.version>
</properties>





<dependencies>

<!-- 動態網頁 -->
Expand Down Expand Up @@ -55,6 +59,16 @@
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Hibernate Framewrok -->
<dependency>
<groupId>org.hibernate</groupId>
Expand Down Expand Up @@ -113,8 +127,18 @@
<artifactId>json</artifactId>
<version>20190722</version>
</dependency>
</dependencies>


<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.29</version>
</dependency>

<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.8.1</version>
</dependency>
</dependencies>
</project>
20 changes: 20 additions & 0 deletions src/main/java/chat/component/CacheManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package chat.component;

public class CacheManager {

public static void put(String cacheName, String string, String sessionId) {
// TODO Auto-generated method stub

}

public static boolean containsKey(String cacheName, String string) {
// TODO Auto-generated method stub
return false;
}

public static void remove(String cacheName, String string) {
// TODO Auto-generated method stub

}

}
13 changes: 13 additions & 0 deletions src/main/java/chat/handler/CacheConstant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package chat.handler;

public class CacheConstant {

private CacheConstant() {
}

/**
* websocket用戶accountId
*/
public static final String WEBSOCKET_ACCOUNT = "websocket_account";

}
13 changes: 13 additions & 0 deletions src/main/java/chat/handler/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package chat.handler;

public class Constants {
/**
* SessionId
*/
public static final String SESSIONID = "sessionid";

/**
* Session對象Key, 用戶id
*/
public static final String SKEY_ACCOUNT_ID = "accountId";
}
37 changes: 37 additions & 0 deletions src/main/java/chat/handler/HttpSessionIdHandshakeInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package chat.handler;

import java.util.Map;
import javax.servlet.http.HttpSession;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;


public class HttpSessionIdHandshakeInterceptor extends HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
// 解決The extension [x-webkit-deflate-frame] is not supported問題
if (request.getHeaders().containsKey("Sec-WebSocket-Extensions")) {
request.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate");
}
// 檢查session的值是否存在
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession(false);
String accountId = (String) session.getAttribute(Constants.SKEY_ACCOUNT_ID);
// 把session和accountId存放起來
attributes.put(Constants.SESSIONID, session.getId());
attributes.put(Constants.SKEY_ACCOUNT_ID, accountId);
}
return super.beforeHandshake(request, response, wsHandler, attributes);
}

@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Exception ex) {
super.afterHandshake(request, response, wsHandler, ex);
}
}
61 changes: 61 additions & 0 deletions src/main/java/chat/handler/PresenceChannelInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package chat.handler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;

import chat.component.CacheManager;

public class PresenceChannelInterceptor implements ChannelInterceptor {
private static final Logger logger = LoggerFactory.getLogger(PresenceChannelInterceptor.class);

@Override
public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
StompHeaderAccessor sha = StompHeaderAccessor.wrap(message);
// ignore non-STOMP messages like heartbeat messages
if (sha.getCommand() == null) {
return;
}
// 這裏的sessionId和accountId對應HttpSessionIdHandshakeInterceptor攔截器的存放key
String sessionId = sha.getSessionAttributes().get(Constants.SESSIONID).toString();
String accountId = sha.getSessionAttributes().get(Constants.SKEY_ACCOUNT_ID).toString();
// 判斷客戶端的連接狀態
switch (sha.getCommand()) {
case CONNECT:
connect(sessionId, accountId);
break;
case CONNECTED:
break;
case DISCONNECT:
disconnect(sessionId, accountId, sha);
break;
default:
break;
}
}

// 連接成功
private void connect(String sessionId, String accountId) {
logger.debug(" STOMP Connect [sessionId: " + sessionId + "]");
// 存放至ehcache
String cacheName = CacheConstant.WEBSOCKET_ACCOUNT;
// 若在多個瀏覽器登錄,直接覆蓋保存
CacheManager.put(cacheName, cacheName + accountId, sessionId);
}

// 斷開連接
private void disconnect(String sessionId, String accountId, StompHeaderAccessor sha) {
logger.debug("STOMP Disconnect [sessionId: " + sessionId + "]");
sha.getSessionAttributes().remove(Constants.SESSIONID);
sha.getSessionAttributes().remove(Constants.SKEY_ACCOUNT_ID);
// ehcache移除
String cacheName = CacheConstant.WEBSOCKET_ACCOUNT;
if (CacheManager.containsKey(cacheName, cacheName + accountId)) {
CacheManager.remove(cacheName, cacheName + accountId);
}

}
}
2 changes: 1 addition & 1 deletion src/main/java/config/WebAppInitializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServlet
@Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return new Class<?>[] { RootAppConfig.class };
return new Class<?>[] { RootAppConfig.class, WebSocketConfig.class };
}

@Override
Expand Down
77 changes: 77 additions & 0 deletions src/main/java/config/WebSocketConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;

import chat.handler.HttpSessionIdHandshakeInterceptor;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

/**
* 服務器要監聽的端口,message會從這裏進來,要對這裏加一個Handler 這樣在網頁中就可以通過websocket連接上服務了
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
// 註冊stomp的節點,映射到指定的url,並指定使用sockjs協議
stompEndpointRegistry.addEndpoint("/contactChatSocket").withSockJS()
.setInterceptors(httpSessionIdHandshakeInterceptor());
;
}

// 配置消息代理
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// queue、topic、user代理
registry.enableSimpleBroker("/queue", "/topic", "/user");
registry.setUserDestinationPrefix("/user/");
}

/**
* 消息傳輸參數配置
*/
@Override
public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
registry.setMessageSizeLimit(8192) // 設置消息字節數大小
.setSendBufferSizeLimit(8192)// 設置消息緩存大小
.setSendTimeLimit(10000); // 設置消息發送時間限制毫秒
}

/**
* 輸入通道參數設置
*/
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.taskExecutor().corePoolSize(4) // 設置消息輸入通道的線程池線程數
.maxPoolSize(8)// 最大線程數
.keepAliveSeconds(60);// 線程活動時間
registration.interceptors(presenceChannelInterceptor());
}

/**
* 輸出通道參數設置
*/
@Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.taskExecutor().corePoolSize(4).maxPoolSize(8);
registration.interceptors(presenceChannelInterceptor());
}

@Bean
public HttpSessionIdHandshakeInterceptor httpSessionIdHandshakeInterceptor() {
return new HttpSessionIdHandshakeInterceptor();
}

@Bean
public PresenceChannelInterceptor presenceChannelInterceptor() {
return new PresenceChannelInterceptor();
}

}
Binary file modified target/classes/Recipe/controller/recipeController.class
Binary file not shown.
Binary file modified target/classes/Recipe/model/BoardBean.class
Binary file not shown.
Binary file modified target/classes/Recipe/model/FollowedRecipeBean.class
Binary file not shown.
Binary file modified target/classes/Recipe/model/GoodBean.class
Binary file not shown.
Binary file modified target/classes/Recipe/model/KeyWordBean.class
Binary file not shown.
Binary file modified target/classes/Recipe/model/MateralBean.class
Binary file not shown.
Binary file modified target/classes/Recipe/model/MethodBean.class
Binary file not shown.
Binary file modified target/classes/Recipe/model/RecipeBean.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/BoardDao.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/FollowedRecipeDao.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/GoodDao.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/Impl/BoardDao_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/Impl/FollowedRecipeDao_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/Impl/GoodDao_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/Impl/KeyWordDao_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/Impl/MateralDao_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/Impl/MethodDao_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/Impl/RecipeDao_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/KeyWordDao.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/MateralDao.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/MethodDao.class
Binary file not shown.
Binary file modified target/classes/Recipe/repository/RecipeDao.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/BoardService.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/FollowedRecipeService.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/GoodService.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/Impl/BoardService_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/Impl/FollowedRecipeService_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/Impl/GoodService_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/Impl/KeyWordService_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/Impl/MateralService_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/Impl/MethodService_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/Impl/RecipeService_Impl.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/KeyWordService.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/MateralService.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/MethodService.class
Binary file not shown.
Binary file modified target/classes/Recipe/service/RecipeService.class
Binary file not shown.
Binary file modified target/classes/_00/filter/ServiceController.class
Binary file not shown.
Binary file modified target/classes/_00/init/web/CreateSessionFactoryListener.class
Binary file not shown.
Binary file modified target/classes/_00/utils/DateYearTime.class
Binary file not shown.
Binary file modified target/classes/_00/utils/HibernateProxyTypeAdapter$1.class
Binary file not shown.
Binary file modified target/classes/_00/utils/HibernateProxyTypeAdapter.class
Binary file not shown.
Binary file modified target/classes/_00/utils/SystemUtils2018.class
Binary file not shown.
Binary file modified target/classes/_00/utils/ToJson$1.class
Binary file not shown.
Binary file modified target/classes/_00/utils/ToJson.class
Binary file not shown.
Binary file modified target/classes/_99/HashTest.class
Binary file not shown.
Binary file added target/classes/chat/component/CacheManager.class
Binary file not shown.
Binary file added target/classes/chat/handler/CacheConstant.class
Binary file not shown.
Binary file added target/classes/chat/handler/Constants.class
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified target/classes/config/RootAppConfig.class
Binary file not shown.
Binary file modified target/classes/config/WebAppConfig.class
Binary file not shown.
Binary file modified target/classes/config/WebAppInitializer.class
Binary file not shown.
Binary file added target/classes/config/WebSocketConfig.class
Binary file not shown.
Binary file modified target/classes/createAccount/SendEmail$1.class
Binary file not shown.
Binary file modified target/classes/createAccount/SendEmail$2.class
Binary file not shown.
Binary file modified target/classes/createAccount/SendEmail.class
Binary file not shown.
Binary file modified target/classes/createAccount/model/CodeBean.class
Binary file not shown.
Binary file modified target/classes/createAccount/model/EncrypAES.class
Binary file not shown.
Binary file modified target/classes/createAccount/model/MemberBean.class
Binary file not shown.
Binary file modified target/classes/createAccount/repository/CodeDao.class
Binary file not shown.
Binary file modified target/classes/createAccount/repository/CodeDaoImpl.class
Binary file not shown.
Binary file modified target/classes/createAccount/repository/MemberDao.class
Binary file not shown.
Binary file modified target/classes/createAccount/repository/MemberDaoImpl.class
Binary file not shown.
Binary file modified target/classes/createAccount/service/CodeService.class
Binary file not shown.
Binary file modified target/classes/createAccount/service/Impl/CodeServiceImpl.class
Binary file not shown.
Binary file modified target/classes/createAccount/service/Impl/MemberServiceImpl.class
Binary file not shown.
Binary file modified target/classes/createAccount/service/MemberService.class
Binary file not shown.
Binary file modified target/classes/login/controller/Member.class
Binary file not shown.
Binary file modified target/classes/login/controller/VerifyRecaptcha.class
Binary file not shown.
Binary file modified target/classes/login/filter/FindUserPassword.class
Binary file not shown.
Binary file modified target/classes/login/filter/LoginCheckingFilter.class
Binary file not shown.
Binary file modified target/classes/login/model/LogoutBean.class
Binary file not shown.
Binary file modified target/classes/login/service/Impl/LoginServiceImpl.class
Binary file not shown.
Binary file modified target/classes/login/service/LoginService.class
Binary file not shown.
Binary file modified target/classes/shopping/CreateTable.class
Binary file not shown.
Binary file modified target/classes/shopping/HelloWorld.class
Binary file not shown.
Binary file modified target/classes/shopping/controller/Mall.class
Binary file not shown.
Binary file modified target/classes/shopping/model/CartItem.class
Binary file not shown.
Binary file modified target/classes/shopping/model/CuisineProduct.class
Binary file not shown.
Binary file modified target/classes/shopping/model/GroupBuyBean.class
Binary file not shown.
Binary file modified target/classes/shopping/model/IngredientProduct.class
Binary file not shown.
Binary file modified target/classes/shopping/model/OrderBean.class
Binary file not shown.
Binary file modified target/classes/shopping/model/OrderItemBean.class
Binary file not shown.
Binary file modified target/classes/shopping/model/OrderPlaneItem.class
Binary file not shown.
Binary file modified target/classes/shopping/model/PlaneItem.class
Binary file not shown.
Binary file modified target/classes/shopping/model/PlaneProduct.class
Binary file not shown.
Binary file modified target/classes/shopping/model/Product.class
Binary file not shown.
Binary file modified target/classes/shopping/model/ProductCategory.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/CartItemDao.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/CuisineProductDao.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/GroupBuyDao.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/IngredientProductDao.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/OrderDao.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/OrderItemDao.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/OrderItemService.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/PlaneProductDao.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/ProductCategoryDao.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/ProductDao.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/impl/CartItemDaoImpl.class
Binary file not shown.
Binary file not shown.
Binary file modified target/classes/shopping/repository/impl/GroupBuyDaoImpl.class
Binary file not shown.
Binary file not shown.
Binary file modified target/classes/shopping/repository/impl/OrderDaoImpl.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/impl/OrderItemDaoImpl.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/impl/PlaneItemDaoImpl.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/impl/PlaneProductDaoImpl.class
Binary file not shown.
Binary file not shown.
Binary file modified target/classes/shopping/repository/impl/ProductDaoImpl.class
Binary file not shown.
Binary file modified target/classes/shopping/repository/planeItemDao.class
Binary file not shown.
Binary file modified target/classes/shopping/service/CartItemService.class
Binary file not shown.
Binary file modified target/classes/shopping/service/CuisineProductService.class
Binary file not shown.
Binary file modified target/classes/shopping/service/GroupBuyService.class
Binary file not shown.
Binary file modified target/classes/shopping/service/IngredientProductService.class
Binary file not shown.
Binary file modified target/classes/shopping/service/OrderService.class
Binary file not shown.
Binary file modified target/classes/shopping/service/PlaneItemService.class
Binary file not shown.
Binary file modified target/classes/shopping/service/PlaneProductService.class
Binary file not shown.
Binary file modified target/classes/shopping/service/ProductCategoryService.class
Binary file not shown.
Binary file modified target/classes/shopping/service/ProductService.class
Binary file not shown.
Binary file modified target/classes/shopping/service/impl/CartItemServiceImpl.class
Binary file not shown.
Binary file not shown.
Binary file modified target/classes/shopping/service/impl/GroupBuyServiceImpl.class
Binary file not shown.
Binary file not shown.
Binary file modified target/classes/shopping/service/impl/OrderItemServiceImpl.class
Binary file not shown.
Binary file modified target/classes/shopping/service/impl/OrderServiceImpl.class
Binary file not shown.
Binary file modified target/classes/shopping/service/impl/PlaneItemServiceImpl.class
Binary file not shown.
Binary file modified target/classes/shopping/service/impl/PlaneProductServiceImpl.class
Binary file not shown.
Binary file not shown.
Binary file modified target/classes/shopping/service/impl/ProductServiceImpl.class
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#Generated by Maven Integration for Eclipse
#Fri Nov 08 17:32:28 CST 2019
#Fri Nov 08 20:49:24 CST 2019
m2e.projectLocation=C\:\\_JSP\\workspaceJDBC\\ezfit
m2e.projectName=ezfit
groupId=ntut.edu.com.java012
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
<hibernate.version>5.4.6.Final</hibernate.version>
</properties>





<dependencies>

<!-- 動態網頁 -->
Expand Down Expand Up @@ -55,6 +59,16 @@
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Hibernate Framewrok -->
<dependency>
<groupId>org.hibernate</groupId>
Expand Down Expand Up @@ -113,8 +127,18 @@
<artifactId>json</artifactId>
<version>20190722</version>
</dependency>
</dependencies>


<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.29</version>
</dependency>

<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.8.1</version>
</dependency>
</dependencies>
</project>

0 comments on commit e3571fd

Please sign in to comment.