Commit Graph

56521 Commits

Author SHA1 Message Date
svcscm
550cb0fc80 Updating submodules
Summary:
GitHub commits:

cb8ac18a5b
940c095e23
e811afb890
4fc216649d
e859d78c6d
1e67f8003c
dadacb3e05

Reviewed By: wittgenst

fbshipit-source-id: 7a188cc3ffb7a3f31558107c42b2aaa1cebaf01a
2020-03-20 16:59:24 -07:00
Arun Kulshreshtha
d179270444 edenapi: remove unused log fields
Summary:
Originally, we wanted to log EdenAPI batch sizes to Scuba in order to A/B test the effect of batch size on fetching speed. It turns out that the original arbitrary choice of 1000 works pretty well, so there isn't really a need to log this to Scuba anymore.

In addition to removing these fields, this diff moves the "http_enabled" column to be logged from the config by the wrapper instead of being manually logged by hg.

Reviewed By: quark-zju

Differential Revision: D20568104

fbshipit-source-id: 1e113489d005e93e6283f7e4a439b1c78b6f0fb9
2020-03-20 16:53:43 -07:00
generatedunixname89002005287564
090b4cdc17 eden/cli/debug_posix.py
Reviewed By: simpkins

Differential Revision: D20415405

fbshipit-source-id: d0a9a281beb929a7c58d5d584a35b80dc318d376
2020-03-20 16:34:34 -07:00
Adam Simpkins
f89bfe7670 fix a type-checking error
Summary:
Fix code in `memcommit/serialization.py` that was assigning a `str` to a
`bytes` variable.

Reviewed By: singhsrb

Differential Revision: D20564418

fbshipit-source-id: 578ebe9d2b8823353d5a4727f6ea888678ca881f
2020-03-20 15:32:51 -07:00
Wez Furlong
0be26944f7 eden: fix some unreferenced variable warnings on Windows
Summary: the exception object is unused in each of these catch blocks.

Reviewed By: chadaustin

Differential Revision: D20562251

fbshipit-source-id: 12502429e47f5603b73cfc88b10dda0db5daeb93
2020-03-20 14:00:33 -07:00
Wez Furlong
0a6aa21d77 eden: fix multiply defined symbols issue with ImportPriority
Summary:
This is a rough pass that resolves a linker issue on MSVC by
switching to inline static member functions.

Reviewed By: chadaustin

Differential Revision: D20529163

fbshipit-source-id: 578ed440758c685091d3e039e261638e027db17a
2020-03-20 10:56:08 -07:00
Wez Furlong
9972789892 eden: make bitfield usage in DirEntry.h more portable
Summary:
the type of `mode_t` that we were using for this on Windows
recently changed in the folly portability layer, resulting in a padding/alignment
problem that breaks our assumption at the size of this struct.

I don't believe that we were using bitfields correctly here; in my experience
all of the members must have the same type in order to get packed in the
struct correctly, because the standard doesn't define much in the way
of bitfield behavior beyond the syntax.

This commit uses an unsigned integer type for all of the bitfields
and takes a stab at using a cast when returning the actual mode
member for macOS.  This may not be right; I'm just throwing up this
diff first in order to be able to get it on a mac machine.

Reviewed By: simpkins

Differential Revision: D20529006

fbshipit-source-id: e9362bf263fab03d51cc8aa97f94f00806650618
2020-03-20 10:56:07 -07:00
Adam Simpkins
46767d9723 add type annotations for a few more edenscmnative modules
Summary:
There isn't really much to annotate here, but this lets us eliminate a couple
`pyre-fixme` comments about not being able to find these modules during type
checkign.

Reviewed By: singhsrb

Differential Revision: D20550267

fbshipit-source-id: 271f8406890787c0613294a9047365fdebcdeda1
2020-03-20 10:41:32 -07:00
Adam Simpkins
66f7b2e813 remove some duplicate .pyx files
Summary:
These were copied into the `edenscmnative` directory in D15798642, but never
removed from their original location.

Reviewed By: singhsrb

Differential Revision: D20550268

fbshipit-source-id: dadce279f1717a66ece86376bd51179b8669cc8a
2020-03-20 10:41:31 -07:00
svcscm
1a7ac863ac Updating submodules
Summary:
GitHub commits:

966f3fab23
e838f6323a

Reviewed By: wittgenst

