Commit Graph

53 Commits

Author SHA1 Message Date
Shawn O. Pearce 18e822a7fe smart-http: Fix recognition of gzip encoding
Some clients coming through proxies may advertise a different
Accept-Encoding, for example "Accept-Encoding: gzip(proxy)".
Matching by substring causes us to identify this as a false positive;
that the client understands gzip encoding and will inflate the
response before reading it.

In this particular case however it doesn't.  Its the reverse proxy
server in front of JGit letting us know the proxy<->JGit link can
be gzip compressed, while the client<->proxy part of the link is not:

  client <-- no gzip --> proxy <-- gzip --> JGit

Use a more standard method of parsing by splitting the value into
tokens, and only using gzip if one of the tokens is exactly the
string "gzip".  Add a unit test to make sure this isn't broken in
the future.

Change-Id: I30cda8a6d11ad235b56457adf54a2d27095d964e
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2011-02-15 16:32:51 -08:00
Shawn O. Pearce f194eeb71f http.test: Delete badly named JUnit configurations
We also have org.eclipse.jgit.http--All-Tests, which matches the
style of the org.eclipse.jgit.core--All-Tests name. Drop the others
as these are just redundant duplicates.

Change-Id: I8600a343f6a85d21dc07bda68a8cb834c82946b5
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2011-02-15 16:32:51 -08:00
Shawn O. Pearce 1b7a5a2960 daemon: Use HTTP's resolver and factory pattern
Using a resolver and factory pattern for the anonymous git:// Daemon
class makes transport.Daemon more useful on non-file storage systems,
or in embedded applications where the caller wants more precise
control over the work tasks constructed within the daemon.

Rather than defining new interfaces, move the existing HTTP ones
into transport.resolver and make them generic on the connection
handle type.  For HTTP, continue to use HttpServletRequest, and
for transport.Daemon use DaemonClient.

To remain compatible with transport.Daemon, FileResolver needs to
learn how to use multiple base directories, and how to export any
Repository instance at a fixed name.

Change-Id: I1efa6b2bd7c6567e983fbbf346947238ea2e847e
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2011-02-14 18:28:21 -08:00
Matthias Sohn f2c8eec57b Qualify post 0.11 builds
Change-Id: Ibcef4fc4c986c2cda01e943d16aa1c53eff99f25
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2011-02-12 03:30:05 +01:00
Matthias Sohn 857d151198 JGit 0.11.1
Change-Id: I9ac2fdfb4326536502964ba614d37d0bd103f524
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2011-02-11 23:25:34 +01:00
Matthias Sohn a6e3f53069 [findbugs] Do not ignore exceptional return value of createNewFile()
Properly handle return value of java.io.File.createNewFile().

Change-Id: I3a74cc84cd126ca1a0eaccc77b2944d783ff0747
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2011-01-28 01:11:12 +01:00
Robin Rosenberg ff7149fb95 Require the hamcrest packaging that comes with Eclipse
The other one gets installed with SWTBot, but you do not
need it if you do not hack EGit. Using import-package
instead of require-bundle fixes the dependency. Actually
we do not need hamcrest at this time, but JUnit wants it.

Change-Id: I59873618f86d02e8439d40c1f322ea8e5c4fe3fc
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
2011-01-01 19:05:00 +01:00
Robin Rosenberg d9e07a574a Convert all JGit unit tests to JUnit 4
Eclipse has some problem re-running single JUnit tests if
the tests are in Junit 3 format, but the JUnit 4 launcher
is used. This was quite unnecessary and the move was not
completed. We still have no JUnit4 test.

This completes the extermination of JUnit3. Most of the
work was global searce/replace using regular expression,
followed by numerous invocarions of quick-fix and organize
imports and verification that we had the same number of
tests before and after.

- Annotations were introduced.
- All references to JUnit3 classes removed
- Half-good replacement for getting the test name. This was
  needed to make the TestRngs work. The initialization of
  TestRngs was also made lazily since we can not longer find
  out the test name in runtime in the @Before methods.
- Renamed test classes to end with Test, with the exception
  of TestTranslateBundle, which fails from Maven
- Moved JGitTestUtil to the junit support bundle

