diff --git a/Dockerfile.curio b/Dockerfile.curio new file mode 100644 index 000000000..45183ad17 --- /dev/null +++ b/Dockerfile.curio @@ -0,0 +1,97 @@ +##################################### +FROM golang:1.21.7-bullseye AS curio-builder +MAINTAINER Curio Development Team + +RUN apt-get update && apt-get install -y ca-certificates build-essential clang ocl-icd-opencl-dev ocl-icd-libopencl1 jq libhwloc-dev + +ENV XDG_CACHE_HOME="/tmp" + +### taken from https://github.com/rust-lang/docker-rust/blob/master/1.63.0/buster/Dockerfile +ENV RUSTUP_HOME=/usr/local/rustup \ + CARGO_HOME=/usr/local/cargo \ + PATH=/usr/local/cargo/bin:$PATH \ + RUST_VERSION=1.63.0 + +RUN set -eux; \ + dpkgArch="$(dpkg --print-architecture)"; \ + case "${dpkgArch##*-}" in \ + amd64) rustArch='x86_64-unknown-linux-gnu'; rustupSha256='5cc9ffd1026e82e7fb2eec2121ad71f4b0f044e88bca39207b3f6b769aaa799c' ;; \ + arm64) rustArch='aarch64-unknown-linux-gnu'; rustupSha256='e189948e396d47254103a49c987e7fb0e5dd8e34b200aa4481ecc4b8e41fb929' ;; \ + *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \ + esac; \ + url="https://static.rust-lang.org/rustup/archive/1.25.1/${rustArch}/rustup-init"; \ + wget "$url"; \ + echo "${rustupSha256} *rustup-init" | sha256sum -c -; \ + chmod +x rustup-init; \ + ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch}; \ + rm rustup-init; \ + chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \ + rustup --version; \ + cargo --version; \ + rustc --version; + +COPY ./ /opt/curio +WORKDIR /opt/curio + +#RUN scripts/docker-git-state-check.sh + +### make configurable filecoin-ffi build +ARG FFI_BUILD_FROM_SOURCE=0 +ENV FFI_BUILD_FROM_SOURCE=${FFI_BUILD_FROM_SOURCE} + +RUN make clean deps + +ARG RUSTFLAGS="" +ARG GOFLAGS="" + +RUN make curio-devnet + +##################################### +FROM ubuntu:22.04 AS curio-all-in-one + +RUN apt-get update && apt-get install -y dnsutils vim curl + +# Copy libraries and binaries from curio-builder +COPY --from=curio-builder /etc/ssl/certs /etc/ssl/certs +COPY --from=curio-builder /lib/*/libdl.so.2 /lib/ +COPY --from=curio-builder /lib/*/librt.so.1 /lib/ +COPY --from=curio-builder /lib/*/libgcc_s.so.1 /lib/ +COPY --from=curio-builder /lib/*/libutil.so.1 /lib/ +COPY --from=curio-builder /usr/lib/*/libltdl.so.7 /lib/ +COPY --from=curio-builder /usr/lib/*/libnuma.so.1 /lib/ +COPY --from=curio-builder /usr/lib/*/libhwloc.so.* /lib/ +COPY --from=curio-builder /usr/lib/*/libOpenCL.so.1 /lib/ + +# Setup user and OpenCL configuration +RUN useradd -r -u 532 -U fc && \ + mkdir -p /etc/OpenCL/vendors && \ + echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd + +# Environment setup +ENV FILECOIN_PARAMETER_CACHE=/var/tmp/filecoin-proof-parameters \ + LOTUS_MINER_PATH=/var/lib/lotus-miner \ + LOTUS_PATH=/var/lib/lotus \ + CURIO_REPO_PATH=/var/lib/curio + +# Copy binaries and scripts +COPY --from=curio-builder /opt/curio/lotus /usr/local/bin/ +COPY --from=curio-builder /opt/curio/lotus-seed /usr/local/bin/ +COPY --from=curio-builder /opt/curio/lotus-shed /usr/local/bin/ +COPY --from=curio-builder /opt/curio/lotus-miner /usr/local/bin/ +COPY --from=curio-builder /opt/curio/curio /usr/local/bin/ +COPY --from=curio-builder /opt/curio/sptool /usr/local/bin/ + +# Set up directories and permissions +RUN mkdir /var/tmp/filecoin-proof-parameters \ + /var/lib/lotus \ + /var/lib/lotus-miner \ + /var/lib/curio && \ + chown fc: /var/tmp/filecoin-proof-parameters /var/lib/lotus /var/lib/lotus-miner /var/lib/curio + +# Define volumes +VOLUME ["/var/tmp/filecoin-proof-parameters", "/var/lib/lotus", "/var/lib/lotus-miner", "/var/lib/curio"] + +# Expose necessary ports +EXPOSE 1234 2345 12300 4701 32100 + +CMD ["/bin/bash"] \ No newline at end of file diff --git a/Makefile b/Makefile index 83e3fd89d..f37e25750 100644 --- a/Makefile +++ b/Makefile @@ -430,3 +430,33 @@ print-%: circleci: go generate -x ./.circleci + +### Curio devnet images +curio_docker_user?=curio +curio_base_image=$(curio_docker_user)/curio-all-in-one:latest-debug +ffi_from_source?=0 + +curio-devnet: lotus lotus-miner lotus-shed lotus-seed curio sptool +.PHONY: curio-devnet + +curio_docker_build_cmd=docker build --build-arg CURIO_TEST_IMAGE=$(curio_base_image) \ + --build-arg FFI_BUILD_FROM_SOURCE=$(ffi_from_source) $(docker_args) + +docker/curio-all-in-one: + $(curio_docker_build_cmd) -f Dockerfile.curio --target curio-all-in-one \ + -t $(curio_base_image) --build-arg GOFLAGS=-tags=debug . +.PHONY: docker/curio-all-in-one + +docker/%: + cd curiosrc/docker/$* && DOCKER_BUILDKIT=1 $(curio_docker_build_cmd) -t $(curio_docker_user)/$*-dev:dev \ + --build-arg BUILD_VERSION=dev . + +docker/curio-devnet: $(lotus_build_cmd) \ + docker/curio-all-in-one docker/lotus docker/lotus-miner docker/curio docker/yugabyte +.PHONY: docker/curio-devnet + +curio-devnet/up: + rm -rf ./curiosrc/docker/data && docker compose -f ./curiosrc/docker/docker-compose.yaml up -d + +curio-devnet/down: + docker compose -f ./curiosrc/docker/docker-compose.yaml down --rmi=local && sleep 2 && rm -rf ./curiosrc/docker/data diff --git a/cmd/curio/run.go b/cmd/curio/run.go index cacacfc0f..5422a382e 100644 --- a/cmd/curio/run.go +++ b/cmd/curio/run.go @@ -35,7 +35,7 @@ var runCmd = &cli.Command{ Name: "listen", Usage: "host address and port the worker api will listen on", Value: "0.0.0.0:12300", - EnvVars: []string{"LOTUS_WORKER_LISTEN"}, + EnvVars: []string{"CURIO_LISTEN"}, }, &cli.BoolFlag{ Name: "nosync", diff --git a/curiosrc/docker/.env b/curiosrc/docker/.env new file mode 100644 index 000000000..b8cc5e80b --- /dev/null +++ b/curiosrc/docker/.env @@ -0,0 +1,5 @@ +DOCKER_USER=curio +LOTUS_IMAGE=${DOCKER_USER}/lotus-dev:dev +LOTUS_MINER_IMAGE=${DOCKER_USER}/lotus-miner-dev:dev +CURIO_IMAGE=${DOCKER_USER}/curio-dev:dev +FIL_PROOFS_PARAMETER_CACHE=${HOME}/.cache/filecoin-proof-parameters \ No newline at end of file diff --git a/curiosrc/docker/.gitignore b/curiosrc/docker/.gitignore new file mode 100644 index 000000000..1269488f7 --- /dev/null +++ b/curiosrc/docker/.gitignore @@ -0,0 +1 @@ +data diff --git a/curiosrc/docker/curio/Dockerfile b/curiosrc/docker/curio/Dockerfile new file mode 100644 index 000000000..ad969f5bc --- /dev/null +++ b/curiosrc/docker/curio/Dockerfile @@ -0,0 +1,30 @@ +ARG CURIO_TEST_IMAGE=curio/curio-all-in-one:latest +############################################################################# +FROM ${CURIO_TEST_IMAGE} + +ARG BUILD_VERSION=0.1 + +LABEL org.opencontainers.image.version=$BUILD_VERSION \ + org.opencontainers.image.authors="Curio Dev Team" \ + name="lotus-dev" \ + maintainer="Curio Dev Team" \ + vendor="Curio Dev Team" \ + version=$BUILD_VERSION \ + release=$BUILD_VERSION \ + summary="This image is used to host the curio dev service" \ + description="This image is used to host the curio dev service" + +EXPOSE 12300 4701 32100 + +VOLUME /var/tmp/filecoin-proof-parameters +VOLUME /var/lib/genesis +VOLUME /var/lib/builtin-actors + +WORKDIR /app +RUN mkdir -p /app + +COPY entrypoint.sh /app + +USER root + +ENTRYPOINT ["./entrypoint.sh"] diff --git a/curiosrc/docker/curio/entrypoint.sh b/curiosrc/docker/curio/entrypoint.sh new file mode 100755 index 000000000..12410a394 --- /dev/null +++ b/curiosrc/docker/curio/entrypoint.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +set -e +echo CURIO_REPO_PATH=$CURIO_REPO_PATH +echo Wait for lotus is ready ... +lotus wait-api +echo Wait for lotus-miner is ready ... +lotus-miner wait-api +head=0 +# Loop until the head is greater than 9 +while [[ $head -le 9 ]]; do + head=$(lotus chain list | awk '{print $1}' | awk -F':' '{print $1}' | tail -1) + if [[ $head -le 9 ]]; then + echo "Current head: $head, which is not greater than 9. Waiting..." + sleep 1 # Wait for 4 seconds before checking again + else + echo "The head is now greater than 9: $head" + fi +done + +echo All ready. Lets go +myip=`nslookup curio | grep -v "#" | grep Address | awk '{print $2}'` + +if [ ! -f $CURIO_REPO_PATH/.init.curio ]; then + + if [ ! -f $CURIO_REPO_PATH/.init.setup ]; then + export DEFAULT_WALLET=`lotus wallet default` + echo Create a new miner actor ... + lotus-shed miner create $DEFAULT_WALLET $DEFAULT_WALLET $DEFAULT_WALLET 8MiB + touch $CURIO_REPO_PATH/.init.setup + fi + + if [ ! -f $CURIO_REPO_PATH/.init.config ]; then + + newminer=`lotus state list-miners | grep -v t01000` + echo "New Miner is $newminer" + echo Initiating a new Curio cluster ... + curio config new-cluster $newminer + echo Enabling market ... + curio config get seal | sed -e $'$a\\\n BoostAdapters = ["'"$newminer"':'"$myip"':32100"]' | curio config set --title seal + touch $CURIO_REPO_PATH/.init.config + fi + + echo Starting Curio node to attach storage ... + curio run --nosync --layers seal,post,gui & + CURIO_PID=`echo $!` + until curio cli --machine $myip:12300 wait-api; do + echo "Waiting for the curio CLI to become ready..." + sleep 5 + done + curio cli --machine $myip:12300 storage attach --init --seal --store $CURIO_REPO_PATH + touch $CURIO_REPO_PATH/.init.curio + echo Stopping Curio node ... + echo Try to stop boost... + kill -15 $CURIO_PID || kill -9 $CURIO_PID + echo Done +fi + +echo Starting curio node ... +exec curio run --nosync --layers seal,post,gui + diff --git a/curiosrc/docker/docker-compose.yaml b/curiosrc/docker/docker-compose.yaml new file mode 100644 index 000000000..2cc32bc65 --- /dev/null +++ b/curiosrc/docker/docker-compose.yaml @@ -0,0 +1,101 @@ +version: '3.8' +name: curio-devnet + +x-logging: + &default-logging + options: + max-size: '20m' + max-file: '3' + driver: json-file + +networks: + curio-net: + driver: bridge + ipam: + config: + - subnet: 172.20.0.0/16 + +services: + lotus: + container_name: lotus + image: ${LOTUS_IMAGE} + init: true + ports: + - "1234:1234" + - "9090:9090" + environment: + - LOTUS_FEVM_ENABLEETHRPC=true + - LOTUS_API_LISTENADDRESS=/dns/lotus/tcp/1234/http + - LOTUS_LIBP2P_LISTENADDRESSES=/ip4/0.0.0.0/tcp/9090 + restart: unless-stopped + logging: *default-logging + volumes: + - ./data/lotus:/var/lib/lotus:rw + - ./data/genesis:/var/lib/genesis:rw + - ${FIL_PROOFS_PARAMETER_CACHE}:/var/tmp/filecoin-proof-parameters:rw + networks: + curio-net: + ipv4_address: 172.20.0.2 + + lotus-miner: + container_name: lotus-miner + image: ${LOTUS_MINER_IMAGE} + init: true + ports: + - "2345:2345" + environment: + - LOTUS_API_LISTENADDRESS=/dns/lotus-miner/tcp/2345/http + - LOTUS_API_REMOTELISTENADDRESS=lotus-miner:2345 + - LOTUS_SEALING_BATCHPRECOMMITS=false + - LOTUS_SEALING_AGGREGATECOMMITS=false + - LOTUS_SUBSYSTEMS_ENABLEMARKETS=false + - LOTUS_SEALING_WAITDEALSDELAY=20s + restart: unless-stopped + logging: *default-logging + volumes: + - ./data/lotus-miner:/var/lib/lotus-miner:rw + - ./data/lotus:/var/lib/lotus:ro + - ./data/genesis:/var/lib/genesis:ro + - ${FIL_PROOFS_PARAMETER_CACHE}:/var/tmp/filecoin-proof-parameters:rw + networks: + curio-net: + ipv4_address: 172.20.0.3 + + curio: + container_name: curio + image: ${CURIO_IMAGE} + init: true + ports: + - "12300:12300" # API + - "4701:4701" # UI + - "32100:32100" # Market + environment: + - CURIO_REPO_PATH=/var/lib/curio + - CURIO_HARMONYDB_HOSTS=yugabyte + restart: unless-stopped + logging: *default-logging + volumes: + - ./data/curio:/var/lib/curio:rw + - ./data/lotus:/var/lib/lotus:ro + - ./data/lotus-miner:/var/lib/lotus-miner:ro + - ${FIL_PROOFS_PARAMETER_CACHE}:/var/tmp/filecoin-proof-parameters:rw + networks: + curio-net: + ipv4_address: 172.20.0.4 + + yugabyte: + container_name: yugabyte + image: curio/yugabyte-dev:dev + init: true + ports: + - "5433:5433" + - "9000:9000" + - "9042:9042" + restart: unless-stopped + logging: *default-logging + volumes: + - ./data/yugabyte-data:/root/var/data + - ./data/yugabyte-logs:/root/var/logs + networks: + curio-net: + ipv4_address: 172.20.0.5 diff --git a/curiosrc/docker/lotus-miner/Dockerfile b/curiosrc/docker/lotus-miner/Dockerfile new file mode 100644 index 000000000..43a3e3fa4 --- /dev/null +++ b/curiosrc/docker/lotus-miner/Dockerfile @@ -0,0 +1,33 @@ +ARG CURIO_TEST_IMAGE=curio/curio-all-in-one:latest +############################################################################# +FROM ${CURIO_TEST_IMAGE} + +ARG BUILD_VERSION=0.1 + +LABEL org.opencontainers.image.version=$BUILD_VERSION \ + org.opencontainers.image.authors="Curio Dev Team" \ + name="lotus-miner-dev" \ + maintainer="Curio Dev Team" \ + vendor="Curio Dev Team" \ + version=$BUILD_VERSION \ + release=$BUILD_VERSION \ + summary="This image is used to host the lotus-miner dev service" \ + description="This image is used to host the lotus-miner dev service" + +EXPOSE 2345 +ENV LOTUS_SKIP_GENESIS_CHECK=_yes_ +ENV GENESIS_PATH=/var/lib/genesis +ENV SECTOR_SIZE=8388608 + +VOLUME /var/tmp/filecoin-proof-parameters +VOLUME /var/lib/genesis +VOLUME /var/lib/builtin-actors + +WORKDIR /app +RUN mkdir -p /app + +COPY entrypoint.sh /app + +USER root + +ENTRYPOINT ["./entrypoint.sh"] diff --git a/curiosrc/docker/lotus-miner/entrypoint.sh b/curiosrc/docker/lotus-miner/entrypoint.sh new file mode 100755 index 000000000..e1041ebaa --- /dev/null +++ b/curiosrc/docker/lotus-miner/entrypoint.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -e +echo Wait for lotus is ready ... +lotus wait-api +echo Lotus ready. Lets go +if [ ! -f $LOTUS_MINER_PATH/.init.miner ]; then + echo Import the genesis miner key ... + lotus wallet import --as-default $GENESIS_PATH/pre-seal-t01000.key + echo Set up the genesis miner ... + lotus-miner init --genesis-miner --actor=t01000 --sector-size=$SECTOR_SIZE --pre-sealed-sectors=$GENESIS_PATH --pre-sealed-metadata=$GENESIS_PATH/pre-seal-t01000.json --nosync + touch $LOTUS_MINER_PATH/.init.miner + echo Done +fi + +echo Starting lotus miner ... +exec lotus-miner run --nosync diff --git a/curiosrc/docker/lotus/Dockerfile b/curiosrc/docker/lotus/Dockerfile new file mode 100644 index 000000000..f73a8982b --- /dev/null +++ b/curiosrc/docker/lotus/Dockerfile @@ -0,0 +1,35 @@ +ARG CURIO_TEST_IMAGE=curio/curio-all-in-one:latest +############################################################################# +FROM ${CURIO_TEST_IMAGE} + +ARG BUILD_VERSION=0.1 + +LABEL org.opencontainers.image.version=$BUILD_VERSION \ + org.opencontainers.image.authors="Curio Dev Team" \ + name="lotus-dev" \ + maintainer="Curio Dev Team" \ + vendor="Curio Dev Team" \ + version=$BUILD_VERSION \ + release=$BUILD_VERSION \ + summary="This image is used to host the lotus dev service" \ + description="This image is used to host the lotus dev service" + +EXPOSE 1234 +EXPOSE 9090 +ENV LOTUS_SKIP_GENESIS_CHECK=_yes_ +ENV GENESIS_PATH=/var/lib/genesis +ENV SECTOR_SIZE=8388608 +ENV LOTUS_FEVM_ENABLEETHRPC=true + +VOLUME /var/tmp/filecoin-proof-parameters +VOLUME /var/lib/genesis +VOLUME /var/lib/builtin-actors + +WORKDIR /app +RUN mkdir -p /app + +COPY entrypoint.sh /app + +USER root + +ENTRYPOINT ["./entrypoint.sh"] diff --git a/curiosrc/docker/lotus/entrypoint.sh b/curiosrc/docker/lotus/entrypoint.sh new file mode 100755 index 000000000..d748c0ef9 --- /dev/null +++ b/curiosrc/docker/lotus/entrypoint.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -e +if [ ! -f $LOTUS_PATH/.init.params ]; then + echo Initializing fetch params ... + lotus fetch-params $SECTOR_SIZE + touch $LOTUS_PATH/.init.params + echo Done +fi + +if [ ! -f $LOTUS_PATH/.init.genesis ]; then + pushd $LOTUS_PATH + echo Generate root-key-1 for FIL plus + ROOT_KEY_1=`lotus-shed keyinfo new bls` + echo $ROOT_KEY_1 > rootkey-1 + echo Generate root-key-2 for FIL plus + ROOT_KEY_2=`lotus-shed keyinfo new bls` + echo $ROOT_KEY_2 > rootkey-2 + popd + + echo Initializing pre seal ... + lotus-seed --sector-dir $GENESIS_PATH pre-seal --sector-size $SECTOR_SIZE --num-sectors 1 + echo Initializing genesis ... + lotus-seed --sector-dir $GENESIS_PATH genesis new $LOTUS_PATH/localnet.json + echo Setting signers ... + lotus-seed --sector-dir $GENESIS_PATH genesis set-signers --threshold=2 --signers $ROOT_KEY_1 --signers $ROOT_KEY_2 $LOTUS_PATH/localnet.json + echo Initializing address ... + lotus-seed --sector-dir $GENESIS_PATH genesis add-miner $LOTUS_PATH/localnet.json $GENESIS_PATH/pre-seal-t01000.json + touch $LOTUS_PATH/.init.genesis + echo Done +fi + +echo Starting lotus deamon ... +exec lotus daemon --lotus-make-genesis=$LOTUS_PATH/devgen.car --genesis-template=$LOTUS_PATH/localnet.json --bootstrap=false diff --git a/curiosrc/docker/yugabyte/Dockerfile b/curiosrc/docker/yugabyte/Dockerfile new file mode 100644 index 000000000..ad830fe9e --- /dev/null +++ b/curiosrc/docker/yugabyte/Dockerfile @@ -0,0 +1,12 @@ +FROM centos:centos8 +RUN cd /etc/yum.repos.d/ +RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* +RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* +RUN yum upgrade -y +RUN yum install procps-ng wget libatomic python39 -y +RUN alternatives --set python /usr/bin/python3 +RUN arch=$(arch | sed s/aarch64/el8-aarch64/ | sed s/x86_64/linux-x86_64/) && wget "https://downloads.yugabyte.com/releases/2.20.2.0/yugabyte-2.20.2.0-b145-${arch}.tar.gz" -O /tmp/yugabyte.tar.gz +RUN tar xvfz /tmp/yugabyte.tar.gz +RUN ln -s /yugabyte-2.20.2.0 /yugabyte +RUN /yugabyte/bin/post_install.sh +CMD /yugabyte/bin/yugabyted start --daemon=false --ui=false diff --git a/curiosrc/seal/task_porep.go b/curiosrc/seal/task_porep.go index 58e307bc0..d4d744e40 100644 --- a/curiosrc/seal/task_porep.go +++ b/curiosrc/seal/task_porep.go @@ -147,12 +147,16 @@ func (p *PoRepTask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.Task } func (p *PoRepTask) TypeDetails() harmonytask.TaskTypeDetails { + gpu := 1.0 + if isDevnet { + gpu = 0 + } res := harmonytask.TaskTypeDetails{ Max: p.max, Name: "PoRep", Cost: resources.Resources{ Cpu: 1, - Gpu: 1, + Gpu: gpu, Ram: 50 << 30, // todo correct value MachineID: 0, }, diff --git a/curiosrc/seal/task_treed.go b/curiosrc/seal/task_treed.go index 7b31e12fb..fda1d1f65 100644 --- a/curiosrc/seal/task_treed.go +++ b/curiosrc/seal/task_treed.go @@ -32,6 +32,9 @@ type TreeDTask struct { } func (t *TreeDTask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + if isDevnet { + return &ids[0], nil + } if engine.Resources().Gpu > 0 { return &ids[0], nil } diff --git a/curiosrc/seal/task_treerc.go b/curiosrc/seal/task_treerc.go index 02cf0350e..7584c47ac 100644 --- a/curiosrc/seal/task_treerc.go +++ b/curiosrc/seal/task_treerc.go @@ -153,13 +153,17 @@ func (t *TreeRCTask) TypeDetails() harmonytask.TaskTypeDetails { if isDevnet { ssize = abi.SectorSize(2 << 20) } + gpu := 1.0 + if isDevnet { + gpu = 0 + } return harmonytask.TaskTypeDetails{ Max: t.max, Name: "TreeRC", Cost: resources.Resources{ Cpu: 1, - Gpu: 1, + Gpu: gpu, Ram: 8 << 30, Storage: t.sc.Storage(t.taskToSector, storiface.FTSealed, storiface.FTCache, ssize, storiface.PathSealing, paths.MinFreeStoragePercentage), }, diff --git a/curiosrc/web/hapi/web/root.gohtml b/curiosrc/web/hapi/web/root.gohtml index 8fe3ba71a..3766158a3 100644 --- a/curiosrc/web/hapi/web/root.gohtml +++ b/curiosrc/web/hapi/web/root.gohtml @@ -4,8 +4,9 @@