/// <summary> /// Creates a new object that is a copy of the current instance. /// </summary> /// <returns> /// A new object that is a copy of this instance. /// </returns> ITamperProtectionChannelBindingElement ITamperProtectionChannelBindingElement.Clone() { ITamperProtectionChannelBindingElement clone = this.Clone(); clone.SignatureCallback = this.SignatureCallback; return(clone); }
/// <summary> /// Initializes a new instance of the <see cref="CoordinatingOAuthChannel"/> class for Consumers. /// </summary> /// <param name="signingBindingElement"> /// The signing element for the Consumer to use. Null for the Service Provider. /// </param> /// <param name="tokenManager">The token manager to use.</param> internal CoordinatingOAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, IServiceProviderTokenManager tokenManager) : base( signingBindingElement, new NonceMemoryStore(StandardExpirationBindingElement.MaximumMessageAge), tokenManager) { }
/// <summary> /// Initializes a new instance of the <see cref="SigningBindingElementChain"/> class. /// </summary> /// <param name="signers"> /// The signing binding elements that may be used for some outgoing message, /// in preferred use order. /// </param> internal SigningBindingElementChain(ITamperProtectionChannelBindingElement[] signers) { Requires.NotNullOrEmpty(signers, "signers"); Requires.NullOrNotNullElements(signers, "signers"); Requires.That(signers.Select(s => s.Protection).Distinct().Count() == 1, "signers", OAuthStrings.SigningElementsMustShareSameProtection); this.signers = signers; }
/// <summary> /// Initializes a new instance of the <see cref="OAuthChannel"/> class. /// </summary> /// <param name="signingBindingElement">The binding element to use for signing.</param> /// <param name="store">The web application store to use for nonces.</param> /// <param name="tokenManager">The token manager instance to use.</param> /// <param name="isConsumer">A value indicating whether this channel is being constructed for a Consumer (as opposed to a Service Provider).</param> internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, bool isConsumer) : this(signingBindingElement, store, tokenManager, isConsumer ? (IMessageFactory)new OAuthConsumerMessageFactory() : new OAuthServiceProviderMessageFactory(tokenManager)) { }
/// <summary> /// Initializes a new instance of the <see cref="OAuthChannel"/> class. /// </summary> /// <param name="signingBindingElement">The binding element to use for signing.</param> /// <param name="store">The web application store to use for nonces.</param> /// <param name="tokenManager">The token manager instance to use.</param> internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, IServiceProviderTokenManager tokenManager) : this( signingBindingElement, store, tokenManager, new OAuthServiceProviderMessageFactory(tokenManager)) { }
/// <summary> /// Initializes a new instance of the <see cref="OAuthChannel"/> class. /// </summary> /// <param name="signingBindingElement">The binding element to use for signing.</param> /// <param name="store">The web application store to use for nonces.</param> /// <param name="tokenManager">The token manager instance to use.</param> /// <param name="isConsumer">A value indicating whether this channel is being constructed for a Consumer (as opposed to a Service Provider).</param> internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, bool isConsumer) : this( signingBindingElement, store, tokenManager, isConsumer ? (IMessageFactory) new OAuthConsumerMessageFactory() : new OAuthServiceProviderMessageFactory(tokenManager)) { }
/// <summary> /// Initializes a new instance of the <see cref="SigningBindingElementChain"/> class. /// </summary> /// <param name="signers"> /// The signing binding elements that may be used for some outgoing message, /// in preferred use order. /// </param> internal SigningBindingElementChain(ITamperProtectionChannelBindingElement[] signers) { Contract.Requires<ArgumentNullException>(signers != null); Contract.Requires<ArgumentException>(signers.Length > 0); Contract.Requires<ArgumentException>(!signers.Contains(null), MessagingStrings.SequenceContainsNullElement); Contract.Requires<ArgumentException>(signers.Select(s => s.Protection).Distinct().Count() == 1, OAuthStrings.SigningElementsMustShareSameProtection); this.signers = signers; }
/// <summary> /// Initializes a new instance of the <see cref="CoordinatingOAuthConsumerChannel"/> class. /// </summary> /// <param name="signingBindingElement">The signing element for the Consumer to use. Null for the Service Provider.</param> /// <param name="tokenManager">The token manager to use.</param> /// <param name="securitySettings">The security settings.</param> internal CoordinatingOAuthConsumerChannel(ITamperProtectionChannelBindingElement signingBindingElement, IConsumerTokenManager tokenManager, DotNetOpenAuth.OAuth.ConsumerSecuritySettings securitySettings) : base( signingBindingElement, new NonceMemoryStore(StandardExpirationBindingElement.MaximumMessageAge), tokenManager, securitySettings) { }
/// <summary> /// Initializes a new instance of the <see cref="OAuthChannel"/> class. /// </summary> /// <param name="signingBindingElement">The binding element to use for signing.</param> /// <param name="store">The web application store to use for nonces.</param> /// <param name="tokenManager">The ITokenManager instance to use.</param> /// <param name="messageTypeProvider"> /// An injected message type provider instance. /// Except for mock testing, this should always be one of /// <see cref="OAuthConsumerMessageFactory"/> or <see cref="OAuthServiceProviderMessageFactory"/>. /// </param> internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, IMessageFactory messageTypeProvider) : base(messageTypeProvider, InitializeBindingElements(signingBindingElement, store, tokenManager)) { Contract.Requires<ArgumentNullException>(tokenManager != null); Contract.Requires<ArgumentNullException>(signingBindingElement != null); Contract.Requires<ArgumentException>(signingBindingElement.SignatureCallback == null, OAuthStrings.SigningElementAlreadyAssociatedWithChannel); this.TokenManager = tokenManager; signingBindingElement.SignatureCallback = this.SignatureCallback; }
/// <summary> /// Initializes a new instance of the <see cref="CoordinatingOAuthServiceProviderChannel"/> class. /// </summary> /// <param name="signingBindingElement">The signing element for the Consumer to use. Null for the Service Provider.</param> /// <param name="tokenManager">The token manager to use.</param> /// <param name="securitySettings">The security settings.</param> internal CoordinatingOAuthServiceProviderChannel(ITamperProtectionChannelBindingElement signingBindingElement, IServiceProviderTokenManager tokenManager, DotNetOpenAuth.OAuth.ServiceProviderSecuritySettings securitySettings) : base( signingBindingElement, new NonceMemoryStore(StandardExpirationBindingElement.MaximumMessageAge), tokenManager, securitySettings, new OAuthServiceProviderMessageFactory(tokenManager)) { }
/// <summary> /// Initializes a new instance of the <see cref="OAuthChannel"/> class. /// </summary> /// <param name="signingBindingElement">The binding element to use for signing.</param> /// <param name="store">The web application store to use for nonces.</param> /// <param name="tokenManager">The ITokenManager instance to use.</param> /// <param name="messageTypeProvider"> /// An injected message type provider instance. /// Except for mock testing, this should always be one of /// <see cref="OAuthConsumerMessageFactory"/> or <see cref="OAuthServiceProviderMessageFactory"/>. /// </param> internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, IMessageFactory messageTypeProvider) : base(messageTypeProvider, InitializeBindingElements(signingBindingElement, store, tokenManager)) { ErrorUtilities.VerifyArgumentNotNull(tokenManager, "tokenManager"); this.TokenManager = tokenManager; ErrorUtilities.VerifyArgumentNamed(signingBindingElement.SignatureCallback == null, "signingBindingElement", OAuthStrings.SigningElementAlreadyAssociatedWithChannel); signingBindingElement.SignatureCallback = this.SignatureCallback; }
/// <summary> /// Initializes a new instance of the <see cref="OAuthChannel"/> class. /// </summary> /// <param name="signingBindingElement">The binding element to use for signing.</param> /// <param name="store">The web application store to use for nonces.</param> /// <param name="tokenManager">The ITokenManager instance to use.</param> /// <param name="messageTypeProvider"> /// An injected message type provider instance. /// Except for mock testing, this should always be one of /// <see cref="OAuthConsumerMessageFactory"/> or <see cref="OAuthServiceProviderMessageFactory"/>. /// </param> internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, IMessageFactory messageTypeProvider) : base(messageTypeProvider, InitializeBindingElements(signingBindingElement, store, tokenManager)) { Contract.Requires <ArgumentNullException>(tokenManager != null); Contract.Requires <ArgumentNullException>(signingBindingElement != null); Contract.Requires <ArgumentException>(signingBindingElement.SignatureCallback == null, OAuthStrings.SigningElementAlreadyAssociatedWithChannel); this.TokenManager = tokenManager; signingBindingElement.SignatureCallback = this.SignatureCallback; }
internal OAuthConsumerChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, IConsumerTokenManager tokenManager, ConsumerSecuritySettings securitySettings, IMessageFactory messageFactory = null) : base( signingBindingElement, tokenManager, securitySettings, messageFactory ?? new OAuthConsumerMessageFactory(), InitializeBindingElements(signingBindingElement, store)) { Requires.NotNull(tokenManager, "tokenManager"); Requires.NotNull(securitySettings, "securitySettings"); Requires.NotNull(signingBindingElement, "signingBindingElement"); }
/// <summary> /// Initializes the binding elements for the OAuth channel. /// </summary> /// <param name="signingBindingElement">The signing binding element.</param> /// <param name="store">The nonce store.</param> /// <returns> /// An array of binding elements used to initialize the channel. /// </returns> protected static List <IChannelBindingElement> InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store) { var bindingElements = new List <IChannelBindingElement> { new OAuthHttpMethodBindingElement(), signingBindingElement, new StandardExpirationBindingElement(), new StandardReplayProtectionBindingElement(store), }; return(bindingElements); }
/// <summary> /// Initializes the binding elements for the OAuth channel. /// </summary> /// <param name="signingBindingElement">The signing binding element.</param> /// <param name="store">The nonce store.</param> /// <param name="tokenManager">The token manager.</param> /// <param name="securitySettings">The security settings.</param> /// <returns> /// An array of binding elements used to initialize the channel. /// </returns> private static IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings) { Requires.NotNull(securitySettings, "securitySettings"); var bindingElements = OAuthChannel.InitializeBindingElements(signingBindingElement, store); var spTokenManager = tokenManager as IServiceProviderTokenManager; var serviceProviderSecuritySettings = securitySettings as ServiceProviderSecuritySettings; bindingElements.Insert(0, new TokenHandlingBindingElement(spTokenManager, serviceProviderSecuritySettings)); return bindingElements.ToArray(); }
protected OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, ITokenManager tokenManager, SecuritySettings securitySettings, IMessageFactory messageTypeProvider, IChannelBindingElement[] bindingElements) : base(messageTypeProvider, bindingElements) { Requires.NotNull(tokenManager, "tokenManager"); Requires.NotNull(securitySettings, "securitySettings"); Requires.NotNull(signingBindingElement, "signingBindingElement"); Requires.That(signingBindingElement.SignatureCallback == null, "signingBindingElement", OAuthStrings.SigningElementAlreadyAssociatedWithChannel); Requires.NotNull(bindingElements, "bindingElements"); this.TokenManager = tokenManager; signingBindingElement.SignatureCallback = this.SignatureCallback; }
internal OAuthServiceProviderChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, IServiceProviderTokenManager tokenManager, ServiceProviderSecuritySettings securitySettings, IMessageFactory messageTypeProvider = null) : base( signingBindingElement, tokenManager, securitySettings, messageTypeProvider ?? new OAuthServiceProviderMessageFactory(tokenManager), InitializeBindingElements(signingBindingElement, store, tokenManager, securitySettings)) { Requires.NotNull(tokenManager, "tokenManager"); Requires.NotNull(securitySettings, "securitySettings"); Requires.NotNull(signingBindingElement, "signingBindingElement"); }
/// <summary> /// Initializes a new instance of the <see cref="OAuthChannel"/> class. /// </summary> /// <param name="signingBindingElement">The binding element to use for signing.</param> /// <param name="store">The web application store to use for nonces.</param> /// <param name="tokenManager">The ITokenManager instance to use.</param> /// <param name="messageTypeProvider"> /// An injected message type provider instance. /// Except for mock testing, this should always be one of /// <see cref="OAuthConsumerMessageFactory"/> or <see cref="OAuthServiceProviderMessageFactory"/>. /// </param> /// <remarks> /// This overload for testing purposes only. /// </remarks> internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, IMessageFactory messageTypeProvider) : base(messageTypeProvider, new OAuthHttpMethodBindingElement(), signingBindingElement, new StandardExpirationBindingElement(), new StandardReplayProtectionBindingElement(store)) { if (tokenManager == null) { throw new ArgumentNullException("tokenManager"); } this.TokenManager = tokenManager; ErrorUtilities.VerifyArgumentNamed(signingBindingElement.SignatureCallback == null, "signingBindingElement", OAuthStrings.SigningElementAlreadyAssociatedWithChannel); signingBindingElement.SignatureCallback = this.SignatureCallback; }
internal OAuthChannel(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, IServiceProviderTokenManager tokenManager, ServiceProviderSecuritySettings securitySettings) : this( signingBindingElement, store, tokenManager, securitySettings, new OAuthServiceProviderMessageFactory(tokenManager)) { Contract.Requires<ArgumentNullException>(tokenManager != null); Contract.Requires<ArgumentNullException>(securitySettings != null); Contract.Requires<ArgumentNullException>(signingBindingElement != null); Contract.Requires<ArgumentException>(signingBindingElement.SignatureCallback == null, OAuthStrings.SigningElementAlreadyAssociatedWithChannel); }
/// <summary> /// Initializes the binding elements for the OAuth channel. /// </summary> /// <param name="signingBindingElement">The signing binding element.</param> /// <param name="store">The nonce store.</param> /// <param name="tokenManager">The token manager.</param> /// <param name="securitySettings">The security settings.</param> /// <returns> /// An array of binding elements used to initialize the channel. /// </returns> private static IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings) { Requires.NotNull(securitySettings, "securitySettings"); var bindingElements = OAuthChannel.InitializeBindingElements(signingBindingElement, store); var spTokenManager = tokenManager as IServiceProviderTokenManager; var serviceProviderSecuritySettings = securitySettings as ServiceProviderSecuritySettings; bindingElements.Insert(0, new TokenHandlingBindingElement(spTokenManager, serviceProviderSecuritySettings)); return(bindingElements.ToArray()); }
/// <summary> /// Initializes a new instance of the <see cref="ConsumerBase"/> class. /// </summary> /// <param name="serviceDescription">The endpoints and behavior of the Service Provider.</param> /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param> protected ConsumerBase(ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager) { Contract.Requires <ArgumentNullException>(serviceDescription != null); Contract.Requires <ArgumentNullException>(tokenManager != null); ITamperProtectionChannelBindingElement signingElement = serviceDescription.CreateTamperProtectionElement(); INonceStore store = new NonceMemoryStore(StandardExpirationBindingElement.MaximumMessageAge); this.OAuthChannel = new OAuthChannel(signingElement, store, tokenManager); this.ServiceProvider = serviceDescription; this.SecuritySettings = DotNetOpenAuthSection.Configuration.OAuth.Consumer.SecuritySettings.CreateSecuritySettings(); Reporting.RecordFeatureAndDependencyUse(this, serviceDescription, tokenManager, null); }
/// <summary> /// Initializes a new instance of the <see cref="ConsumerBase"/> class. /// </summary> /// <param name="serviceDescription">The endpoints and behavior of the Service Provider.</param> /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param> protected ConsumerBase(ServiceProviderDescription serviceDescription, IConsumerTokenManager tokenManager) { Requires.NotNull(serviceDescription, "serviceDescription"); Requires.NotNull(tokenManager, "tokenManager"); ITamperProtectionChannelBindingElement signingElement = serviceDescription.CreateTamperProtectionElement(); INonceStore store = new NonceMemoryStore(StandardExpirationBindingElement.MaximumMessageAge); this.SecuritySettings = OAuthElement.Configuration.Consumer.SecuritySettings.CreateSecuritySettings(); this.OAuthChannel = new OAuthConsumerChannel(signingElement, store, tokenManager, this.SecuritySettings); this.ServiceProvider = serviceDescription; OAuthReporting.RecordFeatureAndDependencyUse(this, serviceDescription, tokenManager, null); }
/// <summary> /// Initializes a new instance of the <see cref="ConsumerBase"/> class. /// </summary> /// <param name="serviceDescription">The endpoints and behavior of the Service Provider.</param> /// <param name="tokenManager">The host's method of storing and recalling tokens and secrets.</param> protected ConsumerBase(ServiceProviderDescription serviceDescription, ITokenManager tokenManager) { if (serviceDescription == null) { throw new ArgumentNullException("serviceDescription"); } if (tokenManager == null) { throw new ArgumentNullException("tokenManager"); } ITamperProtectionChannelBindingElement signingElement = serviceDescription.CreateTamperProtectionElement(); INonceStore store = new NonceMemoryStore(StandardExpirationBindingElement.DefaultMaximumMessageAge); this.OAuthChannel = new OAuthChannel(signingElement, store, tokenManager, new OAuthConsumerMessageFactory()); this.ServiceProvider = serviceDescription; }
/// <summary> /// Initializes the binding elements for the OAuth channel. /// </summary> /// <param name="signingBindingElement">The signing binding element.</param> /// <param name="store">The nonce store.</param> /// <param name="tokenManager">The token manager.</param> /// <returns>An array of binding elements used to initialize the channel.</returns> private static IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager) { var bindingElements = new List <IChannelBindingElement> { new OAuthHttpMethodBindingElement(), signingBindingElement, new StandardExpirationBindingElement(), new StandardReplayProtectionBindingElement(store), }; var spTokenManager = tokenManager as IServiceProviderTokenManager; if (spTokenManager != null) { bindingElements.Insert(0, new TokenHandlingBindingElement(spTokenManager)); } return(bindingElements.ToArray()); }
/// <summary> /// Initializes a new instance of the <see cref="SigningBindingElementChain"/> class. /// </summary> /// <param name="signers"> /// The signing binding elements that may be used for some outgoing message, /// in preferred use order. /// </param> internal SigningBindingElementChain(ITamperProtectionChannelBindingElement[] signers) { if (signers == null) { throw new ArgumentNullException("signers"); } if (signers.Length == 0) { throw new ArgumentException(MessagingStrings.SequenceContainsNoElements, "signers"); } if (signers.Contains(null)) { throw new ArgumentException(MessagingStrings.SequenceContainsNullElement, "signers"); } MessageProtections protection = signers[0].Protection; if (signers.Any(element => element.Protection != protection)) { throw new ArgumentException(OAuthStrings.SigningElementsMustShareSameProtection, "signers"); } this.signers = signers; }
/// <summary> /// Initializes the binding elements for the OAuth channel. /// </summary> /// <param name="signingBindingElement">The signing binding element.</param> /// <param name="store">The nonce store.</param> /// <returns> /// An array of binding elements used to initialize the channel. /// </returns> protected static List<IChannelBindingElement> InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store) { var bindingElements = new List<IChannelBindingElement> { new OAuthHttpMethodBindingElement(), signingBindingElement, new StandardExpirationBindingElement(), new StandardReplayProtectionBindingElement(store), }; return bindingElements; }
/// <summary> /// Initializes the binding elements for the OAuth channel. /// </summary> /// <param name="signingBindingElement">The signing binding element.</param> /// <param name="store">The nonce store.</param> /// <returns> /// An array of binding elements used to initialize the channel. /// </returns> private static new IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store) { return OAuthChannel.InitializeBindingElements(signingBindingElement, store).ToArray(); }
/// <summary> /// Initializes the binding elements for the OAuth channel. /// </summary> /// <param name="signingBindingElement">The signing binding element.</param> /// <param name="store">The nonce store.</param> /// <param name="tokenManager">The token manager.</param> /// <param name="securitySettings">The security settings.</param> /// <returns> /// An array of binding elements used to initialize the channel. /// </returns> private static IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings) { Contract.Requires(securitySettings != null); var bindingElements = new List<IChannelBindingElement> { new OAuthHttpMethodBindingElement(), signingBindingElement, new StandardExpirationBindingElement(), new StandardReplayProtectionBindingElement(store), }; var spTokenManager = tokenManager as IServiceProviderTokenManager; var serviceProviderSecuritySettings = securitySettings as ServiceProviderSecuritySettings; if (spTokenManager != null && serviceProviderSecuritySettings != null) { bindingElements.Insert(0, new TokenHandlingBindingElement(spTokenManager, serviceProviderSecuritySettings)); } return bindingElements.ToArray(); }
/// <summary> /// Initializes the binding elements for the OAuth channel. /// </summary> /// <param name="signingBindingElement">The signing binding element.</param> /// <param name="store">The nonce store.</param> /// <returns> /// An array of binding elements used to initialize the channel. /// </returns> private static new IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store) { return(OAuthChannel.InitializeBindingElements(signingBindingElement, store).ToArray()); }
/// <summary> /// Initializes the binding elements for the OAuth channel. /// </summary> /// <param name="signingBindingElement">The signing binding element.</param> /// <param name="store">The nonce store.</param> /// <param name="tokenManager">The token manager.</param> /// <param name="securitySettings">The security settings.</param> /// <returns> /// An array of binding elements used to initialize the channel. /// </returns> protected static List<IChannelBindingElement> InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager, SecuritySettings securitySettings) { Contract.Requires(securitySettings != null); var bindingElements = new List<IChannelBindingElement> { new OAuthHttpMethodBindingElement(), signingBindingElement, new StandardExpirationBindingElement(), new StandardReplayProtectionBindingElement(store), }; return bindingElements; }
/// <summary> /// Initializes the binding elements for the OAuth channel. /// </summary> /// <param name="signingBindingElement">The signing binding element.</param> /// <param name="store">The nonce store.</param> /// <param name="tokenManager">The token manager.</param> /// <returns>An array of binding elements used to initialize the channel.</returns> private static IChannelBindingElement[] InitializeBindingElements(ITamperProtectionChannelBindingElement signingBindingElement, INonceStore store, ITokenManager tokenManager) { var bindingElements = new List<IChannelBindingElement> { new OAuthHttpMethodBindingElement(), signingBindingElement, new StandardExpirationBindingElement(), new StandardReplayProtectionBindingElement(store), }; var spTokenManager = tokenManager as IServiceProviderTokenManager; if (spTokenManager != null) { bindingElements.Insert(0, new TokenHandlingBindingElement(spTokenManager)); } return bindingElements.ToArray(); }