diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6de1836..3ad86aa 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -41,8 +41,8 @@ tasks.asciidoctor { dependencies { implementation(project(":sitemap")) implementation(project(":linkback")) + implementation(project(":web-app")) - implementation(project(":address-finder")) implementation("com.vladsch.flexmark:flexmark-all:0.62.2") implementation("org.springframework.boot:spring-boot-starter-data-jpa") diff --git a/app/src/main/java/com/elex_project/asgard/Application.java b/app/src/main/java/com/elex_project/asgard/Application.java index 92a6f8d..7eb91ac 100644 --- a/app/src/main/java/com/elex_project/asgard/Application.java +++ b/app/src/main/java/com/elex_project/asgard/Application.java @@ -31,4 +31,5 @@ public class Application { } } + } diff --git a/app/src/main/java/com/elex_project/asgard/config/AsgardCacheCustomizer.java b/app/src/main/java/com/elex_project/asgard/config/AsgardCacheCustomizer.java new file mode 100644 index 0000000..a45fed2 --- /dev/null +++ b/app/src/main/java/com/elex_project/asgard/config/AsgardCacheCustomizer.java @@ -0,0 +1,24 @@ +/* + * Project Asgard + * + * Copyright (c) 2021. Elex. All Rights Reserved. + * https://www.elex-project.com/ + */ + +package com.elex_project.asgard.config; + +import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.stereotype.Component; + +import java.util.Arrays; + +@Component +public class AsgardCacheCustomizer implements CacheManagerCustomizer { + + @Override + public void customize(ConcurrentMapCacheManager cacheManager) { + cacheManager.setCacheNames(Arrays + .asList("sitemap", "syndication/rss", "syndication/atom")); + } +} diff --git a/app/src/main/java/com/elex_project/asgard/config/Config.java b/app/src/main/java/com/elex_project/asgard/config/Config.java index fc77425..4d21b80 100644 --- a/app/src/main/java/com/elex_project/asgard/config/Config.java +++ b/app/src/main/java/com/elex_project/asgard/config/Config.java @@ -9,6 +9,8 @@ package com.elex_project.asgard.config; import com.elex_project.asgard.supplements.Markdown; import com.elex_project.asgard.view.AsgardLocaleResolver; +import org.springframework.cache.CacheManager; +import org.springframework.cache.support.SimpleCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.LocaleResolver; @@ -16,32 +18,14 @@ import org.springframework.web.servlet.LocaleResolver; @Configuration public class Config { - /*@Bean - public RestTemplate restTemplate() { - return new RestTemplate(); - } -*/ - /*@Bean - public HttpTraceRepository httpTraceRepository() { - return new InMemoryHttpTraceRepository(); - }*/ - - /** * Locale resolver, 디폴트 로캐일을 지정한다. */ @Bean public LocaleResolver localeResolver() { - /*SessionLocaleResolver localeResolver = new SessionLocaleResolver(); - localeResolver.setDefaultLocale(Locale.ENGLISH); - localeResolver.setLocaleAttributeName("lc"); - localeResolver.setTimeZoneAttributeName("tz"); - return localeResolver;*/ - return new AsgardLocaleResolver(); } - /** * Markdown parser * diff --git a/app/src/main/java/com/elex_project/asgard/controller/BaseController.java b/app/src/main/java/com/elex_project/asgard/controller/BaseController.java deleted file mode 100644 index 350240f..0000000 --- a/app/src/main/java/com/elex_project/asgard/controller/BaseController.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Project Asgard - * - * Copyright (c) 2021. Elex. All Rights Reserved. - * https://www.elex-project.com/ - */ - -package com.elex_project.asgard.controller; - -import org.jetbrains.annotations.NotNull; -import org.springframework.web.context.request.RequestAttributes; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.net.URI; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -abstract class BaseController { - - /*@NotNull - protected Map map() { - final HashMap map = new HashMap<>(); - map.put("html_lang", lang()); - return map; - } - - @NotNull - private String lang() { - return getHttpRequest() - .map(request -> request.getLocale().toLanguageTag()) - .orElse("en"); - } - - @NotNull - protected URI getRequestURI() { - return getHttpRequest() - .map(request -> URI.create(request.getRequestURI())) - .orElse(URI.create("/")); - } - - private Optional getRequestAttributes() { - return Optional - .ofNullable((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()); - } - - protected Optional getHttpRequest() { - return getRequestAttributes() - .map(ServletRequestAttributes::getRequest); - } - - protected Optional getHttpResponse() { - return getRequestAttributes() - .map(ServletRequestAttributes::getResponse); - } - - @NotNull - protected String[] getAttributeNames() { - return getRequestAttributes() - .map(attr -> attr.getAttributeNames(RequestAttributes.SCOPE_REQUEST)) - .orElse(new String[0]); - } - - @NotNull - protected String[] getSessionAttributeNames() { - return getRequestAttributes() - .map(attr -> attr.getAttributeNames(RequestAttributes.SCOPE_SESSION)) - .orElse(new String[0]); - } - - @NotNull - protected Optional getAttribute(@NotNull final String key) { - return getRequestAttributes() - .map(attr -> attr.getAttribute(key, RequestAttributes.SCOPE_REQUEST)); - } - - @NotNull - protected Optional getSessionAttribute(@NotNull final String key) { - return getRequestAttributes() - .map(attr -> attr.getAttribute(key, RequestAttributes.SCOPE_SESSION)); - } - - protected void setAttribute(@NotNull final String key, final Object value) { - getRequestAttributes() - .ifPresent(attr -> attr.setAttribute(key, value, RequestAttributes.SCOPE_REQUEST)); - } - - protected void setSessionAttribute(@NotNull final String key, final Object value) { - getRequestAttributes() - .ifPresent(attr -> attr.setAttribute(key, value, RequestAttributes.SCOPE_SESSION)); - } - - protected void removeAttribute(@NotNull final String key) { - getRequestAttributes() - .ifPresent(attr -> attr.removeAttribute(key, RequestAttributes.SCOPE_REQUEST)); - } - - protected void removeSessionAttribute(@NotNull final String key) { - getRequestAttributes() - .ifPresent(attr -> attr.removeAttribute(key, RequestAttributes.SCOPE_SESSION)); - }*/ -} diff --git a/app/src/main/java/com/elex_project/asgard/controller/NoteController.java b/app/src/main/java/com/elex_project/asgard/controller/DocumentController.java similarity index 86% rename from app/src/main/java/com/elex_project/asgard/controller/NoteController.java rename to app/src/main/java/com/elex_project/asgard/controller/DocumentController.java index 5f7c354..5e9688f 100644 --- a/app/src/main/java/com/elex_project/asgard/controller/NoteController.java +++ b/app/src/main/java/com/elex_project/asgard/controller/DocumentController.java @@ -7,27 +7,25 @@ package com.elex_project.asgard.controller; -import com.elex_project.asgard.service.NoteService; +import com.elex_project.asgard.service.DocumentService; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import java.net.URI; -import java.util.List; @Slf4j @Controller -public class NoteController extends BaseController { +public class DocumentController { @Autowired - private NoteService noteService; + private DocumentService documentService; /*@GetMapping(path = "/*") public ModelAndView reader(){ @@ -35,7 +33,7 @@ public class NoteController extends BaseController { return new ModelAndView("document", map()); }*/ @GetMapping(path = "/*") - public ModelAndView editor(@RequestParam boolean edit, ModelAndView model) { + public ModelAndView editor(@RequestParam(required = false) boolean edit, ModelAndView model) { if (edit) { model.setViewName("edit"); } else { diff --git a/app/src/main/java/com/elex_project/asgard/controller/HomeController.java b/app/src/main/java/com/elex_project/asgard/controller/HomeController.java index 8f0864b..b4f53d8 100644 --- a/app/src/main/java/com/elex_project/asgard/controller/HomeController.java +++ b/app/src/main/java/com/elex_project/asgard/controller/HomeController.java @@ -9,6 +9,7 @@ package com.elex_project.asgard.controller; import com.elex_project.asgard.service.SitemapService; import com.elex_project.asgard.service.SyndicationService; +import com.elex_project.asgard.syndication.SyndicationType; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -19,15 +20,13 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ResponseStatusException; import org.springframework.web.servlet.ModelAndView; -import java.util.Map; - /** * @link http://www.robotstxt.org/robotstxt.html * @link http://humanstxt.org/ */ @Slf4j @Controller -public class HomeController extends BaseController { +public class HomeController { @Autowired private SyndicationService syndicationService; @Autowired @@ -73,8 +72,7 @@ public class HomeController extends BaseController { @ResponseStatus(HttpStatus.OK) @ResponseBody public String rss() { - return syndicationService.getRssSyndication(); - //return "syndication/rss2"; + return syndicationService.getSyndication(SyndicationType.RSS_2); } /** @@ -86,7 +84,7 @@ public class HomeController extends BaseController { @ResponseStatus(HttpStatus.OK) @ResponseBody public String atom() { - return syndicationService.getAtomSyndication(); + return syndicationService.getSyndication(SyndicationType.ATOM); } @PostMapping(path = "/trackback/{id}", diff --git a/app/src/main/java/com/elex_project/asgard/controller/package-info.java b/app/src/main/java/com/elex_project/asgard/controller/package-info.java deleted file mode 100644 index 7c215e6..0000000 --- a/app/src/main/java/com/elex_project/asgard/controller/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Project Asgard - * - * Copyright (c) 2021. Elex. All Rights Reserved. - * https://www.elex-project.com/ - */ - -package com.elex_project.asgard.controller; diff --git a/app/src/main/java/com/elex_project/asgard/model/Note.java b/app/src/main/java/com/elex_project/asgard/model/Document.java similarity index 87% rename from app/src/main/java/com/elex_project/asgard/model/Note.java rename to app/src/main/java/com/elex_project/asgard/model/Document.java index 503d0db..21eb6b8 100644 --- a/app/src/main/java/com/elex_project/asgard/model/Note.java +++ b/app/src/main/java/com/elex_project/asgard/model/Document.java @@ -8,8 +8,7 @@ package com.elex_project.asgard.model; import com.elex_project.asgard.supplements.StringArrayConverter; -import lombok.Data; -import lombok.NoArgsConstructor; +import lombok.*; import lombok.extern.slf4j.Slf4j; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; @@ -18,11 +17,14 @@ import javax.persistence.*; import java.time.LocalDateTime; @Slf4j -@Data @NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@ToString @Entity -@Table(name = "notes") -public class Note { +@Table(name = "documents") +public class Document { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @@ -48,7 +50,7 @@ public class Note { @LastModifiedDate private LocalDateTime modifiedOn; - public static Note of(){ + public static Document of() { return null; } } diff --git a/app/src/main/java/com/elex_project/asgard/model/HttpTraceModel.java b/app/src/main/java/com/elex_project/asgard/model/HttpTraceModel.java deleted file mode 100644 index c29d2c1..0000000 --- a/app/src/main/java/com/elex_project/asgard/model/HttpTraceModel.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Project Asgard - * - * Copyright (c) 2021. Elex. All Rights Reserved. - * https://www.elex-project.com/ - */ - -package com.elex_project.asgard.model; - -import com.elex_project.asgard.supplements.InetAddressConverter; -import com.elex_project.asgard.supplements.StringArrayConverter; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -import javax.persistence.*; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.time.Duration; -import java.time.LocalDateTime; - -import static com.elex_project.asgard.supplements.RequestLogInterceptor.REQUEST_TIME; - -@Slf4j -@Data -@AllArgsConstructor -@NoArgsConstructor -@Entity -@Table(name = "http_trace") -public class HttpTraceModel { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private long id; - @Column - private LocalDateTime requestTime; - @Column - private Long elapsed; - @Column - private String requestUrl; - @Column - private String requestMethod; - @Column - private String userAgent; - @Column - private String referer; - @Column - @Convert(converter = StringArrayConverter.class) - private String[] acceptLang; - @Column - @Convert(converter = InetAddressConverter.class) - private InetAddress ipAddress; - - public static HttpTraceModel of(final HttpServletRequest request, final HttpServletResponse response) { - final HttpTraceModel model = new HttpTraceModel(); - model.requestUrl = request.getRequestURI(); - model.requestMethod = request.getMethod(); - model.userAgent = request.getHeader("User-Agent"); - model.referer = request.getHeader("Referer"); - - final String acceptLang = request.getHeader("Accept-Language"); - if (null != acceptLang) { - model.acceptLang = acceptLang.replaceAll(";q=[0-9.]*", "").split(","); - } else { - model.acceptLang = new String[0]; - } - - model.requestTime = (LocalDateTime) request.getAttribute(REQUEST_TIME); - if (null != model.requestTime) { - model.elapsed = Duration.between(model.requestTime, LocalDateTime.now()).toMillis(); - } - - String ip = request.getHeader("X-Forwarded-For"); - if (null == ip) ip = request.getHeader("X-Real-Ip"); - if (null == ip) ip = request.getRemoteAddr(); - try { - model.ipAddress = InetAddress.getByName(ip); - } catch (UnknownHostException ignore) { - } - return model; - } -} diff --git a/app/src/main/java/com/elex_project/asgard/model/package-info.java b/app/src/main/java/com/elex_project/asgard/model/package-info.java deleted file mode 100644 index d4e63f5..0000000 --- a/app/src/main/java/com/elex_project/asgard/model/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Project Asgard - * - * Copyright (c) 2021. Elex. All Rights Reserved. - * https://www.elex-project.com/ - */ - -package com.elex_project.asgard.model; diff --git a/app/src/main/java/com/elex_project/asgard/service/NoteService.java b/app/src/main/java/com/elex_project/asgard/service/DocumentService.java similarity index 89% rename from app/src/main/java/com/elex_project/asgard/service/NoteService.java rename to app/src/main/java/com/elex_project/asgard/service/DocumentService.java index 322de71..dd10c25 100644 --- a/app/src/main/java/com/elex_project/asgard/service/NoteService.java +++ b/app/src/main/java/com/elex_project/asgard/service/DocumentService.java @@ -12,5 +12,5 @@ import org.springframework.stereotype.Service; @Slf4j @Service -public class NoteService { +public class DocumentService { } diff --git a/app/src/main/java/com/elex_project/asgard/service/SitemapService.java b/app/src/main/java/com/elex_project/asgard/service/SitemapService.java index 2734d97..01d7994 100644 --- a/app/src/main/java/com/elex_project/asgard/service/SitemapService.java +++ b/app/src/main/java/com/elex_project/asgard/service/SitemapService.java @@ -13,8 +13,11 @@ import com.elex_project.asgard.sitemap.Sitemap; import com.elex_project.asgard.sitemap.SitemapItem; import lombok.extern.slf4j.Slf4j; import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; +import java.time.LocalDate; import java.time.LocalDateTime; @Slf4j @@ -25,6 +28,11 @@ public class SitemapService extends BaseSitemapService { @Override protected Sitemap sitemap() { final Sitemap sitemap = new Sitemap(); + sitemap.addItem(SitemapItem.builder() + .loc("https://www.elex-project.com/address-finder/") + .lastMod(LocalDate.of(2021,8,19).atStartOfDay()) + .changeFreq(Frequency.NEVER) + .build()); sitemap.addItem(SitemapItem.builder() .loc("https://aaa.com/1") .lastMod(LocalDateTime.now()) @@ -37,7 +45,13 @@ public class SitemapService extends BaseSitemapService { return sitemap; } - //@CacheEvict(allEntries = true) + @Cacheable + @Override + public String getSitemap() { + return super.getSitemap(); + } + + @CacheEvict(allEntries = true) public void clearCaches() { } diff --git a/app/src/main/java/com/elex_project/asgard/service/SyndicationService.java b/app/src/main/java/com/elex_project/asgard/service/SyndicationService.java index c0a62af..ce3f139 100644 --- a/app/src/main/java/com/elex_project/asgard/service/SyndicationService.java +++ b/app/src/main/java/com/elex_project/asgard/service/SyndicationService.java @@ -10,7 +10,11 @@ package com.elex_project.asgard.service; import com.elex_project.asgard.syndication.BaseSyndicationService; import com.elex_project.asgard.syndication.Syndication; import com.elex_project.asgard.syndication.SyndicationItem; +import com.elex_project.asgard.syndication.SyndicationType; import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.time.LocalDateTime; @@ -19,12 +23,16 @@ import java.util.List; import java.util.Locale; @Slf4j +@CacheConfig(cacheNames = "syndication") @Service -//@CacheConfig(cacheNames = "templates/syndication") public class SyndicationService extends BaseSyndicationService { + @Cacheable + @Override + public String getSyndication(SyndicationType type) { + return super.getSyndication(type); + } - - //@CacheEvict(allEntries = true) + @CacheEvict(allEntries = true) public void clearCaches() { } @@ -60,7 +68,7 @@ public class SyndicationService extends BaseSyndicationService { .url("https://something.com/2") .build()) .build(); - final List items = new ArrayList<>();// todo + final List items = new ArrayList<>();// todo read from db items.forEach(syndication::addItem); return syndication; } diff --git a/app/src/main/java/com/elex_project/asgard/service/package-info.java b/app/src/main/java/com/elex_project/asgard/service/package-info.java deleted file mode 100644 index 867b5bd..0000000 --- a/app/src/main/java/com/elex_project/asgard/service/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Project Asgard - * - * Copyright (c) 2021. Elex. All Rights Reserved. - * https://www.elex-project.com/ - */ - -package com.elex_project.asgard.service; diff --git a/app/src/main/java/com/elex_project/asgard/supplements/RequestLogInterceptor.java b/app/src/main/java/com/elex_project/asgard/supplements/RequestLogInterceptor.java index 0806657..a397728 100644 --- a/app/src/main/java/com/elex_project/asgard/supplements/RequestLogInterceptor.java +++ b/app/src/main/java/com/elex_project/asgard/supplements/RequestLogInterceptor.java @@ -7,7 +7,6 @@ package com.elex_project.asgard.supplements; -import com.elex_project.asgard.model.HttpTraceModel; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.web.servlet.HandlerInterceptor; @@ -15,11 +14,12 @@ import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.time.Duration; import java.time.LocalDateTime; @Slf4j public class RequestLogInterceptor implements HandlerInterceptor { - public static final String REQUEST_TIME = "elex.request.time"; + private static final String REQUEST_TIME = "elex.request.time"; @Override public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) @@ -37,8 +37,8 @@ public class RequestLogInterceptor implements HandlerInterceptor { @Override public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, Exception ex) throws Exception { - final HttpTraceModel traceModel = HttpTraceModel.of(request, response); - log.info("Http Trace: {}", traceModel); - + Duration elapsed = Duration + .between((LocalDateTime) request.getAttribute(REQUEST_TIME), LocalDateTime.now()); + log.info("Http Trace: {}", elapsed); } } diff --git a/app/src/main/java/com/elex_project/asgard/supplements/package-info.java b/app/src/main/java/com/elex_project/asgard/supplements/package-info.java deleted file mode 100644 index 71ab111..0000000 --- a/app/src/main/java/com/elex_project/asgard/supplements/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Project Asgard - * - * Copyright (c) 2021. Elex. All Rights Reserved. - * https://www.elex-project.com/ - */ - -package com.elex_project.asgard.supplements; diff --git a/app/src/main/java/com/elex_project/asgard/view/ViewModelInterceptor.java b/app/src/main/java/com/elex_project/asgard/view/ViewModelInterceptor.java index f941f3b..caba6f4 100644 --- a/app/src/main/java/com/elex_project/asgard/view/ViewModelInterceptor.java +++ b/app/src/main/java/com/elex_project/asgard/view/ViewModelInterceptor.java @@ -14,10 +14,13 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ViewModelInterceptor implements HandlerInterceptor { + @Override - public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception { if (null != modelAndView) { modelAndView.addObject("title", "Title~!!!"); } } + } diff --git a/app/src/main/java/com/elex_project/asgard/view/package-info.java b/app/src/main/java/com/elex_project/asgard/view/package-info.java deleted file mode 100644 index 72fdd86..0000000 --- a/app/src/main/java/com/elex_project/asgard/view/package-info.java +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Project Asgard - * - * Copyright (c) 2021. Elex. All Rights Reserved. - * https://www.elex-project.com/ - */ - -package com.elex_project.asgard.view; diff --git a/app/src/main/resources/static/humans.txt b/app/src/main/resources/static/humans.txt index c056dba..4519353 100644 --- a/app/src/main/resources/static/humans.txt +++ b/app/src/main/resources/static/humans.txt @@ -8,5 +8,5 @@ Name: /* SITE */ Front-end: HTML5, CSS3, Javascript, Material Design Components, Node-js(yarn, webpack, babel), Scss -Back-end: Spring-boot, Mustache, Hibernate +Back-end: Spring-boot, Mustache, Thymeleaf, Hibernate Server: Docker, MariaDB, Tomcat, Nginx, Linux diff --git a/app/src/main/resources/templates/document.html b/app/src/main/resources/templates/document.html index b078699..ded1bfb 100644 --- a/app/src/main/resources/templates/document.html +++ b/app/src/main/resources/templates/document.html @@ -1,14 +1,14 @@ - + - {{> fragments/meta}} + - {{title}} + {{title}} @@ -158,7 +158,7 @@

-