public object MapToIdlSequence(Type clsType, int bound, AttributeExtCollection allAttributes, AttributeExtCollection elemTypeAttributes) { // sequence should not contain itself! -> do not register typecode omg.org.CORBA.TypeCode elementTC = CreateOrGetTypeCodeForType(clsType.GetElementType(), elemTypeAttributes); return(new SequenceTC(elementTC, bound)); }
public object MapToIdlStruct(Type clsType) { lock (structTCs) { StructTC result = structTCs[clsType] as StructTC; if (result != null) { return(result); } result = new StructTC(); RegisterCreatedTypeCodeForType(clsType, AttributeExtCollection.EmptyCollection, result); FieldInfo[] members = ReflectionHelper.GetAllDeclaredInstanceFieldsOrdered(clsType); StructMember[] structMembers = new StructMember[members.Length]; for (int i = 0; i < members.Length; i++) { omg.org.CORBA.TypeCode memberType = CreateOrGetTypeCodeForType(members[i].FieldType, ReflectionHelper.GetCustomAttriutesForField(members[i], true)); structMembers[i] = new StructMember(members[i].Name, memberType); } result.Initalize(Repository.GetRepositoryID(clsType), IdlNaming.ReverseIdlToClsNameMapping(clsType.Name), structMembers); structTCs[clsType] = result; return(result); } }
public CallerChain DecodeChain(byte[] encoded) { try { VersionedData[] versions = DecodeExportedVersions(encoded, _magicTagCallChain); CallerChainImpl decodedChain = null; for (int i = 0; i < versions.Length; i++) { // Se houver duas versões, a versão atual virá antes da versão legacy. if (versions[i].version == ExportVersion.ConstVal) { TypeCode signedDataTypeCode = ORB.create_tc_for_type(typeof(SignedData)); SignedData exportedChain = (SignedData) _codec.decode_value(versions[i].encoded, signedDataTypeCode); CallChain chain = CallerChainImpl.UnmarshalCallChain(exportedChain); if (decodedChain == null) { decodedChain = new CallerChainImpl(chain.bus, chain.caller, chain.target, chain.originators, exportedChain); } else { decodedChain.Signed.Chain = exportedChain; } } if (versions[i].version == CurrentVersion.ConstVal) { TypeCode exportedChainTypeCode = ORB.create_tc_for_type(typeof(ExportedCallChain)); ExportedCallChain exportedChain = (ExportedCallChain) _codec.decode_value(versions[i].encoded, exportedChainTypeCode); core.v2_0.services.access_control.CallChain chain = CallerChainImpl.UnmarshalLegacyCallChain(exportedChain.signedChain); if (decodedChain == null) { decodedChain = new CallerChainImpl(exportedChain.bus, chain.caller, chain.target, chain.originators, exportedChain.signedChain); } else { decodedChain.Signed.LegacyChain = exportedChain.signedChain; } } } if (decodedChain != null) { return(decodedChain); } } catch (GenericUserException e) { const string message = "Falha inesperada ao decodificar uma cadeia exportada."; Logger.Error(message, e); throw new InvalidEncodedStreamException(message, e); } throw new InvalidEncodedStreamException("Versão de cadeia incompatível."); }
public void ShareDataKeys(List <byte[]> keys) { omg.org.CORBA.TypeCode byteTC = OrbServices.GetSingleton().create_octet_tc(); omg.org.CORBA.TypeCode sequenceTC = OrbServices.GetSingleton().create_sequence_tc(0, byteTC); omg.org.CORBA.TypeCode arrayTC = OrbServices.GetSingleton().create_array_tc(keys.Count, sequenceTC); Share(new Any(keys.ToArray(), arrayTC)); }
internal static CallChain UnmarshalCallChain(SignedData signed) { TypeCode chainTypeCode = OrbServices.GetSingleton().create_tc_for_type(typeof(CallChain)); return((CallChain)InterceptorsInitializer.Codec.decode_value(signed.encoded, chainTypeCode)); }
internal static core.v2_0.services.access_control.CallChain UnmarshalLegacyCallChain(SignedCallChain signed) { TypeCode chainTypeCode = OrbServices.GetSingleton().create_tc_for_type(typeof(core.v2_0.services.access_control.CallChain)); return((core.v2_0.services.access_control.CallChain)InterceptorsInitializer.Codec.decode_value(signed.encoded, chainTypeCode)); }
public void TestCreateTCForLongType() { int longArg = 1; omg.org.CORBA.TypeCode long_TC = m_orb.create_tc_for(longArg); Assert.AreEqual(TCKind.tk_long, long_TC.kind(), "created tc kind"); }
private static CredentialData UnmarshalCredential(ServiceContext serviceContext) { OrbServices orb = OrbServices.GetSingleton(); TypeCode credentialTypeCode = orb.create_tc_for_type(typeof(CredentialData)); byte[] data = serviceContext.context_data; return((CredentialData)InterceptorsInitializer.Codec.decode_value(data, credentialTypeCode)); }
public void TestSequenceTC() { TypeCodeImpl seqMemberType = (TypeCodeImpl)m_orb.create_octet_tc(); omg.org.CORBA.TypeCode seqOfOctet_TC = m_orb.create_sequence_tc(0, seqMemberType); Assert.AreEqual(TCKind.tk_sequence, seqOfOctet_TC.kind(), "sequence kind"); Assert.AreEqual(seqMemberType.GetClsForTypeCode(), ((TypeCodeImpl)seqOfOctet_TC.content_type()).GetClsForTypeCode(), "sequence member type"); }
public SharedAuthSecret DecodeSharedAuth(byte[] encoded) { try { VersionedData[] versions = DecodeExportedVersions(encoded, _magicTagSharedAuth); SharedAuthSecretImpl sharedAuth = null; for (int i = 0; i < versions.Length; i++) { // Se houver duas versões, a versão atual virá antes da versão legacy. if (versions[i].version == ExportVersion.ConstVal) { TypeCode exportedAuthTypeCode = ORB.create_tc_for_type(typeof(ExportedSharedAuth)); ExportedSharedAuth exportedAuth = (ExportedSharedAuth) _codec.decode_value(versions[i].encoded, exportedAuthTypeCode); if (sharedAuth == null) { sharedAuth = new SharedAuthSecretImpl(exportedAuth.bus, exportedAuth.attempt, exportedAuth.secret, null); } else { sharedAuth.Attempt = exportedAuth.attempt; } } if (versions[i].version == CurrentVersion.ConstVal) { TypeCode exportedAuthTypeCode = ORB.create_tc_for_type(typeof(core.v2_0.data_export.ExportedSharedAuth)); core.v2_0.data_export.ExportedSharedAuth exportedAuth = (core.v2_0.data_export.ExportedSharedAuth) _codec.decode_value(versions[i].encoded, exportedAuthTypeCode); if (sharedAuth == null) { sharedAuth = new SharedAuthSecretImpl(exportedAuth.bus, null, exportedAuth.secret, exportedAuth.attempt); } else { sharedAuth.LegacyAttempt = exportedAuth.attempt; } } } if (sharedAuth != null) { return(sharedAuth); } } catch (GenericUserException e) { const string message = "Falha inesperada ao decodificar uma autenticação compartilhada exportada."; Logger.Error(message, e); throw new InvalidEncodedStreamException(message, e); } throw new InvalidEncodedStreamException("Versão de autenticação compartilhada incompatível."); }
public object RetrieveIdlIntArrayAsAny([IdlArray(0L, 5)] int[] arg) { // test with explicit typecode-creation IOrbServices orbServices = OrbServices.GetSingleton(); omg.org.CORBA.TypeCode arrayTC = orbServices.create_array_tc(5, orbServices.create_tc_for_type(typeof(int))); Any arrayAsAny = new Any(arg, arrayTC); return(arrayAsAny); }
public static AttributeExtCollection GetAttrsForTypeCode(omg.org.CORBA.TypeCode typeCode) { if (!(typeCode is omg.org.CORBA.TypeCodeImpl)) { return(AttributeExtCollection.EmptyCollection); } else { return((typeCode as TypeCodeImpl).GetClsAttributesForTypeCode()); } }
/// <summary>gets the CLS type for the Typecode</summary> public static Type GetTypeForTypeCode(omg.org.CORBA.TypeCode typeCode) { if (!(typeCode is omg.org.CORBA.TypeCodeImpl)) { throw new INTERNAL(567, CompletionStatus.Completed_MayBe); } else { return((typeCode as TypeCodeImpl).GetClsForTypeCode()); } }
public void TestAnyContainer() { System.String testString = "abcd"; OrbServices orb = OrbServices.GetSingleton(); omg.org.CORBA.TypeCode wstringTc = orb.create_wstring_tc(0); Any any = new Any(testString, wstringTc); Any result = m_testService.EchoAny(any); Assertion.AssertEquals(any.Value, result.Value); }
private object MapToIdlBoxedValueType(Type clsType, bool boxInAny) { // dotNetType is subclass of BoxedValueBase if (!clsType.IsSubclassOf(ReflectionHelper.BoxedValueBaseType)) { // mapper error: MapToIdlBoxedValue found incorrect type throw new INTERNAL(1929, CompletionStatus.Completed_MayBe); } Type boxedType; object[] attributesOnBoxed = new object[0]; try { boxedType = (Type)clsType.InvokeMember(BoxedValueBase.GET_BOXED_TYPE_METHOD_NAME, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly, null, null, new object[0]); attributesOnBoxed = (object[])clsType.InvokeMember(BoxedValueBase.GET_BOXED_TYPE_ATTRIBUTES_METHOD_NAME, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly, null, null, new object[0]); } catch (Exception) { // invalid type: clsType // static method missing or not callable: // BoxedValueBase.GET_BOXED_TYPE_METHOD_NAME throw new INTERNAL(1930, CompletionStatus.Completed_MayBe); } if (boxInAny) { omg.org.CORBA.TypeCode boxed = CreateOrGetTypeCodeForType(boxedType, AttributeExtCollection.ConvertToAttributeCollection(attributesOnBoxed)); ValueBoxTC result = new ValueBoxTC(Repository.GetRepositoryID(clsType), IdlNaming.ReverseIdlToClsNameMapping(clsType.Name), boxed); RegisterCreatedTypeCodeForType(clsType, AttributeExtCollection.EmptyCollection, result); return(result); } else { // don't use boxed form // therefore create a typecode for the type boxed inside // e.g. in case of a boxed sequence of int, there will be a idlsequence typecode with int as element type created. // e.g. in case, where a sequence of boxed valuetype is boxed, an idl sequence will be created containing a typecode // for the boxed type. omg.org.CORBA.TypeCodeImpl forBoxed = CreateOrGetTypeCodeForType(boxedType, AttributeExtCollection.ConvertToAttributeCollection(attributesOnBoxed)); return(forBoxed); } }
private byte[] EncodeExportedVersions(VersionedData[] exports, byte[] tag) { TypeCode versionedTypeCode = ORB.create_tc_for_type(typeof(VersionedData)); TypeCode sequenceTypeCode = ORB.create_sequence_tc(0, versionedTypeCode); Any any = new Any(exports, sequenceTypeCode); byte[] encodedVersions = _codec.encode_value(any); byte[] fullEnconding = new byte[encodedVersions.Length + MagicTagSize]; Buffer.BlockCopy(tag, 0, fullEnconding, 0, MagicTagSize); Buffer.BlockCopy(encodedVersions, 0, fullEnconding, MagicTagSize, encodedVersions.Length); return(fullEnconding); }
public void ConsumeAnysTest() { omg.org.CORBA.TypeCode long_tc = context.ORB.create_long_tc(); EasyCollaboration target = new EasyCollaboration(context); target.StartCollaboration(); List <object> actual = null; try { actual = target.ConsumeAnys(); Assert.AreEqual(0, actual.Count); target.Share(new omg.org.CORBA.Any(11, long_tc)); target.Share(new omg.org.CORBA.Any(12, long_tc)); target.Share(new omg.org.CORBA.Any(21, long_tc)); target.Share(new omg.org.CORBA.Any(22, long_tc)); Thread.Sleep(4000); actual = target.ConsumeAnys(); Assert.AreEqual(4, actual.Count); Assert.AreEqual(11, actual[0]); Assert.AreEqual(12, actual[1]); Assert.AreEqual(21, actual[2]); Assert.AreEqual(22, actual[3]); } finally { target.ExitCollaboration(); } target = new EasyCollaboration(context, null, null); target.StartCollaboration(); try { actual = target.ConsumeAnys(); Assert.AreEqual(0, actual.Count); target.Share(new omg.org.CORBA.Any(11, long_tc)); target.Share(new omg.org.CORBA.Any(12, long_tc)); target.Share(new omg.org.CORBA.Any(21, long_tc)); target.Share(new omg.org.CORBA.Any(22, long_tc)); Thread.Sleep(2000); actual = target.ConsumeAnys(); Assert.AreEqual(0, actual.Count); } finally { target.ExitCollaboration(); } }
public void ConsumeDataKeysTest() { EasyCollaboration target = new EasyCollaboration(context); target.StartCollaboration(); List <byte[]> actual = null; List <byte[]> datakeys = new List <byte[]>(); datakeys.Add(ASCIIEncoding.Default.GetBytes("test")); datakeys.Add(ASCIIEncoding.Default.GetBytes("test1")); datakeys.Add(ASCIIEncoding.Default.GetBytes("test2")); datakeys.Add(ASCIIEncoding.Default.GetBytes("test3")); omg.org.CORBA.TypeCode byteTC = context.ORB.create_octet_tc(); omg.org.CORBA.TypeCode sequenceTC = context.ORB.create_sequence_tc(0, byteTC); try { actual = target.ConsumeDataKeys(); Assert.AreEqual(0, actual.Count); target.ShareDataKeys(datakeys); Thread.Sleep(4000); actual = target.ConsumeDataKeys(); Assert.AreEqual(datakeys.Count, actual.Count); for (int i = 0; i < datakeys.Count; i++) { CollectionAssert.AreEqual(datakeys[i], actual[i]); } } finally { target.ExitCollaboration(); } target = new EasyCollaboration(context, null, null); target.StartCollaboration(); try { actual = target.ConsumeDataKeys(); Assert.AreEqual(0, actual.Count); target.ShareDataKeys(datakeys); Thread.Sleep(2000); actual = target.ConsumeDataKeys(); Assert.AreEqual(0, actual.Count); } finally { target.ExitCollaboration(); } }
public void TestAliasTC() { string name = "OrbServices_TestAlias"; string aliasRepId = "IDL:Ch/Elca/Iiop/Tests/" + name + ":1.0"; TypeCodeImpl aliasedTC = (TypeCodeImpl)m_orb.create_long_tc(); omg.org.CORBA.TypeCode alias_TC = m_orb.create_alias_tc(aliasRepId, name, aliasedTC); Assert.AreEqual(aliasRepId, alias_TC.id(), "alias id"); Assert.AreEqual(TCKind.tk_alias, alias_TC.kind(), "alias kind"); Assert.AreEqual(aliasedTC.GetClsForTypeCode(), ((TypeCodeImpl)alias_TC).GetClsForTypeCode(), "alias cls type"); }
public object RetrieveIdlInt3DimArray2x2x3AsAny([IdlArray(0L, 2)][IdlArrayDimension(0L, 1, 2)][IdlArrayDimension(0L, 2, 3)] System.Int32[,,] arg) { // test with explicit typecode-creation IOrbServices orbServices = OrbServices.GetSingleton(); omg.org.CORBA.TypeCode arrayTC = orbServices.create_array_tc(3, orbServices.create_tc_for_type(typeof(int))); arrayTC = orbServices.create_array_tc(2, arrayTC); arrayTC = orbServices.create_array_tc(2, arrayTC); Any arrayAsAny = new Any(arg, arrayTC); return(arrayAsAny); }
public object decode_value([IdlSequence(0L)] byte[] data, omg.org.CORBA.TypeCode tc) { CdrEncapsulationInputStream inputStream = new CdrEncapsulationInputStream(data, m_version); Type marshalAs = ((TypeCodeImpl)tc).GetClsForTypeCode(); AttributeExtCollection marshalAsAttrs = ((TypeCodeImpl)tc).GetClsAttributesForTypeCode(); Serializer ser = m_serFactory.Create(marshalAs, marshalAsAttrs); return(ser.Deserialize(inputStream)); }
/// <summary> /// returns the deserialised data of the first component with the given tag or null, if not found. /// Assumes, that the componentData is encapsulated in a cdr encapsulation. The secound argument /// specifies, how the data inside the encapsulation looks like. /// </summary> public object GetComponentData(int tag, Codec codec, omg.org.CORBA.TypeCode componentDataType) { object result = null; object resultComp = GetComponentInternal(tag); if (resultComp != null) { return(codec.decode_value(((TaggedComponent)resultComp).component_data, componentDataType)); } return(result); }
public void TestNilReferenceAsAny() { OrbServices orb = OrbServices.GetSingleton(); omg.org.CORBA.TypeCode nilRefTC = orb.create_tc_for_type(typeof(System.MarshalByRefObject)); Any nilRefAny = new Any(null, nilRefTC); object result = m_testService.EchoAny(nilRefAny); Assert.IsNull(result, "result not null"); Any nilRefAny2 = new Any(null, orb.create_interface_tc(String.Empty, String.Empty)); object result2 = m_testService.EchoAny(nilRefAny2); Assert.IsNull(result2, "result not null"); }
public object MapToIdlArray(Type clsType, int[] dimensions, AttributeExtCollection allAttributes, AttributeExtCollection elemTypeAttributes) { // array should not contain itself! -> do not register typecode // get the typecode for the array element type omg.org.CORBA.TypeCode elementTC = CreateOrGetTypeCodeForType(clsType.GetElementType(), elemTypeAttributes); // for multidim arrays, nest array tcs ArrayTC arrayTC = new ArrayTC(elementTC, dimensions[dimensions.Length - 1]); // the innermost array tc for the rightmost dimension for (int i = dimensions.Length - 2; i >= 0; i--) { arrayTC = new ArrayTC(arrayTC, dimensions[i]); } return(arrayTC); }
public void TestULongAsAny() { int arg = 74; int result = (int)m_testService.RetrieveULongAsAny(arg); Assert.AreEqual(arg, result, "wrong result of retrieveULongAsAny"); OrbServices orb = OrbServices.GetSingleton(); int arg2 = 89; omg.org.CORBA.TypeCode ulongTC = orb.create_ulong_tc(); Any any = new Any(arg2, ulongTC); int result2 = m_testService.ExtractFromULongAny(any); Assert.AreEqual(arg2, result2, "wrong result of ExtractFromULongAny"); }
public void TestExceptTC() { string name = "OrbServices_TestException"; string repId = "IDL:Ch/Elca/Iiop/Tests/" + name + ":1.0"; StructMember m1 = new StructMember("M1", m_orb.create_long_tc()); omg.org.CORBA.TypeCode tc = m_orb.create_exception_tc(repId, name, new StructMember[] { m1 }); Assert.AreEqual(repId, tc.id(), "id"); Assert.AreEqual(TCKind.tk_except, tc.kind(), "king"); Assert.AreEqual(1, tc.member_count(), "nr of members"); Assert.AreEqual(m1.name, tc.member_name(0), "member m1 name"); Assert.AreEqual(m1.type.kind(), tc.member_type(0).kind(), "member m1 type"); }
public void TestValueTypeTC() { string name = "OrbServices_TestValueType"; string repId = "IDL:Ch/Elca/Iiop/Tests/" + name + ":1.0"; ValueMember m1 = new ValueMember("M1", m_orb.create_long_tc(), 0); omg.org.CORBA.TypeCode tc = m_orb.create_value_tc(repId, name, 0, m_orb.create_null_tc(), new ValueMember[] { m1 }); Assert.AreEqual(repId, tc.id(), "id"); Assert.AreEqual(TCKind.tk_value, tc.kind(), "king"); Assert.AreEqual(1, tc.member_count(), "nr of members"); Assert.AreEqual(m1.name, tc.member_name(0), "member m1 name"); Assert.AreEqual(m1.type.kind(), tc.member_type(0).kind(), "member m1 type"); }
public byte[] EncodeSharedAuth(SharedAuthSecret secret) { try { SharedAuthSecretImpl sharedAuth = (SharedAuthSecretImpl)secret; int i = 0; VersionedData?actualVersion = null; VersionedData?legacyVersion = null; if (!sharedAuth.Legacy) { // se não é legacy, tem a versão atual. Pode ter a versão legacy ou não. ExportedSharedAuth exportedAuth = new ExportedSharedAuth(sharedAuth.BusId, sharedAuth.Attempt, sharedAuth.Secret); TypeCode exportedAuthTC = _orb.create_tc_for_type(typeof(ExportedSharedAuth)); Any any = new Any(exportedAuth, exportedAuthTC); byte[] encoded = _codec.encode_value(any); actualVersion = new VersionedData(ExportVersion.ConstVal, encoded); i++; } if (sharedAuth.LegacyAttempt != null) { core.v2_0.data_export.ExportedSharedAuth legacyAuth = new core.v2_0.data_export.ExportedSharedAuth(sharedAuth.BusId, sharedAuth.LegacyAttempt, sharedAuth.Secret); TypeCode legacyExportedAuthTC = _orb.create_tc_for_type(typeof(core.v2_0.data_export.ExportedSharedAuth)); Any any = new Any(legacyAuth, legacyExportedAuthTC); byte[] legacyEncoded = _codec.encode_value(any); legacyVersion = new VersionedData(CurrentVersion.ConstVal, legacyEncoded); i++; } VersionedData[] versions = new VersionedData[i]; // A ordem das versões exportadas IMPORTA. A 2.1 deve vir antes da 2.0. if (legacyVersion != null) { versions[--i] = legacyVersion.Value; } if (actualVersion != null) { versions[--i] = actualVersion.Value; } return(EncodeExportedVersions(versions, _magicTagSharedAuth)); } catch (InvalidTypeForEncoding e) { const string message = "Falha inesperada ao codificar uma autenticação compartilhada para exportação."; Logger.Error(message, e); throw new OpenBusInternalException(message, e); } }
public void TestLongTypeDefAsAny() { OrbServices orb = OrbServices.GetSingleton(); int arg = 74; int result = (int)m_testService.RetrieveLongTypeDefAsAny(arg); Assert.AreEqual(arg, result, "result of RetrieveLongTypeDefAsAny"); int arg2 = 91; omg.org.CORBA.TypeCode argTC = orb.create_tc_for(arg2); omg.org.CORBA.TypeCode longTD_TC = orb.create_alias_tc("IDL:longTD:1.0", "longTD", argTC); Any any = new Any(arg2, longTD_TC); int result2 = m_testService.ExtractFromLongTypeDef(any); Assert.AreEqual(arg2, result2, "result of ExtractFromLongTypeDef"); }
public byte[] EncodeChain(CallerChain chain) { try { CallerChainImpl chainImpl = (CallerChainImpl)chain; int i = 0; VersionedData? actualVersion = null; VersionedData? legacyVersion = null; if (!chainImpl.Legacy) { // se não é legacy, tem a versão atual. Pode ter a versão legacy ou não. TypeCode signedChainTC = _orb.create_tc_for_type(typeof(SignedData)); Any any = new Any(chainImpl.Signed.Chain, signedChainTC); byte[] encoded = _codec.encode_value(any); actualVersion = new VersionedData(ExportVersion.ConstVal, encoded); i++; } if (chainImpl.Signed.LegacyChain.encoded != null) { ExportedCallChain exported = new ExportedCallChain(chainImpl.BusId, chainImpl.Signed.LegacyChain); TypeCode exportedChainTC = _orb.create_tc_for_type(typeof(ExportedCallChain)); Any any = new Any(exported, exportedChainTC); byte[] legacyEncoded = _codec.encode_value(any); legacyVersion = new VersionedData(CurrentVersion.ConstVal, legacyEncoded); i++; } VersionedData[] versions = new VersionedData[i]; // A ordem das versões exportadas IMPORTA. A 2.1 deve vir antes da 2.0. if (legacyVersion != null) { versions[--i] = legacyVersion.Value; } if (actualVersion != null) { versions[--i] = actualVersion.Value; } return(EncodeExportedVersions(versions, _magicTagCallChain)); } catch (InvalidTypeForEncoding e) { const string message = "Falha inesperada ao codificar uma cadeia para exportação."; Logger.Error(message, e); throw new OpenBusInternalException(message, e); } }
public BiDirIiopServerInterceptor(OrbServices orb) { m_codec = orb.CodecFactory.create_codec( new Encoding(ENCODING_CDR_ENCAPS.ConstVal, 1, 2)); m_svcContextTypeCode = orb.create_tc_for_type(typeof(BiDirIIOPServiceContext)); }