Change-Id: Iddcd3da6ca927a7be773a9c63ebf8bb2147e2d13
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-12-31 14:00:05 -08:00
Robin Rosenberg 02ae788fa6 Add launchers for the JGit HTTP package test
Change-Id: I8bb5cb5342ab86fbc586d879dc56f70f4c0e6ace
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
2010-12-30 01:37:04 +01:00
Robin Rosenberg bf4ee4e6d4 Enable JUnit4 in the jgit.http package too
There are currently no JUnit4 tests here, but since we made JUnit4
the default for maven, it should be for Eclipse builds too.

Change-Id: Ic910df1705fa8d6ac26e97a41947cb8e5526d334
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
2010-12-30 01:25:18 +01:00
Matthias Sohn 485917598e Qualify post 0.10 builds
Change-Id: Ifcb8fdea95286779c8aea6bf4d7647e8c1c98d63
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2010-12-17 15:49:30 +01:00
Matthias Sohn 67d8f3a338 Merge branch 'stable-0.10' 2010-12-17 15:41:27 +01:00
Matthias Sohn 51d1af9489 Qualify post 0.10.1 builds
Change-Id: I320f1f739f3689daf11d532a55ae1133785aec8e
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2010-12-17 15:23:14 +01:00
Matthias Sohn 1fdc17bfe4 JGit 0.10.1
Change-Id: I4a46d35d354193e5d4f28ef7dfae75944be8ffcf
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2010-12-17 03:10:07 +01:00
Shawn O. Pearce 6f3b4d5d04 Save StoredConfig after modifications
When the Config is changed, it should be saved back to its local
file.  This ensure that a future call to getConfig() won't wipe
out the edits that were just made.

Change-Id: Id46d3f85d1c9b377f63ef861b72824e1aa060eee
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-12-15 15:14:05 -08:00
Shawn O. Pearce 013cb8de38 Reduce calls to Repository.getConfig
Each time getConfig() is called on FileRepository, it checks the
last modified time of both ~/.gitconfig and $GIT_DIR?config.  If
$GIT_DIR/config appears to have been modified, it is read back in
from disk and the current config is wiped out.

When mutating a configuration file, this may cause in-memory edits
to disappear.  To avoid that callers need to avoid calling getConfig
until after the configuration has been saved to disk.

Unfortunately the API is still horribly broken.  Configuration should
be modified only while a lock is held on the configuration file, very
similar to the way a ref is updated via its locking protocol.  But our
existing API is really broken for that so we'll have to defer cleaning
up the edit path for a future change.

Change-Id: I5888dd97bac20ddf60456c81ffc1eb8df04ef410
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-12-15 15:14:05 -08:00
Jens Baumgart c0b49c1366 JGit Build: use jetty 7.1.6
Jetty 7.1.6 is used because this version is also available in P2.

Change-Id: I410fbca8592cac6e58c651c4d086573820e777a5
Signed-off-by: Jens Baumgart <jens.baumgart@sap.com>
2010-12-09 10:42:05 +01:00
Jens Baumgart 51e2646d4a Introduce http test bundle
Introduce a http test bundle to make this functionality available for
EGit tests. A simple http server class is provided. The jetty version
was updated to a version that is also available via p2 (needed in EGit
UI tests).

Change-Id: I13bfc4c6c47e27d8f97d3e9752347d6d23e553d4
Signed-off-by: Jens Baumgart <jens.baumgart@sap.com>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2010-12-08 16:20:28 +01:00
Shawn O. Pearce 308e074f65 Enable providing credentials for HTTP authentication
This change is based on http://egit.eclipse.org/r/#change,1652
by David Green. The change adds the concept of a CredentialsProvider
which can be registered for git transports and which is
responsible to return credential-related data like passwords and
usernames. Whenenver the transports detects that an authentication
with certain credentials has to be done it will ask the
CredentialsProvider for this data. Foreseen implementations for
such a Provider may be a EGitCredentialsProvider (caching
credential data entered e.g. in the Clone-Wizzard) or a NetRcProvider
(gathering data out of ~/.netrc file).

