Commit Graph

5329 Commits

Author SHA1 Message Date
Matthias Sohn 6b544da293 Prepare 4.10.0-SNAPSHOT builds
Change-Id: I5ca462d1db18a2c5c9382cfb9c83972510fa2b88
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2017-10-08 11:35:54 +02:00
Till Brychcy 401c6c98b5 Terminate StreamCopy threads in case of errors
- fix NPE: don't invoke close() if no exception happened.

Bug: 513554
Change-Id: I29f9b2ac1607ee26521e8aba334facd20e4ad79c
Signed-off-by: Till Brychcy <register.eclipse@brychcy.de>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2017-10-07 00:03:45 +02:00
Zhen Chen 65f9046547 Use a new RevWalk for validating not advertised wants
Shadow commits in the RevWalk in the UploadPack object may cause the
UNINTERESTING flag not being carried over to their parents commits since
they were marked NO_PARENTS during the assumeShallow or
initializeShallowCommits call.

A new RevWalk needs to be created for this reason, but instead of
creating a new RevWalk from Repository, we can reuse the ObjectReader in
the RevWalk of UploadPack to load objects.

Change-Id: Ic3fee0512d35b4f555c60e696a880f8b192e4439
Signed-off-by: Zhen Chen <czhen@google.com>
2017-10-05 17:16:13 -07:00
Matthias Sohn a2ec6ccf0a Add photon target platform jgit-4.8.target
Change-Id: I87f52f512db4c89fa4e3e550ff97fdec843b8469
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2017-10-05 17:58:02 -04:00
Ned Twigg f333c7496b Checkout now reports failures through exceptions.
Checkout sometimes throws an exception, and
other times it writes an error message to outw
and returns normally, even though the command
failed.  This commit now reports all failures
through a die() exception.

Change-Id: I038a5d976d95020fea3faac68e9178f923c25b28
Signed-off-by: Ned Twigg <ned.twigg@diffplug.com>
2017-10-01 00:07:26 -04:00
Dmitry Neverov a0a8a6a3e4 Terminate StreamCopy threads in case of errors
Bug: 513554
Change-Id: I065836b8fc77ade6de92e4a809fcf770a4f793ec
Signed-off-by: Dmitry Neverov <dmitry.neverov@gmail.com>
2017-09-30 14:01:16 +01:00
Dave Borowitz 2bbe15abd4 ReflogWriter: Align auto-creation defaults with C git
Per git-config(1), core.logAllRefUpdates auto-creates reflogs for HEAD
and for refs under heads, notes, tags, and for HEAD. Add notes and
remove stash from ReflogWriter#shouldAutoCreateLog. Explicitly force
writing reflogs for refs/stash at call sites, now that this is
supported.

Change-Id: I3a46d2c2703b7c243e0ee2bbf6948279800c485c
2017-09-30 12:01:19 +01:00
Dave Borowitz 77a28e0d58 Support force writing reflog on a per-update basis
Even if a repository has core.logAllRefUpdates=true, ReflogWriter does
not create reflog files unless the refs are under a hard-coded list of
prefixes, or unless the forceWrite bit is set. Expose the forceWrite bit
on a per-update basis in RefUpdate/BatchRefUpdate/ReceiveCommand,
creating RefLogWriters as necessary.

Change-Id: Ifc851fba00f76bf56d4134f821d0576b37810f80
2017-09-30 11:55:31 +01:00
Dave Borowitz b1ae96bf84 Ensure ReflogWriter only works with a RefDirectory
The ReflogWriter constructor just took a Repository and called
getDirectory() on it to figure out the reflog dirs, but not all
Repository instances use this storage format for reflogs, so it's
incorrect to attempt to use ReflogWriter when there is not a
RefDirectory directly involved. In practice, ReflogWriter was mostly
only used by the implementation of RefDirectory, so enforcing this is
mostly just shuffling around calls in the same internal package.

The one exception is StashDropCommand, which writes to a reflog lock
file directly. This was a reasonable implementation decision, because
there is no general reflog interface in JGit beyond using
(Batch)RefUpdate to write new entries to the reflog. So to implement
"git stash drop <N>", which removes an arbitrary element from the
reflog, it's fair to fall back to the RefDirectory implementation.
Creating and using a more general interface is well beyond the scope of
this change.

That said, the old behavior of writing out the reflog file even if
that's not the reflog format used by the given Repository is clearly
wrong. Fail fast in this case instead.