fbshipit-source-id: c77aacda7db26dad5b6591ade774614c5a4c961b
2020-03-20 09:44:53 -07:00
Lukas Piatkowski
c3e8dfd31a rust-shed: add hostname crate to the shed
Reviewed By: StanislavGlebik

Differential Revision: D20468997

fbshipit-source-id: 25240c38812f848c9b152e648a491fdfc645ee56
2020-03-20 08:56:12 -07:00
Lukas Piatkowski
12f639159e cargo_from_buck: get rid of signatures in generated Cargo.toml files
Summary: The signatures were used by the linter to warn if the files require regenerating, since the linter now regenerates the files regardless of the signature it is no longer needed to sign the files.

Reviewed By: krallin

Differential Revision: D20467745

fbshipit-source-id: aff2643f80939d5693e7a30abf07484c9060796f
2020-03-20 08:56:11 -07:00
Mark Thomas
12e94a142a newdoc: Add mutation and visibility documentation
Summary: Add Mercurial Developer Guide documentation for Mutation and Visibility.

Reviewed By: quark-zju

Differential Revision: D20534279

fbshipit-source-id: 3f06de79b5efe3903f4d1baf76fa2030ee58e7f4
2020-03-20 04:09:32 -07:00
Kostia Balytskyi
21f70ac6d1 mononoke: do not log JSON field extra_contents to scuba, log columns instead
Reviewed By: farnz

Differential Revision: D20500084

fbshipit-source-id: 296747780298fe81e4cca4cdb8af05548ba80169
2020-03-20 02:48:03 -07:00
svcscm
aab18f1a6f Updating submodules
Summary:
GitHub commits:

4a3af6ba64
d1bd44bd09
201f98fdaa
f2e15611b5
b8340d2e1c
a52a6bd7a4
33b52209d7
dcc6c04da9

Reviewed By: wittgenst

fbshipit-source-id: f7202c64d1c0b8ab724bc25eeaa6aa086954af67
2020-03-20 02:48:03 -07:00
svcscm
61ff1954cb Updating submodules
Summary:
GitHub commits:

8294c5e7d4
9325cacc44
704e6ae332
e7b465ec55
7b15dda248
c25ae7df32
0e1e875a72
fc11f4c748
711e303ee7

Reviewed By: wittgenst

fbshipit-source-id: 27a15914b1b92e82581636a1d0a4917f1dd23bed
2020-03-19 21:18:36 -07:00
Shrikrishna Khare
50538d7a41 Script to build OpenNSA kernel modules
Summary:
OpenNSA has prebuilt SDK but kernel modules have to be built from sources. Add
a utility script to build and extend packaging script.

In future, we can consider folding this build into fbcode_builder itself.

Differential Revision: D20549883

fbshipit-source-id: f9475b7e0223e9f357117d7d7d27df8904fa1d73
2020-03-19 20:23:24 -07:00
Adam Simpkins
2e0aaa3ee0 fix signal delivery when using edenfsctl start --foreground
Summary:
This fixes handling of Ctrl-C when using `edenfsctl start --foreground` or
`edenfsctl start --gdb`.

The changes in D19861810 to make `exec_daemon()` fork and exec instead of
simply calling exec accidentally broke this.  While it attempted to forward
SIGINT to the child process, in practice this would normally fail in
development environments.  In development environments EdenFS is normally
started using `sudo`, and the CLI does not have permissions to send signals to
this child process since it is running with elevated privileges.  As a result
on Ctrl-C the foreground `edenfsctl` process would die since it did not handle
the error attempting to forward the signal, and the actual EdenFS process
would continue running.

The main goal of D19861810 was to allow telemetry logging of success or
failure on restart.  This changes the `edenfsctl restart` code to use the
existing `start_daemon()` function, and reverts the old behavior of
`exec_daemon()` to use `execve()` to replace the current process.

Reviewed By: genevievehelsel

Differential Revision: D20355252

fbshipit-source-id: 5e61f70e8b411ee023eee6fe06e0cd641f732631
2020-03-19 20:10:06 -07:00
Adam Simpkins
91f4fbc5b7 improve behavior of stopping EdenFS in the integration tests
Summary:
Fix `EdenFS.shutdown()` to call `edenfsctl stop` with a timeout of 0 seconds,
telling it not to wait for EdenFS to exit.  This code then performs its own
wait with a timeout.

