From various forums etc, I have got this far:
public static void InitializeEndpoint(ServiceEndpoint endpoint)
{
CustomBinding customBinding = new CustomBinding(endpoint.Binding);
SecurityBindingElement securityBinding =
customBinding.Elements.Find<SecurityBindingElement>();
securityBinding.LocalServiceSettings.MaxClockSkew =
TimeSpan.FromHours(1);
securityBinding.LocalClientSettings.MaxClockSkew =
TimeSpan.FromHours(1);
endpoint.Binding = customBinding;
}
However, this does not seem to do the trick. Running a client with a clock
out by 10 minutes still results in an error logged on the service and the
message states that the max skew is still the default 5 mins.
Looking at some other forums I can find information about having to set the
skew on a bootstrapper element as well, but that only seems to be for
SymmetricSecurityBindingElements, where as we are using
TransportWithMessageCredential resulting in a TransportSecurityBindingElement.
The configuration on my client is:
<system.serviceModel>
<client>
<endpoint
address="https://localhost/Diligent.Boardbooks.SiteService/SiteService.svc/SiteUN"
binding="wsHttpBinding" bindingConfiguration="WSUsernameMtomBinding"
contract="Diligent.Boardbooks.Services.SiteService.Proxy.ISiteServiceContract"
name="SiteServiceUN" />
</client>
<behaviors />
<bindings>
<wsHttpBinding>
<binding name="WSUsernameBinding" sendTimeout="00:05:00"
maxReceivedMessageSize="1048576">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"
establishSecurityContext="false" />
</security>
</binding>
<binding name="WSUsernameMtomBinding" sendTimeout="00:05:00"
maxReceivedMessageSize="67108864" messageEncoding="Mtom">
<readerQuotas maxDepth="512" maxStringContentLength="67108864"
maxArrayLength="67108864" maxBytesPerRead="67108864"
maxNameTableCharCount="65536" />
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"
establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services />
</system.serviceModel>
And on my service is:
<system.serviceModel>
<client>
</client>
<bindings>
<wsHttpBinding>
<binding name="WSMtomBinding" sendTimeout="00:05:00"
maxReceivedMessageSize="67108864"
messageEncoding="Mtom">
<readerQuotas maxDepth="512"
maxStringContentLength="67108864"
maxArrayLength="67108864"
maxBytesPerRead="67108864" maxNameTableCharCount="65536" />
<reliableSession enabled="false" />
<security mode="TransportWithMessageCredential">
<message establishSecurityContext="false" />
</security>
</binding>
<binding name="WSUsernameMtomBinding" sendTimeout="00:05:00"
maxReceivedMessageSize="67108864"
messageEncoding="Mtom">
<readerQuotas maxDepth="512"
maxStringContentLength="67108864"
maxArrayLength="67108864"
maxBytesPerRead="67108864" maxNameTableCharCount="65536" />
<reliableSession enabled="false" />
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"
establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SiteService">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="true"
httpsGetEnabled="true" />
<serviceCredentials>
<serviceCertificate
findValue="Diligent.Boardbooks.Services" x509FindType="FindBySubjectName" />
<issuedTokenAuthentication>
<knownCertificates>
<add
findValue="Diligent.Boardbooks.SecurityTokenService"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
</knownCertificates>
</issuedTokenAuthentication>
</serviceCredentials>
<serviceThrottling maxConcurrentCalls="100"
maxConcurrentSessions="100" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="SiteService"
name="Diligent.Boardbooks.Services.SiteService.Implementation.SiteService">
<endpoint address="Site" binding="wsHttpBinding"
bindingConfiguration="WSMtomBinding"
name="SiteService"
contract="Diligent.Boardbooks.Services.SiteService.ServiceContracts.ISiteServiceContract" />
<endpoint address="SiteUN" binding="wsHttpBinding"
bindingConfiguration="WSUsernameMtomBinding"
name="SiteServiceUN"
contract="Diligent.Boardbooks.Services.SiteService.ServiceContracts.ISiteServiceContract" />
<endpoint address="InternalSite" binding="wsHttpBinding"
bindingConfiguration="WSMtomBinding"
name="InternalSiteService"
contract="Diligent.Boardbooks.Services.SiteService.ServiceContracts.IInternalSiteServiceContract" />
<endpoint address="InternalSiteUN" binding="wsHttpBinding"
bindingConfiguration="WSUsernameMtomBinding"
name="InternalSiteServiceUN"
contract="Diligent.Boardbooks.Services.SiteService.ServiceContracts.IInternalSiteServiceContract" />
<endpoint address="Test" binding="wsHttpBinding"
bindingConfiguration="WSUsernameMtomBinding"
name="TestService"
contract="Diligent.Boardbooks.Services.SiteService.ServiceContracts.ISiteServiceTestContract" />
</service>
</services>
</system.serviceModel>
Is there anything else I need to set on the binding or endpoint to get the
skew adjusted properly?
Many thanks,
Greg Jackman
To dump the binding to a configuraiton file, see Brian McNamara post, quite
useful.
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1232472&SiteID=1
hope it helps
Tiago Halm
"d72e4d" <d72...@discussions.microsoft.com> wrote in message
news:EBEA3A44-A94D-4F48...@microsoft.com...
I have followed the code to dump out the custom binding. Looking at the
result I don't see any other maxClockSkew settings in there. Is there
anything else I need to change? I'm thinking maybe replayWindow or
timestampValidityDuration? Any further help would be much appreciated.
For information, the custom binding is as follows:
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.serviceModel>
<bindings>
<customBinding>
<binding name="WSHttpBinding">
<transactionFlow
transactionProtocol="WSAtomicTransactionOctober2004" />
<security defaultAlgorithmSuite="Default"
authenticationMode="SspiNegotiatedOverTransport"
requireDerivedKeys="false"
securityHeaderLayout="Strict" includeTimestamp="true"
keyEntropyMode="CombinedEntropy"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
requireSecurityContextCancellation="true">
<localClientSettings cacheCookies="true"
detectReplays="false"
replayCacheSize="900000" maxClockSkew="01:00:00"
maxCookieCachingTime="Infinite"
replayWindow="00:05:00"
sessionKeyRenewalInterval="10:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="false"
timestampValidityDuration="00:05:00"
cookieRenewalThresholdPercentage="60" />
<localServiceSettings detectReplays="false"
issuedCookieLifetime="10:00:00"
maxStatefulNegotiations="128"
replayCacheSize="900000" maxClockSkew="01:00:00"
negotiationTimeout="00:01:00"
replayWindow="00:05:00" inactivityTimeout="00:02:00"
sessionKeyRenewalInterval="15:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="false"
maxPendingSessions="128"
maxCachedCookies="1000"
timestampValidityDuration="00:05:00" />
<secureConversationBootstrap />
</security>
<mtomMessageEncoding maxReadPoolSize="64"
maxWritePoolSize="16"
messageVersion="Default" maxBufferSize="67108864"
writeEncoding="utf-8">
<readerQuotas maxDepth="512"
maxStringContentLength="67108864"
maxArrayLength="67108864"
maxBytesPerRead="67108864" maxNameTableCharCount="65536" />
</mtomMessageEncoding>
<httpsTransport manualAddressing="false"
maxBufferPoolSize="524288"
maxReceivedMessageSize="67108864"
allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="67108864"
proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered"
unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true"
requireClientCertificate="false" />
</binding>
<binding name="WSHttpBinding1">
<transactionFlow
transactionProtocol="WSAtomicTransactionOctober2004" />
<security defaultAlgorithmSuite="Default"
authenticationMode="UserNameOverTransport"
requireDerivedKeys="true"
securityHeaderLayout="Strict" includeTimestamp="true"
keyEntropyMode="CombinedEntropy"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<localClientSettings cacheCookies="true"
detectReplays="false"
replayCacheSize="900000" maxClockSkew="01:00:00"
maxCookieCachingTime="Infinite"
replayWindow="00:05:00"
sessionKeyRenewalInterval="10:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="false"
timestampValidityDuration="00:05:00"
cookieRenewalThresholdPercentage="60" />
<localServiceSettings detectReplays="false"
issuedCookieLifetime="10:00:00"
maxStatefulNegotiations="128"
replayCacheSize="900000" maxClockSkew="01:00:00"
negotiationTimeout="00:01:00"
replayWindow="00:05:00" inactivityTimeout="00:02:00"
sessionKeyRenewalInterval="15:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="false"
maxPendingSessions="128"
maxCachedCookies="1000"
timestampValidityDuration="00:05:00" />
<secureConversationBootstrap />
</security>
<mtomMessageEncoding maxReadPoolSize="64"
maxWritePoolSize="16"
messageVersion="Default" maxBufferSize="67108864"
writeEncoding="utf-8">
<readerQuotas maxDepth="512"
maxStringContentLength="67108864"
maxArrayLength="67108864"
maxBytesPerRead="67108864" maxNameTableCharCount="65536" />
</mtomMessageEncoding>
<httpsTransport manualAddressing="false"
maxBufferPoolSize="524288"
maxReceivedMessageSize="67108864"
allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="67108864"
proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered"
unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true"
requireClientCertificate="false" />
</binding>
<binding name="WSHttpBinding2">
<transactionFlow
transactionProtocol="WSAtomicTransactionOctober2004" />
<security defaultAlgorithmSuite="Default"
authenticationMode="SspiNegotiatedOverTransport"
requireDerivedKeys="false"
securityHeaderLayout="Strict" includeTimestamp="true"
keyEntropyMode="CombinedEntropy"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
requireSecurityContextCancellation="true">
<localClientSettings cacheCookies="true"
detectReplays="false"
replayCacheSize="900000" maxClockSkew="01:00:00"
maxCookieCachingTime="Infinite"
replayWindow="00:05:00"
sessionKeyRenewalInterval="10:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="false"
timestampValidityDuration="00:05:00"
cookieRenewalThresholdPercentage="60" />
<localServiceSettings detectReplays="false"
issuedCookieLifetime="10:00:00"
maxStatefulNegotiations="128"
replayCacheSize="900000" maxClockSkew="01:00:00"
negotiationTimeout="00:01:00"
replayWindow="00:05:00" inactivityTimeout="00:02:00"
sessionKeyRenewalInterval="15:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="false"
maxPendingSessions="128"
maxCachedCookies="1000"
timestampValidityDuration="00:05:00" />
<secureConversationBootstrap />
</security>
<mtomMessageEncoding maxReadPoolSize="64"
maxWritePoolSize="16"
messageVersion="Default" maxBufferSize="67108864"
writeEncoding="utf-8">
<readerQuotas maxDepth="512"
maxStringContentLength="67108864"
maxArrayLength="67108864"
maxBytesPerRead="67108864" maxNameTableCharCount="65536" />
</mtomMessageEncoding>
<httpsTransport manualAddressing="false"
maxBufferPoolSize="524288"
maxReceivedMessageSize="67108864"
allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="67108864"
proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered"
unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true"
requireClientCertificate="false" />
</binding>
<binding name="WSHttpBinding3">
<transactionFlow
transactionProtocol="WSAtomicTransactionOctober2004" />
<security defaultAlgorithmSuite="Default"
authenticationMode="UserNameOverTransport"
requireDerivedKeys="true"
securityHeaderLayout="Strict" includeTimestamp="true"
keyEntropyMode="CombinedEntropy"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<localClientSettings cacheCookies="true"
detectReplays="false"
replayCacheSize="900000" maxClockSkew="01:00:00"
maxCookieCachingTime="Infinite"
replayWindow="00:05:00"
sessionKeyRenewalInterval="10:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="false"
timestampValidityDuration="00:05:00"
cookieRenewalThresholdPercentage="60" />
<localServiceSettings detectReplays="false"
issuedCookieLifetime="10:00:00"
maxStatefulNegotiations="128"
replayCacheSize="900000" maxClockSkew="01:00:00"
negotiationTimeout="00:01:00"
replayWindow="00:05:00" inactivityTimeout="00:02:00"
sessionKeyRenewalInterval="15:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="false"
maxPendingSessions="128"
maxCachedCookies="1000"
timestampValidityDuration="00:05:00" />
<secureConversationBootstrap />
</security>
<mtomMessageEncoding maxReadPoolSize="64"
maxWritePoolSize="16"
messageVersion="Default" maxBufferSize="67108864"
writeEncoding="utf-8">
<readerQuotas maxDepth="512"
maxStringContentLength="67108864"
maxArrayLength="67108864"
maxBytesPerRead="67108864" maxNameTableCharCount="65536" />
</mtomMessageEncoding>
<httpsTransport manualAddressing="false"
maxBufferPoolSize="524288"
maxReceivedMessageSize="67108864"
allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="67108864"
proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered"
unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true"
requireClientCertificate="false" />
</binding>
<binding name="WSHttpBinding4">
<transactionFlow
transactionProtocol="WSAtomicTransactionOctober2004" />
<security defaultAlgorithmSuite="Default"
authenticationMode="UserNameOverTransport"
requireDerivedKeys="true"
securityHeaderLayout="Strict" includeTimestamp="true"
keyEntropyMode="CombinedEntropy"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<localClientSettings cacheCookies="true"
detectReplays="false"
replayCacheSize="900000" maxClockSkew="01:00:00"
maxCookieCachingTime="Infinite"
replayWindow="00:05:00"
sessionKeyRenewalInterval="10:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="false"
timestampValidityDuration="00:05:00"
cookieRenewalThresholdPercentage="60" />
<localServiceSettings detectReplays="false"
issuedCookieLifetime="10:00:00"
maxStatefulNegotiations="128"
replayCacheSize="900000" maxClockSkew="01:00:00"
negotiationTimeout="00:01:00"
replayWindow="00:05:00" inactivityTimeout="00:02:00"
sessionKeyRenewalInterval="15:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="false"
maxPendingSessions="128"
maxCachedCookies="1000"
timestampValidityDuration="00:05:00" />
<secureConversationBootstrap />
</security>
<mtomMessageEncoding maxReadPoolSize="64"
maxWritePoolSize="16"
messageVersion="Default" maxBufferSize="67108864"
writeEncoding="utf-8">
<readerQuotas maxDepth="512"
maxStringContentLength="67108864"
maxArrayLength="67108864"
maxBytesPerRead="67108864" maxNameTableCharCount="65536" />
</mtomMessageEncoding>
<httpsTransport manualAddressing="false"
maxBufferPoolSize="524288"
maxReceivedMessageSize="67108864"
allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="67108864"
proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered"
unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true"
requireClientCertificate="false" />
</binding>
</customBinding>
</bindings>
</system.serviceModel>
</configuration>
Cheers,
Greg
But Ok, from what I can see you've updated the maxClockSkew on the
localServiceSettings. The reason why you do not have a
secureConversationBootstrap is because you're setting
establishSecurityContext="false".
You also need to set the maxClockSkew on the client configuration, but
now on localClientSettings to the same TimeSpan.
Finally, I assume that not establishing a security context should not
prevent the maxClockSkew from working. Try to make it work with
establishSecurityContext="false" by setting the maxClockSkew
programatically on the server and on the client. If you cannot make it
work, then set establishSecurityContext="true" and do the same, now
setting it also on the secureConversationBootstrap.
This thread may help on the latter case:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1231419&SiteID=1
Tiago Halm
We have intentionally turned off establishSecurityContext to get a
performance gain. We found that with it turned on, we were getting 6 round
trips to the service for each service request (2 creating the channel, 2
doing the request, and 2 closing the channel - btw, we are curious as to why
we get two round trips for each stage?). If we turn it off, we only get the
two round trips for the service request. On high latency networks this makes
quite a difference to our client performance.
Are you saying that we can't change the maxClockSkew properly without the
security context turned on? Is that a known issue?
Many thanks,
Greg
I was only saying that your sample should work as long as you update the
client side. I'm just not sure if secureConversationBootstrap is needed
since most advices are on webservices with secureConversationBootstrap.
Anyway, give the client update a try (still with
establishSecurityContext="false") and let us know the outcome.
Tiago Halm
"d72e4d" <d72...@discussions.microsoft.com> wrote in message
news:1035266A-96A0-47A1...@microsoft.com...
My initial testing did include creating the same binding on the client as
well. And we were still seeing the problem.
As you can see from the dump of the xml:
<localClientSettings cacheCookies="true"
detectReplays="false"
replayCacheSize="900000" maxClockSkew="01:00:00"
maxCookieCachingTime="Infinite"
replayWindow="00:05:00"
sessionKeyRenewalInterval="10:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="false"
timestampValidityDuration="00:05:00"
cookieRenewalThresholdPercentage="60" />
<localServiceSettings detectReplays="false"
issuedCookieLifetime="10:00:00"
maxStatefulNegotiations="128"
replayCacheSize="900000" maxClockSkew="01:00:00"
negotiationTimeout="00:01:00"
replayWindow="00:05:00" inactivityTimeout="00:02:00"
sessionKeyRenewalInterval="15:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="false"
maxPendingSessions="128"
maxCachedCookies="1000"
timestampValidityDuration="00:05:00" />
the code I have is setting both the client and service settings
MaxClockSkew, and I was running the same method on the client and service
bindings.
Hope that helps.
Cheers,
Greg
The testing was done with wsHttpBinding, securityMode="Message",
clientCredentialType="Windows". The establishSecurityContext="..." can
be set "true" or "false" as needed. The code below that sets
maxClockSkew takes care of both scenarios.
I've also enabled failure auditing with:
<serviceSecurityAudit
auditLogLocation="Application"
messageAuthenticationAuditLevel="Failure"
serviceAuthorizationAuditLevel="Failure"
suppressAuditFailure="false" />
This auditing setting helps to look into the EventLog and find the
current maxClockSkew setting on the service side when an error
happens.
Both the client and server share the same code snippet when adjusting
the maxClockSkew as below:
Binding AdjustClockSkew(Binding binding)
{
CustomBinding customBinding = new CustomBinding(binding);
SecurityBindingElement bindingElement =
customBinding.Elements.Find<SecurityBindingElement>();
bindingElement.LocalServiceSettings.MaxClockSkew =
TimeSpan.FromHours(2);
bindingElement.LocalClientSettings.MaxClockSkew =
TimeSpan.FromHours(2);
//
// Check if secure conversation is enabled
//
SecurityTokenParameters tokenParameters =
((SymmetricSecurityBindingElement)bindingElement).ProtectionTokenParameters;
if (tokenParameters is SecureConversationSecurityTokenParameters)
{
SecureConversationSecurityTokenParameters sct =
tokenParameters as SecureConversationSecurityTokenParameters;
bindingElement = sct.BootstrapSecurityBindingElement;
bindingElement.LocalServiceSettings.MaxClockSkew =
TimeSpan.FromHours(2);
bindingElement.LocalClientSettings.MaxClockSkew =
TimeSpan.FromHours(2);
}
return customBinding;
}
Obviously, the LocalServiceSettings is only needed in the service code
and LocalClientSettings is only needed in the client code, but for
simplification purposes I've decided to change both settings in both
the service code and the client code.
The client code:
CalcClient channel = new CalcClient();
channel.Endpoint.Binding =
AdjustClockSkew(channel.Endpoint.Binding);
channel.Hello();
channel.Close();
The service code:
[ServiceBehavior]
public class Calc : ICalc
{
string ICalc.Hello()
{
return "Hello";
}
}
[ServiceContract]
interface ICalc
{
[OperationContract]
string Hello();
}
class CustomServiceHost : ServiceHost
{
public CustomServiceHost(object singletonInstance, params Uri[]
baseAddresses)
: base(singletonInstance, baseAddresses)
{ }
public CustomServiceHost(Type serviceType, params Uri[]
baseAddresses)
: base(serviceType, baseAddresses)
{ }
protected override void ApplyConfiguration()
{
base.ApplyConfiguration();
foreach (ServiceEndpoint endpoint in Description.Endpoints)
{
endpoint.Binding = AdjustClockSkew(endpoint.Binding);
}
}
}
class Program
{
static void Main(string[] args)
{
CustomServiceHost host = new CustomServiceHost(typeof(Calc));
host.Open();
Console.WriteLine("Listening ...");
Console.ReadLine();
}
}
Tiago Halm
Thanks for your help on this one. I've used the code you supplied and the
problem is now solved. I've actually taken out the part about Symmetric
bindings as we never get those (as we use TransportWithMessageCredentials
security mode).
I'm not sure how its different from my original code. I'm thinking I may
have done a bad job of testing it first time round. Apologies for wasting
your time if thats the case.
Anyway, thanks for your help with it.
Cheers,
Greg