package com.taiwanlife.teamwalk.api.aop.aspectj;
import com.taiwanlife.teamwalk.api.util.ApiLogUtils;
import com.taiwanlife.teamwalk.common.entity.member.MbrMemberAccessLog;
import com.taiwanlife.teamwalk.common.entity.system.SysApiLog;
import com.taiwanlife.teamwalk.common.repository.member.MemberAccessLogRepository;
import com.taiwanlife.teamwalk.common.repository.member.MemberRepository;
import com.taiwanlife.teamwalk.common.repository.system.ApiLogRepository;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.transaction.Transactional;
import java.io.BufferedReader;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
@Slf4j
@Aspect
@Component
public class ApiLogAspectj {
@Value("${spring.profiles.active}")
private String hostIP;
@Resource
private ApiLogRepository apiLogRepository;
@Resource
private MemberAccessLogRepository memberAccessLogRepository;
@Resource
MemberRepository memberRepository;
@Before("execution(* com.taiwanlife.teamwalk.api.controller.rest..*.*(..)) && " +
"!execution(* com.taiwanlife.teamwalk.api.controller.rest.system.ImageController.*(..))")
@Modifying
@Transactional
public void doBefore(JoinPoint joinPoint) throws Throwable {
if (log.isDebugEnabled()) {
log.debug("[START] doBefore() ...");
}
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.isAuthenticated()) {
String username = authentication.getName();
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
String url = request.getRequestURL().toString();
String method = request.getMethod();
Map<String, String[]> parameters = request.getParameterMap();
StringBuilder reqContent = new StringBuilder();
int keyIdx = 0;
Iterator iterator = parameters.entrySet().iterator();
String[] vals;
while(iterator.hasNext( )) {
Map.Entry entry = (Map.Entry) iterator.next();
if (keyIdx != 0) {
reqContent.append("; ");
} else {
reqContent.append("Params: {");
}
reqContent.append((String) entry.getKey()).append(": ");
vals = (String[]) entry.getValue();
int idx = 0;
for (String val : vals) {
if (idx != 0) {
reqContent.append(", ");
}
reqContent.append(val);
idx++;
}
if (keyIdx == parameters.keySet().size() - 1) {
reqContent.append("}");
}
keyIdx++;
}
if (reqContent.toString().equals("")) {
BufferedReader br = request.getReader();
String str;
boolean isFirstLine = true;
while ((str = br.readLine()) != null) {
if (!str.trim().equals("")) {
if (isFirstLine) {
reqContent.append("Body: ");
isFirstLine = false;
}
reqContent.append(str.trim());
}
}
}
if (reqContent.toString().equals("")) {
reqContent.append("** NONE **");
}
SysApiLog sysApiLog = new SysApiLog();
sysApiLog.setLogAt(LocalDateTime.now());
sysApiLog.setUrl(url);
sysApiLog.setHttpMethod(method);
sysApiLog.setHttpCode(""); // 先預設空白
sysApiLog.setFromIp(request.getRemoteAddr());
sysApiLog.setUsername(username);
sysApiLog.setClientDevice(request.getHeader("User-Agent"));
sysApiLog.setRequest(reqContent.toString());
sysApiLog.setResponse(""); // 先預設空白
/*
if (log.isDebugEnabled()) {
log.debug("Call apiLogRepository.save()...");
}
apiLogRepository.save(sysApiLog);
*/
log.debug(new StringBuffer().append("[API REQ] | ")
.append(LocalDateTime.now()).append(" | ") // log_at
.append("").append(" | ") // log_at_resp
.append(url).append(" | ") // url
.append(method).append(" | ") // http_method
.append("").append(" | ") // http_code
.append(request.getRemoteAddr()).append(" | ") // from ip
.append(username).append(" | ") // username
.append(request.getHeader("User-Agent")).append(" | ") // client device
.append(reqContent.toString()).append(" | ") // request
.append("") // response
.toString()
);
if (log.isDebugEnabled()) {
log.debug("Call ApiLogUtils.setApiLog()...");
}
ApiLogUtils.setApiLog(sysApiLog);
MbrMemberAccessLog accessLog = new MbrMemberAccessLog();
accessLog.setLogAt(LocalDateTime.now());
accessLog.setUrl(url);
accessLog.setHttpMethod(method);
accessLog.setFromIp(request.getRemoteAddr());
accessLog.setUsername(username);
accessLog.setRequest(reqContent.toString());
accessLog.setEnv(hostIP);
accessLog.setHostIp(request.getServerName());
accessLog.setThreadId(Long.valueOf(Thread.currentThread().getId()).intValue());
if (log.isDebugEnabled()) {
log.debug("Call memberAccessLogRepository.save()...");
}
memberAccessLogRepository.save(accessLog);
}
if (log.isDebugEnabled()) {
log.debug("[END] doBefore().");
}
}
@AfterReturning(
pointcut = "execution(* com.taiwanlife.teamwalk.api.controller.rest..*.*(..)) && " +
"!execution(* com.taiwanlife.teamwalk.api.controller.rest.system.ImageController.*(..))",
returning = "rtv")
@Modifying
@Transactional
public void doAfter(JoinPoint point, Object rtv) {
if (log.isDebugEnabled()) {
log.debug("[START] doAfter() ...");
log.debug("Call ApiLogUtils.getApiLog()...");
}
SysApiLog sysApiLogForReq = ApiLogUtils.getApiLog();
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getResponse();
if (sysApiLogForReq != null) {
/*
SysApiLog sysApiLog = new SysApiLog();
// 從舊物件抄寫過來
sysApiLog.setLogAt(sysApiLogForReq.getLogAt());
sysApiLog.setUrl(sysApiLogForReq.getUrl());
sysApiLog.setHttpMethod(sysApiLogForReq.getHttpMethod());
sysApiLog.setFromIp(sysApiLogForReq.getFromIp());
sysApiLog.setUsername(sysApiLogForReq.getUsername());
sysApiLog.setClientDevice(sysApiLogForReq.getClientDevice());
sysApiLog.setRequest(sysApiLogForReq.getRequest());
sysApiLog.setHttpCode(Integer.toString(response.getStatus()));
int startIdx = rtv.toString().indexOf(",") + 1;
int endIdx = rtv.toString().lastIndexOf(",");
if (startIdx > 0) {
if (endIdx > startIdx) {
sysApiLog.setResponse(rtv.toString().substring(rtv.toString().indexOf(",") + 1, rtv.toString().lastIndexOf(",")));
} else {
sysApiLog.setResponse(rtv.toString().substring(rtv.toString().indexOf(",") + 1));
}
}
sysApiLog.setLogAtResp(LocalDateTime.now());
if (log.isDebugEnabled()) {
log.debug("Call apiLogRepository.save()...");
}
apiLogRepository.save(sysApiLog);
*/
int startIdx = rtv.toString().indexOf(",") + 1;
int endIdx = rtv.toString().lastIndexOf(",");
String resp = null;
if (startIdx > 0) {
if (endIdx > startIdx) {
resp = rtv.toString().substring(rtv.toString().indexOf(",") + 1, rtv.toString().lastIndexOf(","));
} else {
resp = rtv.toString().substring(rtv.toString().indexOf(",") + 1);
}
}
log.debug(new StringBuffer().append("[API RESP] | ")
.append(sysApiLogForReq.getLogAt()).append(" | ") // log_at
.append(LocalDateTime.now()).append(" | ") // log_at_resp
.append(sysApiLogForReq.getUrl()).append(" | ") // url
.append(sysApiLogForReq.getHttpMethod()).append(" | ") // http_method
.append(response.getStatus()).append(" | ") // http_code
.append(sysApiLogForReq.getFromIp()).append(" | ") // from ip
.append(sysApiLogForReq.getUsername()).append(" | ") // username
.append(sysApiLogForReq.getClientDevice()).append(" | ")// client device
.append(sysApiLogForReq.getRequest()).append(" | ") // request
.append(resp) // response
.toString()
);
}
if (log.isDebugEnabled()) {
log.debug("Call ApiLogUtils.removeApiLog()...");
}
ApiLogUtils.removeApiLog();
if (log.isDebugEnabled()) {
log.debug("[END] doAfter().");
}
}
}
cGFja2FnZSBjb20udGFpd2FubGlmZS50ZWFtd2Fsay5hcGkuYW9wLmFzcGVjdGo7CgoKCmltcG9ydCBjb20udGFpd2FubGlmZS50ZWFtd2Fsay5hcGkudXRpbC5BcGlMb2dVdGlsczsKCmltcG9ydCBjb20udGFpd2FubGlmZS50ZWFtd2Fsay5jb21tb24uZW50aXR5Lm1lbWJlci5NYnJNZW1iZXJBY2Nlc3NMb2c7CgppbXBvcnQgY29tLnRhaXdhbmxpZmUudGVhbXdhbGsuY29tbW9uLmVudGl0eS5zeXN0ZW0uU3lzQXBpTG9nOwoKaW1wb3J0IGNvbS50YWl3YW5saWZlLnRlYW13YWxrLmNvbW1vbi5yZXBvc2l0b3J5Lm1lbWJlci5NZW1iZXJBY2Nlc3NMb2dSZXBvc2l0b3J5OwoKaW1wb3J0IGNvbS50YWl3YW5saWZlLnRlYW13YWxrLmNvbW1vbi5yZXBvc2l0b3J5Lm1lbWJlci5NZW1iZXJSZXBvc2l0b3J5OwoKaW1wb3J0IGNvbS50YWl3YW5saWZlLnRlYW13YWxrLmNvbW1vbi5yZXBvc2l0b3J5LnN5c3RlbS5BcGlMb2dSZXBvc2l0b3J5OwoKaW1wb3J0IGxvbWJvay5leHRlcm4uc2xmNGouU2xmNGo7CgppbXBvcnQgb3JnLmFzcGVjdGoubGFuZy5Kb2luUG9pbnQ7CgppbXBvcnQgb3JnLmFzcGVjdGoubGFuZy5hbm5vdGF0aW9uLkFmdGVyUmV0dXJuaW5nOwoKaW1wb3J0IG9yZy5hc3BlY3RqLmxhbmcuYW5ub3RhdGlvbi5Bc3BlY3Q7CgppbXBvcnQgb3JnLmFzcGVjdGoubGFuZy5hbm5vdGF0aW9uLkJlZm9yZTsKCmltcG9ydCBvcmcuc3ByaW5nZnJhbWV3b3JrLmJlYW5zLmZhY3RvcnkuYW5ub3RhdGlvbi5WYWx1ZTsKCmltcG9ydCBvcmcuc3ByaW5nZnJhbWV3b3JrLmRhdGEuanBhLnJlcG9zaXRvcnkuTW9kaWZ5aW5nOwoKaW1wb3J0IG9yZy5zcHJpbmdmcmFtZXdvcmsuc2VjdXJpdHkuY29yZS5BdXRoZW50aWNhdGlvbjsKCmltcG9ydCBvcmcuc3ByaW5nZnJhbWV3b3JrLnNlY3VyaXR5LmNvcmUuY29udGV4dC5TZWN1cml0eUNvbnRleHRIb2xkZXI7CgppbXBvcnQgb3JnLnNwcmluZ2ZyYW1ld29yay5zdGVyZW90eXBlLkNvbXBvbmVudDsKCmltcG9ydCBvcmcuc3ByaW5nZnJhbWV3b3JrLnN0ZXJlb3R5cGUuU2VydmljZTsKCmltcG9ydCBvcmcuc3ByaW5nZnJhbWV3b3JrLndlYi5jb250ZXh0LnJlcXVlc3QuUmVxdWVzdENvbnRleHRIb2xkZXI7CgppbXBvcnQgb3JnLnNwcmluZ2ZyYW1ld29yay53ZWIuY29udGV4dC5yZXF1ZXN0LlNlcnZsZXRSZXF1ZXN0QXR0cmlidXRlczsKCgoKaW1wb3J0IGpha2FydGEuYW5ub3RhdGlvbi5SZXNvdXJjZTsKCmltcG9ydCBqYWthcnRhLnNlcnZsZXQuaHR0cC5IdHRwU2VydmxldFJlcXVlc3Q7CgppbXBvcnQgamFrYXJ0YS5zZXJ2bGV0Lmh0dHAuSHR0cFNlcnZsZXRSZXNwb25zZTsKCmltcG9ydCBqYWthcnRhLnRyYW5zYWN0aW9uLlRyYW5zYWN0aW9uYWw7CgppbXBvcnQgamF2YS5pby5CdWZmZXJlZFJlYWRlcjsKCmltcG9ydCBqYXZhLnRpbWUuTG9jYWxEYXRlVGltZTsKCmltcG9ydCBqYXZhLnV0aWwuSXRlcmF0b3I7CgppbXBvcnQgamF2YS51dGlsLk1hcDsKCmltcG9ydCBqYXZhLnV0aWwuU2V0OwoKCgpAU2xmNGoKCkBBc3BlY3QKCkBDb21wb25lbnQKCnB1YmxpYyBjbGFzcyBBcGlMb2dBc3BlY3RqIHsKCiAgICBAVmFsdWUoIiR7c3ByaW5nLnByb2ZpbGVzLmFjdGl2ZX0iKQoKICAgIHByaXZhdGUgU3RyaW5nIGhvc3RJUDsKCgoKICAgIEBSZXNvdXJjZQoKICAgIHByaXZhdGUgQXBpTG9nUmVwb3NpdG9yeSBhcGlMb2dSZXBvc2l0b3J5OwoKCgogICAgQFJlc291cmNlCgogICAgcHJpdmF0ZSBNZW1iZXJBY2Nlc3NMb2dSZXBvc2l0b3J5IG1lbWJlckFjY2Vzc0xvZ1JlcG9zaXRvcnk7CgoKCiAgICBAUmVzb3VyY2UKCiAgICBNZW1iZXJSZXBvc2l0b3J5IG1lbWJlclJlcG9zaXRvcnk7CgoKCgoKICAgIEBCZWZvcmUoImV4ZWN1dGlvbigqIGNvbS50YWl3YW5saWZlLnRlYW13YWxrLmFwaS5jb250cm9sbGVyLnJlc3QuLiouKiguLikpICYmICIgKwoKICAgICAgICAgICAgIiFleGVjdXRpb24oKiBjb20udGFpd2FubGlmZS50ZWFtd2Fsay5hcGkuY29udHJvbGxlci5yZXN0LnN5c3RlbS5JbWFnZUNvbnRyb2xsZXIuKiguLikpIikKCiAgICBATW9kaWZ5aW5nCgogICAgQFRyYW5zYWN0aW9uYWwKCiAgICBwdWJsaWMgdm9pZCBkb0JlZm9yZShKb2luUG9pbnQgam9pblBvaW50KSB0aHJvd3MgVGhyb3dhYmxlIHsKCiAgICAgICAgaWYgKGxvZy5pc0RlYnVnRW5hYmxlZCgpKSB7CgogICAgICAgICAgICBsb2cuZGVidWcoIltTVEFSVF0gZG9CZWZvcmUoKSAuLi4iKTsKCiAgICAgICAgfQoKCgogICAgICAgIEF1dGhlbnRpY2F0aW9uIGF1dGhlbnRpY2F0aW9uID0gU2VjdXJpdHlDb250ZXh0SG9sZGVyLmdldENvbnRleHQoKS5nZXRBdXRoZW50aWNhdGlvbigpOwoKICAgICAgICBpZiAoYXV0aGVudGljYXRpb24gIT0gbnVsbCAmJiBhdXRoZW50aWNhdGlvbi5pc0F1dGhlbnRpY2F0ZWQoKSkgewoKICAgICAgICAgICAgU3RyaW5nIHVzZXJuYW1lID0gYXV0aGVudGljYXRpb24uZ2V0TmFtZSgpOwoKCgogICAgICAgICAgICBIdHRwU2VydmxldFJlcXVlc3QgcmVxdWVzdCA9ICgoU2VydmxldFJlcXVlc3RBdHRyaWJ1dGVzKSAoUmVxdWVzdENvbnRleHRIb2xkZXIuY3VycmVudFJlcXVlc3RBdHRyaWJ1dGVzKCkpKS5nZXRSZXF1ZXN0KCk7CgoKCiAgICAgICAgICAgIFN0cmluZyB1cmwgPSByZXF1ZXN0LmdldFJlcXVlc3RVUkwoKS50b1N0cmluZygpOwoKICAgICAgICAgICAgU3RyaW5nIG1ldGhvZCA9IHJlcXVlc3QuZ2V0TWV0aG9kKCk7CgoKCiAgICAgICAgICAgIE1hcDxTdHJpbmcsIFN0cmluZ1tdPiBwYXJhbWV0ZXJzID0gcmVxdWVzdC5nZXRQYXJhbWV0ZXJNYXAoKTsKCgoKICAgICAgICAgICAgU3RyaW5nQnVpbGRlciByZXFDb250ZW50ID0gbmV3IFN0cmluZ0J1aWxkZXIoKTsKCiAgICAgICAgICAgIGludCBrZXlJZHggPSAwOwoKCgogICAgICAgICAgICBJdGVyYXRvciBpdGVyYXRvciA9IHBhcmFtZXRlcnMuZW50cnlTZXQoKS5pdGVyYXRvcigpOwoKICAgICAgICAgICAgU3RyaW5nW10gdmFsczsKCiAgICAgICAgICAgIHdoaWxlKGl0ZXJhdG9yLmhhc05leHQoICkpIHsKCiAgICAgICAgICAgICAgICBNYXAuRW50cnkgZW50cnkgPSAoTWFwLkVudHJ5KSBpdGVyYXRvci5uZXh0KCk7CgoKCiAgICAgICAgICAgICAgICBpZiAoa2V5SWR4ICE9IDApIHsKCiAgICAgICAgICAgICAgICAgICAgcmVxQ29udGVudC5hcHBlbmQoIjsgIik7CgogICAgICAgICAgICAgICAgfSBlbHNlIHsKCiAgICAgICAgICAgICAgICAgICAgcmVxQ29udGVudC5hcHBlbmQoIlBhcmFtczogeyIpOwoKICAgICAgICAgICAgICAgIH0KCgoKICAgICAgICAgICAgICAgIHJlcUNvbnRlbnQuYXBwZW5kKChTdHJpbmcpIGVudHJ5LmdldEtleSgpKS5hcHBlbmQoIjogIik7CgoKCiAgICAgICAgICAgICAgICB2YWxzID0gKFN0cmluZ1tdKSBlbnRyeS5nZXRWYWx1ZSgpOwoKCgogICAgICAgICAgICAgICAgaW50IGlkeCA9IDA7CgogICAgICAgICAgICAgICAgZm9yIChTdHJpbmcgdmFsIDogdmFscykgewoKICAgICAgICAgICAgICAgICAgICBpZiAoaWR4ICE9IDApIHsKCiAgICAgICAgICAgICAgICAgICAgICAgIHJlcUNvbnRlbnQuYXBwZW5kKCIsICIpOwoKICAgICAgICAgICAgICAgICAgICB9CgoKCiAgICAgICAgICAgICAgICAgICAgcmVxQ29udGVudC5hcHBlbmQodmFsKTsKCgoKICAgICAgICAgICAgICAgICAgICBpZHgrKzsKCiAgICAgICAgICAgICAgICB9CgoKCiAgICAgICAgICAgICAgICBpZiAoa2V5SWR4ID09IHBhcmFtZXRlcnMua2V5U2V0KCkuc2l6ZSgpIC0gMSkgewoKICAgICAgICAgICAgICAgICAgICByZXFDb250ZW50LmFwcGVuZCgifSIpOwoKICAgICAgICAgICAgICAgIH0KCgoKICAgICAgICAgICAgICAgIGtleUlkeCsrOwoKICAgICAgICAgICAgfQoKCgogICAgICAgICAgICBpZiAocmVxQ29udGVudC50b1N0cmluZygpLmVxdWFscygiIikpIHsKCiAgICAgICAgICAgICAgICBCdWZmZXJlZFJlYWRlciBiciA9IHJlcXVlc3QuZ2V0UmVhZGVyKCk7CgoKCiAgICAgICAgICAgICAgICBTdHJpbmcgc3RyOwoKICAgICAgICAgICAgICAgIGJvb2xlYW4gaXNGaXJzdExpbmUgPSB0cnVlOwoKICAgICAgICAgICAgICAgIHdoaWxlICgoc3RyID0gYnIucmVhZExpbmUoKSkgIT0gbnVsbCkgewoKICAgICAgICAgICAgICAgICAgICBpZiAoIXN0ci50cmltKCkuZXF1YWxzKCIiKSkgewoKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzRmlyc3RMaW5lKSB7CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxQ29udGVudC5hcHBlbmQoIkJvZHk6ICIpOwoKCgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNGaXJzdExpbmUgPSBmYWxzZTsKCiAgICAgICAgICAgICAgICAgICAgICAgIH0KCgoKICAgICAgICAgICAgICAgICAgICAgICAgcmVxQ29udGVudC5hcHBlbmQoc3RyLnRyaW0oKSk7CgogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICB9CgoKCiAgICAgICAgICAgIGlmIChyZXFDb250ZW50LnRvU3RyaW5nKCkuZXF1YWxzKCIiKSkgewoKICAgICAgICAgICAgICAgIHJlcUNvbnRlbnQuYXBwZW5kKCIqKiBOT05FICoqIik7CgogICAgICAgICAgICB9CgoKCgoKICAgICAgICAgICAgU3lzQXBpTG9nIHN5c0FwaUxvZyA9IG5ldyBTeXNBcGlMb2coKTsKCgoKICAgICAgICAgICAgc3lzQXBpTG9nLnNldExvZ0F0KExvY2FsRGF0ZVRpbWUubm93KCkpOwoKICAgICAgICAgICAgc3lzQXBpTG9nLnNldFVybCh1cmwpOwoKICAgICAgICAgICAgc3lzQXBpTG9nLnNldEh0dHBNZXRob2QobWV0aG9kKTsKCiAgICAgICAgICAgIHN5c0FwaUxvZy5zZXRIdHRwQ29kZSgiIik7ICAvLyDlhYjpoJDoqK3nqbrnmb0KCiAgICAgICAgICAgIHN5c0FwaUxvZy5zZXRGcm9tSXAocmVxdWVzdC5nZXRSZW1vdGVBZGRyKCkpOwoKICAgICAgICAgICAgc3lzQXBpTG9nLnNldFVzZXJuYW1lKHVzZXJuYW1lKTsKCiAgICAgICAgICAgIHN5c0FwaUxvZy5zZXRDbGllbnREZXZpY2UocmVxdWVzdC5nZXRIZWFkZXIoIlVzZXItQWdlbnQiKSk7CgogICAgICAgICAgICBzeXNBcGlMb2cuc2V0UmVxdWVzdChyZXFDb250ZW50LnRvU3RyaW5nKCkpOwoKICAgICAgICAgICAgc3lzQXBpTG9nLnNldFJlc3BvbnNlKCIiKTsgIC8vIOWFiOmgkOioreepuueZvQoKCgogICAgICAgICAgICAvKgoKICAgICAgICAgICAgaWYgKGxvZy5pc0RlYnVnRW5hYmxlZCgpKSB7CgogICAgICAgICAgICAgICAgbG9nLmRlYnVnKCJDYWxsIGFwaUxvZ1JlcG9zaXRvcnkuc2F2ZSgpLi4uIik7CgogICAgICAgICAgICB9CgoKCiAgICAgICAgICAgIGFwaUxvZ1JlcG9zaXRvcnkuc2F2ZShzeXNBcGlMb2cpOwoKICAgICAgICAgICAgKi8KCgoKICAgICAgICAgICAgbG9nLmRlYnVnKG5ldyBTdHJpbmdCdWZmZXIoKS5hcHBlbmQoIltBUEkgUkVRXSB8ICIpCgogICAgICAgICAgICAgICAgICAgIC5hcHBlbmQoTG9jYWxEYXRlVGltZS5ub3coKSkuYXBwZW5kKCIgfCAiKSAgICAgLy8gbG9nX2F0CgogICAgICAgICAgICAgICAgICAgIC5hcHBlbmQoIiIpLmFwcGVuZCgiIHwgIikgICAgICAgICAgICAgICAgICAgICAgLy8gbG9nX2F0X3Jlc3AKCiAgICAgICAgICAgICAgICAgICAgLmFwcGVuZCh1cmwpLmFwcGVuZCgiIHwgIikgICAgICAgICAgICAgICAgICAgICAvLyB1cmwKCiAgICAgICAgICAgICAgICAgICAgLmFwcGVuZChtZXRob2QpLmFwcGVuZCgiIHwgIikgICAgICAgICAgICAgICAgICAvLyBodHRwX21ldGhvZAoKICAgICAgICAgICAgICAgICAgICAuYXBwZW5kKCIiKS5hcHBlbmQoIiB8ICIpICAgICAgICAgICAgICAgICAgICAgIC8vIGh0dHBfY29kZQoKICAgICAgICAgICAgICAgICAgICAuYXBwZW5kKHJlcXVlc3QuZ2V0UmVtb3RlQWRkcigpKS5hcHBlbmQoIiB8ICIpIC8vIGZyb20gaXAKCiAgICAgICAgICAgICAgICAgICAgLmFwcGVuZCh1c2VybmFtZSkuYXBwZW5kKCIgfCAiKSAgICAgICAgICAgICAgICAvLyB1c2VybmFtZQoKICAgICAgICAgICAgICAgICAgICAuYXBwZW5kKHJlcXVlc3QuZ2V0SGVhZGVyKCJVc2VyLUFnZW50IikpLmFwcGVuZCgiIHwgIikgIC8vIGNsaWVudCBkZXZpY2UKCiAgICAgICAgICAgICAgICAgICAgLmFwcGVuZChyZXFDb250ZW50LnRvU3RyaW5nKCkpLmFwcGVuZCgiIHwgIikgICAvLyByZXF1ZXN0CgogICAgICAgICAgICAgICAgICAgIC5hcHBlbmQoIiIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVzcG9uc2UKCiAgICAgICAgICAgICAgICAgICAgLnRvU3RyaW5nKCkKCiAgICAgICAgICAgICk7CgoKCiAgICAgICAgICAgIGlmIChsb2cuaXNEZWJ1Z0VuYWJsZWQoKSkgewoKICAgICAgICAgICAgICAgIGxvZy5kZWJ1ZygiQ2FsbCBBcGlMb2dVdGlscy5zZXRBcGlMb2coKS4uLiIpOwoKICAgICAgICAgICAgfQoKCgogICAgICAgICAgICBBcGlMb2dVdGlscy5zZXRBcGlMb2coc3lzQXBpTG9nKTsKCgoKICAgICAgICAgICAgTWJyTWVtYmVyQWNjZXNzTG9nIGFjY2Vzc0xvZyA9IG5ldyBNYnJNZW1iZXJBY2Nlc3NMb2coKTsKCgoKICAgICAgICAgICAgYWNjZXNzTG9nLnNldExvZ0F0KExvY2FsRGF0ZVRpbWUubm93KCkpOwoKICAgICAgICAgICAgYWNjZXNzTG9nLnNldFVybCh1cmwpOwoKICAgICAgICAgICAgYWNjZXNzTG9nLnNldEh0dHBNZXRob2QobWV0aG9kKTsKCiAgICAgICAgICAgIGFjY2Vzc0xvZy5zZXRGcm9tSXAocmVxdWVzdC5nZXRSZW1vdGVBZGRyKCkpOwoKICAgICAgICAgICAgYWNjZXNzTG9nLnNldFVzZXJuYW1lKHVzZXJuYW1lKTsKCiAgICAgICAgICAgIGFjY2Vzc0xvZy5zZXRSZXF1ZXN0KHJlcUNvbnRlbnQudG9TdHJpbmcoKSk7CgogICAgICAgICAgICBhY2Nlc3NMb2cuc2V0RW52KGhvc3RJUCk7CgogICAgICAgICAgICBhY2Nlc3NMb2cuc2V0SG9zdElwKHJlcXVlc3QuZ2V0U2VydmVyTmFtZSgpKTsKCiAgICAgICAgICAgIGFjY2Vzc0xvZy5zZXRUaHJlYWRJZChMb25nLnZhbHVlT2YoVGhyZWFkLmN1cnJlbnRUaHJlYWQoKS5nZXRJZCgpKS5pbnRWYWx1ZSgpKTsKCgoKICAgICAgICAgICAgaWYgKGxvZy5pc0RlYnVnRW5hYmxlZCgpKSB7CgogICAgICAgICAgICAgICAgbG9nLmRlYnVnKCJDYWxsIG1lbWJlckFjY2Vzc0xvZ1JlcG9zaXRvcnkuc2F2ZSgpLi4uIik7CgogICAgICAgICAgICB9CgoKCiAgICAgICAgICAgIG1lbWJlckFjY2Vzc0xvZ1JlcG9zaXRvcnkuc2F2ZShhY2Nlc3NMb2cpOwoKICAgICAgICB9CgoKCiAgICAgICAgaWYgKGxvZy5pc0RlYnVnRW5hYmxlZCgpKSB7CgogICAgICAgICAgICBsb2cuZGVidWcoIltFTkRdIGRvQmVmb3JlKCkuIik7CgogICAgICAgIH0KCiAgICB9CgoKCiAgICBAQWZ0ZXJSZXR1cm5pbmcoCgogICAgICAgICAgICBwb2ludGN1dCA9ICJleGVjdXRpb24oKiBjb20udGFpd2FubGlmZS50ZWFtd2Fsay5hcGkuY29udHJvbGxlci5yZXN0Li4qLiooLi4pKSAmJiAiICsKCiAgICAgICAgICAgICAgICAgICAgICAgIiFleGVjdXRpb24oKiBjb20udGFpd2FubGlmZS50ZWFtd2Fsay5hcGkuY29udHJvbGxlci5yZXN0LnN5c3RlbS5JbWFnZUNvbnRyb2xsZXIuKiguLikpIiwKCiAgICAgICAgICAgIHJldHVybmluZyA9ICJydHYiKQoKICAgIEBNb2RpZnlpbmcKCiAgICBAVHJhbnNhY3Rpb25hbAoKICAgIHB1YmxpYyB2b2lkIGRvQWZ0ZXIoSm9pblBvaW50IHBvaW50LCBPYmplY3QgcnR2KSB7CgogICAgICAgIGlmIChsb2cuaXNEZWJ1Z0VuYWJsZWQoKSkgewoKICAgICAgICAgICAgbG9nLmRlYnVnKCJbU1RBUlRdIGRvQWZ0ZXIoKSAuLi4iKTsKCiAgICAgICAgICAgIGxvZy5kZWJ1ZygiQ2FsbCBBcGlMb2dVdGlscy5nZXRBcGlMb2coKS4uLiIpOwoKICAgICAgICB9CgoKCiAgICAgICAgU3lzQXBpTG9nIHN5c0FwaUxvZ0ZvclJlcSA9IEFwaUxvZ1V0aWxzLmdldEFwaUxvZygpOwoKCgogICAgICAgIEh0dHBTZXJ2bGV0UmVzcG9uc2UgcmVzcG9uc2UgPSAoKFNlcnZsZXRSZXF1ZXN0QXR0cmlidXRlcykgUmVxdWVzdENvbnRleHRIb2xkZXIuY3VycmVudFJlcXVlc3RBdHRyaWJ1dGVzKCkpCgogICAgICAgICAgICAgICAgLmdldFJlc3BvbnNlKCk7CgoKCiAgICAgICAgaWYgKHN5c0FwaUxvZ0ZvclJlcSAhPSBudWxsKSB7CgogICAgICAgICAgICAvKgoKICAgICAgICAgICAgU3lzQXBpTG9nIHN5c0FwaUxvZyA9IG5ldyBTeXNBcGlMb2coKTsKCgoKICAgICAgICAgICAgLy8g5b6e6IiK54mp5Lu25oqE5a+r6YGO5L6GCgogICAgICAgICAgICBzeXNBcGlMb2cuc2V0TG9nQXQoc3lzQXBpTG9nRm9yUmVxLmdldExvZ0F0KCkpOwoKICAgICAgICAgICAgc3lzQXBpTG9nLnNldFVybChzeXNBcGlMb2dGb3JSZXEuZ2V0VXJsKCkpOwoKICAgICAgICAgICAgc3lzQXBpTG9nLnNldEh0dHBNZXRob2Qoc3lzQXBpTG9nRm9yUmVxLmdldEh0dHBNZXRob2QoKSk7CgogICAgICAgICAgICBzeXNBcGlMb2cuc2V0RnJvbUlwKHN5c0FwaUxvZ0ZvclJlcS5nZXRGcm9tSXAoKSk7CgogICAgICAgICAgICBzeXNBcGlMb2cuc2V0VXNlcm5hbWUoc3lzQXBpTG9nRm9yUmVxLmdldFVzZXJuYW1lKCkpOwoKICAgICAgICAgICAgc3lzQXBpTG9nLnNldENsaWVudERldmljZShzeXNBcGlMb2dGb3JSZXEuZ2V0Q2xpZW50RGV2aWNlKCkpOwoKICAgICAgICAgICAgc3lzQXBpTG9nLnNldFJlcXVlc3Qoc3lzQXBpTG9nRm9yUmVxLmdldFJlcXVlc3QoKSk7CgoKCiAgICAgICAgICAgIHN5c0FwaUxvZy5zZXRIdHRwQ29kZShJbnRlZ2VyLnRvU3RyaW5nKHJlc3BvbnNlLmdldFN0YXR1cygpKSk7CgoKCiAgICAgICAgICAgIGludCBzdGFydElkeCA9IHJ0di50b1N0cmluZygpLmluZGV4T2YoIiwiKSArIDE7CgogICAgICAgICAgICBpbnQgZW5kSWR4ID0gcnR2LnRvU3RyaW5nKCkubGFzdEluZGV4T2YoIiwiKTsKCgoKICAgICAgICAgICAgaWYgKHN0YXJ0SWR4ID4gMCkgewoKICAgICAgICAgICAgICAgIGlmIChlbmRJZHggPiBzdGFydElkeCkgewoKICAgICAgICAgICAgICAgICAgICBzeXNBcGlMb2cuc2V0UmVzcG9uc2UocnR2LnRvU3RyaW5nKCkuc3Vic3RyaW5nKHJ0di50b1N0cmluZygpLmluZGV4T2YoIiwiKSArIDEsIHJ0di50b1N0cmluZygpLmxhc3RJbmRleE9mKCIsIikpKTsKCiAgICAgICAgICAgICAgICB9IGVsc2UgewoKICAgICAgICAgICAgICAgICAgICBzeXNBcGlMb2cuc2V0UmVzcG9uc2UocnR2LnRvU3RyaW5nKCkuc3Vic3RyaW5nKHJ0di50b1N0cmluZygpLmluZGV4T2YoIiwiKSArIDEpKTsKCiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICB9CgoKCiAgICAgICAgICAgIHN5c0FwaUxvZy5zZXRMb2dBdFJlc3AoTG9jYWxEYXRlVGltZS5ub3coKSk7CgoKCiAgICAgICAgICAgIGlmIChsb2cuaXNEZWJ1Z0VuYWJsZWQoKSkgewoKICAgICAgICAgICAgICAgIGxvZy5kZWJ1ZygiQ2FsbCBhcGlMb2dSZXBvc2l0b3J5LnNhdmUoKS4uLiIpOwoKICAgICAgICAgICAgfQoKCgogICAgICAgICAgICBhcGlMb2dSZXBvc2l0b3J5LnNhdmUoc3lzQXBpTG9nKTsKCiAgICAgICAgICAgICovCgoKCiAgICAgICAgICAgIGludCBzdGFydElkeCA9IHJ0di50b1N0cmluZygpLmluZGV4T2YoIiwiKSArIDE7CgogICAgICAgICAgICBpbnQgZW5kSWR4ID0gcnR2LnRvU3RyaW5nKCkubGFzdEluZGV4T2YoIiwiKTsKCgoKICAgICAgICAgICAgU3RyaW5nIHJlc3AgPSBudWxsOwoKICAgICAgICAgICAgaWYgKHN0YXJ0SWR4ID4gMCkgewoKICAgICAgICAgICAgICAgIGlmIChlbmRJZHggPiBzdGFydElkeCkgewoKICAgICAgICAgICAgICAgICAgICByZXNwID0gcnR2LnRvU3RyaW5nKCkuc3Vic3RyaW5nKHJ0di50b1N0cmluZygpLmluZGV4T2YoIiwiKSArIDEsIHJ0di50b1N0cmluZygpLmxhc3RJbmRleE9mKCIsIikpOwoKICAgICAgICAgICAgICAgIH0gZWxzZSB7CgogICAgICAgICAgICAgICAgICAgIHJlc3AgPSBydHYudG9TdHJpbmcoKS5zdWJzdHJpbmcocnR2LnRvU3RyaW5nKCkuaW5kZXhPZigiLCIpICsgMSk7CgogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgfQoKCgogICAgICAgICAgICBsb2cuZGVidWcobmV3IFN0cmluZ0J1ZmZlcigpLmFwcGVuZCgiW0FQSSBSRVNQXSB8ICIpCgogICAgICAgICAgICAgICAgICAgIC5hcHBlbmQoc3lzQXBpTG9nRm9yUmVxLmdldExvZ0F0KCkpLmFwcGVuZCgiIHwgIikgICAgICAgLy8gbG9nX2F0CgogICAgICAgICAgICAgICAgICAgIC5hcHBlbmQoTG9jYWxEYXRlVGltZS5ub3coKSkuYXBwZW5kKCIgfCAiKSAgICAgICAgICAgICAgLy8gbG9nX2F0X3Jlc3AKCiAgICAgICAgICAgICAgICAgICAgLmFwcGVuZChzeXNBcGlMb2dGb3JSZXEuZ2V0VXJsKCkpLmFwcGVuZCgiIHwgIikgICAgICAgICAvLyB1cmwKCiAgICAgICAgICAgICAgICAgICAgLmFwcGVuZChzeXNBcGlMb2dGb3JSZXEuZ2V0SHR0cE1ldGhvZCgpKS5hcHBlbmQoIiB8ICIpICAvLyBodHRwX21ldGhvZAoKICAgICAgICAgICAgICAgICAgICAuYXBwZW5kKHJlc3BvbnNlLmdldFN0YXR1cygpKS5hcHBlbmQoIiB8ICIpICAgICAgICAgICAgIC8vIGh0dHBfY29kZQoKICAgICAgICAgICAgICAgICAgICAuYXBwZW5kKHN5c0FwaUxvZ0ZvclJlcS5nZXRGcm9tSXAoKSkuYXBwZW5kKCIgfCAiKSAgICAgIC8vIGZyb20gaXAKCiAgICAgICAgICAgICAgICAgICAgLmFwcGVuZChzeXNBcGlMb2dGb3JSZXEuZ2V0VXNlcm5hbWUoKSkuYXBwZW5kKCIgfCAiKSAgICAvLyB1c2VybmFtZQoKICAgICAgICAgICAgICAgICAgICAuYXBwZW5kKHN5c0FwaUxvZ0ZvclJlcS5nZXRDbGllbnREZXZpY2UoKSkuYXBwZW5kKCIgfCAiKS8vIGNsaWVudCBkZXZpY2UKCiAgICAgICAgICAgICAgICAgICAgLmFwcGVuZChzeXNBcGlMb2dGb3JSZXEuZ2V0UmVxdWVzdCgpKS5hcHBlbmQoIiB8ICIpICAgICAvLyByZXF1ZXN0CgogICAgICAgICAgICAgICAgICAgIC5hcHBlbmQocmVzcCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVzcG9uc2UKCiAgICAgICAgICAgICAgICAgICAgLnRvU3RyaW5nKCkKCiAgICAgICAgICAgICk7CgogICAgICAgIH0KCgoKICAgICAgICBpZiAobG9nLmlzRGVidWdFbmFibGVkKCkpIHsKCiAgICAgICAgICAgIGxvZy5kZWJ1ZygiQ2FsbCBBcGlMb2dVdGlscy5yZW1vdmVBcGlMb2coKS4uLiIpOwoKICAgICAgICB9CgoKCiAgICAgICAgQXBpTG9nVXRpbHMucmVtb3ZlQXBpTG9nKCk7CgoKCiAgICAgICAgaWYgKGxvZy5pc0RlYnVnRW5hYmxlZCgpKSB7CgogICAgICAgICAgICBsb2cuZGVidWcoIltFTkRdIGRvQWZ0ZXIoKS4iKTsKCiAgICAgICAgfQoKICAgIH0KCn0K