Change-Id: I9bd4b047bc3e28a5607fd346ec2400dde9151730
2017-09-30 11:54:05 +01:00
David Pursehouse 4160938c8b ChangeIdUtilTest: Remove unused notestCommitDashV
This test was never being run. Since it was introduced it was
named "notest.." which meant it didn't run with JUnit3, and
since it is not annotated @Test it also doesn't run with JUnit4.

When compiling with Bazel 0.6.0, error-prone raises an error
that the public method is not annotated with @Ignore or @Test.

Given that the test has never been run anyway, we can just
remove it.

Bug: 525415
Change-Id: Ie9a54f89fe42e0c201f547ff54ff1d419ce37864
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-30 11:04:09 +01:00
Pepper Lebeck-Jobe bc45947c98 Add the args4j jar
This allows the tests to all be built and run by bazel.

Bug: 525412
Change-Id: Ie9281d07462cd07200fadb4b0e7b7f88c44f7865
Signed-off-by: Pepper Lebeck-Jobe <eljobe@gmail.com>
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-30 10:04:56 +01:00
Thomas Wolf 6dab29f4b5 HttpConfig: load user config before reading values from it
Same problem as in commit c227268: openUserConfig() just creates the
FileBasedConfig object, but doesn't read the file yet. An explicit
load() is needed.

As HttpConfig is read-only this omission did not cause any bad effects,
but it simply ignored values from the user config. Most uses of
HttpConfig go through the two-argument constructor, though, where
HttpConfig is given an already loaded repo config.

Change-Id: Ibe7c562c17d6ef37de8b661ab7f6fa0246db01a2
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
2017-09-26 23:54:45 +02:00
Thomas Wolf c227268995 Load the user config before modifying it
SystemReader.openUserConfig() does not load the config yet; an
explicit StoredConfig.load() is needed.

Bug: 374703
Change-Id: I1c397e2fb1a07ac4d9de3675d996417734ff90e9
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
2017-09-23 11:15:27 +02:00
Ned Twigg c1fbef3cab Added API to TextBuiltin for piped usage.
Added a public method to TextBuiltin which makes it possible for
clients to initialize all of its state, including output and error
streams.  This gives clients the ability to customize the way in
which a command is run.

Change-Id: If718236964d2c5cf869e120c74f1a12965f4812e
Signed-off-by: Ned Twigg <ned.twigg@diffplug.com>
2017-09-21 14:48:45 -04:00
David Pursehouse e32aed6d75 SubmoduleUpdateCommand: Add fetch callback
When the submodule already exists, it is fetched instead of
cloned.

Use the fetch callback instead of clone callback in this case.

Change-Id: I170c21ab92b4117f25fdf940fe6807f214b04d39
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-20 21:49:47 +02:00
Michael FIG 06835f3e4f Fetch submodule repo before resolving commits
By default, this is turned off unless cmd.setFetch(true) is given.  It
will default to true in a future release to mimic c-git behaviour.

This is needed to prevent Eclipse from crashing with "Missing unknown
[REF]" when cloning a repo with submodules.

Bug: 470318
Change-Id: I8ae37c7c5bd2408cead8d57dd13e93e01e0e9dc1
Signed-off-by: Michael FIG <michael@fig.org>
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-20 21:49:46 +02:00
Thomas Wolf d946f95c9c Handle SSL handshake failures in TransportHttp
When a https connection could not be established because the SSL
handshake was unsuccessful, TransportHttp would unconditionally
throw a TransportException.

Other https clients like web browsers or also some SVN clients
handle this more gracefully. If there's a problem with the server
certificate, they inform the user and give him a possibility to
connect to the server all the same.

In git, this would correspond to dynamically setting http.sslVerify
to false for the server.

Implement this using the CredentialsProvider to inform and ask the
user. We offer three choices:

1. skip SSL verification for the current git operation, or
2. skip SSL verification for the server always from now on for
   requests originating from the current repository, or
3. always skip SSL verification for the server from now on.

For (1), we just suppress SSL verification for the current instance of
TransportHttp.

For (2), we store a http.<uri>.sslVerify = false setting for the
original URI in the repo config.

For (3), we store the http.<uri>.sslVerify setting in the git user
config.

Adapt the SmartClientSmartServerSslTest such that it uses this
mechanism instead of setting http.sslVerify up front.

Improve SimpleHttpServer to enable setting it up also with HTTPS
support in anticipation of an EGit SWTbot UI test verifying that
cloning via HTTPS from a server that has a certificate that doesn't
validate pops up the correct dialog, and that cloning subsequently
proceeds successfully if the user decides to skip SSL verification.