Bug: 296201
Change-Id: Ibe13e546b45eed3e193c09ecb414bbec2971d362
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Signed-off-by: Christian Halstrick <christian.halstrick@sap.com>
Signed-off-by: Stefan Lay <stefan.lay@sap.com>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
CC: David Green <dgreen99@gmail.com>
2010-11-10 14:58:44 -08:00
Stefan Lay 20a5a34444 Fix WWW-Authenticate auth-scheme comparison
The auth-scheme token (like "Basic" or "Digest") is not specified in a
case sensitive way. RFC2617 (http://tools.ietf.org/html/rfc2617) specifies
in section 1.2 the use of a "case-insensitive token to identify the
authentication scheme". Jetty, for example, uses "basic" as token.

Change-Id: I635a94eb0a741abcb3e68195da6913753bdbd889
Signed-off-by: Stefan Lay <stefan.lay@sap.com>
2010-11-10 09:42:51 +01:00
Matthias Sohn 784d388c49 Externalize strings in TransportHttp
Some strings were not externalized. Also use them in HTTP tests to
ensure that they will also succeed when message bundles are
translated.

Change-Id: Id02717176557e7d57e676e1339cd89f2be88d330
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2010-10-08 01:03:17 +03:00
Matthias Sohn 2b98a878b4 Fix HTTP tests
Since 858b2c92 we have a HTTP authentication implementation hence
we now get different exception messages when required authentication
headers are not available. This broke the HTTP tests.

Change-Id: Ie08c1ec37e497c2a6f70a75f7c59f0805812a5cc
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2010-10-07 23:40:40 +03:00
Shawn O. Pearce 4b5d3d291b Qualify builds as 0.10.0
Change-Id: I54815c85b32b9492c059064b39f48677e68c5e90
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-09-16 17:26:53 -07:00
Matthias Sohn 26f507f0df Qualify post-0.9.3 builds
Change-Id: Ideab4923a5d8055f0e8a36ddcf0bc8adbf71c329
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2010-09-16 01:49:03 +02:00
Matthias Sohn 2920fcdde8 JGit 0.9.3
Change-Id: I114106f3286c36f7d5e136748a7e5130f4da163f
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2010-09-16 01:02:53 +02:00
Matthias Sohn 7ae5e82d66 Qualify post-0.9.1 builds
Change-Id: I07a3391de03379f32ecfd055d45750e3860b2be4
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2010-09-15 11:31:05 +02:00
Matthias Sohn 445a3a281d JGit 0.9.1
Change-Id: Ic411b1b8a7e6039ae3ff567e2c9cdd5db84f4d41
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2010-09-15 09:46:11 +02:00
Robin Rosenberg 236899204a Revert "Hide Maven target directories from Eclipse"
This reverts commit db4c516f67 since
it breaks compatibility with Eclipse 3.5 which can no longer import
the projects

Bug: 323390
Change-Id: I3cc91364a6747cfcb4c611a9be5258f81562f726
2010-08-28 09:50:50 +02:00
Chris Aniszczyk d1edd00f56 Run formatter on edited lines via save action
Updates the project level settings to run the formatter
on save on only on the edited lines.

Change-Id: I26dd69d0c95e6d73f9fdf7031f3c1dbf3becbb79
Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
2010-08-26 12:33:09 -05:00
Robin Rosenberg db4c516f67 Hide Maven target directories from Eclipse
Change-Id: I64f12a35423a90ced9c9bc83f6869d8ed766dd35
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
2010-08-08 13:16:53 +02:00
Shawn O. Pearce fa9b225e06 Merge branch 'delta'
* delta: (103 commits)
  Discard the uncompressed delta as soon as its compressed
  Honor pack.windowlimit to cap memory usage during packing
  Honor pack.threads and perform delta search in parallel
  Cache small deltas during packing
  Implement delta generation during packing
  debug-show-packdelta:  Dump a pack delta to the console
  Initial pack format delta generator
  Add debugging toString() method to ObjectToPack
  Make ObjectToPack clearReuseAsIs signal available to subclasses
  Correctly classify the compressing objects phase
  Refactor ObjectToPack's delta depth setting
  Configure core.bigFileThreshold into PackWriter
  Add doNotDelta flag to ObjectToPack
  Add more configuration options to PackWriter
  Save object path hash codes during packing
  Add path hash code to ObjectWalk
  Add getObjectSize to ObjectReader
  Allow TemporaryBuffer.Heap to allocate smaller than 8 KiB
  Define a constant for 127 in DeltaEncoder
  Cap delta copy instructions at 64k
  ...

Conflicts:
	org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
	org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
	org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
	org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteTreeFilter.java

Change-Id: I7c7a05e443a48d32c836173a409ee7d340c70796
2010-07-22 14:56:34 -07:00
Jonathan Gossage ec13e0382a Fully implement Logger interface
On April 27, 2010 the Logger interface was upgraded with a number of new methods
to make it consistent with the implementations it was meant to support.

This patch makes RecordingLogger consistent with the Logger interface and allows to
also use Jetty 7.1.5 released with Helios which can be installed from the p2 repository
at http://download.eclipse.org/jetty/7.1.5.v20100705/repository

Change-Id: I5645436bbe7492f82d4069e4d9cbebede0bf764e
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2010-07-17 01:53:23 +02:00
Shawn O. Pearce ad5238dc67 Move FileRepository to storage.file.FileRepository
This move isolates all of the local file specific implementation code
into a single package, where their package-private methods and support
classes are properly hidden away from the rest of the core library.

Because of the sheer number of files impacted, I have limited this
change to only the renames and the updated imports.

Change-Id: Icca4884e1a418f83f8b617d0c4c78b73d8a4bd17
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-06-26 18:50:34 -07:00
Shawn O. Pearce 89d4a7377f Use FileRepository where we assume other file semantics
When the surrounding code is already heavily based upon the
assumption that we have a FileRepository (e.g. because it
created that type of repository) keep the type around and
use it directly.  This permits us to continue to do things
like save the configuration file.

Change-Id: Ib783f0f6a11acd6aa305c16d61ccc368b46beecc
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-06-25 17:46:40 -07:00
Shawn O. Pearce 6a822f0ebf Remove RepositoryConfig and use FileBasedConfig instead
Change the Repository API to use straight-up FileBasedConfig.
This lets us remove the subclass RepositoryConfig and stop having
a specialized configuration type for repository, letting us instead
focus the config type heirarchy on type-of-storage rather than use.

Change-Id: I7236800e8090624453a89cb0c7a9a632702691c6
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-06-25 17:46:40 -07:00
Matthias Sohn 767fb175ed Fix line endings
Some sources had dos line endings. Also configure all projects to use
unix line endings and UTF-8 text encoding.

Change-Id: I8fc9a1dbb219ffa91d1b3011b3b11b7e48e74ca7
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2010-06-18 23:36:18 +02:00
Shawn Pearce 86fcdc53ad Merge changes I53f71dc0,I3a899a3a,I3e8bd245,Ie7c9db83,If396326e,I6f4cf8da,I3bf96dd0,I3a2a43a1,I292fe88c,Ia1cf40cf
* changes:
  git-servlet: Fix comparing uploadFactory with the wrong DISABLED instance
  Prefer static inner classes
  Override equals for SwingLane since super class PlotLane defines it
  Make sure a Stream is closed upon errors in IpLogGenerator
  Make constant static in RebuildCommitGraph
  Make inner classes static in http code
  Cache filemode in GitIndex 
  Remove unused parent field in PlotLane
  Removed unused repo field in WorkDirCheckout
  Extend DiffFormatter API to simplify styling
2010-06-14 19:59:48 -04:00
Shawn O. Pearce 239ce58553 Start 0.9 development
Change-Id: I84173ece5100f1fcb78168e2e102b649d9466c08
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-06-14 08:11:27 -07:00
Robin Rosenberg 6f4cf8daec Make inner classes static in http code
Static classes are preferrable to keep unwanted dependencies away, 
and they have one less member field.

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
2010-06-13 03:19:47 +02:00
Shawn O. Pearce d8ec8527a6 Qualify post-0.8.1 builds
Change-Id: Id86e5876b2f684b2a272c07061a276b054ba410d
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-06-02 15:55:39 -07:00
Shawn O. Pearce be86767d71 JGit 0.8.1
Change-Id: I3d4ac7d0617a3575019e2ed748ed2a298a988340
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-06-02 14:47:31 -07:00
Shawn O. Pearce 14e469c44e Qualify builds as 0.8.0
Since the API is changing relative to 0.7.0, we'll call our next
release 0.8.1.  But until that gets released, builds from master
will be 0.8.0.qualifier.

Change-Id: I921e984f51ce498610c09e0db21be72a533fee88
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-03-20 19:06:58 -07:00
Shawn O. Pearce c0f093899f http.server: Use TemporaryBuffer and compress some responses
The HTTP server side code now uses the same approach that the smart
HTTP client code uses when preparing a request body.  The payload
is streamed into a TemporaryBuffer of limited size.  If the entire
data fits, its compressed with gzip if the user agent supports that,
and a Content-Length header is used to transmit the fixed length
body to the peer.  If however the data overflows the limited memory
segment, its streamed uncompressed to the peer.

One might initially think that larger contents which overflow
the buffer should also be compressed, rather than sent raw, since
they were deemed "large".  But usually these larger contents are
actually a pack file which has been already heavily compressed by
Git specific routines.  Trying to deflate that with gzip is probably
going to take up more space, not less, so the compression overhead
isn't worthwhile.

This buffer and compress optimization helps repositories with a
large number of references, as their text based advertisements
compress well. For example jgit's own native repository currently
requires 32,628 bytes for its full advertisement of 489 references.
Most repositories have fewer references, and thus could compress
their entire response in one buffer.

Change-Id: I790609c9f763339e0a1db9172aa570e29af96f42
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-03-12 16:08:14 -08:00
Shawn O. Pearce d8c3e98d73 Use "ERR message" for early ReceivePack problems
If the application wants to, it can use sendError(String) to send one
or more error messages to clients before the advertisements are sent.
These will cause a C Git client to break out of the advertisement
parsing loop, display "remote error: message\n", and terminate.

Servers can optionally use this to send a detailed error to a client
explaining why it cannot use the ReceivePack service on a repository.
Over smart HTTP these errors are sent in a 200 OK response, and
are in the payload, allowing the Git client to give the end-user
the custom message rather than the generic error "403 Forbidden".

Change-Id: I03f4345183765d21002118617174c77f71427b5a
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-03-12 16:08:14 -08:00
Shawn O. Pearce 673b3984bd Capture non-progress side band #2 messages and put in result
Any messages received on side band #2 that aren't scraped as a
progress message into our ProgressMonitor are now forwarded to a
buffer which is later included into the OperationResult object.
Application callers can use this buffer to present the additional
messages from the remote peer after the push or fetch operation
has concluded.

The smart push connections using the native send-pack/receive-pack
protocol now request side-band-64k capability if it is available
and forward any messages received through that channel onto this
message buffer.  This makes hook messages available over smart HTTP,
or even over SSH.

The SSH transport was modified to redirect the remote command's
stderr stream into the message buffer, interleaved with any data
received over side band #2.  Due to buffering between these two
different channels in the SSH channel mux itself the order of any
writes between the two cannot be ensured, but it tries to stay close.

The local fork transport was also modified to redirect the local
receive-pack's stderr into the message buffer, rather than going to
the invoking JVM's System.err.  This gives applications a chance
to log the local error messages, rather than needing to redirect
their JVM's stderr before startup.

To keep things simple, the application has to wait for the entire
operation to complete before it can see the messages.  This may
be a downside if the user is trying to debug a remote hook that is
blocking indefinitely, the user would need to abort the connection
before they can inspect the message buffer in any sort of UI built
on top of JGit.

Change-Id: Ibc215f4569e63071da5b7e5c6674ce924ae39e11
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-03-12 16:08:13 -08:00
Shawn O. Pearce 3dd067042f http.test: Use JUnit 3 test runner
JGit relies on JUnit 3, not JUnit 4.

Change-Id: Ic5a0ae1564d7744c203321857fc603e7008dbf13
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-02-09 19:51:36 -08:00
Shawn O. Pearce 1ca22467f5 http.test: Add missing plugin.properties to build
Change-Id: I17e2c22498092d25dace88319698626ce55df822
2010-02-09 19:28:28 -08:00
Shawn O. Pearce d207c69ff4 http.test: Use JGit Format and compiler settings
Somehow we missed setting this up for the project.

Change-Id: Id55a6415f5fd03a7cd9d4d4ecbdd726cef79430d
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-02-09 19:28:28 -08:00
Shawn O. Pearce 179a9ba4a2 Cleanup OSGi Import-Package specifications to use versions
Actually set the range of versions we are willing to accept for
each package we import, lest we import something in the future
that isn't compatible with our needs.

Change-Id: I25dbbb9eaabe852631b677e0c608792b3ed97532
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-02-02 20:03:03 -08:00
Shawn O. Pearce f2d5187ea1 Fix racy HTTP tests by waiting for requests to finish
Ensure the background Jetty threads have been able to write the
request log record before the JUnit thread tries to read the set
of requests back.  This wait is necessary because the JUnit thread
may be able to continue as soon as Jetty has finished writing
the response onto the socket, and hasn't necessarily finished the
post-response logging activity.

By using a semaphore with a fixed number of resources, and using
one resource per request, but all of them when we want to read the
log, we implement a simple lock that requires there be no active
requests when we want to get the log from the JUnit thread.

Change-Id: I499e1c96418557185d0e19ba8befe892f26ce7e4
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
2010-01-25 14:51:56 -08:00