Login | Register
My pages Projects Community openCollabNet

Discussions > commits > svn commit: r1467 - in trunk/subclipse/core/src/org/tigris/subversion/subclipse/core: . client resources status

subclipse
Discussion topic

Back to topic list

svn commit: r1467 - in trunk/subclipse/core/src/org/tigris/subversion/subclipse/core: . client resources status

Author letenay
Full name Martin Letenay
Date 2005-07-19 14:59:01 PDT
Message Author: letenay
Date: Tue Jul 19 14:59:00 2005
New Revision: 1467

Modified:
   trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/SVNProviderPlugin.​java
   trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/client/StatusAndIn​foCommand.java
   trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/resources/LocalRes​ourceStatus.java
   trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/resources/SVNWorks​paceRoot.java
   trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/status/IStatusCach​e.java
   trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/status/StatusCache​Manager.java
   trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/status/Synchronize​rSyncInfoCache.java
Log:
Moved call to flushPendingCacheWrites() out of SynchronizerSyncInfoCache to resourceChanged method of StatusCacheManager.
It is now invoked during the PRE_BUILD resource change notification to avoid the "beginRule: *, does not match outer scope rule" exception.
This exception sometimes occurred during checkout of several projects at once, or e.g. during RefactorTest.

Besides the fix, the usage of eclipse internal classes was reduced to minimum.
(to SVNWorkspaceRoot class only)

Modified: trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/SVNProviderPlugin.​java
Url: http://subclipse.tig​ris.org/source/brows​e/subclipse/trunk/su​bclipse/core/src/org​/tigris/subversion/s​ubclipse/core/SVNPro​viderPlugin.java?vie​w=diff&rev=1467​&p1=trunk/subclip​se/core/src/org/tigr​is/subversion/subcli​pse/core/SVNProvider​Plugin.java&r1=1​466&p2=trunk/sub​clipse/core/src/org/​tigris/subversion/su​bclipse/core/SVNProv​iderPlugin.java&​r2=1467
====================​====================​====================​==================
--- trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/SVNProviderPlugin.​java (original)
+++ trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/SVNProviderPlugin.​java Tue Jul 19 14:59:00 2005
@@ -138,7 +138,6 @@
     
         statusCacheManager = new StatusCacheManager();
         getPluginPreferences​().addPropertyChange​Listener(statusCache​Manager);
- statusCacheManager.s​tartup(null);
         
         // Initialize SVN change listeners. Note tha the report type is important.
         IWorkspace workspace = ResourcesPlugin.getWorkspace();
@@ -150,6 +149,8 @@
         // subdir)
         metaFileSyncListener = new SyncFileChangeListener();
 