Bug: 374703
Change-Id: Ie1abada9a3d389ad4d8d52c2d5265d2764e3fb0e
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
2017-09-13 23:23:08 +02:00
Thomas Wolf fdcd4f9a34 Support http.<url>.* configs
Git has a rather elaborate mechanism to specify HTTP configuration
options per URL, based on pattern matching the URL against "http"
subsection names.[1] The URLs used for this matching are always the
original URLs; redirected URLs do not participate.

* Scheme and host must match exactly case-insensitively.
* An optional user name must match exactly.
* Ports must match exactly after default ports have been filled in.
* The path of a subsection, if any, must match a segment prefix of
  the path of the URL.
* Matches with user name take precedence over equal-length path
  matches without, but longer path matches are preferred over
  shorter matches with user name.

Implement this for JGit. Factor out the HttpConfig from TransportHttp
and implement the matching and override mechanism.

The set of supported settings is still the same; JGit currently
supports only followRedirects, postBuffer, and sslVerify, plus the
JGit-specific maxRedirects key.

Add tests for path normalization and prefix matching only on segment
separators, and use the new mechanism in SmartClientSmartServerSslTest
to disable sslVerify selectively for only the test server URLs.

Compare also bug 374703 and bug 465492. With this commit it would be
possible to set sslVerify to false for only the git server using a
self-signed certificate instead of having to switch it off globally
via http.sslVerify.

[1] https://git-scm.com/docs/git-config

Change-Id: I42a3c2399cb937cd7884116a2a32fcaa7a418fcb
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
2017-09-10 17:37:54 -04:00
David Pursehouse 2dbfe49a42 Add PushConfig class with PushRecurseSubmodulesMode
This will be used later when adding for support for recursing
submodules on push.

Change-Id: Ie2a183e5404a32046de9f6524e6ceeec37919671
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-09 13:58:09 -04:00
Matthias Sohn 52ed475211 Implement CommandRef.toString() to help debugging
Change-Id: If3ebed08c8f4e2cc925a97dbdd4c84410bc7c4a5
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2017-09-08 01:51:23 +02:00
Thomas Wolf c27f36dfc7 Fix missing RefsChangedEvent when packed refs are used
With atomic ref updates using packed refs, JGit did not fire a
RefsChangedEvent. This resulted in a user-visible regression in
EGit: the UI would not update after a "Fetch from upstream...".
Presumably it would also make Gerrit miss out on ref changes?

Strengthen the BatchRefUpdateTest by also asserting the expected
number of RefsChangedEvents, and ensure modCnt is incremented in
RefDirectory.commitPackedRefs() when refs really changed (as opposed
to some internal housekeeping operation, such as packing loose refs).

Bug: 521296
Change-Id: Ia985bda1d99f45a5f89c8020ca4845e7a66e743e
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
2017-09-07 18:47:45 -04:00
Dave Borowitz bb09e09344 Add FetchCommand#setRefSpecs(String...) variant
Much of the time the caller can specify a RefSpec succinctly using a
string, and doesn't care about calling setters. Add a convenience method
for this case, and use it where applicable in JGit core.

Change-Id: Ic3fac7fc568eee4759236a5264d2e7e5f9b9716d
2017-09-07 07:46:25 -04:00
Shawn Pearce e68a9b3ed8 ReceivePack: clear advertised .haves if application changes refs
An application can choose to invoke setAdvertisedRefs multiple times,
for example several AdvertiseRefsHook installed in a chain. Each of
these invocations populates the advertisedHaves collection with the
unique set of ObjectIds.

This can lead to a server over-advertising with ".have" lines if the
first hook pushes in a lot of references, and the second hook filters
this to a subset.  ReceivePack will advertise the unique objects from
the first hook using ".have" lines, which may lead to a huge
advertisement sent to the client.

This can also contribute to a very slow connectivity check after the
pack is parsed as ReceivePack calls markUninteresting on every commit
in advertisedHaves.  This may require expanding a lot of subtrees to
mark all trees as uninteresting as well.  On a very big repository
this can lead to a many-second stall.

Clear the advertisedHaves collection any time the refs are updated.
Add a test to verify the correct set of objects was sent.

Change-Id: I97f6998d0597251444a2e846a3ea1f461bae96f9
2017-09-07 05:39:47 -04:00
Shawn Pearce d0d15c3848 DfsGarbageCollector: support disabling conversion to reftable
When a repository is initially created using only reftable but doesn't
yet have a GC pack, the garbage collector shouldn't scan the ref
database. Support disabling the reftable conversion path.

Change-Id: Iaaf3a4375cd43760b7181c1bd10244de8b2c5d9e
2017-09-06 16:37:54 -07:00
Shawn Pearce f0a40b1933 Remove dead warning about minUpdaeIndex and maxUpdateIndex affecting refresh
DfsGarbageCollector always performs refreshes.  This warning was from
a prior iteration of the patch set and should have been removed before
the change was merged.