Previously the code called `edenfsctl stop` asking it to wait for EdenFS to
exit with a 30 second timeout.  However, since the integration test could be
the immediate parent process of EdenFS the `edenfs` process may not actually
go away until the test called `wait()` on this process, which wouldn't happen
until `edenfsctl stop` returned.  This only caused problems for cases where
the test could run `edenfs` directly without needing to run it through `sudo`:
when run through `sudo` the edenfs process would get cleaned up since `sudo`
was the immediate parent and it would wait on the process.

Reviewed By: genevievehelsel

Differential Revision: D20434081

fbshipit-source-id: 513fd2ebb5fc24a54c546a76e94827c81a4ab754
2020-03-19 20:10:06 -07:00
Steven Troxler
41378d4f37 Deprecate rust-crypto in eden/monanoke/derived_data
Summary:
The rust-crypto library appears to be unmaintained, switching
 - `crypto::digest::Digest` to `digest::Digest`
 - `crypto::sha1::Sha1` to `sha1::Sha1`
 - `crypto::sha2::Sha256` to `sha2::Sha256`

Reviewed By: jsgf

Differential Revision: D20456962

fbshipit-source-id: 2e3406dedba05245265d96b480c35ba2421aa3fd
2020-03-19 19:00:06 -07:00
svcscm
378d03858f Updating submodules
Summary:
GitHub commits:

9b74a85c6a
ecf3417784
eca93a4502
a795f497ea
efd1abfa80
d5f8bc5505
34b8d7c8ab
6230082450
233dca40b4
5dd79a370a

Reviewed By: wittgenst

fbshipit-source-id: b7eea2087093403480b489f2f4ac5007cf0413de
2020-03-19 18:26:39 -07:00
Koray Polat
c993337227 Update fmt from 5.3.0 to 6.1.1
Summary: Updated fmt version to be on par with buck build. It was causing inconsistencies.

Reviewed By: vitaut

Differential Revision: D20528011

fbshipit-source-id: d9e04ed2c28b839eaeff24120162c4db4732fa55
2020-03-19 17:54:15 -07:00
Steven Troxler
13fa9a5f1f Deprecate rust-crypto in eden/mononoke/filestore
Summary:
The rust-crypto library appears to be unmaintained, switching
 - `crypto::digest::Digest` to `digest::Digest`
 - `crypto::sha1::Sha1` to `sha1::Sha1`
 - `crypto::sha2::Sha256` to `sha2::Sha256`

Reviewed By: jsgf

Differential Revision: D20456840

fbshipit-source-id: 90cc031ec5402b60b6eb06a301a3733bd92bbc69
2020-03-19 17:25:44 -07:00
Xavier Deguillard
bb68ce52ff remotefilelog: provide fast path for cmp, size and isbinary
Summary: For LFS blobs, these can be obtained very easily by querying the ContentStore.

Reviewed By: DurhamG

Differential Revision: D20504235

fbshipit-source-id: 937ef20184d6524b1355565f9ab81e40b56d7ab0
2020-03-19 16:36:41 -07:00
Steven Troxler
8e99cdbd34 Asyncify the loop in statistics_collector
Summary:
This diff asyncifies the `loop_fn` call in `run_statistics`.

I was unable to find an existing example of asyncifying an infinite
loop - my solution requires allowing the `Ok` around my `loop`
to be unreachable via the `#[allow(unreachable_code)]` annotation. There may be
a better solution.

We also swap out the `tokio-timer` dependency, which uses old-style
futures, for current-version `tokio` so we can use the new-style future
`tokio::time::delay_for`.

Reviewed By: farnz

Differential Revision: D20527530

fbshipit-source-id: 90d30ec9465402d06d3b4b30c1bbd5e340ac94b6
2020-03-19 15:39:18 -07:00
Xavier Deguillard
68edce4365 lfs: allow the LFS remote to be a local directory
Summary:
This is only intended for Mercurial .t tests and not in any production
environment.

Reviewed By: DurhamG

Differential Revision: D20504236

fbshipit-source-id: 618e17631b73afa650875cb7217ba7c55fb9f737
2020-03-19 14:36:19 -07:00
Xavier Deguillard
9995e95e06 pyrevisionstore: expose ContentDataStore methods to Python
Summary:
This will enables the fast-path for comparing LFS blobs without reading the
entire blob.

