RE: [jira] Commented: (JCS-68) Admin.jsp on remote cache server does not broadcast removes - patch
Aaron Smuts <[email protected]> Mon, 31 Aug 2009 10:58:03 -0700 (PDT)
| Newsgroups | gmane.comp.jakarta.turbine.jcs.devel |
|---|---|
| Message-ID | <[email protected]> |
I have no idea. Strange. =0A=0ABut to make a patch, you have to checkout = the code. . . . =0A=0A--- On Mon, 8/31/09, Tim Cronin <Tim.Cronin@autonomy= .com> wrote:=0A=0A> From: Tim Cronin <[email protected]>=0A> Subject:= RE: [jira] Commented: (JCS-68) Admin.jsp on remote cache server does not b= roadcast removes - patch=0A> To: "JCS Developers List" <[email protected]= che.org>=0A> Date: Monday, August 31, 2009, 8:22 AM=0A> Any reason that the= RemoteCacheServer=0A> class is not exposed in the=0A> Javadocs?=0A> =0A> h= ttp://jakarta.apache.org/jcs/apidocs/org/apache/jcs/auxiliary/remote/se=0A>= rver/RemoteCacheServerFactory.html=0A> =0A> =0A> -----Original Message----= -=0A> From: Aaron Smuts (JIRA) [mailto:[email protected]] =0A> Sent: Monday, = August 31, 2009 8:29 AM=0A> To: [email protected]=0A> Subject: [ji= ra] Commented: (JCS-68) Admin.jsp on remote=0A> cache server=0A> does not b= roadcast removes - patch=0A> =0A> =0A> =A0 =A0 [=0A> https://issues.apache.= org/jira/browse/JCS-68?page=3Dcom.atlassian.jira.plu=0A> gin.system.issueta= bpanels:comment-tabpanel&focusedCommentId=3D12749487#act=0A> ion_12749487 ]= =0A> =0A> Aaron Smuts commented on JCS-68:=0A> ---------------------------= -----=0A> =0A> Thanks, this is a good idea.=A0 Why are you calling the=0A> = remove method via=0A> reflection?=A0 That's too fragile.=A0 Especially=0A> = without any unit tests.=A0 I=0A> need unit tests for all changes.=A0 =0A> = =0A> > Admin.jsp on remote cache server does not broadcast=0A> removes - pa= tch=0A> >=0A> -------------------------------------------------------------= ------=0A> >=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0Key: JCS-68=0A> = >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0URL: https://issues.apache.org/ji= ra/browse/JCS-68=0A> >=A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0Project: JCS=0A> >= =A0 =A0 =A0 =A0 =A0 Issue Type: Bug=0A> >=A0 =A0 =A0 =A0 =A0 Components: RM= I=0A> Remote Cache=0A> >=A0 =A0 Affects Versions: jcs-1.3, jcs-1.4-dev=0A> = >=A0 =A0 =A0 =A0=A0=A0Environment:=0A> All=0A> >=A0 =A0 =A0 =A0 =A0 =A0 Rep= orter:=0A> Niall Gallagher=0A> >=A0 =A0 =A0 =A0 =A0 =A0 Assignee:=0A> Aaron= Smuts=0A> >=A0 =A0 =A0 =A0 =A0 =A0 Priority:=0A> Minor=0A> >=A0=A0=A0Origi= nal Estimate: 0.5h=0A> >=A0 Remaining Estimate: 0.5h=0A> >=0A> > We'd like = to contribute some patches to fix an issue=0A> with the=0A> JCSAdmin.jsp wh= en it's used on a JCS remote cache server.=0A> > We use this JSP on our rem= ote cache server. This=0A> allows us to browse=0A> the objects stored in ou= r distributed cache (i.e. uploaded=0A> by the client=0A> servers), and allo= ws us to remove arbitrary objects from=0A> the distributed=0A> cache by cli= cking 'remove' next to the key of the relevant=0A> object=0A> displayed on = the JSP.=0A> > The issue is: when we use the unmodified version of=0A> the = code to remove=0A> an object, the object is successfully removed from the J= CS=0A> remote=0A> server, but the 'remove' event for that object is not=0A>= broadcast to all=0A> client machines. Client machines which start up after= we=0A> remove the=0A> object get 'null' when they try to retrieve the obje= ct (the=0A> desired=0A> behaviour). However client machines which were alre= ady=0A> running and using=0A> this object continue to see the object in the= ir view of the=0A> cache.=0A> > This problem occurs because the JCSAdminBea= n (used by=0A> this JSP) calls=0A> the wrong API in JCS to remove objects f= rom the cache when=0A> it's running=0A> on the remote cache server. It call= s the CompositeCache=0A> API, which is=0A> intended for use client-side onl= y.=0A> > Our patches update JCSAdminBean to call this same API=0A> when its= running=0A> on a client machine, BUT if it's running on a machine on=0A> w= hich the JCS=0A> remote server is enabled, it calls the RemoteCacheServer= =0A> API instead.=0A> > The fix involves replacing 3 methods in=0A> org.apa= che.jcs.admin.JCSAdminBean as follows:=0A> >=A0 =A0=A0=A0/**=0A> >=A0 =A0 = =A0 * Clears all regions in the=0A> cache.=0A> >=A0 =A0 =A0 * <p/>=0A> >=A0= =A0 =A0 * If this class is running within=0A> a remote cache server, clear= s=0A> all regions via the=0A> <code>RemoteCacheServer</code>=0A> >=A0 =A0 = =A0 * API, so that removes will be=0A> broadcast to client machines.=0A> Ot= herwise clears all regions in the cache directly via=0A> >=A0 =A0 =A0 * the= usual cache API.=0A> >=A0 =A0 =A0 */=0A> >=A0 =A0=A0=A0public void clearAl= lRegions()=0A> throws IOException {=0A> >=A0 =A0 =A0 =A0=A0=A0if=0A> (Remot= eCacheServerFactory.getRemoteCacheServer() =3D=3D null) {=0A> >=A0 =A0 =A0 = =A0 =A0 =A0=A0=A0//=0A> Not running in a remote cache server.=0A> >=A0 =A0 = =A0 =A0 =A0 =A0=A0=A0//=0A> Remove objects from the cache directly, as no n= eed to=0A> broadcast removes to client machines...=0A> >=A0 =A0 =A0 =A0 =A0= =0A> =A0=A0=A0String[] names =3D=0A> cacheHub.getCacheNames();=0A> >=A0 =A0= =A0 =A0 =A0=0A> =A0=A0=A0for (int i =3D 0; i < names.length; i++)=0A> {=0A= > >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0cacheHub.getCache(names[i]).rem= oveAll();=0A> >=A0 =A0 =A0 =A0 =A0 =A0=A0=A0}=0A> >=A0 =A0 =A0 =A0=A0=A0}= =0A> >=A0 =A0 =A0 =A0=A0=A0else {=0A> >=A0 =A0 =A0 =A0 =A0 =A0=A0=A0//=0A> = Running in a remote cache server.=0A> >=A0 =A0 =A0 =A0 =A0 =A0=A0=A0//=0A> = Remove objects via the RemoteCacheServer API, so that=0A> removes will be b= roadcast to client machines...=0A> >=A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0try {= =0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0String[] cacheNames =3D=0A> = CompositeCacheManager.getInstance().getCacheNames();=0A> >=A0 =A0 =A0 =A0 = =A0 =A0 =A0=0A> =A0=A0=A0// Call=0A> remoteCacheServer.removeAll(String) fo= r each=0A> cacheName...=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0// No= te: We must do this using reflection=0A> to bypass=0A> its package-private = access...=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0Object remoteCacheS= erverObject =3D=0A> RemoteCacheServerFactory.getRemoteCacheServer();=0A> >= =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0Method removeAllMethod =3D=0A> rem= oteCacheServerObject.getClass().getMethod("removeAll",=0A> new=0A> Class[]{= String.class});=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0boolean previ= ouslyAccessibility =3D=0A> removeAllMethod.isAccessible();=0A> >=A0 =A0 =A0= =A0 =A0 =A0 =A0=0A> =A0=A0=A0removeAllMethod.setAccessible(true);=0A> >=A0= =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0for (int i =3D 0; i < cacheNames.leng= th;=0A> i++) {=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0 =A0=A0=A0String= cacheName =3D cacheNames[i];=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0= =0A> =A0=A0=A0removeAllMethod.invoke(remoteCacheServerObject,=0A> new Objec= t[]{cacheName});=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0}=0A> >=0A> = removeAllMethod.setAccessible(previouslyAccessibility);=0A> >=A0 =A0 =A0 = =A0 =A0 =A0=A0=A0}=0A> >=A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0catch (Exception e= ) {=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0throw new IllegalStateExc= eption("Failed to=0A> remove all=0A> elements from all cache regions: " + e= , e);=0A> >=A0 =A0 =A0 =A0 =A0 =A0=A0=A0}=0A> >=A0 =A0 =A0 =A0=A0=A0}=0A> >= =A0 =A0=A0=A0}=0A> >=A0 =A0=A0=A0/**=0A> >=A0 =A0 =A0 * Clears a particular= cache=0A> region.=0A> >=A0 =A0 =A0 * <p/>=0A> >=A0 =A0 =A0 * If this class= is running within=0A> a remote cache server, clears=0A> the region via the= =0A> <code>RemoteCacheServer</code>=0A> >=A0 =A0 =A0 * API, so that removes= will be=0A> broadcast to client machines.=0A> Otherwise clears the region = directly via the usual=0A> >=A0 =A0 =A0 * cache API.=0A> >=A0 =A0 =A0 */=0A= > >=A0 =A0=A0=A0public void clearRegion(String=0A> cacheName) throws IOExce= ption {=0A> >=A0 =A0 =A0 =A0=A0=A0if (cacheName =3D=3D=0A> null) {=0A> >=A0= =A0 =A0 =A0 =A0=0A> =A0=A0=A0throw new IllegalArgumentException("The=0A> c= ache name=0A> specified was null.");=0A> >=A0 =A0 =A0 =A0=A0=A0}=0A> >=A0 = =A0 =A0 =A0=A0=A0if=0A> (RemoteCacheServerFactory.getRemoteCacheServer() = =3D=3D null) {=0A> >=A0 =A0 =A0 =A0 =A0 =A0=A0=A0//=0A> Not running in a re= mote cache server.=0A> >=A0 =A0 =A0 =A0 =A0 =A0=A0=A0//=0A> Remove objects = from the cache directly, as no need to=0A> broadcast removes to client mach= ines...=0A> >=A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0cacheHub.getCache(cacheName).= removeAll();=0A> >=A0 =A0 =A0 =A0=A0=A0}=0A> >=A0 =A0 =A0 =A0=A0=A0else {= =0A> >=A0 =A0 =A0 =A0 =A0 =A0=A0=A0//=0A> Running in a remote cache server.= =0A> >=A0 =A0 =A0 =A0 =A0 =A0=A0=A0//=0A> Remove objects via the RemoteCach= eServer API, so that=0A> removes will be broadcast to client machines...=0A= > >=A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0try {=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0= =0A> =A0=A0=A0// Call=0A> remoteCacheServer.removeAll(String)...=0A> >=A0 = =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0// Note: We must do this using reflect= ion=0A> to bypass=0A> its package-private access...=0A> >=A0 =A0 =A0 =A0 = =A0 =A0 =A0=0A> =A0=A0=A0Object remoteCacheServerObject =3D=0A> RemoteCache= ServerFactory.getRemoteCacheServer();=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> = =A0=A0=A0Method removeAllMethod =3D=0A> remoteCacheServerObject.getClass().= getMethod("removeAll",=0A> new=0A> Class[]{String.class});=0A> >=A0 =A0 =A0= =A0 =A0 =A0 =A0=0A> =A0=A0=A0boolean previouslyAccessibility =3D=0A> remov= eAllMethod.isAccessible();=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0re= moveAllMethod.setAccessible(true);=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0= =A0=A0removeAllMethod.invoke(remoteCacheServerObject,=0A> new=0A> Object[]{= cacheName});=0A> >=0A> removeAllMethod.setAccessible(previouslyAccessibilit= y);=0A> >=A0 =A0 =A0 =A0 =A0 =A0=A0=A0}=0A> >=A0 =A0 =A0 =A0 =A0=0A> =A0=A0= =A0catch (Exception e) {=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0thro= w new IllegalStateException("Failed to=0A> remove all=0A> elements from cac= he region [" + cacheName + "]: " + e, e);=0A> >=A0 =A0 =A0 =A0 =A0 =A0=A0= =A0}=0A> >=A0 =A0 =A0 =A0=A0=A0}=0A> >=A0 =A0=A0=A0}=0A> >=A0 =A0=A0=A0/**= =0A> >=A0 =A0 =A0 * Removes a particular item from a=0A> particular region.= =0A> >=A0 =A0 =A0 * <p/>=0A> >=A0 =A0 =A0 * If this class is running within= =0A> a remote cache server, removes=0A> the item via the=0A> <code>RemoteCa= cheServer</code>=0A> >=A0 =A0 =A0 * API, so that removes will be=0A> broadc= ast to client machines.=0A> Otherwise clears the region directly via the us= ual=0A> >=A0 =A0 =A0 * cache API.=0A> >=A0 =A0 =A0 *=0A> >=A0 =A0 =A0 * @pa= ram cacheName=0A> >=A0 =A0 =A0 * @param key=0A> >=A0 =A0 =A0 *=0A> >=A0 =A0= =A0 * @throws IOException=0A> >=A0 =A0 =A0 */=0A> >=A0 =A0=A0=A0public voi= d removeItem(String=0A> cacheName, String key) throws=0A> IOException {=0A>= >=A0 =A0 =A0 =A0=A0=A0if (cacheName =3D=3D=0A> null) {=0A> >=A0 =A0 =A0 = =A0 =A0=0A> =A0=A0=A0throw new IllegalArgumentException("The=0A> cache name= =0A> specified was null.");=0A> >=A0 =A0 =A0 =A0=A0=A0}=0A> >=A0 =A0 =A0 = =A0=A0=A0if (key =3D=3D null)=0A> {=0A> >=A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0t= hrow new IllegalArgumentException("The=0A> key specified was=0A> null.");= =0A> >=A0 =A0 =A0 =A0=A0=A0}=0A> >=A0 =A0 =A0 =A0=A0=A0if=0A> (RemoteCacheS= erverFactory.getRemoteCacheServer() =3D=3D null) {=0A> >=A0 =A0 =A0 =A0 =A0= =A0=A0=A0//=0A> Not running in a remote cache server.=0A> >=A0 =A0 =A0 =A0= =A0 =A0=A0=A0//=0A> Remove objects from the cache directly, as no need to= =0A> broadcast removes to client machines...=0A> >=A0 =A0 =A0 =A0 =A0=0A> = =A0=A0=A0cacheHub.getCache(cacheName).remove(key);=0A> >=A0 =A0 =A0 =A0=A0= =A0}=0A> >=A0 =A0 =A0 =A0=A0=A0else {=0A> >=A0 =A0 =A0 =A0 =A0 =A0=A0=A0//= =0A> Running in a remote cache server.=0A> >=A0 =A0 =A0 =A0 =A0 =A0=A0=A0//= =0A> Remove objects via the RemoteCacheServer API, so that=0A> removes will= be broadcast to client machines...=0A> >=A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0t= ry {=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0Object keyToRemove =3D n= ull;=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0CompositeCache cache =3D= =0A> CompositeCacheManager.getInstance().getCache(cacheName);=0A> >=A0 =A0 = =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0// A String key was supplied, but to=0A> r= emove elements=0A> via the RemoteCacheServer API, we need the=0A> >=A0 =A0 = =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0// actual key object as stored in the=0A> = cache (i.e. a=0A> Serializable object). To find the key in this form,=0A> >= =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0// we iterate through all keys sto= red in=0A> the memory=0A> cache until we find one whose toString matches=0A= > >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0// the string supplied...=0A> >= =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0Object[] allKeysInCache =3D=0A> ca= che.getMemoryCache().getKeyArray();=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> = =A0=A0=A0for (int i =3D 0; i <=0A> allKeysInCache.length; i++) {=0A> >=A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0 =A0=A0=A0Object keyInCache =3D=0A> allK= eysInCache[i];=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0 =A0=A0=A0if=0A>= (keyInCache.toString().equals(key)) {=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =0A> =A0 =A0 =A0 =A0=A0=A0if (keyToRemove =3D=3D=0A> null) {=0A> >=A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0keyToRemove = =3D keyInCache;=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0 =A0 =A0 =A0=A0= =A0}=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0 =A0 =A0 =A0=A0=A0else {= =0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0 =A0 =A0 =A0 =A0 =A0=A0=A0// A= =0A> key matching the one specified was=0A> already found...=0A> >=A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0 =A0 =A0 =A0 =A0 =A0=A0=A0throw=0A> new=0A> = IllegalStateException("Unexpectedly found duplicate keys in=0A> the cache= =0A> region matching the key specified.");=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0=0A> =A0 =A0 =A0 =A0=A0=A0}=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> = =A0 =A0=A0=A0}=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0}=0A> >=A0 =A0= =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0if (keyToRemove =3D=3D null) {=0A> >=A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0 =A0=A0=A0throw new IllegalStateExceptio= n("No=0A> match for this=0A> key could be found in the set of keys retrieve= d from the=0A> memory=0A> cache.");=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> = =A0=A0=A0}=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0if (!(keyToRemove = instanceof=0A> Serializable)) {=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> = =A0 =A0=A0=A0throw new=0A> IllegalStateException("Found key [" +=0A> keyToR= emove + ", " + keyToRemove.getClass() + "] in cache=0A> matching key=0A> sp= ecified, however key found in cache is unexpectedly not=0A> serializable.")= ;=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0}=0A> >=A0 =A0 =A0 =A0 =A0 = =A0 =A0=0A> =A0=A0=A0// At this point, we have retrieved the=0A> matching= =0A> Serializable key.=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0// Cal= l remoteCacheServer.remove(String,=0A> Serializable)...=0A> >=A0 =A0 =A0 = =A0 =A0 =A0 =A0=0A> =A0=A0=A0// Note: We must fo this using reflection=0A> = to bypass=0A> its package-private access...=0A> >=A0 =A0 =A0 =A0 =A0 =A0 = =A0=0A> =A0=A0=A0Object remoteCacheServerObject =3D=0A> RemoteCacheServerFa= ctory.getRemoteCacheServer();=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0= =A0Method removeMethod =3D=0A> remoteCacheServerObject.getClass().getMethod= ("remove", new=0A> Class[]{String.class, Serializable.class});=0A> >=A0 =A0= =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0boolean previouslyAccessibility =3D=0A> r= emoveMethod.isAccessible();=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0r= emoveMethod.setAccessible(true);=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0= =A0=A0removeMethod.invoke(remoteCacheServerObject,=0A> new=0A> Object[]{cac= heName, keyToRemove});=0A> >=A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0remove= Method.setAccessible(previouslyAccessibility);=0A> >=A0 =A0 =A0 =A0 =A0 =A0= =A0=A0}=0A> >=A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0catch (Exception e) {=0A> >= =A0 =A0 =A0 =A0 =A0 =A0 =A0=0A> =A0=A0=A0throw new IllegalStateException("F= ailed to=0A> remove=0A> element with key [" + key + ", " + key.getClass() += "] from=0A> cache region=0A> [" + cacheName + "]: " + e, e);=0A> >=A0 =A0 = =A0 =A0 =A0 =A0=A0=A0}=0A> >=A0 =A0 =A0 =A0=A0=A0}=0A> >=A0 =A0=A0=A0}=0A> = =0A> -- =0A> This message is automatically generated by JIRA.=0A> -=0A> You= can reply to this email to add a comment to the issue=0A> online.=0A> =0A>= =0A> ---------------------------------------------------------------------= =0A> To unsubscribe, e-mail: [email protected]=0A> For= additional commands, e-mail: [email protected]=0A> =0A> =0A>= ---------------------------------------------------------------------=0A> = To unsubscribe, e-mail: [email protected]=0A> For addi= tional commands, e-mail: [email protected]=0A> =0A>