List of usage examples for org.dom4j Node selectSingleNode
Node selectSingleNode(String xpathExpression);
selectSingleNode
evaluates an XPath expression and returns the result as a single Node
instance.
From source file:com.noterik.bart.fs.fscommand.CommandHandler.java
License:Open Source License
/** * Load a specific command/*from www . j a va2 s .c o m*/ * @param cid the command to load * @return the command object loaded */ private Command loadCommand(String cid) { File file = new File(GlobalConfig.instance().getBaseDir() + "conf/" + CONFIG_FILE); Document doc = XMLHelper.getXmlFromFile(file); if (doc != null) { List<Node> nl = doc.selectNodes("//command"); for (Node n : nl) { if (n instanceof Element) { if (n.getName() != null && n.getName().equals("command")) { Node idn = n.selectSingleNode("./id"); Node cln = n.selectSingleNode("./class"); Node jn = n.selectSingleNode("./jar"); if (idn != null && cln != null) { String id = idn.getText(); String cl = cln.getText(); String jar = null; if (id != null && cl != null && id.equals(cid)) { if (jn != null && cl != null) { jar = jn.getText(); } try { if (jar != null) { logger.info("Loading jar " + jar + " for class " + cl); Class<?> commandClass = loadJar(jar, cl); if (commandClass != null) { Command o = (Command) commandClass.newInstance(); commands.put(id, o); } } else { Class c = Class.forName(cl); Object o = c.newInstance(); if (o instanceof Command) { commands.put(id, (Command) o); } } } catch (ClassNotFoundException e) { logger.error("", e); } catch (InstantiationException e) { logger.error("", e); } catch (IllegalAccessException e) { logger.error("", e); } } } } } } } return commands.get(cid); }
From source file:com.noterik.bart.fs.fscommand.CopyCommand.java
License:Open Source License
/** * Copy resource specified by the input parameters. * //ww w . j ava 2 s.com * @param input input parameters * @param uri local directory * @return status/error message */ private String copy(Properties input, String uri) { String res = null; // get input parameters String source = input.getProperty("source"); String destination = input.getProperty("destination"); String params = input.getProperty("params"); logger.debug("source: " + source + ", destination: " + destination + ", params: " + params); //System.out.println("source: "+source+", destination: "+destination+", params: "+params); // determine optional parameters boolean recursive = false, override = false; if (params != null) { recursive = params.contains("-r"); override = params.contains("-o"); } // check input parameters if (source == null || destination == null) { return FSXMLBuilder.getErrorMessage("500", "No source or destination", "Please provide the SOURCE and DESTINATION input parameters", "http://teamelements.noterik.com/team"); } // resolve uris String sourceUri = URIParser.resolveLocalUri(source, uri); if (sourceUri.lastIndexOf("/") == sourceUri.length() - 1) { sourceUri = sourceUri.substring(0, sourceUri.lastIndexOf("/")); } String destinationUri = URIParser.resolveLocalUri(destination, uri); if (destinationUri.lastIndexOf("/") == destinationUri.length() - 1) { destinationUri = destinationUri.substring(0, destinationUri.lastIndexOf("/")); } logger.debug("ABSOLUTE URIS -- source: " + sourceUri + ", destination: " + destinationUri); // check if uri is an uri of type id String typeSource = URIParser.getResourceTypeFromUri(sourceUri); String cpDest = URIParser.getCurrentUriPart(destinationUri); if (!URIParser.isResourceId(sourceUri)) { return FSXMLBuilder.getErrorMessage("500", "Invalid source specified, only id nodes permitted.", "Invalid source specified, only id nodes permitted.", "http://teamelements.noterik.com/team"); } String docStr = null; String refer = null; if (recursive) { // get properties of source Document doc = getPropertiesOfUri(sourceUri, -1); logger.debug("document being created: " + doc.asXML()); // exception for first node Element root = doc.getRootElement(); Node first = root.selectSingleNode("//" + typeSource); refer = first.valueOf("@referid"); List<Node> children = first.selectNodes("child::*"); for (Iterator<Node> iter = children.iterator(); iter.hasNext();) { Node node = iter.next(); docStr += node.asXML(); } docStr = "<fsxml>" + docStr + "</fsxml>"; logger.debug("document being created after first node exception: " + docStr); } else { // get properties of source Document doc = getPropertiesOfUri(sourceUri, 0); logger.debug("document being created: " + doc.asXML()); // exception for first node Element root = doc.getRootElement(); Node first = root.selectSingleNode("//" + typeSource); Node properties = first.selectSingleNode("properties"); refer = first.valueOf("@referid"); docStr = "<fsxml>" + properties.asXML() + "</fsxml>"; logger.debug("document being created after first node exception: " + docStr); } // check if dest ends with 'properties' String newResourceUri = null; if (cpDest.equals(FSXMLHelper.XML_PROPERTIES)) { logger.debug("putting to " + destinationUri); res = rHandler.handlePUT(destinationUri, docStr); newResourceUri = URIParser.getParentUri(destinationUri); } else if (URIParser.isResourceId(destinationUri)) { destinationUri += "/" + FSXMLHelper.XML_PROPERTIES; logger.debug("putting to " + destinationUri); res = rHandler.handlePUT(destinationUri, docStr); newResourceUri = URIParser.getParentUri(destinationUri); } else { logger.debug("posting to " + destinationUri); res = rHandler.handlePOST(destinationUri, docStr); try { if (FSXMLParser.getErrorMessageFromXml(res) == null) { Document respDoc = DocumentHelper.parseText(res); newResourceUri = respDoc.valueOf("//uri"); } } catch (Exception e) { logger.error("", e); } } // add refer of first node if (refer != null && !refer.equals("")) { logger.debug("adding refer for first node (" + refer + ")"); boolean ok = rHandler.saveAttributes(newResourceUri, "<fsxml><attributes><referid>" + refer + "</referid></attributes></fsxml>", "PUT"); logger.debug("attributes added: " + ok); } else { logger.debug("not need for adding refer id"); } logger.debug("response: " + res); return res; }
From source file:com.noterik.bart.fs.fscommand.dynamic.playlist.util.TimeLine.java
License:Open Source License
public List<Node> getSortedList(List<Node> input) { final class SortElement implements Comparator<SortElement> { // start stepping through the array from the beginning public double starttime; public Node value; public int compare(SortElement n, SortElement n2) { return (n.starttime < n2.starttime ? -1 : (n.starttime == n2.starttime ? 0 : 1)); }/*from www . j a va 2 s .c om*/ } List<SortElement> sorted = new ArrayList<SortElement>(); for (Iterator<Node> i = input.iterator(); i.hasNext();) { Node block = i.next(); SortElement sn = new SortElement(); sn.starttime = Double.parseDouble(block.selectSingleNode("properties/starttime").getText()); sn.value = block; sorted.add(sn); } Collections.sort(sorted, new SortElement()); List<Node> result = new ArrayList<Node>(); for (Iterator<SortElement> i = sorted.iterator(); i.hasNext();) { SortElement e = i.next(); result.add(e.value); } return result; }
From source file:com.noterik.bart.fs.fscommand.dynamic.presentation.playout.flash.java
License:Open Source License
private static Node getPresentationConfig(String presentation, Node presentationXml, config c) { Document tmpConf = null;/*from w ww . j a v a 2 s . c om*/ // domain conf logger.debug("before domain conf"); String url = "/domain/" + c.getDomain() + "/config/presentation/filesystem/1"; Document conf = cache.get(url); if (conf == null) { conf = FSXMLRequestHandler.instance().getNodeProperties(url, false); cache.put(url, conf); } logger.debug("after domain conf"); Boolean allowReplace = conf.selectSingleNode("/fsxml/filesystem[@id='1']/properties/allow_replace") == null ? false : Boolean.valueOf( conf.selectSingleNode("/fsxml/filesystem[@id='1']/properties/allow_replace").getText()); //check if presentation has a sponsor, take his config String sponsor = presentationXml.selectSingleNode("//presentation/properties/sponsor") == null ? null : presentationXml.selectSingleNode("//presentation/properties/sponsor").getText(); if (sponsor != null) { logger.debug("found sponsor in presentation = " + sponsor); // sponsor conf logger.debug("before sponsor conf"); tmpConf = cache.get(url); if (tmpConf == null && !cache.isEmpty(sponsor + "/config/presentation/filesystem/1")) { tmpConf = FSXMLRequestHandler.instance() .getNodeProperties(sponsor + "/config/presentation/filesystem/1", false); cache.put(sponsor + "/config/presentation/filesystem/1", tmpConf); } logger.debug("after sponsor conf"); if (tmpConf != null && (conf == null || !allowReplace)) { conf = tmpConf; allowReplace = conf.selectSingleNode("/fsxml/filesystem[@id='1']/properties/allow_replace") == null ? false : Boolean.valueOf(conf .selectSingleNode("/fsxml/filesystem[@id='1']/properties/allow_replace").getText()); } else if (tmpConf != null && allowReplace) { handleIncludeExcludeNodes(conf, tmpConf); allowReplace = tmpConf .selectSingleNode("/fsxml/filesystem[@id='1']/properties/allow_replace") == null ? false : Boolean.valueOf(tmpConf .selectSingleNode("/fsxml/filesystem[@id='1']/properties/allow_replace") .getText()); tmpConf = null; } } // user conf logger.debug("before user conf"); tmpConf = cache .get("/domain/" + c.getDomain() + "/user/" + c.getUser() + "/config/presentation/filesystem/1"); if (tmpConf == null && !cache.isEmpty( "/domain/" + c.getDomain() + "/user/" + c.getUser() + "/config/presentation/filesystem/1")) { tmpConf = FSXMLRequestHandler.instance().getNodeProperties( "/domain/" + c.getDomain() + "/user/" + c.getUser() + "/config/presentation/filesystem/1", false); cache.put("/domain/" + c.getDomain() + "/user/" + c.getUser() + "/config/presentation/filesystem/1", tmpConf); } logger.debug("after sponsor conf"); if (tmpConf != null && (conf == null || !allowReplace)) { conf = tmpConf; allowReplace = conf.selectSingleNode("/fsxml/filesystem[@id='1']/properties/allow_replace") == null ? false : Boolean.valueOf( conf.selectSingleNode("/fsxml/filesystem[@id='1']/properties/allow_replace").getText()); } else if (tmpConf != null && allowReplace) { handleIncludeExcludeNodes(conf, tmpConf); allowReplace = tmpConf.selectSingleNode("/fsxml/filesystem[@id='1']/properties/allow_replace") == null ? false : Boolean.valueOf(tmpConf .selectSingleNode("/fsxml/filesystem[@id='1']/properties/allow_replace").getText()); tmpConf = null; } // user collection conf logger.debug("before collection conf"); tmpConf = cache.get("/domain/" + c.getDomain() + "/user/" + c.getUser() + "/collection/" + c.getCollection() + "/config/presentation/filesystem/1"); if (tmpConf == null && !cache.isEmpty("/domain/" + c.getDomain() + "/user/" + c.getUser() + "/collection/" + c.getCollection() + "/config/presentation/filesystem/1")) { tmpConf = FSXMLRequestHandler.instance().getNodeProperties("/domain/" + c.getDomain() + "/user/" + c.getUser() + "/collection/" + c.getCollection() + "/config/presentation/filesystem/1", false); cache.put("/domain/" + c.getDomain() + "/user/" + c.getUser() + "/collection/" + c.getCollection() + "/config/presentation/filesystem/1", tmpConf); } logger.debug("after collection conf"); if (tmpConf != null) { String refer = tmpConf.selectSingleNode("/fsxml/filesystem/@referid") == null ? "" : tmpConf.selectSingleNode("/fsxml/filesystem/@referid").getText(); if (!refer.equals("")) { tmpConf = FSXMLRequestHandler.instance().getNodeProperties(refer, false); } } if (tmpConf != null && (conf == null || !allowReplace)) { conf = tmpConf; } else if (tmpConf != null && allowReplace) { handleIncludeExcludeNodes(conf, tmpConf); } if (conf != null) { return conf.selectSingleNode("fsxml/filesystem[@id='1']").detach(); } return null; }
From source file:com.taobao.datax.engine.conf.ParseXMLUtil.java
License:Open Source License
/** * Parse plugins configuration file, get all plugin configurations * //w ww . java 2s. co m * @return a map mapping plugin name to plugin configurations * */ @SuppressWarnings("unchecked") public static Map<String, PluginConf> loadPluginConfig() { Map<String, PluginConf> plugins = new HashMap<String, PluginConf>(); File file = new File(Constants.PLUGINSXML); SAXReader saxReader = new SAXReader(); Document document = null; try { document = saxReader.read(file); } catch (DocumentException e) { LOG.error("DataX Can not find " + Constants.PLUGINSXML); throw new DataExchangeException(e.getCause()); } String xpath = "/plugins/plugin"; List<Node> pluginnode = (List<Node>) document.selectNodes(xpath); for (Node node : pluginnode) { PluginConf plugin = new PluginConf(); plugin.setVersion(node.selectSingleNode("./version").getStringValue()); plugin.setName(node.selectSingleNode("./name").getStringValue()); plugin.setTarget(node.selectSingleNode("./target").getStringValue()); plugin.setJar(node.selectSingleNode("./jar").getStringValue()); plugin.setType(node.selectSingleNode("./type").getStringValue()); plugin.setClassName(node.selectSingleNode("./class").getStringValue()); plugin.setMaxthreadnum(Integer.parseInt(node.selectSingleNode("./maxthreadnum").getStringValue())); if (node.selectSingleNode("./path") != null) plugin.setPath(node.selectSingleNode("./path").getStringValue()); plugins.put(plugin.getName(), plugin); } return plugins; }
From source file:com.taobao.tddl.common.sequence.Config.java
License:Open Source License
public static Config createConfig(Node generator) throws ConfigException { Config config = new Config(); String typeStr = generator.valueOf("@type"); if (typeStr == null || "".equals(typeStr) || "default".equals(typeStr)) { config.setType(DEFAULT);/*from w ww. jav a 2 s .c o m*/ } else if ("long2date".equals(typeStr)) { config.setType(Long2DATE); } else { throw new Config.ConfigException("unsupported generator type!"); } Node route = generator.selectSingleNode("route"); if (route != null) { String position = route.valueOf("@position"); if ("right".equals(position) || "".equals(position)) { config.setPositionRight(true); } else if ("left".equals(position)) { config.setPositionRight(false); } else { throw new Config.ConfigException(); } String overFlowCheckStr = route.valueOf("@overflowcheck"); if ("on".equals(overFlowCheckStr) || "".equals(overFlowCheckStr)) { config.setOverFlowCheck(true); } else if ("off".equals(overFlowCheckStr)) { config.setOverFlowCheck(false); } else { throw new Config.ConfigException(); } String totalSizeStr = route.valueOf("@size"); if (totalSizeStr != null && !"".equals(totalSizeStr)) { try { config.setTotalSize(Integer.parseInt(totalSizeStr)); } catch (NumberFormatException e) { throw new Config.ConfigException(); } } Node database = route.selectSingleNode("database"); int routeSize = 0; if (database != null) { Route dbRoute = new Route(); try { dbRoute.setSize(Integer.parseInt(database.valueOf("@size"))); routeSize += dbRoute.getSize(); } catch (NumberFormatException e) { throw new Config.ConfigException(); } dbRoute.setExpression(ExpressionFactory.create(database.selectSingleNode("*"))); config.setDatabaseRoute(dbRoute); } Node table = route.selectSingleNode("table"); if (table != null) { Route tableRoute = new Route(); try { tableRoute.setSize(Integer.parseInt(table.valueOf("@size"))); routeSize += tableRoute.getSize(); } catch (NumberFormatException e) { throw new Config.ConfigException(); } tableRoute.setExpression(ExpressionFactory.create(table.selectSingleNode("*"))); config.setTablerRoute(tableRoute); } if (config.isOverFlowCheck() && routeSize > 8) { throw new Config.ConfigException("id()8"); } if (config.getTotalSize() != 0 && routeSize != 0 && config.getTotalSize() != routeSize) { throw new Config.ConfigException(); } } return config; }
From source file:com.thoughtworks.cruise.page.AlreadyOnSourceXmlTab.java
License:Apache License
@com.thoughtworks.gauge.Step("Config xml should have an environment <environmentName> with environment variable <name> <value>") public void configXmlShouldHaveAnEnvironmentWithEnvironmentVariable(String environmentName, String name, String value) throws Exception { CruiseConfigDom cruiseConfigDom = getCruiseConfigDom(); Element environment = cruiseConfigDom.getEnvironment(environmentName); Assert.assertThat("Environment not found", environment, notNullValue()); Node elementVar = environment .selectSingleNode(String.format("environmentvariables/variable[@name=\"%s\"]", name)); Assert.assertThat("Environment variable not found", elementVar, notNullValue()); Assert.assertThat("invalid environment variable value", elementVar.selectSingleNode("value").getText(), Matchers.is(value));/*from w w w . j a v a 2s. co m*/ }
From source file:com.weibo.datasys.crawler.base.factory.TaskFactory.java
License:Open Source License
/** * /* ww w . j av a 2 s. c om*/ * * * @param task * @param doc */ @SuppressWarnings("unchecked") private static void buildSaveStrategy(Task task, Document doc) throws Exception { SaveStrategy saveStrategy = new SaveStrategy(task); task.setSaveStrategy(saveStrategy); // ??? saveStrategy.setSeedDS(doc.selectSingleNode("//Config/SaveStrategy/seedDB/dsname").getText().trim()); saveStrategy.setSeedDB(doc.selectSingleNode("//Config/SaveStrategy/seedDB/db").getText().trim()); saveStrategy.setSeedTable(doc.selectSingleNode("//Config/SaveStrategy/seedDB/table").getText().trim()); // ? saveStrategy.setLinkDS(doc.selectSingleNode("//Config/SaveStrategy/linkDB/dsname").getText().trim()); saveStrategy.setLinkDB(doc.selectSingleNode("//Config/SaveStrategy/linkDB/db").getText().trim()); saveStrategy.setLinkTable(doc.selectSingleNode("//Config/SaveStrategy/linkDB/table").getText().trim()); // ? saveStrategy.setPageDS(doc.selectSingleNode("//Config/SaveStrategy/pageDB/dsname").getText().trim()); saveStrategy.setPageDB(doc.selectSingleNode("//Config/SaveStrategy/pageDB/db").getText().trim()); saveStrategy.setPageTable(doc.selectSingleNode("//Config/SaveStrategy/pageDB/table").getText().trim()); List<Node> saveRuleNodes = doc.selectNodes("//Config/SaveStrategy/saveRule"); for (Node saveRuleNode : saveRuleNodes) { String saveRuleName = saveRuleNode.selectSingleNode("@name").getText().trim(); String saveRuleClass = saveRuleNode.selectSingleNode("@class").getText().trim(); AbstractSaveRule saveRule = (AbstractSaveRule) Class.forName(saveRuleClass).getConstructor(Task.class) .newInstance(task); saveRule.setName(saveRuleName); saveRule.configWithParameters(getParaMap(saveRuleNode)); saveStrategy.addSaveRule(saveRule); } }
From source file:com.weibo.datasys.crawler.base.factory.TaskFactory.java
License:Open Source License
/** * //www . j a va 2 s . c o m * ? * * @param task * @param doc */ @SuppressWarnings("unchecked") private static void buildParseStrategy(Task task, Document doc) throws Exception { ParseStrategy parseStrategy = new ParseStrategy(task); task.setParseStrategy(parseStrategy); // Field??? List<Node> fieldRuleNodes = doc.selectNodes("//Config/ParseStrategy/FieldRule"); for (Node fieldRuleNode : fieldRuleNodes) { FieldRule fieldRule = new FieldRule(task); fieldRule.configWithParameters(getParaMap(fieldRuleNode)); parseStrategy.addFieldRule(fieldRule); // ??? Node contentRuleNode = fieldRuleNode.selectSingleNode("contentExtractRule"); String contentRuleClass = contentRuleNode.selectSingleNode("@class").getText().trim(); AbstractContentExtractRule contentRule = (AbstractContentExtractRule) Class.forName(contentRuleClass) .getConstructor(Task.class).newInstance(task); contentRule.configWithParameters(getParaMap(contentRuleNode)); fieldRule.setContentRule(contentRule); // ?s List<Node> processRuleNodes = fieldRuleNode.selectNodes("processRule"); for (Node processRuleNode : processRuleNodes) { String processRuleClass = processRuleNode.selectSingleNode("@class").getText().trim(); AbstractProcessRule processRule = (AbstractProcessRule) Class.forName(processRuleClass) .getConstructor(Task.class).newInstance(task); processRule.configWithParameters(getParaMap(processRuleNode)); fieldRule.addProcessRule(processRule); } // s List<Node> filterNodes = fieldRuleNode.selectNodes("filterRule"); for (Node filterNode : filterNodes) { // ??? String filterClass = filterNode.selectSingleNode("@class").getText().trim(); AbstractFilterRule filterRule = (AbstractFilterRule) Class.forName(filterClass) .getConstructor(Task.class).newInstance(task); // ??? filterRule.configWithParameters(getParaMap(filterNode)); fieldRule.addFilter(filterRule); } } }
From source file:com.weibo.datasys.crawler.base.factory.TaskFactory.java
License:Open Source License
/** * /*from w w w.j ava2s . c o m*/ * ? * * @param task * @param doc * @throws Exception */ @SuppressWarnings("unchecked") private static void buildCrawlStrategy(Task task, Document doc) throws Exception { CrawlStrategy crawlStrategy = new CrawlStrategy(task); task.setCrawlStrategy(crawlStrategy); // String priorityString = doc.selectSingleNode("//Config/CrawlStrategy/priority").getText().trim(); crawlStrategy.setPriority(StringUtils.parseInt(priorityString, 0)); // ? String siteEncoding = doc.selectSingleNode("//Config/CrawlStrategy/siteEncoding").getText().trim(); crawlStrategy.setSiteEncoding(siteEncoding); // ? String maxCrawlDepthString = doc.selectSingleNode("//Config/CrawlStrategy/maxCrawlDepth").getText().trim(); int maxCrawlDepth = StringUtils.parseInt(maxCrawlDepthString, Integer.MAX_VALUE); if (maxCrawlDepth <= 0) { maxCrawlDepth = Integer.MAX_VALUE; } crawlStrategy.setMaxCrawlDepth(maxCrawlDepth); // ??? Node seedRuleNode = doc.selectSingleNode("//Config/CrawlStrategy/seedGenerateRule"); String seedRuleClass = seedRuleNode.selectSingleNode("@class").getText().trim(); // ??? AbstractSeedGenerateRule seedRule = (AbstractSeedGenerateRule) Class.forName(seedRuleClass) .getConstructor(Task.class).newInstance(task); seedRule.configWithParameters(getParaMap(seedRuleNode)); crawlStrategy.setSeedRule(seedRule); // ? ConcurrentControlRule concurrentRule = new ConcurrentControlRule(task); crawlStrategy.setConcurrentRule(concurrentRule); Node controlRuleNode = doc.selectSingleNode("//Config/CrawlStrategy/concurrentControlRule"); concurrentRule.configWithParameters(getParaMap(controlRuleNode)); // ? List<Node> crawlRuleNodes = doc.selectNodes("//Config/CrawlStrategy/crawlRule"); for (Node crawlRuleNode : crawlRuleNodes) { CrawlRule crawlRule = new CrawlRule(task); // ??? crawlRule.configWithParameters(getParaMap(crawlRuleNode)); // crawlStrategy.addCrawlRule(crawlRule); // url??? List<Node> urlExtractNodes = crawlRuleNode.selectNodes("urlExtractRule"); for (Node urlExtractNode : urlExtractNodes) { UrlExtractRule urlExtractRule = new UrlExtractRule(task); // ??? urlExtractRule.configWithParameters(getParaMap(urlExtractNode)); crawlRule.addUrlExtractRule(urlExtractRule); // ?s List<Node> processNodes = urlExtractNode.selectNodes("processRule"); for (Node processNode : processNodes) { // ??? String processClass = processNode.selectSingleNode("@class").getText().trim(); AbstractProcessRule processRule = (AbstractProcessRule) Class.forName(processClass) .getConstructor(Task.class).newInstance(task); // ??? processRule.configWithParameters(getParaMap(processNode)); urlExtractRule.addProcessRule(processRule); } // s List<Node> filterNodes = urlExtractNode.selectNodes("filterRule"); for (Node filterNode : filterNodes) { // ??? String filterClass = filterNode.selectSingleNode("@class").getText().trim(); AbstractFilterRule filterRule = (AbstractFilterRule) Class.forName(filterClass) .getConstructor(Task.class).newInstance(task); // ??? filterRule.configWithParameters(getParaMap(filterNode)); urlExtractRule.addFilter(filterRule); } } // http? Node httpParaNode = crawlRuleNode.selectSingleNode("httpRequest"); Map<String, String> paraMap = getParaMap(httpParaNode); crawlRule.setHttpReqParameters(paraMap); } }