Reviewed By: DurhamG

Differential Revision: D20504233

fbshipit-source-id: 446cec57fba77e02cc7070203bd759d341fc01ab
2020-03-19 14:36:19 -07:00
Xavier Deguillard
092cfcec7d revisionstore: add a ContentDataStore trait
Summary:
For now, this is only used for LFS, as this is the only store that can
correctly answer both.

This API will be exposed to Python to be able to have cheap filectx comparison,
and other use cases.

Reviewed By: DurhamG

Differential Revision: D20504234

fbshipit-source-id: 0edb912ce479eb469d679b7df39ba80fceef05f2
2020-03-19 14:36:18 -07:00
Xavier Deguillard
632bd53a02 revisionstore: add a LFS remote store
Summary:
This enables fetching blobs from the LFS server. For now, this is limited to
fetching them, but the protocol specify ways to also upload. That second part
will matter for commit cloud and when pushing code to the server.

One caveat to this code is that the LFS server is not mocked in tests, and thus
requests are done directly to the server. I chose very small blobs to limit the
disruption to the server, by setting a test specific user-agent, we should be
able to monitor traffic due to tests and potentially rate limit it.

Reviewed By: DurhamG

Differential Revision: D20445628

fbshipit-source-id: beb3acb3f69dd27b54f8df7ccb95b04192deca30
2020-03-19 14:36:18 -07:00
svcscm
3a0c35a7b6 Updating submodules
Summary:
GitHub commits:

368451edbe
8c6cf3a291
e10553f2a6
17fecc692a

Reviewed By: wittgenst

fbshipit-source-id: bfce0c3da761dfcdc10dd0982269a35feaffcc16
2020-03-19 12:59:35 -07:00
Stanislau Hlebik
757fab414c mononoke: prefix ods key
Summary: Most of our keys are prefixed, let's prefix this as well

Differential Revision: D20536231

fbshipit-source-id: 9a2ffecfc7de46d109a9fba2444212735cacbebf
2020-03-19 12:28:54 -07:00
Aida Getoeva
4815913d9e mononoke/scs: use changeset info in changeset context
Summary:
Changeset info is less expensive to load than Bonsai, so we would like to use it in SCS as a source of commit info if possible.

This diff adds a method into the Repo object that checks `changeset_info` derivation is enabled for the repo in the `DerivedDataConfig`. If derivation is enabled, then SCS derives this info otherwise it awaits for bonsai and converts it into the changeset info. The bonsai fields aren't copied but moved to the `ChangesetInfo`.

Reviewed By: StanislavGlebik

Differential Revision: D20282403

fbshipit-source-id: b8ddad50dcd5c6de109728b2081ca5a13f440988
2020-03-19 12:16:40 -07:00
svcscm
17b95307b6 Updating submodules
Summary:
GitHub commits:

ced74147c3
33849b670b
63bf7655e4
d70eb504b7
442404558a
fbf509dcb5

Reviewed By: wittgenst

fbshipit-source-id: a3eb6b95a915e85e88719ca5870e5c34f4dfed7f
2020-03-19 11:17:05 -07:00
Steven Troxler
882c2c04d6 Push compat one layer down in statistics_collector
Summary:
This diff asyncifies the outermost layer of `statistics_collector`,
so that `main` doesn't need a `compat`, by extracting the
futures portion of `main` into an async function `run_statistics`
and using async futures for the outermost layers of `run_statistics`
logic (everything outside the `loop_fn` call)

Reviewed By: farnz

Differential Revision: D20527529

fbshipit-source-id: 00ad9033584360f45715719f2636dcfac1926004
2020-03-19 10:55:11 -07:00
Jun Wu
6ffdcebadf tracing: write some blackbox events as tracing events
Summary:
This is the start of migrating blackbox events to tracing events. The
motivation is to have a single data source for log processing (for simplicity)
and the tracing data seems a better fit, since it can represent a tree of
spans, instead of just a flat list. Eventually blackbox might be mostly
a wrapper for tracing data, with some minimal support for logging some indexed
events.

Reviewed By: DurhamG

Differential Revision: D19797710

fbshipit-source-id: 034f17fb5552242b60e759559a202fd26061f1f1
2020-03-19 10:23:24 -07:00
Jun Wu
609330486e smartlog: optimize --all with narrow-heads
Summary:
The `all()` revset is much slower with narrow-heads for correctness. Use an
alternative that is fast.

Reviewed By: markbt

Differential Revision: D20528063

fbshipit-source-id: c8ae35e67e60407406ca81d67878278392626e9a
2020-03-19 10:05:28 -07:00
Kostia Balytskyi
c058e72f48 mononoke: migrate filestore's rechunk API to async/await
Summary: A little step towards asyncifying the filestore. This is just mechanical, without removing clones. TBD: add a diff, which starts to actually use the benefits of new futures.

Reviewed By: farnz

Differential Revision: D20534272

fbshipit-source-id: a038e6f22b666f3f2c9782ee25c0c2582ddced6c
2020-03-19 09:24:30 -07:00
James Crooks
d2f5062182 Move fbcode/eden/mononoke/cmds/populate_healer.rs to async diff4
Summary:
Last diff. Fully migrates all of populate_healer.rs to async/await
futures.  This makes `put_resume_state()` async, with one `.compat()` call needed
for dealing with `manifold.put()`. Also changes `populate_healer_queue()` to
use the new async `put_resume_state()`. At this point, the only `.compat()`
calls remaining are for interop with ThrifManifoldBlob's interface, and can be
removed once ThriftManifoldBlob is updated or provides async replacement
functions. All explicit old-style future creation sites have been removed in
favor of 0.3 futures.

Reviewed By: krallin

Differential Revision: D20479264

fbshipit-source-id: baad535da3fc8b621d72de567454bcd64862977a
2020-03-19 09:16:25 -07:00
James Crooks
7ecd298e7b Move fbcode/eden/mononoke/cmds/populate_healer.rs to async diff3
Summary: Moves to using 0.3 futures inside of the populate_healer_queue() function. This leaves only one remaining source of `.compat()` calls inside of populate_healer.rs, which will be removed in the following diff.

Reviewed By: krallin

Differential Revision: D20473834

fbshipit-source-id: 6d76e0673b875fba15611a495d86b9ca0b1695db
2020-03-19 09:16:25 -07:00
Stanislau Hlebik
107d049cf9 mononoke: fix some of the suggestions from clippy
Summary:
Run buck build -c rust.clippy=true eden/mononoke/:mononoke#check and fix some
of them manually. I wasn't able to make rustfix to work - will try to see
what's wrong and run it.

The suggestions looks non-controversial

Reviewed By: krallin

Differential Revision: D20520123

fbshipit-source-id: 25d4eb493f2363c5aa77bdb3876da4378483f6cb
2020-03-19 06:06:10 -07:00
Kostia Balytskyi
95b17f1d4d mononole: migrate filestore's test_api to fbinit::compat_test
Summary: This makes thigs a little more readable.

Reviewed By: krallin

Differential Revision: D20515645

fbshipit-source-id: ae04e18b0f415353431a995ae22844f6e301780c
2020-03-19 05:20:45 -07:00
Kostia Balytskyi
04406a7e3c mononoke: fix a typo
Reviewed By: krallin

Differential Revision: D20470561

fbshipit-source-id: 3f8072570dc652df952f4e6c79b07dff3fa5fe2b
2020-03-19 05:20:44 -07:00
Kostia Balytskyi
96cba6e4dc mononoke: introduce rechunk_if_needed fn to the filestore
Summary:
This is going to be used in D20469131, but in a nutshell the idea is to
perform as many checks as possible before actually doing the rechunking.
This way we can avoid churning through the entire blobstore.

Reviewed By: krallin

Differential Revision: D20491189

fbshipit-source-id: 4f7c2a8e02c890db789d25aa819b5c91d08ea7be
2020-03-19 05:20:44 -07:00
Thomas Orozco
01c05f5925 mononoke/hgproto: zero copy-validation (120x faster on 70MiB Gettreepack)
Summary:
The way decoders work in Tokio is that they get repeatedly presented whatever
is on the wire right now, and they have to report whether the data being
presented is valid and they'd like to consume it (and otherwise expect Tokio to
provide more data).

It follows that decoders have to be pretty fast, because they will be presented
a bunch of data a bunch of times. Unfortunately, it turns out our SSH Protocol
decoder is everything but.

This hadn't really been a problem until now, because we had ad-hoc decoding for
things like Getpack that might have a large number of parameters, but for now
the designated nodes implementation is decoded in one go through the existing
Gettreepack decoder, so it is important ot make the parsing fast (not to
mention, right now, we buffer the entire request for Getpack as well ... so
maybe we could actually update it to this too!).

Unfortunately, as I mentioned, right now the parsing wasn't fast. The reason is
because it copies parameters to a `Vec<u8>` while it decodes them. So, if
you start decoding and copying, say, 50MB of arguments, before you find out
you're missing a few more bytes, then you just copied 50MB that you need to
throw away.

Unfortunately, the buffer size is 8KiB, so if we say "I need more data", we get
8KiB. That means that if we want to decode a 70MiB request, we're going to make
8960 ( = 70 * 1024 / 8) copies of the data (the first 8KiB, then the first 16,
and so on), which effectively means we are going to copy and throw away ~612GiB
of data (8960 * 70 / 2). That's a lot of work, and indeed it is slow.

Fortunately, our implementation is really close to doing the right thing. Since
everything is length delimited, we can parse pretty quick if we don't make
copies: all we need to do is read the first length, skip ahead, read the second
length, and so on.

This is what this patch does: it extracts the parsing into something that
operates over slices. Then, **assuming the parsing is successful** (and that is
the operative part here), it does the conversion to an owned Vec<u8>.

In O(X) terms .. this means the old parsing is O(N^2) and the new one is O(N).

I actually think we could take this one step further and do the conversion even
later (once we want to start decoding), but for now this is more than fast
enough.

After this patch, it takes < 1 second to parse a 70MiB Gettreepack request.
Before this patch, it took over 2 minutes (which is 3 times longer than it
takes to actually service it).

PS: While in there, I also moved the `gettreepack_directories` function to a
place that makes more sense, which I had introduced earlier in the wrong place
(`parse_star`, `parse_kv` and `params` are a group of things that go together,
it's a bit clowny to have `gettreepack_directories` in the middle of them!).

Reviewed By: kulshrax

Differential Revision: D20517072

fbshipit-source-id: 85b10e82768bf14530a1ddadff8f61a28fdcbcbe
2020-03-19 04:31:23 -07:00
svcscm
e69973e62d Updating submodules
Summary:
GitHub commits:

1b37794ff8

Reviewed By: wittgenst

fbshipit-source-id: ff8d72e6e8b3ff68a8c37ca867fc3236f4d18917
2020-03-19 04:31:22 -07:00
svcscm
d118dc85d4 Updating submodules
Summary:
GitHub commits:

ef157d4f41
d462322b1e
86727df12a

Reviewed By: wittgenst

fbshipit-source-id: 9fd53212430404c12ba07c954d3c142828d4167b
2020-03-19 01:58:42 -07:00
Arun Kulshreshtha
431a9c02b5 mercurial_types: rename Node to HgId
Summary: The `Node` type in Mercurial's Rust code was renamed to `HgId`, with an alias to `Node` to keep older code building. Let's rename the usages in Mononoke to `HgId` to reduce ambiguity and keep the terminology consistent with Mercurial.

Reviewed By: StanislavGlebik

Differential Revision: D20460543

fbshipit-source-id: f6d8e3aef42743370323cde79ec10b21de956313
2020-03-19 01:43:12 -07:00
Stanislau Hlebik
bf866d3a21 mononoke: log how many filenodes were inserted
Summary:
It was (or rather, might have been) useful during debugging of S197766.
Let's now count both "count" (i.e. how often the method was called)
and count how many filenodes were inserted

Reviewed By: krallin

Differential Revision: D20519701

fbshipit-source-id: f19f413171fcbcc300deffbe29baa946ebbe8dce
2020-03-19 01:22:23 -07:00
svcscm
ad42aee4cc Updating submodules
Summary:
GitHub commits:

7be4309f89
b331064b7c
1fb58e14c7

Reviewed By: wittgenst

fbshipit-source-id: a7a787dda67ed01744c7e76eeb6b94ab18c5a849
2020-03-19 01:22:23 -07:00
svcscm
cd854340a4 Updating submodules
Summary:
GitHub commits:

16e810d342
42e49bb262

Reviewed By: zpao

fbshipit-source-id: ed10e85c6f659b488aff2c7fbf21b0a34657cc18
2020-03-18 21:43:25 -07:00