import org.apache.axis.message.MessageElement;
import org.w3c.dom.*;
import java.util.*;
import java.util.regex.Pattern;
public LinkedHashMap<String, String> getKBContentData(int ifqSid, String userType, boolean isFromRelation) throws Exception {
LinkedHashMap<String, String> map = new LinkedHashMap<>();
IQKB_XMLSoapProxy service = new IQKB_XMLSoapProxy();
// keep your original logs
WsGetKBContentDataResponseWsGetKBContentDataResult result =
service.wsGetKBContentData(strValidCode, 1, channelMap.get(userType), "內部答案", ifqSid, "1");
MessageElement[] anyArr = result.get_any();
LOGGER.info(vaildLog("### method:getKBContentData, webservice:wsGetKBContentData"));
LOGGER.info(vaildLog("### req:" + "wsGetKBContentData(" + strValidCode + ", 1, "
+ channelMap.get(userType) + ", 內部答案, " + ifqSid + ", 1)"));
LOGGER.info(vaildLog("### kbContentData:" + (anyArr != null && anyArr.length > 0 ? anyArr[0] : "null")));
if (anyArr == null || anyArr.length == 0) {
return map;
}
// 1) find <diffgram>
Element diffgram = null;
for (MessageElement me : anyArr) {
String ln = me.getLocalName();
if ("diffgram".equalsIgnoreCase(ln)) { diffgram = me; break; }
}
if (diffgram == null) { return map; }
// 2) move into <IQKB>, then rows <KBContentData>
Element dataRoot = firstChildElementByLocalName(diffgram, "IQKB");
if (dataRoot == null) dataRoot = diffgram;
NodeList rows = dataRoot.getElementsByTagName("KBContentData");
if (rows == null || rows.getLength() == 0) { return map; }
// 3) assume first KBContentData is the target
Element row = (Element) rows.item(0);
// 3a) answer: sfa_desc
String sfaDesc = getChildText(row, "sfa_desc");
if (sfaDesc == null || sfaDesc.isBlank()) {
sfaDesc = "暫無相關答案內容";
}
// If you need HTML unescape (e.g. <strong>), enable the next line with Apache Commons Text:
// sfaDesc = org.apache.commons.text.StringEscapeUtils.unescapeHtml4(sfaDesc);
map.put("sfaDesc", sfaDesc);
// 4) relations (skip when opened from relation list)
if (!isFromRelation) {
String rel = getChildText(row, "sfq_relation"); // e.g. "ifq_sid:5439,5444,5443"
List<Integer> relIds = parseRelationIds(rel);
for (Integer relId : relIds) {
// call wsGetKBContent for title (behavior kept; your logs preserved)
WsGetKBContentResponseWsGetKBContentResult relationResult =
service.wsGetKBContent(strValidCode, 1, channelMap.get(userType), "3", relId);
MessageElement[] anyArrRelation = relationResult.get_any();
LOGGER.info(vaildLog("### method:getKBContentData, webservice:wsGetKBContent"));
LOGGER.info(vaildLog("### req:" + "wsGetKBContent(" + strValidCode + ", 1, "
+ channelMap.get(userType) + ", 3, " + relId + ")"));
LOGGER.info(vaildLog("### relation:" + (anyArrRelation != null && anyArrRelation.length > 0 ? anyArrRelation[0] : "null")));
String title = extractTitleFromRelation(anyArrRelation);
if (title != null) {
map.put(String.valueOf(relId), title);
} else {
// fallback: try with other user types; keep your original behavior
List<String> userTypeList = new ArrayList<>(channelMap.values());
userTypeList.removeIf(x -> Objects.equals(x, channelMap.get(userType)));
for (String usrType : userTypeList) {
WsGetKBContentResponseWsGetKBContentResult rr2 =
service.wsGetKBContent(strValidCode, 1, usrType, "3", relId);
MessageElement[] anyArr2 = rr2.get_any();
String t2 = extractTitleFromRelation(anyArr2);
if (t2 != null) {
map.put(relId + "notAllowed", t2);
break;
}
}
}
}
}
LOGGER.info("getKBContentData: rows=" + rows.getLength() + ", relations=" + (map.size() - 1));
return map;
}
/* ---------------- helpers (shared, English comments) ---------------- */
/** Get first child element by local or node name (ignores prefix) */
private static Element firstChildElementByLocalName(Element parent, String local) {
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;
}
/** Axis-compatible text fetch (TEXT_NODE / CDATA only) */
private static String getChildText(Element parent, String tag) {
NodeList nl = parent.getElementsByTagName(tag);
if (nl == null || nl.getLength() == 0) return "";
return getNodeTextCompat(nl.item(0)).trim();
}
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();
}
/** Parse "ifq_sid:5439,5444,5443" → [5439, 5444, 5443] */
private static List<Integer> parseRelationIds(String rel) {
if (rel == null) return List.of();
String s = rel.trim();
if (s.isEmpty()) return List.of();
s = s.replace("ifq_sid:", "").trim();
String[] parts = s.split(",");
List<Integer> out = new ArrayList<>(parts.length);
for (String p : parts) {
String v = p.trim();
if (!v.isEmpty() && Pattern.matches("\\d+", v)) {
try { out.add(Integer.parseInt(v)); } catch (NumberFormatException ignored) {}
}
}
return out;
}
/** Extract sfq_name from a wsGetKBContent(...) response (diffgram → IQKB → first row) */
private static String extractTitleFromRelation(MessageElement[] anyArr) {
if (anyArr == null || anyArr.length == 0) return null;
Element diffgram = null;
for (MessageElement me : anyArr) {
String ln = me.getLocalName();
if ("diffgram".equalsIgnoreCase(ln)) { diffgram = me; break; }
}
if (diffgram == null) return null;
Element dataRoot = firstChildElementByLocalName(diffgram, "IQKB");
if (dataRoot == null) dataRoot = diffgram;
// titles usually live under <TreeAllKB> / <KBContentData>; try both
NodeList names = dataRoot.getElementsByTagName("sfq_name");
if (names != null && names.getLength() > 0) {
String name = getNodeTextCompat(names.item(0)).trim();
return name.isEmpty() ? null : name;
}
return null;
}
aW1wb3J0IG9yZy5hcGFjaGUuYXhpcy5tZXNzYWdlLk1lc3NhZ2VFbGVtZW50OwoKaW1wb3J0IG9yZy53M2MuZG9tLio7CgoKCmltcG9ydCBqYXZhLnV0aWwuKjsKCmltcG9ydCBqYXZhLnV0aWwucmVnZXguUGF0dGVybjsKCgoKcHVibGljIExpbmtlZEhhc2hNYXA8U3RyaW5nLCBTdHJpbmc+IGdldEtCQ29udGVudERhdGEoaW50IGlmcVNpZCwgU3RyaW5nIHVzZXJUeXBlLCBib29sZWFuIGlzRnJvbVJlbGF0aW9uKSB0aHJvd3MgRXhjZXB0aW9uIHsKCiAgICBMaW5rZWRIYXNoTWFwPFN0cmluZywgU3RyaW5nPiBtYXAgPSBuZXcgTGlua2VkSGFzaE1hcDw+KCk7CgoKCiAgICBJUUtCX1hNTFNvYXBQcm94eSBzZXJ2aWNlID0gbmV3IElRS0JfWE1MU29hcFByb3h5KCk7CgogICAgLy8ga2VlcCB5b3VyIG9yaWdpbmFsIGxvZ3MKCiAgICBXc0dldEtCQ29udGVudERhdGFSZXNwb25zZVdzR2V0S0JDb250ZW50RGF0YVJlc3VsdCByZXN1bHQgPQoKICAgICAgICAgICAgc2VydmljZS53c0dldEtCQ29udGVudERhdGEoc3RyVmFsaWRDb2RlLCAxLCBjaGFubmVsTWFwLmdldCh1c2VyVHlwZSksICLlhafpg6jnrZTmoYgiLCBpZnFTaWQsICIxIik7CgogICAgTWVzc2FnZUVsZW1lbnRbXSBhbnlBcnIgPSByZXN1bHQuZ2V0X2FueSgpOwoKCgogICAgTE9HR0VSLmluZm8odmFpbGRMb2coIiMjIyBtZXRob2Q6Z2V0S0JDb250ZW50RGF0YSwgd2Vic2VydmljZTp3c0dldEtCQ29udGVudERhdGEiKSk7CgogICAgTE9HR0VSLmluZm8odmFpbGRMb2coIiMjIyByZXE6IiArICJ3c0dldEtCQ29udGVudERhdGEoIiArIHN0clZhbGlkQ29kZSArICIsIDEsICIKCiAgICAgICAgICAgICsgY2hhbm5lbE1hcC5nZXQodXNlclR5cGUpICsgIiwg5YWn6YOo562U5qGILCAiICsgaWZxU2lkICsgIiwgMSkiKSk7CgogICAgTE9HR0VSLmluZm8odmFpbGRMb2coIiMjIyBrYkNvbnRlbnREYXRhOiIgKyAoYW55QXJyICE9IG51bGwgJiYgYW55QXJyLmxlbmd0aCA+IDAgPyBhbnlBcnJbMF0gOiAibnVsbCIpKSk7CgoKCiAgICBpZiAoYW55QXJyID09IG51bGwgfHwgYW55QXJyLmxlbmd0aCA9PSAwKSB7CgogICAgICAgIHJldHVybiBtYXA7CgogICAgfQoKCgogICAgLy8gMSkgZmluZCA8ZGlmZmdyYW0+CgogICAgRWxlbWVudCBkaWZmZ3JhbSA9IG51bGw7CgogICAgZm9yIChNZXNzYWdlRWxlbWVudCBtZSA6IGFueUFycikgewoKICAgICAgICBTdHJpbmcgbG4gPSBtZS5nZXRMb2NhbE5hbWUoKTsKCiAgICAgICAgaWYgKCJkaWZmZ3JhbSIuZXF1YWxzSWdub3JlQ2FzZShsbikpIHsgZGlmZmdyYW0gPSBtZTsgYnJlYWs7IH0KCiAgICB9CgogICAgaWYgKGRpZmZncmFtID09IG51bGwpIHsgcmV0dXJuIG1hcDsgfQoKCgogICAgLy8gMikgbW92ZSBpbnRvIDxJUUtCPiwgdGhlbiByb3dzIDxLQkNvbnRlbnREYXRhPgoKICAgIEVsZW1lbnQgZGF0YVJvb3QgPSBmaXJzdENoaWxkRWxlbWVudEJ5TG9jYWxOYW1lKGRpZmZncmFtLCAiSVFLQiIpOwoKICAgIGlmIChkYXRhUm9vdCA9PSBudWxsKSBkYXRhUm9vdCA9IGRpZmZncmFtOwoKCgogICAgTm9kZUxpc3Qgcm93cyA9IGRhdGFSb290LmdldEVsZW1lbnRzQnlUYWdOYW1lKCJLQkNvbnRlbnREYXRhIik7CgogICAgaWYgKHJvd3MgPT0gbnVsbCB8fCByb3dzLmdldExlbmd0aCgpID09IDApIHsgcmV0dXJuIG1hcDsgfQoKCgogICAgLy8gMykgYXNzdW1lIGZpcnN0IEtCQ29udGVudERhdGEgaXMgdGhlIHRhcmdldAoKICAgIEVsZW1lbnQgcm93ID0gKEVsZW1lbnQpIHJvd3MuaXRlbSgwKTsKCgoKICAgIC8vIDNhKSBhbnN3ZXI6IHNmYV9kZXNjCgogICAgU3RyaW5nIHNmYURlc2MgPSBnZXRDaGlsZFRleHQocm93LCAic2ZhX2Rlc2MiKTsKCiAgICBpZiAoc2ZhRGVzYyA9PSBudWxsIHx8IHNmYURlc2MuaXNCbGFuaygpKSB7CgogICAgICAgIHNmYURlc2MgPSAi5pqr54Sh55u46Zec562U5qGI5YWn5a65IjsKCiAgICB9CgogICAgLy8gSWYgeW91IG5lZWQgSFRNTCB1bmVzY2FwZSAoZS5nLiAmbHQ7c3Ryb25nJmd0OyksIGVuYWJsZSB0aGUgbmV4dCBsaW5lIHdpdGggQXBhY2hlIENvbW1vbnMgVGV4dDoKCiAgICAvLyBzZmFEZXNjID0gb3JnLmFwYWNoZS5jb21tb25zLnRleHQuU3RyaW5nRXNjYXBlVXRpbHMudW5lc2NhcGVIdG1sNChzZmFEZXNjKTsKCiAgICBtYXAucHV0KCJzZmFEZXNjIiwgc2ZhRGVzYyk7CgoKCiAgICAvLyA0KSByZWxhdGlvbnMgKHNraXAgd2hlbiBvcGVuZWQgZnJvbSByZWxhdGlvbiBsaXN0KQoKICAgIGlmICghaXNGcm9tUmVsYXRpb24pIHsKCiAgICAgICAgU3RyaW5nIHJlbCA9IGdldENoaWxkVGV4dChyb3csICJzZnFfcmVsYXRpb24iKTsgLy8gZS5nLiAiaWZxX3NpZDo1NDM5LDU0NDQsNTQ0MyIKCiAgICAgICAgTGlzdDxJbnRlZ2VyPiByZWxJZHMgPSBwYXJzZVJlbGF0aW9uSWRzKHJlbCk7CgoKCiAgICAgICAgZm9yIChJbnRlZ2VyIHJlbElkIDogcmVsSWRzKSB7CgogICAgICAgICAgICAvLyBjYWxsIHdzR2V0S0JDb250ZW50IGZvciB0aXRsZSAoYmVoYXZpb3Iga2VwdDsgeW91ciBsb2dzIHByZXNlcnZlZCkKCiAgICAgICAgICAgIFdzR2V0S0JDb250ZW50UmVzcG9uc2VXc0dldEtCQ29udGVudFJlc3VsdCByZWxhdGlvblJlc3VsdCA9CgogICAgICAgICAgICAgICAgICAgIHNlcnZpY2Uud3NHZXRLQkNvbnRlbnQoc3RyVmFsaWRDb2RlLCAxLCBjaGFubmVsTWFwLmdldCh1c2VyVHlwZSksICIzIiwgcmVsSWQpOwoKICAgICAgICAgICAgTWVzc2FnZUVsZW1lbnRbXSBhbnlBcnJSZWxhdGlvbiA9IHJlbGF0aW9uUmVzdWx0LmdldF9hbnkoKTsKCgoKICAgICAgICAgICAgTE9HR0VSLmluZm8odmFpbGRMb2coIiMjIyBtZXRob2Q6Z2V0S0JDb250ZW50RGF0YSwgd2Vic2VydmljZTp3c0dldEtCQ29udGVudCIpKTsKCiAgICAgICAgICAgIExPR0dFUi5pbmZvKHZhaWxkTG9nKCIjIyMgcmVxOiIgKyAid3NHZXRLQkNvbnRlbnQoIiArIHN0clZhbGlkQ29kZSArICIsIDEsICIKCiAgICAgICAgICAgICAgICAgICAgKyBjaGFubmVsTWFwLmdldCh1c2VyVHlwZSkgKyAiLCAzLCAiICsgcmVsSWQgKyAiKSIpKTsKCiAgICAgICAgICAgIExPR0dFUi5pbmZvKHZhaWxkTG9nKCIjIyMgcmVsYXRpb246IiArIChhbnlBcnJSZWxhdGlvbiAhPSBudWxsICYmIGFueUFyclJlbGF0aW9uLmxlbmd0aCA+IDAgPyBhbnlBcnJSZWxhdGlvblswXSA6ICJudWxsIikpKTsKCgoKICAgICAgICAgICAgU3RyaW5nIHRpdGxlID0gZXh0cmFjdFRpdGxlRnJvbVJlbGF0aW9uKGFueUFyclJlbGF0aW9uKTsKCiAgICAgICAgICAgIGlmICh0aXRsZSAhPSBudWxsKSB7CgogICAgICAgICAgICAgICAgbWFwLnB1dChTdHJpbmcudmFsdWVPZihyZWxJZCksIHRpdGxlKTsKCiAgICAgICAgICAgIH0gZWxzZSB7CgogICAgICAgICAgICAgICAgLy8gZmFsbGJhY2s6IHRyeSB3aXRoIG90aGVyIHVzZXIgdHlwZXM7IGtlZXAgeW91ciBvcmlnaW5hbCBiZWhhdmlvcgoKICAgICAgICAgICAgICAgIExpc3Q8U3RyaW5nPiB1c2VyVHlwZUxpc3QgPSBuZXcgQXJyYXlMaXN0PD4oY2hhbm5lbE1hcC52YWx1ZXMoKSk7CgogICAgICAgICAgICAgICAgdXNlclR5cGVMaXN0LnJlbW92ZUlmKHggLT4gT2JqZWN0cy5lcXVhbHMoeCwgY2hhbm5lbE1hcC5nZXQodXNlclR5cGUpKSk7CgoKCiAgICAgICAgICAgICAgICBmb3IgKFN0cmluZyB1c3JUeXBlIDogdXNlclR5cGVMaXN0KSB7CgogICAgICAgICAgICAgICAgICAgIFdzR2V0S0JDb250ZW50UmVzcG9uc2VXc0dldEtCQ29udGVudFJlc3VsdCBycjIgPQoKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2Uud3NHZXRLQkNvbnRlbnQoc3RyVmFsaWRDb2RlLCAxLCB1c3JUeXBlLCAiMyIsIHJlbElkKTsKCiAgICAgICAgICAgICAgICAgICAgTWVzc2FnZUVsZW1lbnRbXSBhbnlBcnIyID0gcnIyLmdldF9hbnkoKTsKCiAgICAgICAgICAgICAgICAgICAgU3RyaW5nIHQyID0gZXh0cmFjdFRpdGxlRnJvbVJlbGF0aW9uKGFueUFycjIpOwoKICAgICAgICAgICAgICAgICAgICBpZiAodDIgIT0gbnVsbCkgewoKICAgICAgICAgICAgICAgICAgICAgICAgbWFwLnB1dChyZWxJZCArICJub3RBbGxvd2VkIiwgdDIpOwoKICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CgogICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICB9CgogICAgICAgIH0KCiAgICB9CgoKCiAgICBMT0dHRVIuaW5mbygiZ2V0S0JDb250ZW50RGF0YTogcm93cz0iICsgcm93cy5nZXRMZW5ndGgoKSArICIsIHJlbGF0aW9ucz0iICsgKG1hcC5zaXplKCkgLSAxKSk7CgogICAgcmV0dXJuIG1hcDsKCn0KCgoKLyogLS0tLS0tLS0tLS0tLS0tLSBoZWxwZXJzIChzaGFyZWQsIEVuZ2xpc2ggY29tbWVudHMpIC0tLS0tLS0tLS0tLS0tLS0gKi8KCgoKLyoqIEdldCBmaXJzdCBjaGlsZCBlbGVtZW50IGJ5IGxvY2FsIG9yIG5vZGUgbmFtZSAoaWdub3JlcyBwcmVmaXgpICovCgpwcml2YXRlIHN0YXRpYyBFbGVtZW50IGZpcnN0Q2hpbGRFbGVtZW50QnlMb2NhbE5hbWUoRWxlbWVudCBwYXJlbnQsIFN0cmluZyBsb2NhbCkgewoKICAgIGZvciAoTm9kZSBuID0gcGFyZW50LmdldEZpcnN0Q2hpbGQoKTsgbiAhPSBudWxsOyBuID0gbi5nZXROZXh0U2libGluZygpKSB7CgogICAgICAgIGlmIChuLmdldE5vZGVUeXBlKCkgPT0gTm9kZS5FTEVNRU5UX05PREUpIHsKCiAgICAgICAgICAgIFN0cmluZyBsbiA9IG4uZ2V0TG9jYWxOYW1lKCk7CgogICAgICAgICAgICBTdHJpbmcgbm4gPSBuLmdldE5vZGVOYW1lKCk7CgogICAgICAgICAgICBpZiAobG9jYWwuZXF1YWxzKG5uKSB8fCBsb2NhbC5lcXVhbHNJZ25vcmVDYXNlKGxuKSkgcmV0dXJuIChFbGVtZW50KSBuOwoKICAgICAgICB9CgogICAgfQoKICAgIHJldHVybiBudWxsOwoKfQoKCgovKiogQXhpcy1jb21wYXRpYmxlIHRleHQgZmV0Y2ggKFRFWFRfTk9ERSAvIENEQVRBIG9ubHkpICovCgpwcml2YXRlIHN0YXRpYyBTdHJpbmcgZ2V0Q2hpbGRUZXh0KEVsZW1lbnQgcGFyZW50LCBTdHJpbmcgdGFnKSB7CgogICAgTm9kZUxpc3QgbmwgPSBwYXJlbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUodGFnKTsKCiAgICBpZiAobmwgPT0gbnVsbCB8fCBubC5nZXRMZW5ndGgoKSA9PSAwKSByZXR1cm4gIiI7CgogICAgcmV0dXJuIGdldE5vZGVUZXh0Q29tcGF0KG5sLml0ZW0oMCkpLnRyaW0oKTsKCn0KCgoKcHJpdmF0ZSBzdGF0aWMgU3RyaW5nIGdldE5vZGVUZXh0Q29tcGF0KE5vZGUgbm9kZSkgewoKICAgIGlmIChub2RlID09IG51bGwpIHJldHVybiAiIjsKCiAgICBTdHJpbmdCdWlsZGVyIHNiID0gbmV3IFN0cmluZ0J1aWxkZXIoKTsKCiAgICBOb2RlTGlzdCBjcyA9IG5vZGUuZ2V0Q2hpbGROb2RlcygpOwoKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgY3MuZ2V0TGVuZ3RoKCk7IGkrKykgewoKICAgICAgICBOb2RlIGMgPSBjcy5pdGVtKGkpOwoKICAgICAgICBzaG9ydCB0ID0gYy5nZXROb2RlVHlwZSgpOwoKICAgICAgICBpZiAodCA9PSBOb2RlLlRFWFRfTk9ERSB8fCB0ID09IE5vZGUuQ0RBVEFfU0VDVElPTl9OT0RFKSBzYi5hcHBlbmQoYy5nZXROb2RlVmFsdWUoKSk7CgogICAgfQoKICAgIHJldHVybiBzYi50b1N0cmluZygpOwoKfQoKCgovKiogUGFyc2UgImlmcV9zaWQ6NTQzOSw1NDQ0LDU0NDMiIOKGkiBbNTQzOSwgNTQ0NCwgNTQ0M10gKi8KCnByaXZhdGUgc3RhdGljIExpc3Q8SW50ZWdlcj4gcGFyc2VSZWxhdGlvbklkcyhTdHJpbmcgcmVsKSB7CgogICAgaWYgKHJlbCA9PSBudWxsKSByZXR1cm4gTGlzdC5vZigpOwoKICAgIFN0cmluZyBzID0gcmVsLnRyaW0oKTsKCiAgICBpZiAocy5pc0VtcHR5KCkpIHJldHVybiBMaXN0Lm9mKCk7CgogICAgcyA9IHMucmVwbGFjZSgiaWZxX3NpZDoiLCAiIikudHJpbSgpOwoKICAgIFN0cmluZ1tdIHBhcnRzID0gcy5zcGxpdCgiLCIpOwoKICAgIExpc3Q8SW50ZWdlcj4gb3V0ID0gbmV3IEFycmF5TGlzdDw+KHBhcnRzLmxlbmd0aCk7CgogICAgZm9yIChTdHJpbmcgcCA6IHBhcnRzKSB7CgogICAgICAgIFN0cmluZyB2ID0gcC50cmltKCk7CgogICAgICAgIGlmICghdi5pc0VtcHR5KCkgJiYgUGF0dGVybi5tYXRjaGVzKCJcXGQrIiwgdikpIHsKCiAgICAgICAgICAgIHRyeSB7IG91dC5hZGQoSW50ZWdlci5wYXJzZUludCh2KSk7IH0gY2F0Y2ggKE51bWJlckZvcm1hdEV4Y2VwdGlvbiBpZ25vcmVkKSB7fQoKICAgICAgICB9CgogICAgfQoKICAgIHJldHVybiBvdXQ7Cgp9CgoKCi8qKiBFeHRyYWN0IHNmcV9uYW1lIGZyb20gYSB3c0dldEtCQ29udGVudCguLi4pIHJlc3BvbnNlIChkaWZmZ3JhbSDihpIgSVFLQiDihpIgZmlyc3Qgcm93KSAqLwoKcHJpdmF0ZSBzdGF0aWMgU3RyaW5nIGV4dHJhY3RUaXRsZUZyb21SZWxhdGlvbihNZXNzYWdlRWxlbWVudFtdIGFueUFycikgewoKICAgIGlmIChhbnlBcnIgPT0gbnVsbCB8fCBhbnlBcnIubGVuZ3RoID09IDApIHJldHVybiBudWxsOwoKICAgIEVsZW1lbnQgZGlmZmdyYW0gPSBudWxsOwoKICAgIGZvciAoTWVzc2FnZUVsZW1lbnQgbWUgOiBhbnlBcnIpIHsKCiAgICAgICAgU3RyaW5nIGxuID0gbWUuZ2V0TG9jYWxOYW1lKCk7CgogICAgICAgIGlmICgiZGlmZmdyYW0iLmVxdWFsc0lnbm9yZUNhc2UobG4pKSB7IGRpZmZncmFtID0gbWU7IGJyZWFrOyB9CgogICAgfQoKICAgIGlmIChkaWZmZ3JhbSA9PSBudWxsKSByZXR1cm4gbnVsbDsKCgoKICAgIEVsZW1lbnQgZGF0YVJvb3QgPSBmaXJzdENoaWxkRWxlbWVudEJ5TG9jYWxOYW1lKGRpZmZncmFtLCAiSVFLQiIpOwoKICAgIGlmIChkYXRhUm9vdCA9PSBudWxsKSBkYXRhUm9vdCA9IGRpZmZncmFtOwoKCgogICAgLy8gdGl0bGVzIHVzdWFsbHkgbGl2ZSB1bmRlciA8VHJlZUFsbEtCPiAvIDxLQkNvbnRlbnREYXRhPjsgdHJ5IGJvdGgKCiAgICBOb2RlTGlzdCBuYW1lcyA9IGRhdGFSb290LmdldEVsZW1lbnRzQnlUYWdOYW1lKCJzZnFfbmFtZSIpOwoKICAgIGlmIChuYW1lcyAhPSBudWxsICYmIG5hbWVzLmdldExlbmd0aCgpID4gMCkgewoKICAgICAgICBTdHJpbmcgbmFtZSA9IGdldE5vZGVUZXh0Q29tcGF0KG5hbWVzLml0ZW0oMCkpLnRyaW0oKTsKCiAgICAgICAgcmV0dXJuIG5hbWUuaXNFbXB0eSgpID8gbnVsbCA6IG5hbWU7CgogICAgfQoKICAgIHJldHVybiBudWxsOwoKfQo=