Change-Id: Id4750bb6c1c177e1ef040fd22912f434bbb5e992
2017-09-06 11:12:34 -07:00
David Pursehouse b23dfe1616 Merge "Remove no longer needed API problem filters" 2017-09-06 01:33:05 -04:00
Matthias Sohn 5bd9392f96 Remove no longer needed API problem filters
Change-Id: I206682a60ad9228c89efa22f8db9e72e19f17f6d
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2017-09-06 00:58:09 +02:00
David Pursehouse 72b3587d42 Stop using deprecated CmdLineException constructors
Instead of taking a String, the constructors now take a Localizable
and a variable list of format arguments.

Introduce a new Format helper class in CLIText, which implements the
Localizable interface, and use it in place of raw Strings.

Change-Id: I241eda16e242293ceb17b3c85ae5df85bd37c658
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-06 00:28:47 +02:00
David Pursehouse e7c2ae052b UntrackedFilesHandler: Fix non-localized string
Change-Id: Ida7b9ddc991515ab233763f2cb985853c9143a3c
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2017-09-06 00:28:19 +02:00
David Pursehouse 41bfc20a2c Main: Replace deprecated ExampleMode with OptionHandlerFilter
Change-Id: I1161a82269b7f093c00c9533ed8b99b7cca0a322
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-06 00:06:33 +02:00
David Pursehouse d6aec5da31 ObjectCheckerTest: Factor duplicate instances out to constants
The tests:

- testCheckBlobNotCorrupt
- testCheckBlobCorrupt

create instances of ObjectChecker that are the same.

The tests:

- testCheckBlobWithBlobObjectCheckerNotCorrupt
- testCheckBlobWithBlobObjectCheckerCorrupt

also create instances of ObjectChecker that are the same.

Factor these instances out to constants instead of creating them
in the tests.

The `checker` member is still created anew in each test, since some
of the tests change its state.

Change-Id: I2d90263829d01d208632185b1ec2f678ae1a3f4c
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-06 00:02:28 +02:00
David Pursehouse 17e849145c SubmoduleConfigTest: Add additional tests in fetchRecurseToConfigValue
Add tests for "true" and "false" matching to "YES" and "NO".

Change-Id: I58223855022871ac4b21bd34ff6a9cd00fce30a1
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-05 23:30:18 +02:00
David Pursehouse f9ac86fde2 SubmoduleConfig: Simplify #toConfigValue
Just return configValue instead of transforming name().

Change-Id: I7f94ab2e206e93d1370467e187c5e68e8f6a8836
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-05 23:30:17 +02:00
Shawn Pearce d26309c4d9 Merge changes from topic 'dfs-reftable'
* changes:
  dfs: write reftable from DfsGarbageCollector
  dfs: compact reftables during DfsPackCompactor
2017-09-05 12:39:53 -04:00
Shawn Pearce d13dfac9dc dfs: write reftable from DfsGarbageCollector
If a ReftableConfig has been supplied by the caller, write out a
reftable as a sibling of the the GC pack, alongside the heads.

To bootstrap from a non-reftable system, the refs are read from the
DfsRefDatabase if no GC reftables are present.  Its assumed the
references are fully current, and do not need to be merged with any
other reftables.  Any non-GC reftables will be pruned at the end of
the GC cycle, just like any packs that were replaced.

If a GC reftable is present, all existing reftables are compacted, and
references from DfsRefDatabase are only used to seed the packer.  Its
assumed these are consistent with each other.

Change-Id: Ie397eb58aaaefb6865c816d9b39de3ac12998019
2017-09-05 09:10:16 -07:00
Shawn Pearce d126bcc5c8 dfs: compact reftables during DfsPackCompactor
Combine intermediate, non-GC reftables when combining pack files.
This shrinks the reftable stack, improving lookup times.

Change-Id: I5dbba41806f99af5ecaff3a3119f6630e9404256
2017-09-05 09:05:08 -07:00
Matthias Sohn a0558b7094 Remove final modifier on args4j option or argument fields
Remove final field modifier since args4j does no longer allow use of
final fields [1].

[1] 6e11f89d40

Change-Id: Ib3dee10828d87d6b558c2e90387eadd9aa2ce260
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2017-09-05 00:06:38 +02:00
Thomas Wolf 11c476346d Fix Daemon.stop() to actually stop the listener thread
ServerSocket.accept() is not interruptible: a thread busy in accept()
may not react to Thread.interrupt() and may not return from accept()
via an InterruptedException. Close the socket instead to make the
daemon's listener thread terminate.

* Close the listening socket to get the listening thread to exit
  instead of interrupting it.
* Add a stopAndWait() method that stops the listening thread and
  then waits until it has indeed finished.
* Set SO_REUSE_ADDRESS on the listening socket.

Bug: 376369
Change-Id: I9d6014103e6dcb0173daea134feb44dc52c5c69a
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
2017-09-04 23:50:48 +02:00
Shawn Pearce de4e0acc30 Merge "Remove workaround for bug in Java's ReferenceQueue" 2017-09-04 14:35:58 -04:00
Matthias Sohn 39b193b6f4 Remove workaround for bug in Java's ReferenceQueue
Sun's Java 5, 6, 7 implementation had a bug [1] where a Reference can be
enqueued and dequeued twice on the same reference queue due to a race
condition within ReferenceQueue.enqueue(Reference).

This bug was fixed for Java 8 [2] hence remove the workaround.

[1] http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6837858
[2] http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/858c75eb83b5

Change-Id: I2deeb607e3d237f9f825a207533acdee305c7e73
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2017-09-04 14:44:12 +02:00
Thomas Wolf 6d27869659 Use Config.getEnum() to read the IgnoreSubmoduleMode
Doing so goes through the TypedConfigGetter and thus allows library
clients (for instance EGit) to warn about invalid configurations.

Change-Id: If1080ad90b8aff54a903d4d75637614faad6469b
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
2017-09-04 09:19:03 +02:00
Thomas Wolf 06ea633c18 Don't assume name = path in .gitmodules
While parsing .gitmodules, the name of the submodule subsection is
purely arbitrary: it frequently is the path of the submodule, but
there's no requirement for it to be. By building a map of paths to
the section name in .gitmodules, we can more accurately return
the submodule URL.

Bug: 508801
Change-Id: I8399ccada1834d4cc5d023344b97dcf8d5869b16
Also-by: Doug Kelly <dougk.ff7@gmail.com>
Signed-off-by: Doug Kelly <dougk.ff7@gmail.com>
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-04 09:19:03 +02:00
David Pursehouse 7317432c31 Upgrade Maven compiler plugins
- error_prone_core to 2.1.1
- maven-compiler-plugin to 3.6.2
- plexus-compiler-javac{-error-prone} to 2.8.2

Change-Id: I20d864c869f2d03f623ea054b6d08e7ee0eb262a
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-02 12:11:35 +09:00
David Pursehouse 4e913fcee6 Upgrade args4j to 2.33 in the bazel build
Change-Id: Ic440657e3da53b643f79fbcdde45d4e659bc166d
2017-09-01 12:51:37 +09:00
Matthias Sohn 0b75d0f0f1 Add org.apache.commons.codec 1.9.0 to target platform
This is needed to run tests in org.eclipse.jgit.http.test from Eclipse.
The change 7ac1bfc8 which added this dependency to
org.eclipse.jgit.http.test was already merged.

Restrict dependency to org.apache.commons.codec to the
version range [1.6.0,2.0.0).

CQ: 14048
Change-Id: I461a5f6bfc114757061d68992f9bc7ab38622328
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
2017-09-01 11:03:18 +09:00
David Pursehouse 8abb47b296 Merge "Fix some tests for running in bazel" 2017-08-31 22:02:21 -04:00
David Pursehouse 37ea57701b Merge "Update args4j to 2.33" 2017-08-31 22:01:04 -04:00
David Pursehouse 53deba1b4f FsckPackParser: Fix warning about int being boxed to Integer
Change-Id: I525164090e3990ce353bbb1627aaafaad2c903b6
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-09-01 00:14:32 +09:00
Thomas Wolf c91c20f36f Fix some tests for running in bazel
Some tests call out to external cgit. Those tests all failed for me
locally on Mac. Turned out that the reason was that the system git
config used by the git in the bazel run contained paths with ~/ but
somehow $HOME was not set. As a result the external git returned
with exit code 128.

Fix this by passing along $HOME explicitly. Also improve assertions
to make sure we do get the stderr of the external command in the
test log.

I hadn't noticed that until now because apparently the maven build
does pass along $HOME.

Change-Id: I7069676d5cc7b23a71e79a4866fe8acab5a405f4
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
2017-08-31 15:48:10 +02:00
David Pursehouse de5eb5e2cd FsckPackParser: Fix "Empty block should be documented" warnings
Add "Do nothing" comments, consistent with other empty methods in
the same class.

Change-Id: I27a13a402e94104af617be0e14d8982e75fa73bd
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
2017-08-31 21:40:10 +09:00