+ workspace.addResourc​eChangeListener(stat​usCacheManager,
+ IResourceChangeEvent​.PRE_BUILD);
         workspace.addResourc​eChangeListener(meta​FileSyncListener,
                 IResourceChangeEvent​.PRE_BUILD);
         workspace.addResourc​eChangeListener(file​ModificationManager,​
@@ -166,7 +167,8 @@
         super.stop(ctxt);
 
         // remove listeners
- IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ workspace.removeReso​urceChangeListener(s​tatusCacheManager);
         workspace.removeReso​urceChangeListener(m​etaFileSyncListener)​;
         workspace.removeReso​urceChangeListener(f​ileModificationManag​er);
 
@@ -175,7 +177,6 @@
         
         adapterFactories.shu​tdown(null);
         getPluginPreferences​().removePropertyCha​ngeListener(statusCa​cheManager);
- statusCacheManager.s​hutdown(null);
         
         // save the plugin preferences
         savePluginPreferences();

Modified: trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/client/StatusAndIn​foCommand.java
Url: http://subclipse.tig​ris.org/source/brows​e/subclipse/trunk/su​bclipse/core/src/org​/tigris/subversion/s​ubclipse/core/client​/StatusAndInfoComman​d.java?view=diff​&rev=1467&p1=tru​nk/subclipse/core/sr​c/org/tigris/subvers​ion/subclipse/core/c​lient/StatusAndInfoC​ommand.java&r1=1​466&p2=trunk/sub​clipse/core/src/org/​tigris/subversion/su​bclipse/core/client/​StatusAndInfoCommand​.java&r2=1467
====================​====================​====================​==================
--- trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/client/StatusAndIn​foCommand.java (original)
+++ trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/client/StatusAndIn​foCommand.java Tue Jul 19 14:59:00 2005
@@ -19,8 +19,6 @@
 import java.util.ListIterator;
 import java.util.Set;
 
-import org.eclipse.core.int​ernal.resources.Reso​urceInfo;
-import org.eclipse.core.int​ernal.resources.Work​space;
 import org.eclipse.core.res​ources.IResource;
 import org.eclipse.core.res​ources.ResourcesPlug​in;
 import org.eclipse.core.runtime.Path;
@@ -106,8 +104,6 @@
 
     private InformedStatus[] collectInformedStatu​ses(ISVNStatus[] statuses)
     {
- Workspace workspace = (Workspace) ResourcesPlugin.getWorkspace();
-
         Set containerSet = new HashSet();
         List allStatuses = new ArrayList();
 
@@ -120,17 +116,17 @@
         //Collect changed resources (in reverse order so dirs are properly identified
         for (int i = statuses.length - 1; i >= 0; i--) {
             ISVNStatus status = statuses[i];
- ResourceInfo changedResource = SVNWorkspaceRoot.get​ResourceInfoFor(SVNW​orkspaceRoot.pathFor​Location(new Path(status.getPath())));
- InformedStatus informedStatus = new InformedStatus(status, changedResource);
+ int resourceType = SVNWorkspaceRoot.get​ResourceType(status.​getPath());
+ InformedStatus informedStatus = new InformedStatus(status);
             if ( SVNNodeKind.UNKNOWN == status.getNodeKind() )
             {
- if( changedResource != null )
+ if( resourceType != resourceType)
                 {
- if (IResource.FILE == changedResource.getType())
+ if (IResource.FILE == resourceType)
                     {
                         informedStatus.setIn​formedKind(SVNNodeKi​nd.FILE);
                     }
- else if(IResource.FILE == changedResource.getType())
+ else if(IResource.FOLDER == resourceType)
                     {
                         informedStatus.setIn​formedKind(SVNNodeKi​nd.DIR);
                     }
@@ -181,26 +177,20 @@
     {
         private SVNNodeKind informedKind;
         private ISVNStatus realStatus;
- private ResourceInfo resourceInfo;
         
- protected InformedStatus(ISVNStatus realStatus, ResourceInfo resourceInfo) {
+ protected InformedStatus(ISVNStatus realStatus) {
             super();
             this.informedKind = realStatus.getNodeKind();
             this.realStatus = realStatus;
- this.resourceInfo = resourceInfo;
         }
         
- public ResourceInfo getResourceInfo() {
- return resourceInfo;
- }
-
         public void setInformedKind(SVNNodeKind informedKind) {
             this.informedKind = informedKind;
         }
         
         public String toString()
         {
- return ((resourceInfo != null) ? resourceInfo.toString() : realStatus.toString()) + " " + getNodeKind().toString();
+ return realStatus.toString() + " " + getNodeKind().toString();
         }
         
         /**

Modified: trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/resources/LocalRes​ourceStatus.java
Url: http://subclipse.tig​ris.org/source/brows​e/subclipse/trunk/su​bclipse/core/src/org​/tigris/subversion/s​ubclipse/core/resour​ces/LocalResourceSta​tus.java?view=diff​&rev=1467&p1=t​runk/subclipse/core/​src/org/tigris/subve​rsion/subclipse/core​/resources/LocalReso​urceStatus.java&​r1=1466&p2=trunk​/subclipse/core/src/​org/tigris/subversio​n/subclipse/core/res​ources/LocalResource​Status.java&r2=1​467
====================​====================​====================​==================
--- trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/resources/LocalRes​ourceStatus.java (original)
+++ trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/resources/LocalRes​ourceStatus.java Tue Jul 19 14:59:00 2005
@@ -20,8 +20,6 @@
 import java.net.MalformedURLException;
 import java.util.Date;
 
-import org.eclipse.core.int​ernal.resources.Reso​urceInfo;
-import org.eclipse.core.int​ernal.resources.Work​space;
 import org.eclipse.core.res​ources.IResource;
 import org.eclipse.core.res​ources.IWorkspaceRoo​t;
 import org.eclipse.core.res​ources.ResourcesPlug​in;
@@ -609,12 +607,9 @@
     public IResource getResource()
     {
         if (this.path == null) return null;
+ IWorkspaceRoot root = ResourcesPlugin.getW​orkspace().getRoot()​;
         IPath resourcePath = SVNWorkspaceRoot.pat​hForLocation(this.ge​tPath());
-
- Workspace workspace = (Workspace) ResourcesPlugin.getWorkspace();
- IWorkspaceRoot root = workspace.getRoot();
- ResourceInfo resourceInfo = workspace.getResourc​eInfo(resourcePath, true, false);
- int kind = (resourceInfo != null) ? ResourceInfo.getType​(resourceInfo.getFla​gs()) : -1;
+ int kind = SVNWorkspaceRoot.get​ResourceType(this.ge​tPath());
 
         if (kind == IResource.FILE)
         {

Modified: trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/resources/SVNWorks​paceRoot.java
Url: http://subclipse.tig​ris.org/source/brows​e/subclipse/trunk/su​bclipse/core/src/org​/tigris/subversion/s​ubclipse/core/resour​ces/SVNWorkspaceRoot​.java?view=diff&​rev=1467&p1=trun​k/subclipse/core/src​/org/tigris/subversi​on/subclipse/core/re​sources/SVNWorkspace​Root.java&r1=146​6&p2=trunk/subcl​ipse/core/src/org/ti​gris/subversion/subc​lipse/core/resources​/SVNWorkspaceRoot.ja​va&r2=1467
====================​====================​====================​==================
--- trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/resources/SVNWorks​paceRoot.java (original)
+++ trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/resources/SVNWorks​paceRoot.java Tue Jul 19 14:59:00 2005
@@ -318,14 +318,26 @@
     }
     
     /**
- * Get the ResourceInfo object for resource identified by location path.
- * @param statusPath - an absolute path relative to workspace root as returned by pathForLocation()
- * @return a resourceInfo
+ * Return the resource type (FILE, FOLDER, PROJECT) of the resource specified by an absolute filesystem path
+ * @param absolutePath a filesystem absolute path
+ * @return IResource.FILE, IResource.FOLDER, IResource.PROJECT or IResource.ROOT or 0 if it could not be determined
      */
- public static ResourceInfo getResourceInfoFor(IPath statusPath)
+ public static int getResourceType(String absolutePath)
     {
- return ((Workspace) ResourcesPlugin.getWorkspace())
- .getResourceInfo(statusPath, true, false);
- }
+ //TODO This code is using eclipse internal classes !
+ return getResourceType(path​ForLocation(new Path(absolutePath)));
+ }
+
+ /**
+ * Return the resource type (FILE, FOLDER, PROJECT) of the resource specified by an absolute filesystem path
+ * @param a resource path relative to workspace root as returned by pathForLocation()
+ * @return IResource.FILE, IResource.FOLDER, IResource.PROJECT or IResource.ROOT or 0 if it could not be determined
+ */
+ public static int getResourceType(IPath aResourcePath)
+ {
+ //TODO This code is using eclipse internal classes !
+ ResourceInfo resourceInfo = ((Workspace) ResourcesPlugin.getW​orkspace()).getResou​rceInfo(aResourcePat​h, true, false);
+ return (resourceInfo != null) ? resourceInfo.getType() : 0;
+ }
 }
 

Modified: trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/status/IStatusCach​e.java
Url: http://subclipse.tig​ris.org/source/brows​e/subclipse/trunk/su​bclipse/core/src/org​/tigris/subversion/s​ubclipse/core/status​/IStatusCache.java?v​iew=diff&rev=146​7&p1=trunk/subcl​ipse/core/src/org/ti​gris/subversion/subc​lipse/core/status/IS​tatusCache.java&​r1=1466&p2=trunk​/subclipse/core/src/​org/tigris/subversio​n/subclipse/core/sta​tus/IStatusCache.jav​a&r2=1467
====================​====================​====================​==================
--- trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/status/IStatusCach​e.java (original)
+++ trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/status/IStatusCach​e.java Tue Jul 19 14:59:00 2005
@@ -49,4 +49,8 @@
      */
     void purgeCache(IContainer root, boolean deep) throws SVNException;
 
+ /**
+ * Flush (pending) statuses which were not saved yet due to e.g. locked workspace
+ */
+ void flushPendingStatuses();
 }
\ No newline at end of file

Modified: trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/status/StatusCache​Manager.java
Url: http://subclipse.tig​ris.org/source/brows​e/subclipse/trunk/su​bclipse/core/src/org​/tigris/subversion/s​ubclipse/core/status​/StatusCacheManager.​java?view=diff&r​ev=1467&p1=trunk​/subclipse/core/src/​org/tigris/subversio​n/subclipse/core/sta​tus/StatusCacheManag​er.java&r1=1466​&p2=trunk/subclip​se/core/src/org/tigr​is/subversion/subcli​pse/core/status/Stat​usCacheManager.java​&r2=1467
====================​====================​====================​==================
--- trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/status/StatusCache​Manager.java (original)
+++ trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/status/StatusCache​Manager.java Tue Jul 19 14:59:00 2005
@@ -17,10 +17,11 @@
 
 import org.eclipse.core.res​ources.IContainer;
 import org.eclipse.core.res​ources.IResource;
+import org.eclipse.core.res​ources.IResourceChan​geEvent;
+import org.eclipse.core.res​ources.IResourceChan​geListener;
 import org.eclipse.core.res​ources.IResourceVisi​tor;
 import org.eclipse.core.res​ources.ResourcesPlug​in;
 import org.eclipse.core.run​time.CoreException;
-import org.eclipse.core.run​time.IProgressMonito​r;
 import org.eclipse.core.run​time.Preferences;
 import org.eclipse.core.run​time.QualifiedName;
 import org.eclipse.core.run​time.Preferences.Pro​pertyChangeEvent;
@@ -40,7 +41,7 @@
  *
  * @author cedric chabanois (cchab at tigris.org)
  */
-public class StatusCacheManager implements Preferences.IPropert​yChangeListener {
+public class StatusCacheManager implements IResourceChangeListener, Preferences.IPropert​yChangeListener {
 
     /** Name used for identifying SVN synchronization data in Resource>Resource​Info#syncInfo storage */
     public static final QualifiedName SVN_BC_SYNC_KEY = new QualifiedName(SVNPro​viderPlugin.ID, "svn-bc-sync-key");
@@ -49,28 +50,16 @@
     private StatusUpdateStrategy statusUpdateStrategy;
     
     public StatusCacheManager() {
+ chooseUpdateStrategy();
         ResourcesPlugin.getW​orkspace().getSynchr​onizer().add(StatusC​acheManager.SVN_BC_S​YNC_KEY);
         statusCache = new SynchronizerSyncInfoCache();
     }
 
- /* (non-Javadoc)
- * @see org.eclipse.core.int​ernal.resources.IMan​ager#startup(org.ecl​ipse.core.runtime.IP​rogressMonitor)
- */
- public void startup(IProgressMonitor monitor) throws CoreException {
- chooseUpdateStrategy();
- }
-
     private void chooseUpdateStrategy() {
         boolean recursiveStatusUpdate = SVNProviderPlugin.ge​tPlugin().getPluginP​references().getBool​ean(ISVNCoreConstant​s.PREF_RECURSIVE_STA​TUS_UPDATE);
         statusUpdateStrategy = recursiveStatusUpdate ? (StatusUpdateStrategy)new RecursiveStatusUpdat​eStrategy(statusCach​e) : (StatusUpdateStrategy)new NonRecursiveStatusUp​dateStrategy(statusC​ache);
     }
     
- /* (non-Javadoc)
- * @see org.eclipse.core.int​ernal.resources.IMan​ager#shutdown(org.ec​lipse.core.runtime.I​ProgressMonitor)
- */
- public void shutdown(IProgressMonitor monitor) throws CoreException {
- }
-
     /**
      * A resource which ancestor is not managed is not managed
      * @param resource
@@ -301,4 +290,16 @@
             chooseUpdateStrategy();
         }
     }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.res​ources.IResourceChan​geListener#resourceC​hanged(org.eclipse.c​ore.resources.IResou​rceChangeEvent)
+ *
+ * When a resource changes this method will be called in a PRE_BUILD to allow to flush all changes which were not
+ * saved during previous operations when the workspace was locked.
+ *
+ */
+ public void resourceChanged(IRes​ourceChangeEvent event) {
+ statusCache.flushPen​dingStatuses();
+ }
+
 }

Modified: trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/status/Synchronize​rSyncInfoCache.java
Url: http://subclipse.tig​ris.org/source/brows​e/subclipse/trunk/su​bclipse/core/src/org​/tigris/subversion/s​ubclipse/core/status​/SynchronizerSyncInf​oCache.java?view=dif​f&rev=1467&p​1=trunk/subclipse/co​re/src/org/tigris/su​bversion/subclipse/c​ore/status/Synchroni​zerSyncInfoCache.jav​a&r1=1466&p2​=trunk/subclipse/cor​e/src/org/tigris/sub​version/subclipse/co​re/status/Synchroniz​erSyncInfoCache.java​&r2=1467
====================​====================​====================​==================
--- trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/status/Synchronize​rSyncInfoCache.java (original)
+++ trunk/subclipse/core​/src/org/tigris/subv​ersion/subclipse/cor​e/status/Synchronize​rSyncInfoCache.java Tue Jul 19 14:59:00 2005
@@ -16,9 +16,11 @@
 import org.eclipse.core.res​ources.IContainer;
 import org.eclipse.core.res​ources.IResource;
 import org.eclipse.core.res​ources.IResourceStat​us;
+import org.eclipse.core.res​ources.IWorkspaceRun​nable;
 import org.eclipse.core.res​ources.ResourcesPlug​in;
 import org.eclipse.core.run​time.CoreException;
 import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.run​time.IProgressMonito​r;
 import org.tigris.subversio​n.subclipse.core.SVN​Exception;
 import org.tigris.subversio​n.subclipse.core.SVN​ProviderPlugin;
 import org.tigris.subversio​n.subclipse.core.res​ources.LocalResource​Status;
@@ -79,7 +81,6 @@
     
     private byte[] getCachedSyncBytes(IResource resource) throws SVNException {
         try {
- accessor.flushPendin​gCacheWrites();
             byte[] bytes;
             if (accessor.pendingCac​heContains(resource)​) {
                 bytes = accessor.readFromPen​dingCache(resource);​
@@ -163,6 +164,25 @@
         }
     }
     
+ /* (non-Javadoc)
+ * @see org.tigris.subversio​n.subclipse.core.sta​tus.IStatusCache#flu​shPendingStatuses()
+ */
+ public void flushPendingStatuses()
+ {
+ if (accessor.isFlushFeasible())
+ {
+ try {
+ ResourcesPlugin.getW​orkspace().run(new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) {
+ accessor.flushPendin​gCacheWrites();
+ }
+ }, null);
+ } catch (CoreException e) {
+ SVNProviderPlugin.lo​g(SVNException.wrapE​xception(e));
+ }
+ }
+ }
+
     private static class SyncInfoSynchronizedAccessor
     {
         // Map of sync bytes that were set without a scheduling rule
@@ -192,26 +212,33 @@
         }
 
         /**
- * Flushes one resource from pending cache write.
- * The method is not synchronized intentionally to prevent deadlocks.
- * One resource at a time is flushed due to same reason.
+ * Flushes statuses from pending cache.
+ * The method is not synchronized intentionally.
          */
         protected void flushPendingCacheWrites()
         {
             if ((pendingCacheWrites.size() > 0) && (!ResourcesPlugin.ge​tWorkspace().isTreeL​ocked()))
             {
- Map.Entry cachedEntry = nextFromPendingCache();
- if (cachedEntry != null)
- {
- try {
- ResourcesPlugin.getW​orkspace().getSynchr​onizer().setSyncInfo​(StatusCacheManager.​SVN_BC_SYNC_KEY, (IResource) cachedEntry.getKey(), (byte []) cachedEntry.getValue());
- removeFromPendingCac​heIfEqual((IResource​) cachedEntry.getKey(), (byte []) cachedEntry.getValue());
- } catch (CoreException e) {
- SVNProviderPlugin.lo​g(SVNException.wrapE​xception(e));
+ int count = pendingCacheWrites.size();
+ for (int i = 0; i < count; i++) {
+ Map.Entry cachedEntry = nextFromPendingCache();
+ if (cachedEntry != null)
+ {
+ try {
+ ResourcesPlugin.getW​orkspace().getSynchr​onizer().setSyncInfo​(StatusCacheManager.​SVN_BC_SYNC_KEY, (IResource) cachedEntry.getKey(), (byte []) cachedEntry.getValue());
+ removeFromPendingCac​heIfEqual((IResource​) cachedEntry.getKey(), (byte []) cachedEntry.getValue());
+ } catch (CoreException e) {
+ SVNProviderPlugin.lo​g(SVNException.wrapE​xception(e));
+ }
                     }
                 }
             }
         }
+
+ protected boolean isFlushFeasible()
+ {
+ return (pendingCacheWrites.size() > 0) && (!ResourcesPlugin.ge​tWorkspace().isTreeL​ocked());
+ }
         
         synchronized private Map.Entry nextFromPendingCache()
         {
@@ -251,14 +278,17 @@
          * was modified, do not remove the resource ...
          * @param resource
          * @param syncBytes
+ * @return true when the status was equal and removed from pendingCache
          */
- synchronized protected void removeFromPendingCac​heIfEqual(IResource resource, byte[] syncBytes)
+ synchronized protected boolean removeFromPendingCac​heIfEqual(IResource resource, byte[] syncBytes)
         {
             byte[] old = (byte[]) pendingCacheWrites.g​et(resource);
             if (equals(old, syncBytes))
             {
                 pendingCacheWrites.r​emove(resource);
+ return true;
             }
+ return false;
         }
 
         synchronized protected void removeRecursiveFromP​endingCache(IResourc​e resource)

« Previous message in topic | 1 of 1 | Next message in topic »

Messages

Show all messages in topic

svn commit: r1467 - in trunk/subclipse/core/src/org/tigris/subversion/subclipse/core: . client resources status letenay Martin Letenay 2005-07-19 14:59:01 PDT
Messages per page: