List of usage examples for org.dom4j Element elements
List<Element> elements();
From source file:com.devoteam.srit.xmlloader.core.operations.basic.OperationTestOr.java
License:Open Source License
/** * Constructor// ww w . j av a2 s.co m * * @param operationsTests list of tests */ public OperationTestOr(Element root, Scenario scenario) throws Exception { super(root, null); this.scenario = scenario; this.operations = new ArrayList(); for (Object object : root.elements()) { Element element = (Element) object; this.operations.add(scenario.parseOperation(element)); } }
From source file:com.devoteam.srit.xmlloader.core.operations.protocol.OperationReceiveMessage.java
License:Open Source License
/** * Parses the operation from a root element *///from ww w .j a v a 2 s .com private void parse(Element root) throws Exception { List<Element> list = root.elements(); for (Element element : list) { operations.add(scenario.parseOperation(element)); } }
From source file:com.devoteam.srit.xmlloader.core.Scenario.java
License:Open Source License
/** * Parse the scenario//from ww w.j a v a 2s. c o m */ private void parse(XMLDocument scenarioDocument) throws Exception { //String relativePath = getFilename(); //XMLDocument scenarioDocument = XMLDocumentCache.getXMLDocument(URIRegistry.MTS_TEST_HOME.resolve(relativePath), URIFactory.newURI("../conf/schemas/scenario.xsd")); Element root = scenarioDocument.getDocument().getRootElement(); /** * Check the position of the finally tag */ boolean isFinallyLast = false; int finallyInstances = 0; List<Element> elements = root.elements(); for (Element element : elements) { isFinallyLast = false; if (element.getName().equals("finally")) { isFinallyLast = true; finallyInstances++; } } if (finallyInstances == 1 && !isFinallyLast) { throw new ParsingException("Finally must be the last operation of the scenario."); } else if (finallyInstances > 1) { throw new ParsingException("There must be at most one finally operation."); } /** * Create the finally operations sequence. If there is a finally then the sequence is created and then the finally tag is removed from the scenario. To allow the creation of the scenario * operations sequence. */ if (finallyInstances == 1) { Element finallyRoot = root.element("finally"); root.remove(finallyRoot); this._operationSequenceFinally = new OperationSequence(finallyRoot, this); } _operationSequenceScenario = new OperationSequence(root, this); }
From source file:com.devoteam.srit.xmlloader.core.utils.XMLTree.java
License:Open Source License
private void listMatchingElements(Element element, String regex, boolean recurse) { ////from w ww . j av a 2 s .c o m // First check attributes // List<Attribute> namedNodeMap = element.attributes(); if (null != namedNodeMap) { for (Attribute attribute : namedNodeMap) { String value = attribute.getValue(); if (Utils.containsRegex(value, regex)) { if (false == elementsMap.containsKey(element)) { elementsMap.put(element, null); elementsOrder.addFirst(element); } } } } // // Then check text // if (Utils.containsRegex(element.getText(), regex)) { if (false == elementsMap.containsKey(element)) { elementsMap.put(element, null); elementsOrder.addFirst(element); } } // // Finally elements // if (recurse) { List<Element> childrens = element.elements(); for (Element child : childrens) { listMatchingElements(child, regex, recurse); } } }
From source file:com.devoteam.srit.xmlloader.diameter.MsgDiameterParser.java
License:Open Source License
public void doDictionnary(Element root, String applicationId, boolean recurse) throws ParsingException { Application application = Dictionary.getInstance().getApplication(applicationId); if (null == application) { throw new ParsingException("Unknown \"applicationId\" attribute in header: " + applicationId); }/*www . j a va 2s . c o m*/ Element unmodifiedRoot = root.createCopy(); if (root.getName().equalsIgnoreCase("header")) { // // ApplicationId // String attributeValue; attributeValue = root.attributeValue("applicationId"); if (!Utils.isInteger(attributeValue)) { root.attribute("applicationId").setValue(Integer.toString(application.get_id())); } // // CommandCode // attributeValue = root.attributeValue("command"); if (!Utils.isInteger(attributeValue)) { CommandDef commandDef = Dictionary.getInstance().getCommandDefByName(attributeValue, applicationId); if (commandDef == null) { throw (new ParsingException( "Unknown \"command\" attribute in header: " + attributeValue + "skipp it")); } root.attribute("command").setValue(Integer.toString(commandDef.get_code())); } } else if (root.getName().equalsIgnoreCase("avp")) { boolean isTypeAppId = false; boolean isTypeVendorId = false; String attributeValue; attributeValue = root.attributeValue("code"); // // Set default values implied by code in XMLTree from dictionnary // if (null != attributeValue) { AvpDef avpDef; if (!Utils.isInteger(attributeValue)) { avpDef = Dictionary.getInstance().getAvpDefByName(attributeValue, applicationId); } else { avpDef = Dictionary.getInstance().getAvpDefByCode(Integer.parseInt(attributeValue), applicationId); } if (null == avpDef) { // // If the code value is an integer, we don't necessary have to know it in the dictionnary. // However, if it isn't, we have to. // } // // Handle the code attribute // if (null != avpDef) { root.addAttribute("code", Integer.toString(avpDef.get_code())); } // // Handle the type attribute // if (null == root.attribute("type") && null != avpDef) { TypeDef typeDef = avpDef.get_type(); if (null != typeDef) { while (null != typeDef.get_type_parent()) { if (typeDef.get_type_name().equalsIgnoreCase("AppId")) isTypeAppId = true; if (typeDef.get_type_name().equalsIgnoreCase("VendorId")) isTypeVendorId = true; typeDef = typeDef.get_type_parent(); } root.addAttribute("type", typeDef.get_type_name()); } } // // Handle the vendorId attribute // if (null == root.attribute("vendorId") && null != avpDef) { VendorDef vendorDef = avpDef.get_vendor_id(); if (null != vendorDef) { root.addAttribute("vendorId", Integer.toString(vendorDef.get_code())); } } // // Handle the mandatory attribute // if (null == root.attribute("mandatory")) { if (null != avpDef && null != avpDef.get_mandatory() && avpDef.get_mandatory().equals("mustnot")) { root.addAttribute("mandatory", "false"); } else { root.addAttribute("mandatory", "true"); } } // // Handle the private attribute // if (null == root.attribute("private") && null != avpDef) { if (null != avpDef && null != avpDef.get_protected() && avpDef.get_protected().equals("mustnot")) { root.addAttribute("private", "false"); } else { root.addAttribute("private", "true"); } } // // Parse the enumerated value that could be present in "value" // if (null != root.attribute("value") && null != avpDef) { String enumName = root.attributeValue("value"); long enumValue = avpDef.getEnumCodeByName(enumName); if (enumValue != -1) { root.attribute("value").setValue(Long.toString(enumValue)); } } } else { throw new ParsingException( "in element: " + unmodifiedRoot + "\n" + "code is a mandatory attribute"); } // // Set the vendorId code (in case it isn't referenced by the avp Code via dictionnary, or overwritten). // attributeValue = root.attributeValue("vendorId"); if (null != attributeValue) { if (!Utils.isInteger(attributeValue)) { VendorDef vendorDef = Dictionary.getInstance().getVendorDefByName(attributeValue, applicationId); if (null != vendorDef) { root.attribute("vendorId").setValue(Integer.toString(vendorDef.get_code())); } else { throw new ParsingException("in element: " + unmodifiedRoot + "\n" + attributeValue + " is not a valid vendor id in element"); } } } // // Set the top-parent type (in case it isn't referenced by the avp Code via dictionnary, or overwritten). // if (root.elements().size() > 0) { root.addAttribute("type", "grouped"); } attributeValue = root.attributeValue("type"); if (null != attributeValue) { if (!attributeValue.equalsIgnoreCase("grouped")) { if (null != attributeValue) { TypeDef typeDef = Dictionary.getInstance().getTypeDefByName(attributeValue, applicationId); if (null != typeDef) { while (null != typeDef && null != typeDef.get_type_parent()) { if (typeDef.get_type_name().equalsIgnoreCase("AppId")) isTypeAppId = true; if (typeDef.get_type_name().equalsIgnoreCase("VendorId")) isTypeVendorId = true; typeDef = typeDef.get_type_parent(); } root.attribute("type").setValue(typeDef.get_type_name()); } else { throw new ParsingException("In element: " + unmodifiedRoot + "\n" + attributeValue + " is not a valid type"); } } } } // // Handle the value in case it is an appId or vendorId avp, enum should have already been handled at this point // attributeValue = root.attributeValue("value"); if (null != attributeValue) { if (isTypeAppId) { Application anApplication = Dictionary.getInstance().getApplication(attributeValue); if (null != anApplication) { root.attribute("value").setValue(Integer.toString(anApplication.get_id())); } } if (isTypeVendorId) { VendorDef vendorDef = Dictionary.getInstance().getVendorDefByName(attributeValue, applicationId); if (null != vendorDef) { root.attribute("value").setValue(Integer.toString(vendorDef.get_code())); } } } else { if (!root.attributeValue("type").equalsIgnoreCase("grouped")) { throw new ParsingException("in element: " + unmodifiedRoot + "\n" + "value is a mandatory attribute for element <avp .../> if it is not a grouped avp"); } } } if (recurse) { List<Element> list = root.elements(); for (Element element : list) { doDictionnary(element, applicationId, recurse); } } }
From source file:com.devoteam.srit.xmlloader.gtppr.StackGtpp.java
License:Open Source License
private void parseTLVs(Element root, GtppMessage msg, GtppDictionary dictionary) throws Exception { List<Element> tlvs = root.elements(); List<Element> attributes = null; Tag tlv = null;//from w w w . j a v a 2 s. co m String value = null; String length = null; for (Element element : tlvs) { String name = element.getName(); if (name.equalsIgnoreCase("tv") || name.equalsIgnoreCase("tlv") || name.equalsIgnoreCase("tliv")) { value = element.attributeValue("name"); if (value != null) tlv = dictionary.getTLVFromName(value); else { value = element.attributeValue("tag"); if (value != null) tlv = dictionary.getTLVFromTag(Integer.parseInt(value)); } if (tlv != null) { length = element.attributeValue("length"); if (length != null) { if ((tlv.getLength() > 0) && (tlv.getLength() != Integer.parseInt(length))) { GlobalLogger.instance().getApplicationLogger().warn(TextEvent.Topic.PROTOCOL, "TLV length for " + tlv.toString() + "is not according to size given in dictionary"); } if (value.equalsIgnoreCase("auto")) tlv.setLength(value.length()); else tlv.setLength(Integer.parseInt(length)); } value = element.attributeValue("value"); if (value != null) { setAttributeValue((Attribute) tlv, value); } else { //check if there is attribute inside the TLV attributes = element.elements("attribute"); parseAtt((Attribute) tlv, attributes); } if (tlv.getLength() == -1)//if no size is given in the dictionary { if (!(tlv.getValue() instanceof LinkedList)) tlv.setLength(((byte[]) tlv.getValue()).length); else tlv.setLength(tlv.getArray().length - 3);//- 3 to remove the tag and length bytes } } else { //add tlv to message even if unknown value = element.attributeValue("value"); tlv = new TagTLV(); tlv.setName(element.attributeValue("name")); tlv.setLength(Integer.parseInt(element.attributeValue("length"))); tlv.setValue(value.getBytes()); } msg.addTLV(tlv); tlv = null; } } }
From source file:com.devoteam.srit.xmlloader.h323.h225cs.XmlToAsn1.java
License:Open Source License
public void initObject(Object objClass, Element root, String ClasseName) throws InvocationTargetException, ClassNotFoundException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InstantiationException { // parsing XML List<Element> children = root.elements(); for (Element element : children) { Class thisClass = objClass.getClass(); Field field = this.findField(objClass, element); initField(objClass, element, field, ClasseName); }/*from w w w . j av a 2 s . c om*/ }
From source file:com.devoteam.srit.xmlloader.radius.StackRadius.java
License:Open Source License
private AVPBytes parseAVP(Integer vendorCode, Element avp) throws Exception { String avpCodeAttribute = avp.attributeValue("code"); String avpTypeAttribute = avp.attributeValue("type"); String avpValueAttribute = avp.attributeValue("value"); RadiusAttributes radiusAttributes = this.radiusDictionary.getRadiusVendors() .getRadiusAttributes(vendorCode); /*// www .ja va2s . com * Read this AVP code, if the code is not an integer, then try to decode * it using the dictionary for the given vendorCode. */ Integer avpCode; if (!Utils.isInteger(avpCodeAttribute)) { if (null == radiusAttributes) throw new Exception("Could not get attribute list from dictionary for vendor" + vendorCode); avpCode = radiusAttributes.getAttributeCode(avpCodeAttribute); if (null == avpCode) throw new Exception("Could not get code from dictionary for avp named" + avpCodeAttribute); } else { avpCode = Integer.valueOf(avpCodeAttribute); } /* * Override the AVP type to vendor-specific if the code is 26 */ if (26 == avpCode) { avpTypeAttribute = "vendor-specific"; } /* * Read this AVP type. if the type is not set, try to read it from the * dictionary, based on the AVP code. */ if (null == avpTypeAttribute) { if (null == radiusAttributes) throw new Exception("Could not get attribute list from dictionary for vendor" + vendorCode); avpTypeAttribute = radiusAttributes.getAttributeType(avpCode); if (null == avpTypeAttribute) throw new Exception("Could not get type from dictionary for avp " + avp.asXML() + " please extend the dictionary or set the type in XML"); } /* * Safety check, for now only vendor-specific data can contain data * defined using <data> or <avp> elements. */ if (26 != avpCode && (null != avp.element("avp") || null != avp.element("data"))) { throw new ParsingException("A non vendor-specific AVP can't contain vendor-specific avp nor data"); } /* * Now create the AVP object depending on type. */ if (avpTypeAttribute.equalsIgnoreCase("vendor-specific")) { /* * Create a vendor-specific AVP. */ String vendorDataVendorAttribute = avpValueAttribute; Integer vendorDataVendor; if (!Utils.isInteger(vendorDataVendorAttribute)) vendorDataVendor = this.radiusDictionary.getRadiusVendors() .getVendorCode(vendorDataVendorAttribute); else vendorDataVendor = Integer.parseInt(vendorDataVendorAttribute); if (null == vendorDataVendor) throw new Exception("Could not get vendor code for vendor named " + vendorDataVendorAttribute); SupArray vendorData = new SupArray(); for (Object object : avp.elements()) { Element element = (Element) object; if (element.getName().equals("data")) { String vendorDataValueAttribute = element.attributeValue("value"); DefaultArray vendorDataValueArray = new DefaultArray( Utils.parseBinaryString(vendorDataValueAttribute)); vendorData.addLast(vendorDataValueArray); } else { vendorData.addLast(this.parseAVP(vendorDataVendor, element).getArray()); } } return new AVPVendorSpecific(26, vendorDataVendor, vendorData); } else if (avpTypeAttribute.equalsIgnoreCase("integer") || avpTypeAttribute.equalsIgnoreCase("date")) { Integer avpValue; /* * If the value is not an integer then try to decode it using the * dictionary (contains list of enumerated values). */ if (!Utils.isInteger(avpValueAttribute)) { if (null == radiusAttributes) throw new Exception("Could not get attribute list from dictionary for vendor" + vendorCode); RadiusValues radiusValues = radiusAttributes.getAttributeRadiusValues(avpCode); if (null == radiusValues) throw new Exception("There is no input in dictionary for value " + avpValueAttribute + " of avp " + avp.asXML()); avpValue = radiusValues.getValueCode(avpValueAttribute); if (null == avpValue) throw new Exception("There is no input in dictionary for value " + avpValueAttribute + " of avp " + avp.asXML()); } else { avpValue = (int) Long.parseLong(avpValueAttribute); } return new AVPInteger(avpCode, avpValue); } else if (avpTypeAttribute.equalsIgnoreCase("octets") || avpTypeAttribute.equalsIgnoreCase("octet")) { return new AVPBytes(avpCode, new DefaultArray(Utils.parseBinaryString(avpValueAttribute))); } else if (avpTypeAttribute.equalsIgnoreCase("ipaddr")) { return new AVPBytes(avpCode, new DefaultArray(InetAddress.getByName(avpValueAttribute).getAddress())); } else if (avpTypeAttribute.equalsIgnoreCase("text") || avpTypeAttribute.equalsIgnoreCase("string")) { return new AVPString(avpCode, avpValueAttribute, "UTF8"); } else { throw new ParsingException("Unknown AVP type : " + avpTypeAttribute); } }
From source file:com.devoteam.srit.xmlloader.stun.MsgStun.java
License:Open Source License
private void parseAttribute(Element elem) { List<Element> children = elem.elements(); for (Element child : children) { AttributeStun attribute = null;// www . j a va 2s. c o m String typeInHexa = (String) DictionnaryStun.readProperties().get(elem.attributeValue("type")); if (child.getName().equalsIgnoreCase("address")) { attribute = new AttributeStunAddress(Array.fromHexString(typeInHexa), Integer.parseInt(child.attributeValue("family")), Integer.parseInt(child.attributeValue("port")), child.attributeValue("addressIP")); } else if (child.getName().equalsIgnoreCase("text")) { if (elem.attributeValue("type").equalsIgnoreCase("username"))//attribute username { this.username = child.attributeValue("text"); } if (elem.attributeValue("type").equalsIgnoreCase("realm"))//attribute realm { this.realm = child.attributeValue("text"); } attribute = new AttributeStunText(Array.fromHexString(typeInHexa), child.attributeValue("value")); } else if (child.getName().equalsIgnoreCase("binary")) { attribute = new AttributeStunBinary(Array.fromHexString(typeInHexa), Array.fromHexString(child.attributeValue("value"))); } else if (child.getName().equalsIgnoreCase("errorCode")) { attribute = new AttributeStunErrorCode(Array.fromHexString(typeInHexa), Integer.parseInt(child.attributeValue("code")), child.attributeValue("reasonPhrase")); } else if (child.getName().equalsIgnoreCase("changeRequest")) { attribute = new AttributeStunChangeRequest(Array.fromHexString(typeInHexa), child.attributeValue("changeIP"), child.attributeValue("changePort")); } else if (child.getName().equalsIgnoreCase("unknownAttribute")) { String[] tab = child.attributeValue("type").split(","); int[] tabType = new int[tab.length]; for (int i = 0; i < tabType.length; i++) { tabType[i] = Integer.parseInt(tab[i]); } attribute = new AttributeStunUnknownAttribute(Array.fromHexString(typeInHexa), tabType); } else if (child.getName().equalsIgnoreCase("messageIntegrity")) { try { String valueMessageIntegrity = child.attributeValue("value"); Array integrityArray = null; if (null != valueMessageIntegrity) { try { integrityArray = Array.fromHexString(valueMessageIntegrity); } catch (Exception e) { valueMessageIntegrity = null; } } if (null == valueMessageIntegrity) { if (this.longTermCredential) { String key = username + ":" + realm + ":" + child.attributeValue("secret"); DigestArray keyarray = new DigestArray(new DefaultArray(key.getBytes()), "HmacMD5"); integrityArray = new MacArray(new DefaultArray(this.getBytesData()), "HmacSHA1", keyarray); } else { DefaultArray arraysecret = new DefaultArray(child.attributeValue("secret").getBytes()); integrityArray = new MacArray(new DefaultArray(this.getBytesData()), "HmacSHA1", arraysecret); } } attribute = new AttributeStunBinary(Array.fromHexString(typeInHexa), integrityArray); } catch (Exception e) { throw new IllegalArgumentException("The secret can not be empty", e); } } this.listAttributeStun.add(attribute); header.setLength(header.getLength() + attribute.getPaddedLength() + 4); } }
From source file:com.dockingsoftware.dockingpreference.PreferenceProcessor.java
License:Apache License
/** * Loads user preference information.//from ww w. ja va 2 s. com * * @param obj * @param parent * @throws ClassNotFoundException * @throws InstantiationException * @throws IllegalArgumentException * @throws IllegalAccessException */ private void load(Object obj, Element parent) throws ClassNotFoundException, InstantiationException, IllegalArgumentException, IllegalAccessException, Exception { Class cls = obj.getClass(); if (cls.isArray()) { List<NodeInfo> infos = new ArrayList<NodeInfo>(); List<Element> lstChildren = parent.elements(); for (int i = 0; i < lstChildren.size(); i++) { Element child = lstChildren.get(i); NodeInfo nodeInfo = new NodeInfo(child); infos.add(nodeInfo); } Object array = obj; for (int i = 0; i < infos.size(); i++) { NodeInfo info = infos.get(i); Class fieldClass = Class.forName(info.getClazz()); if (!StringUtils.isBlank(info.getValue())) { PersistentAdapterIF adapter; if (info.getAdapter() == null) { adapter = new DefaultPersistentAdapter(); } else { adapter = (PersistentAdapterIF) Class.forName(info.getAdapter()).newInstance(); } //Gets the new value for the field of obj. Object fieldValue = adapter.restore(info.getValue(), fieldClass); Array.set(array, i, fieldValue); } else { Object fieldValue = fieldClass.newInstance(); // Loading children load(fieldValue, info.getElement()); Array.set(array, i, fieldValue); } } } else if (obj instanceof Collection) { List<NodeInfo> infos = new ArrayList<NodeInfo>(); List<Element> lstChildren = parent.elements(); for (int i = 0; i < lstChildren.size(); i++) { Element child = lstChildren.get(i); NodeInfo nodeInfo = new NodeInfo(child); infos.add(nodeInfo); } Collection coll = (Collection) obj; for (int i = 0; i < infos.size(); i++) { NodeInfo info = infos.get(i); Class fieldClass = Class.forName(info.getClazz()); if (!StringUtils.isBlank(info.getValue())) { PersistentAdapterIF adapter = null; if (info.getAdapter() == null) { adapter = new DefaultPersistentAdapter(); } else { adapter = (PersistentAdapterIF) Class.forName(info.getAdapter()).newInstance(); } //Gets the new value for the field of obj. Object fieldValue = adapter.restore(info.getValue(), fieldClass); coll.add(fieldValue); } else { Object fieldValue = fieldClass.newInstance(); // Loading children load(fieldValue, info.getElement()); coll.add(fieldValue); } } } else if (obj instanceof Map) { // Key is always String type. Map<String, NodeInfo> infos = new HashMap<String, NodeInfo>(); List<Element> lstKeys = parent.elements(); for (int i = 0; i < lstKeys.size(); i++) { Element keyEle = lstKeys.get(i); Element valueEle = (Element) keyEle.elements().get(0); NodeInfo valueInfo = new NodeInfo(valueEle); infos.put(keyEle.getText().trim(), valueInfo); } Map map = (Map) obj; Iterator<String> iter = infos.keySet().iterator(); while (iter.hasNext()) { String key = iter.next(); NodeInfo valueInfo = infos.get(key); Class fieldClass = Class.forName(valueInfo.getClazz()); if (!StringUtils.isBlank(valueInfo.getValue())) { PersistentAdapterIF adapter = null; if (valueInfo.getAdapter() == null) { adapter = new DefaultPersistentAdapter(); } else { adapter = (PersistentAdapterIF) Class.forName(valueInfo.getAdapter()).newInstance(); } //Gets the new value for the field of obj. Object fieldValue = adapter.restore(valueInfo.getValue(), fieldClass); map.put(key, fieldValue); } else { Object fieldValue = fieldClass.newInstance(); // Loading children load(fieldValue, valueInfo.getElement()); map.put(key, fieldValue); } } } else { Map<String, NodeInfo> infos = new HashMap<String, NodeInfo>(); List<Element> lstChildren = parent.elements(); for (int i = 0; i < lstChildren.size(); i++) { Element child = lstChildren.get(i); NodeInfo nodeInfo = new NodeInfo(child); infos.put(nodeInfo.getName(), nodeInfo); } Field[] fields = cls.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { fields[i].setAccessible(true); NodeInfo info = infos.get(fields[i].getName()); if (info != null) { Class fieldClass = Class.forName(info.getClazz()); if (!StringUtils.isBlank(info.getValue())) { PersistentAdapterIF adapter = null; if (info.getAdapter() == null) { adapter = new DefaultPersistentAdapter(); } else { adapter = (PersistentAdapterIF) Class.forName(info.getAdapter()).newInstance(); } //Gets the new value for the field of obj. Object fieldValue = adapter.restore(info.getValue(), fieldClass); fields[i].set(obj, fieldValue); } else { if (fieldClass == java.lang.reflect.Array.class) { Class arryCls = Class.forName(info.getArrayType()); Object fieldValue = Array.newInstance(arryCls, Integer.parseInt(info.getArrayLength())); // Loading children load(fieldValue, info.getElement()); fields[i].set(obj, fieldValue); } else { Object fieldValue = fieldClass.newInstance(); // Loading children load(fieldValue, info.getElement()); fields[i].set(obj, fieldValue); } } } } } }