From e98de8fcdf7ad564d4088fd49ef4063a0e38793a Mon Sep 17 00:00:00 2001 From: Kevin Hanselman Date: Sun, 17 Jul 2022 21:38:37 -0400 Subject: [PATCH] misc: prepare for 0.4.0 release * install hugo, gawk in Docker image * use homebrew for auxillary packages in Docker image * regenerate getting_started.md * update benchmarks --- .github/workflows/publish-release.yaml | 2 +- .gitignore | 7 ++- Makefile | 8 +-- hugo/content/benchmarks/_index.md | 48 ++++++++--------- hugo/content/getting_started.md | 71 +++++++++++++++---------- hugo/content/getting_started_51_0.png | Bin 21076 -> 19268 bytes hugo/notebooks/getting_started.ipynb | 37 +++++++++---- integration/Dockerfile | 21 ++++---- integration/install_hyperfine_deb.sh | 23 -------- 9 files changed, 114 insertions(+), 103 deletions(-) delete mode 100755 integration/install_hyperfine_deb.sh diff --git a/.github/workflows/publish-release.yaml b/.github/workflows/publish-release.yaml index cd63fec..8f64962 100644 --- a/.github/workflows/publish-release.yaml +++ b/.github/workflows/publish-release.yaml @@ -17,7 +17,7 @@ jobs: - name: Install Hugo uses: peaceiris/actions-hugo@v2 with: - hugo-version: v0.96.0 + hugo-version: latest extended: true - name: Install Go diff --git a/.gitignore b/.gitignore index 265d4b6..1708630 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ -.tags* +/.tags* /dud -/mockery -/goreleaser -depgraph.png +/depgraph.png +/website # auto-generated hugo files # (e.g. cobra CLI and converted Jupyter notebooks) diff --git a/Makefile b/Makefile index dc65be0..5fdbd89 100644 --- a/Makefile +++ b/Makefile @@ -75,7 +75,7 @@ bench: test-short .PHONY: serve-jupyter serve-jupyter: $(GOBIN)/dud - jupyter notebook -y --ip=0.0.0.0 ./hugo/notebooks/ + jupyter notebook -y --ip=0.0.0.0 --notebook-dir ./hugo/notebooks/ # First delete stale supporting files, then convert the notebook to markdown, # and finally clear the notebook outputs. @@ -113,7 +113,7 @@ bench-docs: hugo/content/benchmarks/_index.md hugo/content/%.md: hugo/notebooks/%.md mkdir -p '$(dir $@)' - awk --lint=fatal -f ./hugo/notebooks/fix_md.awk '$<' > '$@' + gawk --lint=fatal -f ./hugo/notebooks/fix_md.awk '$<' > '$@' $(eval supporting_files = $(wildcard $(patsubst %.md,%_files,$<)/*.*)) if test -n "$(supporting_files)"; then cp -v $(supporting_files) $(dir $@); fi @@ -150,8 +150,10 @@ serve-hugo: hugo server \ --disableFastRender \ --bind 0.0.0.0 \ - --baseUrl $(shell hostname -i | xargs)/dud/ + --port 8888 \ + --baseUrl "$(shell hostname -i | xargs)/dud/" # xargs trims whitespace from the hostname +# Port 8888 matches the port exposed by the docker rule above. .PHONY: coverage coverage: diff --git a/hugo/content/benchmarks/_index.md b/hugo/content/benchmarks/_index.md index 7bcbfb0..0ed9d05 100644 --- a/hugo/content/benchmarks/_index.md +++ b/hugo/content/benchmarks/_index.md @@ -8,13 +8,13 @@ **RAM**: 16 GB -**Go version**: 1.18.3 +**Go version**: 1.18.4 -**Rclone version**: rclone v1.58.1 +**Rclone version**: rclone v1.59.0 -**Dud version**: v0.3.1-12-g3f98bdd +**Dud version**: v0.4.0 -**DVC version**: 2.11.0 (pip) +**DVC version**: 2.13.0 (pip) DVC non-default configuration: @@ -30,32 +30,32 @@ This dataset consists of four 1 GB files in a single directory. | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| -| `Dud` | 0.018 ± 0.008 | 0.010 | 0.024 | 1.00 | -| `DVC` | 0.349 ± 0.008 | 0.340 | 0.355 | 18.99 ± 7.95 | +| `Dud` | 0.023 ± 0.000 | 0.022 | 0.023 | 1.00 | +| `DVC` | 0.338 ± 0.013 | 0.326 | 0.352 | 14.92 ± 0.64 | ### commit | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| -| `Dud` | 0.665 ± 0.013 | 0.656 | 0.680 | 1.00 | -| `DVC` | 3.669 ± 0.034 | 3.645 | 3.708 | 5.52 ± 0.12 | +| `Dud` | 0.677 ± 0.030 | 0.644 | 0.701 | 1.00 | +| `DVC` | 6.483 ± 0.012 | 6.471 | 6.495 | 9.57 ± 0.42 | ### fetch | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| -| `Dud` | 11.792 ± 0.519 | 11.224 | 12.244 | 1.56 ± 0.16 | -| `DVC` | 7.562 ± 0.703 | 6.865 | 8.270 | 1.00 | +| `Dud` | 11.876 ± 1.790 | 10.703 | 13.936 | 1.53 ± 0.43 | +| `DVC` | 7.764 ± 1.813 | 5.759 | 9.288 | 1.00 | ### push | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| -| `Dud` | 11.577 ± 0.336 | 11.340 | 11.961 | 1.00 | -| `DVC` | 12.794 ± 6.961 | 8.587 | 20.829 | 1.11 ± 0.60 | +| `Dud` | 10.755 ± 0.240 | 10.538 | 11.012 | 1.52 ± 0.30 | +| `DVC` | 7.082 ± 1.393 | 5.987 | 8.650 | 1.00 | ### status | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| -| `Dud` | 0.021 ± 0.002 | 0.019 | 0.023 | 1.00 | -| `DVC` | 0.303 ± 0.011 | 0.294 | 0.315 | 14.21 ± 1.27 | +| `Dud` | 0.018 ± 0.006 | 0.011 | 0.022 | 1.00 | +| `DVC` | 0.298 ± 0.006 | 0.291 | 0.303 | 16.57 ± 5.21 | ## Many small files This dataset consists of twenty thousand 100 KB files in a single directory. @@ -64,29 +64,29 @@ This dataset consists of twenty thousand 100 KB files in a single directory. | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| -| `Dud` | 1.969 ± 0.025 | 1.941 | 1.988 | 1.00 | -| `DVC` | 11.483 ± 8.241 | 6.644 | 20.998 | 5.83 ± 4.19 | +| `Dud` | 1.262 ± 0.430 | 1.013 | 1.759 | 1.00 | +| `DVC` | 9.021 ± 0.063 | 8.983 | 9.093 | 7.15 ± 2.44 | ### commit | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| -| `Dud` | 1.583 ± 0.261 | 1.423 | 1.885 | 1.00 | -| `DVC` | 46.087 ± 6.321 | 39.050 | 51.285 | 29.11 ± 6.25 | +| `Dud` | 1.668 ± 0.030 | 1.636 | 1.695 | 1.00 | +| `DVC` | 45.934 ± 5.117 | 40.035 | 49.171 | 27.54 ± 3.11 | ### fetch | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| -| `Dud` | 7.227 ± 0.226 | 6.968 | 7.382 | 1.00 | -| `DVC` | 56.176 ± 2.097 | 53.845 | 57.910 | 7.77 ± 0.38 | +| `Dud` | 7.605 ± 0.042 | 7.563 | 7.647 | 1.00 | +| `DVC` | 57.540 ± 2.498 | 56.029 | 60.422 | 7.57 ± 0.33 | ### push | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| -| `Dud` | 5.644 ± 0.051 | 5.586 | 5.683 | 1.00 | -| `DVC` | 44.879 ± 0.184 | 44.745 | 45.089 | 7.95 ± 0.08 | +| `Dud` | 9.896 ± 4.191 | 7.438 | 14.735 | 1.00 | +| `DVC` | 44.301 ± 0.245 | 44.072 | 44.558 | 4.48 ± 1.90 | ### status | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| -| `Dud` | 0.290 ± 0.041 | 0.266 | 0.337 | 1.00 | -| `DVC` | 1.075 ± 0.018 | 1.062 | 1.095 | 3.70 ± 0.52 | +| `Dud` | 0.283 ± 0.012 | 0.270 | 0.295 | 1.00 | +| `DVC` | 1.575 ± 0.015 | 1.562 | 1.592 | 5.56 ± 0.24 | diff --git a/hugo/content/getting_started.md b/hugo/content/getting_started.md index 3ce5f80..b5717a5 100644 --- a/hugo/content/getting_started.md +++ b/hugo/content/getting_started.md @@ -20,7 +20,7 @@ As Dud tells us, `dud init` creates a `.dud` directory and some config files. Du Next, let's download the CIFAR-10 computer vision dataset. - $ curl -C- -sO https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz + $ curl -sSO 'https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz' $ du -h cifar-10-python.tar.gz 163M cifar-10-python.tar.gz @@ -53,7 +53,7 @@ Now we have a stage file, but we need to register it with Dud. We do that with ` $ dud commit committing stage cifar.yaml - cifar-10-python.tar.gz 162.60 MiB / 162.60 MiB 100% ?/s 66ms total + cifar-10-python.tar.gz 162.60 MiB / 162.60 MiB 100% ?/s 65ms total `dud commit` goes through all of our stages (in this case, just `cifar.yaml`) and copies their files/directories to the Dud cache. The cache is a directory that holds all versions of all files and directories owned by Dud. By default, the cache lives at `.dud/cache/`, but it's location is configurable (see `.dud/config.yaml`). @@ -61,16 +61,16 @@ To get a better sense of what `dud commit` did, let's look at the directory stru $ tree -an . + ├── .dud + │   ├── .gitignore + │   ├── cache + │   │   └── fe + │   │   └── 3d11c475ae0f6fec91f3cf42f9c69e87dc32ec6b44a83f8b22544666e25eea + │   ├── config.yaml + │   ├── index + │   └── rclone.conf ├── cifar-10-python.tar.gz -> .dud/cache/fe/3d11c475ae0f6fec91f3cf42f9c69e87dc32ec6b44a83f8b22544666e25eea - ├── cifar.yaml - └── .dud - ├── cache - │   └── fe - │   └── 3d11c475ae0f6fec91f3cf42f9c69e87dc32ec6b44a83f8b22544666e25eea - ├── config.yaml - ├── .gitignore - ├── index - └── rclone.conf + └── cifar.yaml 3 directories, 7 files @@ -79,9 +79,9 @@ Our tarball has been replaced with a link to a file in Dud's cache. That cached But how do we make sure we don't corrupt the cached version of the tarball? What happens if we accidentally modify our dataset? $ echo 'accidental overwrite' > cifar-10-python.tar.gz - /usr/sbin/sh: line 1: cifar-10-python.tar.gz: Permission denied + /usr/bin/sh: 1: cannot create cifar-10-python.tar.gz: Permission denied -Dud makes it very difficult to accidentally modify committed files. When Dud commits a file, it makes the link to the cache read-only. +Dud makes it difficult to accidentally modify committed files. When Dud commits a file, it makes the link to the cache read-only. The tarball isn't the only thing that's changed. Let's look at our stage file: @@ -101,6 +101,7 @@ Dud recorded the tarball's checksum in the stage file. (It also checksummed the $ dud checkout checking out stage cifar.yaml + cifar-10-python.tar.gz 1 / 1 100% ?/s 0s total $ readlink -v cifar-10-python.tar.gz .dud/cache/fe/3d11c475ae0f6fec91f3cf42f9c69e87dc32ec6b44a83f8b22544666e25eea @@ -158,6 +159,7 @@ This looks as expected. Our tarball is committed, but we haven't extracted it ye $ dud run nothing to do for stage cifar.yaml + running stage extract_cifar.yaml cifar-10-batches-py/ cifar-10-batches-py/data_batch_4 @@ -181,9 +183,10 @@ Congrats on [defusing the bomb](https://xkcd.com/1168/)! Now that we know our pi $ dud commit committing stage cifar.yaml - cifar-10-python.tar.gz up-to-date; skipping commit + cifar-10-python.tar.gz up-to-date; skipping commit + committing stage extract_cifar.yaml - cifar-10-batches-py 177.59 MiB / 177.59 MiB 100% ?/s 32ms total + cifar-10-batches-py 177.59 MiB / 177.59 MiB 100% ?/s 30ms total Notice that Dud detected that the tarball from `cifar.yaml` hasn't changed, so it knew not to waste time committing it again. @@ -202,6 +205,7 @@ Because everything is up-to-date, I bet you can guess what happens if we try re- $ dud run nothing to do for stage cifar.yaml + nothing to do for stage extract_cifar.yaml Because both of our stages are committed and up-to-date, Dud detects that there's no sense in re-extracting the tarball. Excellent! @@ -273,20 +277,25 @@ We're now ready to push our data to the remote cache! We do this with one simple $ dud push pushing stage cifar.yaml - Transferred: 162.600Mi / 162.600 MiByte, 100%, 0 Byte/s, ETA - + Gathering files 1 + Transferred: 162.600 MiB / 162.600 MiB, 100%, 0 B/s, ETA - Transferred: 1 / 1, 100% - Elapsed time: 0.4s + Elapsed time: 0.3s + Fixing permissions 1 / 1 + pushing stage extract_cifar.yaml - Transferred: 177.589Mi / 177.589 MiByte, 100%, 0 Byte/s, ETA - + Gathering files 9 + Transferred: 177.589 MiB / 177.589 MiB, 100%, 0 B/s, ETA - Transferred: 9 / 9, 100% Elapsed time: 0.2s + Fixing permissions 9 / 9 `dud push` goes through all of our stages, looks up their committed artifacts (by checksum), and instructs rclone to copy them to the remote cache. We can confirm our artifacts were copied to `/tmp/dud/cache` using rclone as well, which provides the `check` command to compare two directories (or indeed remotes): $ rclone check .dud/cache /tmp/dud/cache - 2022/01/02 16:37:52 NOTICE: Config file "/home/user/.config/rclone/rclone.conf" not found - using defaults - 2022/01/02 16:37:52 NOTICE: Local file system at /tmp/dud/cache: 0 differences found - 2022/01/02 16:37:52 NOTICE: Local file system at /tmp/dud/cache: 10 matching files + 2022/07/18 01:32:43 NOTICE: Config file "/home/user/.config/rclone/rclone.conf" not found - using defaults + 2022/07/18 01:32:45 NOTICE: Local file system at /tmp/dud/cache: 0 differences found + 2022/07/18 01:32:45 NOTICE: Local file system at /tmp/dud/cache: 10 matching files Sure enough, rclone reports that `.dud/cache` and `/tmp/dud/cache` are identical. If it were "real", our collaborators with access to `fake_remote` could now access all of the data we've committed so far! Let's pretend we are one of those collaborators, and we need to fetch the data files from the remote cache. We can do that with the aptly-named `fetch` command: @@ -294,21 +303,25 @@ Sure enough, rclone reports that `.dud/cache` and `/tmp/dud/cache` are identical $ dud fetch fetching stage cifar.yaml - Transferred: 162.600Mi / 162.600 MiByte, 100%, 0 Byte/s, ETA - + Transferred: 162.600 MiB / 162.600 MiB, 100%, 0 B/s, ETA - Transferred: 1 / 1, 100% Elapsed time: 0.3s + Fixing permissions 1 / 1 + fetching stage extract_cifar.yaml - Transferred: 974 / 974 Byte, 100%, 0 Byte/s, ETA - + Transferred: 974 B / 974 B, 100%, 0 B/s, ETA - Transferred: 1 / 1, 100% Elapsed time: 0.0s - Transferred: 177.588Mi / 177.588 MiByte, 100%, 0 Byte/s, ETA - + Fixing permissions 1 / 1 + Transferred: 177.588 MiB / 177.588 MiB, 100%, 0 B/s, ETA - Transferred: 8 / 8, 100% Elapsed time: 0.2s + Fixing permissions 8 / 8 $ rclone check .dud/cache /tmp/dud/cache - 2022/01/02 16:37:55 NOTICE: Config file "/home/user/.config/rclone/rclone.conf" not found - using defaults - 2022/01/02 16:37:55 NOTICE: Local file system at /tmp/dud/cache: 0 differences found - 2022/01/02 16:37:55 NOTICE: Local file system at /tmp/dud/cache: 10 matching files + 2022/07/18 01:32:47 NOTICE: Config file "/home/user/.config/rclone/rclone.conf" not found - using defaults + 2022/07/18 01:32:48 NOTICE: Local file system at /tmp/dud/cache: 0 differences found + 2022/07/18 01:32:48 NOTICE: Local file system at /tmp/dud/cache: 10 matching files `dud fetch` is the inverse of `dud push`; it looks up artifacts the same way `push` does (from stage files), but it copies _from_ the remote cache _to_ the local cache. @@ -322,7 +335,7 @@ The steps below gloss over installing and configuring Git. If you are new to Git First things first, let's create a Git repository for the project: - $ git init -b main + $ git init Initialized empty Git repository in /home/user/cifar/.git/ Let's take a look at our status to decide what to commit: @@ -390,7 +403,7 @@ Let's tell Git to track everything else: With everything in order, let's commit our code: $ git commit -m 'initial commit' - [main (root-commit) 5329de9] initial commit + [main (root-commit) ca689da] initial commit 7 files changed, 25 insertions(+) create mode 100644 .dud/.gitignore create mode 100644 .dud/config.yaml diff --git a/hugo/content/getting_started_51_0.png b/hugo/content/getting_started_51_0.png index 3355e82fca9e6cda5b293c52ecc01e90514f13c7..258e63d907e081c769776b5680019270f3ddb783 100644 GIT binary patch literal 19268 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 ME6Zd`8QuAR0EC13K>z>% literal 21076 zcmb`v2Q-&|A2)uHRar@)fhbBs$jA;6LZ~QvHe{6S5sD;Pm1LHrVQbj4LRP4Z%&cVZ z&GY(ppZocb=Q+3@kuDUk%hNt{wr&~uF)?Q}8RUcDhSx%qaN$JQn(9VNYc zep{Z?+%132d+={i{8(zr^Pv{MIlX#kG22##GVA2yE>qA}5PqCAev^#d4lINMBgIm0Vyi#t8@ukw(BNM( zp8fy-*Q}4?I=Z_4etxb7%oJ=py}iBd?CdIxwooi(&0d%|Bq+$Rb!(s18OGZS&!0b^ zo}LaUV5XU_7=GWisk6iF^JD-*bD1y{Py>=X)&w_CJF{~v!X zZfYSE!iv?^)pN44*v54@tArd}Tte^O{j;)uaGtY@Q_5vLHa51yA&OkVb!fCLr`w$d z4=!9~-4HKhUHhb0fYNVLQ%Q;9k=oizMQslT3`zM_{3OPvFu?r3f4wg;JUsmQ^XJ$@ zOG``mm9z8nVj?2J4<4|m`+1$ce0kV`g-juAV$(et?yUi4_4V~NQG%7a?d|P*_Ut*A zVeBY8-p~} zVe*_ExsHm;%9L7evwzN5Sa8Qq3(LxSJE%#%`tw7A<1)wYoY> zKNYuGVQPB$@?|?a@0Iy$Jdu)DfAVkN9@&;-lk)N<-=RZ~9zNtZ%GXm=N?dvQ`D&`FJwtql4+jSaU%h-e`uNSityvZqFJ3IL zsVaJBbiK4W=IK*QOUp~57qqptPn;kR{@ni2o`W#0jyQk;DcbScqu0z`QBl#sLCC+1 zk(t@a(UDEu&hYBhk@r_ycJ1EHB4}KDpn`!zR#a3}BS!4VzJ2>JVAa*tRaLKYazqXs zIKa(q@%7=MzAquW3p3~y!ZFMjV6<8thG9CeDto~(p@7*IOC@3k<>gjnd&t4wy$RloD`}H9&FK=7Wr=^*p z$ZAWBk9w3q zwUYL=-d{Wr8PV0%b@gZJ(%8rDJ$v^mD=7&J3;)b8DRG+_yxjb9^XAP1{rx>`?j9bI zsxK6l*xiDZxc16+#I4`I&1oyTN_-fIyTQQ~Li`5~e6Fp%UuRvh>Dskxr%#{8>??;#3PsnxdBcal zKH2@wuJbro_+9(?b1%m4Ok6*yu3mH0;!CDJf9~+mP*hx8-2p|~icgUzSqRZ4 zX&+SLYW(!+_K9bvtS6HiDJUqMC%Qt0Ld_YlJ*SiYs*JM9G;}=RkQ3nJ+mdjajKKad zDfSF9WA&96I(oD%)2!mPZVHCW+}zx~hOEA9U~rIU|Na*l84QHBo?fA2U%=zXJBh@i zqP>K+i3tPIif4|Myg@@jEdqNpnj@ZY`72ax<^Zxy#k+WQ?8Nd7bcuzmo)6wxu z=^q$K)6X)W?ynX!DSr3v-RjS!GS^$5&68ig9B<1BtkKec5qk2}=W-QzO!Q+ zpFVy1wWdbWr+Bm@ulf6TJtHHT{rmfu=SCtTA}aI? z*^^UJsHv$Zx=Tt53q5mdraN~Z$O=qINKoQhn`w}XEonpP$;r;{8L5jAul)20Thq2P z|IvwO4(!2Z`u1((T}4vIk7Lm{`}z6B4mExMPP=uhMV7wn?_VG7r#6%gg-0#u4RMFE z7mD29-@RMan51&?!UesvXQ|`&`OU^)j;*W?teetRWTt2(l=J56=;#FRJhJO&(_HPB zFV<_za}`GS&X_;^#7^8wNf}yMm=M3#{>fB`AS5LvSLVk=jvb>U3`@K_zkE5Vt2;AM zvXP#VvC$VQ*Ru~xi@1ev6Y?r5)c4t9!~5_E*g%;(DC%!0rZkfg7)>l{gAcX_>grnw z&Lc;TNJ|@PXr!tK7^?lcNKX)AF?H5CQ!)npJBO_8mH!$qqC_PpCp*UL85?(Xcgu;2 ze(&sDd&}l$r@&kxR3G8wv+!1dMZsM$S!YVFFr0QxX}4(6%@d2`%XvRqS}KaaVBQ3qSxX8uDB}8i>#JXk67Bw}siyv%*f`Z)EmX8sp zQ@=mE#*>ke5rl|{h?Z8v%uvJDty@F)O6~l)`=wR_J;BKogqH8@>|9q@*D2Dk)82Lc z&*VhRkM3kKRtRAu5%Okc`xdxv9`ZbUb_Y>fU!Pv%wsp%EB_*X-dRI)+&uD8q z{QeZ=@bTx*b7p2{X#TlvU0vA!$IZ$qa;vR#=4NM61*RI7Jbah)rsVbXzW@F4)@Nnx zVyi87{rly`t)pzW#+D2P(<;s=SwY3GTHS^C~ zw6wH@qwkyPD=UBQtq44=q4DPJ+qk&6%KL1anxCnJvIhkRZz9&0M+7CR_8mB&Y+$g| zQ|4b}^&~ECFC$}OMuy3S3%l?|db*vh?H&$}?yjz4$G(%8UZx-l6)X9+wl?Ax8u83{ z-wOL|Qo?Ssk%5m_E?xTLN4eGA!^P5Eh_xX>PVnHtZ;g#8-n>jfdVF(D$?CLJ6~BJ{ zDlJX?@L_(iE(Tl9)6;Y7PX2E#Ee+MxK_MYGotz#yHip~OGj5!Sa?^7E2gg4 zWr98A08!=Mh=iV#PrEvG(^PpMzOW zoH&7{hqZ`RVQg$n+zJSw0`A&GO+VWHek;4g&A)mF4kV+Vk`d@HUmooBm>H}aYDlne zfA=~uvBzg)g(FBQAC4xB1WW z!opb9{l690(9D@wS*v6!N;cMa6Xx=hFFNJa@kpnN-Q|KZ_2s~9@L zcDeo6uU?;&@qDLqgT4e%1L}l4@LJl%k4??ZQy)%ZF3>lVlA8O@>}MKIN$}3UIr0-*XkcIfKyP8RtwKf- z#a}cIAPtmcnfGP4ZM*@5v~B2GFdpx64(Z+E`jy85$hC7Zg>P#_~p91DxM#TQy`?xbFUt<#&rA3l81JPf!O8_DeCjeQ~lEy$ZYb>({T-GcPdlix$-WFcnM6k5QF?ehn|3fU z37eJQ#^OOw$M>*Gf!U8n*Vfl-@Q6Yw99qy9#fjG_cH z1IHgaYMS37qQcP{(%Xn{9UZlKB2D(My8Jn-7`HGmn4n85D3oD|0f}L2-BtQc8r=k0 zIwIF|>H3u`f6?QxSho_n*ivy)E>B}(cr{}ev7)T4tGs(eXtR;v3wbjoLo=QBZ85&_Yg?P7u&|E4 zzH9E*X~jR4i}CAnH$c_mC2v@lFsLwg(a_TyXPJKnCG36ev$59l_3IYO`0&(?tjh9o z@&|ItVd1sy?e4k3wNWiF zFc`oZb;zYHk7LQ95!~v@lU5m-efxU*t0Nm58x@Nl?2M_?JauX_E$yDB9DMNXrH7UA ziHV6|E_WW0J<7N5mc4duOh66aR{ib zodw>>cN&fe38^DyhR?XW=NA>pJW?Br@b0e)Z^Awn?k*kR_b ztE+2i*&lI09k2~t26};!kx@aEgTn@EkBcP`$DcoUGbEjRN__?B>@j0;!d7Y~vJMmq z0S5M4pUzv=Q4>zZPV}fTaFT2xLpugLgnUM_zKYIMQ_{I=@fLWBF$>T?l4lo6Q zpgSli<^~9`WM1w^+ba{|-?y)kkw{O?)$Az_#GB+SXdY%6Vq|e#Y}&H|LABoqO_(axX#+e*%_shoPbs_wN_VK z+aumI@M~&r?om{f+>OCnpe~>(YC__AKaKQ@SFbLC2t9lD?9rn~fO?O@!#6W9R0@q^ z6i}9lTRlCd92^|E5?y&WhVogiXRfoh+Ro!wn2N*z!~mJ48x^D*7u_>^5*ewB{d?!c zWvNFcfQ--S_Tpj^goRa!(eZ z5#0Ucv0``WJ12aPOd6hx;OMz|GgQWbsk^mRzrGXL0$9ksw(Qq0fP>|^tF#q(gy+h^ z1c5E_NoW)_NJy+y26N!EJj}b8U-PkVWaRL{gRCqp)Z##$C?>sEvA2v0oO?Y0gEO%G zP^DP|(o9O& zv9Y;XS556}Q&WUZ3+1*TrP3^OX(diZ_p6o>kOk1f8~)Hxl&`O?kP*;n2*Sn1W$)fN zY>qM+u!9E4NKY2f)5R+nz?85?h+8Owyax_Aim3syeEj&)1ayPoJaB-LC|x=9XLz_Q zsrZc#M>{$Q{_9@hDCjz9(qm&|7L^YUFw$hEpEEJxU}QACawQ*av6y+2LRh%zrJ?VR zH*a3Ma^<-D>?IHf=z&AcZh*dB?fJp??)5P3`c{5tD;+H@$SN9gfmO}U)2HhMRx%9p zu7i-FEL?YRP}S1vet-46$=Aox(T9#4smpVofI`xWy=wv4<0;7O|`vz`4E38_MJBv6v!X$3-f!eBR70yK%ShO+#xy@ip8Xl2Ny6d z6Ai_aE=oB$AC9Q(iEa-6r%x{cmFen60;HhKzj$F8<(B{9+OLz(w6RW1S5Gqb7YMzZ zi+}Ru31k|~2{k2U*{`c6+ONNB&^tVnC*;qZ36F?qf(+1m++V`p-X7w~+w&R4-fO!) z$j>TczW_@Dm30eJw?vKn9piIR^C`=1^+{JhnxXmd;%B-?~+b@=#bFMK8ej_3yp?$x7`!*&b!cXoY6c7w2N;XMEF;i1i+*Ev0*pHLDjkCo= z33&SHQ!xE3eFFmnEWF8&(g9{@z>7{qX4>nCHeuHLa_fs0-NjxYLNO5X02X^@4#bv} z_(1yA)!lBR%V?-u^l`}^dixP>?i{Zb=T`NCygWA`ICLTGcgD>=55FHs7#$rYGd{l% zsD}jw`V{owL4Z~fK>#%Z6uMeyxPWoHhC^clv6rl<#ivnHP(ZaZ`zU^Q=2w}}eG%#> z`}m){e?RyAwJvsMsGz|H2nqPfqr>O@>>A(Z)PMboeRgo2c^t}Xk(VKj-~EIBdpvkfKUGTBDJm*j82e>&>C!>y zdW(~0f`SMG_2WkEtpO8nR{JX^!hpJJ%(u#X7NLx+YTJ=@yW$~2%NK`+MID?JmqIC<*W zv19e`!@5g+?CtCxxX^lRta}+68eY7(n~>MivY#JqoBY|P451Q;E%@`(V^<$TBOrPp zC;;I>uvgu$86$RDUq9DFc2izDeldhd{bV6w;itk@TWpNRKsdZWcCxdx3knKyb6xEd zf*@6Z@^*o0j^Lv z-<|8&_xQ-g;^9|aFOrknT3cZaJYW;C))rO@oAArX5PYN-a`*0HfQ9>rXJ-jGm3^vy z)(L(6CpGjaChY9&(uW%upEX`OckUeeeryo>KbV~V%`KwE)CyGT9DN?zAHPp9txo5s zG+%lLN`v}AMM;@<;r+b@%H4(x?9vDM`A4UFrpo-OAtY6t-A|!FMR`xAJ7Io)9>tEz z|BR7Q+Vkh-OFz*f@$(FXey)RAXmhHU$(K-$hK2@vK-j^-moHv?|NdQxCo+oPpj`5^ zgdb-&H?v2v+)#bo4Lr7^W1iQ_{KG@K5;mL=18;j3_3%q|OIcX-p$bnC@bypI5hGuP__2h>?S3yGbc{?g@!Ur zyx`;E`RNr;f9TL_0TB*tb?4|cidFIRG{mhk(|34^=vp8i)_fo{?!yO}x5U)F)IKOA zI-h$Y3m_A{5krS-4|OiIGEUUJSFaY+W`b5Pku2H%!&R2o!Bw!n(I%{{tgc-g<%@87-Ceyz9VP7{^_ zyqHbb3=G)V%_XU?LJ)wm@%r`aG9Tb3sBFC@`EFk1T(!03@0}c|VOe~h zoJ={+$;IW@eG;n^dUen75MXtoFFkM99?)YvPLi&dp(|h=5!IH$(Y0(ZM*jZA{sj{` zfAQj0m%gE)^JmZgzyiZ`^h3B^?-R9IKiCok?uuo)y6P$MVFAk%z78cNWoGYfc}|r5 z(qF%U*L$v=0VFwl_I)K;JB=o`2`&?pl1dk7RrgO~U|erOPZm6M$k)FvNa;CTBIO8~ zp8sY6ppyWt`}&f3HYN*>yz+$seczjwid#x*1?2-uu~5^)M~^^qpsT%pec9Bs=g*(q z>jP@6)^J5n8q8VUW@KdK3|Gb2G`%=w)b-}|Ye2mtu%7t%;H{{iI+f=8`R^C~MV{Kjwybeb%E{-Z~af~CN?qNb)^jLGLvx8+n+01PlN zaD(_B8-#i@8F<3mdmSxPz_^fRNc)_Q4p8^UckgaL1K7-%sL^|{hlJxVeQRrr#hndxxzX6O5>EQP1$J}?Oglb7A<2LnwJJ$9_fXG2y*WCk)UpbC_K zbKz(JDX<9iA+diK3UI~we*0S(A#U#y(@(0&>=|-0cxej6Ctzj z(ybM=M(_Q2d6%oO-bEh*XCb_RE`Vxi%>Sa&Qw*}>0ZVbp9EY*Wr zSAPDieDdU%&z~EIod5_ybV^I*Q90l`=;bUq(rn)RZ%hmT_csx*^!`F3Bi%-1B;@aw zpFdwFCl3JI^!N9Vj?xBx`_F*5B))%tjF0axIt5Aw1`-V)?GK#w31p5p9h_mnsF9>= zJ8`Sp62%UU2p14SbV5QmsK)2dRwT{lQMOqiX^j|yKw#F^(0Ng2Q2Ozau!kpp|MvSU zPU8YhMgQ-jW?)av$Or|O3kpKepcd>DDtLiunIEj}k>O!Fi_MJ*f`0cUSOa8y);lUI zRnDAoEc2tZ6qY=A@D+^Wef!K%VzH(VPI7vsBqmM*G@2ARr)6gg3^!M%((FW%}Ucdn(5PMnR$augb=|6A6XcS6##5UFIq+<(2hygf*%z1XWDDaiu21ECJ$ zvP6`gN|-_!+Gc-0^PWA1xOwzb=!Opz#Y|%1r7isi;&`f0Y1R??fYp1ciFJ zNsiJ5mGeAeA^`c?34aR2ZvOp_nX-;YwN4@bb8`$Xefv3AZ*KRJ9do8#)qGH#;>1giVf}Hunx5pEe9kM z8JweG%{R}SJNGyyM(W0(1^^UV_nm+MdhaL9QVLZH-6 z9liAzK^__&t$5G%RX6mEs5p~CSKvTe6_rZxHd_0F2Z4cs*lEQ}0IX$yi_(&lQGl(? z&6^Ia0s31Cw^dYZvV)sHEyd&&e$R=M`=YwU|hLja3_EK%gxM{_Kv(iGl)IkP>?7XFU0x(A(hP8Z5dC7cXWQ75r>% zMHHqGehh5=|C#e)Zn&qGjOudk>{&N=_wxL`dWMFv4Zvt4yrZj*1_GcjwKaFKWImB6N!=b9C=05eCa>x$eq|fRUwXgi2 zKASH49Giv*K|zk!uP?7Hbc4TANxG!6Y^=^OM7eCUbV38G4CUZ(m5tp&G02zHsN5UdCCKE?nu{+(~1KQ{+c z2e85&;c_}2r@<5Rh{wDfr>KI4Kq)^V%;lXmDKN5FPLCrVX(zfQbw*Czb2iEPDty@9MpkD11G%m!B z0fsCsEd`eo7Zue$_z=~Jj6hfDuAK1F?#RCx92zPpDH&Y@#atFxy!+vidoooF*AAL9 z?C0c^=VSz}1JdN?;(9`|*^sm%ZUGYcCS*+@`G720tF2fEHZj_lm2fm58G3tcxM^qp zO(m{v-G$c&wh)QAxvUjJ67xa=0`wJ`uu6zq$;k)eG#hGaP}zpZz8je{L{>91GG^xF z^mPp33CRg*_t{q~y{LNsw6>kWcg*yytzRPha_0`EXG>EP>B%RL&{kkh;Q$_`^;nrd zLi9i$659KP9RQA1()1OKRQ3Qf@N9qv%$q|4QeIr)BxA~)_2;*51cA>>YP^Id=RQkA zFz(p#qbSTsv!#R~q|O>pkcx^5|6N-fq}o?0DNzp}Dm~L4?=E3j@V(*x=G7}vaq)$D zUxsa1h@h$hQnTFiiSz6fY)nF}7!DFqt*B5mHunDU<}5n8kf`WrvF$(@(r%=p+i#+@aI#`-90YSI%u|II1c+uC+iMog{+ifr4N zTItNwdbX^-o?bSVbRW~xUu$b2I8YF_9l2SlskA5WK(j-C9j{ZDz-WL@69oT}+TKq= z+h4wX=^9AG6eNlc4Cx8-f7y>RKxC*$WQ4aSo4;9v&PFu)khkS5Z_akI@3_LW~WP^KF?piC?i( z?7ipH4PU={bt?nN@qF5a9~T2qL*PW}@jVjRmQH)k)bv}FCy&Mx2Yg&plMea@Zr856 zcnty&sxaVdY)cj8s5@bwgw;e^oD)x@qk-ix_|@3bc9-ye6JrWeg4zi5;dzXsmBUwwi;R>=Y)LhkDcM*9taJg60X|rLjNAzU zyCaz|DKU{CSXDni59PQ((xU-Fi(RLlL%MnJpdL`GfY##zX2e%s!e!jBWUCk>O!n1< zUWT3jo`HiSAun%9OKwe+Il3Z@TR>oZcvun@5KiKqJ9my4WWV_E;oPZHmk-vrazj^! z*o3awn~+=Baz78xm$g#d6@oi0KYlo7uZU_TGq>5PfzdkX*yXgBX{>@ ztUwHj$@J?tZz7_iDm`AO85b>2_Ex}FvC3%!l!)~(_j(d#JKCCsyh}!U`WLB8WE`+4 zFc`%qXQGM`u$M4uBAbH+aiWkGlY{gd6%4;6z3)Mjzf zG4tQ%w8Y|}AXm`V1{aYO6@B;YSuZq1lszRbM<5vhaP-eXD>qLsFIa!swr$yH$b>xB zo2#n?t+cIJ%#0*c@aNwho->1|p(feByCsr}=;vg&*9SrIg>i=0kNFL_xVdNgtGDMG zT)Y?)A72a^ULYDFf}RWxj0h=D`9VNXaAIPDW7n>)1~elbW))TsNk)jMiA1Y-ukQb21N-Nsi~`vOgVXNe3K9<6RQ37%YziI`)FrW;w@v- z15F0hrs>CzJA1_m0vIE6h}<3t)wb z`3va*sBT)EjPUrWyqjdNAigW>b)2}Rx*weJS6f@z10ATZU=^qT=+U2Dsx6zJGYwB|Z;d$MSbesCVUkn1+x ze+r@i^c(;KgnUvB^CHSjO|upkb5T(t$mOr z#I(|tLE8tc1?|RUum)V~Dr6%VVON3ocXX_Ro0 z*8U8gEOlR+V%oJUAM~lKOF67j;Xh%e4j-2VI3Oh$v$(jsUf#;mQd3|C3UXhy7 zT2WW`GaV8V(pFJPff@wCptFEx@PFpEVuP^D&_mHr&=UYBu3f&okC6sE71}gZ3ejC5 z@|?MOdFWj91eBL3Fc|1Jt?ljDG~@*SfFAy>y?qOj`QZa#RSA@b)aBfQg3#UK<1ncp z!npcStU8e#ij8mimZXf5r7#2;c%+vvzeYSB@@_+eoa-d#XnOe}PR?67yycAO$q4uh z9yxMaUA=El$gjBnOSA0o*s6x`$|?=j+b&%LgCH~gD_8i4L}*tl^{^OaB}ibiVD+Ag zM45X7rX_bY2e}p8^;D{=;(iGUSL`PvCYP~xN);Bm;D-;H0Ue-N7qZtPX(1!b|?6-<~NN4aVV7`uqBJ zcMPt{Ua_<5!ZwFCc|Rlsj(i>i`H1-U20DcRQkFF>Z46K*MI-w6*qGPspGI$|j9r~j zE(l_>%!p-ueI3apG*UQvzuoevy6>}zkZ;AqwPQbG_O_;Ne1=43X@O^_~BYTjZp^At3|>PRw;=3C;y;(D#C#D0-cN+ z8XCE^i8C^=D{=L#xxuDFB?RA77LFbr7?_*vRjg<4QluvR&P62hfu7+@kdBR^+^ko$JgvgAFAgaDN5uF~+}0TBSr`k@>0P(G5~Ncg*C%IY8e+sJuy|ob0~G!O zF@XdF83Mru@vo106a&;D5qo;BzB&6A${V5>I2hoBK|uRP6Lg$Vmia?c6Sh^>*78e8 zp0Vr7&LmMh#0E7( z_5sOPTVBxDPlXS^zKVF^a)r@xW(?D(?K^hNLAIQqx6abXkpb*yT*biWzVgt<$}wJ$ zY_Hkc_Ux&x3cdf?+-q?XzfJPMfdPyQlnDf$u<3!u9G#s92WUT-+#!i>;s}$*=Gknl zufYhw9Ni5G3AultM3j%xiUb`vw(Wy}M9IqLTi)ak`Ilx~>a z7&!>2K%S^~nomW8Zb-IIkT3TshMl>ix*xI=J;zvsbq$me!hlk zg>??(Pdt?RIy6c^p2)v{uSf*GBmHZBK2XBbr@QW-jNQ0*_bzSskNeuJ0Y9MK!bv-K z&Uxcwe*P|jSeOwnA?HJpLF4-U`#HV_70Jku<8MAc!-~y0okV&hG~%YFzY+DOLTI99 zqPS1LkM#fxXhG;Ro-)WLT!tT=x1p|};Cll}jw?>L4~oTfA`gjD{4EmO0RA2T_{EFC zf{S41FM&N?y;9{0heE2lzX_Wi=n>E8({DEgeT}9`B=`1>&^|`wNMKm@>L%eMp?kW{ z;O?*_?zouoJ^JcKgZ2*n2X!8g3^N0N;;*Rx_yQM(7~v!QiTrSGu0%()JZEWH4xVK4 z8ArG(gr7e;tgA*OQ_{bzhh)@4qmP|v8pg4*c}zS4w>yKClNwD8eK*iJVWa_z?h2t2 z2TyQ_nBn#-I}6DZwM9#dL2L!qNVzLulmP6V20>Fj#Vi~Pv;Wf2fLZ{T>s z@F`8raTQkyF(s1SVyTMik1*VNNOIthhX|YUJ-TPcihR+qkgVhQ=7r(wxrvFU3+(|| z+n)Qdv$?p)7lyOA?o6WWD!%&Xn<4#-AJmT;S~a zP*Sqg=OI%Hd&a}bNhp4H5x1orhR3&j`(zSnHMO+B6^8d!p+e2P<&Ii%xlP$5rKgj8 zN^^mn9s6-KNjR%eKqgDxqLq8ze^3&J=NiW1#3P}4Cnf!0!I3?ddol#^t*eW^;8%qY zxc}dg5i^@dm~r?*26YJAXIASWzu(mc*ox0Hdwa-Mc;G%Y9J)!yf7#`Aa%z`xop=F; zos)q*la#hR1NU!WtpF#xUcvzxY(ZB;+bdUo*Pe!zhX@faD10A+Np=>Pkm`O^Sb$GR zjS3rKIH~6#cWxA0ffO6>V};UA4dG0X^wU-?)9*A$bYj4II!zLSnloEe>R1lF4n> zg~Y@@WM<0m)!IhUJMIx8gQp$da9bGPdtVec?vTw05pD4VY^z-LvQ|j%ZA{Wb8U5nC~%C4F4_&!uiTR`|e^HxFN7aQ8u1E+jn0P?kj#O z$yQB?LSflVsggZ+{VJ9RuItyYBPa^M{pisTB-hhYQ;|EFD4-y~9s?Xx+WVKWzfzRRq5+Qs0}p~QZvAvhGZw*KK$`@)iJqRs z*RLfzk`;@|Vx1|^-3N@o1p;{DM0u7)rSoX(K5lLi;1xIq`2__@#}E6hYM)daMXdt% zL|w-PS_awP+0hZllGyHvCs9F1z+#JzZnH00qw4#HGcDVhn7lXE7J$;w3hNO-uc)Yi zgqN#+kFzRl_h2g;33OC8>?St0Q_r*!X~l`nAvjaeoRZG@o}mp@+%0CC*gTB#v~AnA zva&KD_PvPNLacb_G>k>r+$+H2$Ej%5YOV#XOI5WBbOdfMbRi^S*h%_al2%xwn!bK3 zw!)7eJ1Q~}M8mKkva|yDjyj56j9BxDt&-eTe=0`uDFe&^g5j2-b$}bJEe$0AU10p6 z>7QhF^>&~jH(Ont0%gSd1)4xg2P$;Rn>T+Or#>GBH4U9`Wb= z++4`$6334Z4h%q^y$X)5=+(q-#ySs%ixO!jDJ9GZl%S!is;a5ElZh!iE6bq3`Pzb2 z7!Hg-pfw{M_LFw{^9^}H0CG?s1PjY^cE+K_;_)3{BKVGT(M8^C?)cT{6`N`k{;>}P zA#a|-$tAG%J{TQ11qLs?yDtlYm*dCXVKqUU<}f{)UrLGwo59>6$%Y-VDl``_{=#`* zQY*c4hi&(6a6r>s_1m1Pa&%`&l>{ip%1e5~pj`eL0ESfE7X=b5uFNCvPL`w#nl z1O6q>_SLVr=^~zmlcBu(_fv@XT1KJf61U)2*x}qqwcKa)*;>=L&|0w455 zNEE0~39#|-Rfi%ezxS;tbOO&4A0H1v0DE>Q{Za8Dc!mlp`pDts3DNWL+1UlFA7cWF1B;sfl zvRw==j#wpB{u~~lq9Ve=sJY-*I01yceu()V4&UPudP3MWqfBjVc#(X(F{Ifl@)u|1 z(1@{Y=VxcpAGgrcTMI{{$zpCD%8&9yvVpZA9*2qvo^|N(;feP5Z$m%d+N51uS2x8B zQ5ir90tsqP*8^<$Et@yvKZ+5tp)bA|YIU)|c?{(TodEerL_kc}Q8iZ!^xVUwZuq9Et9yoZI45HwIYioKM_JdViK z1M-U7ww5+D0Mf4`@{W&(=3NiYKL1XH~jvd2NguMc$*hC@#Vbzwoa4T6! z3AoL6IJkpI6UOJ?R^}!51wUwRZ^vmv*f%HyXjyXC+C_0lp{ssnb?F8nj~|WCwyb6% zh&w0BbeXnqCnF~LJ2!9Lsug$qM_t`D^pi-Q)8xcxS5d*o>@r29EulPqU28u|%N?$Y zwgv4f7yc}Qa|D5#@(Z+u;*J$*D<-vXpKoZWJ>mhZ0cQ>}SRYamz4^2IPeSx>5B?=1RS*>goVYAW`|opm-u)f|6P;WDA~bXwKkC z;et0X3Atw?^Tb27p|oq7m+hMd4l8#*oM5u|EP z(F)9fe~KFiq;+$XjLLTW!Y@;4VaLWU|FCmtrUi&|u z7UYyQiJi!y;Do@Zc!lw+Ve#>H_V$AO{L;B?^M5d^xT#DsDk2kVH2_pAQ-v3m5CnPv zLl9DO0`XWV2na#lof-LPrPm_U{xVu$Gb0UIJ44yW--m4LQ~T2y`qs6g)hPs1URt=!5?;7ccsP zdxC!V^huHXLIS!%5QV?e5h8@AiCyE+00#wj>B3afZV6yp2o0ix%nHTa{vBP-9Uc5Y z9l37vgYYa6VOx_rhc{2`-@pIp(MD{o5`RV4W>p7=NvPJ7vq*@Q2pLgC$cRa4iu(Rvu&IJ7%`qNN_8TQlqz$gEvmvXE$2WC0^!uEaw7Af?K4Ull)O z(+v3jZ+k^VT)-hs+#gH;KeH#`UH0BSJ)lM3F6ok5;q_5~X8(q#u88G8xSa1RMJ+*5 z2cL%8ww(r{*5Tc|cYC=;On1-H!&C+8g@io#hWmgn3+G_Xl`trnw^Cod=KKL z{7LP(3amt�QIab<;s1G!OgbVQ6FoEd&;+ESB~q9JvC&fkIj0y|#>cXb%y4bhoa5QbD zYryT>aF5{JD+li+BgC$?Q+V9K+bhbg-8OCV2m0}Fa|13$=%mPP<|L|&rlx?ncvMd1 z1s3dFqWpJPRzz(#i_0(M%0V z#;$G+yk{mmn<=3+1RV$km>{;?0pdn#33?vZ8u&gm9y1les_)<5RSH~z9YEhv*4EyB z{hZxFW;Gl!0Zu}mXCVS!k)dI&sSpw$k}Nb6#$q5(DDAWr*gvlzm9(hm8%jl1Yn(de zYY+Vyiz+2Kx$HDpJ#ZyK#A$BK4o9Y@@~>;Z!_g>&AH;rERo(Tdlr}Qz#KOUQ6j*od zx?aDB4549!ub^g*v&ib>#1(X5pla}-wm#R^V(ouXZSMOco1z{+wzja)MVvp1?I5G& z_sO}rWS!R_L){J<_6o1N=h***%B^!U(m=?x$iv8kt?vHyfwGdwVG%%*-18cA)f2D2+;ztpjJ zBab1+eEFApl*CJiN=tjdKSXz3Q*F3QOKE1-i(P@tGGH}{ux=KDBmPO~{)uO;zkV?o zv7xWxU0Hb9zy>}FJOX$RMj~zJFi4e-VzITDue?4~cdS|@$glU5lF`wH0J1H7c**PM zv@pE!-o;1o^qk|K(xDF@VlCv%E84DqsK4SY7Bq0q>qoSSDx_N@?5+6+xxDjOZ$wWX9B&)XruSyVyDwY%jZRR ziJ0!O--Qh>QbRLr>~@zgBh-ucO-%gx`-}a?6S37o~GoDmY0n`J8B z@%7lxlJZ^$6a@f_B!nbzr>LpYKI?@)uHZNu=|U>pZTxAJS~6q?(s@8&1V}Oko!&TH zQ_{WB{M_@-WtheNFX$3m`yaO~?^vph_p#=TTJe-kXo#w_2H7PY{RgGT!Ok~&5Nq>M zqe$|gnAq=&>&Gmttp{<40z3d>y3hP*G$)Nf)LV$T6AL-~F%xY^YCum`y?u&p$TGL| z%Xuj2ynY9qi=&&6U!)rr=I5!%eX+MluU|PH1X1qH_Vio!b}VMF3ZZshL@wD z6S0S;ynp{=%-KUaKG`FBll+uEWm{y8Igs4r!9nXFrHDFf)P6uI;}Y+^v{XPdsx!OO z&ede6HV<1G;I$iRv=#bk=b9|Hud}??yEn810TIa^3jZ?r!U(72X>RN2 z&?p~t@$sg(#g+9nn>R|2?|?d2mg3C!?+;!7%1B5of(Tv`RhvhM$+9@7&Gy{eAGTr$ zt_;oXWj?OJh~;yT89oj7=H2l_Zt)FkdIpbWTqk>=OYNbjuE{p{;UsPyNc}y!6mFaW z6P$Ce`(3!m8yE5J8E77_Qxf&~@Matw1JvjLU5d2722WC>{{Hi#pZcb7Oe5r^oX@&6 zN}Q~$CKZ$grl7F$A6xE}UwJP~+vi*W#o{E_p0}rnMT@I^9^Nk+FBu9%)eL;?l)!=b zEqAJV&r0_|v)9znfJW&k{z%PAh!vTM5M+xl?YAg0&iHYqIthQd^8P~F2SRIJ_q84u zDV<+!8A1DdY7rX-N9*`^2A@m{SG|3IXlSTfxBq%xwI$clLa0|I-S%R54^X>hmOf0? zC%-!B3DfAGuJfzBcTSk)v{kLmYy}y!4r%{0*n8NSwoQ~(1V*Nz&w;G*=+d4>WXxDMccOeFVOP%1Ev_~3|w zjc_!kispoH^y>WBMXvBF;3`)`Mv91|mg?hMVJ5_B+6b}Y#1vkHrq2&p$+WS5>56bP zQnd-*uLz>#8EcNsX0_z(H*eHNd5fMPd1Hp=RP> /etc/sudoers @@ -34,18 +31,22 @@ USER user WORKDIR /home/user -# Create a directory to mount a Docker volume to. If we don't create the mount -# point now as the user, Docker will create it with root permissions when it -# creates the container. -RUN mkdir ~/dud-data +RUN curl --fail --location https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh | bash -ENV PATH=$PATH:/home/user/go/bin:/home/user/.local/bin +ENV PATH=$PATH:/home/user/go/bin:/home/user/.local/bin:/home/linuxbrew/.linuxbrew/bin + +RUN brew install hyperfine hugo rclone RUN pip install --no-cache --user dvc notebook \ && dvc config --global core.analytics false \ && dvc config --global core.check_update false \ && dvc config --global cache.type symlink +# Create a directory to mount a Docker volume to. If we don't create the mount +# point now as the user, Docker will create it with root permissions when it +# creates the container. +RUN mkdir ~/dud-data + # Pre-download the Go dependencies for Dud. COPY --chown=user go.mod go.sum ./ diff --git a/integration/install_hyperfine_deb.sh b/integration/install_hyperfine_deb.sh deleted file mode 100755 index 140310f..0000000 --- a/integration/install_hyperfine_deb.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Only considering 64-bit -arch=amd64 -case "$(uname -m)" in - *arm*|*aarch*) - arch=arm64 - ;; -esac - -deb_url=$( - curl -sS https://api.github.com/repos/sharkdp/hyperfine/releases/latest \ - | jq -r '.assets[] | .browser_download_url' \ - | grep -v 'musl' \ - | grep "$arch\.deb$" -) - -echo "using '$deb_url'" - -curl -Lo hyperfine.deb "$deb_url" -dpkg -i hyperfine.deb -rm hyperfine.deb