use of com.ximpleware.XPathParseException in project translationstudio8 by heartsome.
the class PreferenceUtil method initProductEdition.
public static void initProductEdition() {
System.getProperties().put("TSVersion", "89");
Location configArea = Platform.getInstallLocation();
if (configArea == null) {
System.getProperties().put("TSEdition", "");
System.getProperties().put("TSVersion", "");
return;
}
URL location = null;
try {
VTDGen vg = new VTDGen();
AutoPilot ap = new AutoPilot();
location = new URL(configArea.getURL().toExternalForm() + "features");
String featureFolderName = location.getFile();
File featureFolder = new File(featureFolderName);
// 遍历 features 目录
if (featureFolder.isDirectory()) {
boolean isU = false;
boolean isF = false;
boolean isP = false;
boolean isL = false;
String strUVersion = null;
String strFVersion = null;
String strPVersion = null;
String strLVersion = null;
for (File f : featureFolder.listFiles()) {
String name = f.getName();
if (name.startsWith("net.heartsome.cat.ts.edition_")) {
if (vg.parseFile(f.getAbsolutePath() + File.separator + "feature.xml", true)) {
VTDNav vn = vg.getNav();
ap.bind(vn);
ap.selectXPath("/feature");
if (ap.evalXPath() != -1) {
int idIndex = vn.getAttrVal("id");
int versionIndex = vn.getAttrVal("version");
if (idIndex == -1 || versionIndex == -1) {
System.getProperties().put("TSEdition", "");
return;
}
String id = vn.toRawString(idIndex);
String version = vn.toRawString(versionIndex);
if (name.equals(id + "_" + version)) {
// 由于 feature 可以包含,因此要遍历所有以 net.heartsome.cat.ts.edition_ 开头的目录,找到版本最高的
if (id.equals("net.heartsome.cat.ts.edition_ultimate.feature")) {
isU = true;
strUVersion = version;
break;
} else if (id.equals("net.heartsome.cat.ts.edition_professional.feature")) {
isF = true;
strFVersion = version;
continue;
} else if (id.equals("net.heartsome.cat.ts.edition_personal.feature")) {
isP = true;
strPVersion = version;
continue;
} else if (id.equals("net.heartsome.cat.ts.edition_lite.feature")) {
isL = true;
strLVersion = version;
continue;
}
} else {
System.getProperties().put("TSEdition", "");
return;
}
} else {
System.getProperties().put("TSEdition", "");
}
} else {
System.getProperties().put("TSEdition", "");
}
}
}
if (isU) {
System.getProperties().put("TSEdition", "U");
System.getProperties().put("TSVersionDate", strUVersion);
} else if (isF) {
System.getProperties().put("TSEdition", "F");
System.getProperties().put("TSVersionDate", strFVersion);
} else if (isP) {
System.getProperties().put("TSEdition", "P");
System.getProperties().put("TSVersionDate", strPVersion);
} else if (isL) {
System.getProperties().put("TSEdition", "L");
System.getProperties().put("TSVersionDate", strLVersion);
} else {
System.getProperties().put("TSEdition", "");
System.getProperties().put("TSVersionDate", "");
}
} else {
System.getProperties().put("TSEdition", "");
}
location = new URL(configArea.getURL().toExternalForm() + "plugins");
String pluginsFolderName = location.getFile();
File pluginsFolder = new File(pluginsFolderName);
// 遍历 plugins 目录
if (pluginsFolder.isDirectory()) {
List<String> lstPluginName = new ArrayList<String>();
for (File f : pluginsFolder.listFiles()) {
String name = f.getName();
if (name.endsWith(".jar") && (name.startsWith("net.heartsome.cat.ts.ui.plugin_") || name.startsWith("net.heartsome.cat.ts.ui.advanced_") || name.startsWith("net.heartsome.cat.ts.fuzzyTranslation_") || name.startsWith("net.heartsome.cat.converter.ui_") || name.startsWith("net.heartsome.cat.ts.ui.docx_") || name.startsWith("net.heartsome.cat.ts.ui.qa_") || name.startsWith("net.heartsome.cat.database.ui_") || name.startsWith("net.heartsome.cat.database.hsql_") || name.startsWith("net.heartsome.cat.database.oracle_") || name.startsWith("net.heartsome.cat.ts.importproject_") || name.startsWith("net.heartsome.cat.ts.exportproject_") || name.startsWith("net.heartsome.cat.ts.handlexlf_") || name.startsWith("net.heartsome.cat.ts.lockrepeat_") || name.startsWith("net.heartsome.cat.ts.jumpsegment_"))) {
String pluginName = name.substring(0, name.indexOf("_"));
// 更新后原来的插件会保留在 plugins 目录下,应此 lstPluginName 会有重复添加 pluginName 的情况,所以在此处添加判断。
if (!lstPluginName.contains(pluginName)) {
lstPluginName.add(pluginName);
}
}
}
String edition = System.getProperty("TSEdition");
if (lstPluginName.size() == 14 && lstPluginName.indexOf("net.heartsome.cat.ts.ui.plugin") != -1 && lstPluginName.indexOf("net.heartsome.cat.ts.ui.advanced") != -1 && lstPluginName.indexOf("net.heartsome.cat.ts.fuzzyTranslation") != -1 && lstPluginName.indexOf("net.heartsome.cat.converter.ui") != -1 && lstPluginName.indexOf("net.heartsome.cat.ts.ui.docx") != -1 && lstPluginName.indexOf("net.heartsome.cat.ts.ui.qa") != -1 && lstPluginName.indexOf("net.heartsome.cat.database.ui") != -1 && lstPluginName.indexOf("net.heartsome.cat.database.hsql") != -1 && lstPluginName.indexOf("net.heartsome.cat.database.oracle") != -1 && lstPluginName.indexOf("net.heartsome.cat.ts.importproject") != -1 && lstPluginName.indexOf("net.heartsome.cat.ts.exportproject") != -1 && lstPluginName.indexOf("net.heartsome.cat.ts.handlexlf") != -1 && lstPluginName.indexOf("net.heartsome.cat.ts.lockrepeat") != -1 && lstPluginName.indexOf("net.heartsome.cat.ts.jumpsegment") != -1) {
if (!(edition != null && (edition.equals("U") || edition.equals("F")))) {
System.getProperties().put("TSEdition", "");
}
} else if (lstPluginName.size() == 6 && lstPluginName.indexOf("net.heartsome.cat.converter.ui") != -1 && lstPluginName.indexOf("net.heartsome.cat.ts.ui.qa") != -1 && lstPluginName.indexOf("net.heartsome.cat.database.ui") != -1 && lstPluginName.indexOf("net.heartsome.cat.database.hsql") != -1 && lstPluginName.indexOf("net.heartsome.cat.ts.importproject") != -1 && lstPluginName.indexOf("net.heartsome.cat.ts.jumpsegment") != -1) {
if (!(edition != null && edition.equals("P"))) {
System.getProperties().put("TSEdition", "");
}
} else if (lstPluginName.size() == 0) {
if (!(edition != null && edition.equals("L"))) {
System.getProperties().put("TSEdition", "");
}
} else {
System.getProperties().put("TSEdition", "");
}
} else {
System.getProperties().put("TSEdition", "");
}
// if (System.getProperty("TSEdition").equals("")) {
// return;
// }
// String product = Platform.getProduct().getName();
// if (Util.isMac()) {
// location = new URL(configArea.getURL().toExternalForm() + product + ".app" + File.separator
// + "Contents" + File.separator + "MacOS" + File.separator + product + ".ini");
// } else {
// location = new URL(configArea.getURL().toExternalForm() + product + ".ini");
// }
// String fileName = location.getFile();
// BufferedReader in = new BufferedReader(new FileReader(fileName));
// String line = null;
// String tsVersion = null;
// String tsSerial = null;
// while ((line = in.readLine()) != null) {
// if (line.startsWith("TSProductVersion")) {
// tsVersion = line.substring(line.indexOf("=") + 1);
// }
// if (line.startsWith("TSProductSerialNumber")) {
// tsSerial = line.substring(line.indexOf("=") + 1);
// }
// }
// if (tsVersion != null && tsSerial != null && tsVersion.length() == 16 && tsSerial.length() == 16) {
// String edition = System.getProperty("TSEdition");
// int[] arrValue = new int[16];
// for (int i = 0; i < tsVersion.length(); i++) {
// arrValue[i] = Integer.parseInt(Character.toString(tsVersion.charAt(i)));
// }
// int[] arrSerialNum = new int[16];
// for (int i = 0; i < tsSerial.length(); i++) {
// arrSerialNum[i] = Integer.parseInt(Character.toString(tsSerial.charAt(i)));
// }
// String strFullChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// boolean isU = ((arrValue[1] + arrValue[8]) * (arrValue[7] - arrValue[14])) == (strFullChar.indexOf("U") +
// 1);// 验证旗舰版的规则
// boolean isF = arrValue[4] != 0
// && (arrValue[2] - arrValue[9] + arrValue[15]) / arrValue[4] == (strFullChar.indexOf("F") + 1);
// boolean isP = arrValue[5] * (arrValue[3] + arrValue[10] + arrValue[12]) == (strFullChar.indexOf("P") +
// 1);
// boolean isL = (arrValue[0] + arrValue[6] + arrValue[11] + arrValue[13]) == (strFullChar.indexOf("L") +
// 1);
//
// boolean isUVersion = arrSerialNum[12] + arrSerialNum[13] == 8 && arrSerialNum[2] + arrSerialNum[3] ==
// 9;// 验证旗舰版是否满足
// boolean isFVersion = arrSerialNum[6] * arrSerialNum[15] == 8 && arrSerialNum[2] * arrSerialNum[5] == 9;//
// 验证专业版是否满足
// boolean isPVersion = arrSerialNum[3] * arrSerialNum[4] == 8 && arrSerialNum[0] * arrSerialNum[13] == 9;//
// 验证个人版是否满足
// boolean isLVersion = arrSerialNum[0] * arrSerialNum[3] == 8 && arrSerialNum[1] == 9;// 验证精简版是否满足
// if (edition.equals("U")) {
// // 验证 TSEdition
// if (!isU) {
// System.getProperties().put("TSEdition", "");
// } else {
// if (isF) {
// System.getProperties().put("TSEdition", "");
// } else if (isP) {
// System.getProperties().put("TSEdition", "");
// } else if (isL) {
// System.getProperties().put("TSEdition", "");
// }
// }
// // 验证序列号
// if (isUVersion) {
// if (!(isFVersion) && !(isPVersion) && !(isLVersion)) {
// System.getProperties().put("TSVersion", "89");
// } else {
// System.getProperties().put("TSVersion", "");
// }
// } else {
// System.getProperties().put("TSVersion", "");
// }
// } else if (edition.equals("F")) {
// if (!isF) {
// System.getProperties().put("TSEdition", "");
// } else {
// if (isU) {
// System.getProperties().put("TSEdition", "");
// } else if (isP) {
// System.getProperties().put("TSEdition", "");
// } else if (isL) {
// System.getProperties().put("TSEdition", "");
// }
// }
// if (isFVersion) {
// if (!(isUVersion) && !(isPVersion) && !(isLVersion)) {
// System.getProperties().put("TSVersion", "89");
// } else {
// System.getProperties().put("TSVersion", "");
// }
// } else {
// System.getProperties().put("TSVersion", "");
// }
// } else if (edition.equals("P")) {
// if (!isP) {
// System.getProperties().put("TSEdition", "");
// } else {
// if (isU) {
// System.getProperties().put("TSEdition", "");
// } else if (isF) {
// System.getProperties().put("TSEdition", "");
// } else if (isL) {
// System.getProperties().put("TSEdition", "");
// }
// }
// if (isPVersion) {
// if (!(isUVersion) && !(isFVersion) && !(isLVersion)) {
// System.getProperties().put("TSVersion", "89");
// } else {
// System.getProperties().put("TSVersion", "");
// }
// } else {
// System.getProperties().put("TSVersion", "");
// }
// } else if (edition.equals("L")) {
// if (!isL) {
// System.getProperties().put("TSEdition", "");
// } else {
// if (isU) {
// System.getProperties().put("TSEdition", "");
// } else if (isF) {
// System.getProperties().put("TSEdition", "");
// } else if (isP) {
// System.getProperties().put("TSEdition", "");
// }
// }
// if (isLVersion) {
// if (!(isUVersion) && !(isFVersion) && !(isPVersion)) {
// System.getProperties().put("TSVersion", "89");
// } else {
// System.getProperties().put("TSVersion", "");
// }
// } else {
// System.getProperties().put("TSVersion", "");
// }
// }
// } else {
// System.getProperties().put("TSEdition", "");
// System.getProperties().put("TSVersion", "");
// }
} catch (MalformedURLException e) {
e.printStackTrace();
LOGGER.error(Messages.getString("preference.PreferenceUtil.logger1"), e);
} catch (XPathEvalException e) {
e.printStackTrace();
LOGGER.error(Messages.getString("preference.PreferenceUtil.logger1"), e);
} catch (NavException e) {
e.printStackTrace();
LOGGER.error(Messages.getString("preference.PreferenceUtil.logger1"), e);
} catch (XPathParseException e) {
e.printStackTrace();
LOGGER.error(Messages.getString("preference.PreferenceUtil.logger1"), e);
}
}
use of com.ximpleware.XPathParseException in project translationstudio8 by heartsome.
the class VTDUtils method getValue.
/**
* <p>
* 根据 XPath 取值(XPath 支持相对定位)。<br/>
* 使用此方法时,可以结合 {@link #pilot(String)} 或 {@link #pilot(AutoPilot, String)} 方法采用相对定位,可以大大提高导航效率
* </p>
* <b>注意</b>在XPath基础上,添加关键字“[name]”、“puretext()”的支持: <li>[name]:用于取得指定属性名称,例如,/a/@*[name] 取得 a 节点下所有属性的名字</li> <li>
* puretext():用于取得指定节点的纯文本内容(排除子节点),例如,/a/puretext() 取得 a 节点的纯文本内容</li>
* @param ap
* AutoPilot 实例
* @param xpath
* XPath 表达式
* @param defaultValue
* 默认值
* @return XPath 得到的值;
*/
public String getValue(AutoPilot ap, String xpath, String defaultValue) {
if (ap == null) {
ap = new AutoPilot(vn);
}
String value = null;
try {
vn.push();
if (xpath.endsWith("/puretext()")) {
xpath = xpath.substring(0, xpath.length() - "/puretext()".length());
ap.selectXPath(xpath);
if (ap.evalXPath() != -1) {
value = getElementPureText();
}
} else if (xpath.endsWith("/text()")) {
xpath = xpath.substring(0, xpath.length() - "/text()".length());
ap.selectXPath(xpath);
if (ap.evalXPath() != -1) {
value = getElementContent();
}
} else {
// 是否是取属性名字
boolean isAttrName = false;
if (xpath.endsWith("[name]")) {
xpath = xpath.substring(0, xpath.length() - "[name]".length());
isAttrName = true;
}
ap.selectXPath(xpath);
if (ap.evalXPath() != -1) {
int type = vn.getTokenType(vn.getCurrentIndex());
if (type == VTDNav.TOKEN_STARTING_TAG) {
long l = vn.getElementFragment();
value = vn.toString((int) l, (int) (l >> 32));
} else if (type == VTDNav.TOKEN_ATTR_NAME || type == VTDNav.TOKEN_ATTR_NS) {
if (isAttrName) {
value = vn.toString(vn.getCurrentIndex());
} else {
value = vn.toString(vn.getCurrentIndex() + 1);
}
} else {
value = vn.toString(vn.getCurrentIndex());
}
}
}
} catch (XPathParseException e) {
LOGGER.error("", e);
} catch (XPathEvalException e) {
LOGGER.error("", e);
} catch (NavException e) {
LOGGER.error("", e);
} finally {
vn.pop();
}
return value == null ? defaultValue : value;
}
use of com.ximpleware.XPathParseException in project translationstudio8 by heartsome.
the class VTDUtils method handleXML.
/**
* 处理 XPath 表达式所定位到的 XML 内容
* @param ap
* AutoPilot 实例
* @param xm
* XMLModifier 实例
* @param xpath
* xpath表达式
* @param newValue
* 要修改的新值
* @param condition
* 本次操作的限定条件
* @return XMLModifier 实例;
*/
private XMLModifier handleXML(AutoPilot ap, XMLModifier xm, String xpath, String newValue, int condition, boolean remove) {
try {
vn.push();
if (ap == null) {
ap = new AutoPilot(vn);
}
if (xm == null) {
xm = new XMLModifier(vn);
}
boolean pilotToEnd = (condition & PILOT_TO_END) != 0;
boolean isContent = false;
if (xpath.endsWith("/text()")) {
// 操作的是内容节点。
xpath = xpath.substring(0, xpath.length() - "/text()".length());
isContent = true;
}
ap.selectXPath(xpath);
boolean exist = false;
while (ap.evalXPath() != -1) {
exist = true;
long contentFragment = vn.getContentFragment();
int currentIndex = vn.getCurrentIndex();
int type = vn.getTokenType(currentIndex);
if (remove || newValue == null) {
// newValue 为 null,执行移除操作
if (isContent) {
if (contentFragment != -1) {
// 执行删除
// 删除内容
xm.remove(contentFragment);
}
} else {
// 属性节点不执行删除,除非调用 delete 方法(判断是否调用 delete 方法的依据是,newValue 是否为 null)
if ((type != VTDNav.TOKEN_ATTR_NAME && type != VTDNav.TOKEN_ATTR_NS) || newValue == null) {
// 删除节点
xm.remove();
}
}
}
if (newValue != null) {
// 执行修改
if (isContent) {
xm.insertBeforeTail(newValue.getBytes(getCharsetByEncoding()));
} else {
if (type == VTDNav.TOKEN_STARTING_TAG) {
xm.insertAfterElement(newValue);
} else if (type == VTDNav.TOKEN_ATTR_NAME || type == VTDNav.TOKEN_ATTR_NS) {
xm.updateToken(currentIndex + 1, newValue);
} else {
xm.updateToken(currentIndex, newValue.getBytes());
}
}
}
if (!pilotToEnd) {
// 不需要导航到 XML 末尾,停止循环
break;
}
}
boolean createIfNotExist = (condition & CREATE_IF_NOT_EXIST) != 0;
if (!exist && createIfNotExist) {
// 如果不存在并且需要创建
int lastSeperator = xpath.lastIndexOf("/");
String nodeName = xpath.substring(lastSeperator + 1);
// 截掉最后一部分
xpath = xpath.substring(0, lastSeperator);
if (nodeName.startsWith("@")) {
nodeName = nodeName.substring(1);
ap.selectXPath(xpath);
while (ap.evalXPath() != -1) {
// 插入属性
insertAttribute(xm, nodeName, newValue);
if (!pilotToEnd) {
// 不需要导航到 XML 末尾,停止循环
break;
}
}
} else {
if (isContent) {
// 如果改动的是节点内容
newValue = getNodeXML(nodeName, newValue, null);
ap.selectXPath(xpath);
while (ap.evalXPath() != -1) {
xm.insertAfterHead(newValue);
if (!pilotToEnd) {
// 不需要导航到 XML 末尾,停止循环
break;
}
}
}
}
}
} catch (XPathParseException e) {
LOGGER.error("", e);
} catch (XPathEvalException e) {
LOGGER.error("", e);
} catch (NavException e) {
LOGGER.error("", e);
} catch (ModifyException e) {
LOGGER.error("", e);
} catch (UnsupportedEncodingException e) {
LOGGER.error("", e);
} finally {
vn.pop();
}
return xm;
}
use of com.ximpleware.XPathParseException in project translationstudio8 by heartsome.
the class VTDUtils method getValues.
/**
* 根据 XPath 取一个集合的值。<br/>
* <b>注意</b>在XPath基础上,添加关键字“[name]”、“puretext()”的支持: <li>[name]:用于取得指定属性名称,例如,/a/@*[name] 取得 a 节点下所有属性的名字</li> <li>
* puretext():用于取得指定节点的纯文本内容(排除子节点),例如,/a/puretext() 取得 a 节点的纯文本内容</li>
* @param ap
* AutoPilot 对象
* @param xpath
* XPath 表达式
* @param isAllowRepeat
* 是否允许取值重复。
* @return XPath 得到的值,无匹配的值则为 null;
*/
public List<String> getValues(AutoPilot ap, String xpath, boolean isAllowRepeat) {
if (ap == null) {
ap = new AutoPilot(vn);
}
List<String> values = new Vector<String>();
try {
vn.push();
if (xpath.endsWith("/puretext()")) {
xpath = xpath.substring(0, xpath.length() - "/puretext()".length());
ap.selectXPath(xpath);
if (ap.evalXPath() != -1) {
String strTmpValue = getElementPureText();
if (isAllowRepeat) {
values.add(strTmpValue);
} else {
if (!values.contains(strTmpValue)) {
values.add(strTmpValue);
}
}
}
} else if (xpath.endsWith("/text()")) {
xpath = xpath.substring(0, xpath.length() - "/text()".length());
ap.selectXPath(xpath);
while (ap.evalXPath() != -1) {
String strTmpValue = getElementContent();
if (isAllowRepeat) {
values.add(strTmpValue);
} else {
if (!values.contains(strTmpValue)) {
values.add(strTmpValue);
}
}
}
} else {
boolean isAttrName = false;
if (xpath.endsWith("[name]")) {
xpath = xpath.substring(0, xpath.length() - "[name]".length());
isAttrName = true;
}
ap.selectXPath(xpath);
while (ap.evalXPath() != -1) {
int type = vn.getTokenType(vn.getCurrentIndex());
if (type == VTDNav.TOKEN_STARTING_TAG) {
long l = vn.getElementFragment();
String strTmpValue = vn.toString((int) l, (int) (l >> 32));
if (isAllowRepeat) {
values.add(strTmpValue);
} else {
if (!values.contains(strTmpValue)) {
values.add(strTmpValue);
}
}
} else if (type == VTDNav.TOKEN_ATTR_NAME || type == VTDNav.TOKEN_ATTR_NS) {
String strTmpValue;
if (isAttrName) {
strTmpValue = vn.toString(vn.getCurrentIndex());
} else {
strTmpValue = vn.toString(vn.getCurrentIndex() + 1);
}
if (isAllowRepeat) {
values.add(strTmpValue);
} else {
if (!values.contains(strTmpValue)) {
values.add(strTmpValue);
}
}
} else {
String strTmpValue = vn.toString(vn.getCurrentIndex());
if (isAllowRepeat) {
values.add(strTmpValue);
} else {
if (!values.contains(strTmpValue)) {
values.add(strTmpValue);
}
}
}
}
}
} catch (XPathParseException e) {
LOGGER.error("", e);
} catch (XPathEvalException e) {
LOGGER.error("", e);
} catch (NavException e) {
LOGGER.error("", e);
} finally {
vn.pop();
}
if (values.size() == 0) {
values = null;
}
return values;
}
use of com.ximpleware.XPathParseException in project translationstudio8 by heartsome.
the class DocUtils method isTMX.
/**
* 判断是否是正确的 TMX 文件
* @param fileName
* @return ;
* @throws FileNotFoundException
* @throws ParseException
* @throws EntityException
* @throws EOFException
* @throws EncodingException
*/
public static VTDUtils isTMX(String fileName) throws FileNotFoundException, EncodingException, ParseException {
VTDGen vg = new VTDGen();
FileInputStream fis = null;
File f = null;
try {
f = new File(fileName);
fis = new FileInputStream(f);
byte[] b = new byte[(int) f.length()];
int offset = 0;
int numRead = 0;
// I choose this value randomally,
int numOfBytes = 1048576;
// any other (not too big) value also can be here.
if (b.length - offset < numOfBytes) {
numOfBytes = b.length - offset;
}
while (offset < b.length && (numRead = fis.read(b, offset, numOfBytes)) >= 0) {
offset += numRead;
if (b.length - offset < numOfBytes) {
numOfBytes = b.length - offset;
}
}
vg.setDoc(b);
vg.parse(true);
} catch (IOException e) {
LOGGER.error(Messages.getString("document.DocUtils.logger1"), e);
} finally {
if (fis != null) {
try {
fis.close();
} catch (Exception e) {
}
}
}
VTDNav vn = vg.getNav();
AutoPilot ap = new AutoPilot(vn);
String rootPath = "/tmx";
VTDUtils vu = new VTDUtils();
try {
vu.bind(vn);
ap.selectXPath(rootPath);
if (ap.evalXPath() == -1) {
return null;
}
} catch (NavException e) {
LOGGER.error(Messages.getString("document.DocUtils.logger2"), e);
return null;
} catch (XPathEvalException e) {
LOGGER.error(Messages.getString("document.DocUtils.logger2"), e);
return null;
} catch (XPathParseException e) {
LOGGER.error(Messages.getString("document.DocUtils.logger2"), e);
return null;
} finally {
vg.clear();
}
return vu;
}
Aggregations