目前格式:HTML/XML
您完全可以在不依赖 Spring 的情况下,通过注解来使用 Java 缓存。下面介绍几种主流方案:
1. JCache(JSR-107)
JSR-107 是 Java 的标准缓存 API,任何兼容的缓存实现(如 Ehcache 3、Hazelcast、Infinispan、或 Caffeine+JCache 桥接)都支持注解驱动:
添加依赖
xml
複製
編輯
<!-- JCache API -->
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.1</version>
</dependency>
<!-- 以 Ehcache 为例的 JCache 实现 -->
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache-jcache</artifactId>
<version>3.10.0</version>
</dependency>
启动 CacheManager(Java SE 示例)
java
複製
編輯
import javax.cache.Caching;
import javax.cache.CacheManager;
import javax.cache.configuration.MutableConfiguration;
CachingProvider provider = Caching.getCachingProvider();
CacheManager cm = provider.getCacheManager();
MutableConfiguration<String, Book> cfg = new MutableConfiguration<>();
cm.createCache("books", cfg);
在方法上使用注解
java
複製
編輯
import javax.cache.annotation.CacheResult;
public class BookService {
@CacheResult(cacheName = "books")
public Book findBookByIsbn(String isbn) {
// … 昂贵的查询操作 …
}
}
启用注解拦截器
在 Jakarta EE 或任意 CDI 容器中,JCache 实现会自动注册对 @CacheResult 等注解的拦截支持。
在 纯 Java SE 环境下,可以启动一个 CDI 容器(如 Weld)来生效这些注解:
java
複製
編輯
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
Weld weld = new Weld();
try (WeldContainer c = weld.initialize()) {
BookService svc = c.select(BookService.class).get();
svc.findBookByIsbn("978–0134685991"); // 第一次查询后会被缓存
}
2. MicroProfile Caching
如果您使用支持 MicroProfile 的运行时(WildFly、Payara、Quarkus、Thorntail 等),可以使用 MicroProfile Caching API。它与 JCache 非常类似,注解包名为 org.eclipse.microprofile.caching。
添加依赖
xml
複製
編輯
<dependency>
<groupId>org.eclipse.microprofile.caching</groupId>
<artifactId>microprofile-caching-api</artifactId>
<version>1.0</version>
</dependency>
使用注解
java
複製
編輯
import org.eclipse.microprofile.caching.CacheResult;
public class WeatherClient {
@CacheResult(cacheName = "forecast")
public Forecast getForecast(String city) {
// … 请求天气预报 …
}
}
运行时会自动提供缓存拦截器和后端实现。
3. 其他轻量级库
cache2k
自带注解 @CacheResult(包名 org.cache2k.annotation)。
零配置、体积小、易嵌入。
自定义切面(例如结合 Caffeine + AspectJ)
定义自己的 @Cacheable(或自定义注解),通过 AOP 切面拦截并委托给 Caffeine 缓存。
小结
JSR-107(javax.cache):Java SE(借助 CDI)或 EE 容器通用标准,提供 @CacheResult、@CachePut、@CacheRemoveEntry 等注解。
MicroProfile Caching:在 MicroProfile 容器中使用,与 JCache 用法几乎一致。
cache2k 等轻量库:独立于 Spring、Jakarta EE,零 XML、零复杂依赖。
这些方案都能让您在不引入 Spring 的情况下,用注解优雅地驱动缓存功能。
你說:
介紹cache2k
ChatGPT 說:
已思考 2 秒鐘
以下是 cache2k 的完整介紹,涵蓋核心特性、依賴、程式化使用、注解支持及常見配置:
一、什麼是 cache2k
輕量、高效:完全用 Java 實現,無第三方依賴,jar 體積小(約 200KB)。
極低延遲:同步存取毫秒級別以下,適合延遲敏感應用。
豐富功能:支援時效(TTL)、刷新策略、容量限制、統計與監控。
二、核心特性
零配置即可啟用,也可程式化精細化調整
自動過期(Time To Live)與刷新(Refresh Ahead)
容量限制(Max Entries)與驅逐策略(LRU-based)
同步與異步載入(CacheLoader)
統計與 JMX:可開啟命中率、加載次數等監控
Annotation 模組:支援 @CacheResult 等
無需 CDI:在純 Java SE/EE 環境都能正常運作
三、Maven 依賴
xml
複製
編輯
<!-- 核心 -->
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-core</artifactId>
<version>2.8.0.Final</version>
</dependency>
<!-- (選用)注解支持 -->
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-annotation</artifactId>
<version>2.8.0.Final</version>
</dependency>
四、程式化使用範例
java
複製
編輯
import org.cache2k.Cache;
import org.cache2k.Cache2kBuilder;
public class Cache2kDemo {
// 建立一個最多 1000 筆、條目存活 5 分鐘的 Cache
Cache<String, String> cache = new Cache2kBuilder<String, String>() {}
.name("myCache")
.entryCapacity(1000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
public String getData(String key) {
// 如果不存在,回傳 null
return cache.peek(key);
}
public void putData(String key, String value) {
cache.put(key, value);
}
public void reloadData(String key) {
// 透過 CacheLoader 自動加載
cache.toCache(key);
}
}
如果要自動加載——
java
複製
編輯
Cache<String, User> userCache = new Cache2kBuilder<String, User>() {}
.name("userCache")
.entryCapacity(5000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.loader(key -> loadUserFromDb(key)) // CacheLoader
.build();
// 使用時,getOrLoad:若 cache 中無,則自動呼叫 loader
User u = userCache.get("alice");
五、注解支持(cache2k-annotation)
開啟注解模組
在 classpath 中加入 cache2k-annotation
使用 @CacheResult
java
複製
編輯
import org.cache2k.annotation.CacheResult;
public class WeatherService {
@CacheResult(cacheName = "forecast")
public Forecast getForecast(String city) {
// 實際呼叫遠端 API…
}
}
啟用 AOP/Interceptor
在 Spring 以外的環境,可使用 AspectJ 或自帶的拦截器(需透過 Cache2kAopConfig 或手動註冊 AOP)。
例如在 CDI/Jakarta EE 中,注解會自動生效;在純 Java SE,可透過 AspectJ weaving。
六、常見配置選項
配置 說明
name(...) Cache 名稱,用於統計與 JMX 匯出
entryCapacity(n) 最大條目數量
expireAfterWrite(t, unit) 寫入後自動過期時間
refreshAhead(t, unit) 到期前自動刷新(非阻塞)
eternal(true) 永久儲存,不過期
strictEviction(true) 嚴格容量限制,超過立即驅逐
loader(...) 指定同步載入資料的函式
asyncEnabled(true) 啟用非同步加載/刷新
monitoring() 啟用命中率、載入時間等統計
七、性能與使用場景
企業級服務:微服務間、API gateway、資料庫查詢結果緩存
實時系統:遊戲伺服器、金融行情、IoT 資料聚合
相較於 Guava Cache 延遲更低、併發更友好;對比 Caffeine 可提供 JCache 及註解整合更簡易;比 Redis 無網路開銷,適合單機場景。
八、延伸資源
官方網站與範例:https://cache2k.org/
GitHub:https://github.com/cache2k/cache2k
Javadoc:https://cache2k.org/apidocs/
5oKo5a6M5YWo5Y+v5Lul5Zyo5LiN5L6d6LWWIFNwcmluZyDnmoTmg4XlhrXkuIvvvIzpgJrov4fms6jop6PmnaXkvb/nlKggSmF2YSDnvJPlrZjjgILkuIvpnaLku4vnu43lh6Dnp43kuLvmtYHmlrnmoYjvvJoKCgoKMS4gSkNhY2hl77yISlNSLTEwN++8iQoKSlNSLTEwNyDmmK8gSmF2YSDnmoTmoIflh4bnvJPlrZggQVBJ77yM5Lu75L2V5YW85a6555qE57yT5a2Y5a6e546w77yI5aaCIEVoY2FjaGUgM+OAgUhhemVsY2FzdOOAgUluZmluaXNwYW7jgIHmiJYgQ2FmZmVpbmUrSkNhY2hlIOahpeaOpe+8iemDveaUr+aMgeazqOino+mpseWKqO+8mgoKCgrmt7vliqDkvp3otZYKCgoKeG1sCgropIfoo70KCue3qOi8rwoKPCEtLSBKQ2FjaGUgQVBJIC0tPgoKPGRlcGVuZGVuY3k+CgogIDxncm91cElkPmphdmF4LmNhY2hlPC9ncm91cElkPgoKICA8YXJ0aWZhY3RJZD5jYWNoZS1hcGk8L2FydGlmYWN0SWQ+CgogIDx2ZXJzaW9uPjEuMS4xPC92ZXJzaW9uPgoKPC9kZXBlbmRlbmN5PgoKPCEtLSDku6UgRWhjYWNoZSDkuLrkvovnmoQgSkNhY2hlIOWunueOsCAtLT4KCjxkZXBlbmRlbmN5PgoKICA8Z3JvdXBJZD5vcmcuZWhjYWNoZTwvZ3JvdXBJZD4KCiAgPGFydGlmYWN0SWQ+ZWhjYWNoZS1qY2FjaGU8L2FydGlmYWN0SWQ+CgogIDx2ZXJzaW9uPjMuMTAuMDwvdmVyc2lvbj4KCjwvZGVwZW5kZW5jeT4KCuWQr+WKqCBDYWNoZU1hbmFnZXLvvIhKYXZhIFNFIOekuuS+i++8iQoKCgpqYXZhCgropIfoo70KCue3qOi8rwoKaW1wb3J0IGphdmF4LmNhY2hlLkNhY2hpbmc7CgppbXBvcnQgamF2YXguY2FjaGUuQ2FjaGVNYW5hZ2VyOwoKaW1wb3J0IGphdmF4LmNhY2hlLmNvbmZpZ3VyYXRpb24uTXV0YWJsZUNvbmZpZ3VyYXRpb247CgoKCkNhY2hpbmdQcm92aWRlciBwcm92aWRlciA9IENhY2hpbmcuZ2V0Q2FjaGluZ1Byb3ZpZGVyKCk7CgpDYWNoZU1hbmFnZXIgY20gPSBwcm92aWRlci5nZXRDYWNoZU1hbmFnZXIoKTsKCk11dGFibGVDb25maWd1cmF0aW9uPFN0cmluZywgQm9vaz4gY2ZnID0gbmV3IE11dGFibGVDb25maWd1cmF0aW9uPD4oKTsKCmNtLmNyZWF0ZUNhY2hlKCJib29rcyIsIGNmZyk7CgrlnKjmlrnms5XkuIrkvb/nlKjms6jop6MKCgoKamF2YQoK6KSH6KO9Cgrnt6jovK8KCmltcG9ydCBqYXZheC5jYWNoZS5hbm5vdGF0aW9uLkNhY2hlUmVzdWx0OwoKCgpwdWJsaWMgY2xhc3MgQm9va1NlcnZpY2UgewoKICBAQ2FjaGVSZXN1bHQoY2FjaGVOYW1lID0gImJvb2tzIikKCiAgcHVibGljIEJvb2sgZmluZEJvb2tCeUlzYm4oU3RyaW5nIGlzYm4pIHsKCiAgICAvLyDigKYg5piC6LS155qE5p+l6K+i5pON5L2cIOKApgoKICB9Cgp9CgrlkK/nlKjms6jop6Pmi6bmiKrlmagKCgoK5ZyoIEpha2FydGEgRUUg5oiW5Lu75oSPIENESSDlrrnlmajkuK3vvIxKQ2FjaGUg5a6e546w5Lya6Ieq5Yqo5rOo5YaM5a+5IEBDYWNoZVJlc3VsdCDnrYnms6jop6PnmoTmi6bmiKrmlK/mjIHjgIIKCgoK5ZyoIOe6ryBKYXZhIFNFIOeOr+Wig+S4i++8jOWPr+S7peWQr+WKqOS4gOS4qiBDREkg5a655Zmo77yI5aaCIFdlbGTvvInmnaXnlJ/mlYjov5nkupvms6jop6PvvJoKCgoKamF2YQoK6KSH6KO9Cgrnt6jovK8KCmltcG9ydCBvcmcuamJvc3Mud2VsZC5lbnZpcm9ubWVudC5zZS5XZWxkOwoKaW1wb3J0IG9yZy5qYm9zcy53ZWxkLmVudmlyb25tZW50LnNlLldlbGRDb250YWluZXI7CgoKCldlbGQgd2VsZCA9IG5ldyBXZWxkKCk7Cgp0cnkgKFdlbGRDb250YWluZXIgYyA9IHdlbGQuaW5pdGlhbGl6ZSgpKSB7CgogIEJvb2tTZXJ2aWNlIHN2YyA9IGMuc2VsZWN0KEJvb2tTZXJ2aWNlLmNsYXNzKS5nZXQoKTsKCiAgc3ZjLmZpbmRCb29rQnlJc2JuKCI5NzjigJMwMTM0Njg1OTkxIik7ICAvLyDnrKzkuIDmrKHmn6Xor6LlkI7kvJrooqvnvJPlrZgKCn0KCjIuIE1pY3JvUHJvZmlsZSBDYWNoaW5nCgrlpoLmnpzmgqjkvb/nlKjmlK/mjIEgTWljcm9Qcm9maWxlIOeahOi/kOihjOaXtu+8iFdpbGRGbHnjgIFQYXlhcmHjgIFRdWFya3Vz44CBVGhvcm50YWlsIOetie+8ie+8jOWPr+S7peS9v+eUqCBNaWNyb1Byb2ZpbGUgQ2FjaGluZyBBUEnjgILlroPkuI4gSkNhY2hlIOmdnuW4uOexu+S8vO+8jOazqOino+WMheWQjeS4uiBvcmcuZWNsaXBzZS5taWNyb3Byb2ZpbGUuY2FjaGluZ+OAggoKCgrmt7vliqDkvp3otZYKCgoKeG1sCgropIfoo70KCue3qOi8rwoKPGRlcGVuZGVuY3k+CgogIDxncm91cElkPm9yZy5lY2xpcHNlLm1pY3JvcHJvZmlsZS5jYWNoaW5nPC9ncm91cElkPgoKICA8YXJ0aWZhY3RJZD5taWNyb3Byb2ZpbGUtY2FjaGluZy1hcGk8L2FydGlmYWN0SWQ+CgogIDx2ZXJzaW9uPjEuMDwvdmVyc2lvbj4KCjwvZGVwZW5kZW5jeT4KCuS9v+eUqOazqOinowoKCgpqYXZhCgropIfoo70KCue3qOi8rwoKaW1wb3J0IG9yZy5lY2xpcHNlLm1pY3JvcHJvZmlsZS5jYWNoaW5nLkNhY2hlUmVzdWx0OwoKCgpwdWJsaWMgY2xhc3MgV2VhdGhlckNsaWVudCB7CgogIEBDYWNoZVJlc3VsdChjYWNoZU5hbWUgPSAiZm9yZWNhc3QiKQoKICBwdWJsaWMgRm9yZWNhc3QgZ2V0Rm9yZWNhc3QoU3RyaW5nIGNpdHkpIHsKCiAgICAvLyDigKYg6K+35rGC5aSp5rCU6aKE5oqlIOKApgoKICB9Cgp9Cgrov5DooYzml7bkvJroh6rliqjmj5DkvpvnvJPlrZjmi6bmiKrlmajlkozlkI7nq6/lrp7njrDjgIIKCgoKMy4g5YW25LuW6L276YeP57qn5bqTCgpjYWNoZTJrCgoKCuiHquW4puazqOinoyBAQ2FjaGVSZXN1bHTvvIjljIXlkI0gb3JnLmNhY2hlMmsuYW5ub3RhdGlvbu+8ieOAggoKCgrpm7bphY3nva7jgIHkvZPnp6/lsI/jgIHmmJPltYzlhaXjgIIKCgoK6Ieq5a6a5LmJ5YiH6Z2i77yI5L6L5aaC57uT5ZCIIENhZmZlaW5lICsgQXNwZWN0Su+8iQoKCgrlrprkuYnoh6rlt7HnmoQgQENhY2hlYWJsZe+8iOaIluiHquWumuS5ieazqOino++8ie+8jOmAmui/hyBBT1Ag5YiH6Z2i5oum5oiq5bm25aeU5omY57uZIENhZmZlaW5lIOe8k+WtmOOAggoKCgrlsI/nu5MKCkpTUi0xMDfvvIhqYXZheC5jYWNoZe+8ie+8mkphdmEgU0XvvIjlgJ/liqkgQ0RJ77yJ5oiWIEVFIOWuueWZqOmAmueUqOagh+WHhu+8jOaPkOS+myBAQ2FjaGVSZXN1bHTjgIFAQ2FjaGVQdXTjgIFAQ2FjaGVSZW1vdmVFbnRyeSDnrYnms6jop6PjgIIKCgoKTWljcm9Qcm9maWxlIENhY2hpbmfvvJrlnKggTWljcm9Qcm9maWxlIOWuueWZqOS4reS9v+eUqO+8jOS4jiBKQ2FjaGUg55So5rOV5Yeg5LmO5LiA6Ie044CCCgoKCmNhY2hlMmsg562J6L276YeP5bqT77ya54us56uL5LqOIFNwcmluZ+OAgUpha2FydGEgRUXvvIzpm7YgWE1M44CB6Zu25aSN5p2C5L6d6LWW44CCCgoKCui/meS6m+aWueahiOmDveiDveiuqeaCqOWcqOS4jeW8leWFpSBTcHJpbmcg55qE5oOF5Ya15LiL77yM55So5rOo6Kej5LyY6ZuF5Zyw6amx5Yqo57yT5a2Y5Yqf6IO944CCCgoKCgoKCgoKCgoKCgoKCgoK5L2g6Kqq77yaCgrku4vntLljYWNoZTJrCgoKCgoKQ2hhdEdQVCDoqqrvvJoKCgoK5bey5oCd6ICDIDIg56eS6ZCYCgrku6XkuIvmmK8gY2FjaGUyayDnmoTlrozmlbTku4vntLnvvIzmtrXok4vmoLjlv4PnibnmgKfjgIHkvp3os7TjgIHnqIvlvI/ljJbkvb/nlKjjgIHms6jop6PmlK/mjIHlj4rluLjopovphY3nva7vvJoKCgoK5LiA44CB5LuA6bq85pivIGNhY2hlMmsKCui8lemHj+OAgemrmOaViO+8muWujOWFqOeUqCBKYXZhIOWvpuePvu+8jOeEoeesrOS4ieaWueS+neiztO+8jGphciDpq5TnqY3lsI/vvIjntIQgMjAwS0LvvInjgIIKCgoK5qW15L2O5bu26YGy77ya5ZCM5q2l5a2Y5Y+W5q+r56eS57Sa5Yil5Lul5LiL77yM6YGp5ZCI5bu26YGy5pWP5oSf5oeJ55So44CCCgoKCuixkOWvjOWKn+iDve+8muaUr+aPtOaZguaViO+8iFRUTO+8ieOAgeWIt+aWsOetlueVpeOAgeWuuemHj+mZkOWItuOAgee1seioiOiIh+ebo+aOp+OAggoKCgrkuozjgIHmoLjlv4PnibnmgKcKCumbtumFjee9ruWNs+WPr+WVn+eUqO+8jOS5n+WPr+eoi+W8j+WMlueyvue0sOWMluiqv+aVtAoKCgroh6rli5XpgY7mnJ/vvIhUaW1lIFRvIExpdmXvvInoiIfliLfmlrDvvIhSZWZyZXNoIEFoZWFk77yJCgoKCuWuuemHj+mZkOWItu+8iE1heCBFbnRyaWVz77yJ6IiH6amF6YCQ562W55Wl77yITFJVLWJhc2Vk77yJCgoKCuWQjOatpeiIh+eVsOatpei8ieWFpe+8iENhY2hlTG9hZGVy77yJCgoKCue1seioiOiIhyBKTVjvvJrlj6/plovllZ/lkb3kuK3njofjgIHliqDovInmrKHmlbjnrYnnm6PmjqcKCgoKQW5ub3RhdGlvbiDmqKHntYTvvJrmlK/mj7QgQENhY2hlUmVzdWx0IOetiQoKCgrnhKHpnIAgQ0RJ77ya5Zyo57SUIEphdmEgU0UvRUUg55Kw5aKD6YO96IO95q2j5bi46YGL5L2cCgoKCuS4ieOAgU1hdmVuIOS+neiztAoKeG1sCgropIfoo70KCue3qOi8rwoKPCEtLSDmoLjlv4MgLS0+Cgo8ZGVwZW5kZW5jeT4KCiAgPGdyb3VwSWQ+b3JnLmNhY2hlMms8L2dyb3VwSWQ+CgogIDxhcnRpZmFjdElkPmNhY2hlMmstY29yZTwvYXJ0aWZhY3RJZD4KCiAgPHZlcnNpb24+Mi44LjAuRmluYWw8L3ZlcnNpb24+Cgo8L2RlcGVuZGVuY3k+Cgo8IS0tIO+8iOmBuOeUqO+8ieazqOino+aUr+aMgSAtLT4KCjxkZXBlbmRlbmN5PgoKICA8Z3JvdXBJZD5vcmcuY2FjaGUyazwvZ3JvdXBJZD4KCiAgPGFydGlmYWN0SWQ+Y2FjaGUyay1hbm5vdGF0aW9uPC9hcnRpZmFjdElkPgoKICA8dmVyc2lvbj4yLjguMC5GaW5hbDwvdmVyc2lvbj4KCjwvZGVwZW5kZW5jeT4KCuWbm+OAgeeoi+W8j+WMluS9v+eUqOevhOS+iwoKamF2YQoK6KSH6KO9Cgrnt6jovK8KCmltcG9ydCBvcmcuY2FjaGUyay5DYWNoZTsKCmltcG9ydCBvcmcuY2FjaGUyay5DYWNoZTJrQnVpbGRlcjsKCgoKcHVibGljIGNsYXNzIENhY2hlMmtEZW1vIHsKCiAgLy8g5bu656uL5LiA5YCL5pyA5aSaIDEwMDAg562G44CB5qKd55uu5a2Y5rS7IDUg5YiG6ZCY55qEIENhY2hlCgogIENhY2hlPFN0cmluZywgU3RyaW5nPiBjYWNoZSA9IG5ldyBDYWNoZTJrQnVpbGRlcjxTdHJpbmcsIFN0cmluZz4oKSB7fQoKICAgIC5uYW1lKCJteUNhY2hlIikKCiAgICAuZW50cnlDYXBhY2l0eSgxMDAwKQoKICAgIC5leHBpcmVBZnRlcldyaXRlKDUsIFRpbWVVbml0Lk1JTlVURVMpCgogICAgLmJ1aWxkKCk7CgoKCiAgcHVibGljIFN0cmluZyBnZXREYXRhKFN0cmluZyBrZXkpIHsKCiAgICAvLyDlpoLmnpzkuI3lrZjlnKjvvIzlm57lgrMgbnVsbAoKICAgIHJldHVybiBjYWNoZS5wZWVrKGtleSk7CgogIH0KCgoKICBwdWJsaWMgdm9pZCBwdXREYXRhKFN0cmluZyBrZXksIFN0cmluZyB2YWx1ZSkgewoKICAgIGNhY2hlLnB1dChrZXksIHZhbHVlKTsKCiAgfQoKCgogIHB1YmxpYyB2b2lkIHJlbG9hZERhdGEoU3RyaW5nIGtleSkgewoKICAgIC8vIOmAj+mBjiBDYWNoZUxvYWRlciDoh6rli5XliqDovIkKCiAgICBjYWNoZS50b0NhY2hlKGtleSk7CgogIH0KCn0KCuWmguaenOimgeiHquWLleWKoOi8ieKAlOKAlAoKCgpqYXZhCgropIfoo70KCue3qOi8rwoKQ2FjaGU8U3RyaW5nLCBVc2VyPiB1c2VyQ2FjaGUgPSBuZXcgQ2FjaGUya0J1aWxkZXI8U3RyaW5nLCBVc2VyPigpIHt9CgogIC5uYW1lKCJ1c2VyQ2FjaGUiKQoKICAuZW50cnlDYXBhY2l0eSg1MDAwKQoKICAuZXhwaXJlQWZ0ZXJXcml0ZSgxMCwgVGltZVVuaXQuTUlOVVRFUykKCiAgLmxvYWRlcihrZXkgLT4gbG9hZFVzZXJGcm9tRGIoa2V5KSkgIC8vIENhY2hlTG9hZGVyCgogIC5idWlsZCgpOwoKCgovLyDkvb/nlKjmmYLvvIxnZXRPckxvYWTvvJroi6UgY2FjaGUg5Lit54Sh77yM5YmH6Ieq5YuV5ZG85Y+rIGxvYWRlcgoKVXNlciB1ID0gdXNlckNhY2hlLmdldCgiYWxpY2UiKTsKCuS6lOOAgeazqOino+aUr+aMge+8iGNhY2hlMmstYW5ub3RhdGlvbu+8iQoK6ZaL5ZWf5rOo6Kej5qih57WECgoKCuWcqCBjbGFzc3BhdGgg5Lit5Yqg5YWlIGNhY2hlMmstYW5ub3RhdGlvbgoKCgrkvb/nlKggQENhY2hlUmVzdWx0CgoKCmphdmEKCuikh+ijvQoK57eo6LyvCgppbXBvcnQgb3JnLmNhY2hlMmsuYW5ub3RhdGlvbi5DYWNoZVJlc3VsdDsKCgoKcHVibGljIGNsYXNzIFdlYXRoZXJTZXJ2aWNlIHsKCiAgQENhY2hlUmVzdWx0KGNhY2hlTmFtZSA9ICJmb3JlY2FzdCIpCgogIHB1YmxpYyBGb3JlY2FzdCBnZXRGb3JlY2FzdChTdHJpbmcgY2l0eSkgewoKICAgIC8vIOWvpumam+WRvOWPq+mBoOerryBBUEnigKYKCiAgfQoKfQoK5ZWf55SoIEFPUC9JbnRlcmNlcHRvcgoKCgrlnKggU3ByaW5nIOS7peWklueahOeSsOWig++8jOWPr+S9v+eUqCBBc3BlY3RKIOaIluiHquW4tueahOaLpuaIquWZqO+8iOmcgOmAj+mBjiBDYWNoZTJrQW9wQ29uZmlnIOaIluaJi+WLleiou+WGiiBBT1DvvInjgIIKCgoK5L6L5aaC5ZyoIENESe+8j0pha2FydGEgRUUg5Lit77yM5rOo6Kej5pyD6Ieq5YuV55Sf5pWI77yb5Zyo57SUIEphdmEgU0XvvIzlj6/pgI/pgY4gQXNwZWN0SiB3ZWF2aW5n44CCCgoKCuWFreOAgeW4uOimi+mFjee9rumBuOmghQoK6YWN572uCeiqquaYjgoKbmFtZSguLi4pCUNhY2hlIOWQjeeose+8jOeUqOaWvOe1seioiOiIhyBKTVgg5Yyv5Ye6CgplbnRyeUNhcGFjaXR5KG4pCeacgOWkp+aineebruaVuOmHjwoKZXhwaXJlQWZ0ZXJXcml0ZSh0LCB1bml0KQnlr6vlhaXlvozoh6rli5XpgY7mnJ/mmYLplpMKCnJlZnJlc2hBaGVhZCh0LCB1bml0KQnliLDmnJ/liY3oh6rli5XliLfmlrDvvIjpnZ7pmLvloZ7vvIkKCmV0ZXJuYWwodHJ1ZSkJ5rC45LmF5YSy5a2Y77yM5LiN6YGO5pyfCgpzdHJpY3RFdmljdGlvbih0cnVlKQnlmrTmoLzlrrnph4/pmZDliLbvvIzotoXpgY7nq4vljbPpqYXpgJAKCmxvYWRlciguLi4pCeaMh+WumuWQjOatpei8ieWFpeizh+aWmeeahOWHveW8jwoKYXN5bmNFbmFibGVkKHRydWUpCeWVn+eUqOmdnuWQjOatpeWKoOi8iS/liLfmlrAKCm1vbml0b3JpbmcoKQnllZ/nlKjlkb3kuK3njofjgIHovInlhaXmmYLplpPnrYnntbHoqIgKCgoK5LiD44CB5oCn6IO96IiH5L2/55So5aC05pmvCgrkvIHmpa3ntJrmnI3li5nvvJrlvq7mnI3li5nplpPjgIFBUEkgZ2F0ZXdheeOAgeizh+aWmeW6q+afpeipoue1kOaenOe3qeWtmAoKCgrlr6bmmYLns7vntbHvvJrpgYrmiLLkvLrmnI3lmajjgIHph5Hono3ooYzmg4XjgIFJb1Qg6LOH5paZ6IGa5ZCICgoKCuebuOi8g+aWvCBHdWF2YSBDYWNoZSDlu7bpgbLmm7TkvY7jgIHkvbXnmbzmm7Tlj4vlpb3vvJvlsI3mr5QgQ2FmZmVpbmUg5Y+v5o+Q5L6bIEpDYWNoZSDlj4roqLvop6PmlbTlkIjmm7TnsKHmmJPvvJvmr5QgUmVkaXMg54Sh57ay6Lev6ZaL6Yq377yM6YGp5ZCI5Zau5qmf5aC05pmv44CCCgoKCuWFq+OAgeW7tuS8uOizh+a6kAoK5a6Y5pa557ay56uZ6IiH56+E5L6L77yaaHR0cHM6Ly9jYWNoZTJrLm9yZy8KCgoKR2l0SHVi77yaaHR0cHM6Ly9naXRodWIuY29tL2NhY2hlMmsvY2FjaGUyawoKCgpKYXZhZG9j77yaaHR0cHM6Ly9jYWNoZTJrLm9yZy9hcGlkb2NzLwo=