// 取得搜尋資料(0: content only, 1: content + attach, 2: attach only)
public LinkedHashMap<Integer, LinkedHashMap<String, String>>
getSearchContent(Integer iftSid, String strTxt, String userType) throws RemoteException {
LinkedHashMap<Integer, LinkedHashMap<String, String>> map = new LinkedHashMap<>();
LinkedHashMap<String, String> seen = new LinkedHashMap<>(); // de-dup by ifq_sid
int count = 0;
// results for content and attachments
WsGetFullTextSearchResponseWsGetFullTextSearchResult result = null;
WsGetAttachSearchResponseWsGetAttachSearchResult attachResult = null;
// --- call services (keep your logs) ---
switch (iftSid) {
case 0:
result = service.wsGetFullTextSearch(strValidCode, 1, channelMap.get(userType), 100, strTxt, 0, "fq_hit");
LOGGER.info(vaildLog("### method:getSearchContent, webservice:wsGetFullTextSearch"));
LOGGER.info(vaildLog("### req:" + "wsGetFullTextSearch(" + strValidCode + ", 1, "
+ channelMap.get(userType) + ", 100, " + strTxt + ", 0, fq_hit)"));
break;
case 1:
result = service.wsGetFullTextSearch(strValidCode, 1, channelMap.get(userType), 100, strTxt, 0, "fq_hit");
LOGGER.info(vaildLog("### method:getSearchContent, webservice:wsGetFullTextSearch"));
LOGGER.info(vaildLog("### req:" + "wsGetFullTextSearch(" + strValidCode + ", 1, "
+ channelMap.get(userType) + ", 100, " + strTxt + ", 0, fq_hit)"));
attachResult = service.wsGetAttachSearch(strValidCode, 1, channelMap.get(userType), 100, strTxt, 0);
LOGGER.info(vaildLog("### method:getSearchContent, webservice:wsGetAttachSearch"));
LOGGER.info(vaildLog("### req:" + "wsGetAttachSearch(" + strValidCode + ", 1, "
+ channelMap.get(userType) + ", 100, " + strTxt + ", 0)"));
break;
case 2:
attachResult = service.wsGetAttachSearch(strValidCode, 1, channelMap.get(userType), 100, strTxt, 0);
LOGGER.info(vaildLog("### method:getSearchContent, webservice:wsGetAttachSearch"));
LOGGER.info(vaildLog("### req:" + "wsGetAttachSearch(" + strValidCode + ", 1, "
+ channelMap.get(userType) + ", 100, " + strTxt + ", 0)"));
break;
default:
return map;
}
// --- parse content results (reverse order as your original code) ---
if (result != null) {
MessageElement[] anyArr = result.get_any();
LOGGER.info(vaildLog("### data:" + (anyArr != null && anyArr.length > 0 ? anyArr[0] : "null")));
Element diffgram = pickDiffgram(anyArr);
if (diffgram != null) {
Element dataRoot = firstChildElementByLocalName(diffgram, "IQKB");
if (dataRoot == null) dataRoot = diffgram;
// collect pairs; reverse = true (iterate from tail to head)
List<Map.Entry<String, String>> pairs = collectSidNamePairs(dataRoot, true);
for (Map.Entry<String, String> e : pairs) {
String sid = e.getKey(), name = e.getValue();
if (!seen.containsKey(sid)) {
seen.put(sid, name);
LinkedHashMap<String, String> mt = new LinkedHashMap<>();
mt.put(sid, name);
map.put(count++, mt);
}
}
}
}
// --- parse attachment results (normal order) ---
if (attachResult != null) {
MessageElement[] anyArr = attachResult.get_any();
Element diffgram = pickDiffgram(anyArr);
if (diffgram != null) {
Element dataRoot = firstChildElementByLocalName(diffgram, "IQKB");
if (dataRoot == null) dataRoot = diffgram;
List<Map.Entry<String, String>> pairs = collectSidNamePairs(dataRoot, false);
for (Map.Entry<String, String> e : pairs) {
String sid = e.getKey(), name = e.getValue();
if (!seen.containsKey(sid)) {
seen.put(sid, name);
LinkedHashMap<String, String> ma = new LinkedHashMap<>();
ma.put(sid, name);
map.put(count++, ma);
}
}
}
}
return map;
}
/* ===================== helpers (English comments) ===================== */
/** Pick the <diffgram> element from MessageElement[], skipping schema */
private static Element pickDiffgram(MessageElement[] anyArr) {
if (anyArr == null) return null;
for (MessageElement me : anyArr) {
String ln = me.getLocalName();
if ("diffgram".equalsIgnoreCase(ln)) return me;
}
return null;
}
/** Find first child element by local or node name (ignores prefix) */
private static Element firstChildElementByLocalName(Element parent, String local) {
if (parent == null) return null;
for (Node n = parent.getFirstChild(); n != null; n = n.getNextSibling()) {
if (n.getNodeType() == Node.ELEMENT_NODE) {
String ln = n.getLocalName();
String nn = n.getNodeName();
if (local.equals(nn) || local.equalsIgnoreCase(ln)) return (Element) n;
}
}
return null;
}
/**
* Collect (ifq_sid -> sfq_name) pairs under dataRoot.
* Robust approach: query both NodeLists and pair by index.
* `reverse=true` iterates from tail to head to mimic your original order.
*/
private static List<Map.Entry<String, String>> collectSidNamePairs(Element dataRoot, boolean reverse) {
List<Map.Entry<String, String>> out = new ArrayList<>();
if (dataRoot == null) return out;
NodeList nameNodes = dataRoot.getElementsByTagName("sfq_name");
NodeList sidNodes = dataRoot.getElementsByTagName("ifq_sid");
int n = Math.min(nameNodes.getLength(), sidNodes.getLength());
if (n <= 0) return out;
if (reverse) {
for (int i = n - 1; i >= 0; i--) {
String name = getNodeTextCompat(nameNodes.item(i)).trim();
String sid = getNodeTextCompat(sidNodes.item(i)).trim();
if (!sid.isEmpty()) out.add(Map.entry(sid, name));
}
} else {
for (int i = 0; i < n; i++) {
String name = getNodeTextCompat(nameNodes.item(i)).trim();
String sid = getNodeTextCompat(sidNodes.item(i)).trim();
if (!sid.isEmpty()) out.add(Map.entry(sid, name));
}
}
return out;
}
/** Axis-compatible text extraction (TEXT_NODE/CDATA only) */
private static String getNodeTextCompat(Node node) {
if (node == null) return "";
StringBuilder sb = new StringBuilder();
NodeList cs = node.getChildNodes();
for (int i = 0; i < cs.getLength(); i++) {
Node c = cs.item(i);
short t = c.getNodeType();
if (t == Node.TEXT_NODE || t == Node.CDATA_SECTION_NODE) {
sb.append(c.getNodeValue());
}
}
return sb.toString();
}
Ly8g5Y+W5b6X5pCc5bCL6LOH5paZ77yIMDogY29udGVudCBvbmx5LCAxOiBjb250ZW50ICsgYXR0YWNoLCAyOiBhdHRhY2ggb25see+8iQoKcHVibGljIExpbmtlZEhhc2hNYXA8SW50ZWdlciwgTGlua2VkSGFzaE1hcDxTdHJpbmcsIFN0cmluZz4+CgpnZXRTZWFyY2hDb250ZW50KEludGVnZXIgaWZ0U2lkLCBTdHJpbmcgc3RyVHh0LCBTdHJpbmcgdXNlclR5cGUpIHRocm93cyBSZW1vdGVFeGNlcHRpb24gewoKCgogICAgTGlua2VkSGFzaE1hcDxJbnRlZ2VyLCBMaW5rZWRIYXNoTWFwPFN0cmluZywgU3RyaW5nPj4gbWFwID0gbmV3IExpbmtlZEhhc2hNYXA8PigpOwoKICAgIExpbmtlZEhhc2hNYXA8U3RyaW5nLCBTdHJpbmc+IHNlZW4gPSBuZXcgTGlua2VkSGFzaE1hcDw+KCk7IC8vIGRlLWR1cCBieSBpZnFfc2lkCgogICAgaW50IGNvdW50ID0gMDsKCgoKICAgIC8vIHJlc3VsdHMgZm9yIGNvbnRlbnQgYW5kIGF0dGFjaG1lbnRzCgogICAgV3NHZXRGdWxsVGV4dFNlYXJjaFJlc3BvbnNlV3NHZXRGdWxsVGV4dFNlYXJjaFJlc3VsdCByZXN1bHQgPSBudWxsOwoKICAgIFdzR2V0QXR0YWNoU2VhcmNoUmVzcG9uc2VXc0dldEF0dGFjaFNlYXJjaFJlc3VsdCBhdHRhY2hSZXN1bHQgPSBudWxsOwoKCgogICAgLy8gLS0tIGNhbGwgc2VydmljZXMgKGtlZXAgeW91ciBsb2dzKSAtLS0KCiAgICBzd2l0Y2ggKGlmdFNpZCkgewoKICAgICAgICBjYXNlIDA6CgogICAgICAgICAgICByZXN1bHQgPSBzZXJ2aWNlLndzR2V0RnVsbFRleHRTZWFyY2goc3RyVmFsaWRDb2RlLCAxLCBjaGFubmVsTWFwLmdldCh1c2VyVHlwZSksIDEwMCwgc3RyVHh0LCAwLCAiZnFfaGl0Iik7CgogICAgICAgICAgICBMT0dHRVIuaW5mbyh2YWlsZExvZygiIyMjIG1ldGhvZDpnZXRTZWFyY2hDb250ZW50LCB3ZWJzZXJ2aWNlOndzR2V0RnVsbFRleHRTZWFyY2giKSk7CgogICAgICAgICAgICBMT0dHRVIuaW5mbyh2YWlsZExvZygiIyMjIHJlcToiICsgIndzR2V0RnVsbFRleHRTZWFyY2goIiArIHN0clZhbGlkQ29kZSArICIsIDEsICIKCiAgICAgICAgICAgICAgICAgICAgKyBjaGFubmVsTWFwLmdldCh1c2VyVHlwZSkgKyAiLCAxMDAsICIgKyBzdHJUeHQgKyAiLCAwLCBmcV9oaXQpIikpOwoKICAgICAgICAgICAgYnJlYWs7CgogICAgICAgIGNhc2UgMToKCiAgICAgICAgICAgIHJlc3VsdCA9IHNlcnZpY2Uud3NHZXRGdWxsVGV4dFNlYXJjaChzdHJWYWxpZENvZGUsIDEsIGNoYW5uZWxNYXAuZ2V0KHVzZXJUeXBlKSwgMTAwLCBzdHJUeHQsIDAsICJmcV9oaXQiKTsKCiAgICAgICAgICAgIExPR0dFUi5pbmZvKHZhaWxkTG9nKCIjIyMgbWV0aG9kOmdldFNlYXJjaENvbnRlbnQsIHdlYnNlcnZpY2U6d3NHZXRGdWxsVGV4dFNlYXJjaCIpKTsKCiAgICAgICAgICAgIExPR0dFUi5pbmZvKHZhaWxkTG9nKCIjIyMgcmVxOiIgKyAid3NHZXRGdWxsVGV4dFNlYXJjaCgiICsgc3RyVmFsaWRDb2RlICsgIiwgMSwgIgoKICAgICAgICAgICAgICAgICAgICArIGNoYW5uZWxNYXAuZ2V0KHVzZXJUeXBlKSArICIsIDEwMCwgIiArIHN0clR4dCArICIsIDAsIGZxX2hpdCkiKSk7CgoKCiAgICAgICAgICAgIGF0dGFjaFJlc3VsdCA9IHNlcnZpY2Uud3NHZXRBdHRhY2hTZWFyY2goc3RyVmFsaWRDb2RlLCAxLCBjaGFubmVsTWFwLmdldCh1c2VyVHlwZSksIDEwMCwgc3RyVHh0LCAwKTsKCiAgICAgICAgICAgIExPR0dFUi5pbmZvKHZhaWxkTG9nKCIjIyMgbWV0aG9kOmdldFNlYXJjaENvbnRlbnQsIHdlYnNlcnZpY2U6d3NHZXRBdHRhY2hTZWFyY2giKSk7CgogICAgICAgICAgICBMT0dHRVIuaW5mbyh2YWlsZExvZygiIyMjIHJlcToiICsgIndzR2V0QXR0YWNoU2VhcmNoKCIgKyBzdHJWYWxpZENvZGUgKyAiLCAxLCAiCgogICAgICAgICAgICAgICAgICAgICsgY2hhbm5lbE1hcC5nZXQodXNlclR5cGUpICsgIiwgMTAwLCAiICsgc3RyVHh0ICsgIiwgMCkiKSk7CgogICAgICAgICAgICBicmVhazsKCiAgICAgICAgY2FzZSAyOgoKICAgICAgICAgICAgYXR0YWNoUmVzdWx0ID0gc2VydmljZS53c0dldEF0dGFjaFNlYXJjaChzdHJWYWxpZENvZGUsIDEsIGNoYW5uZWxNYXAuZ2V0KHVzZXJUeXBlKSwgMTAwLCBzdHJUeHQsIDApOwoKICAgICAgICAgICAgTE9HR0VSLmluZm8odmFpbGRMb2coIiMjIyBtZXRob2Q6Z2V0U2VhcmNoQ29udGVudCwgd2Vic2VydmljZTp3c0dldEF0dGFjaFNlYXJjaCIpKTsKCiAgICAgICAgICAgIExPR0dFUi5pbmZvKHZhaWxkTG9nKCIjIyMgcmVxOiIgKyAid3NHZXRBdHRhY2hTZWFyY2goIiArIHN0clZhbGlkQ29kZSArICIsIDEsICIKCiAgICAgICAgICAgICAgICAgICAgKyBjaGFubmVsTWFwLmdldCh1c2VyVHlwZSkgKyAiLCAxMDAsICIgKyBzdHJUeHQgKyAiLCAwKSIpKTsKCiAgICAgICAgICAgIGJyZWFrOwoKICAgICAgICBkZWZhdWx0OgoKICAgICAgICAgICAgcmV0dXJuIG1hcDsKCiAgICB9CgoKCiAgICAvLyAtLS0gcGFyc2UgY29udGVudCByZXN1bHRzIChyZXZlcnNlIG9yZGVyIGFzIHlvdXIgb3JpZ2luYWwgY29kZSkgLS0tCgogICAgaWYgKHJlc3VsdCAhPSBudWxsKSB7CgogICAgICAgIE1lc3NhZ2VFbGVtZW50W10gYW55QXJyID0gcmVzdWx0LmdldF9hbnkoKTsKCiAgICAgICAgTE9HR0VSLmluZm8odmFpbGRMb2coIiMjIyBkYXRhOiIgKyAoYW55QXJyICE9IG51bGwgJiYgYW55QXJyLmxlbmd0aCA+IDAgPyBhbnlBcnJbMF0gOiAibnVsbCIpKSk7CgogICAgICAgIEVsZW1lbnQgZGlmZmdyYW0gPSBwaWNrRGlmZmdyYW0oYW55QXJyKTsKCiAgICAgICAgaWYgKGRpZmZncmFtICE9IG51bGwpIHsKCiAgICAgICAgICAgIEVsZW1lbnQgZGF0YVJvb3QgPSBmaXJzdENoaWxkRWxlbWVudEJ5TG9jYWxOYW1lKGRpZmZncmFtLCAiSVFLQiIpOwoKICAgICAgICAgICAgaWYgKGRhdGFSb290ID09IG51bGwpIGRhdGFSb290ID0gZGlmZmdyYW07CgoKCiAgICAgICAgICAgIC8vIGNvbGxlY3QgcGFpcnM7IHJldmVyc2UgPSB0cnVlIChpdGVyYXRlIGZyb20gdGFpbCB0byBoZWFkKQoKICAgICAgICAgICAgTGlzdDxNYXAuRW50cnk8U3RyaW5nLCBTdHJpbmc+PiBwYWlycyA9IGNvbGxlY3RTaWROYW1lUGFpcnMoZGF0YVJvb3QsIHRydWUpOwoKICAgICAgICAgICAgZm9yIChNYXAuRW50cnk8U3RyaW5nLCBTdHJpbmc+IGUgOiBwYWlycykgewoKICAgICAgICAgICAgICAgIFN0cmluZyBzaWQgPSBlLmdldEtleSgpLCBuYW1lID0gZS5nZXRWYWx1ZSgpOwoKICAgICAgICAgICAgICAgIGlmICghc2Vlbi5jb250YWluc0tleShzaWQpKSB7CgogICAgICAgICAgICAgICAgICAgIHNlZW4ucHV0KHNpZCwgbmFtZSk7CgogICAgICAgICAgICAgICAgICAgIExpbmtlZEhhc2hNYXA8U3RyaW5nLCBTdHJpbmc+IG10ID0gbmV3IExpbmtlZEhhc2hNYXA8PigpOwoKICAgICAgICAgICAgICAgICAgICBtdC5wdXQoc2lkLCBuYW1lKTsKCiAgICAgICAgICAgICAgICAgICAgbWFwLnB1dChjb3VudCsrLCBtdCk7CgogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgfQoKICAgICAgICB9CgogICAgfQoKCgogICAgLy8gLS0tIHBhcnNlIGF0dGFjaG1lbnQgcmVzdWx0cyAobm9ybWFsIG9yZGVyKSAtLS0KCiAgICBpZiAoYXR0YWNoUmVzdWx0ICE9IG51bGwpIHsKCiAgICAgICAgTWVzc2FnZUVsZW1lbnRbXSBhbnlBcnIgPSBhdHRhY2hSZXN1bHQuZ2V0X2FueSgpOwoKICAgICAgICBFbGVtZW50IGRpZmZncmFtID0gcGlja0RpZmZncmFtKGFueUFycik7CgogICAgICAgIGlmIChkaWZmZ3JhbSAhPSBudWxsKSB7CgogICAgICAgICAgICBFbGVtZW50IGRhdGFSb290ID0gZmlyc3RDaGlsZEVsZW1lbnRCeUxvY2FsTmFtZShkaWZmZ3JhbSwgIklRS0IiKTsKCiAgICAgICAgICAgIGlmIChkYXRhUm9vdCA9PSBudWxsKSBkYXRhUm9vdCA9IGRpZmZncmFtOwoKCgogICAgICAgICAgICBMaXN0PE1hcC5FbnRyeTxTdHJpbmcsIFN0cmluZz4+IHBhaXJzID0gY29sbGVjdFNpZE5hbWVQYWlycyhkYXRhUm9vdCwgZmFsc2UpOwoKICAgICAgICAgICAgZm9yIChNYXAuRW50cnk8U3RyaW5nLCBTdHJpbmc+IGUgOiBwYWlycykgewoKICAgICAgICAgICAgICAgIFN0cmluZyBzaWQgPSBlLmdldEtleSgpLCBuYW1lID0gZS5nZXRWYWx1ZSgpOwoKICAgICAgICAgICAgICAgIGlmICghc2Vlbi5jb250YWluc0tleShzaWQpKSB7CgogICAgICAgICAgICAgICAgICAgIHNlZW4ucHV0KHNpZCwgbmFtZSk7CgogICAgICAgICAgICAgICAgICAgIExpbmtlZEhhc2hNYXA8U3RyaW5nLCBTdHJpbmc+IG1hID0gbmV3IExpbmtlZEhhc2hNYXA8PigpOwoKICAgICAgICAgICAgICAgICAgICBtYS5wdXQoc2lkLCBuYW1lKTsKCiAgICAgICAgICAgICAgICAgICAgbWFwLnB1dChjb3VudCsrLCBtYSk7CgogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgfQoKICAgICAgICB9CgogICAgfQoKCgogICAgcmV0dXJuIG1hcDsKCn0KCgoKLyogPT09PT09PT09PT09PT09PT09PT09IGhlbHBlcnMgKEVuZ2xpc2ggY29tbWVudHMpID09PT09PT09PT09PT09PT09PT09PSAqLwoKCgovKiogUGljayB0aGUgPGRpZmZncmFtPiBlbGVtZW50IGZyb20gTWVzc2FnZUVsZW1lbnRbXSwgc2tpcHBpbmcgc2NoZW1hICovCgpwcml2YXRlIHN0YXRpYyBFbGVtZW50IHBpY2tEaWZmZ3JhbShNZXNzYWdlRWxlbWVudFtdIGFueUFycikgewoKICAgIGlmIChhbnlBcnIgPT0gbnVsbCkgcmV0dXJuIG51bGw7CgogICAgZm9yIChNZXNzYWdlRWxlbWVudCBtZSA6IGFueUFycikgewoKICAgICAgICBTdHJpbmcgbG4gPSBtZS5nZXRMb2NhbE5hbWUoKTsKCiAgICAgICAgaWYgKCJkaWZmZ3JhbSIuZXF1YWxzSWdub3JlQ2FzZShsbikpIHJldHVybiBtZTsKCiAgICB9CgogICAgcmV0dXJuIG51bGw7Cgp9CgoKCi8qKiBGaW5kIGZpcnN0IGNoaWxkIGVsZW1lbnQgYnkgbG9jYWwgb3Igbm9kZSBuYW1lIChpZ25vcmVzIHByZWZpeCkgKi8KCnByaXZhdGUgc3RhdGljIEVsZW1lbnQgZmlyc3RDaGlsZEVsZW1lbnRCeUxvY2FsTmFtZShFbGVtZW50IHBhcmVudCwgU3RyaW5nIGxvY2FsKSB7CgogICAgaWYgKHBhcmVudCA9PSBudWxsKSByZXR1cm4gbnVsbDsKCiAgICBmb3IgKE5vZGUgbiA9IHBhcmVudC5nZXRGaXJzdENoaWxkKCk7IG4gIT0gbnVsbDsgbiA9IG4uZ2V0TmV4dFNpYmxpbmcoKSkgewoKICAgICAgICBpZiAobi5nZXROb2RlVHlwZSgpID09IE5vZGUuRUxFTUVOVF9OT0RFKSB7CgogICAgICAgICAgICBTdHJpbmcgbG4gPSBuLmdldExvY2FsTmFtZSgpOwoKICAgICAgICAgICAgU3RyaW5nIG5uID0gbi5nZXROb2RlTmFtZSgpOwoKICAgICAgICAgICAgaWYgKGxvY2FsLmVxdWFscyhubikgfHwgbG9jYWwuZXF1YWxzSWdub3JlQ2FzZShsbikpIHJldHVybiAoRWxlbWVudCkgbjsKCiAgICAgICAgfQoKICAgIH0KCiAgICByZXR1cm4gbnVsbDsKCn0KCgoKLyoqCgogKiBDb2xsZWN0IChpZnFfc2lkIC0+IHNmcV9uYW1lKSBwYWlycyB1bmRlciBkYXRhUm9vdC4KCiAqIFJvYnVzdCBhcHByb2FjaDogcXVlcnkgYm90aCBOb2RlTGlzdHMgYW5kIHBhaXIgYnkgaW5kZXguCgogKiBgcmV2ZXJzZT10cnVlYCBpdGVyYXRlcyBmcm9tIHRhaWwgdG8gaGVhZCB0byBtaW1pYyB5b3VyIG9yaWdpbmFsIG9yZGVyLgoKICovCgpwcml2YXRlIHN0YXRpYyBMaXN0PE1hcC5FbnRyeTxTdHJpbmcsIFN0cmluZz4+IGNvbGxlY3RTaWROYW1lUGFpcnMoRWxlbWVudCBkYXRhUm9vdCwgYm9vbGVhbiByZXZlcnNlKSB7CgogICAgTGlzdDxNYXAuRW50cnk8U3RyaW5nLCBTdHJpbmc+PiBvdXQgPSBuZXcgQXJyYXlMaXN0PD4oKTsKCiAgICBpZiAoZGF0YVJvb3QgPT0gbnVsbCkgcmV0dXJuIG91dDsKCgoKICAgIE5vZGVMaXN0IG5hbWVOb2RlcyA9IGRhdGFSb290LmdldEVsZW1lbnRzQnlUYWdOYW1lKCJzZnFfbmFtZSIpOwoKICAgIE5vZGVMaXN0IHNpZE5vZGVzICA9IGRhdGFSb290LmdldEVsZW1lbnRzQnlUYWdOYW1lKCJpZnFfc2lkIik7CgogICAgaW50IG4gPSBNYXRoLm1pbihuYW1lTm9kZXMuZ2V0TGVuZ3RoKCksIHNpZE5vZGVzLmdldExlbmd0aCgpKTsKCiAgICBpZiAobiA8PSAwKSByZXR1cm4gb3V0OwoKCgogICAgaWYgKHJldmVyc2UpIHsKCiAgICAgICAgZm9yIChpbnQgaSA9IG4gLSAxOyBpID49IDA7IGktLSkgewoKICAgICAgICAgICAgU3RyaW5nIG5hbWUgPSBnZXROb2RlVGV4dENvbXBhdChuYW1lTm9kZXMuaXRlbShpKSkudHJpbSgpOwoKICAgICAgICAgICAgU3RyaW5nIHNpZCAgPSBnZXROb2RlVGV4dENvbXBhdChzaWROb2Rlcy5pdGVtKGkpKS50cmltKCk7CgogICAgICAgICAgICBpZiAoIXNpZC5pc0VtcHR5KCkpIG91dC5hZGQoTWFwLmVudHJ5KHNpZCwgbmFtZSkpOwoKICAgICAgICB9CgogICAgfSBlbHNlIHsKCiAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBuOyBpKyspIHsKCiAgICAgICAgICAgIFN0cmluZyBuYW1lID0gZ2V0Tm9kZVRleHRDb21wYXQobmFtZU5vZGVzLml0ZW0oaSkpLnRyaW0oKTsKCiAgICAgICAgICAgIFN0cmluZyBzaWQgID0gZ2V0Tm9kZVRleHRDb21wYXQoc2lkTm9kZXMuaXRlbShpKSkudHJpbSgpOwoKICAgICAgICAgICAgaWYgKCFzaWQuaXNFbXB0eSgpKSBvdXQuYWRkKE1hcC5lbnRyeShzaWQsIG5hbWUpKTsKCiAgICAgICAgfQoKICAgIH0KCiAgICByZXR1cm4gb3V0OwoKfQoKCgovKiogQXhpcy1jb21wYXRpYmxlIHRleHQgZXh0cmFjdGlvbiAoVEVYVF9OT0RFL0NEQVRBIG9ubHkpICovCgpwcml2YXRlIHN0YXRpYyBTdHJpbmcgZ2V0Tm9kZVRleHRDb21wYXQoTm9kZSBub2RlKSB7CgogICAgaWYgKG5vZGUgPT0gbnVsbCkgcmV0dXJuICIiOwoKICAgIFN0cmluZ0J1aWxkZXIgc2IgPSBuZXcgU3RyaW5nQnVpbGRlcigpOwoKICAgIE5vZGVMaXN0IGNzID0gbm9kZS5nZXRDaGlsZE5vZGVzKCk7CgogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBjcy5nZXRMZW5ndGgoKTsgaSsrKSB7CgogICAgICAgIE5vZGUgYyA9IGNzLml0ZW0oaSk7CgogICAgICAgIHNob3J0IHQgPSBjLmdldE5vZGVUeXBlKCk7CgogICAgICAgIGlmICh0ID09IE5vZGUuVEVYVF9OT0RFIHx8IHQgPT0gTm9kZS5DREFUQV9TRUNUSU9OX05PREUpIHsKCiAgICAgICAgICAgIHNiLmFwcGVuZChjLmdldE5vZGVWYWx1ZSgpKTsKCiAgICAgICAgfQoKICAgIH0KCiAgICByZXR1cm4gc2IudG9TdHJpbmcoKTsKCn0K