pax_global_header00006660000000000000000000000064145337423720014524gustar00rootroot0000000000000052 comment=28cd41e73158295e0698dea8f07b5860768a8ec1 nydus-snapshotter-0.13.4/000077500000000000000000000000001453374237200153235ustar00rootroot00000000000000nydus-snapshotter-0.13.4/.github/000077500000000000000000000000001453374237200166635ustar00rootroot00000000000000nydus-snapshotter-0.13.4/.github/codecov.yml000066400000000000000000000012161453374237200210300ustar00rootroot00000000000000coverage: status: patch: off project: default: enabled: yes target: auto # auto compares coverage to the previous base commit # adjust accordingly based on how flaky your tests are # this allows a 0.3% drop from the previous base commit coverage threshold: 0.3% comment: layout: "reach, diff, flags, files" behavior: default require_changes: true # if true: only post the comment if coverage changes codecov: require_ci_to_pass: false notify: wait_for_ci: true # When modifying this file, please validate using # curl -X POST --data-binary @codecov.yml https://codecov.io/validate nydus-snapshotter-0.13.4/.github/workflows/000077500000000000000000000000001453374237200207205ustar00rootroot00000000000000nydus-snapshotter-0.13.4/.github/workflows/ci.yml000066400000000000000000000102541453374237200220400ustar00rootroot00000000000000name: CI on: push: branches: ["**", "stable/**"] pull_request: branches: ["**", "stable/**"] env: CARGO_TERM_COLOR: always jobs: build: name: Build and Lint timeout-minutes: 10 runs-on: ubuntu-latest steps: - name: Set up Go uses: actions/setup-go@v3 with: go-version: "1.20.1" - name: Check out code uses: actions/checkout@v3 - name: cache go mod uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }} restore-keys: | ${{ runner.os }}-go - name: Build run: | go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.2 export PATH=$PATH:$(go env GOPATH)/bin make make test make check build-optimizer: name: Build optimizer timeout-minutes: 10 runs-on: ubuntu-latest steps: - name: Set up Go uses: actions/setup-go@v3 with: go-version: "1.20.1" - name: Check out code uses: actions/checkout@v3 - name: cache go mod uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }} restore-keys: | ${{ runner.os }}-go - name: Build run: | go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.2 export PATH=$PATH:$(go env GOPATH)/bin rustup component add rustfmt clippy make build-optimizer smoke: name: Smoke timeout-minutes: 10 runs-on: ubuntu-latest steps: - name: Set up Go uses: actions/setup-go@v3 with: go-version: "1.19.6" - name: Check out code uses: actions/checkout@v3 - name: cache go mod uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }} restore-keys: | ${{ runner.os }}-go - name: Set up containerd uses: crazy-max/ghaction-setup-containerd@v2 - name: Build run: | # Download nydus components NYDUS_VER=v$(curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -s "https://api.github.com/repos/dragonflyoss/nydus/releases/latest" | jq -r .tag_name | sed 's/^v//') wget https://github.com/dragonflyoss/nydus/releases/download/$NYDUS_VER/nydus-static-$NYDUS_VER-linux-amd64.tgz tar xzvf nydus-static-$NYDUS_VER-linux-amd64.tgz mkdir -p /usr/bin sudo mv nydus-static/nydus-image nydus-static/nydusd nydus-static/nydusify /usr/bin/ export PATH=$PATH:$(go env GOPATH)/bin make smoke cross-build-test: name: Cross Build Test timeout-minutes: 10 runs-on: ubuntu-latest strategy: matrix: GOOS: ["linux", "windows", "darwin"] GOARCH: ["amd64", "arm64"] steps: - name: Set up Go uses: actions/setup-go@v3 with: go-version: "1.19.6" - name: Check out code uses: actions/checkout@v3 - name: cache go mod uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }} restore-keys: | ${{ runner.os }}-go - name: Build run: | make -e GOOS=${{ matrix.GOOS }} GOARCH=${{ matrix.GOARCH }} converter coverage: name: Code coverage timeout-minutes: 10 runs-on: ubuntu-latest needs: [build] steps: - name: Install Go uses: actions/setup-go@v3 with: go-version: "1.19.6" - name: Checkout code uses: actions/checkout@v3 - name: cache go mod uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }} restore-keys: | ${{ runner.os }}-go - name: Run unit tests. run: make cover - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos files: ./coverage.txt nydus-snapshotter-0.13.4/.github/workflows/e2e.yml000066400000000000000000000040661453374237200221240ustar00rootroot00000000000000name: integration test on: push: branches: - "main" tags: - v[0-9]+.[0-9]+.[0-9]+ pull_request: branches: - "main" schedule: # Trigger test every day at 00:03 clock UTC - cron: "3 0 * * *" workflow_dispatch: env: CARGO_TERM_COLOR: always REGISTRY: ghcr.io jobs: run-e2e-for-cgroups-v1: runs-on: ubuntu-20.04 steps: - name: Set up Go uses: actions/setup-go@v3 with: go-version: "1.19.6" - name: Checkout repository uses: actions/checkout@v3 - name: cache go mod uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }} restore-keys: | ${{ runner.os }}-go - name: Log in to container registry uses: docker/login-action@v2 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Run e2e test run: | TAG=$GITHUB_REF_NAME [ "$TAG" == "main" ] && TAG="latest" [ "$GITHUB_EVENT_NAME" == "pull_request" ] && TAG="local" make integration run-e2e-for-cgroups-v2: runs-on: ubuntu-22.04 steps: - name: Set up Go uses: actions/setup-go@v3 with: go-version: "1.19.6" - name: Checkout repository uses: actions/checkout@v3 - name: cache go mod uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }} restore-keys: | ${{ runner.os }}-go - name: Log in to container registry uses: docker/login-action@v2 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Run e2e test run: | TAG=$GITHUB_REF_NAME [ "$TAG" == "main" ] && TAG="latest" [ "$GITHUB_EVENT_NAME" == "pull_request" ] && TAG="local" make integration nydus-snapshotter-0.13.4/.github/workflows/k8s-e2e-run.yml000066400000000000000000000005221453374237200234220ustar00rootroot00000000000000name: E2E Test With Kubernetes on: push: branches: - "main" tags: - v[0-9]+.[0-9]+.[0-9]+ pull_request: branches: [main] jobs: cri_auth: uses: ./.github/workflows/k8s-e2e.yml with: auth-type: cri kubeconf_auth: uses: ./.github/workflows/k8s-e2e.yml with: auth-type: kubeconf nydus-snapshotter-0.13.4/.github/workflows/k8s-e2e.yml000066400000000000000000000157561453374237200226370ustar00rootroot00000000000000name: E2E Test With Kubernetes Template on: workflow_call: inputs: auth-type: required: true type: string env: DOCKER_USER: testuser DOCKER_PASSWORD: testpassword jobs: e2e_tests_k8s: runs-on: ubuntu-latest timeout-minutes: 30 steps: - name: Checkout code uses: actions/checkout@v3 with: submodules: recursive - name: Set up Go uses: actions/setup-go@v3 with: go-version: "1.19.6" - name: Setup Kind uses: engineerd/setup-kind@v0.5.0 with: version: v0.16.0 config: tests/e2e/k8s/kind.yaml - name: Build nydus snapshotter dev image run: | make cp bin/containerd-nydus-grpc ./ cp misc/snapshotter/* ./ ls -tl ./ NYDUS_VER=v$(curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -s "https://api.github.com/repos/dragonflyoss/nydus/releases/latest" | jq -r .tag_name | sed 's/^v//') docker build --build-arg NYDUS_VER=${NYDUS_VER} -t local-dev:e2e . ## load local test image into kind node kind load docker-image local-dev:e2e - name: Setup registry run: | mkdir auth docker run \ --entrypoint htpasswd \ httpd:2 -Bbn ${{ env.DOCKER_USER }} ${{ env.DOCKER_PASSWORD }} > auth/htpasswd docker run -d \ -p 5000:5000 \ --restart=always \ --name registry \ -v "$(pwd)"/auth:/auth \ -e "REGISTRY_AUTH=htpasswd" \ -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \ -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \ registry:2 - name: Login to GitHub Container Registry run: | registry_ip=$(ip addr show eth0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1) ## sudo cat can't modify daemon.json sudo chmod a+w /etc/docker/daemon.json cat << EOF > /etc/docker/daemon.json { "exec-opts": ["native.cgroupdriver=cgroupfs"], "cgroup-parent": "/actions_job", "insecure-registries" : [ "${registry_ip}:5000" ] } EOF sudo systemctl restart docker docker login --username=${{ env.DOCKER_USER }} --password=${{ env.DOCKER_PASSWORD }} $registry_ip:5000 - name: Setup nydus snapshotter run: | kubectl create -f tests/e2e/k8s/snapshotter-${{ inputs.auth-type }}.yaml export ns=nydus-system p=`kubectl -n $ns get pods --no-headers -o custom-columns=NAME:metadata.name` echo "snapshotter pod name ${p}" kubectl -n $ns wait po $p --for=condition=ready --timeout=2m # change snapshotter to nydus after nydus snapshotter started registry_ip=$(ip addr show eth0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1) docker cp kind-control-plane:/etc/containerd/config.toml containerd.config.toml.bak sed -i -e 's|snapshotter = "overlayfs"|snapshotter = "nydus"|' containerd.config.toml.bak cat << EOF >> containerd.config.toml.bak [proxy_plugins] [proxy_plugins.nydus] type = "snapshot" address = "/run/containerd-nydus/containerd-nydus-grpc.sock" [plugins."io.containerd.grpc.v1.cri".registry.mirrors."${registry_ip}:5000"] endpoint = ["http://${registry_ip}:5000"] EOF docker cp containerd.config.toml.bak kind-control-plane:/etc/containerd/config.toml.bak docker exec kind-control-plane sh -c "cat /etc/containerd/config.toml.bak > /etc/containerd/config.toml" docker exec kind-control-plane systemctl restart containerd - name: Install Nydus binaries and convert nydus image run: | NYDUS_VER=v$(curl --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -s "https://api.github.com/repos/dragonflyoss/nydus/releases/latest" | jq -r .tag_name | sed 's/^v//') wget -q https://github.com/dragonflyoss/nydus/releases/download/$NYDUS_VER/nydus-static-$NYDUS_VER-linux-amd64.tgz tar xzf nydus-static-$NYDUS_VER-linux-amd64.tgz sudo cp nydus-static/nydusify nydus-static/nydus-image /usr/local/bin/ registry_ip=$(ip addr show eth0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1) sudo DOCKER_CONFIG=$HOME/.docker nydusify convert \ --source busybox:latest \ --target ${registry_ip}:5000/busybox:nydus-v6-latest \ --fs-version 6 - name: Run E2E test run: | registry_ip=$(ip addr show eth0 | grep 'inet ' | awk '{print $2}' | cut -d/ -f1) kubectl create --namespace nydus-system secret generic regcred \ --from-file=.dockerconfigjson=$HOME/.docker/config.json \ --type=kubernetes.io/dockerconfigjson sed -e "s|REGISTRY_IP|${registry_ip}|" tests/e2e/k8s/test-pod.yaml.tpl > tests/e2e/k8s/test-pod.yaml if [[ "${{ inputs.auth-type }}" == "cri" ]]; then docker exec kind-control-plane sh -c 'echo " --image-service-endpoint=unix:///run/containerd-nydus/containerd-nydus-grpc.sock" >> /etc/default/kubelet' docker exec kind-control-plane sh -c 'systemctl daemon-reload && systemctl restart kubelet' fi kubectl apply -f tests/e2e/k8s/test-pod.yaml kubectl wait po test-pod -n nydus-system --for=condition=ready --timeout=1m kubectl delete -f tests/e2e/k8s/test-pod.yaml - name: Dump logs if: failure() continue-on-error: true run: | log_dir="/tmp/nydus-log" mkdir -p $log_dir export ns=nydus-system for p in `kubectl -n $ns get pods --no-headers -o custom-columns=NAME:metadata.name`; do kubectl -n $ns get pod $p -o yaml >> $log_dir/nydus-pods.conf kubectl -n $ns describe pod $p >> $log_dir/nydus-pods.conf kubectl -n $ns logs $p -c nydus-snapshotter >> $log_dir/nydus-snapshotter.log || echo "failed to get snapshotter log" done kubectl -n $ns get secrets -o yaml >> $log_dir/nydus-secrets.log docker exec kind-control-plane cat /etc/containerd/config.toml >> $log_dir/containerd-config.toml docker exec kind-control-plane containerd config dump >> $log_dir/containerd-config-dump.toml docker exec kind-control-plane journalctl --no-pager -u containerd >> $log_dir/containerd.log docker exec kind-control-plane journalctl --no-pager -u kubelet >> $log_dir/kubelet.log docker exec kind-control-plane ps -ef >> $log_dir/psef.log kubectl get pod test-pod -o yaml >> $log_dir/test-pod.log || echo "test-pod may be deleted or not created" cat ~/.docker/config.json > $log_dir/docker.config.json || echo "~/.docker/config.json not found" - name: Upload Logs uses: actions/upload-artifact@v3 if: failure() with: name: k8s-e2e-tests-logs path: | /tmp/nydus-log nydus-snapshotter-0.13.4/.github/workflows/optimizer.yml000066400000000000000000000104211453374237200234630ustar00rootroot00000000000000name: optimizer test on: push: branches: - "main" tags: - v[0-9]+.[0-9]+.[0-9]+ pull_request: branches: - "main" schedule: # Trigger test every day at 00:03 clock UTC - cron: "3 0 * * *" workflow_dispatch: env: CARGO_TERM_COLOR: always jobs: run_optimizer: runs-on: ubuntu-latest steps: - name: Set up Go uses: actions/setup-go@v3 with: go-version: "1.19.6" - name: Checkout repository uses: actions/checkout@v3 - name: cache go mod uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }} restore-keys: | ${{ runner.os }}-go - name: cache cargo uses: actions/cache@v3 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ tools/optimizer-server/target/ key: ${{ runner.os }}-cargo-${{ hashFiles('tools/optimizer-server/Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo - name: containerd runc and crictl run: | sudo wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.26.0/crictl-v1.26.0-linux-amd64.tar.gz sudo tar zxvf ./crictl-v1.26.0-linux-amd64.tar.gz -C /usr/local/bin sudo install -D -m 755 misc/optimizer/crictl.yaml /etc/crictl.yaml sudo wget https://github.com/containerd/containerd/releases/download/v1.7.0/containerd-static-1.7.0-linux-amd64.tar.gz sudo systemctl stop containerd sudo tar -zxf ./containerd-static-1.7.0-linux-amd64.tar.gz -C /usr/ sudo install -D -m 755 misc/optimizer/containerd-config.toml /etc/containerd/config.toml sudo systemctl restart containerd sudo wget https://github.com/opencontainers/runc/releases/download/v1.1.5/runc.amd64 -O /usr/bin/runc sudo chmod +x /usr/bin/runc - name: Setup CNI run: | wget https://github.com/containernetworking/plugins/releases/download/v1.2.0/cni-plugins-linux-amd64-v1.2.0.tgz sudo mkdir -p /opt/cni/bin sudo tar xzf cni-plugins-linux-amd64-v1.2.0.tgz -C /opt/cni/bin/ sudo install -D -m 755 misc/example/10-containerd-net.conflist /etc/cni/net.d/10-containerd-net.conflist - name: Build and install optimizer run: | rustup component add rustfmt clippy make optimizer sudo chown -R $(id -un):$(id -gn) . ~/.cargo/ pwd ls -lh bin/*optimizer* sudo make install-optimizer sudo install -D -m 755 misc/example/optimizer-nri-plugin.conf /etc/nri/conf.d/02-optimizer-nri-plugin.conf sudo systemctl restart containerd systemctl status containerd --no-pager -l - name: Wait containerd ready run: | unset READY for i in $(seq 30); do if eval "timeout 180 ls /run/containerd/containerd.sock"; then READY=true break fi echo "Fail(${i}). Retrying..." sleep 1 done if [ "$READY" != "true" ];then echo "containerd is not ready" exit 1 fi - name: Generate accessed files list run: | sed -i "s|host_path: script|host_path: $(pwd)/misc/optimizer/script|g" misc/optimizer/nginx.yaml sudo crictl run misc/optimizer/nginx.yaml misc/optimizer/sandbox.yaml sleep 20 sudo crictl rmp -f --all tree /opt/nri/optimizer/results/ count=$(cat /opt/nri/optimizer/results/library/nginx:1.23.3 | wc -l) expected=$(cat misc/optimizer/script/file_list.txt | wc -l) echo "count: $count expected minimum value: $expected" if [ $count -lt $expected ]; then echo "failed to generate accessed files list for nginx:1.23.3" cat misc/optimizer/script/file_list.txt exit 1 fi cat /opt/nri/optimizer/results/library/nginx:1.23.3.csv - name: Dump logs if: failure() continue-on-error: true run: | systemctl status containerd --no-pager -l journalctl -xeu containerd --no-pager nydus-snapshotter-0.13.4/.github/workflows/release.yml000066400000000000000000000075251453374237200230740ustar00rootroot00000000000000name: release on: push: tags: - v[0-9]+.[0-9]+.[0-9]+* env: CARGO_TERM_COLOR: always REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: go-version: "1.19.6" - name: cache go mod uses: actions/cache@v3 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }} restore-keys: | ${{ runner.os }}-go - name: cache cargo uses: actions/cache@v3 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ tools/optimizer-server/target/ key: ${{ runner.os }}-cargo-${{ hashFiles('tools/optimizer-server/Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo - name: build nydus-snapshotter and optimizer run: | go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.2 export PATH=$PATH:$(go env GOPATH)/bin make static-release - name: upload artifacts uses: actions/upload-artifact@v3 with: name: nydus-snapshotter_artifacts path: | bin/containerd-nydus-grpc bin/nydus-overlayfs bin/optimizer-nri-plugin bin/optimizer-server upload: runs-on: ubuntu-latest needs: [build] steps: - uses: actions/checkout@v3 - name: Download Artifacts uses: actions/download-artifact@v3 with: name: nydus-snapshotter_artifacts path: nydus-snapshotter - name: Upload Artifacts run: | tag=$(echo $GITHUB_REF | cut -d/ -f3-) tarball="nydus-snapshotter-$tag-x86_64.tgz" chmod +x nydus-snapshotter/* tar cf - nydus-snapshotter | gzip > ${tarball} echo "tag=$tag" >> $GITHUB_ENV echo "tarball=$tarball" >> $GITHUB_ENV tarball_shasum="$tarball.sha256sum" sha256sum $tarball > $tarball_shasum echo "tarball_shasum=$tarball_shasum" >> $GITHUB_ENV - name: Release uses: softprops/action-gh-release@v1 with: name: "Nydus Snapshotter ${{ env.tag }} Release" generate_release_notes: true files: | ${{ env.tarball }} ${{ env.tarball_shasum }} publish-image: runs-on: ubuntu-latest needs: [build] steps: - name: Checkout repository uses: actions/checkout@v3 - name: Log in to the container registry uses: docker/login-action@v2 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: download artifacts uses: actions/download-artifact@v3 with: name: nydus-snapshotter_artifacts path: misc/snapshotter - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@v4 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - name: Get the nydusd version id: step_one run: | export NYDUS_STABLE_VER=$(curl https://api.github.com/repos/dragonflyoss/nydus/releases/latest | jq -r .tag_name) echo "NYDUS_STABLE_VER=$NYDUS_STABLE_VER" >> "$GITHUB_ENV" printf 'nydus version is: %s\n' "$NYDUS_STABLE_VER" - name: build and push nydus-snapshotter image uses: docker/build-push-action@v3 with: context: misc/snapshotter file: misc/snapshotter/Dockerfile push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} build-args: NYDUS_VER=${{ env.NYDUS_STABLE_VER }} nydus-snapshotter-0.13.4/.gitignore000066400000000000000000000001661453374237200173160ustar00rootroot00000000000000bin/ pkg/filesystem/stargz/testdata/db/ coverage.txt .vscode/ tests/output/ smoke.tests tools/optimizer-server/target nydus-snapshotter-0.13.4/.golangci.yml000066400000000000000000000021301453374237200177030ustar00rootroot00000000000000# https://golangci-lint.run/usage/configuration#config-file run: concurrency: 4 deadline: 5m issues-exit-code: 1 tests: true skip-dirs: - misc # The package is ported from containerd project, let's skip it. - pkg/remote/remotes linters-settings: # govet: # check-shadowing: true # enable: # - fieldalignment funlen: # Checks the number of lines in a function. # If lower than 0, disable the check. # Default: 60 lines: 100 # Checks the number of statements in a function. # If lower than 0, disable the check. # Default: 40 statements: 80 nilnil: checked-types: - ptr - func - iface - map - chan linters: enable: - staticcheck - unconvert - gofmt - goimports - revive - ineffassign - vet - unused - misspell - bodyclose # - cyclop - dogsled - nilnil - unparam - nilerr # - goerr113 - exportloopref # - gosec - gocritic - prealloc - tenv # - funlen - exhaustive - errcheck disable: - gosec nydus-snapshotter-0.13.4/LICENSE000066400000000000000000000261361453374237200163400ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. nydus-snapshotter-0.13.4/MAINTAINERS000066400000000000000000000010451453374237200170200ustar00rootroot00000000000000# nydus-snapshotter maintainers # # As a containerd sub-project, containerd maintainers are also included from https://github.com/containerd/project/blob/main/MAINTAINERS. # See https://github.com/containerd/project/blob/main/GOVERNANCE.md for description of maintainer role # # COMMITTERS # GitHub ID, Name, Email address changweige, Changwei Ge, changweige@gmail.com eryugey, Eryu Guan, eguan@linux.alibaba.com imeoer, Yan Song, yansong.ys@antgroup.com # # REVIEWERS # GitHub ID, Name, Email address sctb512, Bin Tang, tangbin.bin@bytedance.com nydus-snapshotter-0.13.4/Makefile000066400000000000000000000147641453374237200167770ustar00rootroot00000000000000all: clean build optimizer: clean-optimizer build-optimizer PKG = github.com/containerd/nydus-snapshotter PACKAGES ?= $(shell go list ./... | grep -v /tests) SUDO = $(shell which sudo) GO_EXECUTABLE_PATH ?= $(shell which go) NYDUS_BUILDER ?= /usr/bin/nydus-image NYDUS_NYDUSD ?= /usr/bin/nydusd GOOS ?= linux GOARCH ?= $(shell go env GOARCH) KERNEL_VER = $(shell uname -r) # Used to populate variables in version package. BUILD_TIMESTAMP=$(shell date '+%Y-%m-%dT%H:%M:%S') VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always --tags) REVISION=$(shell git rev-parse HEAD)$(shell if ! git diff --no-ext-diff --quiet --exit-code; then echo .m; fi) # Relpace test target images for e2e tests. ifdef E2E_TEST_TARGET_IMAGES_FILE ENV_TARGET_IMAGES_FILE = --env-file ${E2E_TEST_TARGET_IMAGES_FILE} endif ifdef E2E_DOWNLOADS_MIRROR BUILD_ARG_E2E_DOWNLOADS_MIRROR = --build-arg DOWNLOADS_MIRROR=${E2E_DOWNLOADS_MIRROR} endif ifdef GOPROXY PROXY := GOPROXY="${GOPROXY}" endif ifdef FS_CACHE FS_DRIVER = fscache else FS_DRIVER = fusedev endif SNAPSHOTTER_CONFIG=/etc/nydus/config.toml SOURCE_SNAPSHOTTER_CONFIG=misc/snapshotter/config.toml NYDUSD_CONFIG=/etc/nydus/nydusd-config.${FS_DRIVER}.json SOURCE_NYDUSD_CONFIG=misc/snapshotter/nydusd-config.${FS_DRIVER}.json SNAPSHOTTER_SYSTEMD_UNIT_SERVICE=misc/snapshotter/nydus-snapshotter.${FS_DRIVER}.service LDFLAGS = -s -w -X ${PKG}/version.Version=${VERSION} -X ${PKG}/version.Revision=$(REVISION) -X ${PKG}/version.BuildTimestamp=$(BUILD_TIMESTAMP) DEBUG_LDFLAGS = -X ${PKG}/version.Version=${VERSION} -X ${PKG}/version.Revision=$(REVISION) -X ${PKG}/version.BuildTimestamp=$(BUILD_TIMESTAMP) CARGO ?= $(shell which cargo) OPTIMIZER_SERVER = tools/optimizer-server OPTIMIZER_SERVER_TOML = ${OPTIMIZER_SERVER}/Cargo.toml OPTIMIZER_SERVER_BIN = ${OPTIMIZER_SERVER}/target/release/optimizer-server STATIC_OPTIMIZER_SERVER_BIN = ${OPTIMIZER_SERVER}/target/x86_64-unknown-linux-gnu/release/optimizer-server .PHONY: build build: GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(LDFLAGS)" -v -o bin/containerd-nydus-grpc ./cmd/containerd-nydus-grpc GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(LDFLAGS)" -v -o bin/nydus-overlayfs ./cmd/nydus-overlayfs debug: GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(DEBUG_LDFLAGS)" -gcflags "-N -l" -v -o bin/containerd-nydus-grpc ./cmd/containerd-nydus-grpc GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(DEBUG_LDFLAGS)" -gcflags "-N -l" -v -o bin/nydus-overlayfs ./cmd/nydus-overlayfs .PHONY: build-optimizer build-optimizer: GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(LDFLAGS)" -v -o bin/optimizer-nri-plugin ./cmd/optimizer-nri-plugin make -C tools/optimizer-server release && cp ${OPTIMIZER_SERVER_BIN} ./bin static-release: CGO_ENABLED=0 ${PROXY} GOOS=${GOOS} GOARCH=${GOARCH} go build -ldflags "$(LDFLAGS) -extldflags -static" -v -o bin/containerd-nydus-grpc ./cmd/containerd-nydus-grpc CGO_ENABLED=0 ${PROXY} GOOS=${GOOS} GOARCH=${GOARCH} go build -ldflags "$(LDFLAGS) -extldflags -static" -v -o bin/nydus-overlayfs ./cmd/nydus-overlayfs CGO_ENABLED=0 ${PROXY} GOOS=${GOOS} GOARCH=${GOARCH} go build -ldflags "$(LDFLAGS) -extldflags -static" -v -o bin/optimizer-nri-plugin ./cmd/optimizer-nri-plugin make -C tools/optimizer-server static-release && cp ${STATIC_OPTIMIZER_SERVER_BIN} ./bin # Majorly for cross build for converter package since it is imported by other projects converter: GOOS=${GOOS} GOARCH=${GOARCH} ${PROXY} go build -ldflags "$(LDFLAGS)" -v -o bin/converter ./cmd/converter .PHONY: clean clean: rm -f bin/* rm -rf _out .PHONY: clean-optimizer clean-optimizer: rm -rf bin/optimizer-nri-plugin bin/optimizer-server make -C tools/optimizer-server clean .PHONY: install install: @echo "+ $@ bin/containerd-nydus-grpc" @sudo install -D -m 755 bin/containerd-nydus-grpc /usr/local/bin/containerd-nydus-grpc @echo "+ $@ bin/nydus-overlayfs" @sudo install -D -m 755 bin/nydus-overlayfs /usr/local/bin/nydus-overlayfs @if [ ! -e ${NYDUSD_CONFIG} ]; then echo "+ $@ SOURCE_NYDUSD_CONFIG"; sudo install -D -m 664 ${SOURCE_NYDUSD_CONFIG} ${NYDUSD_CONFIG}; fi @if [ ! -e ${SNAPSHOTTER_CONFIG} ]; then echo "+ $@ ${SOURCE_SNAPSHOTTER_CONFIG}"; sudo install -D -m 664 ${SOURCE_SNAPSHOTTER_CONFIG} ${SNAPSHOTTER_CONFIG}; fi @sudo ln -f -s /etc/nydus/nydusd-config.${FS_DRIVER}.json /etc/nydus/nydusd-config.json @echo "+ $@ ${SNAPSHOTTER_SYSTEMD_UNIT_SERVICE}" @sudo install -D -m 644 ${SNAPSHOTTER_SYSTEMD_UNIT_SERVICE} /etc/systemd/system/nydus-snapshotter.service @sudo mkdir -p /etc/nydus/certs.d @if which systemctl >/dev/null; then sudo systemctl enable /etc/systemd/system/nydus-snapshotter.service; sudo systemctl restart nydus-snapshotter; fi install-optimizer: sudo install -D -m 755 bin/optimizer-nri-plugin /opt/nri/plugins/02-optimizer-nri-plugin sudo install -D -m 755 bin/optimizer-server /usr/local/bin/optimizer-server sudo install -D -m 755 misc/example/optimizer-nri-plugin.conf /etc/nri/conf.d/02-optimizer-nri-plugin.conf @sudo mkdir -p /opt/nri/optimizer/results .PHONY: vet vet: go vet $(PACKAGES) ./tests .PHONY: check check: vet golangci-lint run .PHONY: test test: go test -race -v -mod=mod -cover ${PACKAGES} .PHONY: cover cover: go test -v -covermode=atomic -coverprofile=coverage.txt $(PACKAGES) go tool cover -func=coverage.txt # make smoke TESTS=TestPack smoke: ${GO_EXECUTABLE_PATH} test -o smoke.tests -c -race -v -cover ./tests $(SUDO) -E NYDUS_BUILDER=${NYDUS_BUILDER} NYDUS_NYDUSD=${NYDUS_NYDUSD} ./smoke.tests -test.v -test.timeout 10m -test.parallel=8 -test.run=$(TESTS) .PHONY: integration integration: CGO_ENABLED=1 ${PROXY} GOOS=${GOOS} GOARCH=${GOARCH} go build -ldflags '-X "${PKG}/version.Version=${VERSION}" -extldflags "-static"' -race -v -o bin/containerd-nydus-grpc ./cmd/containerd-nydus-grpc CGO_ENABLED=1 ${PROXY} GOOS=${GOOS} GOARCH=${GOARCH} go build -ldflags '-X "${PKG}/version.Version=${VERSION}" -extldflags "-static"' -race -v -o bin/nydus-overlayfs ./cmd/nydus-overlayfs $(SUDO) DOCKER_BUILDKIT=1 docker build ${BUILD_ARG_E2E_DOWNLOADS_MIRROR} -t nydus-snapshotter-e2e:0.1 -f integration/Dockerfile . $(SUDO) docker run --cap-add SYS_ADMIN --security-opt seccomp=unconfined --cgroup-parent=system.slice --cgroupns private --name nydus-snapshotter_e2e --rm --privileged -v /root/.docker:/root/.docker -v `go env GOMODCACHE`:/go/pkg/mod \ -v `go env GOCACHE`:/root/.cache/go-build -v `pwd`:/nydus-snapshotter \ -v /usr/src/linux-headers-${KERNEL_VER}:/usr/src/linux-headers-${KERNEL_VER} \ ${ENV_TARGET_IMAGES_FILE} \ nydus-snapshotter-e2e:0.1 nydus-snapshotter-0.13.4/README.md000066400000000000000000000245651453374237200166160ustar00rootroot00000000000000[**[⬇️ Download]**](https://github.com/containerd/nydus-snapshotter/releases) [**[📖 Website]**](https://nydus.dev/) [**[☸ Quick Start (Kubernetes)**]](https://github.com/containerd/nydus-snapshotter/blob/main/docs/run_nydus_in_kubernetes.md) [**[🤓 Quick Start (nerdctl)**]](https://github.com/containerd/nerdctl/blob/master/docs/nydus.md) [**[❓ FAQs & Troubleshooting]**](https://github.com/dragonflyoss/nydus/wiki/FAQ) # Nydus Snapshotter

[![Release Version](https://img.shields.io/github/v/release/containerd/nydus-snapshotter?style=flat)](https://github.com/containerd/nydus-snapshotter/releases) [![LICENSE](https://img.shields.io/github/license/containerd/nydus-snapshotter.svg?style=flat)](https://github.com/containerd/nydus-snapshotter/blob/main/LICENSE) ![CI](https://github.com/containerd/nydus-snapshotter/actions/workflows/ci.yml/badge.svg?event=push) [![Go Report Card](https://goreportcard.com/badge/github.com/containerd/nydus-snapshotter?style=flat)](https://goreportcard.com/report/github.com/containerd/nydus-snapshotter) [![Twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Ftwitter.com%2Fdragonfly_oss)](https://twitter.com/dragonfly_oss) [![Nydus Stars](https://img.shields.io/github/stars/dragonflyoss/nydus?label=Nydus%20Stars&style=social)](https://github.com/dragonflyoss/nydus) Nydus-snapshotter is a **non-core** sub-project of containerd. Nydus snapshotter is an external plugin of containerd for [Nydus image service](https://nydus.dev) which implements a chunk-based content-addressable filesystem on top of a called `RAFS (Registry Acceleration File System)` format that improves the current OCI image specification, in terms of container launching speed, image space, and network bandwidth efficiency, as well as data integrity with several runtime backends: FUSE, virtiofs and in-kernel [EROFS](https://www.kernel.org/doc/html/latest/filesystems/erofs.html). Nydus supports lazy pulling feature since pulling image is one of the time-consuming steps in the container lifecycle. Lazy pulling here means a container can run even the image is partially available and necessary chunks of the image are fetched on-demand. Apart from that, Nydus also supports [(e)Stargz](https://github.com/containerd/stargz-snapshotter) and OCI (by using [zran](https://github.com/dragonflyoss/nydus/blob/master/docs/nydus-zran.md)) lazy pulling directly **WITHOUT** any explicit conversion. For more details about how to build Nydus container image, please refer to [nydusify](https://github.com/dragonflyoss/nydus/blob/master/docs/nydusify.md) conversion tool and [acceld](https://github.com/goharbor/acceleration-service). ## Architecture ### Architecture Based on FUSE ![fuse arch](./docs/diagram/nydus_fuse_arch.svg) ### Architecture Based on Fscache/Erofs ![fscache arch](./docs/diagram/nydus_fscache_erofs_arch.svg) ## Building Just invoke `make` and check out the output executable binary `./bin/containerd-nydus-grpc` ```bash make ``` ## Integrate Nydus-snapshotter into Containerd The following document will describe how to manually configure containerd + Nydus snapshotter. If you want to run Nydus snapshotter in Kubernetes cluster, you can try to use helm or run nydus snapshotter as a container. You can refer to [this documentation](./docs/run_nydus_in_kubernetes.md). Containerd provides a general mechanism to exploit different types of snapshotters. Please ensure your containerd's version is 1.4.0 or above. Add Nydus as a proxy plugin into containerd's configuration file which may be located at `/etc/containerd/config.toml`. ```toml # The `address` field specifies through which socket snapshotter and containerd communicate. [proxy_plugins] [proxy_plugins.nydus] type = "snapshot" address = "/run/containerd-nydus/containerd-nydus-grpc.sock" ``` Restart your containerd service making the change take effect. Assume that your node is systemd based, restart the service as below: ```bash systemctl restart containerd ``` ### Get Nydus Binaries Get `nydusd` `nydus-image` and `nydusctl` binaries from [nydus releases page](https://github.com/dragonflyoss/nydus/releases). It's suggested to install the binaries to your system path. `nydusd` is FUSE userspace daemon and a vhost-user-fs backend. Nydus-snapshotter will fork a nydusd process when necessary. ### Configure Nydus Please follow instructions to [configure nydus](./docs/configure_nydus.md) in order to make it work properly in your environment. ### Start Nydus Snapshotter Nydus-snapshotter is implemented as a [proxy plugin](https://github.com/containerd/containerd/blob/04985039cede6aafbb7dfb3206c9c4d04e2f924d/PLUGINS.md#proxy-plugins) (`containerd-nydus-grpc`) for containerd. Assume your server is systemd based, install nydus-snapshotter: Note: `nydusd` and `nydus-image` should be found from $PATH. ```bash make install systemctl restart containerd ``` Or you can start nydus-snapshotter manually. ```bash # `--nydusd` specifies the path to nydusd binary. If `nydusd` and `nydus-image` are installed, `--nydusd` and `--nydus-image`can be omitted. # Otherwise, provide them in below command line. # `address` is the domain socket that you configured in containerd configuration file # `--nydusd-config` is the path to `nydusd` configuration file # The default nydus-snapshotter work directory is located at `/var/lib/containerd-nydus` $ sudo ./containerd-nydus-grpc --config /etc/nydus/config.toml --nydusd-config /etc/nydus/nydusd-config.json --log-to-stdout ``` ### Validate Nydus-snapshotter Setup Utilize containerd's `ctr` CLI command to validate if nydus-snapshotter is set up successfully. ```bash $ ctr -a /run/containerd/containerd.sock plugin ls TYPE ID PLATFORMS STATUS io.containerd.snapshotter.v1 nydus - ok ``` ### Optimize Nydus Image as per Workload Nydus usually prefetch image data to local filesystem before a real user on-demand read. It helps to improve the performance and availability. A containerd NRI plugin [container image optimizer](docs/optimize_nydus_image.md) can be used to generate nydus image building suggestions to optimize your nydus image making the nydusd runtime match your workload IO pattern. The optimized nydus image has a better performance. ## Quickstart Container with Lazy Pulling ### Start Container on single Node Start container using `nerdctl` (>=v0.22) which has native nydus support with `nydus-snapshotter`. ```bash # Start container by `nerdctl` nerdctl --snapshotter nydus run ghcr.io/dragonflyoss/image-service/nginx:nydus-latest ``` ### Start Container in Kubernetes Cluster Change containerd's CRI configuration: ```toml [plugins."io.containerd.grpc.v1.cri".containerd] snapshotter = "nydus" disable_snapshot_annotations = false ``` Use `crictl` to debug starting container via Kubernetes CRI. Dry run [steps](./docs/crictl_dry_run.md) of using `crictl` can be found in [documents](./docs). ### Setup with nydus-snapshotter image We can also use the `nydus-snapshotter` container image when we want to put Nydus stuffs inside a container. See the [nydus-snapshotter example](./misc/example/README.md) for how to setup and use it. ## Integrate with Dragonfly to Distribute Images by P2P Nydus is a sub-project of [Dragonfly](https://github.com/dragonflyoss/Dragonfly2). So it closely works with Dragonfly to distribute container images in a fast and efficient P2P fashion to reduce network latency and lower the pressure on a single-point of the registry. ### Quickstart Dragonfly & Nydus in Kubernetes We recommend using the Dragonfly P2P data distribution system to further improve the runtime performance of Nydus images. If you want to deploy Dragonfly and Nydus at the same time, please refer to this **[Quick Start](https://github.com/dragonflyoss/helm-charts/blob/main/INSTALL.md)**. ### Config Dragonfly mode Dragonfly supports both **mirror** mode and HTTP **proxy** mode to boost the containers startup. It is suggested to use Dragonfly mirror mode. To integrate with Dragonfly in the mirror mode, please provide registry mirror in nydusd's json configuration file in section `device.backend.mirrors` ```json { "mirrors": [ { "host": "http://127.0.0.1:65001", "headers": "https://index.docker.io/v1/" } ] } ``` ### Hot updating mirror configurations In addition to setting the registry mirror in nydusd's json configuration file, `nydus-snapshotter` also supports hot updating mirror configurations. You can set the configuration directory in nudus-snapshotter's toml configuration file with `remote.mirrors_config.dir`. The empty `remote.mirrors_config.dir` means disabling it. ```toml [remote.mirrors_config] dir = "/etc/nydus/certs.d" ``` Configuration file is compatible with containerd's configuration file in toml format. ```toml [host] [host."http://127.0.0.1:65001"] [host."http://127.0.0.1:65001".header] # NOTE: For Dragonfly, the HTTP scheme must be explicitly specified. X-Dragonfly-Registry = ["https://p2p-nydus.com"] ``` Mirror configurations loaded from nydusd's json file will be overwritten before pulling image if the valid mirror configuration items loaded from `remote.mirrors_config.dir` are greater than 0. ## Community Nydus aims to form a **vendor-neutral opensource** image distribution solution to all communities. Questions, bug reports, technical discussion, feature requests and contribution are always welcomed! We're very pleased to hear your use cases any time. Feel free to reach/join us via Slack and/or Dingtalk. - **Slack:** [Nydus Workspace](https://join.slack.com/t/nydusimageservice/shared_invite/zt-pz4qvl4y-WIh4itPNILGhPS8JqdFm_w) - **Twitter:** [@dragonfly_oss](https://twitter.com/dragonfly_oss) - **Dingtalk:** [34971767](https://qr.dingtalk.com/action/joingroup?code=v1,k1,ioWGzuDZEIO10Bf+/ohz4RcQqAkW0MtOwoG1nbbMxQg=&_dt_no_comment=1&origin=11) - **Technical Meeting:** Every Wednesday at 06:00 UTC (Beijing, Shanghai 14:00), please see our [HackMD](https://hackmd.io/@Nydus/Bk8u2X0p9) page for more information. ## License [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fcontainerd%2Fnydus-snapshotter.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fcontainerd%2Fnydus-snapshotter?ref=badge_large) nydus-snapshotter-0.13.4/cmd/000077500000000000000000000000001453374237200160665ustar00rootroot00000000000000nydus-snapshotter-0.13.4/cmd/containerd-nydus-grpc/000077500000000000000000000000001453374237200223055ustar00rootroot00000000000000nydus-snapshotter-0.13.4/cmd/containerd-nydus-grpc/main.go000066400000000000000000000073671453374237200235750ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package main import ( "fmt" "os" "github.com/containerd/containerd/log" "github.com/pkg/errors" "github.com/urfave/cli/v2" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/internal/flags" "github.com/containerd/nydus-snapshotter/internal/logging" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/version" ) func main() { flags := flags.NewFlags() app := &cli.App{ Name: "containerd-nydus-grpc", Usage: "Nydus remote snapshotter for containerd", Version: version.Version, Flags: flags.F, HideVersion: true, Action: func(c *cli.Context) error { if flags.Args.PrintVersion { fmt.Println("Version: ", version.Version) fmt.Println("Revision: ", version.Revision) fmt.Println("Go version: ", version.GoVersion) fmt.Println("Build time: ", version.BuildTimestamp) return nil } snapshotterConfigPath := flags.Args.SnapshotterConfigPath var defaultSnapshotterConfig config.SnapshotterConfig var snapshotterConfig config.SnapshotterConfig if err := defaultSnapshotterConfig.FillUpWithDefaults(); err != nil { return errors.New("failed to generate nydus default configuration") } // Once snapshotter's configuration file is provided, parse it and let command line parameters override it. if snapshotterConfigPath != "" { if c, err := config.LoadSnapshotterConfig(snapshotterConfigPath); err == nil { // Command line parameters override the snapshotter's configurations for backwards compatibility if err := config.ParseParameters(flags.Args, c); err != nil { return errors.Wrap(err, "failed to parse commandline options") } snapshotterConfig = *c } else { return errors.Wrapf(err, "failed to load snapshotter configuration from %q", snapshotterConfigPath) } } else { if err := config.ParseParameters(flags.Args, &snapshotterConfig); err != nil { return errors.Wrap(err, "failed to parse commandline options") } } if err := config.MergeConfig(&snapshotterConfig, &defaultSnapshotterConfig); err != nil { return errors.Wrap(err, "failed to merge configurations") } if err := config.ValidateConfig(&snapshotterConfig); err != nil { return errors.Wrapf(err, "failed to validate configurations") } if err := config.ProcessConfigurations(&snapshotterConfig); err != nil { return errors.Wrap(err, "failed to process configurations") } if err := config.SetUpEnvironment(&snapshotterConfig); err != nil { return errors.Wrap(err, "failed to setup environment") } ctx := logging.WithContext() logConfig := &snapshotterConfig.LoggingConfig logRotateArgs := &logging.RotateLogArgs{ RotateLogMaxSize: logConfig.RotateLogMaxSize, RotateLogMaxBackups: logConfig.RotateLogMaxBackups, RotateLogMaxAge: logConfig.RotateLogMaxAge, RotateLogLocalTime: logConfig.RotateLogLocalTime, RotateLogCompress: logConfig.RotateLogCompress, } if err := logging.SetUp(logConfig.LogLevel, logConfig.LogToStdout, logConfig.LogDir, logRotateArgs); err != nil { return errors.Wrap(err, "failed to setup logger") } log.L.Infof("Start nydus-snapshotter. Version: %s, PID: %d, FsDriver: %s, DaemonMode: %s", version.Version, os.Getpid(), config.GetFsDriver(), snapshotterConfig.DaemonMode) return Start(ctx, &snapshotterConfig) }, } if err := app.Run(os.Args); err != nil { if errdefs.IsConnectionClosed(err) { log.L.Info("nydus-snapshotter exited") } else { log.L.WithError(err).Fatal("failed to start nydus-snapshotter") } } } nydus-snapshotter-0.13.4/cmd/containerd-nydus-grpc/snapshotter.go000066400000000000000000000060411453374237200252070ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package main import ( "context" "net" "os" "path/filepath" "github.com/pkg/errors" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/pkg/auth" "github.com/containerd/nydus-snapshotter/pkg/utils/signals" "github.com/containerd/nydus-snapshotter/snapshot" api "github.com/containerd/containerd/api/services/snapshots/v1" "github.com/containerd/containerd/contrib/snapshotservice" "github.com/containerd/containerd/log" "github.com/containerd/containerd/snapshots" "google.golang.org/grpc" ) func Start(ctx context.Context, cfg *config.SnapshotterConfig) error { ctx, cancel := context.WithCancel(ctx) defer cancel() rs, err := snapshot.NewSnapshotter(ctx, cfg) if err != nil { return errors.Wrap(err, "failed to initialize snapshotter") } stopSignal := signals.SetupSignalHandler() opt := ServeOptions{ ListeningSocketPath: cfg.Address, EnableCRIKeychain: cfg.RemoteConfig.AuthConfig.EnableCRIKeychain, ImageServiceAddress: cfg.RemoteConfig.AuthConfig.ImageServiceAddress, } if cfg.RemoteConfig.AuthConfig.EnableKubeconfigKeychain { if err := auth.InitKubeSecretListener(ctx, cfg.RemoteConfig.AuthConfig.KubeconfigPath); err != nil { return err } } return Serve(ctx, rs, opt, stopSignal) } type ServeOptions struct { ListeningSocketPath string EnableCRIKeychain bool ImageServiceAddress string } func Serve(ctx context.Context, sn snapshots.Snapshotter, options ServeOptions, stop <-chan struct{}) error { err := ensureSocketNotExists(options.ListeningSocketPath) if err != nil { return err } rpc := grpc.NewServer() if rpc == nil { return errors.New("start gRPC server") } api.RegisterSnapshotsServer(rpc, snapshotservice.FromSnapshotter(sn)) listener, err := net.Listen("unix", options.ListeningSocketPath) if err != nil { return errors.Wrapf(err, "listen socket %q", options.ListeningSocketPath) } if options.EnableCRIKeychain { auth.AddImageProxy(ctx, rpc, options.ImageServiceAddress) } go func() { <-stop log.L.Infof("Shutting down nydus-snapshotter!") if err := sn.Close(); err != nil { log.L.WithError(err).Errorf("Closing snapshotter error") } if err := listener.Close(); err != nil { log.L.Errorf("Failed to close listener %s, err: %v", options.ListeningSocketPath, err) } }() return rpc.Serve(listener) } func ensureSocketNotExists(listeningSocketPath string) error { if err := os.MkdirAll(filepath.Dir(listeningSocketPath), 0700); err != nil { return errors.Wrapf(err, "failed to create directory %q", filepath.Dir(listeningSocketPath)) } finfo, err := os.Stat(listeningSocketPath) // err is nil means listening socket path exists, remove before serve if err == nil { if finfo.Mode()&os.ModeSocket == 0 { return errors.Errorf("file %s is not a socket", listeningSocketPath) } err := os.Remove(listeningSocketPath) if err != nil { return err } } return nil } nydus-snapshotter-0.13.4/cmd/converter/000077500000000000000000000000001453374237200200755ustar00rootroot00000000000000nydus-snapshotter-0.13.4/cmd/converter/main.go000066400000000000000000000003401453374237200213450ustar00rootroot00000000000000package main // Import the converter package so that it can be compiled during // `go build` to ensure cross-compilation compatibility. import ( _ "github.com/containerd/nydus-snapshotter/pkg/converter" ) func main() { } nydus-snapshotter-0.13.4/cmd/nydus-overlayfs/000077500000000000000000000000001453374237200212405ustar00rootroot00000000000000nydus-snapshotter-0.13.4/cmd/nydus-overlayfs/main.go000066400000000000000000000072711453374237200225220ustar00rootroot00000000000000package main import ( "fmt" "log" "os" "strings" "syscall" "github.com/pkg/errors" "github.com/urfave/cli/v2" "golang.org/x/sys/unix" ) const ( // Extra mount option to pass Nydus specific information from snapshotter to runtime through containerd. extraOptionKey = "extraoption=" // Kata virtual volume infmation passed from snapshotter to runtime through containerd, superset of `extraOptionKey`. // Please refer to `KataVirtualVolume` in https://github.com/kata-containers/kata-containers/blob/main/src/libs/kata-types/src/mount.rs kataVolumeOptionKey = "io.katacontainers.volume=" ) var ( Version = "v0.1" BuildTime = "unknown" ) /* containerd run fuse.mount format: nydus-overlayfs overlay /tmp/ctd-volume107067851 -o lowerdir=/foo/lower2:/foo/lower1,upperdir=/foo/upper,workdir=/foo/work,extraoption={...},dev,suid] */ type mountArgs struct { fsType string target string options []string } func parseArgs(args []string) (*mountArgs, error) { margs := &mountArgs{ fsType: args[0], target: args[1], } if margs.fsType != "overlay" { return nil, errors.Errorf("invalid filesystem type %s for overlayfs", margs.fsType) } if len(margs.target) == 0 { return nil, errors.New("empty overlayfs mount target") } if args[2] == "-o" && len(args[3]) != 0 { for _, opt := range strings.Split(args[3], ",") { // filter Nydus specific options if strings.HasPrefix(opt, extraOptionKey) || strings.HasPrefix(opt, kataVolumeOptionKey) { continue } margs.options = append(margs.options, opt) } } if len(margs.options) == 0 { return nil, errors.New("empty overlayfs mount options") } return margs, nil } func parseOptions(options []string) (int, string) { flagsTable := map[string]int{ "async": unix.MS_SYNCHRONOUS, "atime": unix.MS_NOATIME, "bind": unix.MS_BIND, "defaults": 0, "dev": unix.MS_NODEV, "diratime": unix.MS_NODIRATIME, "dirsync": unix.MS_DIRSYNC, "exec": unix.MS_NOEXEC, "mand": unix.MS_MANDLOCK, "noatime": unix.MS_NOATIME, "nodev": unix.MS_NODEV, "nodiratime": unix.MS_NODIRATIME, "noexec": unix.MS_NOEXEC, "nomand": unix.MS_MANDLOCK, "norelatime": unix.MS_RELATIME, "nostrictatime": unix.MS_STRICTATIME, "nosuid": unix.MS_NOSUID, "rbind": unix.MS_BIND | unix.MS_REC, "relatime": unix.MS_RELATIME, "remount": unix.MS_REMOUNT, "ro": unix.MS_RDONLY, "rw": unix.MS_RDONLY, "strictatime": unix.MS_STRICTATIME, "suid": unix.MS_NOSUID, "sync": unix.MS_SYNCHRONOUS, } var ( flags int data []string ) for _, o := range options { if f, exist := flagsTable[o]; exist { flags |= f } else { data = append(data, o) } } return flags, strings.Join(data, ",") } func run(args cli.Args) error { margs, err := parseArgs(args.Slice()) if err != nil { return errors.Wrap(err, "parse mount options") } flags, data := parseOptions(margs.options) err = syscall.Mount(margs.fsType, margs.target, margs.fsType, uintptr(flags), data) if err != nil { return errors.Wrapf(err, "mount overlayfs by syscall") } return nil } func main() { app := &cli.App{ Name: "NydusOverlayfs", Usage: "FUSE mount helper for containerd to filter out Nydus specific options", Version: fmt.Sprintf("%s.%s", Version, BuildTime), UsageText: "[Usage]: nydus-overlayfs overlay -o ", Action: func(c *cli.Context) error { return run(c.Args()) }, Before: func(c *cli.Context) error { if c.NArg() != 4 { cli.ShowAppHelpAndExit(c, 1) } return nil }, } err := app.Run(os.Args) if err != nil { log.Fatal(err) } os.Exit(0) } nydus-snapshotter-0.13.4/cmd/optimizer-nri-plugin/000077500000000000000000000000001453374237200221725ustar00rootroot00000000000000nydus-snapshotter-0.13.4/cmd/optimizer-nri-plugin/main.go000066400000000000000000000156131453374237200234530ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package main import ( "context" "fmt" "io" "log/syslog" "os" "path/filepath" "strings" "time" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" "github.com/containerd/containerd/reference/docker" "github.com/containerd/nri/pkg/api" "github.com/containerd/nri/pkg/stub" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/pkg/fanotify" "github.com/containerd/nydus-snapshotter/version" "github.com/pelletier/go-toml" ) const ( defaultEvents = "StartContainer,StopContainer" defaultServerPath = "/usr/local/bin/optimizer-server" defaultPersistDir = "/opt/nri/optimizer/results" ) type PluginConfig struct { Events []string `toml:"events"` ServerPath string `toml:"server_path"` PersistDir string `toml:"persist_dir"` Readable bool `toml:"readable"` Timeout int `toml:"timeout"` Overwrite bool `toml:"overwrite"` } type PluginArgs struct { PluginName string PluginIdx string PluginEvents string Config PluginConfig } type Flags struct { Args *PluginArgs F []cli.Flag } func buildFlags(args *PluginArgs) []cli.Flag { return []cli.Flag{ &cli.StringFlag{ Name: "name", Usage: "plugin name to register to NRI", Destination: &args.PluginName, }, &cli.StringFlag{ Name: "idx", Usage: "plugin index to register to NRI", Destination: &args.PluginIdx, }, &cli.StringFlag{ Name: "events", Value: defaultEvents, Usage: "the events that containerd subscribes to. DO NOT CHANGE THIS.", Destination: &args.PluginEvents, }, &cli.StringFlag{ Name: "server-path", Value: defaultServerPath, Usage: "the path of optimizer server binary", Destination: &args.Config.ServerPath, }, &cli.StringFlag{ Name: "persist-dir", Value: defaultPersistDir, Usage: "the directory to persist accessed files list for container", Destination: &args.Config.PersistDir, }, &cli.BoolFlag{ Name: "readable", Value: false, Usage: "whether to make the csv file human readable", Destination: &args.Config.Readable, }, &cli.IntFlag{ Name: "timeout", Value: 0, Usage: "the timeout to kill optimizer server, 0 to disable it", Destination: &args.Config.Timeout, }, &cli.BoolFlag{ Name: "overwrite", Usage: "whether to overwrite the existed persistent files", Destination: &args.Config.Overwrite, }, } } func NewPluginFlags() *Flags { var args PluginArgs return &Flags{ Args: &args, F: buildFlags(&args), } } type plugin struct { stub stub.Stub mask stub.EventMask } var ( cfg PluginConfig log *logrus.Logger logWriter *syslog.Writer _ = stub.ConfigureInterface(&plugin{}) globalFanotifyServer = make(map[string]*fanotify.Server) ) const ( imageNameLabel = "io.kubernetes.cri.image-name" ) func (p *plugin) Configure(config, runtime, version string) (stub.EventMask, error) { log.Infof("got configuration data: %q from runtime %s %s", config, runtime, version) if config == "" { return p.mask, nil } tree, err := toml.Load(config) if err != nil { return 0, errors.Wrap(err, "parse TOML") } if err := tree.Unmarshal(&cfg); err != nil { return 0, err } p.mask, err = api.ParseEventMask(cfg.Events...) if err != nil { return 0, errors.Wrap(err, "parse events in configuration") } log.Infof("configuration: %#v", cfg) return p.mask, nil } func (p *plugin) StartContainer(_ *api.PodSandbox, container *api.Container) error { dir, imageName, err := GetImageName(container.Annotations) if err != nil { return err } persistDir := filepath.Join(cfg.PersistDir, dir) if err := os.MkdirAll(persistDir, os.ModePerm); err != nil { return err } persistFile := filepath.Join(persistDir, imageName) if cfg.Timeout > 0 { persistFile = fmt.Sprintf("%s.timeout%ds", persistFile, cfg.Timeout) } fanotifyServer := fanotify.NewServer(cfg.ServerPath, container.Pid, imageName, persistFile, cfg.Readable, cfg.Overwrite, time.Duration(cfg.Timeout)*time.Second, logWriter) if err := fanotifyServer.RunServer(); err != nil { return err } globalFanotifyServer[imageName] = fanotifyServer return nil } func (p *plugin) StopContainer(_ *api.PodSandbox, container *api.Container) ([]*api.ContainerUpdate, error) { var update = []*api.ContainerUpdate{} _, imageName, err := GetImageName(container.Annotations) if err != nil { return update, err } if fanotifyServer, ok := globalFanotifyServer[imageName]; ok { fanotifyServer.StopServer() } else { return nil, errors.New("can not find fanotify server for container image " + imageName) } return update, nil } func GetImageName(annotations map[string]string) (string, string, error) { named, err := docker.ParseDockerRef(annotations[imageNameLabel]) if err != nil { return "", "", err } nameTagged := named.(docker.NamedTagged) repo := docker.Path(nameTagged) dir := filepath.Dir(repo) image := filepath.Base(repo) imageName := image + ":" + nameTagged.Tag() return dir, imageName, nil } func (p *plugin) onClose() { for _, fanotifyServer := range globalFanotifyServer { fanotifyServer.StopServer() } os.Exit(0) } func main() { flags := NewPluginFlags() app := &cli.App{ Name: "optimizer-nri-plugin", Usage: "Optimizer client for NRI plugin to manage optimizer server", Version: version.Version, Flags: flags.F, HideVersion: true, Action: func(c *cli.Context) error { var ( opts []stub.Option err error ) cfg = flags.Args.Config log = logrus.StandardLogger() log.SetFormatter(&logrus.TextFormatter{ PadLevelText: true, }) logWriter, err = syslog.New(syslog.LOG_INFO, "optimizer-nri-plugin") if err == nil { log.SetOutput(io.MultiWriter(os.Stdout, logWriter)) } if flags.Args.PluginName != "" { opts = append(opts, stub.WithPluginName(flags.Args.PluginName)) } if flags.Args.PluginIdx != "" { opts = append(opts, stub.WithPluginIdx(flags.Args.PluginIdx)) } p := &plugin{} if p.mask, err = api.ParseEventMask(flags.Args.PluginEvents); err != nil { log.Fatalf("failed to parse events: %v", err) } cfg.Events = strings.Split(flags.Args.PluginEvents, ",") if p.stub, err = stub.New(p, append(opts, stub.WithOnClose(p.onClose))...); err != nil { log.Fatalf("failed to create plugin stub: %v", err) } err = p.stub.Run(context.Background()) if err != nil { log.Errorf("plugin exited with error %v", err) os.Exit(1) } return nil }, } if err := app.Run(os.Args); err != nil { if errdefs.IsConnectionClosed(err) { log.Info("optimizer NRI plugin exited") } else { log.WithError(err).Fatal("failed to start optimizer NRI plugin") } } } nydus-snapshotter-0.13.4/cmd/prefetchfiles-nri-plugin/000077500000000000000000000000001453374237200227735ustar00rootroot00000000000000nydus-snapshotter-0.13.4/cmd/prefetchfiles-nri-plugin/main.go000066400000000000000000000115051453374237200242500ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package main import ( "context" "fmt" "io" "log/syslog" "net" "net/http" "os" "path/filepath" "strings" "github.com/containerd/nri/pkg/api" "github.com/containerd/nri/pkg/stub" "github.com/pelletier/go-toml" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/version" ) const ( endpointPrefetch = "/api/v1/prefetch" defaultEvents = "RunPodSandbox" defaultSystemControllerAddress = "/run/containerd-nydus/system.sock" defaultPrefetchConfigDir = "/etc/nydus" nydusPrefetchAnnotation = "containerd.io/nydus-prefetch" ) type PluginArgs struct { PluginName string PluginIdx string SocketAddress string } type Flags struct { Args *PluginArgs Flag []cli.Flag } func buildFlags(args *PluginArgs) []cli.Flag { return []cli.Flag{ &cli.StringFlag{ Name: "name", Usage: "plugin name to register to NRI", Destination: &args.PluginName, }, &cli.StringFlag{ Name: "idx", Usage: "plugin index to register to NRI", Destination: &args.PluginIdx, }, &cli.StringFlag{ Name: "socket-addr", Value: defaultSystemControllerAddress, Usage: "unix domain socket address. If defined in the configuration file, there is no need to add ", Destination: &args.SocketAddress, }, } } func NewPluginFlags() *Flags { var args PluginArgs return &Flags{ Args: &args, Flag: buildFlags(&args), } } type plugin struct { stub stub.Stub mask stub.EventMask } var ( globalSocket string log *logrus.Logger logWriter *syslog.Writer ) // sendDataOverHTTP sends the prefetch data to the specified endpoint over HTTP using a Unix socket. func sendDataOverHTTP(data string, endpoint, sock string) error { url := fmt.Sprintf("http://unix%s", endpoint) req, err := http.NewRequest(http.MethodPut, url, strings.NewReader(data)) if err != nil { return err } client := &http.Client{ Transport: &http.Transport{ DialContext: func(_ context.Context, _, _ string) (net.Conn, error) { return net.Dial("unix", sock) }, }, } resp, err := client.Do(req) if err != nil { return err } if resp.StatusCode != http.StatusOK { return fmt.Errorf("failed to send data, status code: %d", resp.StatusCode) } resp.Body.Close() return nil } func (p *plugin) RunPodSandbox(pod *api.PodSandbox) error { prefetchList, ok := pod.Annotations[nydusPrefetchAnnotation] if !ok { return nil } err := sendDataOverHTTP(prefetchList, endpointPrefetch, globalSocket) if err != nil { log.Errorf("failed to send data: %v", err) return err } return nil } func main() { flags := NewPluginFlags() app := &cli.App{ Name: "prefetch-nri-plugin", Usage: "NRI plugin for obtaining and transmitting prefetch files path", Version: version.Version, Flags: flags.Flag, HideVersion: true, Action: func(c *cli.Context) error { var ( opts []stub.Option err error ) log = logrus.StandardLogger() configFileName := "prefetchConfig.toml" configDir := defaultPrefetchConfigDir configFilePath := filepath.Join(configDir, configFileName) config, err := toml.LoadFile(configFilePath) if err != nil { log.Warnf("failed to read config file: %v", err) } configSocketAddrRaw := config.Get("file_prefetch.socket_address") if configSocketAddrRaw != nil { if configSocketAddr, ok := configSocketAddrRaw.(string); ok { globalSocket = configSocketAddr } else { log.Warnf("failed to read config: 'file_prefetch.socket_address' is not a string") } } else { globalSocket = flags.Args.SocketAddress } log.SetFormatter(&logrus.TextFormatter{ PadLevelText: true, }) logWriter, err = syslog.New(syslog.LOG_INFO, "prefetch-nri-plugin") if err == nil { log.SetOutput(io.MultiWriter(os.Stdout, logWriter)) } if flags.Args.PluginName != "" { opts = append(opts, stub.WithPluginName(flags.Args.PluginName)) } if flags.Args.PluginIdx != "" { opts = append(opts, stub.WithPluginIdx(flags.Args.PluginIdx)) } p := &plugin{} if p.mask, err = api.ParseEventMask(defaultEvents); err != nil { log.Fatalf("failed to parse events: %v", err) } if p.stub, err = stub.New(p, opts...); err != nil { log.Fatalf("failed to create plugin stub: %v", err) } err = p.stub.Run(context.Background()) if err != nil { return errors.Wrap(err, "plugin exited") } return nil }, } if err := app.Run(os.Args); err != nil { if errdefs.IsConnectionClosed(err) { log.Info("prefetch NRI plugin exited") } else { log.WithError(err).Fatal("failed to start prefetch NRI plugin") } } } nydus-snapshotter-0.13.4/config/000077500000000000000000000000001453374237200165705ustar00rootroot00000000000000nydus-snapshotter-0.13.4/config/config.go000066400000000000000000000267461453374237200204030ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package config import ( "os" "github.com/imdario/mergo" "github.com/pelletier/go-toml" "github.com/pkg/errors" "github.com/containerd/nydus-snapshotter/internal/constant" "github.com/containerd/nydus-snapshotter/internal/flags" "github.com/containerd/nydus-snapshotter/pkg/cgroup" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/pkg/utils/file" "github.com/containerd/nydus-snapshotter/pkg/utils/parser" "github.com/containerd/nydus-snapshotter/pkg/utils/sysinfo" ) func init() { recoverPolicyParser = map[string]DaemonRecoverPolicy{ RecoverPolicyNone.String(): RecoverPolicyNone, RecoverPolicyRestart.String(): RecoverPolicyRestart, RecoverPolicyFailover.String(): RecoverPolicyFailover} } // Define a policy how to fork nydusd daemon and attach file system instances to serve. type DaemonMode string const ( // Spawn a dedicated nydusd for each RAFS instance. DaemonModeMultiple DaemonMode = DaemonMode(constant.DaemonModeMultiple) // Spawn a dedicated nydusd for each RAFS instance. DaemonModeDedicated DaemonMode = DaemonMode(constant.DaemonModeDedicated) // Share a global nydusd to serve all RAFS instances. DaemonModeShared DaemonMode = DaemonMode(constant.DaemonModeShared) // Do not spawn nydusd for RAFS instances. // // For tarfs and rund, there's no need to create nydusd to serve RAFS instances, // the snapshotter just returns mount slices with additional information for runC/runD // to manage those snapshots. DaemonModeNone DaemonMode = DaemonMode(constant.DaemonModeNone) DaemonModeInvalid DaemonMode = DaemonMode(constant.DaemonModeInvalid) ) func parseDaemonMode(m string) (DaemonMode, error) { switch m { case string(DaemonModeMultiple): return DaemonModeDedicated, nil case string(DaemonModeDedicated): return DaemonModeDedicated, nil case string(DaemonModeShared): return DaemonModeShared, nil case string(DaemonModeNone): return DaemonModeNone, nil default: return DaemonModeInvalid, errors.Errorf("invalid daemon mode %q", m) } } type DaemonRecoverPolicy int const ( RecoverPolicyInvalid DaemonRecoverPolicy = iota RecoverPolicyNone RecoverPolicyRestart RecoverPolicyFailover ) func (p DaemonRecoverPolicy) String() string { switch p { case RecoverPolicyNone: return "none" case RecoverPolicyRestart: return "restart" case RecoverPolicyFailover: return "failover" case RecoverPolicyInvalid: fallthrough default: return "" } } var recoverPolicyParser map[string]DaemonRecoverPolicy func ParseRecoverPolicy(p string) (DaemonRecoverPolicy, error) { policy, ok := recoverPolicyParser[p] if !ok { return RecoverPolicyInvalid, errors.Errorf("invalid recover policy %q", p) } return policy, nil } const ( FsDriverBlockdev string = constant.FsDriverBlockdev FsDriverFusedev string = constant.FsDriverFusedev FsDriverFscache string = constant.FsDriverFscache FsDriverNodev string = constant.FsDriverNodev FsDriverProxy string = constant.FsDriverProxy ) type Experimental struct { EnableStargz bool `toml:"enable_stargz"` EnableReferrerDetect bool `toml:"enable_referrer_detect"` TarfsConfig TarfsConfig `toml:"tarfs"` } type TarfsConfig struct { EnableTarfs bool `toml:"enable_tarfs"` MountTarfsOnHost bool `toml:"mount_tarfs_on_host"` TarfsHint bool `toml:"tarfs_hint"` MaxConcurrentProc int `toml:"max_concurrent_proc"` ExportMode string `toml:"export_mode"` } type CgroupConfig struct { Enable bool `toml:"enable"` MemoryLimit string `toml:"memory_limit"` } // Configure how to start and recover nydusd daemons type DaemonConfig struct { NydusdPath string `toml:"nydusd_path"` NydusdConfigPath string `toml:"nydusd_config"` NydusImagePath string `toml:"nydusimage_path"` RecoverPolicy string `toml:"recover_policy"` FsDriver string `toml:"fs_driver"` ThreadsNumber int `toml:"threads_number"` LogRotationSize int `toml:"log_rotation_size"` } type LoggingConfig struct { LogToStdout bool `toml:"log_to_stdout"` LogLevel string `toml:"level"` LogDir string `toml:"dir"` RotateLogMaxSize int `toml:"log_rotation_max_size"` RotateLogMaxBackups int `toml:"log_rotation_max_backups"` RotateLogMaxAge int `toml:"log_rotation_max_age"` RotateLogLocalTime bool `toml:"log_rotation_local_time"` RotateLogCompress bool `toml:"log_rotation_compress"` } // Nydus image layers additional process type ImageConfig struct { PublicKeyFile string `toml:"public_key_file"` ValidateSignature bool `toml:"validate_signature"` } // Configure containerd snapshots interfaces and how to process the snapshots // requests from containerd type SnapshotConfig struct { EnableNydusOverlayFS bool `toml:"enable_nydus_overlayfs"` EnableKataVolume bool `toml:"enable_kata_volume"` SyncRemove bool `toml:"sync_remove"` } // Configure cache manager that manages the cache files lifecycle type CacheManagerConfig struct { Disable bool `toml:"disable"` // Trigger GC gc_period after the specified period. // Example format: 24h, 120min GCPeriod string `toml:"gc_period"` CacheDir string `toml:"cache_dir"` } // Configure how nydus-snapshotter receive auth information type AuthConfig struct { // based on kubeconfig or ServiceAccount EnableKubeconfigKeychain bool `toml:"enable_kubeconfig_keychain"` KubeconfigPath string `toml:"kubeconfig_path"` // CRI proxy mode EnableCRIKeychain bool `toml:"enable_cri_keychain"` ImageServiceAddress string `toml:"image_service_address"` } // Configure remote storage like container registry type RemoteConfig struct { AuthConfig AuthConfig `toml:"auth"` ConvertVpcRegistry bool `toml:"convert_vpc_registry"` SkipSSLVerify bool `toml:"skip_ssl_verify"` MirrorsConfig MirrorsConfig `toml:"mirrors_config"` } type MirrorsConfig struct { Dir string `toml:"dir"` } type MetricsConfig struct { Address string `toml:"address"` } type DebugConfig struct { ProfileDuration int64 `toml:"daemon_cpu_profile_duration_secs"` PprofAddress string `toml:"pprof_address"` } type SystemControllerConfig struct { Enable bool `toml:"enable"` Address string `toml:"address"` DebugConfig DebugConfig `toml:"debug"` } type SnapshotterConfig struct { // Configuration format version Version int `toml:"version"` // Snapshotter's root work directory Root string `toml:"root"` Address string `toml:"address"` DaemonMode string `toml:"daemon_mode"` // Clean up all the resources when snapshotter is closed CleanupOnClose bool `toml:"cleanup_on_close"` SystemControllerConfig SystemControllerConfig `toml:"system"` MetricsConfig MetricsConfig `toml:"metrics"` DaemonConfig DaemonConfig `toml:"daemon"` SnapshotsConfig SnapshotConfig `toml:"snapshot"` RemoteConfig RemoteConfig `toml:"remote"` ImageConfig ImageConfig `toml:"image"` CacheManagerConfig CacheManagerConfig `toml:"cache_manager"` LoggingConfig LoggingConfig `toml:"log"` CgroupConfig CgroupConfig `toml:"cgroup"` Experimental Experimental `toml:"experimental"` } func LoadSnapshotterConfig(path string) (*SnapshotterConfig, error) { var config SnapshotterConfig // get nydus-snapshotter configuration from specified path of toml file if path == "" { return nil, errors.New("snapshotter configuration path cannot be empty") } tree, err := toml.LoadFile(path) if err != nil { return nil, errors.Wrapf(err, "load toml configuration from file %q", path) } if err = tree.Unmarshal(&config); err != nil { return nil, errors.Wrap(err, "unmarshal snapshotter configuration") } if config.Version != 1 { return nil, errors.Errorf("unsupported configuration version %d", config.Version) } return &config, nil } func MergeConfig(to, from *SnapshotterConfig) error { err := mergo.Merge(to, from) if err != nil { return err } return nil } func ValidateConfig(c *SnapshotterConfig) error { if c == nil { return errors.Wrapf(errdefs.ErrInvalidArgument, "configuration is none") } if c.ImageConfig.ValidateSignature { if c.ImageConfig.PublicKeyFile == "" { return errors.New("public key file for signature validation is not provided") } else if _, err := os.Stat(c.ImageConfig.PublicKeyFile); err != nil { return errors.Wrapf(err, "check publicKey file %q", c.ImageConfig.PublicKeyFile) } } if len(c.Root) == 0 { return errors.New("empty root directory") } if c.DaemonConfig.FsDriver != FsDriverFscache && c.DaemonConfig.FsDriver != FsDriverFusedev && c.DaemonConfig.FsDriver != FsDriverBlockdev && c.DaemonConfig.FsDriver != FsDriverNodev && c.DaemonConfig.FsDriver != FsDriverProxy { return errors.Errorf("invalid filesystem driver %q", c.DaemonConfig.FsDriver) } if _, err := ParseRecoverPolicy(c.DaemonConfig.RecoverPolicy); err != nil { return err } if c.DaemonConfig.ThreadsNumber > 1024 { return errors.Errorf("nydusd worker thread number %d is too big, max 1024", c.DaemonConfig.ThreadsNumber) } if c.RemoteConfig.AuthConfig.EnableCRIKeychain && c.RemoteConfig.AuthConfig.EnableKubeconfigKeychain { return errors.Wrapf(errdefs.ErrInvalidArgument, "\"enable_cri_keychain\" and \"enable_kubeconfig_keychain\" can't be set at the same time") } if c.RemoteConfig.MirrorsConfig.Dir != "" { dirExisted, err := file.IsDirExisted(c.RemoteConfig.MirrorsConfig.Dir) if err != nil { return err } if !dirExisted { return errors.Errorf("mirrors config directory %s does not exist", c.RemoteConfig.MirrorsConfig.Dir) } } return nil } // Parse command line arguments and fill the nydus-snapshotter configuration // Always let options from CLI override those from configuration file. func ParseParameters(args *flags.Args, cfg *SnapshotterConfig) error { // --- essential configuration if args.Address != "" { cfg.Address = args.Address } if args.RootDir != "" { cfg.Root = args.RootDir } // Give --shared-daemon higher priority if args.DaemonMode != "" { cfg.DaemonMode = args.DaemonMode } // --- image processor configuration // empty // --- daemon configuration daemonConfig := &cfg.DaemonConfig if args.NydusdConfigPath != "" { daemonConfig.NydusdConfigPath = args.NydusdConfigPath } if args.NydusdPath != "" { daemonConfig.NydusdPath = args.NydusdPath } if args.NydusImagePath != "" { daemonConfig.NydusImagePath = args.NydusImagePath } if args.FsDriver != "" { daemonConfig.FsDriver = args.FsDriver } // --- cache manager configuration // empty // --- logging configuration logConfig := &cfg.LoggingConfig if args.LogLevel != "" { logConfig.LogLevel = args.LogLevel } if args.LogToStdoutCount > 0 { logConfig.LogToStdout = args.LogToStdout } // --- remote storage configuration // empty // --- snapshot configuration // empty // --- metrics configuration // empty return nil } func ParseCgroupConfig(config CgroupConfig) (cgroup.Config, error) { totalMemory, err := sysinfo.GetTotalMemoryBytes() if err != nil { return cgroup.Config{}, errors.Wrap(err, "Failed to get total memory bytes") } memoryLimitInBytes, err := parser.MemoryConfigToBytes(config.MemoryLimit, totalMemory) if err != nil { return cgroup.Config{}, err } return cgroup.Config{ MemoryLimitInBytes: memoryLimitInBytes, }, nil } nydus-snapshotter-0.13.4/config/config_test.go000066400000000000000000000173351453374237200214340ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package config import ( "path/filepath" "testing" "time" "github.com/containerd/nydus-snapshotter/internal/constant" "github.com/containerd/nydus-snapshotter/internal/flags" "github.com/stretchr/testify/assert" ) func TestLoadSnapshotterTOMLConfig(t *testing.T) { A := assert.New(t) cfg, err := LoadSnapshotterConfig("../misc/snapshotter/config.toml") A.NoError(err) exampleConfig := SnapshotterConfig{ Version: 1, Root: "/var/lib/containerd-nydus", Address: "/run/containerd-nydus/containerd-nydus-grpc.sock", DaemonMode: "dedicated", Experimental: Experimental{ EnableStargz: false, EnableReferrerDetect: false, }, CleanupOnClose: false, SystemControllerConfig: SystemControllerConfig{ Enable: true, Address: "/run/containerd-nydus/system.sock", DebugConfig: DebugConfig{ ProfileDuration: 5, PprofAddress: "", }, }, DaemonConfig: DaemonConfig{ NydusdPath: "/usr/local/bin/nydusd", NydusImagePath: "/usr/local/bin/nydus-image", FsDriver: "fusedev", RecoverPolicy: "restart", NydusdConfigPath: "/etc/nydus/nydusd-config.fusedev.json", ThreadsNumber: 4, LogRotationSize: 100, }, SnapshotsConfig: SnapshotConfig{ EnableNydusOverlayFS: false, SyncRemove: false, }, RemoteConfig: RemoteConfig{ ConvertVpcRegistry: false, AuthConfig: AuthConfig{ EnableKubeconfigKeychain: false, KubeconfigPath: "", }, MirrorsConfig: MirrorsConfig{ Dir: "", }, }, ImageConfig: ImageConfig{ PublicKeyFile: "", ValidateSignature: false, }, CacheManagerConfig: CacheManagerConfig{ Disable: false, GCPeriod: "24h", CacheDir: "", }, LoggingConfig: LoggingConfig{ LogLevel: "info", RotateLogCompress: true, RotateLogLocalTime: true, RotateLogMaxAge: 7, RotateLogMaxBackups: 5, RotateLogMaxSize: 100, LogToStdout: false, }, MetricsConfig: MetricsConfig{ Address: ":9110", }, CgroupConfig: CgroupConfig{ Enable: true, MemoryLimit: "", }, } A.EqualValues(cfg, &exampleConfig) var args = flags.Args{} args.RootDir = "/var/lib/containerd/nydus" exampleConfig.Root = "/var/lib/containerd/nydus" err = ParseParameters(&args, cfg) A.NoError(err) A.EqualValues(cfg, &exampleConfig) A.EqualValues(cfg.LoggingConfig.LogToStdout, false) args.LogToStdout = true args.LogToStdoutCount = 1 err = ParseParameters(&args, cfg) A.NoError(err) A.EqualValues(cfg.LoggingConfig.LogToStdout, true) err = ProcessConfigurations(cfg) A.NoError(err) A.Equal(GetCacheGCPeriod(), time.Hour*24) } func TestSnapshotterConfig(t *testing.T) { A := assert.New(t) var cfg SnapshotterConfig var args flags.Args // The log_to_stdout is false in toml file without --log-to-stdout flag. // Expected false. cfg.LoggingConfig.LogToStdout = false args.LogToStdoutCount = 0 err := ParseParameters(&args, &cfg) A.NoError(err) A.EqualValues(cfg.LoggingConfig.LogToStdout, false) // The log_to_stdout is true in toml file without --log-to-stdout flag. // Expected true. // This case is failed. cfg.LoggingConfig.LogToStdout = true args.LogToStdoutCount = 0 err = ParseParameters(&args, &cfg) A.NoError(err) A.EqualValues(cfg.LoggingConfig.LogToStdout, true) // The log_to_stdout is false in toml file with --log-to-stdout=true. // Expected true (command flag has higher priority). args.LogToStdout = true args.LogToStdoutCount = 1 cfg.LoggingConfig.LogToStdout = false err = ParseParameters(&args, &cfg) A.NoError(err) A.EqualValues(cfg.LoggingConfig.LogToStdout, true) // The log_to_stdout is true in toml file with --log-to-stdout=true. // Expected true (command flag has higher priority). args.LogToStdout = true args.LogToStdoutCount = 1 cfg.LoggingConfig.LogToStdout = true err = ParseParameters(&args, &cfg) A.NoError(err) A.EqualValues(cfg.LoggingConfig.LogToStdout, true) // The log_to_stdout is false in toml file with --log-to-stdout=false. // Expected false (command flag has higher priority). args.LogToStdout = false args.LogToStdoutCount = 1 cfg.LoggingConfig.LogToStdout = false err = ParseParameters(&args, &cfg) A.NoError(err) A.EqualValues(cfg.LoggingConfig.LogToStdout, false) // The log_to_stdout is true in toml file with --log-to-stdout=false. // Expected false (command flag has higher priority). args.LogToStdout = false args.LogToStdoutCount = 1 cfg.LoggingConfig.LogToStdout = true err = ParseParameters(&args, &cfg) A.NoError(err) A.EqualValues(cfg.LoggingConfig.LogToStdout, false) } func TestMergeConfig(t *testing.T) { A := assert.New(t) var defaultSnapshotterConfig SnapshotterConfig var snapshotterConfig1 SnapshotterConfig err := defaultSnapshotterConfig.FillUpWithDefaults() A.NoError(err) err = MergeConfig(&snapshotterConfig1, &defaultSnapshotterConfig) A.NoError(err) A.Equal(snapshotterConfig1.Root, constant.DefaultRootDir) A.Equal(snapshotterConfig1.LoggingConfig.LogDir, "") A.Equal(snapshotterConfig1.CacheManagerConfig.CacheDir, "") A.Equal(snapshotterConfig1.DaemonMode, constant.DefaultDaemonMode) A.Equal(snapshotterConfig1.SystemControllerConfig.Address, constant.DefaultSystemControllerAddress) A.Equal(snapshotterConfig1.LoggingConfig.LogLevel, constant.DefaultLogLevel) A.Equal(snapshotterConfig1.LoggingConfig.RotateLogMaxSize, constant.DefaultRotateLogMaxSize) A.Equal(snapshotterConfig1.LoggingConfig.RotateLogMaxBackups, constant.DefaultRotateLogMaxBackups) A.Equal(snapshotterConfig1.LoggingConfig.RotateLogMaxAge, constant.DefaultRotateLogMaxAge) A.Equal(snapshotterConfig1.LoggingConfig.RotateLogCompress, constant.DefaultRotateLogCompress) A.Equal(snapshotterConfig1.DaemonConfig.NydusdConfigPath, constant.DefaultNydusDaemonConfigPath) A.Equal(snapshotterConfig1.DaemonConfig.RecoverPolicy, RecoverPolicyRestart.String()) A.Equal(snapshotterConfig1.CacheManagerConfig.GCPeriod, constant.DefaultGCPeriod) var snapshotterConfig2 SnapshotterConfig snapshotterConfig2.Root = "/snapshotter/root" err = MergeConfig(&snapshotterConfig2, &defaultSnapshotterConfig) A.NoError(err) A.Equal(snapshotterConfig2.Root, "/snapshotter/root") A.Equal(snapshotterConfig2.LoggingConfig.LogDir, "") A.Equal(snapshotterConfig2.CacheManagerConfig.CacheDir, "") } func TestProcessConfigurations(t *testing.T) { A := assert.New(t) var defaultSnapshotterConfig SnapshotterConfig var snapshotterConfig1 SnapshotterConfig err := defaultSnapshotterConfig.FillUpWithDefaults() A.NoError(err) err = MergeConfig(&snapshotterConfig1, &defaultSnapshotterConfig) A.NoError(err) err = ValidateConfig(&snapshotterConfig1) A.NoError(err) err = ProcessConfigurations(&snapshotterConfig1) A.NoError(err) A.Equal(snapshotterConfig1.LoggingConfig.LogDir, filepath.Join(snapshotterConfig1.Root, "logs")) A.Equal(snapshotterConfig1.CacheManagerConfig.CacheDir, filepath.Join(snapshotterConfig1.Root, "cache")) var snapshotterConfig2 SnapshotterConfig snapshotterConfig2.Root = "/snapshotter/root" err = MergeConfig(&snapshotterConfig2, &defaultSnapshotterConfig) A.NoError(err) err = ValidateConfig(&snapshotterConfig2) A.NoError(err) err = ProcessConfigurations(&snapshotterConfig2) A.NoError(err) A.Equal(snapshotterConfig2.LoggingConfig.LogDir, filepath.Join(snapshotterConfig2.Root, "logs")) A.Equal(snapshotterConfig2.CacheManagerConfig.CacheDir, filepath.Join(snapshotterConfig2.Root, "cache")) var snapshotterConfig3 SnapshotterConfig snapshotterConfig3.Root = "./snapshotter/root" err = MergeConfig(&snapshotterConfig3, &defaultSnapshotterConfig) A.NoError(err) err = ValidateConfig(&snapshotterConfig3) A.NoError(err) err = ProcessConfigurations(&snapshotterConfig3) A.NoError(err) } nydus-snapshotter-0.13.4/config/daemonconfig/000077500000000000000000000000001453374237200212215ustar00rootroot00000000000000nydus-snapshotter-0.13.4/config/daemonconfig/daemonconfig.go000066400000000000000000000133331453374237200242040ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package daemonconfig import ( "encoding/json" "os" "github.com/pkg/errors" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/pkg/auth" "github.com/containerd/nydus-snapshotter/pkg/utils/registry" ) type StorageBackendType = string const ( backendTypeLocalfs StorageBackendType = "localfs" backendTypeOss StorageBackendType = "oss" backendTypeRegistry StorageBackendType = "registry" ) type DaemonConfig interface { // Provide stuffs relevant to accessing registry apart from auth Supplement(host, repo, snapshotID string, params map[string]string) // Provide auth FillAuth(kc *auth.PassKeyChain) StorageBackend() (StorageBackendType, *BackendConfig) UpdateMirrors(mirrorsConfigDir, registryHost string) error DumpString() (string, error) DumpFile(path string) error } // Daemon configurations factory func NewDaemonConfig(fsDriver, path string) (DaemonConfig, error) { switch fsDriver { case config.FsDriverFscache: cfg, err := LoadFscacheConfig(path) if err != nil { return nil, err } return cfg, nil case config.FsDriverFusedev: cfg, err := LoadFuseConfig(path) if err != nil { return nil, err } return cfg, nil default: return nil, errors.Errorf("unsupported, fs driver %q", fsDriver) } } type MirrorConfig struct { Host string `json:"host,omitempty"` Headers map[string]string `json:"headers,omitempty"` HealthCheckInterval int `json:"health_check_interval,omitempty"` FailureLimit uint8 `json:"failure_limit,omitempty"` PingURL string `json:"ping_url,omitempty"` } type BackendConfig struct { // Localfs backend configs BlobFile string `json:"blob_file,omitempty"` Dir string `json:"dir,omitempty"` ReadAhead bool `json:"readahead"` ReadAheadSec int `json:"readahead_sec,omitempty"` // Registry backend configs Host string `json:"host,omitempty"` Repo string `json:"repo,omitempty"` Auth string `json:"auth,omitempty"` RegistryToken string `json:"registry_token,omitempty"` BlobURLScheme string `json:"blob_url_scheme,omitempty"` BlobRedirectedHost string `json:"blob_redirected_host,omitempty"` Mirrors []MirrorConfig `json:"mirrors,omitempty"` // OSS backend configs EndPoint string `json:"endpoint,omitempty"` AccessKeyID string `json:"access_key_id,omitempty"` AccessKeySecret string `json:"access_key_secret,omitempty"` BucketName string `json:"bucket_name,omitempty"` ObjectPrefix string `json:"object_prefix,omitempty"` // Shared by registry and oss backend Scheme string `json:"scheme,omitempty"` SkipVerify bool `json:"skip_verify,omitempty"` // Below configs are common configs shared by all backends Proxy struct { URL string `json:"url,omitempty"` Fallback bool `json:"fallback"` PingURL string `json:"ping_url,omitempty"` CheckInterval int `json:"check_interval,omitempty"` UseHTTP bool `json:"use_http,omitempty"` } `json:"proxy,omitempty"` Timeout int `json:"timeout,omitempty"` ConnectTimeout int `json:"connect_timeout,omitempty"` RetryLimit int `json:"retry_limit,omitempty"` } type DeviceConfig struct { Backend struct { BackendType string `json:"type"` Config BackendConfig `json:"config"` } `json:"backend"` Cache struct { CacheType string `json:"type"` Compressed bool `json:"compressed,omitempty"` Config struct { WorkDir string `json:"work_dir"` DisableIndexedMap bool `json:"disable_indexed_map"` } `json:"config"` } `json:"cache"` } // For nydusd as FUSE daemon. Serialize Daemon info and persist to a json file // We don't have to persist configuration file for fscache since its configuration // is passed through HTTP API. func DumpConfigFile(c interface{}, path string) error { b, err := json.Marshal(c) if err != nil { return errors.Wrapf(err, "marshal config") } return os.WriteFile(path, b, 0600) } func DumpConfigString(c interface{}) (string, error) { b, err := json.Marshal(c) return string(b), err } // Achieve a daemon configuration from template or snapshotter's configuration func SupplementDaemonConfig(c DaemonConfig, imageID, snapshotID string, vpcRegistry bool, labels map[string]string, params map[string]string) error { image, err := registry.ParseImage(imageID) if err != nil { return errors.Wrapf(err, "parse image %s", imageID) } backendType, _ := c.StorageBackend() switch backendType { case backendTypeRegistry: registryHost := image.Host if vpcRegistry { registryHost = registry.ConvertToVPCHost(registryHost) } else if registryHost == "docker.io" { // For docker.io images, we should use index.docker.io registryHost = "index.docker.io" } if err := c.UpdateMirrors(config.GetMirrorsConfigDir(), registryHost); err != nil { return errors.Wrap(err, "update mirrors config") } // If no auth is provided, don't touch auth from provided nydusd configuration file. // We don't validate the original nydusd auth from configuration file since it can be empty // when repository is public. keyChain := auth.GetRegistryKeyChain(registryHost, imageID, labels) c.Supplement(registryHost, image.Repo, snapshotID, params) c.FillAuth(keyChain) // Localfs and OSS backends don't need any update, // just use the provided config in template case backendTypeLocalfs: case backendTypeOss: default: return errors.Errorf("unknown backend type %s", backendType) } return nil } nydus-snapshotter-0.13.4/config/daemonconfig/daemonconfig_test.go000066400000000000000000000030051453374237200252360ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package daemonconfig import ( "encoding/json" "testing" "github.com/stretchr/testify/require" ) func TestLoadConfig(t *testing.T) { buf := []byte(`{ "device": { "backend": { "type": "registry", "config": { "skip_verify": true, "host": "acr-nydus-registry-vpc.cn-hangzhou.cr.aliyuncs.com", "repo": "test/myserver", "auth": "", "blob_url_scheme": "http", "proxy": { "url": "http://p2p-proxy:65001", "fallback": true, "ping_url": "http://p2p-proxy:40901/server/ping", "check_interval": 5 }, "timeout": 5, "connect_timeout": 5, "retry_limit": 0 } }, "cache": { "type": "blobcache", "config": { "work_dir": "/cache" } } }, "mode": "direct", "digest_validate": true, "iostats_files": true, "enable_xattr": true, "fs_prefetch": { "enable": true, "threads_count": 10, "merging_size": 131072 } }`) var cfg FuseDaemonConfig err := json.Unmarshal(buf, &cfg) require.Nil(t, err) require.Equal(t, cfg.FSPrefetch.Enable, true) require.Equal(t, cfg.FSPrefetch.MergingSize, 131072) require.Equal(t, cfg.FSPrefetch.ThreadsCount, 10) require.Equal(t, cfg.Device.Backend.Config.BlobURLScheme, "http") require.Equal(t, cfg.Device.Backend.Config.SkipVerify, true) require.Equal(t, cfg.Device.Backend.Config.Proxy.CheckInterval, 5) } nydus-snapshotter-0.13.4/config/daemonconfig/fscache.go000066400000000000000000000063761453374237200231600ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package daemonconfig import ( "encoding/json" "os" "path" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/auth" "github.com/containerd/nydus-snapshotter/pkg/utils/erofs" "github.com/pkg/errors" ) const ( WorkDir string = "workdir" Bootstrap string = "bootstrap" ) type BlobPrefetchConfig struct { Enable bool `json:"enable"` ThreadsCount int `json:"threads_count"` MergingSize int `json:"merging_size"` BandwidthRate int `json:"bandwidth_rate"` } type FscacheDaemonConfig struct { // These fields is only for fscache daemon. Type string `json:"type"` // Snapshotter fills ID string `json:"id"` DomainID string `json:"domain_id"` Config *struct { ID string `json:"id"` BackendType string `json:"backend_type"` BackendConfig BackendConfig `json:"backend_config"` CacheType string `json:"cache_type"` // Snapshotter fills CacheConfig struct { WorkDir string `json:"work_dir"` } `json:"cache_config"` BlobPrefetchConfig BlobPrefetchConfig `json:"prefetch_config"` MetadataPath string `json:"metadata_path"` } `json:"config"` } // Load Fscache configuration template file func LoadFscacheConfig(p string) (*FscacheDaemonConfig, error) { var cfg FscacheDaemonConfig b, err := os.ReadFile(p) if err != nil { return nil, errors.Wrapf(err, "read fscache configuration file %s", p) } if err = json.Unmarshal(b, &cfg); err != nil { return nil, errors.Wrapf(err, "unmarshal") } if cfg.Config == nil { return nil, errors.New("invalid fscache configuration") } return &cfg, nil } func (c *FscacheDaemonConfig) UpdateMirrors(mirrorsConfigDir, registryHost string) error { mirrors, err := LoadMirrorsConfig(mirrorsConfigDir, registryHost) if err != nil { return err } if len(mirrors) > 0 { c.Config.BackendConfig.Mirrors = mirrors } return nil } func (c *FscacheDaemonConfig) StorageBackend() (string, *BackendConfig) { return c.Config.BackendType, &c.Config.BackendConfig } // Each fscache/erofs has a configuration with different fscache ID built from snapshot ID. func (c *FscacheDaemonConfig) Supplement(host, repo, snapshotID string, params map[string]string) { c.Config.BackendConfig.Host = host c.Config.BackendConfig.Repo = repo fscacheID := erofs.FscacheID(snapshotID) c.ID = fscacheID if c.DomainID != "" { log.L.Warnf("Linux Kernel Shared Domain feature in use. make sure your kernel version >= 6.1") } else { c.DomainID = fscacheID } c.Config.ID = fscacheID if WorkDir, ok := params[WorkDir]; ok { c.Config.CacheConfig.WorkDir = WorkDir } if bootstrap, ok := params[Bootstrap]; ok { c.Config.MetadataPath = bootstrap } } func (c *FscacheDaemonConfig) FillAuth(kc *auth.PassKeyChain) { if kc != nil { if kc.TokenBase() { c.Config.BackendConfig.RegistryToken = kc.Password } else { c.Config.BackendConfig.Auth = kc.ToBase64() } } } func (c *FscacheDaemonConfig) DumpString() (string, error) { return DumpConfigString(c) } func (c *FscacheDaemonConfig) DumpFile(f string) error { if err := os.MkdirAll(path.Dir(f), 0755); err != nil { return err } return DumpConfigFile(c, f) } nydus-snapshotter-0.13.4/config/daemonconfig/fuse.go000066400000000000000000000054651453374237200225240ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package daemonconfig import ( "encoding/json" "os" "path" "github.com/pkg/errors" "github.com/containerd/nydus-snapshotter/pkg/auth" ) const CacheDir string = "cachedir" // Used when nydusd works as a FUSE daemon or vhost-user-fs backend type FuseDaemonConfig struct { Device *DeviceConfig `json:"device"` Mode string `json:"mode"` DigestValidate bool `json:"digest_validate"` IOStatsFiles bool `json:"iostats_files,omitempty"` EnableXattr bool `json:"enable_xattr,omitempty"` AccessPattern bool `json:"access_pattern,omitempty"` LatestReadFiles bool `json:"latest_read_files,omitempty"` FSPrefetch `json:"fs_prefetch,omitempty"` // (experimental) The nydus daemon could cache more data to increase hit ratio when enabled the warmup feature. Warmup uint64 `json:"warmup,omitempty"` } // Control how to perform prefetch from file system layer type FSPrefetch struct { Enable bool `json:"enable"` PrefetchAll bool `json:"prefetch_all"` ThreadsCount int `json:"threads_count"` MergingSize int `json:"merging_size"` BandwidthRate int `json:"bandwidth_rate"` } // Load fuse daemon configuration from template file func LoadFuseConfig(p string) (*FuseDaemonConfig, error) { b, err := os.ReadFile(p) if err != nil { return nil, errors.Wrapf(err, "read FUSE configuration file %s", p) } var cfg FuseDaemonConfig if err := json.Unmarshal(b, &cfg); err != nil { return nil, errors.Wrapf(err, "unmarshal %s", p) } if cfg.Device == nil { return nil, errors.New("invalid fuse daemon configuration") } return &cfg, nil } func (c *FuseDaemonConfig) Supplement(host, repo, snapshotID string, params map[string]string) { c.Device.Backend.Config.Host = host c.Device.Backend.Config.Repo = repo c.Device.Cache.Config.WorkDir = params[CacheDir] } func (c *FuseDaemonConfig) FillAuth(kc *auth.PassKeyChain) { if kc != nil { if kc.TokenBase() { c.Device.Backend.Config.RegistryToken = kc.Password } else { c.Device.Backend.Config.Auth = kc.ToBase64() } } } func (c *FuseDaemonConfig) UpdateMirrors(mirrorsConfigDir, registryHost string) error { mirrors, err := LoadMirrorsConfig(mirrorsConfigDir, registryHost) if err != nil { return err } if len(mirrors) > 0 { c.Device.Backend.Config.Mirrors = mirrors } return nil } func (c *FuseDaemonConfig) StorageBackend() (string, *BackendConfig) { return c.Device.Backend.BackendType, &c.Device.Backend.Config } func (c *FuseDaemonConfig) DumpString() (string, error) { return DumpConfigString(c) } func (c *FuseDaemonConfig) DumpFile(f string) error { if err := os.MkdirAll(path.Dir(f), 0755); err != nil { return err } return DumpConfigFile(c, f) } nydus-snapshotter-0.13.4/config/daemonconfig/mirrors.go000066400000000000000000000141311453374237200232450ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package daemonconfig import ( "fmt" "net/http" "net/url" "os" "path/filepath" "sort" "strings" "github.com/containerd/containerd/log" "github.com/pelletier/go-toml" "github.com/pkg/errors" ) // Copied from containerd, for compatibility with containerd's toml configuration file. type HostFileConfig struct { Capabilities []string `toml:"capabilities"` CACert interface{} `toml:"ca"` Client interface{} `toml:"client"` SkipVerify *bool `toml:"skip_verify"` Header map[string]interface{} `toml:"header"` OverridePath bool `toml:"override_path"` // The following configuration items are specific to nydus. HealthCheckInterval int `toml:"health_check_interval,omitempty"` FailureLimit uint8 `toml:"failure_limit,omitempty"` PingURL string `toml:"ping_url,omitempty"` } type hostConfig struct { Scheme string Host string Header http.Header HealthCheckInterval int FailureLimit uint8 PingURL string } func makeStringSlice(slice []interface{}, cb func(string) string) ([]string, error) { out := make([]string, len(slice)) for i, value := range slice { str, ok := value.(string) if !ok { return nil, fmt.Errorf("unable to cast %v to string", value) } if cb != nil { out[i] = cb(str) } else { out[i] = str } } return out, nil } func parseMirrorsConfig(hosts []hostConfig) []MirrorConfig { var parsedMirrors = make([]MirrorConfig, len(hosts)) for i, host := range hosts { parsedMirrors[i].Host = fmt.Sprintf("%s://%s", host.Scheme, host.Host) parsedMirrors[i].HealthCheckInterval = host.HealthCheckInterval parsedMirrors[i].FailureLimit = host.FailureLimit parsedMirrors[i].PingURL = host.PingURL if len(host.Header) > 0 { mirrorHeader := make(map[string]string, len(host.Header)) for key, value := range host.Header { if len(value) > 1 { log.L.Warnf("some values of the header[%q] are omitted: %#v", key, value[1:]) } mirrorHeader[key] = host.Header.Get(key) } parsedMirrors[i].Headers = mirrorHeader } } return parsedMirrors } // hostDirectory converts ":port" to "_port_" in directory names func hostDirectory(host string) string { idx := strings.LastIndex(host, ":") if idx > 0 { return host[:idx] + "_" + host[idx+1:] + "_" } return host } func hostPaths(root, host string) []string { var hosts []string ch := hostDirectory(host) if ch != host { hosts = append(hosts, filepath.Join(root, ch)) } return append(hosts, filepath.Join(root, host), filepath.Join(root, "_default"), ) } func hostDirFromRoot(root, host string) (string, error) { for _, p := range hostPaths(root, host) { if _, err := os.Stat(p); err == nil { return p, nil } else if !os.IsNotExist(err) { return "", err } } return "", nil } // getSortedHosts returns the list of hosts as they defined in the file. func getSortedHosts(root *toml.Tree) ([]string, error) { iter, ok := root.Get("host").(*toml.Tree) if !ok { return nil, errors.New("invalid `host` tree") } list := append([]string{}, iter.Keys()...) // go-toml stores TOML sections in the map object, so no order guaranteed. // We retrieve line number for each key and sort the keys by position. sort.Slice(list, func(i, j int) bool { h1 := iter.GetPath([]string{list[i]}).(*toml.Tree) h2 := iter.GetPath([]string{list[j]}).(*toml.Tree) return h1.Position().Line < h2.Position().Line }) return list, nil } // parseHostConfig returns the parsed host configuration, make sure the server is not null. func parseHostConfig(server string, config HostFileConfig) (hostConfig, error) { var ( result = hostConfig{} err error ) if !strings.HasPrefix(server, "http") { server = "https://" + server } u, err := url.Parse(server) if err != nil { return hostConfig{}, fmt.Errorf("unable to parse server %v: %w", server, err) } result.Scheme = u.Scheme result.Host = u.Host if config.Header != nil { header := http.Header{} for key, ty := range config.Header { switch value := ty.(type) { case string: header[key] = []string{value} case []interface{}: header[key], err = makeStringSlice(value, nil) if err != nil { return hostConfig{}, err } default: return hostConfig{}, fmt.Errorf("invalid type %v for header %q", ty, key) } } result.Header = header } result.HealthCheckInterval = config.HealthCheckInterval result.FailureLimit = config.FailureLimit result.PingURL = config.PingURL return result, nil } func parseHostsFile(b []byte) ([]hostConfig, error) { tree, err := toml.LoadBytes(b) if err != nil { return nil, fmt.Errorf("failed to parse TOML: %w", err) } c := struct { // HostConfigs store the per-host configuration HostConfigs map[string]HostFileConfig `toml:"host"` }{} orderedHosts, err := getSortedHosts(tree) if err != nil { return nil, err } var ( hosts []hostConfig ) if err := tree.Unmarshal(&c); err != nil { return nil, err } // Parse hosts array for _, host := range orderedHosts { if host != "" { config := c.HostConfigs[host] parsed, err := parseHostConfig(host, config) if err != nil { return nil, err } hosts = append(hosts, parsed) } } return hosts, nil } func loadHostDir(hostsDir string) ([]hostConfig, error) { b, err := os.ReadFile(filepath.Join(hostsDir, "hosts.toml")) if err != nil { if !os.IsNotExist(err) { return nil, err } return []hostConfig{}, nil } hosts, err := parseHostsFile(b) if err != nil { return nil, err } return hosts, nil } func LoadMirrorsConfig(mirrorsConfigDir, registryHost string) ([]MirrorConfig, error) { var mirrors []MirrorConfig if mirrorsConfigDir == "" { return mirrors, nil } hostDir, err := hostDirFromRoot(mirrorsConfigDir, registryHost) if err != nil { return nil, err } if hostDir == "" { return mirrors, nil } hostConfig, err := loadHostDir(hostDir) if err != nil { return nil, err } mirrors = append(mirrors, parseMirrorsConfig(hostConfig)...) return mirrors, nil } nydus-snapshotter-0.13.4/config/daemonconfig/mirrors_test.go000066400000000000000000000054261453374237200243130ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package daemonconfig import ( "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestLoadMirrorConfig(t *testing.T) { tmpDir := t.TempDir() defer os.RemoveAll(tmpDir) registryHost := "registry.docker.io" mirrorsConfigDir := filepath.Join(tmpDir, "certs.d") registryHostConfigDir := filepath.Join(mirrorsConfigDir, registryHost) defaultHostConfigDir := filepath.Join(mirrorsConfigDir, "_default") mirrors, err := LoadMirrorsConfig("", registryHost) require.NoError(t, err) require.Nil(t, mirrors) mirrors, err = LoadMirrorsConfig(mirrorsConfigDir, registryHost) require.NoError(t, err) require.Nil(t, mirrors) err = os.MkdirAll(defaultHostConfigDir, os.ModePerm) assert.NoError(t, err) mirrors, err = LoadMirrorsConfig(mirrorsConfigDir, registryHost) require.NoError(t, err) require.Nil(t, mirrors) buf1 := []byte(`server = "https://default-docker.hub.com" [host] [host."http://default-p2p-mirror1:65001"] [host."http://default-p2p-mirror1:65001".header] X-Dragonfly-Registry = ["https://default-docker.hub.com"] `) err = os.WriteFile(filepath.Join(defaultHostConfigDir, "hosts.toml"), buf1, 0600) assert.NoError(t, err) mirrors, err = LoadMirrorsConfig(mirrorsConfigDir, registryHost) require.NoError(t, err) require.Equal(t, len(mirrors), 1) require.Equal(t, mirrors[0].Host, "http://default-p2p-mirror1:65001") require.Equal(t, mirrors[0].Headers["X-Dragonfly-Registry"], "https://default-docker.hub.com") err = os.MkdirAll(registryHostConfigDir, os.ModePerm) assert.NoError(t, err) buf2 := []byte(`server = "https://docker.hub.com" [host] [host."http://p2p-mirror1:65001"] [host."http://p2p-mirror1:65001".header] X-Dragonfly-Registry = ["https://docker.hub.com"] `) err = os.WriteFile(filepath.Join(registryHostConfigDir, "hosts.toml"), buf2, 0600) assert.NoError(t, err) mirrors, err = LoadMirrorsConfig(mirrorsConfigDir, registryHost) require.NoError(t, err) require.Equal(t, len(mirrors), 1) require.Equal(t, mirrors[0].Host, "http://p2p-mirror1:65001") require.Equal(t, mirrors[0].Headers["X-Dragonfly-Registry"], "https://docker.hub.com") buf3 := []byte(` [host."http://p2p-mirror2:65001"] [host."http://p2p-mirror2:65001".header] X-Dragonfly-Registry = ["https://docker.hub.com"] `) err = os.WriteFile(filepath.Join(registryHostConfigDir, "hosts.toml"), buf3, 0600) assert.NoError(t, err) mirrors, err = LoadMirrorsConfig(mirrorsConfigDir, registryHost) require.NoError(t, err) require.Equal(t, len(mirrors), 1) require.Equal(t, mirrors[0].Host, "http://p2p-mirror2:65001") require.Equal(t, mirrors[0].Headers["X-Dragonfly-Registry"], "https://docker.hub.com") } nydus-snapshotter-0.13.4/config/default.go000066400000000000000000000036201453374237200205440ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package config import ( "os/exec" "github.com/containerd/nydus-snapshotter/internal/constant" ) func (c *SnapshotterConfig) FillUpWithDefaults() error { c.Version = 1 c.Root = constant.DefaultRootDir c.Address = constant.DefaultAddress // essential configuration if c.DaemonMode == "" { c.DaemonMode = constant.DefaultDaemonMode } // system controller configuration c.SystemControllerConfig.Address = constant.DefaultSystemControllerAddress // logging configuration logConfig := &c.LoggingConfig if logConfig.LogLevel == "" { logConfig.LogLevel = constant.DefaultLogLevel } logConfig.RotateLogMaxSize = constant.DefaultRotateLogMaxSize logConfig.RotateLogMaxBackups = constant.DefaultRotateLogMaxBackups logConfig.RotateLogMaxAge = constant.DefaultRotateLogMaxAge logConfig.RotateLogLocalTime = constant.DefaultRotateLogLocalTime logConfig.RotateLogCompress = constant.DefaultRotateLogCompress // daemon configuration daemonConfig := &c.DaemonConfig if daemonConfig.NydusdConfigPath == "" { daemonConfig.NydusdConfigPath = constant.DefaultNydusDaemonConfigPath } daemonConfig.RecoverPolicy = RecoverPolicyRestart.String() daemonConfig.FsDriver = constant.DefaultFsDriver daemonConfig.LogRotationSize = constant.DefaultDaemonRotateLogMaxSize // cache configuration cacheConfig := &c.CacheManagerConfig if cacheConfig.GCPeriod == "" { cacheConfig.GCPeriod = constant.DefaultGCPeriod } return c.SetupNydusBinaryPaths() } func (c *SnapshotterConfig) SetupNydusBinaryPaths() error { // resolve nydusd path if path, err := exec.LookPath(constant.NydusdBinaryName); err == nil { c.DaemonConfig.NydusdPath = path } // resolve nydus-image path if path, err := exec.LookPath(constant.NydusImageBinaryName); err == nil { c.DaemonConfig.NydusImagePath = path } return nil } nydus-snapshotter-0.13.4/config/global.go000066400000000000000000000131051453374237200203570ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ // Expose configurations across nydus-snapshotter, the configurations is parsed // and extracted from nydus-snapshotter toml based configuration file or command line package config import ( "os" "path/filepath" "time" "github.com/containerd/containerd/log" "github.com/pkg/errors" "github.com/containerd/nydus-snapshotter/internal/logging" "github.com/containerd/nydus-snapshotter/pkg/utils/mount" ) var ( globalConfig GlobalConfig ) // Global cached configuration information to help: // - access configuration information without passing a configuration object // - avoid frequent generation of information from configuration information type GlobalConfig struct { origin *SnapshotterConfig SnapshotsDir string DaemonMode DaemonMode SocketRoot string ConfigRoot string RootMountpoint string DaemonThreadsNum int CacheGCPeriod time.Duration MirrorsConfig MirrorsConfig } func IsFusedevSharedModeEnabled() bool { return globalConfig.DaemonMode == DaemonModeShared } func GetDaemonMode() DaemonMode { return globalConfig.DaemonMode } func GetSnapshotsRootDir() string { return globalConfig.SnapshotsDir } func GetRootMountpoint() string { return globalConfig.RootMountpoint } func GetSocketRoot() string { return globalConfig.SocketRoot } func GetConfigRoot() string { return globalConfig.ConfigRoot } func GetMirrorsConfigDir() string { return globalConfig.MirrorsConfig.Dir } func GetFsDriver() string { return globalConfig.origin.DaemonConfig.FsDriver } func GetCacheGCPeriod() time.Duration { return globalConfig.CacheGCPeriod } func GetLogDir() string { return globalConfig.origin.LoggingConfig.LogDir } func GetLogLevel() string { return globalConfig.origin.LoggingConfig.LogLevel } func GetDaemonLogRotationSize() int { return globalConfig.origin.DaemonConfig.LogRotationSize } func GetDaemonThreadsNumber() int { return globalConfig.origin.DaemonConfig.ThreadsNumber } func GetLogToStdout() bool { return globalConfig.origin.LoggingConfig.LogToStdout } func IsSystemControllerEnabled() bool { return globalConfig.origin.SystemControllerConfig.Enable } func SystemControllerAddress() string { return globalConfig.origin.SystemControllerConfig.Address } func SystemControllerPprofAddress() string { return globalConfig.origin.SystemControllerConfig.DebugConfig.PprofAddress } func GetDaemonProfileCPUDuration() int64 { return globalConfig.origin.SystemControllerConfig.DebugConfig.ProfileDuration } func GetSkipSSLVerify() bool { return globalConfig.origin.RemoteConfig.SkipSSLVerify } const ( TarfsLayerVerityOnly string = "layer_verity_only" TarfsImageVerityOnly string = "image_verity_only" TarfsLayerBlockDevice string = "layer_block" TarfsImageBlockDevice string = "image_block" TarfsLayerBlockWithVerity string = "layer_block_with_verity" TarfsImageBlockWithVerity string = "image_block_with_verity" ) func GetTarfsMountOnHost() bool { return globalConfig.origin.Experimental.TarfsConfig.MountTarfsOnHost } func GetTarfsExportEnabled() bool { switch globalConfig.origin.Experimental.TarfsConfig.ExportMode { case TarfsLayerVerityOnly, TarfsLayerBlockDevice, TarfsLayerBlockWithVerity: return true case TarfsImageVerityOnly, TarfsImageBlockDevice, TarfsImageBlockWithVerity: return true default: return false } } // Returns (wholeImage, generateBlockImage, withVerityInfo) // wholeImage: generate tarfs for the whole image instead of of a specific layer. // generateBlockImage: generate a block image file. // withVerityInfo: generate disk verity information. func GetTarfsExportFlags() (bool, bool, bool) { switch globalConfig.origin.Experimental.TarfsConfig.ExportMode { case "layer_verity_only": return false, false, true case "image_verity_only": return true, false, true case "layer_block": return false, true, false case "image_block": return true, true, false case "layer_block_with_verity": return false, true, true case "image_block_with_verity": return true, true, true default: return false, false, false } } func ProcessConfigurations(c *SnapshotterConfig) error { if c.LoggingConfig.LogDir == "" { c.LoggingConfig.LogDir = filepath.Join(c.Root, logging.DefaultLogDirName) } if c.CacheManagerConfig.CacheDir == "" { c.CacheManagerConfig.CacheDir = filepath.Join(c.Root, "cache") } globalConfig.origin = c globalConfig.SnapshotsDir = filepath.Join(c.Root, "snapshots") globalConfig.ConfigRoot = filepath.Join(c.Root, "config") globalConfig.SocketRoot = filepath.Join(c.Root, "socket") globalConfig.RootMountpoint = filepath.Join(c.Root, "mnt") globalConfig.MirrorsConfig = c.RemoteConfig.MirrorsConfig if c.CacheManagerConfig.GCPeriod != "" { d, err := time.ParseDuration(c.CacheManagerConfig.GCPeriod) if err != nil { return errors.Errorf("invalid GC period '%s'", c.CacheManagerConfig.GCPeriod) } globalConfig.CacheGCPeriod = d } m, err := parseDaemonMode(c.DaemonMode) if err != nil { return err } if c.DaemonConfig.FsDriver == FsDriverFscache && m != DaemonModeShared { log.L.Infof("fscache driver only supports 'shared' mode, override daemon mode from '%s' to 'shared'", m) m = DaemonModeShared } globalConfig.DaemonMode = m return nil } func SetUpEnvironment(c *SnapshotterConfig) error { if err := os.MkdirAll(c.Root, 0700); err != nil { return errors.Wrapf(err, "create root dir %s", c.Root) } realPath, err := mount.NormalizePath(c.Root) if err != nil { return errors.Wrapf(err, "invalid root path") } c.Root = realPath return nil } nydus-snapshotter-0.13.4/docs/000077500000000000000000000000001453374237200162535ustar00rootroot00000000000000nydus-snapshotter-0.13.4/docs/configure_nydus.md000066400000000000000000000141661453374237200220100ustar00rootroot00000000000000# Configure Nydus-snapshotter Nydus-snapshotter can receive a toml file as its configurations to start providing image service through CLI parameter `--config`. An example configuration file can be found [here](../misc/snapshotter/config.toml). Besides nydus-snapshotter's configuration, `nydusd`'s configuration has to be provided to nydus-snapshotter too. Nydusd is started by nydus-snapshotter and it is configured by the provided json configuration file. A minimal configuration file can be found [here](../misc/snapshotter/nydusd-config.fusedev.json) ## Authentication As [containerd#3731](https://github.com/containerd/containerd/issues/3731) discussed, containerd doesn't share credentials with third snapshotters now. Like [stargz snapshotter](https://github.com/containerd/stargz-snapshotter/blob/main/docs/overview.md#authentication), nydus-snapshotter supports 3 main ways to access registries with custom configurations. You can use configuration file to enable them. The snapshotter will try to get image pull keychain in the following order if such way is enabled: 1. intercept CRI request and extract private registry auth 2. docker config (default enabled) 3. k8s docker config secret ### dockerconfig-based authentication By default, the snapshotter tries to get credentials from `$DOCKER_CONFIG` or `~/.docker/config.json`. Following example enables nydus-snapshotter to access to private registries using `docker login` command. ```console # docker login (Enter username and password) # crictl pull --creds USERNAME[:PASSWORD] docker.io//ubuntu:22.04 (Here the credential is only used by containerd) ``` ### CRI-based authentication Following configuration enables nydus-snapshotter to pull private images via CRI requests. ```toml [remote.auth] # Fetch the private registry auth as CRI image service proxy enable_cri_keychain = true image_service_address = "/run/containerd/containerd.sock" ``` The snapshotter works as a proxy of CRI Image Service and exposes CRI Image Service API on the snapshotter's unix socket (i.e. `/run/containerd/containerd-nydus-grpc.sock`). The snapshotter acquires registry creds by scanning requests. The `image_service_address` is the original image service socket. It can be omitted and the default value will be the containerd's default socket path `/run/containerd/containerd.sock`. You **must** specify `--image-service-endpoint=unix:///run/containerd-nydus/containerd-nydus-grpc.sock` option to kubelet when using Kubernetes. Or specify `image-endpoint: "unix:////run/containerd-nydus/containerd-nydus-grpc.sock"` in `crictl.yaml` when using `crictl`. ### kubeconfig-based authentication This is another way to enable lazy pulling of private images on Kubernetes, Nydus snapshotter will start a goroutine to listen on secrets (type = `kubernetes.io/dockerconfigjson`) for private registries. #### use kubeconfig file Following configuration enables nydus-snapshotter to access to private registries using kubernetes secrets in the cluster using kubeconfig files. ```toml [remote.auth] enable_kubeconfig_keychain = true kubeconfig_path = "/path/to/.kubeconfig" ``` If no `kubeconfig_path` is specified, snapshotter searches kubeconfig files from `$KUBECONFIG` or `~/.kube/config`. Please note that kubeconfig-based authentication requires additional privilege (i.e. kubeconfig to list/watch secrets) to the node. And this doesn't work if `kubelet` retrieve credentials from somewhere not API server (e.g. [credential provider](https://kubernetes.io/docs/tasks/kubelet-credential-provider/kubelet-credential-provider/)). #### use ServiceAccount If your Nydus snapshotter runs in a Kubernetes cluster and you don't want to use kubeconfig, you can also choose to use ServiceAccount to configure the corresponding permissions for Nydus snapshotter. ```yaml apiVersion: v1 kind: ServiceAccount metadata: name: nydus-snapshotter-sa namespace: nydus-system --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nydus-snapshotter-role rules: - apiGroups: - "" resources: - secrets verbs: - get - list - watch --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nydus-snapshotter-role-binding roleRef: kind: ClusterRole name: nydus-snapshotter-role apiGroup: rbac.authorization.k8s.io subjects: - kind: ServiceAccount name: nydus-snapshotter-sa namespace: nydus-system ``` Then you can set the desired ServiceAccount with the required permissions fro your Nydus snapshotter Pod: ```yaml apiVersion: v1 kind: Pod metadata: name: nydus-snapshotter namespace: nydus-system spec: containers: name: nydus-snapshotter serviceAccountName: nydus-snapshotter-sa ... ``` #### create secrets If you have logged into a private registry, you can create a secret from the config file: ```bash $ kubectl create --namespace nydus-system secret generic regcred \ --from-file=.dockerconfigjson=$HOME/.docker/config.json \ --type=kubernetes.io/dockerconfigjson ``` The Nydus snapshotter will get the new secret and parse the authorization. If your new Pod uses a private registry, then this authentication information will be used to pull the image from the private registry. ## Metrics Nydusd records metrics in its own format. The metrics are exported via a HTTP server on top of unix domain socket. Nydus-snapshotter fetches the metrics and convert them in to Prometheus format which is exported via a network address. Nydus-snapshotter by default does not fetch metrics from nydusd. You can enable the nydusd metrics download by assigning a network address to `metrics.address` in nydus-snapshotter's toml [configuration file](../misc/snapshotter/config.toml). Once this entry is enabled, not only nydusd metrics, but also some information about the nydus-snapshotter runtime and snapshot related events are exported in Prometheus format as well. ## Diagnose A system controller can be ran insides nydus-snapshotter. By setting `system.enable` to `true`, nydus-snapshotter will start a simple HTTP server on unix domain socket `system.address` path and exports some internal working status to users. The address defaults to `/var/run/containerd-nydus/system.sock` nydus-snapshotter-0.13.4/docs/crictl_dry_run.md000066400000000000000000000021471453374237200216230ustar00rootroot00000000000000# Start Container by crictl ## Create crictl Config The runtime endpoint can be set in the config file. Please refer to [crictl](https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/crictl.md) document for more details. Compose your `crictl` configuration file named as `crictl.yaml`: ```yml runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 10 debug: true ``` Compose a pod configuration which can be named as `pod.yaml` ```yml metadata: attempt: 1 name: nydus-sandbox namespace: default uid: hdishd83djaidwnduwk28bcsb log_directory: /tmp linux: security_context: namespace_options: network: 2 ``` Compose a container configuration which can be named as `container.yaml` ```yml metadata: name: nydus-container image: image: command: - /bin/sleep args: - 600 log_path: container.1.log ``` Start a container based on nydus image. ```bash # auth is base64 encoded string from "username:password" $ crictl --config ./crictl.yaml run --auth ./container.yaml ./pod.yaml ``` nydus-snapshotter-0.13.4/docs/diagram/000077500000000000000000000000001453374237200176575ustar00rootroot00000000000000nydus-snapshotter-0.13.4/docs/diagram/nydus_fscache_erofs_arch.svg000066400000000000000000000566261453374237200254300ustar00rootroot00000000000000snapshotterpluginnydusdcontainerdcontainererofsRegistryPull Bootstrap/MetaLayer Dataoverlayfs stackedPosix File InterfacescontainerKernelAnnotationsMount SliceSnapshot IDsP2P cluster/ DragonflyauthCRIcachefilesfscacheerofsoverlayfs stackednydus-snapshotter-0.13.4/docs/diagram/nydus_fuse_arch.svg000066400000000000000000000544231453374237200235710ustar00rootroot00000000000000snapshotterpluginnydusdcontainerdcontainerfuseRegistryPull Bootstrap/MetaLayer Dataoverlayfs stackedPosix File InterfacescontainerKernelFUSE daemonnydusdnydusdAnnotationsMount SliceSnapshot IDscontainerP2P clusterauthCRInydus-snapshotter-0.13.4/docs/diagram/optmizer_workflow.svg000066400000000000000000000334431453374237200242120ustar00rootroot00000000000000NRI adaptationOptimizer(client)Optimizer server(image1)Optimizer server(image2)CRI runtimelow level runtime(runc/kata)containerOCI Speckubeletaccessed files list(in order)OCI imageoptimized nydus imagenydus-snapshotter-0.13.4/docs/optimize_nydus_image.md000066400000000000000000000120361453374237200230230ustar00rootroot00000000000000# Optimize a nydus image To improve the prefetch hit rate, we can specify a prefetch table when converting an OCI image to a nydus image. The prefetch table is workload related and we should generate the list of accessed files in order when the workload is running. Nydus-snapshotter has implemented an optimizer with Containerd NRI plugin to optimize the nydus image. The optimizer is image format independent and requires NRI 2.0, which is available in containerd (>=v1.7.0). The optimizer subscribes container events to watch what files are opened and read, etc. during container application is starting up. This enables nydus image build tools to optimize the nydus image making it put the necessary and prioritized files into a special region of nydus image with extra image metadata. So nydus runtime can pull this files into local disk in top priority, thus to boost the performance further. ## Requirements - [NRI 2.0](https://github.com/containerd/nri): Which has been integrated into containerd since [v1.7.0](https://github.com/containerd/containerd/tree/v1.7.0-beta.1). ## Workflow ![optimizer workload](./diagram/optmizer_workflow.svg) 1. Run the optimizer as a NRI plugin to run optimizer server when the StartContainer event occurs. 2. Optimizer server joins container mount namespace and starts fanotify server. 3. Optimizer server detects fanotify event and sends the accessed file descriptor to client. 4. Optimizer client converts file descriptor to path. 5. Generate list of accessed files on local disk. 6. Convert OCI images with accessed files list to nydus image. ## Generate an accessed files list To install the optimizer and optimizer-server, invoke below command: ```console make optimizer && make install-optimizer ``` This command installs the optimizer's default toml configuration file in `/etc/nri/conf.d/02-optimizer-nri-plugin.conf`. Here is an example: ```toml # The directory to persist accessed files list for container. persist_dir = "/opt/nri/optimizer/results" # Whether to make the csv file human readable. readable = false # The path of optimizer server binary. server_path = "/usr/local/bin/optimizer-server" # The timeout to kill optimizer server, 0 to disable it. timeout = 0 # Whether to overwrite the existed persistent files. overwrite = false # The events that containerd subscribes to. # Do not change this element. events = [ "StartContainer", "StopContainer" ] ``` Modify containerd's toml configuration file to enable NRI. ```console sudo tee -a /etc/containerd/config.toml <<- EOF [plugins."io.containerd.nri.v1.nri"] config_file = "/etc/nri/nri.conf" disable = false plugin_path = "/opt/nri/plugins" socket_path = "/var/run/nri.sock" EOF ``` Containerd will load all NRI plugins in the `plugin_path` directory on startup. If you want to start a NRI plugin manually, please add the following configuration to allow other NRI plugins to connect via `socket_path`. ```console sudo tee /etc/nri/nri.conf <<- EOF disableConnections: false EOF ``` Restart the containerd service. ```console sudo systemctl restart containerd ``` Now, just run a container workload in sandbox and you will get the list of accessed files in `persist_dir`. Note that NRI plugin can only be called from containerd/CRI. So start a container using `crictl` as below. ```console sudo tee nginx.yaml <<- EOF metadata: name: nginx image: image: nginx:latest log_path: nginx.0.log linux: {} EOF sudo tee pod.yaml <<- EOF metadata: name: nginx-sandbox namespace: default attempt: 1 uid: hdishd83djaidwnduwk28bcsb log_directory: /tmp linux: {} EOF crictl run nginx.yaml pod.yaml ``` The result file for the nginx image is `/opt/nri/optimizer/results/nginx:latest`. ## Build Nydus Image with Optimizer's Suggestions Nydus provides a [nydusify](https://github.com/dragonflyoss/nydus/blob/master/docs/nydusify.md) CLI tool to convert OCI images from the source registry or local file system to nydus format and push them to the target registry. We can install the `nydusify` cli tool from the nydus package. ```console VERSION=v2.1.5 wget https://github.com/dragonflyoss/nydus/releases/download/$VERSION/nydus-static-$VERSION-linux-amd64.tgz tar -zxvf nydus-static-$VERSION-linux-amd64.tgz sudo install -D -m 755 nydus-static/nydusify /usr/local/bin/nydusify sudo install -D -m 755 nydus-static/nydus-image /usr/local/bin/nydus-image ``` A simple example converts the OCI image nginx to nydus format in RAFS V6. ```console sudo nydusify convert --source nginx --target sctb512/nginx:nydusv6 --fs-version 6 ``` With the `--prefetch-patterns` argument, we can specify the list of files to be written in the front of the nydus image and be prefetched in order when starting a container. ```console sudo nydusify convert --source nginx --target sctb512/nginx:optimized-nydusv6 --fs-version 6 --prefetch-patterns < /opt/nri/optimizer/results/nginx:latest ``` On a host with nydus-snapshotter installed and configured properly, start a container with an optimized nydus image. ```console sudo nerdctl --snapshotter nydus run --rm --net host -it sctb512/nginx:optimized-nydusv6 ``` nydus-snapshotter-0.13.4/docs/run_nydus_in_kubernetes.md000066400000000000000000000075671453374237200235570ustar00rootroot00000000000000# Run Dragonfly & Nydus in Kubernetes We recommend using the Dragonfly P2P data distribution system to further improve the runtime performance of Nydus images. If you want to deploy Dragonfly and Nydus at the same time through Helm, please refer to the **[Quick Start](https://github.com/dragonflyoss/helm-charts/blob/main/INSTALL.md)**. # Run Nydus snapshotter in Kubernetes This document will introduce how to run Nydus snapshotter in Kubernetes cluster, you can use helm to deploy Nydus snapshotter container. **NOTE:** This document is mainly to allow everyone to quickly deploy and experience Nydus snapshotter in the Kubernetes cluster. You cannot use it as a deployment and configuration solution for the production environment. ## Setup Kubernetes using kind [kind](https://kind.sigs.k8s.io/) is a tool for running local Kubernetes clusters using Docker container “nodes”. kind was primarily designed for testing Kubernetes itself, but may be used for local development or CI. First, we need to prepare a configuration file(`kind-config.yaml`) for kind to specify the devices and files we need to mount to the kind node. ```yaml kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 networking: ipFamily: dual nodes: - role: control-plane image: kindest/node:v1.23.4 extraMounts: - hostPath: ./containerd-config.toml containerPath: /etc/containerd/config.toml - hostPath: /dev/fuse containerPath: /dev/fuse ``` Next, we also need a config for containerd(`containerd-config.toml`). ```toml version = 2 [debug] level = "debug" [plugins."io.containerd.grpc.v1.cri".containerd] discard_unpacked_layers = false disable_snapshot_annotations = false snapshotter = "overlayfs" default_runtime_name = "runc" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] runtime_type = "io.containerd.runc.v2" [plugins."io.containerd.grpc.v1.cri"] sandbox_image = "registry.k8s.io/pause:3.6" ``` With these two configuration files, we can create a kind cluster. ```bash $ kind create cluster --config=kind-config.yaml ``` If everything is fine, kind should have prepared the configuration for us, and we can run the `kubectl` command directly on the host machine, such as: ```bash $ kubectl get nodes NAME STATUS ROLES AGE VERSION kind-control-plane Ready control-plane,master 19m v1.23.4 ``` ## Use helm to install Nydus snapshotter Before proceeding, you need to make sure [`helm` is installed](https://helm.sh/docs/intro/quickstart/#install-helm). First, you need to create a `config-nydus.yaml` for helm to install Nydus-snapshotter. ```yaml name: nydus-snapshotter pullPolicy: Always hostNetwork: true dragonfly: enable: false containerRuntime: containerd: enable: true ``` Then clone the Nydus snapshotter helm chart. ```bash $ git clone https://github.com/dragonflyoss/helm-charts.git ``` Last run helm to create Nydus snapshotter. ```bash $ cd helm-charts $ helm install --wait --timeout 10m --dependency-update \ --create-namespace --namespace nydus-system \ -f config-nydus.yaml \ nydus-snapshotter charts/nydus-snapshotter ``` ## Run Nydus containers We can then create a Pod(`nydus-pod.yaml`) config file that runs Nydus image. ```yaml apiVersion: v1 kind: Pod metadata: name: nydus-pod spec: containers: - name: nginx image: ghcr.io/dragonflyoss/image-service/nginx:nydus-latest imagePullPolicy: Always command: ["sh", "-c"] args: - tail -f /dev/null ``` Use `kubectl` to create the Pod. ```bash $ kubectl create -f nydus-pod.yaml $ kubectl get pods -w ``` The `-w` options will block the console and wait for the changes of the status of the pod. If everything is normal, you can see that the pod will become `Running` after a while. ```bash NAME READY STATUS RESTARTS AGE nydus-pod 1/1 Running 0 51s ``` nydus-snapshotter-0.13.4/docs/tarfs.md000066400000000000000000000245711453374237200177250ustar00rootroot00000000000000# Nydus Tarfs Mode `Nydus Tarfs Mode` or `Tarfs` is a working mode for Nydus Image, which uses tar files as Nydus data blobs instead of generating native Nydus data blobs. ### Enable Tarfs `Nydus Tarfs Mode` is still an experiment feature, please edit the snapshotter configuration file to enable the feature: ``` [experimental.tarfs] enable_tarfs = true ``` ### Generate Raw Disk Image for Each Layer of a Container Image `Tarfs` supports generating a raw disk image for each layer of a container image, which can be directly mounted as EROFS filesystem through loopdev. Please edit the snapshotter configuration file to enable this submode: ``` [experimental.tarfs] enable_tarfs = true export_mode = "layer_block" ``` This is an example to generate and verify raw disk image for each layer of a container image: ``` $ containerd-nydus-grpc --config /etc/nydus/config.toml & $ nerdctl run --snapshotter nydus --rm nginx # Show mounted rootfs a container $ mount /dev/loop17 on /var/lib/containerd-nydus/snapshots/7/mnt type erofs (ro,relatime,user_xattr,acl,cache_strategy=readaround) # Show loop devices used to mount layers and bootstrap for a container image $ losetup NAME SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE DIO LOG-SEC /dev/loop11 0 0 0 0 /var/lib/containerd-nydus/cache/fd9f026c631046113bd492f69761c3ba6042c791c35a60e7c7f3b8f254592daa 0 512 /dev/loop12 0 0 0 0 /var/lib/containerd-nydus/cache/055fa98b43638b67d10c58d41094d99c8696cc34b7a960c7a0cc5d9d152d12b3 0 512 /dev/loop13 0 0 0 0 /var/lib/containerd-nydus/cache/96576293dd2954ff84251aa0455687c8643358ba1b190ea1818f56b41884bdbd 0 512 /dev/loop14 0 0 0 0 /var/lib/containerd-nydus/cache/a7c4092be9044bd4eef78f27c95785ef3a9f345d01fd4512bc94ddaaefc359f4 0 512 /dev/loop15 0 0 0 0 /var/lib/containerd-nydus/cache/e3b6889c89547ec9ba653ab44ed32a99370940d51df956968c0d578dd61ab665 0 512 /dev/loop16 0 0 0 0 /var/lib/containerd-nydus/cache/da761d9a302b21dc50767b67d46f737f5072fb4490c525b4a7ae6f18e1dbbf75 0 512 /dev/loop17 0 0 0 0 /var/lib/containerd-nydus/snapshots/7/fs/image/image.boot 0 512 # Files without suffix are tar files, files with suffix `layer.disk` are raw disk image for container image layers $ ls -l /var/lib/containerd-nydus/cache/ total 376800 -rw-r--r-- 1 root root 3584 Aug 30 23:18 055fa98b43638b67d10c58d41094d99c8696cc34b7a960c7a0cc5d9d152d12b3 -rw-r--r-- 1 root root 527872 Aug 30 23:18 055fa98b43638b67d10c58d41094d99c8696cc34b7a960c7a0cc5d9d152d12b3.layer.disk -rw-r--r-- 1 root root 77814784 Aug 30 23:18 52d2b7f179e32b4cbd579ee3c4958027988f9a8274850ab0c7c24661e3adaac5 -rw-r--r-- 1 root root 78863360 Aug 30 23:18 52d2b7f179e32b4cbd579ee3c4958027988f9a8274850ab0c7c24661e3adaac5.layer.disk -rw-r--r-- 1 root root 4608 Aug 30 23:18 96576293dd2954ff84251aa0455687c8643358ba1b190ea1818f56b41884bdbd -rw-r--r-- 1 root root 528896 Aug 30 23:18 96576293dd2954ff84251aa0455687c8643358ba1b190ea1818f56b41884bdbd.layer.disk -rw-r--r-- 1 root root 2560 Aug 30 23:18 a7c4092be9044bd4eef78f27c95785ef3a9f345d01fd4512bc94ddaaefc359f4 -rw-r--r-- 1 root root 526848 Aug 30 23:18 a7c4092be9044bd4eef78f27c95785ef3a9f345d01fd4512bc94ddaaefc359f4.layer.disk -rw-r--r-- 1 root root 7168 Aug 30 23:18 da761d9a302b21dc50767b67d46f737f5072fb4490c525b4a7ae6f18e1dbbf75 -rw-r--r-- 1 root root 531456 Aug 30 23:18 da761d9a302b21dc50767b67d46f737f5072fb4490c525b4a7ae6f18e1dbbf75.layer.disk -rw-r--r-- 1 root root 5120 Aug 30 23:18 e3b6889c89547ec9ba653ab44ed32a99370940d51df956968c0d578dd61ab665 -rw-r--r-- 1 root root 529408 Aug 30 23:18 e3b6889c89547ec9ba653ab44ed32a99370940d51df956968c0d578dd61ab665.layer.disk -rw-r--r-- 1 root root 112968704 Aug 30 23:18 fd9f026c631046113bd492f69761c3ba6042c791c35a60e7c7f3b8f254592daa -rw-r--r-- 1 root root 113492992 Aug 30 23:18 fd9f026c631046113bd492f69761c3ba6042c791c35a60e7c7f3b8f254592daa.layer.disk $ file /var/lib/containerd-nydus/cache/055fa98b43638b67d10c58d41094d99c8696cc34b7a960c7a0cc5d9d152d12b3 /var/lib/containerd-nydus/cache/055fa98b43638b67d10c58d41094d99c8696cc34b7a960c7a0cc5d9d152d12b3: POSIX tar archive # Mount the raw disk image for a container image layer $ losetup /dev/loop100 /var/lib/containerd-nydus/cache/055fa98b43638b67d10c58d41094d99c8696cc34b7a960c7a0cc5d9d152d12b3.layer.disk $ mount -t erofs /dev/loop100 ./mnt/ $ mount tmpfs on /run/user/0 type tmpfs (rw,nosuid,nodev,relatime,size=1544836k,nr_inodes=386209,mode=700,inode64) /dev/loop17 on /var/lib/containerd-nydus/snapshots/7/mnt type erofs (ro,relatime,user_xattr,acl,cache_strategy=readaround) /dev/loop100 on /root/ws/nydus-snapshotter.git/mnt type erofs (ro,relatime,user_xattr,acl,cache_strategy=readaround) ``` ### Generate Raw Disk Image for a Container Image `Tarfs` supports generating a raw disk image a container image, which can be directly mounted as EROFS filesystem through loopdev. Please edit the snapshotter configuration file to enable this submode: ``` [experimental.tarfs] enable_tarfs = true export_mode = "image_block" ``` This is an example to generate and verify raw disk image for a container image: ``` $ containerd-nydus-grpc --config /etc/nydus/config.toml & $ nerdctl run --snapshotter nydus --rm nginx # Files without suffix are tar files, files with suffix `image.disk` are raw disk image for a container image $ ls -l /var/lib/containerd-nydus/cache/ total 376320 -rw-r--r-- 1 root root 3584 Aug 30 23:35 055fa98b43638b67d10c58d41094d99c8696cc34b7a960c7a0cc5d9d152d12b3 -rw-r--r-- 1 root root 77814784 Aug 30 23:35 52d2b7f179e32b4cbd579ee3c4958027988f9a8274850ab0c7c24661e3adaac5 -rw-r--r-- 1 root root 4608 Aug 30 23:35 96576293dd2954ff84251aa0455687c8643358ba1b190ea1818f56b41884bdbd -rw-r--r-- 1 root root 2560 Aug 30 23:35 a7c4092be9044bd4eef78f27c95785ef3a9f345d01fd4512bc94ddaaefc359f4 -rw-r--r-- 1 root root 7168 Aug 30 23:35 da761d9a302b21dc50767b67d46f737f5072fb4490c525b4a7ae6f18e1dbbf75 -rw-r--r-- 1 root root 194518016 Aug 30 23:36 da761d9a302b21dc50767b67d46f737f5072fb4490c525b4a7ae6f18e1dbbf75.image.disk -rw-r--r-- 1 root root 5120 Aug 30 23:35 e3b6889c89547ec9ba653ab44ed32a99370940d51df956968c0d578dd61ab665 -rw-r--r-- 1 root root 112968704 Aug 30 23:36 fd9f026c631046113bd492f69761c3ba6042c791c35a60e7c7f3b8f254592daa ``` ### Generate Raw Disk Image with dm-verity Information `Tarfs` supports generating raw disk images with dm-verity information, to enable runtime data integrity validation. Please change `export_mode` in snapshotter configuration file to `layer_block_with_verity` or `image_block_with_verity`. ``` [experimental.tarfs] enable_tarfs = true export_mode = "image_block_with_verity" ``` This is an example to generate and verify raw disk image for a container image with dm-verity information: ``` $ containerd-nydus-grpc --config /etc/nydus/config.toml & $ nerdctl run --snapshotter nydus --rm nginx # Files without suffix are tar files, files with suffix `image.disk` are raw disk image for a container image $ ls -l /var/lib/containerd-nydus/cache/ total 388296 -rw-r--r-- 1 root root 3584 Aug 30 23:45 055fa98b43638b67d10c58d41094d99c8696cc34b7a960c7a0cc5d9d152d12b3 -rw-r--r-- 1 root root 77814784 Aug 30 23:46 52d2b7f179e32b4cbd579ee3c4958027988f9a8274850ab0c7c24661e3adaac5 -rw-r--r-- 1 root root 4608 Aug 30 23:45 96576293dd2954ff84251aa0455687c8643358ba1b190ea1818f56b41884bdbd -rw-r--r-- 1 root root 2560 Aug 30 23:45 a7c4092be9044bd4eef78f27c95785ef3a9f345d01fd4512bc94ddaaefc359f4 -rw-r--r-- 1 root root 7168 Aug 30 23:45 da761d9a302b21dc50767b67d46f737f5072fb4490c525b4a7ae6f18e1dbbf75 -rw-r--r-- 1 root root 206782464 Aug 30 23:46 da761d9a302b21dc50767b67d46f737f5072fb4490c525b4a7ae6f18e1dbbf75.image.disk -rw-r--r-- 1 root root 5120 Aug 30 23:45 e3b6889c89547ec9ba653ab44ed32a99370940d51df956968c0d578dd61ab665 -rw-r--r-- 1 root root 112968704 Aug 30 23:46 fd9f026c631046113bd492f69761c3ba6042c791c35a60e7c7f3b8f254592daa $ losetup /dev/loop100 /var/lib/containerd-nydus/cache/da761d9a302b21dc50767b67d46f737f5072fb4490c525b4a7ae6f18e1dbbf75.image.disk $ veritysetup open --no-superblock --format=1 -s "" --hash=sha256 --data-block-size=512 --hash-block-size=4096 --data-blocks 379918 --hash-offset 194519040 /dev/loop100 image1 /dev/loop100 8113799aaf9a5d14feca1eadc3b7e6ea98bdaf61e3a2e4a8ef8c24e26a551efd $ lsblk loop100 7:100 0 197.2M 0 loop └─dm-0 252:0 0 185.5M 1 crypt $ veritysetup status dm-0 /dev/mapper/dm-0 is active and is in use. type: VERITY status: verified hash type: 1 data block: 512 hash block: 4096 hash name: sha256 salt: - data device: /dev/loop100 data loop: /var/lib/containerd-nydus/cache/da761d9a302b21dc50767b67d46f737f5072fb4490c525b4a7ae6f18e1dbbf75.image.disk size: 379918 sectors mode: readonly hash device: /dev/loop100 hash loop: /var/lib/containerd-nydus/cache/da761d9a302b21dc50767b67d46f737f5072fb4490c525b4a7ae6f18e1dbbf75.image.disk hash offset: 379920 sectors root hash: 8113799aaf9a5d14feca1eadc3b7e6ea98bdaf61e3a2e4a8ef8c24e26a551efd $ mount -t erofs /dev/dm-0 ./mnt/ mount: /root/ws/nydus-snapshotter.git/mnt: WARNING: source write-protected, mounted read-only. $ ls -l mnt/ total 14 lrwxrwxrwx 1 root root 7 Aug 14 08:00 bin -> usr/bin drwxr-xr-x 2 root root 27 Jul 15 00:00 boot drwxr-xr-x 2 root root 27 Aug 14 08:00 dev drwxr-xr-x 2 root root 184 Aug 16 17:50 docker-entrypoint.d -rwxrwxr-x 1 root root 1620 Aug 16 17:50 docker-entrypoint.sh drwxr-xr-x 34 root root 1524 Aug 16 17:50 etc drwxr-xr-x 2 root root 27 Jul 15 00:00 home lrwxrwxrwx 1 root root 7 Aug 14 08:00 lib -> usr/lib lrwxrwxrwx 1 root root 9 Aug 14 08:00 lib32 -> usr/lib32 lrwxrwxrwx 1 root root 9 Aug 14 08:00 lib64 -> usr/lib64 lrwxrwxrwx 1 root root 10 Aug 14 08:00 libx32 -> usr/libx32 drwxr-xr-x 2 root root 27 Aug 14 08:00 media drwxr-xr-x 2 root root 27 Aug 14 08:00 mnt drwxr-xr-x 2 root root 27 Aug 14 08:00 opt drwxr-xr-x 2 root root 27 Jul 15 00:00 proc drwx------ 2 root root 66 Aug 14 08:00 root drwxr-xr-x 3 root root 43 Aug 14 08:00 run lrwxrwxrwx 1 root root 8 Aug 14 08:00 sbin -> usr/sbin drwxr-xr-x 2 root root 27 Aug 14 08:00 srv drwxr-xr-x 2 root root 27 Jul 15 00:00 sys drwxrwxrwt 2 root root 27 Aug 16 17:50 tmp drwxr-xr-x 14 root root 229 Aug 14 08:00 usr drwxr-xr-x 11 root root 204 Aug 14 08:00 var ```nydus-snapshotter-0.13.4/export/000077500000000000000000000000001453374237200166445ustar00rootroot00000000000000nydus-snapshotter-0.13.4/export/snapshotter/000077500000000000000000000000001453374237200212165ustar00rootroot00000000000000nydus-snapshotter-0.13.4/export/snapshotter/snapshotter.go000066400000000000000000000020211453374237200241120ustar00rootroot00000000000000package snapshotter import ( "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/plugin" "github.com/pkg/errors" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/snapshot" ) func init() { plugin.Register(&plugin.Registration{ Type: plugin.SnapshotPlugin, ID: "nydus", Config: &config.SnapshotterConfig{}, InitFn: func(ic *plugin.InitContext) (interface{}, error) { ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec()) cfg, ok := ic.Config.(*config.SnapshotterConfig) if !ok { return nil, errors.New("invalid nydus snapshotter configuration") } if cfg.Root == "" { cfg.Root = ic.Root } if err := cfg.FillUpWithDefaults(); err != nil { return nil, errors.New("failed to fill up nydus configuration with defaults") } rs, err := snapshot.NewSnapshotter(ic.Context, cfg) if err != nil { return nil, errors.Wrap(err, "failed to initialize snapshotter") } return rs, nil }, }) } nydus-snapshotter-0.13.4/go.mod000066400000000000000000000170301453374237200164320ustar00rootroot00000000000000module github.com/containerd/nydus-snapshotter go 1.19 require ( github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 github.com/KarpelesLab/reflink v1.0.1 github.com/aliyun/aliyun-oss-go-sdk v2.2.6+incompatible github.com/aws/aws-sdk-go-v2 v1.17.6 github.com/aws/aws-sdk-go-v2/config v1.18.16 github.com/aws/aws-sdk-go-v2/credentials v1.13.16 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.56 github.com/containerd/cgroups v1.1.0 github.com/containerd/cgroups/v3 v3.0.1 github.com/containerd/containerd v1.7.0 github.com/containerd/continuity v0.3.0 github.com/containerd/fifo v1.1.0 github.com/containerd/nri v0.3.0 github.com/containerd/stargz-snapshotter v0.14.3 github.com/containerd/stargz-snapshotter/estargz v0.14.3 github.com/containers/ocicrypt v1.1.7 github.com/docker/cli v23.0.1+incompatible github.com/freddierice/go-losetup v0.0.0-20220711213114-2a14873012db github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da github.com/google/go-containerregistry v0.13.0 github.com/gorilla/mux v1.8.0 github.com/hashicorp/go-retryablehttp v0.7.2 github.com/imdario/mergo v0.3.13 github.com/klauspost/compress v1.16.0 github.com/moby/locker v1.0.1 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0-rc3 github.com/pelletier/go-toml v1.9.5 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_model v0.3.0 github.com/rs/xid v1.4.0 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.3 github.com/urfave/cli/v2 v2.25.0 go.etcd.io/bbolt v1.3.7 golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/net v0.17.0 golang.org/x/sync v0.4.0 golang.org/x/sys v0.13.0 google.golang.org/grpc v1.59.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gotest.tools v2.2.0+incompatible k8s.io/api v0.26.2 k8s.io/apimachinery v0.26.2 k8s.io/client-go v0.26.2 k8s.io/cri-api v0.28.3 k8s.io/utils v0.0.0-20230726121419-3b25d923346b ) require ( github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652 // indirect github.com/Microsoft/go-winio v0.6.0 // indirect github.com/Microsoft/hcsshim v0.10.0-rc.7 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.22 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.25 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.24 // indirect github.com/aws/aws-sdk-go-v2/service/s3 v1.30.6 github.com/aws/aws-sdk-go-v2/service/sso v1.12.5 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 // indirect github.com/aws/smithy-go v1.13.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cilium/ebpf v0.9.1 // indirect github.com/containerd/ttrpc v1.2.1 // indirect github.com/containerd/typeurl/v2 v2.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cyphar/filepath-securejoin v0.2.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/distribution v2.8.2+incompatible github.com/docker/docker v23.0.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/fatih/color v1.14.1 // indirect github.com/frankban/quicktest v1.14.4 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gnostic v0.6.9 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.3.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.2.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/moby/sys/mountinfo v0.6.2 // indirect github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/sys/signal v0.7.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/runc v1.1.5 // indirect github.com/opencontainers/runtime-spec v1.1.0-rc.1 github.com/opencontainers/selinux v1.11.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 // indirect github.com/vbatts/tar-split v0.11.2 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/trace v1.14.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/mod v0.13.0 // indirect golang.org/x/oauth2 v0.11.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.90.1 // indirect k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) retract ( v0.11.3 v0.11.2 v0.11.1 v0.11.0 v0.3.0 // retagged: cd604c1b597558ea045a79c4f80a8c780909801b -> 85653575c7dafb6b06548478ee1dc61ac5905d00 ) nydus-snapshotter-0.13.4/go.sum000066400000000000000000001451421453374237200164650ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652 h1:+vTEFqeoeur6XSq06bs+roX3YiT49gUniJK7Zky7Xjg= github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20221215162035-5330a85ea652/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/KarpelesLab/reflink v1.0.1 h1:d+tdjliwOCqvub9bl0Y02GxahWkNqejNb3TZTTUcQWA= github.com/KarpelesLab/reflink v1.0.1/go.mod h1:WGkTOKNjd1FsJKBw3mu4JvrPEDJyJJ+JPtxBkbPoCok= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Microsoft/hcsshim v0.10.0-rc.7 h1:HBytQPxcv8Oy4244zbQbe6hnOnx544eL5QPUqhJldz8= github.com/Microsoft/hcsshim v0.10.0-rc.7/go.mod h1:ILuwjA+kNW+MrN/w5un7n3mTqkwsFu4Bp05/okFUZlE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/aliyun/aliyun-oss-go-sdk v2.2.6+incompatible h1:KXeJoM1wo9I/6xPTyt6qCxoSZnmASiAjlrr0dyTUKt8= github.com/aliyun/aliyun-oss-go-sdk v2.2.6+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/aws/aws-sdk-go-v2 v1.17.6 h1:Y773UK7OBqhzi5VDXMi1zVGsoj+CVHs2eaC2bDsLwi0= github.com/aws/aws-sdk-go-v2 v1.17.6/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno= github.com/aws/aws-sdk-go-v2/config v1.18.16 h1:4r7gsCu8Ekwl5iJGE/GmspA2UifqySCCkyyyPFeWs3w= github.com/aws/aws-sdk-go-v2/config v1.18.16/go.mod h1:XjM6lVbq7UgELp9NjXBrb1DQY/ownlWsvDhEQksemJc= github.com/aws/aws-sdk-go-v2/credentials v1.13.16 h1:GgToSxaENX/1zXIGNFfiVk4hxryYJ5Vt4Mh8XLAL7Lc= github.com/aws/aws-sdk-go-v2/credentials v1.13.16/go.mod h1:KP7aFJhfwPFgx9aoVYL2nYHjya5WBD98CWaadpgmnpY= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24 h1:5qyqXASrX2zy5cTnoHHa4N2c3Lc94GH7gjnBP3GwKdU= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.24/go.mod h1:neYVaeKr5eT7BzwULuG2YbLhzWZ22lpjKdCybR7AXrQ= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.56 h1:kFDCPqqVvb9vYcW82L7xYfrBGpuxXQ/8A/zYVayRQK4= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.56/go.mod h1:FoSBuessadgy8Cqp9gQF8U5rzi1XVQhiEJ6su2/kBEE= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 h1:y+8n9AGDjikyXoMBTRaHHHSaFEB8267ykmvyPodJfys= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30/go.mod h1:LUBAO3zNXQjoONBKn/kR1y0Q4cj/D02Ts0uHYjcCQLM= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 h1:r+Kv+SEJquhAZXaJ7G4u44cIwXV3f8K+N482NNAzJZA= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24/go.mod h1:gAuCezX/gob6BSMbItsSlMb6WZGV7K2+fWOvk8xBSto= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31 h1:hf+Vhp5WtTdcSdE+yEcUz8L73sAzN0R+0jQv+Z51/mI= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.31/go.mod h1:5zUjguZfG5qjhG9/wqmuyHRyUftl2B5Cp6NNxNC6kRA= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.22 h1:lTqBRUuy8oLhBsnnVZf14uRbIHPHCrGqg4Plc8gU/1U= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.22/go.mod h1:YsOa3tFriwWNvBPYHXM5ARiU2yqBNWPWeUiq+4i7Na0= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.25 h1:B/hO3jfWRm7hP00UeieNlI5O2xP5WJ27tyJG5lzc7AM= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.25/go.mod h1:54K1zgxK/lai3a4HosE4IKBwZsP/5YAJ6dzJfwsjJ0U= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 h1:c5qGfdbCHav6viBwiyDns3OXqhqAbGjfIB4uVu2ayhk= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24/go.mod h1:HMA4FZG6fyib+NDo5bpIxX1EhYjrAOveZJY2YR0xrNE= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.24 h1:i4RH8DLv/BHY0fCrXYQDr+DGnWzaxB3Ee/esxUaSavk= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.24/go.mod h1:N8X45/o2cngvjCYi2ZnvI0P4mU4ZRJfEYC3maCSsPyw= github.com/aws/aws-sdk-go-v2/service/s3 v1.30.6 h1:zzTm99krKsFcF4N7pu2z17yCcAZpQYZ7jnJZPIgEMXE= github.com/aws/aws-sdk-go-v2/service/s3 v1.30.6/go.mod h1:PudwVKUTApfm0nYaPutOXaKdPKTlZYClGBQpVIRdcbs= github.com/aws/aws-sdk-go-v2/service/sso v1.12.5 h1:bdKIX6SVF3nc3xJFw6Nf0igzS6Ff/louGq8Z6VP/3Hs= github.com/aws/aws-sdk-go-v2/service/sso v1.12.5/go.mod h1:vuWiaDB30M/QTC+lI3Wj6S/zb7tpUK2MSYgy3Guh2L0= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5 h1:xLPZMyuZ4GuqRCIec/zWuIhRFPXh2UOJdLXBSi64ZWQ= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.5/go.mod h1:QjxpHmCwAg0ESGtPQnLIVp7SedTOBMYy+Slr3IfMKeI= github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 h1:rIFn5J3yDoeuKCE9sESXqM5POTAhOP1du3bv/qTL+tE= github.com/aws/aws-sdk-go-v2/service/sts v1.18.6/go.mod h1:48WJ9l3dwP0GSHWGc5sFGGlCkuA82Mc2xnw+T6Q8aDw= github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/cilium/ebpf v0.9.1 h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4= github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/cgroups/v3 v3.0.1 h1:4hfGvu8rfGIwVIDd+nLzn/B9ZXx4BcCjzt5ToenJRaE= github.com/containerd/cgroups/v3 v3.0.1/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/containerd v1.7.0 h1:G/ZQr3gMZs6ZT0qPUZ15znx5QSdQdASW11nXTLTM2Pg= github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= github.com/containerd/nri v0.3.0 h1:2ZM4WImye1ypSnE7COjOvPAiLv84kaPILBDvb1tbDK8= github.com/containerd/nri v0.3.0/go.mod h1:Zw9q2lP16sdg0zYybemZ9yTDy8g7fPCIB3KXOGlggXI= github.com/containerd/stargz-snapshotter v0.14.3 h1:OTUVZoPSPs8mGgmQUE1dqw3WX/3nrsmsurW7UPLWl1U= github.com/containerd/stargz-snapshotter v0.14.3/go.mod h1:j2Ya4JeA5gMZJr8BchSkPjlcCEh++auAxp4nidPI6N0= github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= github.com/containerd/ttrpc v1.2.1 h1:VWv/Rzx023TBLv4WQ+9WPXlBG/s3rsRjY3i9AJ2BJdE= github.com/containerd/ttrpc v1.2.1/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak= github.com/containerd/typeurl/v2 v2.1.0 h1:yNAhJvbNEANt7ck48IlEGOxP7YAp6LLpGn5jZACDNIE= github.com/containerd/typeurl/v2 v2.1.0/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= github.com/containers/ocicrypt v1.1.7 h1:thhNr4fu2ltyGz8aMx8u48Ae0Pnbip3ePP9/mzkZ/3U= github.com/containers/ocicrypt v1.1.7/go.mod h1:7CAhjcj2H8AYp5YvEie7oVSK2AhBY8NscCYRawuDNtw= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM= github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho= github.com/docker/docker v23.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/freddierice/go-losetup v0.0.0-20220711213114-2a14873012db h1:StM6A9LvaVrFS2chAGcfRVDoBB6rHYPIGJ3GknpB25c= github.com/freddierice/go-losetup v0.0.0-20220711213114-2a14873012db/go.mod h1:pwuQfHWn6j2Fpl2AWw/bPLlKfojHxIIEa5TeKIgDFW4= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.13.0 h1:y1C7Z3e149OJbOPDBxLYR8ITPz8dTKqQwjErKVHJC8k= github.com/google/go-containerregistry v0.13.0/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbWhgp0487v+cgiilB4FqDo= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI= github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onsi/ginkgo/v2 v2.5.0 h1:TRtrvv2vdQqzkwrQ1ke6vtXf7IK34RBUJafIy1wMwls= github.com/onsi/gomega v1.24.0 h1:+0glovB9Jd6z3VR+ScSwQqXVTIfJcGA9UBM8yzQxhqg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8= github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.1.0-rc.1 h1:wHa9jroFfKGQqFHj0I1fMRKLl0pfj+ynAqBxo3v6u9w= github.com/opencontainers/runtime-spec v1.1.0-rc.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 h1:lIOOHPEbXzO3vnmx2gok1Tfs31Q8GQqKLc8vVqyQq/I= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.25.0 h1:ykdZKuQey2zq0yin/l7JOm9Mh+pg72ngYMeB0ABn6q8= github.com/urfave/cli/v2 v2.25.0/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 h1:A/5uWzF44DlIgdm/PQFwfMkW0JX+cIcQi/SwLAmZP5M= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a h1:fwgW9j3vHirt4ObdHoYNwuO24BEZjSzbh+zPaNWoiY8= google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:EMfReVxb80Dq1hhioy0sOsY9jCE46YDgHlJ7fWVUWRE= google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.26.2 h1:dM3cinp3PGB6asOySalOZxEG4CZ0IAdJsrYZXE/ovGQ= k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU= k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ= k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= k8s.io/client-go v0.26.2 h1:s1WkVujHX3kTp4Zn4yGNFK+dlDXy1bAAkIl+cFAiuYI= k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= k8s.io/cri-api v0.28.3 h1:84ifk56rAy7yYI1zYqTjLLishpFgs3q7BkCKhoLhmFA= k8s.io/cri-api v0.28.3/go.mod h1:MTdJO2fikImnX+YzE2Ccnosj3Hw2Cinw2fXYV3ppUIE= k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a h1:gmovKNur38vgoWfGtP5QOGNOA7ki4n6qNYoFAgMlNvg= k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= nydus-snapshotter-0.13.4/integration/000077500000000000000000000000001453374237200176465ustar00rootroot00000000000000nydus-snapshotter-0.13.4/integration/Dockerfile000066400000000000000000000051061453374237200216420ustar00rootroot00000000000000 ARG CONTAINERD_VER=1.6.15 ARG CONTAINERD_PROJECT=/containerd ARG RUNC_VERSION=1.1.4 ARG NYDUS_SNAPSHOTTER_PROJECT=/nydus-snapshotter ARG DOWNLOADS_MIRROR="https://github.com" ARG NYDUS_VER=2.1.4 ARG NERDCTL_VER=1.0.0 FROM golang:1.19.6-bullseye AS golang-base ARG CONTAINERD_VER ARG CONTAINERD_PROJECT ARG RUNC_VERSION ARG NYDUS_SNAPSHOTTER_PROJECT ARG DOWNLOADS_MIRROR ARG NYDUS_VER ARG NERDCTL_VER # RUN echo '\ # deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib non-free\n\ # deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-updates main contrib non-free\n\ # deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye-backports main contrib non-free\n\ # deb https://mirrors.tuna.tsinghua.edu.cn/debian-security bullseye-security main contrib non-free\n' > /etc/apt/sources.list RUN apt-get update -y && apt-get install -y libbtrfs-dev libseccomp-dev sudo psmisc jq lsof net-tools RUN go install github.com/go-delve/delve/cmd/dlv@latest # Install containerd RUN wget ${DOWNLOADS_MIRROR}/containerd/containerd/releases/download/v${CONTAINERD_VER}/containerd-${CONTAINERD_VER}-linux-amd64.tar.gz && \ tar xzf containerd-${CONTAINERD_VER}-linux-amd64.tar.gz && \ install -D -m 755 bin/* /usr/local/bin/ COPY misc/example/containerd-config.toml /etc/containerd/config.toml # Install runc RUN wget ${DOWNLOADS_MIRROR}/opencontainers/runc/releases/download/v${RUNC_VERSION}/runc.amd64 && \ install -D -m 755 runc.amd64 /usr/local/bin/runc # Install nydusd nydus-image RUN wget ${DOWNLOADS_MIRROR}/dragonflyoss/nydus/releases/download/v${NYDUS_VER}/nydus-static-v${NYDUS_VER}-linux-amd64.tgz && \ tar xzf nydus-static-v${NYDUS_VER}-linux-amd64.tgz && \ install -D -m 755 nydus-static/nydusd /usr/local/bin/nydusd && \ install -D -m 755 nydus-static/nydus-image /usr/local/bin/nydus-image && \ install -D -m 755 nydus-static/nydusctl /usr/local/bin/nydusctl # Install nerdctl RUN wget ${DOWNLOADS_MIRROR}/containerd/nerdctl/releases/download/v${NERDCTL_VER}/nerdctl-${NERDCTL_VER}-linux-amd64.tar.gz && \ tar xzf nerdctl-${NERDCTL_VER}-linux-amd64.tar.gz && \ install -D -m 755 nerdctl /usr/local/bin/nerdctl # Install fscache driver configuration file COPY misc/snapshotter/nydusd-config.fscache.json /etc/nydus/nydusd-config.fscache.json COPY misc/snapshotter/nydusd-config-localfs.json /etc/nydus/nydusd-config-localfs.json COPY misc/snapshotter/config.toml /etc/nydus/config.toml VOLUME [ "/var/lib" ] COPY integration/entrypoint.sh / WORKDIR /nydus-snapshotter ENV PATH="${PATH}:/usr/local/bin/" ENV GO111MODULE=on ENTRYPOINT [ "/bin/bash", "-c", "make install && /entrypoint.sh"]nydus-snapshotter-0.13.4/integration/entrypoint.sh000077500000000000000000000426061453374237200224300ustar00rootroot00000000000000#!/bin/bash # Copyright (c) 2022. Nydus Developers. All rights reserved. # # SPDX-License-Identifier: Apache-2.0 set -eEuo pipefail FSCACHE_NYDUSD_CONFIG=/etc/nydus/nydusd-config.fscache.json FUSE_NYDUSD_LOCALFS_CONFIG=/etc/nydus/nydusd-config-localfs.json SNAPSHOTTER_CONFIG=/etc/nydus/config.toml CONTAINERD_ROOT=/var/lib/containerd/ CONTAINERD_STATUS=/run/containerd/ REMOTE_SNAPSHOTTER_SOCKET=/run/containerd-nydus/containerd-nydus-grpc.sock REMOTE_SNAPSHOTTER_ROOT=/var/lib/containerd-nydus CONTAINERD_SOCKET=/run/containerd/containerd.sock SNAPSHOTTER_SHARED_MNT=${REMOTE_SNAPSHOTTER_ROOT}/mnt SNAPSHOTTER_CACHE_DIR=${REMOTE_SNAPSHOTTER_ROOT}/cache JAVA_IMAGE=${JAVA_IMAGE:-ghcr.io/dragonflyoss/image-service/java:nydus-nightly-v6} WORDPRESS_IMAGE=${WORDPRESS_IMAGE:-ghcr.io/dragonflyoss/image-service/wordpress:nydus-nightly-v6} TOMCAT_IMAGE=${TOMCAT_IMAGE:-ghcr.io/dragonflyoss/image-service/tomcat:nydus-nightly-v5} STARGZ_IMAGE=${STARGZ_IMAGE:-ghcr.io/stargz-containers/wordpress:5.9.2-esgz} REDIS_OCI_IMAGE=${REDIS_OCI_IMAGE:-ghcr.io/stargz-containers/redis:6.2.6-org} WORDPRESS_OCI_IMAGE=${WORDPRESS_OCI_IMAGE:-ghcr.io/dragonflyoss/image-service/wordpress:latest} PLUGIN=nydus RETRYNUM=30 RETRYINTERVAL=1 TIMEOUTSEC=180 GORACE_REPORT="$(pwd)/go_race_report" export GORACE="log_path=${GORACE_REPORT}" # trap "{ pause 1000; }" ERR function detect_go_race { if [ -n "$(ls -A ${GORACE_REPORT}.* 2>/dev/null)" ]; then echo "go race detected" reports=$(ls -A ${GORACE_REPORT}.* 2>/dev/null) for r in ${reports}; do cat "$r" done exit 1 fi } function stop_all_containers { containers=$(nerdctl ps -q | tr '\n' ' ') if [[ ${containers} == "" ]]; then return 0 else echo "Killing containers ${containers}" for C in ${containers}; do nerdctl kill "${C}" || true nerdctl stop "${C}" || true nerdctl rm "${C}" || true done return 1 fi } function pause { echo "I am going to wait for ${1} seconds only ..." sleep "${1}" } function func_retry { local SUCCESS=false for i in $(seq ${RETRYNUM}); do if "${*}"; then SUCCESS=true break fi echo "Fail(${i}). Retrying function..." sleep ${RETRYINTERVAL} done if [ "${SUCCESS}" == "true" ]; then return 0 else return 1 fi } function retry { local SUCCESS=false for i in $(seq ${RETRYNUM}); do if eval "timeout ${TIMEOUTSEC} ${@}"; then SUCCESS=true break fi echo "Fail(${i}). Retrying..." sleep ${RETRYINTERVAL} done if [ "${SUCCESS}" == "true" ]; then return 0 else return 1 fi } function can_erofs_ondemand_read { return 1 # grep 'CONFIG_EROFS_FS_ONDEMAND=[ym]' /usr/src/linux-headers-"$(uname -r)"/.config 1>/dev/null # echo $? } function validate_mnt_number { expected="${1}" found=$(mount -t fuse | wc -l) if [[ $found != "$expected" ]]; then echo "expecting $expected mountpoints, but found $found" return 1 else return 0 fi } function set_config_option { KEY="${1}" VALUE="${2}" sed -i "s/\($KEY *= *\).*/\1$VALUE/" "${SNAPSHOTTER_CONFIG}" } function set_recover_policy { policy="${1}" set_config_option "recover_policy" \"${policy}\" } function set_enable_referrer_detect { set_config_option "enable_referrer_detect" "true" } function reboot_containerd { killall "containerd" || true killall "containerd-nydus-grpc" || true # In case nydusd is using cache dir killall "nydusd" || true # Let snapshotter shutdown all its services. sleep 0.5 # FIXME echo "umount globally shared mountpoint" umount_global_shared_mnt rm -rf "${CONTAINERD_STATUS}"* rm -rf "${CONTAINERD_ROOT}"* if [ -f "${REMOTE_SNAPSHOTTER_SOCKET}" ]; then rm "${REMOTE_SNAPSHOTTER_SOCKET}" fi local daemon_mode=${1} local fs_driver=${2:-fusedev} local recover_policy=${3:-none} if [ -d "${REMOTE_SNAPSHOTTER_ROOT:?}/snapshotter/snapshots/" ]; then umount -t fuse --all fi if [[ "${fs_driver}" == fusedev ]]; then nydusd_config=/etc/nydus/nydusd-config.json else nydusd_config="$FSCACHE_NYDUSD_CONFIG" fi # Override nydus configuration, this configuration is usually set by each case if [[ -n ${NYDUS_CONFIG_PATH:-} ]]; then nydusd_config=${NYDUS_CONFIG_PATH} fi # rm -rf "${REMOTE_SNAPSHOTTER_ROOT:?}"/* || fuser -m "${REMOTE_SNAPSHOTTER_ROOT}/mnt" && false rm -rf "${REMOTE_SNAPSHOTTER_ROOT:?}"/* set_recover_policy "${recover_policy}" containerd-nydus-grpc --log-to-stdout \ --daemon-mode "${daemon_mode}" --fs-driver "${fs_driver}" \ --config "${SNAPSHOTTER_CONFIG}" --nydusd-config "${nydusd_config}" & retry ls "${REMOTE_SNAPSHOTTER_SOCKET}" containerd --log-level info --config=/etc/containerd/config.toml & retry ls "${CONTAINERD_SOCKET}" # Makes sure containerd and containerd-nydus-grpc are up-and-running. UNIQUE_SUFFIX=$(date +%s%N | shasum | base64 | fold -w 10 | head -1) retry ctr snapshots --snapshotter="${PLUGIN}" prepare "connectiontest-dummy-${UNIQUE_SUFFIX}" "" } function restart_snapshotter { killall -INT containerd-nydus-grpc local daemon_mode=$1 } function umount_global_shared_mnt { umount "${SNAPSHOTTER_SHARED_MNT}" || true } function is_cache_cleared { # With fscache driver, 2.1 nydusd don't have API to release the cache files. # Thy locate at directory ${SNAPSHOTTER_CACHE_DIR}/cache if [[ $(ls -A -p "${SNAPSHOTTER_CACHE_DIR}" | grep -v /) == "" ]]; then true else echo "ERROR: Cache is not cleared" false fi } function nerdctl_prune_images { # Wait for containers observation. sleep 1 func_retry stop_all_containers nerdctl container prune -f nerdctl image prune --all -f nerdctl images is_cache_cleared } function start_single_container_multiple_daemons { echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd multiple nerdctl --snapshotter nydus run -d --net none "${JAVA_IMAGE}" detect_go_race } function start_multiple_containers_multiple_daemons { echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd multiple nerdctl --snapshotter nydus run -d --net none "${JAVA_IMAGE}" nerdctl --snapshotter nydus run -d --net none "${WORDPRESS_IMAGE}" nerdctl --snapshotter nydus run -d --net none "${TOMCAT_IMAGE}" nerdctl_prune_images nerdctl --snapshotter nydus run -d --net none "${TOMCAT_IMAGE}" nerdctl --snapshotter nydus run -d --net none "${JAVA_IMAGE}" nerdctl --snapshotter nydus run -d --net none "${WORDPRESS_IMAGE}" detect_go_race } function start_multiple_containers_shared_daemon { echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd shared nerdctl --snapshotter nydus run -d --net none "${JAVA_IMAGE}" nerdctl --snapshotter nydus run -d --net none "${WORDPRESS_IMAGE}" nerdctl --snapshotter nydus run -d --net none "${TOMCAT_IMAGE}" detect_go_race } function start_single_container_on_stargz { echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd multiple killall "containerd-nydus-grpc" || true sleep 0.5 containerd-nydus-grpc --enable-stargz --daemon-mode multiple --fs-driver fusedev \ --recover-policy none --log-to-stdout --config-path /etc/nydus/nydusd-config.json & nerdctl --snapshotter nydus run -d --net none "${STARGZ_IMAGE}" detect_go_race } function start_container_on_oci { echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd multiple nerdctl --snapshotter nydus run -d --net none "${REDIS_OCI_IMAGE}" nerdctl --snapshotter nydus run -d --net none "${WORDPRESS_OCI_IMAGE}" pause 2 func_retry stop_all_containers # Deleteing with flag --async as a fuzzer nerdctl image rm --async --force "${REDIS_OCI_IMAGE}" nerdctl image rm --force "${WORDPRESS_OCI_IMAGE}" } function start_container_with_referrer_detect { echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd multiple set_enable_referrer_detect nerdctl --snapshotter nydus run -d --net none "${WORDPRESS_OCI_IMAGE}" detect_go_race } function pull_remove_one_image { echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd multiple nerdctl --snapshotter nydus image pull "${JAVA_IMAGE}" nerdctl --snapshotter nydus image rm "${JAVA_IMAGE}" detect_go_race } function pull_remove_multiple_images { local daemon_mode=$1 echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd "${daemon_mode}" # Because nydusd is not started right after image pull. # Nydusd is started when preparing the writable active snapshot as the # uppermost layer. So we must create a container to start nydusd. # Then to test if snapshotter's nydusd daemons management works well nerdctl --snapshotter nydus image pull "${JAVA_IMAGE}" nerdctl --snapshotter nydus image pull "${WORDPRESS_IMAGE}" nerdctl --snapshotter nydus image pull "${TOMCAT_IMAGE}" nerdctl --snapshotter nydus create --rm --net none "${TOMCAT_IMAGE}" nerdctl --snapshotter nydus create --rm --net none "${WORDPRESS_IMAGE}" nerdctl --snapshotter nydus image rm --force "${JAVA_IMAGE}" nerdctl --snapshotter nydus image rm --force "${WORDPRESS_IMAGE}" # Deleteing with flag --async as a fuzzer nerdctl --snapshotter nydus image rm --force --async "${TOMCAT_IMAGE}" nerdctl --snapshotter nydus image pull "${TOMCAT_IMAGE}" nerdctl --snapshotter nydus create --net none "${TOMCAT_IMAGE}" detect_go_race # TODO: Validate running nydusd number } function start_multiple_containers_shared_daemon_fscache { echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd shared fscache nerdctl --snapshotter nydus run -d --net none "${JAVA_IMAGE}" nerdctl --snapshotter nydus run -d --net none "${WORDPRESS_IMAGE}" detect_go_race } function kill_snapshotter_and_nydusd_recover { local daemon_mode=$1 echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd "${daemon_mode}" nerdctl --snapshotter nydus image pull "${WORDPRESS_IMAGE}" nerdctl --snapshotter nydus image pull "${JAVA_IMAGE}" c1=$(nerdctl --snapshotter nydus create --net none "${JAVA_IMAGE}") c2=$(nerdctl --snapshotter nydus create --net none "${WORDPRESS_IMAGE}") sleep 1 echo "killing nydusd" killall -9 nydusd || true echo "killing nydus-snapshotter" killall -9 containerd-nydus-grpc || true rm "${REMOTE_SNAPSHOTTER_SOCKET:?}" containerd-nydus-grpc --config "${SNAPSHOTTER_CONFIG}" \ --daemon-mode "${daemon_mode}" --log-to-stdout --config-path /etc/nydus/nydusd-config.json & retry ls "${REMOTE_SNAPSHOTTER_SOCKET}" echo "start new containers" nerdctl --snapshotter nydus start "$c1" nerdctl --snapshotter nydus start "$c2" detect_go_race } # No restart or failover recover policy. Just let snapshotter start a new nydusd when it refreshes. function fscache_kill_snapshotter_and_nydusd_recover { local daemon_mode=$1 echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd "${daemon_mode}" fscache nerdctl --snapshotter nydus image pull "${WORDPRESS_IMAGE}" nerdctl --snapshotter nydus image pull "${JAVA_IMAGE}" c1=$(nerdctl --snapshotter nydus create --net none "${JAVA_IMAGE}") c2=$(nerdctl --snapshotter nydus create --net none "${WORDPRESS_IMAGE}") sleep 1 echo "killing nydusd" killall -9 nydusd || true killall -9 containerd-nydus-grpc || true sleep 1 rm "${REMOTE_SNAPSHOTTER_SOCKET:?}" containerd-nydus-grpc --log-to-stdout --config "${SNAPSHOTTER_CONFIG}" \ --daemon-mode "${daemon_mode}" --fs-driver fscache --config-path /etc/nydus/nydusd-config.fscache.json & retry ls "${REMOTE_SNAPSHOTTER_SOCKET}" echo "start new containers" nerdctl --snapshotter nydus start "$c1" nerdctl --snapshotter nydus start "$c2" # killall -9 nydusd sleep 0.2 detect_go_race } function fscache_kill_nydusd_failover() { local daemon_mode=shared echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd "${daemon_mode}" fscache failover nerdctl --snapshotter nydus image pull "${WORDPRESS_IMAGE}" nerdctl --snapshotter nydus image pull "${JAVA_IMAGE}" c1=$(nerdctl --snapshotter nydus create --net none "${JAVA_IMAGE}") c2=$(nerdctl --snapshotter nydus create --net none "${WORDPRESS_IMAGE}") killall -9 nydusd echo "start new containers" nerdctl --snapshotter nydus start "$c1" nerdctl --snapshotter nydus start "$c2" sleep 1 detect_go_race } function only_restart_snapshotter { local daemon_mode=$1 echo "testing $FUNCNAME ${daemon_mode}" nerdctl_prune_images reboot_containerd "${daemon_mode}" nerdctl --snapshotter nydus image pull "${WORDPRESS_IMAGE}" nerdctl --snapshotter nydus image pull "${JAVA_IMAGE}" c1=$(nerdctl --snapshotter nydus create --net none "${JAVA_IMAGE}") c2=$(nerdctl --snapshotter nydus create --net none "${WORDPRESS_IMAGE}") echo "killing snapshotter" killall -9 containerd-nydus-grpc || true rm "${REMOTE_SNAPSHOTTER_SOCKET:?}" containerd-nydus-grpc --config "${SNAPSHOTTER_CONFIG}" --daemon-mode \ "${daemon_mode}" --log-to-stdout --config-path /etc/nydus/nydusd-config.json & retry ls "${REMOTE_SNAPSHOTTER_SOCKET}" if [[ "${daemon_mode}" == "shared" ]]; then validate_mnt_number 1 else validate_mnt_number 2 fi echo "start new containers" nerdctl --snapshotter nydus start "$c1" nerdctl --snapshotter nydus start "$c2" detect_go_race } function kill_nydusd_recover_nydusd { local daemon_mode=$1 echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd "${daemon_mode}" fusedev restart nerdctl --snapshotter nydus image pull "${WORDPRESS_IMAGE}" nerdctl --snapshotter nydus image pull "${JAVA_IMAGE}" c1=$(nerdctl --snapshotter nydus create --net none "${JAVA_IMAGE}") c2=$(nerdctl --snapshotter nydus create --net none "${WORDPRESS_IMAGE}") pause 1 echo "killing nydusd" killall -9 nydusd || true echo "start new containers" nerdctl --snapshotter nydus start "$c1" nerdctl --snapshotter nydus start "$c2" detect_go_race } function ctr_snapshot_usage { local daemon_mode=$1 echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd "${daemon_mode}" fusedev restart nerdctl --snapshotter nydus image pull "${WORDPRESS_IMAGE}" nerdctl --snapshotter nydus image pull "${JAVA_IMAGE}" c1=$(nerdctl --snapshotter nydus create --net none "${JAVA_IMAGE}") c2=$(nerdctl --snapshotter nydus create --net none "${WORDPRESS_IMAGE}") pause 1 ctr snapshot --snapshotter nydus ls ctr snapshot --snapshotter nydus usage echo "start new containers" nerdctl --snapshotter nydus start "$c1" nerdctl --snapshotter nydus start "$c2" ctr snapshot --snapshotter nydus ls ctr snapshot --snapshotter nydus usage detect_go_race } function kill_multiple_nydusd_recover_failover { local daemon_mode=$1 echo "testing $FUNCNAME" nerdctl_prune_images reboot_containerd "${daemon_mode}" fusedev failover c1=$(nerdctl --snapshotter nydus run -d --net none "${JAVA_IMAGE}") c2=$(nerdctl --snapshotter nydus run -d --net none "${WORDPRESS_IMAGE}") pause 1 nerdctl kill "$c1" || true nerdctl kill "$c2 " || true echo "killing nydusd" killall -9 nydusd || true echo "start new containers" c1=$(nerdctl --snapshotter nydus run -d --net none "${JAVA_IMAGE}") c2=$(nerdctl --snapshotter nydus run -d --net none "${WORDPRESS_IMAGE}") pause 1 nerdctl kill "$c1" || true nerdctl kill "$c2 " || true echo "killing nydusd again" killall -9 nydusd || true c1=$(nerdctl --snapshotter nydus run -d --net none "${JAVA_IMAGE}") c2=$(nerdctl --snapshotter nydus run -d --net none "${WORDPRESS_IMAGE}") detect_go_race } # Refer to https://github.com/moby/moby/blob/088afc99e4bf8adb78e29733396182417d67ada2/hack/dind#L28-L38 function enable_nesting_for_cgroup_v2() { if [ -f /sys/fs/cgroup/cgroup.controllers ]; then mkdir -p /sys/fs/cgroup/init xargs -rn1 /sys/fs/cgroup/init/cgroup.procs || : sed -e 's/ / +/g' -e 's/^/-/' /sys/fs/cgroup/cgroup.subtree_control fi } enable_nesting_for_cgroup_v2 reboot_containerd multiple start_single_container_multiple_daemons start_multiple_containers_multiple_daemons start_multiple_containers_shared_daemon pull_remove_one_image pull_remove_multiple_images shared pull_remove_multiple_images multiple # start_single_container_on_stargz only_restart_snapshotter shared only_restart_snapshotter multiple kill_snapshotter_and_nydusd_recover shared kill_snapshotter_and_nydusd_recover multiple ctr_snapshot_usage multiple ctr_snapshot_usage shared if [[ $(can_erofs_ondemand_read) == 0 ]]; then kill_multiple_nydusd_recover_failover multiple kill_multiple_nydusd_recover_failover shared start_multiple_containers_shared_daemon_fscache fscache_kill_snapshotter_and_nydusd_recover shared fscache_kill_nydusd_failover fi start_container_on_oci start_container_with_referrer_detect nydus-snapshotter-0.13.4/internal/000077500000000000000000000000001453374237200171375ustar00rootroot00000000000000nydus-snapshotter-0.13.4/internal/constant/000077500000000000000000000000001453374237200207705ustar00rootroot00000000000000nydus-snapshotter-0.13.4/internal/constant/values.go000066400000000000000000000032351453374237200226210ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ // constants of nydus snapshotter CLI config package constant const ( DaemonModeMultiple string = "multiple" DaemonModeDedicated string = "dedicated" DaemonModeShared string = "shared" DaemonModeNone string = "none" DaemonModeInvalid string = "" ) const ( // Mount RAFS filesystem by using EROFS over block devices. FsDriverBlockdev string = "blockdev" // Mount RAFS filesystem by using FUSE subsystem FsDriverFusedev string = "fusedev" // Mount RAFS filesystem by using fscache/EROFS. FsDriverFscache string = "fscache" // Only prepare/supply meta/data blobs, do not mount RAFS filesystem. FsDriverNodev string = "nodev" // Relay layer content download operation to other agents. FsDriverProxy string = "proxy" ) const ( DefaultDaemonMode string = DaemonModeMultiple DefaultFsDriver string = FsDriverFusedev DefaultLogLevel string = "info" DefaultGCPeriod string = "24h" DefaultNydusDaemonConfigPath string = "/etc/nydus/nydusd-config.json" NydusdBinaryName string = "nydusd" NydusImageBinaryName string = "nydus-image" DefaultRootDir = "/var/lib/containerd-nydus" DefaultAddress = "/run/containerd-nydus/containerd-nydus-grpc.sock" DefaultSystemControllerAddress = "/run/containerd-nydus/system.sock" // Log rotation DefaultDaemonRotateLogMaxSize = 100 // 100 megabytes DefaultRotateLogMaxSize = 200 // 200 megabytes DefaultRotateLogMaxBackups = 5 DefaultRotateLogMaxAge = 0 // days DefaultRotateLogLocalTime = true DefaultRotateLogCompress = true ) nydus-snapshotter-0.13.4/internal/flags/000077500000000000000000000000001453374237200202335ustar00rootroot00000000000000nydus-snapshotter-0.13.4/internal/flags/flags.go000066400000000000000000000062261453374237200216640ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package flags import ( "github.com/containerd/nydus-snapshotter/internal/constant" "github.com/urfave/cli/v2" ) type Args struct { Address string NydusdConfigPath string SnapshotterConfigPath string RootDir string NydusdPath string NydusImagePath string DaemonMode string FsDriver string LogLevel string LogToStdout bool LogToStdoutCount int PrintVersion bool } type Flags struct { Args *Args F []cli.Flag } func buildFlags(args *Args) []cli.Flag { return []cli.Flag{ &cli.StringFlag{ Name: "root", Usage: "directory to store snapshotter data and working states", Destination: &args.RootDir, DefaultText: constant.DefaultRootDir, }, &cli.StringFlag{ Name: "address", Usage: "remote snapshotter gRPC socket path", Destination: &args.Address, DefaultText: constant.DefaultAddress, }, &cli.StringFlag{ Name: "config", Usage: "path to nydus-snapshotter configuration (such as: config.toml)", Destination: &args.SnapshotterConfigPath, }, &cli.StringFlag{ Name: "nydus-image", Usage: "path to `nydus-image` binary, default to search in $PATH (such as: /usr/local/bin/nydus-image)", Destination: &args.NydusImagePath, }, &cli.StringFlag{ Name: "nydusd", Usage: "path to `nydusd` binary, default to search in $PATH (such as: /usr/local/bin/nydusd)", Destination: &args.NydusdPath, }, &cli.StringFlag{ Name: "nydusd-config", Aliases: []string{"config-path"}, Usage: "path to nydusd configuration (such as: nydusd-config.json or nydusd-config-v2.toml)", Destination: &args.NydusdConfigPath, DefaultText: constant.DefaultNydusDaemonConfigPath, }, &cli.StringFlag{ Name: "daemon-mode", Usage: "nydusd daemon working mode, possible values: \"dedicated\", \"multiple\", \"shared\" or \"none\". \"multiple\" is an alias of \"dedicated\" and will be deprecated in v1.0", Destination: &args.DaemonMode, DefaultText: constant.DaemonModeMultiple, }, &cli.StringFlag{ Name: "fs-driver", Usage: "driver to mount RAFS filesystem, possible values: \"fusedev\", \"fscache\"", Destination: &args.FsDriver, DefaultText: constant.FsDriverFusedev, }, &cli.StringFlag{ Name: "log-level", Usage: "logging level, possible values: \"trace\", \"debug\", \"info\", \"warn\", \"error\"", Destination: &args.LogLevel, DefaultText: constant.DefaultLogLevel, }, &cli.BoolFlag{ Name: "log-to-stdout", Usage: "print log messages to standard output", Destination: &args.LogToStdout, Count: &args.LogToStdoutCount, }, &cli.BoolFlag{ Name: "version", Usage: "print version and build information", Destination: &args.PrintVersion, }, } } func NewFlags() *Flags { var args Args return &Flags{ Args: &args, F: buildFlags(&args), } } nydus-snapshotter-0.13.4/internal/flags/flags_test.go000066400000000000000000000012001453374237200227060ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package flags import ( "flag" "testing" "github.com/stretchr/testify/assert" ) func TestNewFlags(t *testing.T) { set := flag.NewFlagSet("test", 0) flags := NewFlags() for _, i := range flags.F { err := i.Apply(set) assert.Nil(t, err) } err := set.Parse([]string{"--config-path", "/etc/testconfig", "--root", "/root", "--log-level", "info"}) assert.Nil(t, err) assert.Equal(t, flags.Args.NydusdConfigPath, "/etc/testconfig") assert.Equal(t, flags.Args.LogLevel, "info") assert.Equal(t, flags.Args.RootDir, "/root") } nydus-snapshotter-0.13.4/internal/logging/000077500000000000000000000000001453374237200205655ustar00rootroot00000000000000nydus-snapshotter-0.13.4/internal/logging/setup.go000066400000000000000000000032661453374237200222630ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package logging import ( "context" "os" "path/filepath" "github.com/containerd/containerd/log" "github.com/pkg/errors" "github.com/sirupsen/logrus" lumberjack "gopkg.in/natefinch/lumberjack.v2" ) const ( DefaultLogDirName = "logs" defaultLogFileName = "nydus-snapshotter.log" ) type RotateLogArgs struct { RotateLogMaxSize int RotateLogMaxBackups int RotateLogMaxAge int RotateLogLocalTime bool RotateLogCompress bool } func SetUp(logLevel string, logToStdout bool, logDir string, logRotateArgs *RotateLogArgs) error { lvl, err := logrus.ParseLevel(logLevel) if err != nil { return err } logrus.SetLevel(lvl) if logToStdout { logrus.SetOutput(os.Stdout) } else { if logRotateArgs == nil { return errors.New("logRotateArgs is needed when logToStdout is false") } if err := os.MkdirAll(logDir, 0755); err != nil { return errors.Wrapf(err, "create log dir %s", logDir) } logFile := filepath.Join(logDir, defaultLogFileName) lumberjackLogger := &lumberjack.Logger{ Filename: logFile, MaxSize: logRotateArgs.RotateLogMaxSize, MaxBackups: logRotateArgs.RotateLogMaxBackups, MaxAge: logRotateArgs.RotateLogMaxAge, Compress: logRotateArgs.RotateLogCompress, LocalTime: logRotateArgs.RotateLogLocalTime, } logrus.SetOutput(lumberjackLogger) } logrus.SetFormatter(&logrus.TextFormatter{ TimestampFormat: log.RFC3339NanoFixed, FullTimestamp: true, }) return nil } func WithContext() context.Context { return log.WithLogger(context.Background(), log.L) } nydus-snapshotter-0.13.4/internal/logging/setup_test.go000066400000000000000000000030471453374237200233170ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package logging import ( "os" "path/filepath" "strings" "testing" "time" "github.com/containerd/containerd/log" "github.com/sirupsen/logrus" "gotest.tools/assert" ) const ( TestLogDirName = "test-rotate-logs" TestRootDirName = "test-root" ) func GetRotateLogFileNumbers(testLogDir string, suffix string) int { i := 0 err := filepath.Walk(testLogDir, func(fname string, fi os.FileInfo, err error) error { if !fi.IsDir() && strings.HasSuffix(fname, suffix) { i++ } return nil }) if err != nil { log.L.Fatal("walk path") } return i } func TestSetUp(t *testing.T) { // Try to clean previously created test directory. os.RemoveAll(TestLogDirName) logRotateArgs := &RotateLogArgs{ RotateLogMaxSize: 1, // 1MB RotateLogMaxBackups: 5, RotateLogMaxAge: 0, RotateLogLocalTime: true, RotateLogCompress: true, } logLevel := logrus.InfoLevel.String() err := SetUp(logLevel, true, TestLogDirName, nil) assert.NilError(t, err, nil) err = SetUp(logLevel, false, TestLogDirName, nil) assert.ErrorContains(t, err, "logRotateArgs is needed when logToStdout is false") err = SetUp(logLevel, false, TestLogDirName, logRotateArgs) assert.NilError(t, err) for i := 0; i < 100000; i++ { // total 9.1MB log.L.Infof("test log, now: %s", time.Now().Format("2006-01-02 15:04:05")) } assert.Equal(t, GetRotateLogFileNumbers(TestLogDirName, "log.gz"), logRotateArgs.RotateLogMaxBackups) os.RemoveAll(TestLogDirName) } nydus-snapshotter-0.13.4/misc/000077500000000000000000000000001453374237200162565ustar00rootroot00000000000000nydus-snapshotter-0.13.4/misc/example/000077500000000000000000000000001453374237200177115ustar00rootroot00000000000000nydus-snapshotter-0.13.4/misc/example/10-containerd-net.conflist000066400000000000000000000006741453374237200246130ustar00rootroot00000000000000{ "cniVersion": "1.0.0", "name": "containerd-net", "plugins": [ { "type": "bridge", "bridge": "cni0", "isGateway": true, "ipMasq": true, "promiscMode": true, "ipam": { "type": "host-local", "subnet": "10.88.0.0/16", "routes": [ { "dst": "0.0.0.0/0" } ] } }, { "type": "portmap", "capabilities": {"portMappings": true} } ] } nydus-snapshotter-0.13.4/misc/example/README.md000066400000000000000000000060211453374237200211670ustar00rootroot00000000000000## Example to setup and test nydus-snapshotter The directory holds a few example config files to setup a nydus POC environment that saves its all state files in `/var/lib/containerd-test`, as specified in `containerd-test-config.toml`. For now it contains following files: * crictl.yaml: `crictl` tool config * containerd-config.toml: `containerd` config * containerd-config-v1.toml: `containerd` config in the deprecated v1 format, provided for old containerd versions * containerd-test-config.toml: `containerd` config for testing * 10-containerd-net.conflist: `containerd` cni config * pod.yaml: pod spec yaml to be used by `crictl` * container.yaml: container spec yaml to be used by `crictl` With these config files, users can setup a nydus environment by doing: ``` export CNI_VERSION=v1.1.0 export CRICTL_VERSION=v1.23.0 sudo mkdir -p /var/lib/containerd-test/ /etc/containerd/ /opt/cni/bin/ /etc/cni/net.d/ sudo cp misc/example/containerd-test-config.toml /etc/containerd/ sudo cp misc/example/crictl.yaml /etc/ sudo cp misc/example/10-containerd-net.conflist /etc/cni/net.d/ # install cni plugin wget https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION/cni-plugins-linux-amd64-$CNI_VERSION.tgz sudo tar xzf cni-plugins-linux-amd64-$CNI_VERSION.tgz -C /opt/cni/bin/ # install crictl wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$CRICTL_VERSION/crictl-$CRICTL_VERSION-linux-amd64.tar.gz tar xzf crictl-$CRICTL_VERSION-linux-amd64.tar.gz -C /usr/local/bin/ # install nydus-overlayfs NYDUS_VER=v$(curl -s "https://api.github.com/repos/dragonflyoss/nydus/releases/latest" | jq -r .tag_name | sed 's/^v//') wget https://github.com/dragonflyoss/nydus/releases/download/$NYDUS_VER/nydus-static-$NYDUS_VER-linux-amd64.tgz tar xzf nydus-static-$NYDUS_VER-linux-amd64.tgz sudo cp nydus-static/nydus-overlayfs /usr/local/sbin/ ``` Then start a `nydus-snapshotter` container with: ``` docker run -d --device /dev/fuse --cap-add SYS_ADMIN --security-opt apparmor:unconfined -e CONTAINERD_ROOT=/var/lib/containerd-test -v /var/lib/containerd-test:/var/lib/containerd-test:shared ghcr.io/containerd/nydus-snapshotter/nydus-snapshotter:latest ``` It will bindmount host directory `/var/lib/containerd-test` inside the container and share all the nydus mountpoints from there. `containerd` config in `containerd-test-config.toml` has been setup to use the `nydus-snapshotter` grpc unix domain socket at `/var/lib/containerd-test/io.containerd.snapshotter.v1.nydus/containerd-nydus-grpc.sock`. Then start containerd with: ``` sudo containerd --config /etc/containerd/containerd-test-config.toml ``` Now we can use `crictl` to test against the POC environment. ## Deploy in production When deploying `nydus-snapshotter` in production, following changes need to be applied: 1. remove the `CONTAINERD_ROOT` environment variable when starting `nydus-snapshotter` container, and bindmount `/var/lib/containerd` to `/var/lib/containerd` in the container. 2. use `containerd-config.toml` instead of `containerd-test-config.toml` to start containerd. nydus-snapshotter-0.13.4/misc/example/container.yaml000066400000000000000000000002371453374237200225610ustar00rootroot00000000000000metadata: name: foobar-container image: image: ghcr.io/dragonflyoss/image-service/ubuntu:nydus-latest command: ["tail", "-f", "/dev/null"] log_path: log.0 nydus-snapshotter-0.13.4/misc/example/containerd-config-v1.toml000066400000000000000000000013131453374237200245210ustar00rootroot00000000000000root = "/var/lib/containerd" state = "/run/containerd" oom_score = 0 [grpc] address = "/run/containerd/containerd.sock" [debug] level = "debug" [plugins] [plugins.cgroups] no_prometheus = false [plugins.cri] [plugins.cri.containerd] snapshotter = "nydus" disable_snapshot_annotations = false [plugins.cri.containerd.runtimes] [plugins.cri.containerd.runtimes.kata] runtime_type = "io.containerd.kata.v2" privileged_without_host_devices = true [plugins.cri.cni] bin_dir = "/opt/cni/bin" conf_dir = "/etc/cni/net.d" [proxy_plugins] [proxy_plugins.nydus] type = "snapshot" address = "/run/containerd-nydus/containerd-nydus-grpc.sock" nydus-snapshotter-0.13.4/misc/example/containerd-config.toml000066400000000000000000000014101453374237200241730ustar00rootroot00000000000000version = 2 root = "/var/lib/containerd" state = "/run/containerd" oom_score = 0 [debug] level = "debug" [plugins."io.containerd.grpc.v1.cri"] [plugins."io.containerd.grpc.v1.cri".containerd] snapshotter = "nydus" disable_snapshot_annotations = false [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] runtime_type = "io.containerd.runc.v2" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata] runtime_type = "io.containerd.kata.v2" privileged_without_host_devices = true [plugins."io.containerd.grpc.v1.cri".cni] bin_dir = "/opt/cni/bin" conf_dir = "/etc/cni/net.d" [proxy_plugins] [proxy_plugins.nydus] type = "snapshot" address = "/run/containerd-nydus/containerd-nydus-grpc.sock" nydus-snapshotter-0.13.4/misc/example/containerd-test-config.toml000066400000000000000000000015621453374237200251600ustar00rootroot00000000000000version = 2 root = "/var/lib/containerd-test" state = "/run/containerd-test" oom_score = 0 [grpc] address = "/run/containerd-test/containerd.sock" [debug] level = "debug" [plugins."io.containerd.grpc.v1.cri"] [plugins."io.containerd.grpc.v1.cri".containerd] snapshotter = "nydus" disable_snapshot_annotations = false [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] runtime_type = "io.containerd.runc.v2" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata] runtime_type = "io.containerd.kata.v2" privileged_without_host_devices = true [plugins."io.containerd.grpc.v1.cri".cni] bin_dir = "/opt/cni/bin" conf_dir = "/etc/cni/net.d" [proxy_plugins] [proxy_plugins.nydus] type = "snapshot" address = "/var/lib/containerd-test/io.containerd.snapshotter.v1.nydus/containerd-nydus-grpc.sock" nydus-snapshotter-0.13.4/misc/example/crictl.yaml000066400000000000000000000000761453374237200220600ustar00rootroot00000000000000runtime-endpoint: unix:///run/containerd-test/containerd.sock nydus-snapshotter-0.13.4/misc/example/optimizer-nri-plugin.conf000066400000000000000000000010041453374237200246570ustar00rootroot00000000000000# The directory to persist accessed files list for container. persist_dir = "/opt/nri/optimizer/results" # Whether to make the csv file human readable. readable = false # The path of optimizer server binary. server_path = "/usr/local/bin/optimizer-server" # The timeout to kill optimizer server, 0 to disable it. timeout = 0 # Whether to overwrite the existed persistent files. overwrite = false # The events that containerd subscribes to. # Do not change this element. events = [ "StartContainer", "StopContainer" ]nydus-snapshotter-0.13.4/misc/example/pod.yaml000066400000000000000000000001641453374237200213600ustar00rootroot00000000000000metadata: attempt: 1 name: foobar namespace: default log_directory: /tmp linux: namespaces: options: {} nydus-snapshotter-0.13.4/misc/nri-prefetch/000077500000000000000000000000001453374237200206445ustar00rootroot00000000000000nydus-snapshotter-0.13.4/misc/nri-prefetch/prefetchConfig.toml000066400000000000000000000002121453374237200244620ustar00rootroot00000000000000[file_prefetch] # This is used to configure the socket address for the file prefetch. socket_address = "/run/containerd-nydus/system.sock"nydus-snapshotter-0.13.4/misc/optimizer/000077500000000000000000000000001453374237200203005ustar00rootroot00000000000000nydus-snapshotter-0.13.4/misc/optimizer/containerd-config.toml000066400000000000000000000016041453374237200245670ustar00rootroot00000000000000# Copyright 2018-2022 Docker Inc. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. version = 2 [proxy_plugins] [proxy_plugins.nydus] type = "snapshot" address = "/run/containerd-nydus/containerd-nydus-grpc.sock" [plugins."io.containerd.nri.v1.nri"] config_file = "/etc/nri/nri.conf" disable = false plugin_path = "/opt/nri/plugins" socket_path = "/var/run/nri.sock"nydus-snapshotter-0.13.4/misc/optimizer/crictl.yaml000066400000000000000000000002441453374237200224440ustar00rootroot00000000000000runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:////run/containerd/containerd.sock timeout: 2 debug: false pull-image-on-create: falsenydus-snapshotter-0.13.4/misc/optimizer/nginx.yaml000066400000000000000000000003251453374237200223070ustar00rootroot00000000000000metadata: name: nginx image: image: nginx:1.23.3 mounts: - host_path: script container_path: /script command: - /script/entrypoint.sh args: - /script/file_list.txt log_path: nginx.0.log linux: {}nydus-snapshotter-0.13.4/misc/optimizer/sandbox.yaml000066400000000000000000000002001453374237200226120ustar00rootroot00000000000000metadata: name: nginx-sandbox namespace: default attempt: 1 uid: hdishd83djaidwnduwk28bcsb log_directory: /tmp linux: {}nydus-snapshotter-0.13.4/misc/optimizer/script/000077500000000000000000000000001453374237200216045ustar00rootroot00000000000000nydus-snapshotter-0.13.4/misc/optimizer/script/entrypoint.sh000077500000000000000000000006011453374237200243530ustar00rootroot00000000000000#!/usr/bin/env bash path=$1 default_path=file_list_path.txt if [[ $# -eq 0 ]]; then path=${default_path} fi files=($(cat ${path} | tr "\n" " ")) files_number=${#files[@]} echo "file number: $files_number" for file in "${files[@]}"; do file_size=$(stat -c%s "${file}") echo "file: ${file} size: ${file_size}" cat ${file} >/dev/null done echo "Read file list done." nydus-snapshotter-0.13.4/misc/optimizer/script/file_list.txt000066400000000000000000000007441453374237200243240ustar00rootroot00000000000000/lib/x86_64-linux-gnu/ld-2.31.so /lib/x86_64-linux-gnu/libc-2.31.so /lib/x86_64-linux-gnu/libtinfo.so.6.2 /lib/x86_64-linux-gnu/libdl-2.31.so /lib/x86_64-linux-gnu/libnss_files-2.31.so /lib/x86_64-linux-gnu/libselinux.so.1 /usr/lib/x86_64-linux-gnu/libpcre2-8.so.0.10.1 /lib/x86_64-linux-gnu/libpthread-2.31.so /docker-entrypoint.sh /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh /docker-entrypoint.d/20-envsubst-on-templates.sh /docker-entrypoint.d/30-tune-worker-processes.sh nydus-snapshotter-0.13.4/misc/snapshotter/000077500000000000000000000000001453374237200206305ustar00rootroot00000000000000nydus-snapshotter-0.13.4/misc/snapshotter/Dockerfile000066400000000000000000000017231453374237200226250ustar00rootroot00000000000000FROM alpine:3.17.0 AS sourcer ARG NYDUS_VER=v2.1.5 RUN apk add --no-cache curl RUN apk add --no-cache --upgrade grep RUN wget https://github.com/dragonflyoss/nydus/releases/download/$NYDUS_VER/nydus-static-$NYDUS_VER-linux-amd64.tgz && \ echo $NYDUS_VER > /.nydus_version && \ tar xzf nydus-static-$NYDUS_VER-linux-amd64.tgz && \ rm nydus-static-$NYDUS_VER-linux-amd64.tgz RUN mv nydus-static/* / FROM alpine:3.17.0 WORKDIR /root/ RUN apk add --no-cache libc6-compat VOLUME /var/lib/containerd-nydus /run/containerd-nydus COPY --from=sourcer /.nydus_version /.nydus_version RUN mkdir -p /usr/local/bin/ /etc/nydus/ /var/lib/containerd-nydus/cache /tmp/blobs/ COPY --from=sourcer /nydus* /usr/local/bin/ COPY containerd-nydus-grpc /usr/local/bin/ RUN chmod +x /usr/local/bin/containerd-nydus-grpc COPY nydusd-config.fusedev.json /etc/nydus/config.json COPY nydusd-config-localfs.json /etc/nydus/localfs.json COPY entrypoint.sh / ENTRYPOINT ["/entrypoint.sh"] nydus-snapshotter-0.13.4/misc/snapshotter/config-coco-guest-pulling.toml000066400000000000000000000006461453374237200265160ustar00rootroot00000000000000version = 1 # Snapshotter's own home directory where it stores and creates necessary resources root = "/var/lib/containerd-nydus" # The snapshotter's GRPC server socket, containerd will connect to plugin on this socket address = "/run/containerd-nydus/containerd-nydus-grpc.sock" [daemon] # Enable proxy mode fs_driver = "proxy" [snapshot] # Insert Kata volume information to `Mount.Options` enable_kata_volume = true nydus-snapshotter-0.13.4/misc/snapshotter/config-coco-host-sharing.toml000066400000000000000000000027161453374237200263250ustar00rootroot00000000000000 version = 1 # Snapshotter's own home directory where it stores and creates necessary resources root = "/var/lib/containerd-nydus" # The snapshotter's GRPC server socket, containerd will connect to plugin on this socket address = "/run/containerd-nydus/containerd-nydus-grpc.sock" # No nydusd daemon needed daemon_mode = "none" [daemon] # Use `blockdev` for tarfs fs_driver = "blockdev" # Path to nydus-image binary nydusimage_path = "/usr/local/bin/nydus-image" [remote] skip_ssl_verify = true [snapshot] # Insert Kata volume information to `Mount.Options` enable_kata_volume = true [experimental.tarfs] # Whether to enable nydus tarfs mode. Tarfs is supported by: # - The EROFS filesystem driver since Linux 6.4 # - Nydus Image Service release v2.3 enable_tarfs = true # Mount rafs on host by loopdev and EROFS mount_tarfs_on_host = false # Mode to export tarfs images: # - "none" or "": do not export tarfs # - "layer_verity_only": only generate disk verity information for a layer blob # - "image_verity_only": only generate disk verity information for all blobs of an image # - "layer_block": generate a raw block disk image with tarfs for a layer # - "image_block": generate a raw block disk image with tarfs for an image # - "layer_block_with_verity": generate a raw block disk image with tarfs for a layer with dm-verity info # - "image_block_with_verity": generate a raw block disk image with tarfs for an image with dm-verity info export_mode = "image_block_with_verity"nydus-snapshotter-0.13.4/misc/snapshotter/config.toml000066400000000000000000000115601453374237200227750ustar00rootroot00000000000000version = 1 # Snapshotter's own home directory where it stores and creates necessary resources root = "/var/lib/containerd-nydus" # The snapshotter's GRPC server socket, containerd will connect to plugin on this socket address = "/run/containerd-nydus/containerd-nydus-grpc.sock" daemon_mode = "dedicated" # Whether snapshotter should try to clean up resources when it is closed cleanup_on_close = false [system] # Snapshotter's debug and trace HTTP server interface enable = true # Unix domain socket path where system controller is listening on address = "/run/containerd-nydus/system.sock" [system.debug] # Snapshotter can profile the CPU utilization of each nydusd daemon when it is being started. # This option specifies the profile duration when nydusd is downloading and uncomproessing data. daemon_cpu_profile_duration_secs = 5 # Enable by assigning an address, empty indicates pprof server is disabled pprof_address = "" [daemon] # Specify a configuration file for nydusd nydusd_config = "/etc/nydus/nydusd-config.fusedev.json" nydusd_path = "/usr/local/bin/nydusd" nydusimage_path = "/usr/local/bin/nydus-image" # fusedev or fscache fs_driver = "fusedev" # How to process when daemon dies: "none", "restart" or "failover" recover_policy = "restart" # Nydusd worker thread number to handle FUSE or fscache requests, [0-1024]. # Setting to 0 will use the default configuration of nydusd. threads_number = 4 # Log rotation size for nydusd, in unit MB(megabytes) log_rotation_size = 100 [cgroup] # Whether to use separate cgroup for nydusd. enable = true # The memory limit for nydusd cgroup, which contains all nydusd processes. # Percentage is supported as well, please ensure it is end with "%". # The default unit is bytes. Acceptable values include "209715200", "200MiB", "200Mi" and "10%". memory_limit = "" [log] # Print logs to stdout rather than logging files log_to_stdout = false # Snapshotter's log level level = "info" log_rotation_compress = true log_rotation_local_time = true # Max number of days to retain logs log_rotation_max_age = 7 log_rotation_max_backups = 5 # In unit MB(megabytes) log_rotation_max_size = 100 [metrics] # Enable by assigning an address, empty indicates metrics server is disabled address = ":9110" [remote] convert_vpc_registry = false [remote.mirrors_config] # Snapshotter will overwrite daemon's mirrors configuration # if the values loaded from this driectory are not null before starting a daemon. # Set to "" or an empty directory to disable it. #dir = "/etc/nydus/certs.d" [remote.auth] # Fetch the private registry auth by listening to K8s API server enable_kubeconfig_keychain = false # synchronize `kubernetes.io/dockerconfigjson` secret from kubernetes API server with specified kubeconfig (default `$KUBECONFIG` or `~/.kube/config`) kubeconfig_path = "" # Fetch the private registry auth as CRI image service proxy enable_cri_keychain = false # the target image service when using image proxy #image_service_address = "/run/containerd/containerd.sock" [snapshot] # Let containerd use nydus-overlayfs mount helper enable_nydus_overlayfs = false # Insert Kata Virtual Volume option to `Mount.Options` enable_kata_volume = false # Whether to remove resources when a snapshot is removed sync_remove = false [cache_manager] # Disable or enable recyclebin disable = false # How long to keep deleted files in recyclebin gc_period = "24h" # Directory to host cached files cache_dir = "" [image] public_key_file = "" validate_signature = false # The configuraions for features that are not production ready [experimental] # Whether to enable stargz support enable_stargz = false # Whether to enable referrers support # The option enables trying to fetch the Nydus image associated with the OCI image and run it. # Also see https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers enable_referrer_detect = false [experimental.tarfs] # Whether to enable nydus tarfs mode. Tarfs is supported by: # - The EROFS filesystem driver since Linux 6.4 # - Nydus Image Service release v2.3 enable_tarfs = false # Mount rafs on host by loopdev and EROFS mount_tarfs_on_host = false # Only enable nydus tarfs mode for images with `tarfs hint` label when true tarfs_hint = false # Maximum of concurrence to converting OCIv1 images to tarfs, 0 means default max_concurrent_proc = 0 # Mode to export tarfs images: # - "none" or "": do not export tarfs # - "layer_verity_only": only generate disk verity information for a layer blob # - "image_verity_only": only generate disk verity information for all blobs of an image # - "layer_block": generate a raw block disk image with tarfs for a layer # - "image_block": generate a raw block disk image with tarfs for an image # - "layer_block_with_verity": generate a raw block disk image with tarfs for a layer with dm-verity info # - "image_block_with_verity": generate a raw block disk image with tarfs for an image with dm-verity info export_mode = "" nydus-snapshotter-0.13.4/misc/snapshotter/entrypoint.sh000077500000000000000000000010421453374237200233770ustar00rootroot00000000000000#! /bin/sh NYDUS_LIB="${NYDUS_LIB:-/var/lib/containerd-nydus}" NYDUS_RUN="${NYDUS_RUN:-/run/containerd-nydus}" LEVEL="${LEVEL:-info}" set -eu BACKEND_TYPE="${BACKEND_TYPE:-config}" NYDUSD_DAEMON_MODE="${NYDUSD_DAEMON_MODE:-multiple}" if [ "$#" -eq 0 ]; then containerd-nydus-grpc \ --nydusd /usr/local/bin/nydusd \ --nydusd-config /etc/nydus/${BACKEND_TYPE}.json \ --root ${NYDUS_LIB} \ --address ${NYDUS_RUN}/containerd-nydus-grpc.sock \ --log-level ${LEVEL} \ --daemon-mode ${NYDUSD_DAEMON_MODE} \ --log-to-stdout fi exec $@ nydus-snapshotter-0.13.4/misc/snapshotter/nydus-snapshotter.fscache.service000066400000000000000000000006571453374237200273270ustar00rootroot00000000000000[Unit] Description=nydus snapshotter After=network.target Before=containerd.service [Service] Type=simple Environment=HOME=/root ExecStart=/usr/local/bin/containerd-nydus-grpc --config /etc/nydus/config.toml --fs-driver fscache --nydusd-config /etc/nydus/nydusd-config.fscache.json Restart=always RestartSec=1 KillMode=process OOMScoreAdjust=-999 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target nydus-snapshotter-0.13.4/misc/snapshotter/nydus-snapshotter.fusedev.service000066400000000000000000000005451453374237200273700ustar00rootroot00000000000000[Unit] Description=nydus snapshotter After=network.target Before=containerd.service [Service] Type=simple Environment=HOME=/root ExecStart=/usr/local/bin/containerd-nydus-grpc --config /etc/nydus/config.toml Restart=always RestartSec=1 KillMode=process OOMScoreAdjust=-999 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target nydus-snapshotter-0.13.4/misc/snapshotter/nydusd-config-localfs.json000066400000000000000000000005461453374237200257220ustar00rootroot00000000000000{ "device": { "backend": { "type": "localfs", "config": { "dir": "/var/lib/containerd-nydus/cache/" } }, "cache": { "type": "blobcache" } }, "mode": "direct", "digest_validate": false, "iostats_files": false, "enable_xattr": true, "fs_prefetch": { "enable": true, "threads_count": 2 } }nydus-snapshotter-0.13.4/misc/snapshotter/nydusd-config.fscache.json000066400000000000000000000004351453374237200256710ustar00rootroot00000000000000{ "type": "bootstrap", "config": { "backend_type": "registry", "backend_config": {}, "cache_type": "fscache", "prefetch_config": { "enable": true, "threads_count": 8, "merging_size": 1048576 } } } nydus-snapshotter-0.13.4/misc/snapshotter/nydusd-config.fusedev.json000066400000000000000000000006721453374237200257410ustar00rootroot00000000000000{ "device": { "backend": { "type": "registry", "config": { "timeout": 5, "connect_timeout": 5, "retry_limit": 2 } }, "cache": { "type": "blobcache" } }, "mode": "direct", "digest_validate": false, "iostats_files": false, "enable_xattr": true, "fs_prefetch": { "enable": true, "threads_count": 8, "merging_size": 1048576, "prefetch_all": true } } nydus-snapshotter-0.13.4/pkg/000077500000000000000000000000001453374237200161045ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/auth/000077500000000000000000000000001453374237200170455ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/auth/docker.go000066400000000000000000000023371453374237200206500ustar00rootroot00000000000000/* * Copyright (c) 2021. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package auth import ( "os" dockerconfig "github.com/docker/cli/cli/config" "github.com/sirupsen/logrus" ) const ( dockerHost = "https://index.docker.io/v1/" convertedDockerHost = "registry-1.docker.io" ) // FromDockerConfig finds auth for a given host in docker's config.json settings. func FromDockerConfig(host string) *PassKeyChain { if len(host) == 0 { return nil } // The host of docker hub image will be converted to `registry-1.docker.io` in: // github.com/containerd/containerd/remotes/docker/registry.go // But we need use the key `https://index.docker.io/v1/` to find auth from docker config. if host == convertedDockerHost { host = dockerHost } config := dockerconfig.LoadDefaultConfigFile(os.Stderr) authConfig, err := config.GetAuthConfig(host) if err != nil { logrus.WithError(err).Infof("no auth from docker config for host %s", host) return nil } // Do not return empty auth. It makes caller life easier. if len(authConfig.Username) == 0 || len(authConfig.Password) == 0 { return nil } return &PassKeyChain{ Username: authConfig.Username, Password: authConfig.Password, } } nydus-snapshotter-0.13.4/pkg/auth/docker_test.go000066400000000000000000000037401453374237200217060ustar00rootroot00000000000000/* * Copyright (c) 2021. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package auth import ( "encoding/base64" "fmt" "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" ) const ( testConfigFmt = ` { "auths": { "%s": { "auth": "%s" }, "%s": { "auth": "%s" } } } ` dockerUser = "dockeruserfoobar" dockerPass = "dockerpassfoobar" extraHost = "reg.docker.alibaba-cloud.com" extraUser = "extrauserfoobar" extraPass = "extrapassfoobar" configFile = "config.json" ) var oldDockerConfig = os.Getenv("DOCKER_CONFIG") func setupDockerConfig() (string, error) { dir, err := os.MkdirTemp("", "testdocker-") if err != nil { return "", err } os.Setenv("DOCKER_CONFIG", dir) err = os.WriteFile(filepath.Join(dir, configFile), []byte(fmt.Sprintf(testConfigFmt, dockerHost, base64.StdEncoding.EncodeToString([]byte(dockerUser+":"+dockerPass)), extraHost, base64.StdEncoding.EncodeToString([]byte(extraUser+":"+extraPass)))), 0600) if err != nil { os.RemoveAll(dir) return "", err } return dir, nil } func TestDockerCred(t *testing.T) { assert := assert.New(t) dir, err := setupDockerConfig() assert.Nil(err) defer func() { os.RemoveAll(dir) os.Setenv("DOCKER_CONFIG", oldDockerConfig) }() // Empty host should get empty auth auth := FromDockerConfig("") assert.Nil(auth) // Unmatching host should get empty auth auth = FromDockerConfig("foo") assert.Nil(auth) auth = FromDockerConfig(dockerHost) assert.NotNil(auth) assert.Equal(auth.Username, dockerUser) assert.Equal(auth.Password, dockerPass) auth = FromDockerConfig(convertedDockerHost) assert.NotNil(auth) assert.Equal(auth.Username, dockerUser) assert.Equal(auth.Password, dockerPass) auth = FromDockerConfig(extraHost) assert.NotNil(auth) assert.Equal(auth.Username, extraUser) assert.Equal(auth.Password, extraPass) } nydus-snapshotter-0.13.4/pkg/auth/image_proxy.go000066400000000000000000000073721453374237200217300ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package auth import ( "context" "fmt" "time" "github.com/containerd/containerd/defaults" "github.com/containerd/containerd/log" "github.com/containerd/containerd/pkg/dialer" "github.com/containerd/containerd/reference" distribution "github.com/containerd/containerd/reference/docker" runtime_alpha "github.com/containerd/containerd/third_party/k8s.io/cri-api/pkg/apis/runtime/v1alpha2" "github.com/containerd/stargz-snapshotter/service/keychain/cri" "github.com/containerd/stargz-snapshotter/service/keychain/crialpha" "github.com/containerd/stargz-snapshotter/service/resolver" "github.com/pkg/errors" "google.golang.org/grpc" "google.golang.org/grpc/backoff" "google.golang.org/grpc/credentials/insecure" runtime "k8s.io/cri-api/pkg/apis/runtime/v1" ) const DefaultImageServiceAddress = "/run/containerd/containerd.sock" // Should be concurrency safe var Credentials []resolver.Credential = make([]resolver.Credential, 0, 8) // This function is borrowed from stargz func newCRIConn(criAddr string) (*grpc.ClientConn, error) { // TODO: make gRPC options configurable from config.toml backoffConfig := backoff.DefaultConfig backoffConfig.MaxDelay = 3 * time.Second connParams := grpc.ConnectParams{ Backoff: backoffConfig, } gopts := []grpc.DialOption{ grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithConnectParams(connParams), grpc.WithContextDialer(dialer.ContextDialer), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(defaults.DefaultMaxRecvMsgSize)), grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(defaults.DefaultMaxSendMsgSize)), } return grpc.Dial(dialer.DialAddress(criAddr), gopts...) } // from stargz-snapshotter/cmd/containerd-stargz-grpc/main.go#main func AddImageProxy(ctx context.Context, rpc *grpc.Server, imageServiceAddress string) { criAddr := DefaultImageServiceAddress if imageServiceAddress != "" { criAddr = imageServiceAddress } connectAlphaCRI := func() (runtime_alpha.ImageServiceClient, error) { conn, err := newCRIConn(criAddr) if err != nil { return nil, err } return runtime_alpha.NewImageServiceClient(conn), nil } connectCri := func() (runtime.ImageServiceClient, error) { conn, err := newCRIConn(criAddr) if err != nil { return nil, err } return runtime.NewImageServiceClient(conn), nil } criAlphaCred, criAlphaServer := crialpha.NewCRIAlphaKeychain(ctx, connectAlphaCRI) runtime_alpha.RegisterImageServiceServer(rpc, criAlphaServer) criCred, criServer := cri.NewCRIKeychain(ctx, connectCri) runtime.RegisterImageServiceServer(rpc, criServer) Credentials = append(Credentials, criAlphaCred, criCred) log.G(ctx).WithField("target-image-service", criAddr).Info("setup image proxy keychain") } func FromCRI(host, ref string) (*PassKeyChain, error) { if Credentials == nil { return nil, errors.New("No Credentials parsers") } refSpec, err := parseReference(ref) if err != nil { log.L.WithError(err).Error("parse ref failed") return nil, errors.Wrapf(err, "parse image reference %s", ref) } var u, p string var keychain *PassKeyChain for _, cred := range Credentials { if username, secret, err := cred(host, refSpec); err != nil { return nil, err } else if !(username == "" && secret == "") { u = username p = secret keychain = &PassKeyChain{ Username: u, Password: p, } break } } return keychain, nil } // from stargz-snapshotter/service/keychain/cri/cri.go func parseReference(ref string) (reference.Spec, error) { namedRef, err := distribution.ParseDockerRef(ref) if err != nil { return reference.Spec{}, fmt.Errorf("failed to parse image reference %q: %w", ref, err) } return reference.Parse(namedRef.String()) } nydus-snapshotter-0.13.4/pkg/auth/image_proxy_test.go000066400000000000000000000100021453374237200227470ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package auth import ( "context" "net" "os" "path/filepath" "testing" "github.com/containerd/containerd/pkg/dialer" runtime_alpha "github.com/containerd/containerd/third_party/k8s.io/cri-api/pkg/apis/runtime/v1alpha2" "github.com/stretchr/testify/assert" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" runtime "k8s.io/cri-api/pkg/apis/runtime/v1" ) type MockAlphaImageService struct { runtime_alpha.UnimplementedImageServiceServer } func (*MockAlphaImageService) PullImage(ctx context.Context, req *runtime_alpha.PullImageRequest) (*runtime_alpha.PullImageResponse, error) { return &runtime_alpha.PullImageResponse{}, nil } type MockImageService struct { runtime.UnimplementedImageServiceServer } func (*MockImageService) PullImage(ctx context.Context, req *runtime.PullImageRequest) (*runtime.PullImageResponse, error) { return &runtime.PullImageResponse{}, nil } func TestFromImagePull(t *testing.T) { var err error assert := assert.New(t) ctx := context.TODO() d := t.TempDir() defer os.RemoveAll(d) tagImage := "docker.io/library/busybox:latest" // should return nil if no proxy kc, err := FromCRI("docker.io", tagImage) assert.Nil(kc) assert.NoError(err) mockRPC := grpc.NewServer() mockSocket := filepath.Join(d, "mock.sock") lm, err := net.Listen("unix", mockSocket) assert.NoError(err) // The server of CRI image service proxy. proxyRPC := grpc.NewServer() proxySocket := filepath.Join(d, "proxy.sock") lp, err := net.Listen("unix", proxySocket) assert.NoError(err) // Mocking the end CRI request consumer. serverAlpha := &MockAlphaImageService{} server := &MockImageService{} runtime_alpha.RegisterImageServiceServer(mockRPC, serverAlpha) runtime.RegisterImageServiceServer(mockRPC, server) go func() { err := mockRPC.Serve(lm) assert.NoError(err) }() defer mockRPC.Stop() AddImageProxy(ctx, proxyRPC, mockSocket) go func() { err := proxyRPC.Serve(lp) assert.NoError(err) }() defer proxyRPC.Stop() kc, err = FromCRI("docker.io", tagImage) // should return empty kc before pulling assert.Nil(kc) assert.NoError(err) gopts := []grpc.DialOption{ grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithContextDialer(dialer.ContextDialer), } conn, err := grpc.Dial(dialer.DialAddress(proxySocket), gopts...) assert.NoError(err) criAlphaClient := runtime_alpha.NewImageServiceClient(conn) irAlpha := &runtime_alpha.PullImageRequest{ Image: &runtime_alpha.ImageSpec{ Image: tagImage, }, Auth: &runtime_alpha.AuthConfig{ Username: "test", Password: "passwd", }, } _, err = criAlphaClient.PullImage(ctx, irAlpha) assert.NoError(err) criClient := runtime.NewImageServiceClient(conn) kc, err = FromCRI("docker.io", tagImage) // get correct kc after pulling assert.Equal("test", kc.Username) assert.Equal("passwd", kc.Password) assert.NoError(err) kc, err = FromCRI("docker.io", "docker.io/library/busybox:another") // get empty kc with wrong tag assert.Nil(kc) assert.NoError(err) image2 := "ghcr.io/busybox:latest" ir := &runtime.PullImageRequest{ Image: &runtime.ImageSpec{ Image: image2, }, Auth: &runtime.AuthConfig{ Username: "test_1", Password: "passwd_1", }, } _, err = criClient.PullImage(ctx, ir) assert.NoError(err) kc, err = FromCRI("ghcr.io", image2) assert.Equal(kc.Username, "test_1") assert.Equal(kc.Password, "passwd_1") assert.NoError(err) // should work with digest digestImage := "docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa" irAlpha = &runtime_alpha.PullImageRequest{ Image: &runtime_alpha.ImageSpec{ Image: digestImage, }, Auth: &runtime_alpha.AuthConfig{ Username: "digest", Password: "dpwd", }, } _, err = criAlphaClient.PullImage(ctx, irAlpha) assert.NoError(err) kc, err = FromCRI("docker.io", digestImage) assert.Equal("digest", kc.Username) assert.Equal("dpwd", kc.Password) assert.NoError(err) } nydus-snapshotter-0.13.4/pkg/auth/keychain.go000066400000000000000000000060411453374237200211700ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package auth import ( "encoding/base64" "fmt" "strings" "github.com/pkg/errors" "github.com/containerd/containerd/reference/docker" "github.com/containerd/nydus-snapshotter/pkg/label" "github.com/google/go-containerregistry/pkg/authn" ) const ( sep = ":" ) var ( emptyPassKeyChain = PassKeyChain{} ) // PassKeyChain is user/password based key chain type PassKeyChain struct { Username string Password string } func FromBase64(str string) (PassKeyChain, error) { decoded, err := base64.StdEncoding.DecodeString(str) if err != nil { return emptyPassKeyChain, err } pair := strings.Split(string(decoded), sep) if len(pair) != 2 { return emptyPassKeyChain, errors.New("invalid registry auth token") } return PassKeyChain{ Username: pair[0], Password: pair[1], }, nil } func (kc PassKeyChain) ToBase64() string { if kc.Username == "" && kc.Password == "" { return "" } return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", kc.Username, kc.Password))) } // TokenBase check if PassKeyChain is token based, when username is empty and password is not empty // then password is registry token func (kc PassKeyChain) TokenBase() bool { return kc.Username == "" && kc.Password != "" } // FromLabels finds image pull username and secret from snapshot labels. // Returned `nil` means no valid username and secret is passed, it should // not override input nydusd configuration. func FromLabels(labels map[string]string) *PassKeyChain { u, found := labels[label.NydusImagePullUsername] if !found || u == "" { return nil } p, found := labels[label.NydusImagePullSecret] if !found || p == "" { return nil } return &PassKeyChain{ Username: u, Password: p, } } // GetRegistryKeyChain get image pull keychain from (ordered): // 1. username and secrets labels // 2. cri request // 3. docker config // 4. k8s docker config secret func GetRegistryKeyChain(host, ref string, labels map[string]string) *PassKeyChain { kc := FromLabels(labels) if kc != nil { return kc } // TODO: Handle error kc, _ = FromCRI(host, ref) if kc != nil { return kc } kc = FromDockerConfig(host) if kc != nil { return kc } return FromKubeSecretDockerConfig(host) } func GetKeyChainByRef(ref string, labels map[string]string) (*PassKeyChain, error) { named, err := docker.ParseDockerRef(ref) if err != nil { return nil, errors.Wrapf(err, "parse ref %s", ref) } host := docker.Domain(named) keychain := GetRegistryKeyChain(host, ref, labels) return keychain, nil } func (kc PassKeyChain) Resolve(target authn.Resource) (authn.Authenticator, error) { return authn.FromConfig(kc.toAuthConfig()), nil } // toAuthConfig convert PassKeyChain to authn.AuthConfig when kc is token based, // RegistryToken is preferred to func (kc PassKeyChain) toAuthConfig() authn.AuthConfig { if kc.TokenBase() { return authn.AuthConfig{ RegistryToken: kc.Password, } } return authn.AuthConfig{ Username: kc.Username, Password: kc.Password, } } nydus-snapshotter-0.13.4/pkg/auth/keychain_test.go000066400000000000000000000015411453374237200222270ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package auth import ( "testing" "github.com/stretchr/testify/assert" "github.com/containerd/nydus-snapshotter/pkg/label" ) func TestFromLabels(t *testing.T) { labels := map[string]string{ label.NydusImagePullUsername: "mock", label.NydusImagePullSecret: "mock", } kc := FromLabels(labels) assert.Equal(t, kc.Username, "mock") assert.Equal(t, kc.Password, "mock") assert.Equal(t, "bW9jazptb2Nr", kc.ToBase64()) kc1, err := FromBase64("bW9jazptb2Nr") assert.Nil(t, err) assert.Equal(t, kc1.Username, "mock") assert.Equal(t, kc1.Password, "mock") labels = map[string]string{} kc = FromLabels(labels) assert.Nil(t, kc) labels = map[string]string{ label.NydusImagePullSecret: "mock", } kc = FromLabels(labels) assert.Nil(t, kc) } nydus-snapshotter-0.13.4/pkg/auth/kubesecret.go000066400000000000000000000125361453374237200215370ustar00rootroot00000000000000package auth import ( "bytes" "context" "fmt" "os" "sync" "k8s.io/client-go/tools/clientcmd" "github.com/docker/cli/cli/config/configfile" "github.com/pkg/errors" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" ) var ( kubeSecretListener *KubeSecretListener configMu sync.Mutex ) type KubeSecretListener struct { dockerConfigs map[string]*configfile.ConfigFile informer cache.SharedIndexInformer } func InitKubeSecretListener(ctx context.Context, kubeconfigPath string) error { configMu.Lock() defer configMu.Unlock() if kubeSecretListener != nil { return nil } kubeSecretListener = &KubeSecretListener{ dockerConfigs: make(map[string]*configfile.ConfigFile), } if kubeconfigPath != "" { _, err := os.Stat(kubeconfigPath) if err != nil && !os.IsNotExist(err) { logrus.WithError(err).Warningf("kubeconfig does not exist, kubeconfigPath %s", kubeconfigPath) return err } else if err != nil { logrus.WithError(err).Warningf("failed to detect kubeconfig existence, kubeconfigPath %s", kubeconfigPath) return err } } loadingRule := clientcmd.NewDefaultClientConfigLoadingRules() loadingRule.ExplicitPath = kubeconfigPath clientConfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( loadingRule, &clientcmd.ConfigOverrides{}, ).ClientConfig() if err != nil { logrus.WithError(err).Warningf("failed to load kubeconfig") return err } clientset, err := kubernetes.NewForConfig(clientConfig) if err != nil { logrus.WithError(err).Warningf("failed to create kubernetes client") return err } if err := kubeSecretListener.SyncKubeSecrets(ctx, clientset); err != nil { logrus.WithError(err).Warningf("failed to sync secrets") return err } return nil } func (kubelistener *KubeSecretListener) addDockerConfig(key string, obj interface{}) error { data, ok := obj.(*corev1.Secret).Data[corev1.DockerConfigJsonKey] if !ok { return fmt.Errorf("failed to get data from new object") } dockerConfig := configfile.ConfigFile{} if err := dockerConfig.LoadFromReader(bytes.NewReader(data)); err != nil { return errors.Wrap(err, "failed to load docker config json from secret") } configMu.Lock() kubelistener.dockerConfigs[key] = &dockerConfig configMu.Unlock() return nil } func (kubelistener *KubeSecretListener) deleteDockerConfig(key string) { configMu.Lock() delete(kubelistener.dockerConfigs, key) configMu.Unlock() } func (kubelistener *KubeSecretListener) SyncKubeSecrets(ctx context.Context, clientset *kubernetes.Clientset) error { if kubelistener.informer != nil { return nil } informer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { options.FieldSelector = "type=" + string(corev1.SecretTypeDockerConfigJson) return clientset.CoreV1().Secrets(metav1.NamespaceAll).List(context.Background(), options) }, WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { options.FieldSelector = "type=" + string(corev1.SecretTypeDockerConfigJson) return clientset.CoreV1().Secrets(metav1.NamespaceAll).Watch(context.Background(), options) }}, &corev1.Secret{}, 0, cache.Indexers{}, ) kubelistener.informer = informer _, err := kubelistener.informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { key, err := cache.MetaNamespaceKeyFunc(obj) if err != nil { logrus.WithError(err).Errorf("failed to get key for secret from cache") return } if err := kubelistener.addDockerConfig(key, obj); err != nil { logrus.WithError(err).Errorf("failed to add a new dockerconfigjson") return } }, UpdateFunc: func(old, new interface{}) { key, err := cache.MetaNamespaceKeyFunc(new) if err != nil { logrus.WithError(err).Errorf("failed to get key for secret from cache") return } if err := kubelistener.addDockerConfig(key, new); err != nil { logrus.WithError(err).Errorf("failed to add a new dockerconfigjson") return } }, DeleteFunc: func(obj interface{}) { key, err := cache.MetaNamespaceKeyFunc(obj) if err != nil { logrus.WithError(err).Errorf("failed to get key for secret from cache") } kubelistener.deleteDockerConfig(key) }}, ) if err != nil { return errors.Wrap(err, "add event handler to informer") } go kubelistener.informer.Run(ctx.Done()) if !cache.WaitForCacheSync(ctx.Done(), informer.HasSynced) { return fmt.Errorf("timed out for syncing cache") } return nil } func (kubelistener *KubeSecretListener) GetCredentialsStore(host string) *PassKeyChain { configMu.Lock() defer configMu.Unlock() for _, dockerConfig := range kubelistener.dockerConfigs { // Find the auth for the host. authConfig, err := dockerConfig.GetAuthConfig(host) if err != nil { logrus.WithError(err).Errorf("failed to get auth config for host %s", host) continue } if len(authConfig.Username) != 0 && len(authConfig.Password) != 0 { return &PassKeyChain{ Username: authConfig.Username, Password: authConfig.Password, } } } return nil } func FromKubeSecretDockerConfig(host string) *PassKeyChain { if kubeSecretListener != nil { return kubeSecretListener.GetCredentialsStore(host) } return nil } nydus-snapshotter-0.13.4/pkg/auth/kubesecret_test.go000066400000000000000000000032351453374237200225720ustar00rootroot00000000000000package auth import ( "context" "encoding/base64" "fmt" "testing" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" ) const ( testDockerConfigJSONFmt = ` { "auths": { "%s": { "username": "%s", "password": "%s", "email": "%s", "auth": "%s" } } } ` dockerConfigKey = "testKey" registryUser = "dockeruserfoobar" registryPass = "dockerpassfoobar" registryEmail = "test@alibaba.com" ) func TestGetCredentialsStore(t *testing.T) { assert := assert.New(t) ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Host may not has kubeconfig, so ignore the error and continue the test _ = InitKubeSecretListener(ctx, "") assert.NotNil(kubeSecretListener) var obj interface{} = &corev1.Secret{ Data: map[string][]byte{ corev1.DockerConfigJsonKey: []byte(fmt.Sprintf(testDockerConfigJSONFmt, extraHost, registryUser, registryPass, registryEmail, base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", registryUser, registryPass))))), }, } err := kubeSecretListener.addDockerConfig(dockerConfigKey, obj) assert.Nil(err) auth := FromKubeSecretDockerConfig(extraHost) assert.Equal(auth.Username, registryUser) assert.Equal(auth.Password, registryPass) auth = kubeSecretListener.GetCredentialsStore(extraHost) assert.Equal(auth.Username, registryUser) assert.Equal(auth.Password, registryPass) _, ok := kubeSecretListener.dockerConfigs[dockerConfigKey] assert.Equal(ok, true) kubeSecretListener.deleteDockerConfig(dockerConfigKey) _, ok = kubeSecretListener.dockerConfigs[dockerConfigKey] assert.Equal(ok, false) auth = kubeSecretListener.GetCredentialsStore(extraHost) assert.Nil(auth) } nydus-snapshotter-0.13.4/pkg/backend/000077500000000000000000000000001453374237200174735ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/backend/backend.go000066400000000000000000000033331453374237200214130ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package backend import ( "context" "fmt" "github.com/containerd/containerd/content" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) const ( BackendTypeOSS = "oss" BackendTypeS3 = "s3" BackendTypeLocalFS = "localfs" ) var ( // We always use multipart upload for backend, and limit the // multipart chunk size to 500MB by default. MultipartChunkSize int64 = 500 * 1024 * 1024 ) // Backend uploads blobs generated by nydus-image builder to a backend storage. type Backend interface { // Push pushes specified blob file to remote storage backend. Push(ctx context.Context, cs content.Store, desc ocispec.Descriptor) error // Check checks whether a blob exists in remote storage backend, // blob exists -> return (blobPath, nil) // blob not exists -> return ("", err) Check(blobDigest digest.Digest) (string, error) // Type returns backend type name. Type() string } // Nydus driver majorly works for registry backend, which means blob is stored in // registry as per OCI distribution specification. But nydus can also make OSS or // other storage services as backend storage. Pass config as byte slice here because // we haven't find a way to represent all backend config at the same time. func NewBackend(_type string, config []byte, forcePush bool) (Backend, error) { switch _type { case BackendTypeOSS: return newOSSBackend(config, forcePush) case BackendTypeS3: return newS3Backend(config, forcePush) case BackendTypeLocalFS: return newLocalFSBackend(config, forcePush) default: return nil, fmt.Errorf("unsupported backend type %s", _type) } } nydus-snapshotter-0.13.4/pkg/backend/localfs.go000066400000000000000000000042531453374237200214510ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package backend import ( "context" "encoding/json" "fmt" "io" "os" "path" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) type LocalFSBackend struct { dir string forcePush bool } func newLocalFSBackend(rawConfig []byte, forcePush bool) (*LocalFSBackend, error) { var configMap map[string]string if err := json.Unmarshal(rawConfig, &configMap); err != nil { return nil, errors.Wrap(err, "parse LocalFS storage backend configuration") } dir, ok := configMap["dir"] if !ok { return nil, fmt.Errorf("no `dir` option is specified") } return &LocalFSBackend{ dir: dir, forcePush: forcePush, }, nil } func (b *LocalFSBackend) dstPath(blobID string) string { return path.Join(b.dir, blobID) } func (b *LocalFSBackend) Push(ctx context.Context, cs content.Store, desc ocispec.Descriptor) error { if _, err := b.Check(desc.Digest); err == nil && !b.forcePush { return nil } if err := os.MkdirAll(b.dir, 0755); err != nil { return errors.Wrap(err, "create directory in localfs backend") } ra, err := cs.ReaderAt(ctx, desc) if err != nil { return errors.Wrap(err, "get reader from content store") } defer ra.Close() blobID := desc.Digest.Hex() dstPath := b.dstPath(blobID) dstFile, err := os.Create(dstPath) if err != nil { return errors.Wrapf(err, "create destination file: %s", dstPath) } defer dstFile.Close() sr := io.NewSectionReader(ra, 0, ra.Size()) if _, err := io.Copy(dstFile, sr); err != nil { return errors.Wrapf(err, "copy blob to %s", dstPath) } return nil } func (b *LocalFSBackend) Check(blobDigest digest.Digest) (string, error) { dstPath := b.dstPath(blobDigest.Hex()) info, err := os.Stat(dstPath) if err != nil { if os.IsNotExist(err) { return "", errdefs.ErrNotFound } return "", err } if !info.IsDir() { return dstPath, nil } return "", errdefs.ErrNotFound } func (b *LocalFSBackend) Type() string { return BackendTypeLocalFS } nydus-snapshotter-0.13.4/pkg/backend/oss.go000066400000000000000000000112201453374237200206220ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package backend import ( "context" "encoding/json" "fmt" "io" "time" "github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "golang.org/x/sync/errgroup" ) type OSSBackend struct { // OSS storage does not support directory. Therefore add a prefix to each object // to make it a path-like object. objectPrefix string bucket *oss.Bucket forcePush bool } func newOSSBackend(rawConfig []byte, forcePush bool) (*OSSBackend, error) { var configMap map[string]string if err := json.Unmarshal(rawConfig, &configMap); err != nil { return nil, errors.Wrap(err, "Parse OSS storage backend configuration") } endpoint, ok1 := configMap["endpoint"] bucketName, ok2 := configMap["bucket_name"] // Below fields are not mandatory. accessKeyID := configMap["access_key_id"] accessKeySecret := configMap["access_key_secret"] objectPrefix := configMap["object_prefix"] if !ok1 || !ok2 { return nil, fmt.Errorf("no endpoint or bucket is specified") } client, err := oss.New(endpoint, accessKeyID, accessKeySecret) if err != nil { return nil, errors.Wrap(err, "Create client") } bucket, err := client.Bucket(bucketName) if err != nil { return nil, errors.Wrap(err, "Create bucket") } return &OSSBackend{ objectPrefix: objectPrefix, bucket: bucket, forcePush: forcePush, }, nil } // Ported from https://github.com/aliyun/aliyun-oss-go-sdk/blob/v2.2.6/oss/utils.go#L259 func splitFileByPartSize(blobSize, chunkSize int64) ([]oss.FileChunk, error) { if chunkSize <= 0 { return nil, errors.New("invalid chunk size") } var chunkN = blobSize / chunkSize if chunkN >= 10000 { return nil, errors.New("too many parts, please increase chunk size") } var chunks []oss.FileChunk var chunk = oss.FileChunk{} for i := int64(0); i < chunkN; i++ { chunk.Number = int(i + 1) chunk.Offset = i * chunkSize chunk.Size = chunkSize chunks = append(chunks, chunk) } if blobSize%chunkSize > 0 { chunk.Number = len(chunks) + 1 chunk.Offset = int64(len(chunks)) * chunkSize chunk.Size = blobSize % chunkSize chunks = append(chunks, chunk) } return chunks, nil } // Upload nydus blob to oss storage backend. func (b *OSSBackend) push(ctx context.Context, cs content.Store, desc ocispec.Descriptor) error { blobID := desc.Digest.Hex() blobObjectKey := b.objectPrefix + blobID ra, err := cs.ReaderAt(ctx, desc) if err != nil { return errors.Wrapf(err, "get reader for compression blob %q", desc.Digest) } defer ra.Close() if exist, err := b.bucket.IsObjectExist(blobObjectKey); err != nil { return errors.Wrap(err, "check object existence") } else if exist && !b.forcePush { return nil } chunks, err := splitFileByPartSize(ra.Size(), MultipartChunkSize) if err != nil { return errors.Wrap(err, "split blob by part num") } imur, err := b.bucket.InitiateMultipartUpload(blobObjectKey) if err != nil { return errors.Wrap(err, "initiate multipart upload") } partsChan := make(chan oss.UploadPart, len(chunks)) g := new(errgroup.Group) for _, chunk := range chunks { ck := chunk g.Go(func() error { p, err := b.bucket.UploadPart(imur, io.NewSectionReader(ra, ck.Offset, ck.Size), ck.Size, ck.Number) if err != nil { return errors.Wrap(err, "upload part") } partsChan <- p return nil }) } if err := g.Wait(); err != nil { _ = b.bucket.AbortMultipartUpload(imur) close(partsChan) return errors.Wrap(err, "upload parts") } close(partsChan) parts := make([]oss.UploadPart, 0, 16) for p := range partsChan { parts = append(parts, p) } _, err = b.bucket.CompleteMultipartUpload(imur, parts) if err != nil { return errors.Wrap(err, "complete multipart upload") } return nil } func (b *OSSBackend) Push(ctx context.Context, cs content.Store, desc ocispec.Descriptor) error { backoff := time.Second for { err := b.push(ctx, cs, desc) if err != nil { select { case <-ctx.Done(): return err default: } } else { return nil } if backoff >= 8*time.Second { return err } time.Sleep(backoff) backoff *= 2 } } func (b *OSSBackend) Check(blobDigest digest.Digest) (string, error) { blobID := blobDigest.Hex() blobObjectKey := b.objectPrefix + blobID if exist, err := b.bucket.IsObjectExist(blobObjectKey); err != nil { return "", err } else if exist { return blobID, nil } return "", errdefs.ErrNotFound } func (b *OSSBackend) Type() string { return BackendTypeOSS } nydus-snapshotter-0.13.4/pkg/backend/s3.go000066400000000000000000000115651453374237200203570ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package backend import ( "context" "encoding/json" "fmt" "net/http" "github.com/aws/aws-sdk-go-v2/aws" awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http" awscfg "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/credentials" "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) type S3Backend struct { // objectPrefix is the path prefix of the uploaded object. // For example, if the blobID which should be uploaded is "abc", // and the objectPrefix is "path/to/my-registry/", then the object key will be // "path/to/my-registry/abc". objectPrefix string bucketName string endpointWithScheme string region string accessKeySecret string accessKeyID string forcePush bool } type S3Config struct { AccessKeyID string `json:"access_key_id,omitempty"` AccessKeySecret string `json:"access_key_secret,omitempty"` Endpoint string `json:"endpoint,omitempty"` Scheme string `json:"scheme,omitempty"` BucketName string `json:"bucket_name,omitempty"` Region string `json:"region,omitempty"` ObjectPrefix string `json:"object_prefix,omitempty"` } func newS3Backend(rawConfig []byte, forcePush bool) (*S3Backend, error) { cfg := &S3Config{} if err := json.Unmarshal(rawConfig, cfg); err != nil { return nil, errors.Wrap(err, "parse S3 storage backend configuration") } if cfg.Endpoint == "" { cfg.Endpoint = "s3.amazonaws.com" } if cfg.Scheme == "" { cfg.Scheme = "https" } endpointWithScheme := fmt.Sprintf("%s://%s", cfg.Scheme, cfg.Endpoint) if cfg.BucketName == "" || cfg.Region == "" { return nil, fmt.Errorf("invalid S3 configuration: missing 'bucket_name' or 'region'") } return &S3Backend{ objectPrefix: cfg.ObjectPrefix, bucketName: cfg.BucketName, region: cfg.Region, endpointWithScheme: endpointWithScheme, accessKeySecret: cfg.AccessKeySecret, accessKeyID: cfg.AccessKeyID, forcePush: forcePush, }, nil } func (b *S3Backend) client() (*s3.Client, error) { s3AWSConfig, err := awscfg.LoadDefaultConfig(context.TODO()) if err != nil { return nil, errors.Wrap(err, "load default AWS config") } client := s3.NewFromConfig(s3AWSConfig, func(o *s3.Options) { o.EndpointResolver = s3.EndpointResolverFromURL(b.endpointWithScheme) o.Region = b.region o.UsePathStyle = true if len(b.accessKeySecret) > 0 && len(b.accessKeyID) > 0 { o.Credentials = credentials.NewStaticCredentialsProvider(b.accessKeyID, b.accessKeySecret, "") } o.UsePathStyle = true }) return client, nil } func (b *S3Backend) existObject(ctx context.Context, objectKey string) (bool, error) { client, err := b.client() if err != nil { return false, errors.Wrap(err, "failed to create s3 client") } _, err = client.HeadObject(ctx, &s3.HeadObjectInput{ Bucket: &b.bucketName, Key: &objectKey, }) if err != nil { var responseError *awshttp.ResponseError if errors.As(err, &responseError) && responseError.ResponseError.HTTPStatusCode() == http.StatusNotFound { return false, nil } return false, err } return true, nil } func (b *S3Backend) Push(ctx context.Context, cs content.Store, desc ocispec.Descriptor) error { blobID := desc.Digest.Hex() blobObjectKey := b.objectPrefix + blobID if exist, err := b.existObject(ctx, blobObjectKey); err != nil { return errors.Wrap(err, "check object existence") } else if exist && !b.forcePush { return nil } ra, err := cs.ReaderAt(ctx, desc) if err != nil { return errors.Wrap(err, "get reader from content store") } defer ra.Close() reader := content.NewReader(ra) client, err := b.client() if err != nil { return errors.Wrap(err, "failed to create s3 client") } uploader := manager.NewUploader(client, func(u *manager.Uploader) { u.PartSize = MultipartChunkSize }) if _, err := uploader.Upload(ctx, &s3.PutObjectInput{ Bucket: aws.String(b.bucketName), Key: aws.String(blobObjectKey), Body: reader, ChecksumAlgorithm: types.ChecksumAlgorithmCrc32, }); err != nil { return errors.Wrap(err, "push blob to s3 backend") } return nil } func (b *S3Backend) Check(blobDigest digest.Digest) (string, error) { blobID := blobDigest.Hex() objectKey := b.objectPrefix + blobDigest.Hex() if exist, err := b.existObject(context.Background(), objectKey); err != nil { return "", err } else if exist { return blobID, nil } return "", errdefs.ErrNotFound } func (b *S3Backend) Type() string { return BackendTypeS3 } nydus-snapshotter-0.13.4/pkg/backend/s3_test.go000066400000000000000000000024351453374237200214120ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package backend import ( "reflect" "testing" ) func Test_newS3Backend(t *testing.T) { type args struct { rawConfig []byte } tests := []struct { name string args args want *S3Backend wantErr bool }{ { name: "test1, no error", args: args{ rawConfig: []byte(`{ "endpoint": "localhost:9000", "scheme": "http", "bucket_name": "nydus", "region": "us-east-1", "object_prefix": "path/to/my-registry/", "access_key_id": "minio", "access_key_secret": "minio123" }`), }, want: &S3Backend{ objectPrefix: "path/to/my-registry/", bucketName: "nydus", endpointWithScheme: "http://localhost:9000", region: "us-east-1", accessKeySecret: "minio123", accessKeyID: "minio", }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := newS3Backend(tt.args.rawConfig, false) if (err != nil) != tt.wantErr { t.Errorf("newS3Backend() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { t.Errorf("newS3Backend() = %+#v\nwant %+#v\n\n", got, tt.want) } }) } } nydus-snapshotter-0.13.4/pkg/cache/000077500000000000000000000000001453374237200171475ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/cache/manager.go000066400000000000000000000062361453374237200211170ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package cache import ( "context" "os" "path" "time" "github.com/pkg/errors" "github.com/containerd/containerd/log" "github.com/containerd/containerd/snapshots" "github.com/containerd/continuity/fs" "github.com/containerd/nydus-snapshotter/pkg/store" ) const ( imageDiskFileSuffix = ".image.disk" layerDiskFileSuffix = ".layer.disk" chunkMapFileSuffix = ".chunk_map" metaFileSuffix = ".blob.meta" // Blob cache is suffixed after nydus v2.1 dataFileSuffix = ".blob.data" ) // Disk cache manager for fusedev. type Manager struct { cacheDir string period time.Duration eventCh chan struct{} } type Opt struct { Disabled bool CacheDir string Period time.Duration Database *store.Database } func NewManager(opt Opt) (*Manager, error) { // Ensure cache directory exists if err := os.MkdirAll(opt.CacheDir, 0755); err != nil { return nil, errors.Wrapf(err, "failed to create cache dir %s", opt.CacheDir) } eventCh := make(chan struct{}) m := &Manager{ cacheDir: opt.CacheDir, period: opt.Period, eventCh: eventCh, } return m, nil } func (m *Manager) CacheDir() string { return m.cacheDir } // Report each blob disk usage // TODO: For fscache cache files, the cache files are managed by nydusd and Linux kernel // We don't know how it manages cache files. A method to address this is to query nydusd. // So we can't report cache usage in the case of fscache now func (m *Manager) CacheUsage(ctx context.Context, blobID string) (snapshots.Usage, error) { var usage snapshots.Usage blobCachePath := path.Join(m.cacheDir, blobID) // For backward compatibility blobCacheSuffixedPath := path.Join(m.cacheDir, blobID+dataFileSuffix) blobChunkMap := path.Join(m.cacheDir, blobID+chunkMapFileSuffix) blobMeta := path.Join(m.cacheDir, blobID+metaFileSuffix) imageDisk := path.Join(m.cacheDir, blobID+imageDiskFileSuffix) layerDisk := path.Join(m.cacheDir, blobID+layerDiskFileSuffix) stuffs := []string{blobCachePath, blobCacheSuffixedPath, blobChunkMap, blobMeta, imageDisk, layerDisk} for _, f := range stuffs { du, err := fs.DiskUsage(ctx, f) if err != nil { if errors.Is(err, os.ErrNotExist) { log.L.Debugf("Cache %s does not exist", f) continue } return snapshots.Usage{}, err } usage.Add(snapshots.Usage(du)) } return usage, nil } func (m *Manager) RemoveBlobCache(blobID string) error { blobCachePath := path.Join(m.cacheDir, blobID) blobCacheSuffixedPath := path.Join(m.cacheDir, blobID+dataFileSuffix) blobChunkMap := path.Join(m.cacheDir, blobID+chunkMapFileSuffix) blobMeta := path.Join(m.cacheDir, blobID+metaFileSuffix) imageDisk := path.Join(m.cacheDir, blobID+imageDiskFileSuffix) layerDisk := path.Join(m.cacheDir, blobID+layerDiskFileSuffix) // NOTE: Delete chunk bitmap file before data blob stuffs := []string{blobChunkMap, blobMeta, blobCachePath, blobCacheSuffixedPath, imageDisk, layerDisk} for _, f := range stuffs { err := os.Remove(f) if err != nil { if errors.Is(err, os.ErrNotExist) { log.L.Debugf("file %s doest not exist.", f) continue } return err } } return nil } nydus-snapshotter-0.13.4/pkg/cgroup/000077500000000000000000000000001453374237200174035ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/cgroup/cgroup.go000066400000000000000000000022611453374237200212320ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package cgroup import ( "errors" "github.com/containerd/cgroups" v1 "github.com/containerd/nydus-snapshotter/pkg/cgroup/v1" v2 "github.com/containerd/nydus-snapshotter/pkg/cgroup/v2" ) const ( defaultSlice = "system.slice" ) var ( ErrCgroupNotSupported = errors.New("cgroups: cgroup not supported") ) type Config struct { MemoryLimitInBytes int64 } type DaemonCgroup interface { // Delete the current cgroup. Delete() error // Add a process to current cgroup. AddProc(pid int) error } func createCgroup(name string, config Config) (DaemonCgroup, error) { if cgroups.Mode() == cgroups.Unified { return v2.NewCgroup(defaultSlice, name, config.MemoryLimitInBytes) } return v1.NewCgroup(defaultSlice, name, config.MemoryLimitInBytes) } func supported() bool { return cgroups.Mode() != cgroups.Unavailable } func displayMode() string { switch cgroups.Mode() { case cgroups.Legacy: return "legacy" case cgroups.Hybrid: return "hybrid" case cgroups.Unified: return "unified" case cgroups.Unavailable: return "unavailable" default: return "unknown" } } nydus-snapshotter-0.13.4/pkg/cgroup/manager.go000066400000000000000000000016041453374237200213450ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package cgroup import ( "github.com/containerd/containerd/log" ) type Manager struct { name string config Config cgroup DaemonCgroup } type Opt struct { Name string Config Config } func NewManager(opt Opt) (*Manager, error) { if !supported() { log.L.Warn("cgroup is not supported") return nil, ErrCgroupNotSupported } log.L.Infof("cgroup mode: %s", displayMode()) cg, err := createCgroup(opt.Name, opt.Config) if err != nil { return nil, err } return &Manager{ name: opt.Name, config: opt.Config, cgroup: cg, }, nil } // Please make sure the *Manager is not null. func (m *Manager) AddProc(pid int) error { return m.cgroup.AddProc(pid) } // Please make sure the *Manager is not null. func (m *Manager) Delete() error { return m.cgroup.Delete() } nydus-snapshotter-0.13.4/pkg/cgroup/v1/000077500000000000000000000000001453374237200177315ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/cgroup/v1/v1.go000066400000000000000000000041141453374237200206060ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package v1 import ( "github.com/containerd/cgroups/v3/cgroup1" "github.com/containerd/containerd/log" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" ) type Cgroup struct { controller cgroup1.Cgroup } func generateHierarchy() cgroup1.Hierarchy { return cgroup1.SingleSubsystem(cgroup1.Default, cgroup1.Memory) } func NewCgroup(slice, name string, memoryLimitInBytes int64) (Cgroup, error) { hierarchy := generateHierarchy() specResources := &specs.LinuxResources{ Memory: &specs.LinuxMemory{ Limit: &memoryLimitInBytes, }, } controller, err := cgroup1.Load(cgroup1.Slice(slice, name), cgroup1.WithHiearchy(hierarchy)) if err != nil && err != cgroup1.ErrCgroupDeleted { return Cgroup{}, err } if controller != nil { processes, err := controller.Processes(cgroup1.Memory, true) if err != nil { return Cgroup{}, err } if len(processes) > 0 { log.L.Infof("target cgroup is existed with processes %v", processes) if err := controller.Update(specResources); err != nil { return Cgroup{}, err } return Cgroup{ controller: controller, }, nil } if err := controller.Delete(); err != nil { return Cgroup{}, err } } controller, err = cgroup1.New(cgroup1.Slice(slice, name), specResources, cgroup1.WithHiearchy(hierarchy)) if err != nil { return Cgroup{}, errors.Wrapf(err, "create cgroup") } log.L.Infof("create cgroup (v1) successful, state: %v", controller.State()) return Cgroup{ controller: controller, }, nil } func (cg Cgroup) Delete() error { processes, err := cg.controller.Processes(cgroup1.Memory, true) if err != nil { return err } if len(processes) > 0 { log.L.Infof("skip destroy cgroup because of running daemon %v", processes) return nil } return cg.controller.Delete() } func (cg Cgroup) AddProc(pid int) error { err := cg.controller.AddProc(uint64(pid), cgroup1.Memory) if err != nil { return err } log.L.Infof("add process %d to daemon cgroup successful", pid) return nil } nydus-snapshotter-0.13.4/pkg/cgroup/v2/000077500000000000000000000000001453374237200177325ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/cgroup/v2/v2.go000066400000000000000000000036571453374237200206230ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package v2 import ( "errors" "fmt" "os" "path/filepath" "strings" "github.com/containerd/cgroups/v3/cgroup2" "github.com/containerd/containerd/log" "golang.org/x/exp/slices" ) const ( defaultRoot = "/sys/fs/cgroup" ) var ( ErrRootMemorySubtreeControllerDisabled = errors.New("cgroups v2: root subtree controller for memory is disabled") ) type Cgroup struct { manager *cgroup2.Manager } func readSubtreeControllers(dir string) ([]string, error) { b, err := os.ReadFile(filepath.Join(dir, "cgroup.subtree_control")) if err != nil { return nil, err } return strings.Fields(string(b)), nil } func NewCgroup(slice, name string, memoryLimitInBytes int64) (Cgroup, error) { resources := &cgroup2.Resources{ Memory: &cgroup2.Memory{}, } if memoryLimitInBytes > -1 { resources = &cgroup2.Resources{ Memory: &cgroup2.Memory{ Max: &memoryLimitInBytes, }, } } rootSubtreeControllers, err := readSubtreeControllers(defaultRoot) if err != nil { return Cgroup{}, err } log.L.Infof("root subtree controllers: %s", rootSubtreeControllers) if !slices.Contains(rootSubtreeControllers, "memory") { return Cgroup{}, ErrRootMemorySubtreeControllerDisabled } m, err := cgroup2.NewManager(defaultRoot, fmt.Sprintf("/%s/%s", slice, name), resources) if err != nil { return Cgroup{}, err } controllers, err := m.Controllers() if err != nil { return Cgroup{}, err } log.L.Infof("create cgroup (v2) successful, controllers: %v", controllers) return Cgroup{ manager: m, }, nil } func (cg Cgroup) Delete() error { if cg.manager != nil { return cg.manager.Delete() } return nil } func (cg Cgroup) AddProc(pid int) error { if cg.manager != nil { err := cg.manager.AddProc(uint64(pid)) if err != nil { return err } log.L.Infof("add process %d to daemon cgroup successful", pid) } return nil } nydus-snapshotter-0.13.4/pkg/converter/000077500000000000000000000000001453374237200201135ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/converter/constant.go000066400000000000000000000023361453374237200222770ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package converter const ( ManifestOSFeatureNydus = "nydus.remoteimage.v1" MediaTypeNydusBlob = "application/vnd.oci.image.layer.nydus.blob.v1" BootstrapFileNameInLayer = "image/image.boot" ManifestNydusCache = "containerd.io/snapshot/nydus-cache" LayerAnnotationFSVersion = "containerd.io/snapshot/nydus-fs-version" LayerAnnotationNydusBlob = "containerd.io/snapshot/nydus-blob" LayerAnnotationNydusBlobDigest = "containerd.io/snapshot/nydus-blob-digest" LayerAnnotationNydusBlobSize = "containerd.io/snapshot/nydus-blob-size" LayerAnnotationNydusBootstrap = "containerd.io/snapshot/nydus-bootstrap" LayerAnnotationNydusSourceChainID = "containerd.io/snapshot/nydus-source-chainid" LayerAnnotationNydusEncryptedBlob = "containerd.io/snapshot/nydus-encrypted-blob" LayerAnnotationNydusSourceDigest = "containerd.io/snapshot/nydus-source-digest" LayerAnnotationNydusTargetDigest = "containerd.io/snapshot/nydus-target-digest" LayerAnnotationNydusReferenceBlobIDs = "containerd.io/snapshot/nydus-reference-blob-ids" LayerAnnotationUncompressed = "containerd.io/uncompressed" ) nydus-snapshotter-0.13.4/pkg/converter/convert_unix.go000066400000000000000000001074541453374237200232000ustar00rootroot00000000000000//go:build !windows // +build !windows /* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package converter import ( "archive/tar" "bytes" "compress/gzip" "context" "encoding/binary" "fmt" "io" "os" "path/filepath" "sync" "syscall" "github.com/containerd/containerd/archive" "github.com/containerd/containerd/archive/compression" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/images/converter" "github.com/containerd/containerd/labels" "github.com/containerd/fifo" "github.com/klauspost/compress/zstd" "github.com/opencontainers/go-digest" "github.com/opencontainers/image-spec/identity" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "golang.org/x/sync/errgroup" "github.com/containerd/nydus-snapshotter/pkg/converter/tool" "github.com/containerd/nydus-snapshotter/pkg/label" ) const EntryBlob = "image.blob" const EntryBootstrap = "image.boot" const EntryBlobMeta = "blob.meta" const EntryBlobMetaHeader = "blob.meta.header" const EntryTOC = "rafs.blob.toc" const envNydusBuilder = "NYDUS_BUILDER" const envNydusWorkDir = "NYDUS_WORKDIR" const configGCLabelKey = "containerd.io/gc.ref.content.config" var bufPool = sync.Pool{ New: func() interface{} { buffer := make([]byte, 1<<20) return &buffer }, } func getBuilder(specifiedPath string) string { if specifiedPath != "" { return specifiedPath } builderPath := os.Getenv(envNydusBuilder) if builderPath != "" { return builderPath } return "nydus-image" } func ensureWorkDir(specifiedBasePath string) (string, error) { var baseWorkDir string if specifiedBasePath != "" { baseWorkDir = specifiedBasePath } else { baseWorkDir = os.Getenv(envNydusWorkDir) } if baseWorkDir == "" { baseWorkDir = os.TempDir() } if err := os.MkdirAll(baseWorkDir, 0750); err != nil { return "", errors.Wrapf(err, "create base directory %s", baseWorkDir) } workDirPath, err := os.MkdirTemp(baseWorkDir, "nydus-converter-") if err != nil { return "", errors.Wrap(err, "create work directory") } return workDirPath, nil } // Unpack a OCI formatted tar stream into a directory. func unpackOciTar(ctx context.Context, dst string, reader io.Reader) error { ds, err := compression.DecompressStream(reader) if err != nil { return errors.Wrap(err, "unpack stream") } defer ds.Close() if _, err := archive.Apply( ctx, dst, ds, archive.WithConvertWhiteout(func(hdr *tar.Header, file string) (bool, error) { // Keep to extract all whiteout files. return true, nil }), ); err != nil { return errors.Wrap(err, "apply with convert whiteout") } return nil } // unpackNydusBlob unpacks a Nydus formatted tar stream into a directory. // unpackBlob indicates whether to unpack blob data. func unpackNydusBlob(bootDst, blobDst string, ra content.ReaderAt, unpackBlob bool) error { boot, err := os.OpenFile(bootDst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0640) if err != nil { return errors.Wrapf(err, "write to bootstrap %s", bootDst) } defer boot.Close() if _, err = UnpackEntry(ra, EntryBootstrap, boot); err != nil { return errors.Wrap(err, "unpack bootstrap from nydus") } if unpackBlob { blob, err := os.OpenFile(blobDst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0640) if err != nil { return errors.Wrapf(err, "write to blob %s", blobDst) } defer blob.Close() if _, err = UnpackEntry(ra, EntryBlob, blob); err != nil { if errors.Is(err, ErrNotFound) { // The nydus layer may contain only bootstrap and no blob // data, which should be ignored. return nil } return errors.Wrap(err, "unpack blob from nydus") } } return nil } func seekFileByTarHeader(ra content.ReaderAt, targetName string, maxSize *int64, handle func(io.Reader, *tar.Header) error) error { const headerSize = 512 if headerSize > ra.Size() { return fmt.Errorf("invalid nydus tar size %d", ra.Size()) } cur := ra.Size() - headerSize reader := newSeekReader(ra) // Seek from tail to head of nydus formatted tar stream to find // target data. for { // Try to seek the part of tar header. _, err := reader.Seek(cur, io.SeekStart) if err != nil { return errors.Wrapf(err, "seek %d for nydus tar header", cur) } // Parse tar header. tr := tar.NewReader(reader) hdr, err := tr.Next() if err != nil { return errors.Wrap(err, "parse nydus tar header") } if cur < hdr.Size { return fmt.Errorf("invalid nydus tar data, name %s, size %d", hdr.Name, hdr.Size) } if hdr.Name == targetName { if maxSize != nil && hdr.Size > *maxSize { return fmt.Errorf("invalid nydus tar size %d", ra.Size()) } // Try to seek the part of tar data. _, err = reader.Seek(cur-hdr.Size, io.SeekStart) if err != nil { return errors.Wrap(err, "seek target data offset") } dataReader := io.NewSectionReader(reader, cur-hdr.Size, hdr.Size) if err := handle(dataReader, hdr); err != nil { return errors.Wrap(err, "handle target data") } return nil } cur = cur - hdr.Size - headerSize if cur < 0 { break } } return errors.Wrapf(ErrNotFound, "can't find target %s by seeking tar", targetName) } func seekFileByTOC(ra content.ReaderAt, targetName string, handle func(io.Reader, *tar.Header) error) (*TOCEntry, error) { entrySize := 128 maxSize := int64(1 << 20) var tocEntry *TOCEntry err := seekFileByTarHeader(ra, EntryTOC, &maxSize, func(tocEntryDataReader io.Reader, _ *tar.Header) error { entryData, err := io.ReadAll(tocEntryDataReader) if err != nil { return errors.Wrap(err, "read toc entries") } if len(entryData)%entrySize != 0 { return fmt.Errorf("invalid entries length %d", len(entryData)) } count := len(entryData) / entrySize for i := 0; i < count; i++ { var entry TOCEntry r := bytes.NewReader(entryData[i*entrySize : i*entrySize+entrySize]) if err := binary.Read(r, binary.LittleEndian, &entry); err != nil { return errors.Wrap(err, "read toc entries") } if entry.GetName() == targetName { compressor, err := entry.GetCompressor() if err != nil { return errors.Wrap(err, "get compressor of entry") } compressedOffset := int64(entry.GetCompressedOffset()) compressedSize := int64(entry.GetCompressedSize()) sr := io.NewSectionReader(ra, compressedOffset, compressedSize) var rd io.Reader switch compressor { case CompressorZstd: decoder, err := zstd.NewReader(sr) if err != nil { return errors.Wrap(err, "seek to target data offset") } defer decoder.Close() rd = decoder case CompressorNone: rd = sr default: return fmt.Errorf("unsupported compressor %x", compressor) } if err := handle(rd, nil); err != nil { return errors.Wrap(err, "handle target entry data") } tocEntry = &entry return nil } } return errors.Wrapf(ErrNotFound, "can't find target %s by seeking TOC", targetName) }) return tocEntry, err } // Unpack the file from nydus formatted tar stream. // The nydus formatted tar stream is a tar-like structure that arranges the // data as follows: // // `data | tar_header | ... | data | tar_header | [toc_entry | ... | toc_entry | tar_header]` func UnpackEntry(ra content.ReaderAt, targetName string, target io.Writer) (*TOCEntry, error) { handle := func(dataReader io.Reader, _ *tar.Header) error { // Copy data to provided target writer. if _, err := io.Copy(target, dataReader); err != nil { return errors.Wrap(err, "copy target data to reader") } return nil } return seekFile(ra, targetName, handle) } func seekFile(ra content.ReaderAt, targetName string, handle func(io.Reader, *tar.Header) error) (*TOCEntry, error) { // Try seek target data by TOC. entry, err := seekFileByTOC(ra, targetName, handle) if err != nil { if !errors.Is(err, ErrNotFound) { return nil, errors.Wrap(err, "seek file by TOC") } } else { return entry, nil } // Seek target data by tar header, ensure compatible with old rafs blob format. return nil, seekFileByTarHeader(ra, targetName, nil, handle) } // Pack converts an OCI tar stream to nydus formatted stream with a tar-like // structure that arranges the data as follows: // // `data | tar_header | data | tar_header | [toc_entry | ... | toc_entry | tar_header]` // // The caller should write OCI tar stream into the returned `io.WriteCloser`, // then the Pack method will write the nydus formatted stream to `dest` // provided by the caller. // // Important: the caller must check `io.WriteCloser.Close() == nil` to ensure // the conversion workflow is finished. func Pack(ctx context.Context, dest io.Writer, opt PackOption) (io.WriteCloser, error) { if opt.FsVersion == "" { opt.FsVersion = "6" } builderPath := getBuilder(opt.BuilderPath) requiredFeatures := tool.NewFeatures(tool.FeatureTar2Rafs) if opt.BatchSize != "" && opt.BatchSize != "0" { requiredFeatures.Add(tool.FeatureBatchSize) } if opt.Encrypt { requiredFeatures.Add(tool.FeatureEncrypt) } detectedFeatures, err := tool.DetectFeatures(builderPath, requiredFeatures, tool.GetHelp) if err != nil { return nil, err } opt.features = detectedFeatures if opt.OCIRef { if opt.FsVersion == "6" { return packFromTar(ctx, dest, opt) } return nil, fmt.Errorf("oci ref can only be supported by fs version 6") } if opt.features.Contains(tool.FeatureBatchSize) && opt.FsVersion != "6" { return nil, fmt.Errorf("'--batch-size' can only be supported by fs version 6") } if opt.features.Contains(tool.FeatureTar2Rafs) { return packFromTar(ctx, dest, opt) } return packFromDirectory(ctx, dest, opt, builderPath) } func packFromDirectory(ctx context.Context, dest io.Writer, opt PackOption, builderPath string) (io.WriteCloser, error) { workDir, err := ensureWorkDir(opt.WorkDir) if err != nil { return nil, errors.Wrap(err, "ensure work directory") } defer func() { if err != nil { os.RemoveAll(workDir) } }() sourceDir := filepath.Join(workDir, "source") if err := os.MkdirAll(sourceDir, 0755); err != nil { return nil, errors.Wrap(err, "create source directory") } pr, pw := io.Pipe() unpackDone := make(chan bool, 1) go func() { if err := unpackOciTar(ctx, sourceDir, pr); err != nil { pr.CloseWithError(errors.Wrapf(err, "unpack to %s", sourceDir)) close(unpackDone) return } unpackDone <- true }() wc := newWriteCloser(pw, func() error { defer os.RemoveAll(workDir) // Because PipeWriter#Close is called does not mean that the PipeReader // has finished reading all the data, and unpack may not be complete yet, // so we need to wait for that here. <-unpackDone blobPath := filepath.Join(workDir, "blob") blobFifo, err := fifo.OpenFifo(ctx, blobPath, syscall.O_CREAT|syscall.O_RDONLY|syscall.O_NONBLOCK, 0640) if err != nil { return errors.Wrapf(err, "create fifo file") } defer blobFifo.Close() go func() { err := tool.Pack(tool.PackOption{ BuilderPath: builderPath, BlobPath: blobPath, FsVersion: opt.FsVersion, SourcePath: sourceDir, ChunkDictPath: opt.ChunkDictPath, PrefetchPatterns: opt.PrefetchPatterns, AlignedChunk: opt.AlignedChunk, ChunkSize: opt.ChunkSize, BatchSize: opt.BatchSize, Compressor: opt.Compressor, Timeout: opt.Timeout, Encrypt: opt.Encrypt, Features: opt.features, }) if err != nil { pw.CloseWithError(errors.Wrapf(err, "convert blob for %s", sourceDir)) blobFifo.Close() } }() buffer := bufPool.Get().(*[]byte) defer bufPool.Put(buffer) if _, err := io.CopyBuffer(dest, blobFifo, *buffer); err != nil { return errors.Wrap(err, "pack nydus tar") } return nil }) return wc, nil } func packFromTar(ctx context.Context, dest io.Writer, opt PackOption) (io.WriteCloser, error) { workDir, err := ensureWorkDir(opt.WorkDir) if err != nil { return nil, errors.Wrap(err, "ensure work directory") } defer func() { if err != nil { os.RemoveAll(workDir) } }() rafsBlobPath := filepath.Join(workDir, "blob.rafs") rafsBlobFifo, err := fifo.OpenFifo(ctx, rafsBlobPath, syscall.O_CREAT|syscall.O_RDONLY|syscall.O_NONBLOCK, 0640) if err != nil { return nil, errors.Wrapf(err, "create fifo file") } tarBlobPath := filepath.Join(workDir, "blob.targz") tarBlobFifo, err := fifo.OpenFifo(ctx, tarBlobPath, syscall.O_CREAT|syscall.O_WRONLY|syscall.O_NONBLOCK, 0640) if err != nil { defer rafsBlobFifo.Close() return nil, errors.Wrapf(err, "create fifo file") } pr, pw := io.Pipe() eg := errgroup.Group{} wc := newWriteCloser(pw, func() error { defer os.RemoveAll(workDir) if err := eg.Wait(); err != nil { return errors.Wrapf(err, "convert nydus ref") } return nil }) eg.Go(func() error { defer tarBlobFifo.Close() buffer := bufPool.Get().(*[]byte) defer bufPool.Put(buffer) if _, err := io.CopyBuffer(tarBlobFifo, pr, *buffer); err != nil { return errors.Wrapf(err, "copy targz to fifo") } return nil }) eg.Go(func() error { defer rafsBlobFifo.Close() buffer := bufPool.Get().(*[]byte) defer bufPool.Put(buffer) if _, err := io.CopyBuffer(dest, rafsBlobFifo, *buffer); err != nil { return errors.Wrapf(err, "copy blob meta fifo to nydus blob") } return nil }) eg.Go(func() error { var err error if opt.OCIRef { err = tool.Pack(tool.PackOption{ BuilderPath: getBuilder(opt.BuilderPath), OCIRef: opt.OCIRef, BlobPath: rafsBlobPath, SourcePath: tarBlobPath, Timeout: opt.Timeout, Features: opt.features, }) } else { err = tool.Pack(tool.PackOption{ BuilderPath: getBuilder(opt.BuilderPath), BlobPath: rafsBlobPath, FsVersion: opt.FsVersion, SourcePath: tarBlobPath, ChunkDictPath: opt.ChunkDictPath, PrefetchPatterns: opt.PrefetchPatterns, AlignedChunk: opt.AlignedChunk, ChunkSize: opt.ChunkSize, BatchSize: opt.BatchSize, Compressor: opt.Compressor, Timeout: opt.Timeout, Encrypt: opt.Encrypt, Features: opt.features, }) } if err != nil { // Without handling the returned error because we just only // focus on the command exit status in `tool.Pack`. wc.Close() } return errors.Wrapf(err, "call builder") }) return wc, nil } func calcBlobTOCDigest(ra content.ReaderAt) (*digest.Digest, error) { maxSize := int64(1 << 20) digester := digest.Canonical.Digester() if err := seekFileByTarHeader(ra, EntryTOC, &maxSize, func(tocData io.Reader, _ *tar.Header) error { if _, err := io.Copy(digester.Hash(), tocData); err != nil { return errors.Wrap(err, "calc toc data and header digest") } return nil }); err != nil { return nil, err } tocDigest := digester.Digest() return &tocDigest, nil } // Merge multiple nydus bootstraps (from each layer of image) to a final // bootstrap. And due to the possibility of enabling the `ChunkDictPath` // option causes the data deduplication, it will return the actual blob // digests referenced by the bootstrap. func Merge(ctx context.Context, layers []Layer, dest io.Writer, opt MergeOption) ([]digest.Digest, error) { workDir, err := ensureWorkDir(opt.WorkDir) if err != nil { return nil, errors.Wrap(err, "ensure work directory") } defer os.RemoveAll(workDir) getBootstrapPath := func(layerIdx int) string { digestHex := layers[layerIdx].Digest.Hex() if originalDigest := layers[layerIdx].OriginalDigest; originalDigest != nil { return filepath.Join(workDir, originalDigest.Hex()) } return filepath.Join(workDir, digestHex) } eg, _ := errgroup.WithContext(ctx) sourceBootstrapPaths := []string{} rafsBlobDigests := []string{} rafsBlobSizes := []int64{} rafsBlobTOCDigests := []string{} for idx := range layers { sourceBootstrapPaths = append(sourceBootstrapPaths, getBootstrapPath(idx)) if layers[idx].OriginalDigest != nil { rafsBlobTOCDigest, err := calcBlobTOCDigest(layers[idx].ReaderAt) if err != nil { return nil, errors.Wrapf(err, "calc blob toc digest for layer %s", layers[idx].Digest) } rafsBlobTOCDigests = append(rafsBlobTOCDigests, rafsBlobTOCDigest.Hex()) rafsBlobDigests = append(rafsBlobDigests, layers[idx].Digest.Hex()) rafsBlobSizes = append(rafsBlobSizes, layers[idx].ReaderAt.Size()) } eg.Go(func(idx int) func() error { return func() error { // Use the hex hash string of whole tar blob as the bootstrap name. bootstrap, err := os.Create(getBootstrapPath(idx)) if err != nil { return errors.Wrap(err, "create source bootstrap") } defer bootstrap.Close() if _, err := UnpackEntry(layers[idx].ReaderAt, EntryBootstrap, bootstrap); err != nil { return errors.Wrap(err, "unpack nydus tar") } return nil } }(idx)) } if err := eg.Wait(); err != nil { return nil, errors.Wrap(err, "unpack all bootstraps") } targetBootstrapPath := filepath.Join(workDir, "bootstrap") blobDigests, err := tool.Merge(tool.MergeOption{ BuilderPath: getBuilder(opt.BuilderPath), SourceBootstrapPaths: sourceBootstrapPaths, RafsBlobDigests: rafsBlobDigests, RafsBlobSizes: rafsBlobSizes, RafsBlobTOCDigests: rafsBlobTOCDigests, TargetBootstrapPath: targetBootstrapPath, ChunkDictPath: opt.ChunkDictPath, ParentBootstrapPath: opt.ParentBootstrapPath, PrefetchPatterns: opt.PrefetchPatterns, OutputJSONPath: filepath.Join(workDir, "merge-output.json"), Timeout: opt.Timeout, }) if err != nil { return nil, errors.Wrap(err, "merge bootstrap") } var rc io.ReadCloser if opt.WithTar { rc, err = packToTar(targetBootstrapPath, fmt.Sprintf("image/%s", EntryBootstrap), false) if err != nil { return nil, errors.Wrap(err, "pack bootstrap to tar") } } else { rc, err = os.Open(targetBootstrapPath) if err != nil { return nil, errors.Wrap(err, "open targe bootstrap") } } defer rc.Close() buffer := bufPool.Get().(*[]byte) defer bufPool.Put(buffer) if _, err = io.CopyBuffer(dest, rc, *buffer); err != nil { return nil, errors.Wrap(err, "copy merged bootstrap") } return blobDigests, nil } // Unpack converts a nydus blob layer to OCI formatted tar stream. func Unpack(ctx context.Context, ra content.ReaderAt, dest io.Writer, opt UnpackOption) error { workDir, err := ensureWorkDir(opt.WorkDir) if err != nil { return errors.Wrap(err, "ensure work directory") } defer os.RemoveAll(workDir) bootPath, blobPath := filepath.Join(workDir, EntryBootstrap), filepath.Join(workDir, EntryBlob) if err = unpackNydusBlob(bootPath, blobPath, ra, !opt.Stream); err != nil { return errors.Wrap(err, "unpack nydus tar") } tarPath := filepath.Join(workDir, "oci.tar") blobFifo, err := fifo.OpenFifo(ctx, tarPath, syscall.O_CREAT|syscall.O_RDONLY|syscall.O_NONBLOCK, 0640) if err != nil { return errors.Wrapf(err, "create fifo file") } defer blobFifo.Close() unpackOpt := tool.UnpackOption{ BuilderPath: getBuilder(opt.BuilderPath), BootstrapPath: bootPath, BlobPath: blobPath, TarPath: tarPath, Timeout: opt.Timeout, } if opt.Stream { proxy, err := setupContentStoreProxy(opt.WorkDir, ra) if err != nil { return errors.Wrap(err, "new content store proxy") } defer proxy.close() // generate backend config file backendConfigStr := fmt.Sprintf(`{"version":2,"backend":{"type":"http-proxy","http-proxy":{"addr":"%s"}}}`, proxy.socketPath) backendConfigPath := filepath.Join(workDir, "backend-config.json") if err := os.WriteFile(backendConfigPath, []byte(backendConfigStr), 0640); err != nil { return errors.Wrap(err, "write backend config") } unpackOpt.BlobPath = "" unpackOpt.BackendConfigPath = backendConfigPath } unpackErrChan := make(chan error) go func() { defer close(unpackErrChan) err := tool.Unpack(unpackOpt) if err != nil { blobFifo.Close() unpackErrChan <- err } }() buffer := bufPool.Get().(*[]byte) defer bufPool.Put(buffer) if _, err := io.CopyBuffer(dest, blobFifo, *buffer); err != nil { if unpackErr := <-unpackErrChan; unpackErr != nil { return errors.Wrap(unpackErr, "unpack") } return errors.Wrap(err, "copy oci tar") } return nil } // IsNydusBlobAndExists returns true when the specified digest of content exists in // the content store and it's nydus blob format. func IsNydusBlobAndExists(ctx context.Context, cs content.Store, desc ocispec.Descriptor) bool { _, err := cs.Info(ctx, desc.Digest) if err != nil { return false } return IsNydusBlob(desc) } // IsNydusBlob returns true when the specified descriptor is nydus blob layer. func IsNydusBlob(desc ocispec.Descriptor) bool { if desc.Annotations == nil { return false } _, hasAnno := desc.Annotations[LayerAnnotationNydusBlob] return hasAnno } // IsNydusBootstrap returns true when the specified descriptor is nydus bootstrap layer. func IsNydusBootstrap(desc ocispec.Descriptor) bool { if desc.Annotations == nil { return false } _, hasAnno := desc.Annotations[LayerAnnotationNydusBootstrap] return hasAnno } // isNydusImage checks if the last layer is nydus bootstrap, // so that we can ensure it is a nydus image. func isNydusImage(manifest *ocispec.Manifest) bool { layers := manifest.Layers if len(layers) != 0 { desc := layers[len(layers)-1] if IsNydusBootstrap(desc) { return true } } return false } // makeBlobDesc returns a ocispec.Descriptor by the given information. func makeBlobDesc(ctx context.Context, cs content.Store, opt PackOption, sourceDigest, targetDigest digest.Digest) (*ocispec.Descriptor, error) { targetInfo, err := cs.Info(ctx, targetDigest) if err != nil { return nil, errors.Wrapf(err, "get target blob info %s", targetDigest) } if targetInfo.Labels == nil { targetInfo.Labels = map[string]string{} } // Write a diff id label of layer in content store for simplifying // diff id calculation to speed up the conversion. // See: https://github.com/containerd/containerd/blob/e4fefea5544d259177abb85b64e428702ac49c97/images/diffid.go#L49 targetInfo.Labels[labels.LabelUncompressed] = targetDigest.String() _, err = cs.Update(ctx, targetInfo) if err != nil { return nil, errors.Wrap(err, "update layer label") } targetDesc := ocispec.Descriptor{ Digest: targetDigest, Size: targetInfo.Size, MediaType: MediaTypeNydusBlob, Annotations: map[string]string{ // Use `containerd.io/uncompressed` to generate DiffID of // layer defined in OCI spec. LayerAnnotationUncompressed: targetDigest.String(), LayerAnnotationNydusBlob: "true", }, } if opt.OCIRef { targetDesc.Annotations[label.NydusRefLayer] = sourceDigest.String() } if opt.Encrypt { targetDesc.Annotations[LayerAnnotationNydusEncryptedBlob] = "true" } return &targetDesc, nil } // LayerConvertFunc returns a function which converts an OCI image layer to // a nydus blob layer, and set the media type to "application/vnd.oci.image.layer.nydus.blob.v1". func LayerConvertFunc(opt PackOption) converter.ConvertFunc { return func(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (*ocispec.Descriptor, error) { if !images.IsLayerType(desc.MediaType) { return nil, nil } // Skip the conversion of nydus layer. if IsNydusBlob(desc) || IsNydusBootstrap(desc) { return nil, nil } // Use remote cache to avoid unnecessary conversion info, err := cs.Info(ctx, desc.Digest) if err != nil { return nil, errors.Wrapf(err, "get blob info %s", desc.Digest) } if targetDigest := digest.Digest(info.Labels[LayerAnnotationNydusTargetDigest]); targetDigest.Validate() == nil { return makeBlobDesc(ctx, cs, opt, desc.Digest, targetDigest) } ra, err := cs.ReaderAt(ctx, desc) if err != nil { return nil, errors.Wrap(err, "get source blob reader") } defer ra.Close() rdr := io.NewSectionReader(ra, 0, ra.Size()) ref := fmt.Sprintf("convert-nydus-from-%s", desc.Digest) dst, err := content.OpenWriter(ctx, cs, content.WithRef(ref)) if err != nil { return nil, errors.Wrap(err, "open blob writer") } defer dst.Close() var tr io.ReadCloser if opt.OCIRef { tr = io.NopCloser(rdr) } else { tr, err = compression.DecompressStream(rdr) if err != nil { return nil, errors.Wrap(err, "decompress blob stream") } } digester := digest.SHA256.Digester() pr, pw := io.Pipe() tw, err := Pack(ctx, io.MultiWriter(pw, digester.Hash()), opt) if err != nil { return nil, errors.Wrap(err, "pack tar to nydus") } go func() { defer pw.Close() buffer := bufPool.Get().(*[]byte) defer bufPool.Put(buffer) if _, err := io.CopyBuffer(tw, tr, *buffer); err != nil { pw.CloseWithError(err) return } if err := tr.Close(); err != nil { pw.CloseWithError(err) return } if err := tw.Close(); err != nil { pw.CloseWithError(err) return } }() if err := content.Copy(ctx, dst, pr, 0, ""); err != nil { return nil, errors.Wrap(err, "copy nydus blob to content store") } blobDigest := digester.Digest() newDesc, err := makeBlobDesc(ctx, cs, opt, desc.Digest, blobDigest) if err != nil { return nil, err } if opt.Backend != nil { if err := opt.Backend.Push(ctx, cs, *newDesc); err != nil { return nil, errors.Wrap(err, "push to storage backend") } } return newDesc, nil } } // ConvertHookFunc returns a function which will be used as a callback // called for each blob after conversion is done. The function only hooks // the index conversion and the manifest conversion. func ConvertHookFunc(opt MergeOption) converter.ConvertHookFunc { return func(ctx context.Context, cs content.Store, orgDesc ocispec.Descriptor, newDesc *ocispec.Descriptor) (*ocispec.Descriptor, error) { // If the previous conversion did not occur, the `newDesc` may be nil. if newDesc == nil { return &orgDesc, nil } switch { case images.IsIndexType(newDesc.MediaType): return convertIndex(ctx, cs, orgDesc, newDesc) case images.IsManifestType(newDesc.MediaType): return convertManifest(ctx, cs, orgDesc, newDesc, opt) default: return newDesc, nil } } } // convertIndex modifies the original index by appending "nydus.remoteimage.v1" // to the Platform.OSFeatures of each modified manifest descriptors. func convertIndex(ctx context.Context, cs content.Store, orgDesc ocispec.Descriptor, newDesc *ocispec.Descriptor) (*ocispec.Descriptor, error) { var orgIndex ocispec.Index if _, err := readJSON(ctx, cs, &orgIndex, orgDesc); err != nil { return nil, errors.Wrap(err, "read target image index json") } // isManifestModified is a function to check whether the manifest is modified. isManifestModified := func(manifest ocispec.Descriptor) bool { for _, oldManifest := range orgIndex.Manifests { if manifest.Digest == oldManifest.Digest { return false } } return true } var index ocispec.Index indexLabels, err := readJSON(ctx, cs, &index, *newDesc) if err != nil { return nil, errors.Wrap(err, "read index json") } for i, manifest := range index.Manifests { if !isManifestModified(manifest) { // Skip the manifest which is not modified. continue } manifest.Platform.OSFeatures = append(manifest.Platform.OSFeatures, ManifestOSFeatureNydus) index.Manifests[i] = manifest } // If the converted manifest list contains only one manifest, // convert it directly to manifest. if len(index.Manifests) == 1 { return &index.Manifests[0], nil } // Update image index in content store. newIndexDesc, err := writeJSON(ctx, cs, index, *newDesc, indexLabels) if err != nil { return nil, errors.Wrap(err, "write index json") } return newIndexDesc, nil } // convertManifest merges all the nydus blob layers into a // nydus bootstrap layer, update the image config, // and modify the image manifest. func convertManifest(ctx context.Context, cs content.Store, oldDesc ocispec.Descriptor, newDesc *ocispec.Descriptor, opt MergeOption) (*ocispec.Descriptor, error) { var manifest ocispec.Manifest manifestDesc := *newDesc manifestLabels, err := readJSON(ctx, cs, &manifest, manifestDesc) if err != nil { return nil, errors.Wrap(err, "read manifest json") } if isNydusImage(&manifest) { return &manifestDesc, nil } // This option needs to be enabled for image scenario. opt.WithTar = true // If the original image is already an OCI type, we should forcibly set the // bootstrap layer to the OCI type. if !opt.OCI && oldDesc.MediaType == ocispec.MediaTypeImageManifest { opt.OCI = true } // Append bootstrap layer to manifest, encrypt bootstrap layer if needed. bootstrapDesc, blobDescs, err := MergeLayers(ctx, cs, manifest.Layers, opt) if err != nil { return nil, errors.Wrap(err, "merge nydus layers") } if opt.Backend != nil { // Only append nydus bootstrap layer into manifest, and do not put nydus // blob layer into manifest if blob storage backend is specified. manifest.Layers = []ocispec.Descriptor{*bootstrapDesc} } else { for idx, blobDesc := range blobDescs { blobGCLabelKey := fmt.Sprintf("containerd.io/gc.ref.content.l.%d", idx) manifestLabels[blobGCLabelKey] = blobDesc.Digest.String() } // Affected by chunk dict, the blob list referenced by final bootstrap // are from different layers, part of them are from original layers, part // from chunk dict bootstrap, so we need to rewrite manifest's layers here. blobDescs := append(blobDescs, *bootstrapDesc) manifest.Layers = blobDescs } // Update the gc label of bootstrap layer bootstrapGCLabelKey := fmt.Sprintf("containerd.io/gc.ref.content.l.%d", len(manifest.Layers)-1) manifestLabels[bootstrapGCLabelKey] = bootstrapDesc.Digest.String() // Rewrite diff ids and remove useless annotation. var config ocispec.Image configLabels, err := readJSON(ctx, cs, &config, manifest.Config) if err != nil { return nil, errors.Wrap(err, "read image config") } bootstrapHistory := ocispec.History{ CreatedBy: "Nydus Converter", Comment: "Nydus Bootstrap Layer", } if opt.Backend != nil { config.RootFS.DiffIDs = []digest.Digest{digest.Digest(bootstrapDesc.Annotations[LayerAnnotationUncompressed])} config.History = []ocispec.History{bootstrapHistory} } else { config.RootFS.DiffIDs = make([]digest.Digest, 0, len(manifest.Layers)) for i, layer := range manifest.Layers { config.RootFS.DiffIDs = append(config.RootFS.DiffIDs, digest.Digest(layer.Annotations[LayerAnnotationUncompressed])) // Remove useless annotation. delete(manifest.Layers[i].Annotations, LayerAnnotationUncompressed) } // Append history item for bootstrap layer, to ensure the history consistency. // See https://github.com/distribution/distribution/blob/e5d5810851d1f17a5070e9b6f940d8af98ea3c29/manifest/schema1/config_builder.go#L136 config.History = append(config.History, bootstrapHistory) } // Update image config in content store. newConfigDesc, err := writeJSON(ctx, cs, config, manifest.Config, configLabels) if err != nil { return nil, errors.Wrap(err, "write image config") } manifest.Config = *newConfigDesc // Update the config gc label manifestLabels[configGCLabelKey] = newConfigDesc.Digest.String() if opt.WithReferrer { // Associate a reference to the original OCI manifest. // See the `subject` field description in // https://github.com/opencontainers/image-spec/blob/main/manifest.md#image-manifest-property-descriptions manifest.Subject = &oldDesc } // Update image manifest in content store. newManifestDesc, err := writeJSON(ctx, cs, manifest, manifestDesc, manifestLabels) if err != nil { return nil, errors.Wrap(err, "write manifest") } return newManifestDesc, nil } // MergeLayers merges a list of nydus blob layer into a nydus bootstrap layer. // The media type of the nydus bootstrap layer is "application/vnd.oci.image.layer.v1.tar+gzip". func MergeLayers(ctx context.Context, cs content.Store, descs []ocispec.Descriptor, opt MergeOption) (*ocispec.Descriptor, []ocispec.Descriptor, error) { // Extracts nydus bootstrap from nydus format for each layer. layers := []Layer{} var chainID digest.Digest nydusBlobDigests := []digest.Digest{} for _, nydusBlobDesc := range descs { ra, err := cs.ReaderAt(ctx, nydusBlobDesc) if err != nil { return nil, nil, errors.Wrapf(err, "get reader for blob %q", nydusBlobDesc.Digest) } defer ra.Close() var originalDigest *digest.Digest if opt.OCIRef { digestStr := nydusBlobDesc.Annotations[label.NydusRefLayer] _originalDigest, err := digest.Parse(digestStr) if err != nil { return nil, nil, errors.Wrapf(err, "invalid label %s=%s", label.NydusRefLayer, digestStr) } originalDigest = &_originalDigest } layers = append(layers, Layer{ Digest: nydusBlobDesc.Digest, OriginalDigest: originalDigest, ReaderAt: ra, }) if chainID == "" { chainID = identity.ChainID([]digest.Digest{nydusBlobDesc.Digest}) } else { chainID = identity.ChainID([]digest.Digest{chainID, nydusBlobDesc.Digest}) } nydusBlobDigests = append(nydusBlobDigests, nydusBlobDesc.Digest) } // Merge all nydus bootstraps into a final nydus bootstrap. pr, pw := io.Pipe() originalBlobDigestChan := make(chan []digest.Digest, 1) go func() { defer pw.Close() originalBlobDigests, err := Merge(ctx, layers, pw, opt) if err != nil { pw.CloseWithError(errors.Wrapf(err, "merge nydus bootstrap")) } originalBlobDigestChan <- originalBlobDigests }() // Compress final nydus bootstrap to tar.gz and write into content store. cw, err := content.OpenWriter(ctx, cs, content.WithRef("nydus-merge-"+chainID.String())) if err != nil { return nil, nil, errors.Wrap(err, "open content store writer") } defer cw.Close() gw := gzip.NewWriter(cw) uncompressedDgst := digest.SHA256.Digester() compressed := io.MultiWriter(gw, uncompressedDgst.Hash()) buffer := bufPool.Get().(*[]byte) defer bufPool.Put(buffer) if _, err := io.CopyBuffer(compressed, pr, *buffer); err != nil { return nil, nil, errors.Wrapf(err, "copy bootstrap targz into content store") } if err := gw.Close(); err != nil { return nil, nil, errors.Wrap(err, "close gzip writer") } compressedDgst := cw.Digest() if err := cw.Commit(ctx, 0, compressedDgst, content.WithLabels(map[string]string{ LayerAnnotationUncompressed: uncompressedDgst.Digest().String(), })); err != nil { if !errdefs.IsAlreadyExists(err) { return nil, nil, errors.Wrap(err, "commit to content store") } } if err := cw.Close(); err != nil { return nil, nil, errors.Wrap(err, "close content store writer") } bootstrapInfo, err := cs.Info(ctx, compressedDgst) if err != nil { return nil, nil, errors.Wrap(err, "get info from content store") } originalBlobDigests := <-originalBlobDigestChan blobDescs := []ocispec.Descriptor{} var blobDigests []digest.Digest if opt.OCIRef { blobDigests = nydusBlobDigests } else { blobDigests = originalBlobDigests } for idx, blobDigest := range blobDigests { blobInfo, err := cs.Info(ctx, blobDigest) if err != nil { return nil, nil, errors.Wrap(err, "get info from content store") } blobDesc := ocispec.Descriptor{ Digest: blobDigest, Size: blobInfo.Size, MediaType: MediaTypeNydusBlob, Annotations: map[string]string{ LayerAnnotationUncompressed: blobDigest.String(), LayerAnnotationNydusBlob: "true", }, } if opt.OCIRef { blobDesc.Annotations[label.NydusRefLayer] = layers[idx].OriginalDigest.String() } if opt.Encrypt != nil { blobDesc.Annotations[LayerAnnotationNydusEncryptedBlob] = "true" } blobDescs = append(blobDescs, blobDesc) } if opt.FsVersion == "" { opt.FsVersion = "6" } mediaType := images.MediaTypeDockerSchema2LayerGzip if opt.OCI { mediaType = ocispec.MediaTypeImageLayerGzip } bootstrapDesc := ocispec.Descriptor{ Digest: compressedDgst, Size: bootstrapInfo.Size, MediaType: mediaType, Annotations: map[string]string{ LayerAnnotationUncompressed: uncompressedDgst.Digest().String(), LayerAnnotationFSVersion: opt.FsVersion, // Use this annotation to identify nydus bootstrap layer. LayerAnnotationNydusBootstrap: "true", }, } if opt.Encrypt != nil { // Encrypt the Nydus bootstrap layer. bootstrapDesc, err = opt.Encrypt(ctx, cs, bootstrapDesc) if err != nil { return nil, nil, errors.Wrap(err, "encrypt bootstrap layer") } } return &bootstrapDesc, blobDescs, nil } nydus-snapshotter-0.13.4/pkg/converter/convert_windows.go000066400000000000000000000026261453374237200237020ustar00rootroot00000000000000//go:build windows // +build windows /* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package converter import ( "context" "io" "github.com/containerd/containerd/content" "github.com/containerd/containerd/images/converter" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) func Pack(ctx context.Context, dest io.Writer, opt PackOption) (io.WriteCloser, error) { panic("not implemented") } func Merge(ctx context.Context, layers []Layer, dest io.Writer, opt MergeOption) ([]digest.Digest, error) { panic("not implemented") } func Unpack(ctx context.Context, ra content.ReaderAt, dest io.Writer, opt UnpackOption) error { panic("not implemented") } func IsNydusBlobAndExists(ctx context.Context, cs content.Store, desc ocispec.Descriptor) bool { panic("not implemented") } func IsNydusBlob(desc ocispec.Descriptor) bool { panic("not implemented") } func IsNydusBootstrap(desc ocispec.Descriptor) bool { panic("not implemented") } func LayerConvertFunc(opt PackOption) converter.ConvertFunc { panic("not implemented") } func ConvertHookFunc(opt MergeOption) converter.ConvertHookFunc { panic("not implemented") } func MergeLayers(ctx context.Context, cs content.Store, descs []ocispec.Descriptor, opt MergeOption) (*ocispec.Descriptor, []ocispec.Descriptor, error) { panic("not implemented") } nydus-snapshotter-0.13.4/pkg/converter/cs_proxy_unix.go000066400000000000000000000100011453374237200233430ustar00rootroot00000000000000//go:build !windows // +build !windows /* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package converter import ( "archive/tar" "context" "fmt" "io" "net" "net/http" "os" "strconv" "strings" "github.com/containerd/containerd/content" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) type contentStoreProxy struct { socketPath string server *http.Server } func setupContentStoreProxy(workDir string, ra content.ReaderAt) (*contentStoreProxy, error) { sockP, err := os.CreateTemp(workDir, "nydus-cs-proxy-*.sock") if err != nil { return nil, errors.Wrap(err, "create unix socket file") } if err := os.Remove(sockP.Name()); err != nil { return nil, err } listener, err := net.Listen("unix", sockP.Name()) if err != nil { return nil, errors.Wrap(err, "listen unix socket when setup content store proxy") } server := &http.Server{ Handler: contentProxyHandler(ra), } go func() { if err := server.Serve(listener); err != nil && err != http.ErrServerClosed { logrus.WithError(err).Warn("serve content store proxy") } }() return &contentStoreProxy{ socketPath: sockP.Name(), server: server, }, nil } func (p *contentStoreProxy) close() error { defer os.Remove(p.socketPath) if err := p.server.Shutdown(context.Background()); err != nil { return errors.Wrap(err, "shutdown content store proxy") } return nil } func parseRangeHeader(rangeStr string, totalLen int64) (start, wantedLen int64, err error) { rangeList := strings.Split(rangeStr, "-") start, err = strconv.ParseInt(rangeList[0], 10, 64) if err != nil { err = errors.Wrap(err, "parse range header") return } if len(rangeList) == 2 { var end int64 end, err = strconv.ParseInt(rangeList[1], 10, 64) if err != nil { err = errors.Wrap(err, "parse range header") return } wantedLen = end - start + 1 } else { wantedLen = totalLen - start } if start < 0 || start >= totalLen || wantedLen <= 0 { err = fmt.Errorf("invalid range header: %s", rangeStr) return } return } func contentProxyHandler(ra content.ReaderAt) http.Handler { var ( dataReader io.Reader curPos int64 tarHeader *tar.Header totalLen int64 ) resetReader := func() { // TODO: Handle error? _, _ = seekFile(ra, EntryBlob, func(reader io.Reader, hdr *tar.Header) error { dataReader, tarHeader = reader, hdr return nil }) curPos = 0 } resetReader() if tarHeader != nil { totalLen = tarHeader.Size } else { totalLen = ra.Size() } handler := func(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodHead: { w.Header().Set("Content-Length", strconv.FormatInt(totalLen, 10)) w.Header().Set("Content-Type", "application/octet-stream") return } case http.MethodGet: { start, wantedLen, err := parseRangeHeader(strings.TrimPrefix(r.Header.Get("Range"), "bytes="), totalLen) if err != nil { w.WriteHeader(http.StatusBadRequest) // TODO: Handle error? _, _ = w.Write([]byte(err.Error())) return } // we need to make sure that the dataReader is at the right position if start < curPos { resetReader() } if start > curPos { _, err = io.CopyN(io.Discard, dataReader, start-curPos) if err != nil { w.WriteHeader(http.StatusInternalServerError) // TODO: Handle error? _, _ = w.Write([]byte(err.Error())) return } curPos = start } // then, the curPos must be equal to start readLen, err := io.CopyN(w, dataReader, wantedLen) if err != nil && !errors.Is(err, io.EOF) { w.WriteHeader(http.StatusInternalServerError) // TODO: Handle error? _, _ = w.Write([]byte(err.Error())) return } curPos += readLen w.Header().Set("Content-Length", strconv.FormatInt(readLen, 10)) w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, start+readLen-1, totalLen)) w.Header().Set("Content-Type", "application/octet-stream") return } } } return http.HandlerFunc(handler) } nydus-snapshotter-0.13.4/pkg/converter/tool/000077500000000000000000000000001453374237200210705ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/converter/tool/builder.go000066400000000000000000000177531453374237200230620ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package tool import ( "context" "encoding/json" "fmt" "os" "os/exec" "strings" "time" "github.com/opencontainers/go-digest" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) var logger = logrus.WithField("module", "builder") func isSignalKilled(err error) bool { return strings.Contains(err.Error(), "signal: killed") } type PackOption struct { BuilderPath string BootstrapPath string BlobPath string FsVersion string SourcePath string ChunkDictPath string PrefetchPatterns string Compressor string OCIRef bool AlignedChunk bool ChunkSize string BatchSize string Encrypt bool Timeout *time.Duration Features Features } type MergeOption struct { BuilderPath string SourceBootstrapPaths []string RafsBlobDigests []string RafsBlobTOCDigests []string RafsBlobSizes []int64 TargetBootstrapPath string ChunkDictPath string ParentBootstrapPath string PrefetchPatterns string OutputJSONPath string Timeout *time.Duration } type UnpackOption struct { BuilderPath string BootstrapPath string BlobPath string BackendConfigPath string TarPath string Timeout *time.Duration } type outputJSON struct { Blobs []string } func buildPackArgs(option PackOption) []string { if option.FsVersion == "" { option.FsVersion = "6" } args := []string{ "create", "--log-level", "warn", "--prefetch-policy", "fs", "--blob", option.BlobPath, "--whiteout-spec", "none", "--fs-version", option.FsVersion, } if option.Features.Contains(FeatureTar2Rafs) { args = append( args, "--type", "tar-rafs", "--blob-inline-meta", ) if option.FsVersion == "6" { args = append( args, "--features", "blob-toc", ) } } else { args = append( args, "--source-type", "directory", // Sames with `--blob-inline-meta`, it's used for compatibility // with the old nydus-image builder. "--inline-bootstrap", ) } if option.ChunkDictPath != "" { args = append(args, "--chunk-dict", fmt.Sprintf("bootstrap=%s", option.ChunkDictPath)) } if option.PrefetchPatterns == "" { option.PrefetchPatterns = "/" } if option.Compressor != "" { args = append(args, "--compressor", option.Compressor) } if option.AlignedChunk { args = append(args, "--aligned-chunk") } if option.ChunkSize != "" { args = append(args, "--chunk-size", option.ChunkSize) } if option.Features.Contains(FeatureBatchSize) { args = append(args, "--batch-size", option.BatchSize) } if option.Encrypt { args = append(args, "--encrypt") } args = append(args, option.SourcePath) return args } func Pack(option PackOption) error { if option.OCIRef { return packRef(option) } ctx := context.Background() var cancel context.CancelFunc if option.Timeout != nil { ctx, cancel = context.WithTimeout(ctx, *option.Timeout) defer cancel() } args := buildPackArgs(option) logrus.Debugf("\tCommand: %s %s", option.BuilderPath, strings.Join(args, " ")) cmd := exec.CommandContext(ctx, option.BuilderPath, args...) cmd.Stdout = logger.Writer() cmd.Stderr = logger.Writer() cmd.Stdin = strings.NewReader(option.PrefetchPatterns) if err := cmd.Run(); err != nil { if isSignalKilled(err) && option.Timeout != nil { logrus.WithError(err).Errorf("fail to run %v %+v, possibly due to timeout %v", option.BuilderPath, args, *option.Timeout) } else { logrus.WithError(err).Errorf("fail to run %v %+v", option.BuilderPath, args) } return err } return nil } func packRef(option PackOption) error { args := []string{ "create", "--log-level", "warn", "--type", "targz-ref", "--blob-inline-meta", "--features", "blob-toc", "--blob", option.BlobPath, } args = append(args, option.SourcePath) ctx := context.Background() var cancel context.CancelFunc if option.Timeout != nil { ctx, cancel = context.WithTimeout(ctx, *option.Timeout) defer cancel() } logrus.Debugf("\tCommand: %s %s", option.BuilderPath, strings.Join(args, " ")) cmd := exec.CommandContext(ctx, option.BuilderPath, args...) cmd.Stdout = logger.Writer() cmd.Stderr = logger.Writer() if err := cmd.Run(); err != nil { if isSignalKilled(err) && option.Timeout != nil { logrus.WithError(err).Errorf("fail to run %v %+v, possibly due to timeout %v", option.BuilderPath, args, *option.Timeout) } else { logrus.WithError(err).Errorf("fail to run %v %+v", option.BuilderPath, args) } return err } return nil } func Merge(option MergeOption) ([]digest.Digest, error) { args := []string{ "merge", "--log-level", "warn", "--prefetch-policy", "fs", "--output-json", option.OutputJSONPath, "--bootstrap", option.TargetBootstrapPath, } if option.ChunkDictPath != "" { args = append(args, "--chunk-dict", fmt.Sprintf("bootstrap=%s", option.ChunkDictPath)) } if option.ParentBootstrapPath != "" { args = append(args, "--parent-bootstrap", option.ParentBootstrapPath) } if option.PrefetchPatterns == "" { option.PrefetchPatterns = "/" } args = append(args, option.SourceBootstrapPaths...) if len(option.RafsBlobDigests) > 0 { args = append(args, "--blob-digests", strings.Join(option.RafsBlobDigests, ",")) } if len(option.RafsBlobTOCDigests) > 0 { args = append(args, "--blob-toc-digests", strings.Join(option.RafsBlobTOCDigests, ",")) } if len(option.RafsBlobSizes) > 0 { sizes := []string{} for _, size := range option.RafsBlobSizes { sizes = append(sizes, fmt.Sprintf("%d", size)) } args = append(args, "--blob-sizes", strings.Join(sizes, ",")) } ctx := context.Background() var cancel context.CancelFunc if option.Timeout != nil { ctx, cancel = context.WithTimeout(ctx, *option.Timeout) defer cancel() } logrus.Debugf("\tCommand: %s %s", option.BuilderPath, strings.Join(args, " ")) cmd := exec.CommandContext(ctx, option.BuilderPath, args...) cmd.Stdout = logger.Writer() cmd.Stderr = logger.Writer() cmd.Stdin = strings.NewReader(option.PrefetchPatterns) if err := cmd.Run(); err != nil { if isSignalKilled(err) && option.Timeout != nil { logrus.WithError(err).Errorf("fail to run %v %+v, possibly due to timeout %v", option.BuilderPath, args, *option.Timeout) } else { logrus.WithError(err).Errorf("fail to run %v %+v", option.BuilderPath, args) } return nil, errors.Wrap(err, "run merge command") } outputBytes, err := os.ReadFile(option.OutputJSONPath) if err != nil { return nil, errors.Wrapf(err, "read file %s", option.OutputJSONPath) } var output outputJSON err = json.Unmarshal(outputBytes, &output) if err != nil { return nil, errors.Wrapf(err, "unmarshal output json file %s", option.OutputJSONPath) } blobDigests := []digest.Digest{} for _, blobID := range output.Blobs { blobDigests = append(blobDigests, digest.NewDigestFromHex(string(digest.SHA256), blobID)) } return blobDigests, nil } func Unpack(option UnpackOption) error { args := []string{ "unpack", "--log-level", "warn", "--bootstrap", option.BootstrapPath, "--output", option.TarPath, } if option.BackendConfigPath != "" { args = append(args, "--backend-config", option.BackendConfigPath) } else if option.BlobPath != "" { args = append(args, "--blob", option.BlobPath) } ctx := context.Background() var cancel context.CancelFunc if option.Timeout != nil { ctx, cancel = context.WithTimeout(ctx, *option.Timeout) defer cancel() } logrus.Debugf("\tCommand: %s %s", option.BuilderPath, strings.Join(args, " ")) cmd := exec.CommandContext(ctx, option.BuilderPath, args...) cmd.Stdout = logger.Writer() cmd.Stderr = logger.Writer() if err := cmd.Run(); err != nil { if isSignalKilled(err) && option.Timeout != nil { logrus.WithError(err).Errorf("fail to run %v %+v, possibly due to timeout %v", option.BuilderPath, args, *option.Timeout) } else { logrus.WithError(err).Errorf("fail to run %v %+v", option.BuilderPath, args) } return err } return nil } nydus-snapshotter-0.13.4/pkg/converter/tool/feature.go000066400000000000000000000074121453374237200230560ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package tool import ( "context" "fmt" "os" "os/exec" "strings" "sync" "github.com/sirupsen/logrus" ) type Feature string type Features map[Feature]struct{} const envNydusDisableTar2Rafs string = "NYDUS_DISABLE_TAR2RAFS" const ( // The option `--type tar-rafs` enables converting OCI tar blob // stream into nydus blob directly, the tar2rafs eliminates the // need to decompress it to a local directory first, thus greatly // accelerating the pack process. FeatureTar2Rafs Feature = "--type tar-rafs" // The option `--batch-size` enables merging multiple small chunks // into a big batch chunk, which can reduce the the size of the image // and accelerate the runtime file loading. FeatureBatchSize Feature = "--batch-size" // The option `--encrypt` enables converting directories, tar files // or OCI images into encrypted nydus blob. FeatureEncrypt Feature = "--encrypt" ) var requiredFeatures Features var detectedFeatures Features var detectFeaturesOnce sync.Once var disableTar2Rafs = os.Getenv(envNydusDisableTar2Rafs) != "" func NewFeatures(items ...Feature) Features { features := Features{} features.Add(items...) return features } func (features *Features) Add(items ...Feature) { for _, item := range items { (*features)[item] = struct{}{} } } func (features *Features) Remove(items ...Feature) { for _, item := range items { delete(*features, item) } } func (features *Features) Contains(feature Feature) bool { _, ok := (*features)[feature] return ok } func (features *Features) Equals(other Features) bool { if len(*features) != len(other) { return false } for f := range *features { if !other.Contains(f) { return false } } return true } // GetHelp returns the help message of `nydus-image create`. func GetHelp(builder string) []byte { cmd := exec.CommandContext(context.Background(), builder, "create", "-h") output, err := cmd.Output() if err != nil { return nil } return output } // detectFeature returns true if the feature is detected in the help message. func detectFeature(msg []byte, feature Feature) bool { if feature == "" { return false } if strings.Contains(string(msg), string(feature)) { return true } if parts := strings.Split(string(feature), " "); len(parts) == 2 { // Check each part of the feature. // e.g., "--type tar-rafs" -> ["--type", "tar-rafs"] if strings.Contains(string(msg), parts[0]) && strings.Contains(string(msg), parts[1]) { return true } } return false } // DetectFeatures returns supported feature list from required feature list. // The supported feature list is detected from the help message of `nydus-image create`. func DetectFeatures(builder string, required Features, getHelp func(string) []byte) (Features, error) { detectFeaturesOnce.Do(func() { requiredFeatures = required detectedFeatures = Features{} helpMsg := getHelp(builder) for feature := range required { // The feature is supported by current version of nydus-image. supported := detectFeature(helpMsg, feature) if supported { // It is an experimental feature, so we still provide an env // variable to allow users to disable it. if feature == FeatureTar2Rafs && disableTar2Rafs { logrus.Warnf("the feature '%s' is disabled by env '%s'", FeatureTar2Rafs, envNydusDisableTar2Rafs) continue } detectedFeatures.Add(feature) } else { logrus.Warnf("the feature '%s' is ignored, it requires higher version of nydus-image", feature) } } }) // Return Error if required features changed in different calls. if !requiredFeatures.Equals(required) { return nil, fmt.Errorf("features changed: %v -> %v", requiredFeatures, required) } return detectedFeatures, nil } nydus-snapshotter-0.13.4/pkg/converter/tool/feature_test.go000066400000000000000000001000711453374237200241100ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package tool import ( "sync" "testing" "github.com/stretchr/testify/require" ) func TestFeature(t *testing.T) { testsAdd := []struct { name string features Features items []Feature expect Features }{ { name: "should successfully add items", features: Features{FeatureBatchSize: {}}, items: []Feature{FeatureTar2Rafs}, expect: Features{FeatureTar2Rafs: {}, FeatureBatchSize: {}}, }, { name: "should add nothing if duplicated", features: Features{FeatureBatchSize: {}}, items: []Feature{FeatureBatchSize}, expect: Features{FeatureBatchSize: {}}, }, { name: "add should accept nil", features: Features{FeatureBatchSize: {}}, items: nil, expect: Features{FeatureBatchSize: {}}, }, } for _, tt := range testsAdd { t.Run(tt.name, func(t *testing.T) { tt.features.Add(tt.items...) require.Equal(t, tt.expect, tt.features) }) } testsNew := []struct { name string items []Feature expect Features }{ { name: "should successfully new Features", items: []Feature{FeatureTar2Rafs, FeatureBatchSize}, expect: Features{FeatureTar2Rafs: {}, FeatureBatchSize: {}}, }, { name: "should duplicate same items", items: []Feature{FeatureBatchSize, FeatureBatchSize}, expect: Features{FeatureBatchSize: {}}, }, { name: "New should accept nil", items: nil, expect: Features{}, }, } for _, tt := range testsNew { t.Run(tt.name, func(t *testing.T) { features := NewFeatures(tt.items...) require.Equal(t, tt.expect, features) }) } testsRemove := []struct { name string features Features items []Feature expect Features }{ { name: "should successfully remove items", features: Features{FeatureBatchSize: {}, FeatureTar2Rafs: {}}, items: []Feature{FeatureTar2Rafs}, expect: Features{FeatureBatchSize: {}}, }, { name: "should remove item iff exists", features: Features{FeatureBatchSize: {}}, items: []Feature{FeatureBatchSize, FeatureTar2Rafs}, expect: Features{}, }, { name: "Remove should accept nil", features: Features{FeatureBatchSize: {}}, items: nil, expect: Features{FeatureBatchSize: {}}, }, } for _, tt := range testsRemove { t.Run(tt.name, func(t *testing.T) { tt.features.Remove(tt.items...) require.Equal(t, tt.expect, tt.features) }) } testsContains := []struct { name string features Features item Feature expect bool }{ { name: "should return contains", features: Features{FeatureBatchSize: {}, FeatureTar2Rafs: {}}, item: FeatureTar2Rafs, expect: true, }, { name: "should return not contains", features: Features{FeatureBatchSize: {}}, item: FeatureTar2Rafs, expect: false, }, { name: "Contains should accept empty string", features: Features{FeatureBatchSize: {}}, item: "", expect: false, }, } for _, tt := range testsContains { t.Run(tt.name, func(t *testing.T) { require.Equal(t, tt.expect, tt.features.Contains(tt.item)) }) } testsEquals := []struct { name string features Features other Features expect bool }{ { name: "should successfully check equality", features: Features{FeatureBatchSize: {}, FeatureTar2Rafs: {}}, other: Features{FeatureBatchSize: {}, FeatureTar2Rafs: {}}, expect: true, }, { name: "should successfully check inequality with different length", features: Features{FeatureBatchSize: {}, FeatureTar2Rafs: {}}, other: Features{FeatureBatchSize: {}}, expect: false, }, { name: "should successfully check inequality with different items", features: Features{FeatureTar2Rafs: {}}, other: Features{FeatureBatchSize: {}}, expect: false, }, { name: "should ignore order", features: Features{FeatureBatchSize: {}, FeatureTar2Rafs: {}}, other: Features{FeatureTar2Rafs: {}, FeatureBatchSize: {}}, expect: true, }, { name: "Equals should accept nil", features: Features{FeatureBatchSize: {}}, other: nil, expect: false, }, } for _, tt := range testsEquals { t.Run(tt.name, func(t *testing.T) { require.Equal(t, tt.expect, tt.features.Equals(tt.other)) }) } } func TestDetectFeature(t *testing.T) { tests := []struct { name string feature Feature helpMsg []byte expect bool }{ { name: "'--type tar-rafs' is supported in v2.2.0-239-gf5c08fcf", feature: FeatureTar2Rafs, expect: true, helpMsg: []byte(` Create RAFS filesystems from directories, tar files or OCI images Usage: nydus-image create [OPTIONS] Arguments: source from which to build the RAFS filesystem Options: -L, --log-file Log file path -t, --type Conversion type: [default: dir-rafs] [possible values: directory, dir-rafs, estargz-rafs, estargz-ref, estargztoc-ref, tar-rafs, tar-tarfs, targz-rafs, targz-ref, stargz_index] -B, --bootstrap File path to save the generated RAFS metadata blob -l, --log-level Log level: [default: info] [possible values: trace, debug, info, warn, error] -D, --blob-dir Directory path to save generated RAFS metadata and data blobs -b, --blob File path to save the generated RAFS data blob --blob-inline-meta Inline RAFS metadata and blob metadata into the data blob --blob-id OSS object id for the generated RAFS data blob --blob-data-size Set data blob size for 'estargztoc-ref' conversion --chunk-size Set the size of data chunks, must be power of two and between 0x1000-0x1000000: --batch-size Set the batch size to merge small chunks, must be power of two, between 0x1000-0x1000000 or be zero: [default: 0] --compressor Algorithm to compress data chunks: [default: zstd] [possible values: none, lz4_block, zstd] --digester Algorithm to digest data chunks: [default: blake3] [possible values: blake3, sha256] -C, --config Configuration file for storage backend, cache and RAFS FUSE filesystem. -v, --fs-version Set RAFS format version number: [default: 6] [possible values: 5, 6] --features Enable/disable features [possible values: blob-toc] --chunk-dict File path of chunk dictionary for data deduplication --parent-bootstrap File path of the parent/referenced RAFS metadata blob (optional) --aligned-chunk Align uncompressed data chunks to 4K, only for RAFS V5 --repeatable Generate reproducible RAFS metadata --whiteout-spec Set the type of whiteout specification: [default: oci] [possible values: oci, overlayfs, none] --prefetch-policy Set data prefetch policy [default: none] [possible values: fs, blob, none] -J, --output-json File path to save operation result in JSON format -h, --help Print help information `), }, { name: "'--batch-size' is supported in v2.2.0-239-gf5c08fcf", feature: FeatureBatchSize, expect: true, helpMsg: []byte(` Create RAFS filesystems from directories, tar files or OCI images Usage: nydus-image create [OPTIONS] Arguments: source from which to build the RAFS filesystem Options: -L, --log-file Log file path -t, --type Conversion type: [default: dir-rafs] [possible values: directory, dir-rafs, estargz-rafs, estargz-ref, estargztoc-ref, tar-rafs, tar-tarfs, targz-rafs, targz-ref, stargz_index] -B, --bootstrap File path to save the generated RAFS metadata blob -l, --log-level Log level: [default: info] [possible values: trace, debug, info, warn, error] -D, --blob-dir Directory path to save generated RAFS metadata and data blobs -b, --blob File path to save the generated RAFS data blob --blob-inline-meta Inline RAFS metadata and blob metadata into the data blob --blob-id OSS object id for the generated RAFS data blob --blob-data-size Set data blob size for 'estargztoc-ref' conversion --chunk-size Set the size of data chunks, must be power of two and between 0x1000-0x1000000: --batch-size Set the batch size to merge small chunks, must be power of two, between 0x1000-0x1000000 or be zero: [default: 0] --compressor Algorithm to compress data chunks: [default: zstd] [possible values: none, lz4_block, zstd] --digester Algorithm to digest data chunks: [default: blake3] [possible values: blake3, sha256] -C, --config Configuration file for storage backend, cache and RAFS FUSE filesystem. -v, --fs-version Set RAFS format version number: [default: 6] [possible values: 5, 6] --features Enable/disable features [possible values: blob-toc] --chunk-dict File path of chunk dictionary for data deduplication --parent-bootstrap File path of the parent/referenced RAFS metadata blob (optional) --aligned-chunk Align uncompressed data chunks to 4K, only for RAFS V5 --repeatable Generate reproducible RAFS metadata --whiteout-spec Set the type of whiteout specification: [default: oci] [possible values: oci, overlayfs, none] --prefetch-policy Set data prefetch policy [default: none] [possible values: fs, blob, none] -J, --output-json File path to save operation result in JSON format -h, --help Print help information `), }, { name: "'--batch-size' is not supported in v2.2.0-163-g180f6d2c", feature: FeatureBatchSize, expect: false, helpMsg: []byte(` Create RAFS filesystems from directories, tar files or OCI images Usage: nydus-image create [OPTIONS] Arguments: source from which to build the RAFS filesystem Options: -L, --log-file Log file path -t, --type Conversion type: [default: dir-rafs] [possible values: directory, dir-rafs, estargz-rafs, estargz-ref, estargztoc-ref, tar-rafs, tar-tarfs, targz-rafs, targz-ref, stargz_index] -B, --bootstrap File path to save the generated RAFS metadata blob -l, --log-level Log level: [default: info] [possible values: trace, debug, info, warn, error] -D, --blob-dir Directory path to save generated RAFS metadata and data blobs -b, --blob File path to save the generated RAFS data blob --blob-inline-meta Inline RAFS metadata and blob metadata into the data blob --blob-id OSS object id for the generated RAFS data blob --blob-data-size Set data blob size for 'estargztoc-ref' conversion --chunk-size Set the size of data chunks, must be power of two and between 0x1000-0x1000000: --compressor Algorithm to compress data chunks: [default: zstd] [possible values: none, lz4_block, zstd] --digester Algorithm to digest data chunks: [default: blake3] [possible values: blake3, sha256] -C, --config Configuration file for storage backend, cache and RAFS FUSE filesystem. -v, --fs-version Set RAFS format version number: [default: 6] [possible values: 5, 6] --features Enable/disable features [possible values: blob-toc] --chunk-dict File path of chunk dictionary for data deduplication --parent-bootstrap File path of the parent/referenced RAFS metadata blob (optional) --aligned-chunk Align uncompressed data chunks to 4K, only for RAFS V5 --repeatable Generate reproducible RAFS metadata --whiteout-spec Set the type of whiteout specification: [default: oci] [possible values: oci, overlayfs, none] --prefetch-policy Set data prefetch policy [default: none] [possible values: fs, blob, none] -J, --output-json File path to save operation result in JSON format -h, --help Print help information `), }, { name: "'--encrypt' is supported in v2.2.0-261-g22ad0e2c", feature: FeatureEncrypt, expect: true, helpMsg: []byte(` Create RAFS filesystems from directories, tar files or OCI images Usage: nydus-image create [OPTIONS] Arguments: source from which to build the RAFS filesystem Options: -L, --log-file Log file path -t, --type Conversion type: [default: dir-rafs] [possible values: directory, dir-rafs, estargz-rafs, estargz-ref, estargztoc-ref, tar-rafs, tar-tarfs, targz-rafs, targz-ref, stargz_index] -B, --bootstrap File path to save the generated RAFS metadata blob -l, --log-level Log level: [default: info] [possible values: trace, debug, info, warn, error] -D, --blob-dir Directory path to save generated RAFS metadata and data blobs -b, --blob File path to save the generated RAFS data blob --blob-inline-meta Inline RAFS metadata and blob metadata into the data blob --blob-id OSS object id for the generated RAFS data blob --blob-data-size Set data blob size for 'estargztoc-ref' conversion --chunk-size Set the size of data chunks, must be power of two and between 0x1000-0x1000000: --batch-size Set the batch size to merge small chunks, must be power of two, between 0x1000-0x1000000 or be zero: [default: 0] --compressor Algorithm to compress data chunks: [default: zstd] [possible values: none, lz4_block, zstd] --digester Algorithm to digest data chunks: [default: blake3] [possible values: blake3, sha256] -C, --config Configuration file for storage backend, cache and RAFS FUSE filesystem. -v, --fs-version Set RAFS format version number: [default: 6] [possible values: 5, 6] --features Enable/disable features [possible values: blob-toc] --chunk-dict File path of chunk dictionary for data deduplication --parent-bootstrap File path of the parent/referenced RAFS metadata blob (optional) --aligned-chunk Align uncompressed data chunks to 4K, only for RAFS V5 --repeatable Generate reproducible RAFS metadata --whiteout-spec Set the type of whiteout specification: [default: oci] [possible values: oci, overlayfs, none] --prefetch-policy Set data prefetch policy [default: none] [possible values: fs, blob, none] -J, --output-json File path to save operation result in JSON format -E, --encrypt Encrypt the generated RAFS metadata and data blobs -h, --help Print help information `), }, { name: "'--type tar-rafs' is not supported in v2.1.4", feature: FeatureTar2Rafs, expect: false, helpMsg: []byte(` nydus-image-create Creates a nydus image from source USAGE: nydus-image create [FLAGS] [OPTIONS] ... --blob --bootstrap --fs-version --whiteout-spec FLAGS: -A, --aligned-chunk Align data chunks to 4K --disable-check disable validation of metadata after building -h, --help Prints help information --inline-bootstrap append bootstrap data to blob -R, --repeatable generate reproducible nydus image -V, --version Prints version information OPTIONS: --backend-config [deprecated!] Blob storage backend config - JSON string, only support localfs for compatibility --backend-type [deprecated!] Blob storage backend type, only support localfs for compatibility. Try use --blob instead. [possible values: localfs] -b, --blob path to store nydus image's data blob -D, --blob-dir directory to store nydus image's metadata and data blob --blob-id blob id (as object id in backend/oss) --blob-meta path to store nydus blob metadata --blob-offset add an offset for compressed blob (is only used to put the blob in the tarball) [default: 0] -B, --bootstrap path to store the nydus image's metadata blob -M, --chunk-dict Specify a chunk dictionary for chunk deduplication -S, --chunk-size size of nydus image data chunk, must be power of two and between 0x1000-0x100000: [default: 0x100000] -c, --compressor algorithm to compress image data blob: [default: lz4_block] [possible values: none, lz4_block, gzip, zstd] -d, --digester algorithm to digest inodes and data chunks: [default: blake3] [possible values: blake3, sha256] -v, --fs-version version number of nydus image format: [default: 5] [possible values: 5, 6] -o, --log-file Specify log file name -l, --log-level Specify log level: [default: info] [possible values: trace, debug, info, warn, error] -J, --output-json JSON file output path for result -p, --parent-bootstrap path to parent/referenced image's metadata blob (optional) -P, --prefetch-policy blob data prefetch policy [default: none] [possible values: fs, blob, none] -t, --source-type type of the source: [default: directory] [possible values: directory, stargz_index] -W, --whiteout-spec type of whiteout specification: [default: oci] [possible values: oci, overlayfs, none] ARGS: ... source path to build the nydus image from `), }, { name: "'--batch-size' is not supported in v1.1.2", feature: FeatureBatchSize, expect: false, helpMsg: []byte(` nydus-image-create Create a nydus format accelerated container image USAGE: nydus-image create [FLAGS] [OPTIONS] --blob --bootstrap --whiteout-spec FLAGS: --aligned-chunk Whether to align chunks into blobcache --disable-check Disable to validate bootstrap file after building -h, --help Prints help information --repeatable Produce environment independent image -V, --version Prints version information OPTIONS: --backend-config [deprecated!] Blob storage backend config - JSON string, only support localfs for compatibility --backend-type [deprecated!] Blob storage backend type, only support localfs for compatibility. Try use --blob instead. [possible values: localfs] --blob A path to blob file which stores nydus image data portion --blob-dir A directory where blob files are saved named as their sha256 digest. It's very useful when multiple layers are built at the same time. --blob-id blob id (as object id in backend/oss) --bootstrap A path to bootstrap file which stores nydus image metadata portion --chunk-dict specify a chunk dictionary file in bootstrap/db format for chunk deduplication. --compressor how blob will be compressed: none, lz4_block (default) [default: lz4_block] --digester how inode and blob chunk will be digested: blake3 (default), sha256 [default: blake3] --log-level Specify log level: trace, debug, info, warn, error [default: info] [possible values: trace, debug, info, warn, error] --output-json JSON output path for build result --parent-bootstrap bootstrap file path of parent (optional) --prefetch-policy Prefetch policy: fs(issued from Fs layer), blob(issued from backend/blob layer), none(no readahead is needed) [default: none] --source-type source type [default: directory] [possible values: directory, stargz_index] --whiteout-spec decide which whiteout spec to follow: "oci" or "overlayfs" [default: oci] [possible values: oci, overlayfs] ARGS: source path `), }, { name: "'--type tar-rafs' is not supported in v0.1.0", feature: FeatureTar2Rafs, expect: false, helpMsg: []byte(` nydus-image-create dump image bootstrap and upload blob to storage backend USAGE: nydus-image create [FLAGS] [OPTIONS] --bootstrap --whiteout-spec FLAGS: --aligned-chunk Whether to align chunks into blobcache --disable-check Disable to validate bootstrap file after building -h, --help Prints help information --repeatable Produce environment independent image -V, --version Prints version information OPTIONS: --backend-config blob storage backend config (JSON string) --backend-config-file blob storage backend config (JSON file) --backend-type blob storage backend type (enable blob upload if specified) --blob blob file path --blob-id blob id (as object id in backend) --bootstrap bootstrap file path (required) --compressor how blob will be compressed: none, lz4_block (default) [default: lz4_block] --digester how inode and blob chunk will be digested: blake3 (default), sha256 [default: blake3] --log-level Specify log level: trace, debug, info, warn, error [default: info] [possible values: trace, debug, info, warn, error] --output-json JSON output path for build result --parent-bootstrap bootstrap file path of parent (optional) --prefetch-policy Prefetch policy: fs(issued from Fs layer), blob(issued from backend/blob layer), none(no readahead is needed) [default: none] --source-type source type [default: directory] [possible values: directory, stargz_index] --whiteout-spec decide which whiteout spec to follow: "oci" or "overlayfs" [default: oci] [possible values: oci, overlayfs] ARGS: source path `), }, { name: "'--encrypt' is not supported in v2.2.0", feature: FeatureEncrypt, expect: false, helpMsg: []byte(` Create RAFS filesystems from directories, tar files or OCI images Usage: nydus-image create [OPTIONS] Arguments: source from which to build the RAFS filesystem Options: -L, --log-file Log file path -t, --type Conversion type: [default: dir-rafs] [possible values: directory, dir-rafs, estargz-rafs, estargz-ref, estargztoc-ref, tar-rafs, tar-tarfs, targz-rafs, targz-ref, stargz_index] -B, --bootstrap File path to save the generated RAFS metadata blob -l, --log-level Log level: [default: info] [possible values: trace, debug, info, warn, error] -D, --blob-dir Directory path to save generated RAFS metadata and data blobs -b, --blob File path to save the generated RAFS data blob --blob-inline-meta Inline RAFS metadata and blob metadata into the data blob --blob-id OSS object id for the generated RAFS data blob --blob-data-size Set data blob size for 'estargztoc-ref' conversion --chunk-size Set the size of data chunks, must be power of two and between 0x1000-0x1000000: --batch-size Set the batch size to merge small chunks, must be power of two, between 0x1000-0x1000000 or be zero: [default: 0] --compressor Algorithm to compress data chunks: [default: zstd] [possible values: none, lz4_block, zstd] --digester Algorithm to digest data chunks: [default: blake3] [possible values: blake3, sha256] -C, --config Configuration file for storage backend, cache and RAFS FUSE filesystem. -v, --fs-version Set RAFS format version number: [default: 6] [possible values: 5, 6] --features Enable/disable features [possible values: blob-toc] --chunk-dict File path of chunk dictionary for data deduplication --parent-bootstrap File path of the parent/referenced RAFS metadata blob (optional) --aligned-chunk Align uncompressed data chunks to 4K, only for RAFS V5 --repeatable Generate reproducible RAFS metadata --whiteout-spec Set the type of whiteout specification: [default: oci] [possible values: oci, overlayfs, none] --prefetch-policy Set data prefetch policy [default: none] [possible values: fs, blob, none] -J, --output-json File path to save operation result in JSON format -h, --help Print help information `), }, { name: "detectFeature should support empty input", feature: "", expect: false, helpMsg: []byte(` OPTIONS: --type [deprecated!] Conversion type. [possible values: tar-rafs] `), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { require.Equal(t, tt.expect, detectFeature(tt.helpMsg, tt.feature)) }) } } func TestDetectFeatures(t *testing.T) { testsCompare := []struct { name string resetGlobal bool disableTar2Rafs bool helpText []byte required Features detected Features expectErr bool }{ { name: "should satisfy required features in v2.2.0-239-gf5c08fcf", resetGlobal: true, disableTar2Rafs: false, helpText: []byte(` Options: -t, --type Conversion type: [default: dir-rafs] [possible values: directory, dir-rafs, estargz-rafs, estargz-ref, estargztoc-ref, tar-rafs, tar-tarfs, targz-rafs, targz-ref, stargz_index] --batch-size Set the batch size to merge small chunks, must be power of two, between 0x1000-0x1000000 or be zero: [default: 0] `), required: Features{FeatureTar2Rafs: {}, FeatureBatchSize: {}}, detected: Features{FeatureTar2Rafs: {}, FeatureBatchSize: {}}, expectErr: false, }, { name: "should not support '--encrypt', '--batch-size' or '--type tar-rafs' in v2.1.4", resetGlobal: true, disableTar2Rafs: true, helpText: []byte(` nydus-image-create Creates a nydus image from source USAGE: nydus-image create [FLAGS] [OPTIONS] ... --blob --bootstrap --fs-version --whiteout-spec FLAGS: -A, --aligned-chunk Align data chunks to 4K --disable-check disable validation of metadata after building -h, --help Prints help information --inline-bootstrap append bootstrap data to blob -R, --repeatable generate reproducible nydus image -V, --version Prints version information OPTIONS: --backend-config [deprecated!] Blob storage backend config - JSON string, only support localfs for compatibility --backend-type [deprecated!] Blob storage backend type, only support localfs for compatibility. Try use --blob instead. [possible values: localfs] -b, --blob path to store nydus image's data blob -D, --blob-dir directory to store nydus image's metadata and data blob --blob-id blob id (as object id in backend/oss) --blob-meta path to store nydus blob metadata --blob-offset add an offset for compressed blob (is only used to put the blob in the tarball) [default: 0] -B, --bootstrap path to store the nydus image's metadata blob -M, --chunk-dict Specify a chunk dictionary for chunk deduplication -S, --chunk-size size of nydus image data chunk, must be power of two and between 0x1000-0x100000: [default: 0x100000] -c, --compressor algorithm to compress image data blob: [default: lz4_block] [possible values: none, lz4_block, gzip, zstd] -d, --digester algorithm to digest inodes and data chunks: [default: blake3] [possible values: blake3, sha256] -v, --fs-version version number of nydus image format: [default: 5] [possible values: 5, 6] -o, --log-file Specify log file name -l, --log-level Specify log level: [default: info] [possible values: trace, debug, info, warn, error] -J, --output-json JSON file output path for result -p, --parent-bootstrap path to parent/referenced image's metadata blob (optional) -P, --prefetch-policy blob data prefetch policy [default: none] [possible values: fs, blob, none] -t, --source-type type of the source: [default: directory] [possible values: directory, stargz_index] -W, --whiteout-spec type of whiteout specification: [default: oci] [possible values: oci, overlayfs, none] ARGS: ... source path to build the nydus image from `), required: Features{FeatureTar2Rafs: {}, FeatureBatchSize: {}, FeatureEncrypt: {}}, detected: Features{}, expectErr: false, }, { name: "should ignore '--type tar-rafs' if disabled", resetGlobal: true, disableTar2Rafs: true, helpText: []byte(` Options: -t, --type Conversion type: [default: dir-rafs] [possible values: directory, dir-rafs, estargz-rafs, estargz-ref, estargztoc-ref, tar-rafs, tar-tarfs, targz-rafs, targz-ref, stargz_index] --batch-size Set the batch size to merge small chunks, must be power of two, between 0x1000-0x1000000 or be zero: [default: 0] `), required: Features{FeatureTar2Rafs: {}, FeatureBatchSize: {}}, detected: Features{FeatureBatchSize: {}}, expectErr: false, }, { name: "should return error if required features changed in different calls", resetGlobal: false, disableTar2Rafs: false, helpText: nil, required: Features{}, detected: nil, expectErr: true, }, } for _, tt := range testsCompare { t.Run(tt.name, func(t *testing.T) { if tt.resetGlobal { // Reset global variables. requiredFeatures = Features{} detectedFeatures = Features{} detectFeaturesOnce = sync.Once{} disableTar2Rafs = tt.disableTar2Rafs } detected, err := DetectFeatures("", tt.required, func(_ string) []byte { return tt.helpText }) require.Equal(t, tt.expectErr, err != nil) require.Equal(t, tt.detected, detected) }) } } nydus-snapshotter-0.13.4/pkg/converter/types.go000066400000000000000000000143021453374237200216060ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package converter import ( "context" "errors" "fmt" "strings" "time" "github.com/containerd/containerd/content" "github.com/containerd/nydus-snapshotter/pkg/converter/tool" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) type Compressor = uint32 type Encrypter = func(context.Context, content.Store, ocispec.Descriptor) (ocispec.Descriptor, error) const ( CompressorNone Compressor = 0x0000_0001 CompressorZstd Compressor = 0x0000_0002 CompressorLz4Block Compressor = 0x0000_0004 CompressorMask Compressor = 0x0000_000f ) var ( ErrNotFound = errors.New("data not found") ) type Layer struct { // Digest represents the hash of whole tar blob. Digest digest.Digest // Digest represents the original OCI tar(.gz) blob. OriginalDigest *digest.Digest // ReaderAt holds the reader of whole tar blob. ReaderAt content.ReaderAt } // Backend uploads blobs generated by nydus-image builder to a backend storage. type Backend interface { // Push pushes specified blob file to remote storage backend. Push(ctx context.Context, cs content.Store, desc ocispec.Descriptor) error // Check checks whether a blob exists in remote storage backend, // blob exists -> return (blobPath, nil) // blob not exists -> return ("", err) Check(blobDigest digest.Digest) (string, error) // Type returns backend type name. Type() string } type PackOption struct { // WorkDir is used as the work directory during layer pack. WorkDir string // BuilderPath holds the path of `nydus-image` binary tool. BuilderPath string // FsVersion specifies nydus RAFS format version, possible // values: `5`, `6` (EROFS-compatible), default is `6`. FsVersion string // ChunkDictPath holds the bootstrap path of chunk dict image. ChunkDictPath string // PrefetchPatterns holds file path pattern list want to prefetch. PrefetchPatterns string // Compressor specifies nydus blob compression algorithm. Compressor string // OCIRef enables converting OCI tar(.gz) blob to nydus referenced blob. OCIRef bool // AlignedChunk aligns uncompressed data chunks to 4K, only for RAFS V5. AlignedChunk bool // ChunkSize sets the size of data chunks, must be power of two and between 0x1000-0x1000000. ChunkSize string // BacthSize sets the size of batch data chunks, must be power of two and between 0x1000-0x1000000 or zero. BatchSize string // Backend uploads blobs generated by nydus-image builder to a backend storage. Backend Backend // Timeout cancels execution once exceed the specified time. Timeout *time.Duration // Whether the generated Nydus blobs should be encrypted. Encrypt bool // Features keeps a feature list supported by newer version of builder, // It is detected automatically, so don't export it. features tool.Features } type MergeOption struct { // WorkDir is used as the work directory during layer merge. WorkDir string // BuilderPath holds the path of `nydus-image` binary tool. BuilderPath string // FsVersion specifies nydus RAFS format version, possible // values: `5`, `6` (EROFS-compatible), default is `6`. FsVersion string // ChunkDictPath holds the bootstrap path of chunk dict image. ChunkDictPath string // ParentBootstrapPath holds the bootstrap path of parent image. ParentBootstrapPath string // PrefetchPatterns holds file path pattern list want to prefetch. PrefetchPatterns string // WithTar puts bootstrap into a tar stream (no gzip). WithTar bool // OCI converts docker media types to OCI media types. OCI bool // OCIRef enables converting OCI tar(.gz) blob to nydus referenced blob. OCIRef bool // WithReferrer associates a reference to the original OCI manifest. // See the `subject` field description in // https://github.com/opencontainers/image-spec/blob/main/manifest.md#image-manifest-property-descriptions // // With this association, we can track all nydus images associated with // an OCI image. For example, in Harbor we can cascade to show nydus // images linked to an OCI image, deleting the OCI image can also delete // the corresponding nydus images. At runtime, nydus snapshotter can also // automatically upgrade an OCI image run to nydus image. WithReferrer bool // Backend uploads blobs generated by nydus-image builder to a backend storage. Backend Backend // Timeout cancels execution once exceed the specified time. Timeout *time.Duration // Encrypt encrypts the bootstrap layer if it's specified. Encrypt Encrypter } type UnpackOption struct { // WorkDir is used as the work directory during layer unpack. WorkDir string // BuilderPath holds the path of `nydus-image` binary tool. BuilderPath string // Timeout cancels execution once exceed the specified time. Timeout *time.Duration // Stream enables streaming mode, which doesn't unpack the blob data to disk, // but setup a http server to serve the blob data. Stream bool } type TOCEntry struct { // Feature flags of entry Flags uint32 Reserved1 uint32 // Name of entry data Name [16]byte // Sha256 of uncompressed entry data UncompressedDigest [32]byte // Offset of compressed entry data CompressedOffset uint64 // Size of compressed entry data CompressedSize uint64 // Size of uncompressed entry data UncompressedSize uint64 Reserved2 [44]byte } func (entry *TOCEntry) GetCompressor() (Compressor, error) { switch entry.Flags & CompressorMask { case CompressorNone: return CompressorNone, nil case CompressorZstd: return CompressorZstd, nil case CompressorLz4Block: return CompressorLz4Block, nil } return 0, fmt.Errorf("unsupported compressor, entry flags %x", entry.Flags) } func (entry *TOCEntry) GetName() string { var name strings.Builder name.Grow(16) for _, c := range entry.Name { if c == 0 { break } fmt.Fprintf(&name, "%c", c) } return name.String() } func (entry *TOCEntry) GetUncompressedDigest() string { return fmt.Sprintf("%x", entry.UncompressedDigest) } func (entry *TOCEntry) GetCompressedOffset() uint64 { return entry.CompressedOffset } func (entry *TOCEntry) GetCompressedSize() uint64 { return entry.CompressedSize } func (entry *TOCEntry) GetUncompressedSize() uint64 { return entry.UncompressedSize } nydus-snapshotter-0.13.4/pkg/converter/utils.go000066400000000000000000000103401453374237200216000ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package converter import ( "archive/tar" "bytes" "compress/gzip" "context" "encoding/json" "fmt" "io" "os" "path/filepath" "github.com/containerd/containerd/content" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) type writeCloser struct { closed bool io.WriteCloser action func() error } func (c *writeCloser) Close() error { if c.closed { return nil } if err := c.WriteCloser.Close(); err != nil { return err } c.closed = true if err := c.action(); err != nil { return err } return nil } func newWriteCloser(wc io.WriteCloser, action func() error) *writeCloser { return &writeCloser{ WriteCloser: wc, action: action, } } type seekReader struct { io.ReaderAt pos int64 } func (ra *seekReader) Read(p []byte) (int, error) { n, err := ra.ReaderAt.ReadAt(p, ra.pos) ra.pos += int64(n) return n, err } func (ra *seekReader) Seek(offset int64, whence int) (int64, error) { switch { case whence == io.SeekCurrent: ra.pos += offset case whence == io.SeekStart: ra.pos = offset default: return 0, fmt.Errorf("unsupported whence %d", whence) } return ra.pos, nil } func newSeekReader(ra io.ReaderAt) *seekReader { return &seekReader{ ReaderAt: ra, pos: 0, } } // packToTar makes .tar(.gz) stream of file named `name` and return reader. func packToTar(src string, name string, compress bool) (io.ReadCloser, error) { fi, err := os.Stat(src) if err != nil { return nil, err } dirHdr := &tar.Header{ Name: filepath.Dir(name), Mode: 0755, Typeflag: tar.TypeDir, } hdr := &tar.Header{ Name: name, Mode: 0444, Size: fi.Size(), } reader, writer := io.Pipe() go func() { // Prepare targz writer var tw *tar.Writer var gw *gzip.Writer var err error var file *os.File if compress { gw = gzip.NewWriter(writer) tw = tar.NewWriter(gw) } else { tw = tar.NewWriter(writer) } defer func() { err1 := tw.Close() var err2 error if gw != nil { err2 = gw.Close() } var finalErr error // Return the first error encountered to the other end and ignore others. switch { case err != nil: finalErr = err case err1 != nil: finalErr = err1 case err2 != nil: finalErr = err2 } writer.CloseWithError(finalErr) }() file, err = os.Open(src) if err != nil { return } defer file.Close() // Write targz stream if err = tw.WriteHeader(dirHdr); err != nil { return } if err = tw.WriteHeader(hdr); err != nil { return } if _, err = io.Copy(tw, file); err != nil { return } }() return reader, nil } // Copied from containerd/containerd project, copyright The containerd Authors. // https://github.com/containerd/containerd/blob/4902059cb554f4f06a8d06a12134c17117809f4e/images/converter/default.go#L385 func readJSON(ctx context.Context, cs content.Store, x interface{}, desc ocispec.Descriptor) (map[string]string, error) { info, err := cs.Info(ctx, desc.Digest) if err != nil { return nil, err } labels := info.Labels if labels == nil { labels = map[string]string{} } b, err := content.ReadBlob(ctx, cs, desc) if err != nil { return nil, err } if err := json.Unmarshal(b, x); err != nil { return nil, err } return labels, nil } // Copied from containerd/containerd project, copyright The containerd Authors. // https://github.com/containerd/containerd/blob/4902059cb554f4f06a8d06a12134c17117809f4e/images/converter/default.go#L401 func writeJSON(ctx context.Context, cs content.Store, x interface{}, oldDesc ocispec.Descriptor, labels map[string]string) (*ocispec.Descriptor, error) { b, err := json.Marshal(x) if err != nil { return nil, err } dgst := digest.SHA256.FromBytes(b) ref := fmt.Sprintf("converter-write-json-%s", dgst.String()) w, err := content.OpenWriter(ctx, cs, content.WithRef(ref)) if err != nil { return nil, err } if err := content.Copy(ctx, w, bytes.NewReader(b), int64(len(b)), dgst, content.WithLabels(labels)); err != nil { return nil, err } if err := w.Close(); err != nil { return nil, err } newDesc := oldDesc newDesc.Size = int64(len(b)) newDesc.Digest = dgst return &newDesc, nil } nydus-snapshotter-0.13.4/pkg/daemon/000077500000000000000000000000001453374237200173475ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/daemon/client.go000066400000000000000000000214211453374237200211540ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package daemon import ( "bytes" "context" "encoding/json" "fmt" "io" "io/fs" "net" "net/http" "net/url" "os" "time" "github.com/pkg/errors" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/containerd/nydus-snapshotter/pkg/metrics/tool" "github.com/containerd/nydus-snapshotter/pkg/utils/retry" ) const ( // Get information about nydus daemon endpointDaemonInfo = "/api/v1/daemon" // Mount or umount filesystems. endpointMount = "/api/v1/mount" // Fetch generic filesystem metrics. endpointMetrics = "/api/v1/metrics" // Fetch metrics relevant to caches usage. endpointCacheMetrics = "/api/v1/metrics/blobcache" // Fetch metrics about inflighting operations. endpointInflightMetrics = "/api/v1/metrics/inflight" // Request nydus daemon to retrieve its runtime states from the supervisor, recovering states for failover. endpointTakeOver = "/api/v1/daemon/fuse/takeover" // Request nydus daemon to send its runtime states to the supervisor, preparing for failover. endpointSendFd = "/api/v1/daemon/fuse/sendfd" // Request nydus daemon to start filesystem service. endpointStart = "/api/v1/daemon/start" // Request nydus daemon to exit endpointExit = "/api/v1/daemon/exit" // --- V2 API begins // Add/remove blobs managed by the blob cache manager. endpointBlobs = "/api/v2/blobs" defaultHTTPClientTimeout = 30 * time.Second jsonContentType = "application/json" ) // Nydusd HTTP client to query nydusd runtime status, operate file system instances. // Control nydusd workflow like failover and upgrade. type NydusdClient interface { GetDaemonInfo() (*types.DaemonInfo, error) Mount(mountpoint, bootstrap, daemonConfig string) error Umount(mountpoint string) error BindBlob(daemonConfig string) error UnbindBlob(domainID, blobID string) error GetFsMetrics(sid string) (*types.FsMetrics, error) GetInflightMetrics() (*types.InflightMetrics, error) GetCacheMetrics(sid string) (*types.CacheMetrics, error) TakeOver() error SendFd() error Start() error Exit() error } // Nydusd API server http client used to command nydusd's action and // query nydusd working status. type nydusdClient struct { httpClient *http.Client } type query = url.Values func (c *nydusdClient) url(path string, query query) (url string) { url = fmt.Sprintf("http://unix%s", path) if len(query) != 0 { url += "?" + query.Encode() } return } // A simple http client request wrapper with capability to take // request body and handle or process http response if result is expected. func (c *nydusdClient) request(method string, url string, body io.Reader, respHandler func(resp *http.Response) error) error { req, err := http.NewRequest(method, url, body) if err != nil { return errors.Wrapf(err, "construct request %s", url) } if body != nil { req.Header.Add("Content-Type", jsonContentType) } resp, err := c.httpClient.Do(req) if err != nil { return err } defer resp.Body.Close() if succeeded(resp) { if respHandler != nil { if err = respHandler(resp); err != nil { return errors.Wrapf(err, "handle response") } } return nil } return parseErrorMessage(resp) } func succeeded(resp *http.Response) bool { return resp.StatusCode == http.StatusNoContent || resp.StatusCode == http.StatusOK } func decode(resp *http.Response, v any) error { if err := json.NewDecoder(resp.Body).Decode(&v); err != nil { return errors.Wrap(err, "decode response") } return nil } // Parse http response to get the specific error message formatted by nydusd API server. // So it will be clear what's wrong in nydusd during processing http requests. func parseErrorMessage(resp *http.Response) error { var errMessage types.ErrorMessage err := decode(resp, &errMessage) if err != nil { return err } return errors.Errorf("http response: %d, error code: %s, error message: %s", resp.StatusCode, errMessage.Code, errMessage.Message) } func buildTransport(sock string) http.RoundTripper { return &http.Transport{ MaxIdleConns: 10, IdleConnTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) { dialer := &net.Dialer{ Timeout: 5 * time.Second, KeepAlive: 5 * time.Second, } return dialer.DialContext(ctx, "unix", sock) }, } } func WaitUntilSocketExisted(sock string, pid int) error { return retry.Do(func() (err error) { var st fs.FileInfo if st, err = os.Stat(sock); err != nil { return } if st.Mode()&os.ModeSocket == 0 { return errors.Errorf("file %s is not socket file", sock) } return nil }, retry.Attempts(100), // totally wait for 10 seconds, should be enough retry.LastErrorOnly(true), retry.Delay(100*time.Millisecond), retry.OnlyRetryIf(func(error) bool { zombie, err := tool.IsZombieProcess(pid) if err != nil { return false } // Stop retry if nydus daemon process is already in Zombie state. if zombie { log.L.Errorf("Process %d has been a zombie", pid) return true } return false }), ) } func NewNydusClient(sock string) (NydusdClient, error) { transport := buildTransport(sock) return &nydusdClient{ httpClient: &http.Client{ Timeout: defaultHTTPClientTimeout, Transport: transport, }, }, nil } func (c *nydusdClient) GetDaemonInfo() (*types.DaemonInfo, error) { url := c.url(endpointDaemonInfo, query{}) var info types.DaemonInfo err := c.request(http.MethodGet, url, nil, func(resp *http.Response) error { if err := decode(resp, &info); err != nil { return err } return nil }) if err != nil { return nil, err } return &info, nil } func (c *nydusdClient) Mount(mp, bootstrap, mountConfig string) error { cmd, err := json.Marshal(types.NewMountRequest(bootstrap, mountConfig)) if err != nil { return errors.Wrap(err, "construct mount request") } query := query{} query.Add("mountpoint", mp) url := c.url(endpointMount, query) return c.request(http.MethodPost, url, bytes.NewBuffer(cmd), nil) } func (c *nydusdClient) Umount(mp string) error { query := query{} query.Add("mountpoint", mp) url := c.url(endpointMount, query) return c.request(http.MethodDelete, url, nil, nil) } func (c *nydusdClient) BindBlob(daemonConfig string) error { url := c.url(endpointBlobs, query{}) return c.request(http.MethodPut, url, bytes.NewBuffer([]byte(daemonConfig)), nil) } // Delete /api/v2/blobs implements different functions according to different parameters // 1. domainID , delete all blob entries in the domain. // 2. domainID + blobID, delete the blob entry, if the blob is bootstrap // also delete blob entries belong to it. // 3. blobID, try to find and cull blob cache files by blobID in all domains. func (c *nydusdClient) UnbindBlob(domainID, blobID string) error { query := query{} if domainID != "" { query.Add("domain_id", domainID) if domainID != blobID { query.Add("blob_id", blobID) } } else { query.Add("blob_id", blobID) } url := c.url(endpointBlobs, query) return c.request(http.MethodDelete, url, nil, nil) } func (c *nydusdClient) GetFsMetrics(sid string) (*types.FsMetrics, error) { query := query{} if sid != "" { query.Add("id", "/"+sid) } url := c.url(endpointMetrics, query) var m types.FsMetrics if err := c.request(http.MethodGet, url, nil, func(resp *http.Response) error { return decode(resp, &m) }); err != nil { return nil, err } return &m, nil } func (c *nydusdClient) GetInflightMetrics() (*types.InflightMetrics, error) { url := c.url(endpointInflightMetrics, query{}) var m types.InflightMetrics if err := c.request(http.MethodGet, url, nil, func(resp *http.Response) error { if resp.StatusCode != http.StatusNoContent { return decode(resp, &m.Values) } return nil }); err != nil { return nil, err } return &m, nil } func (c *nydusdClient) GetCacheMetrics(sid string) (*types.CacheMetrics, error) { query := query{} if sid != "" { query.Add("id", "/"+sid) } url := c.url(endpointCacheMetrics, query) var m types.CacheMetrics if err := c.request(http.MethodGet, url, nil, func(resp *http.Response) error { return decode(resp, &m) }); err != nil { return nil, err } return &m, nil } func (c *nydusdClient) TakeOver() error { url := c.url(endpointTakeOver, query{}) return c.request(http.MethodPut, url, nil, nil) } func (c *nydusdClient) SendFd() error { url := c.url(endpointSendFd, query{}) return c.request(http.MethodPut, url, nil, nil) } func (c *nydusdClient) Start() error { url := c.url(endpointStart, query{}) return c.request(http.MethodPut, url, nil, nil) } func (c *nydusdClient) Exit() error { url := c.url(endpointExit, query{}) return c.request(http.MethodPut, url, nil, nil) } nydus-snapshotter-0.13.4/pkg/daemon/client_test.go000066400000000000000000000032501453374237200222130ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package daemon import ( "encoding/json" "net" "net/http" "net/http/httptest" "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" ) var BTI = types.BuildTimeInfo{ PackageVer: "1.1.0", GitCommit: "67f4ecc7acee6dd37234e6a697e72ac09d6cc8ba", BuildTime: "Thu, 28 Jan 2021 14:02:39 +0000", Profile: "debug", Rustc: "rustc 1.46.0 (04488afe3 2020-08-24)", } func prepareNydusServer(t *testing.T) (string, func()) { dir, _ := os.MkdirTemp("", "nydus-snapshotter-test") mockSocket := filepath.Join(dir, "nydusd.sock") _, err := os.Stat(mockSocket) if err == nil { _ = os.Remove(mockSocket) } ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) info := types.DaemonInfo{ ID: "testid", Version: BTI, State: "RUNNING", } w.Header().Set("Content-Type", "application/json") j, _ := json.Marshal(info) _, err := w.Write(j) assert.Nil(t, err) })) unixListener, err := net.Listen("unix", mockSocket) require.Nil(t, err) ts.Listener = unixListener ts.Start() return mockSocket, func() { ts.Close() } } func TestNydusClient_CheckStatus(t *testing.T) { sock, dispose := prepareNydusServer(t) defer dispose() client, err := NewNydusClient(sock) require.Nil(t, err) info, err := client.GetDaemonInfo() require.Nil(t, err) assert.Equal(t, info.DaemonState(), types.DaemonStateRunning) assert.Equal(t, "testid", info.ID) assert.Equal(t, BTI, info.Version) } nydus-snapshotter-0.13.4/pkg/daemon/command/000077500000000000000000000000001453374237200207655ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/daemon/command/command.go000066400000000000000000000077301453374237200227410ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package command import ( "fmt" "reflect" "strconv" "github.com/pkg/errors" ) type Opt = func(cmd *DaemonCommand) // Define how to build a command line to start a nydusd daemon type DaemonCommand struct { // "singleton" "fuse" Mode string `type:"subcommand"` // "blobcache" "fscache" "virtiofs" FscacheDriver string `type:"param" name:"fscache"` FscacheThreads string `type:"param" name:"fscache-threads"` Upgrade bool `type:"flag" name:"upgrade" default:""` ThreadNum string `type:"param" name:"thread-num"` // `--id` is required by `--supervisor` when starting nydusd ID string `type:"param" name:"id"` Config string `type:"param" name:"config"` Bootstrap string `type:"param" name:"bootstrap"` Mountpoint string `type:"param" name:"mountpoint"` APISock string `type:"param" name:"apisock"` LogLevel string `type:"param" name:"log-level"` LogRotationSize int `type:"param" name:"log-rotation-size"` Supervisor string `type:"param" name:"supervisor"` LogFile string `type:"param" name:"log-file"` PrefetchFiles string `type:"param" name:"prefetch-files"` } // Build exec style command line func BuildCommand(opts []Opt) ([]string, error) { var cmd DaemonCommand var subcommand string for _, o := range opts { o(&cmd) } args := make([]string, 0, 32) t := reflect.TypeOf(cmd) v := reflect.ValueOf(cmd) for i := 0; i < t.NumField(); i++ { tag := t.Field(i).Tag argType := tag.Get("type") switch argType { case "param": // Zero value will be skipped appending to command line if v.Field(i).IsZero() { continue } value := v.Field(i).Interface() pair := []string{fmt.Sprintf("--%s", tag.Get("name")), fmt.Sprintf("%v", value)} args = append(args, pair...) case "subcommand": // Zero value will be skipped appending to command line if v.Field(i).IsZero() { continue } subcommand = v.Field(i).String() case "flag": kind := v.Field(i).Kind() if kind != reflect.Bool { return nil, errors.Errorf("flag must be boolean") } v := v.Field(i).Bool() if v { flag := fmt.Sprintf("--%s", tag.Get("name")) args = append(args, flag) } else { continue } default: return nil, errors.Errorf("unknown tag type: %s ", argType) } } if subcommand != "" { // Ensure subcommand is at the first place. args = append([]string{subcommand}, args...) } return args, nil } func WithMode(m string) Opt { return func(cmd *DaemonCommand) { cmd.Mode = m } } func WithPrefetchFiles(p string) Opt { return func(cmd *DaemonCommand) { cmd.PrefetchFiles = p } } func WithFscacheDriver(w string) Opt { return func(cmd *DaemonCommand) { cmd.FscacheDriver = w } } func WithFscacheThreads(num int) Opt { return func(cmd *DaemonCommand) { cmd.FscacheThreads = strconv.Itoa(num) } } func WithThreadNum(num int) Opt { return func(cmd *DaemonCommand) { cmd.ThreadNum = strconv.Itoa(num) } } func WithConfig(config string) Opt { return func(cmd *DaemonCommand) { cmd.Config = config } } func WithBootstrap(b string) Opt { return func(cmd *DaemonCommand) { cmd.Bootstrap = b } } func WithMountpoint(m string) Opt { return func(cmd *DaemonCommand) { cmd.Mountpoint = m } } func WithAPISock(api string) Opt { return func(cmd *DaemonCommand) { cmd.APISock = api } } func WithLogFile(l string) Opt { return func(cmd *DaemonCommand) { cmd.LogFile = l } } func WithLogLevel(l string) Opt { return func(cmd *DaemonCommand) { cmd.LogLevel = l } } func WithLogRotationSize(l int) Opt { return func(cmd *DaemonCommand) { cmd.LogRotationSize = l } } func WithSupervisor(s string) Opt { return func(cmd *DaemonCommand) { cmd.Supervisor = s } } func WithID(id string) Opt { return func(cmd *DaemonCommand) { cmd.ID = id } } func WithUpgrade() Opt { return func(cmd *DaemonCommand) { cmd.Upgrade = true } } nydus-snapshotter-0.13.4/pkg/daemon/command/command_builder_test.go000066400000000000000000000025331453374237200255020ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package command import ( "strings" "testing" "github.com/stretchr/testify/assert" ) func TestBuildCommand(t *testing.T) { c := []Opt{WithMode("singleton"), WithFscacheDriver("fs_cache_dir"), WithFscacheThreads(4), WithAPISock("/dummy/apisock"), WithUpgrade()} args, err := BuildCommand(c) assert.Nil(t, err) actual := strings.Join(args, " ") assert.Equal(t, "singleton --fscache fs_cache_dir --fscache-threads 4 --upgrade --apisock /dummy/apisock", actual) c1 := []Opt{WithMode("singleton"), WithFscacheDriver("fs_cache_dir"), WithFscacheThreads(4), WithAPISock("/dummy/apisock")} args1, err := BuildCommand(c1) assert.Nil(t, err) actual1 := strings.Join(args1, " ") assert.Equal(t, "singleton --fscache fs_cache_dir --fscache-threads 4 --apisock /dummy/apisock", actual1) } // cpu: Intel(R) Xeon(R) Platinum 8260 CPU @ 2.40GHz // BenchmarkBuildCommand-8 394146 3084 ns/op // BenchmarkXxx-8 3933902 281.4 ns/op // PASS func BenchmarkBuildCommand(b *testing.B) { c := []Opt{WithMode("singleton"), WithFscacheDriver("fs_cache_dir"), WithFscacheThreads(4), WithAPISock("/dummy/apisock"), WithUpgrade()} for n := 0; n < b.N; n++ { _, err := BuildCommand(c) assert.Nil(b, err) } } nydus-snapshotter-0.13.4/pkg/daemon/config.go000066400000000000000000000047351453374237200211540ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package daemon import ( "os" "path" "path/filepath" "github.com/pkg/errors" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/internal/constant" ) // Build runtime nydusd daemon object, which might be persisted later func WithSocketDir(dir string) NewDaemonOpt { return func(d *Daemon) error { s := filepath.Join(dir, d.ID()) // this may be failed, should handle that if err := os.MkdirAll(s, 0755); err != nil { return errors.Wrapf(err, "create socket dir %s", s) } d.States.APISocket = path.Join(s, "api.sock") return nil } } func WithRef(ref int32) NewDaemonOpt { return func(d *Daemon) error { d.ref = ref return nil } } func WithLogDir(dir string) NewDaemonOpt { return func(d *Daemon) error { if err := os.MkdirAll(dir, 0755); err != nil { return errors.Wrapf(err, "create logging dir %s", dir) } d.States.LogDir = filepath.Join(dir, d.ID()) return nil } } func WithLogToStdout(logToStdout bool) NewDaemonOpt { return func(d *Daemon) error { d.States.LogToStdout = logToStdout return nil } } func WithLogLevel(logLevel string) NewDaemonOpt { return func(d *Daemon) error { if logLevel == "" { d.States.LogLevel = constant.DefaultLogLevel } else { d.States.LogLevel = logLevel } return nil } } func WithLogRotationSize(logRotationSize int) NewDaemonOpt { return func(d *Daemon) error { d.States.LogRotationSize = logRotationSize return nil } } func WithConfigDir(dir string) NewDaemonOpt { return func(d *Daemon) error { s := filepath.Join(dir, d.ID()) // this may be failed, should handle that if err := os.MkdirAll(s, 0755); err != nil { return errors.Wrapf(err, "failed to create config dir %s", s) } d.States.ConfigDir = s return nil } } func WithMountpoint(mountpoint string) NewDaemonOpt { return func(d *Daemon) error { d.States.Mountpoint = mountpoint return nil } } func WithNydusdThreadNum(nydusdThreadNum int) NewDaemonOpt { return func(d *Daemon) error { d.States.ThreadNum = nydusdThreadNum return nil } } func WithFsDriver(fsDriver string) NewDaemonOpt { return func(d *Daemon) error { d.States.FsDriver = fsDriver return nil } } func WithDaemonMode(daemonMode config.DaemonMode) NewDaemonOpt { return func(d *Daemon) error { d.States.DaemonMode = daemonMode return nil } } nydus-snapshotter-0.13.4/pkg/daemon/daemon.go000066400000000000000000000407701453374237200211510ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package daemon import ( "os" "path/filepath" "sort" "sync" "sync/atomic" "syscall" "time" "github.com/pkg/errors" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/config/daemonconfig" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/pkg/rafs" "github.com/containerd/nydus-snapshotter/pkg/supervisor" "github.com/containerd/nydus-snapshotter/pkg/utils/erofs" "github.com/containerd/nydus-snapshotter/pkg/utils/mount" "github.com/containerd/nydus-snapshotter/pkg/utils/retry" ) const ( APISocketFileName = "api.sock" SharedNydusDaemonID = "shared_daemon" ) type NewDaemonOpt func(d *Daemon) error // Fields in this structure should be write-once, and caller should hold `Daemon.mu` when updating fields. type ConfigState struct { // A unique ID generated by daemon manager to identify the nydusd instance. ID string ProcessID int APISocket string DaemonMode config.DaemonMode FsDriver string LogDir string LogLevel string LogRotationSize int LogToStdout bool Mountpoint string SupervisorPath string ThreadNum int // Where the configuration file resides, all rafs instances share the same configuration template ConfigDir string } // TODO: Record queried nydusd state type Daemon struct { States ConfigState mu sync.Mutex // Host all RAFS filesystems managed by this daemon: // fusedev dedicated mode: one and only one RAFS instance // fusedev shared mode: zero, one or more RAFS instances // fscache shared mode: zero, one or more RAFS instances RafsCache rafs.Cache // Protect nydusd http client cmu sync.Mutex // client will be rebuilt on Reconnect, skip marshal/unmarshal client NydusdClient // Nil means this daemon object has no supervisor Supervisor *supervisor.Supervisor Config daemonconfig.DaemonConfig // How much CPU nydusd is utilizing when starts since full prefetch might // consume many CPU cycles StartupCPUUtilization float64 Version types.BuildTimeInfo ref int32 // Cache the nydusd daemon state to avoid frequently querying nydusd by API. state types.DaemonState } func (d *Daemon) Lock() { d.mu.Lock() } func (d *Daemon) Unlock() { d.mu.Unlock() } func (d *Daemon) ID() string { return d.States.ID } func (d *Daemon) Pid() int { return d.States.ProcessID } func (d *Daemon) IncRef() { atomic.AddInt32(&d.ref, 1) } func (d *Daemon) DecRef() int32 { return atomic.AddInt32(&d.ref, -1) } func (d *Daemon) GetRef() int32 { return atomic.LoadInt32(&d.ref) } func (d *Daemon) HostMountpoint() (mnt string) { mnt = d.States.Mountpoint return } // Each nydusd daemon has a copy of configuration json file. func (d *Daemon) ConfigFile(instanceID string) string { if instanceID == "" { return filepath.Join(d.States.ConfigDir, "config.json") } return filepath.Join(d.States.ConfigDir, instanceID, "config.json") } // NydusdThreadNum returns how many working threads are needed of a single nydusd func (d *Daemon) NydusdThreadNum() int { return d.States.ThreadNum } func (d *Daemon) GetAPISock() string { return d.States.APISocket } func (d *Daemon) LogFile() string { return filepath.Join(d.States.LogDir, "nydusd.log") } func (d *Daemon) AddRafsInstance(r *rafs.Rafs) { d.RafsCache.Add(r) d.IncRef() r.DaemonID = d.ID() } func (d *Daemon) RemoveRafsInstance(snapshotID string) { d.RafsCache.Remove(snapshotID) d.DecRef() } // Get and cache daemon current working state by querying nydusd: // 1. INIT // 2. READY: All needed resources are ready. // 3. RUNNING func (d *Daemon) GetState() (types.DaemonState, error) { c, err := d.GetClient() if err != nil { return types.DaemonStateUnknown, errors.Wrapf(err, "get daemon state") } info, err := c.GetDaemonInfo() if err != nil { return types.DaemonStateUnknown, err } st := info.DaemonState() d.Lock() d.state = st d.Version = info.DaemonVersion() d.Unlock() return st, nil } // Return the cached nydusd working status, no API is invoked. func (d *Daemon) State() types.DaemonState { d.Lock() defer d.Unlock() return d.state } // Reset the cached nydusd working status func (d *Daemon) ResetState() { d.Lock() defer d.Unlock() d.state = types.DaemonStateUnknown } // Wait for the nydusd daemon to reach specified state with timeout. func (d *Daemon) WaitUntilState(expected types.DaemonState) error { return retry.Do(func() error { if expected == d.State() { return nil } state, err := d.GetState() if err != nil { return errors.Wrapf(err, "wait until daemon is %s", expected) } if state != expected { return errors.Errorf("daemon %s is not %s yet, current state %s", d.ID(), expected, state) } return nil }, retry.LastErrorOnly(true), retry.Attempts(20), // totally wait for 2 seconds, should be enough retry.Delay(100*time.Millisecond), ) } func (d *Daemon) IsSharedDaemon() bool { if d.States.DaemonMode != "" { return d.States.DaemonMode == config.DaemonModeShared } return d.HostMountpoint() == config.GetRootMountpoint() } func (d *Daemon) SharedMount(rafs *rafs.Rafs) error { defer d.SendStates() switch d.States.FsDriver { case config.FsDriverFscache: if err := d.sharedErofsMount(rafs); err != nil { return errors.Wrapf(err, "mount erofs") } return nil case config.FsDriverFusedev: return d.sharedFusedevMount(rafs) default: return errors.Errorf("unsupported fs driver %s", d.States.FsDriver) } } func (d *Daemon) sharedFusedevMount(rafs *rafs.Rafs) error { client, err := d.GetClient() if err != nil { return errors.Wrapf(err, "mount instance %s", rafs.SnapshotID) } bootstrap, err := rafs.BootstrapFile() if err != nil { return err } c, err := daemonconfig.NewDaemonConfig(d.States.FsDriver, d.ConfigFile(rafs.SnapshotID)) if err != nil { return errors.Wrapf(err, "Failed to reload instance configuration %s", d.ConfigFile(rafs.SnapshotID)) } cfg, err := c.DumpString() if err != nil { return errors.Wrap(err, "dump instance configuration") } err = client.Mount(rafs.RelaMountpoint(), bootstrap, cfg) if err != nil { return errors.Wrapf(err, "mount rafs instance") } return nil } func (d *Daemon) sharedErofsMount(ra *rafs.Rafs) error { client, err := d.GetClient() if err != nil { return errors.Wrapf(err, "bind blob %s", d.ID()) } // TODO: Why fs cache needing this work dir? if err := os.MkdirAll(ra.FscacheWorkDir(), 0755); err != nil { return errors.Wrapf(err, "failed to create fscache work dir %s", ra.FscacheWorkDir()) } c, err := daemonconfig.NewDaemonConfig(d.States.FsDriver, d.ConfigFile(ra.SnapshotID)) if err != nil { log.L.Errorf("Failed to reload daemon configuration %s, %s", d.ConfigFile(ra.SnapshotID), err) return err } cfgStr, err := c.DumpString() if err != nil { return err } if err := client.BindBlob(cfgStr); err != nil { return errors.Wrapf(err, "request to bind fscache blob") } mountPoint := ra.GetMountpoint() if err := os.MkdirAll(mountPoint, 0755); err != nil { return errors.Wrapf(err, "create mountpoint %s", mountPoint) } bootstrapPath, err := ra.BootstrapFile() if err != nil { return err } fscacheID := erofs.FscacheID(ra.SnapshotID) cfg := c.(*daemonconfig.FscacheDaemonConfig) ra.AddAnnotation(rafs.AnnoFsCacheDomainID, cfg.DomainID) ra.AddAnnotation(rafs.AnnoFsCacheID, fscacheID) if err := erofs.Mount(bootstrapPath, cfg.DomainID, fscacheID, mountPoint); err != nil { if !errdefs.IsErofsMounted(err) { return errors.Wrapf(err, "mount erofs to %s", mountPoint) } // When snapshotter exits (either normally or abnormally), it will not have a // chance to umount erofs mountpoint, so if snapshotter resumes running and mount // again (by a new request to create container), it will need to ignore the mount // error `device or resource busy`. log.L.Warnf("erofs mountpoint %s has been mounted", mountPoint) } return nil } func (d *Daemon) SharedUmount(rafs *rafs.Rafs) error { defer d.SendStates() switch d.States.FsDriver { case config.FsDriverFscache: if err := d.sharedErofsUmount(rafs); err != nil { return errors.Wrapf(err, "failed to erofs mount") } return nil case config.FsDriverFusedev: c, err := d.GetClient() if err != nil { return errors.Wrapf(err, "umount instance %s", rafs.SnapshotID) } return c.Umount(rafs.RelaMountpoint()) default: return errors.Errorf("unsupported fs driver %s", d.States.FsDriver) } } func (d *Daemon) sharedErofsUmount(ra *rafs.Rafs) error { c, err := d.GetClient() if err != nil { return errors.Wrapf(err, "unbind blob %s", d.ID()) } domainID := ra.Annotations[rafs.AnnoFsCacheDomainID] fscacheID := ra.Annotations[rafs.AnnoFsCacheID] if err := c.UnbindBlob(domainID, fscacheID); err != nil { return errors.Wrapf(err, "request to unbind fscache blob, domain %s, fscache %s", domainID, fscacheID) } mountpoint := ra.GetMountpoint() if err := erofs.Umount(mountpoint); err != nil { return errors.Wrapf(err, "umount erofs %s mountpoint, %s", err, mountpoint) } // delete fscache bootstrap cache file // erofs generate fscache cache file for bootstrap with fscacheID if err := c.UnbindBlob("", fscacheID); err != nil { log.L.Warnf("delete bootstrap %s err %s", fscacheID, err) } return nil } func (d *Daemon) UmountRafsInstance(r *rafs.Rafs) error { if d.IsSharedDaemon() { if err := d.SharedUmount(r); err != nil { return errors.Wrapf(err, "umount fs instance %s", r.SnapshotID) } } return nil } func (d *Daemon) UmountRafsInstances() error { if d.IsSharedDaemon() { d.RafsCache.Lock() defer d.RafsCache.Unlock() instances := d.RafsCache.ListLocked() for _, r := range instances { if err := d.SharedUmount(r); err != nil { return errors.Wrapf(err, "umount fs instance %s", r.SnapshotID) } } } return nil } func (d *Daemon) SendStates() { su := d.Supervisor if su != nil { // TODO: This should be optional by checking snapshotter's configuration. // FIXME: Is it possible the states are overwritten during two API mounts. // FIXME: What if nydusd does not support sending states. err := su.FetchDaemonStates(func() error { if err := d.doSendStates(); err != nil { return errors.Wrapf(err, "send daemon %s states", d.ID()) } return nil }) if err != nil { log.L.Warnf("Daemon %s does not support sending states, %v", d.ID(), err) } } } func (d *Daemon) doSendStates() error { c, err := d.GetClient() if err != nil { return errors.Wrapf(err, "send states %s", d.ID()) } if err := c.SendFd(); err != nil { return errors.Wrap(err, "request to send states") } return nil } func (d *Daemon) TakeOver() error { c, err := d.GetClient() if err != nil { return errors.Wrapf(err, "takeover daemon %s", d.ID()) } if err := c.TakeOver(); err != nil { return errors.Wrap(err, "request to take over") } return nil } func (d *Daemon) Start() error { c, err := d.GetClient() if err != nil { return errors.Wrapf(err, "start service") } if err := c.Start(); err != nil { return errors.Wrap(err, "request to start service") } return nil } func (d *Daemon) Exit() error { c, err := d.GetClient() if err != nil { return errors.Wrapf(err, "start service") } if err := c.Exit(); err != nil { return errors.Wrap(err, "request to exit service") } return nil } func (d *Daemon) GetDaemonInfo() (*types.DaemonInfo, error) { c, err := d.GetClient() if err != nil { return nil, errors.Wrapf(err, "get daemon information") } return c.GetDaemonInfo() } func (d *Daemon) GetFsMetrics(sid string) (*types.FsMetrics, error) { c, err := d.GetClient() if err != nil { return nil, errors.Wrapf(err, "get fs metrics") } return c.GetFsMetrics(sid) } func (d *Daemon) GetInflightMetrics() (*types.InflightMetrics, error) { c, err := d.GetClient() if err != nil { return nil, errors.Wrapf(err, "get inflight metrics") } return c.GetInflightMetrics() } func (d *Daemon) GetCacheMetrics(sid string) (*types.CacheMetrics, error) { c, err := d.GetClient() if err != nil { return nil, errors.Wrapf(err, "get cache metrics") } return c.GetCacheMetrics(sid) } func (d *Daemon) GetClient() (NydusdClient, error) { d.cmu.Lock() defer d.cmu.Unlock() if d.client == nil { sock := d.GetAPISock() // The socket file may be residual from a dead nydusd err := WaitUntilSocketExisted(sock, d.Pid()) if err != nil { return nil, errors.Wrapf(errdefs.ErrNotFound, "daemon socket %s", sock) } client, err := NewNydusClient(sock) if err != nil { return nil, errors.Wrapf(err, "create daemon %s client", d.ID()) } d.client = client } return d.client, nil } func (d *Daemon) ResetClient() { d.cmu.Lock() d.client = nil d.cmu.Unlock() } func (d *Daemon) Terminate() error { // if we found pid here, we need to kill and wait process to exit, Pid=0 means somehow we lost // the daemon pid, so that we can't kill the process, just roughly umount the mountpoint d.Lock() defer d.Unlock() if d.Pid() > 0 { p, err := os.FindProcess(d.Pid()) if err != nil { return errors.Wrapf(err, "find process %d", d.Pid()) } if err = p.Signal(syscall.SIGTERM); err != nil { return errors.Wrapf(err, "send SIGTERM signal to process %d", d.Pid()) } } return nil } func (d *Daemon) Wait() error { // if we found pid here, we need to kill and wait process to exit, Pid=0 means somehow we lost // the daemon pid, so that we can't kill the process, just roughly umount the mountpoint d.Lock() defer d.Unlock() if d.Pid() > 0 { p, err := os.FindProcess(d.Pid()) if err != nil { return errors.Wrapf(err, "find process %d", d.Pid()) } // if nydus-snapshotter restarts, it will break the relationship between nydusd and // nydus-snapshotter, p.Wait() will return err, so here should exclude this case if _, err = p.Wait(); err != nil && !errors.Is(err, syscall.ECHILD) { log.L.Errorf("failed to process wait, %v", err) } else if d.HostMountpoint() != "" && config.GetFsDriver() == config.FsDriverFusedev { // No need to umount if the nydusd never performs mount. In other word, it does not // associate with a host mountpoint. if err := mount.WaitUntilUnmounted(d.HostMountpoint()); err != nil { log.L.WithError(err).Errorf("umount %s", d.HostMountpoint()) } } } return nil } // When daemon dies, clean up its vestige before start a new one. func (d *Daemon) ClearVestige() { mounter := mount.Mounter{} if d.States.FsDriver == config.FsDriverFscache { instances := d.RafsCache.List() for _, i := range instances { if err := mounter.Umount(i.GetMountpoint()); err != nil { log.L.Warnf("Can't umount %s, %v", d.States.Mountpoint, err) } } } else { log.L.Infof("Unmounting %s when clear vestige", d.HostMountpoint()) if err := mounter.Umount(d.HostMountpoint()); err != nil { log.L.Warnf("Can't umount %s, %v", d.States.Mountpoint, err) } } // Nydusd judges if it should enter failover phrase by checking // if unix socket is existed and it can't be connected. if err := os.Remove(d.GetAPISock()); err != nil { log.L.Warnf("Can't delete residual unix socket %s, %v", d.GetAPISock(), err) } // `CheckStatus->ensureClient` only checks if socket file is existed when building http client. // But the socket file may be residual and will be cleared before starting a new nydusd. // So clear the client by assigning nil d.ResetClient() } func (d *Daemon) CloneRafsInstances(src *Daemon) { instances := src.RafsCache.List() d.RafsCache.SetIntances(instances) } // Daemon must be started and reach RUNNING state before call this method func (d *Daemon) RecoverRafsInstances() error { if d.IsSharedDaemon() { d.RafsCache.Lock() defer d.RafsCache.Unlock() instances := make([]*rafs.Rafs, 0, 16) for _, r := range d.RafsCache.ListLocked() { instances = append(instances, r) } sort.Slice(instances, func(i, j int) bool { return instances[i].Seq < instances[j].Seq }) for _, i := range instances { if d.HostMountpoint() != i.GetMountpoint() { log.L.Infof("Recovered mount instance %s", i.SnapshotID) if err := d.SharedMount(i); err != nil { return err } } } } return nil } // Instantiate a daemon object func NewDaemon(opt ...NewDaemonOpt) (*Daemon, error) { d := &Daemon{} d.States.ID = newID() d.States.DaemonMode = config.DaemonModeDedicated d.RafsCache = rafs.NewRafsCache() for _, o := range opt { err := o(d) if err != nil { return nil, err } } return d, nil } nydus-snapshotter-0.13.4/pkg/daemon/idgen.go000066400000000000000000000003151453374237200207630ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package daemon import ( "github.com/rs/xid" ) func newID() string { return xid.New().String() } nydus-snapshotter-0.13.4/pkg/daemon/types/000077500000000000000000000000001453374237200205135ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/daemon/types/types.go000066400000000000000000000062071453374237200222130ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package types type BuildTimeInfo struct { PackageVer string `json:"package_ver"` GitCommit string `json:"git_commit"` BuildTime string `json:"build_time"` Profile string `json:"profile"` Rustc string `json:"rustc"` } type DaemonState string const ( DaemonStateUnknown DaemonState = "UNKNOWN" DaemonStateInit DaemonState = "INIT" DaemonStateReady DaemonState = "READY" DaemonStateRunning DaemonState = "RUNNING" DaemonStateDied DaemonState = "DIED" DaemonStateDestroyed DaemonState = "DESTROYED" ) type DaemonInfo struct { ID string `json:"id"` Version BuildTimeInfo `json:"version"` State DaemonState `json:"state"` } func (info *DaemonInfo) DaemonState() DaemonState { return info.State } func (info *DaemonInfo) DaemonVersion() BuildTimeInfo { return info.Version } type ErrorMessage struct { Code string `json:"code"` Message string `json:"message"` } type MountRequest struct { FsType string `json:"fs_type"` Source string `json:"source"` Config string `json:"config"` } func NewMountRequest(source, config string) MountRequest { return MountRequest{ FsType: "rafs", Source: source, Config: config, } } type FsMetrics struct { FilesAccountEnabled bool `json:"files_account_enabled"` AccessPatternEnabled bool `json:"access_pattern_enabled"` MeasureLatency bool `json:"measure_latency"` ID string `json:"id"` DataRead uint64 `json:"data_read"` BlockCountRead []uint64 `json:"block_count_read"` FopHits []uint64 `json:"fop_hits"` FopErrors []uint64 `json:"fop_errors"` FopCumulativeLatencyTotal []uint64 `json:"fop_cumulative_latency_total"` ReadLatencyDist []uint64 `json:"read_latency_dist"` NrOpens uint64 `json:"nr_opens"` } type InflightMetrics struct { Values []struct { Inode uint64 `json:"inode"` Opcode uint32 `json:"opcode"` Unique uint64 `json:"unique"` TimestampSecs uint64 `json:"timestamp_secs"` } } type CacheMetrics struct { ID string `json:"id"` UnderlyingFiles []string `json:"underlying_files"` StorePath string `json:"store_path"` PartialHits uint64 `json:"partial_hits"` WholeHits uint64 `json:"whole_hits"` Total uint64 `json:"total"` EntriesCount uint64 `json:"entries_count"` PrefetchDataAmount uint64 `json:"prefetch_data_amount"` PrefetchRequestsCount uint64 `json:"prefetch_requests_count"` PrefetchWorkers uint `json:"prefetch_workers"` PrefetchCumulativeTimeMillis uint64 `json:"prefetch_cumulative_time_millis"` PrefetchBeginTimeSecs uint64 `json:"prefetch_begin_time_secs"` PrefetchEndTimeSecs uint64 `json:"prefetch_end_time_secs"` BufferedBackendSize uint64 `json:"buffered_backend_size"` } nydus-snapshotter-0.13.4/pkg/encryption/000077500000000000000000000000001453374237200202765ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/encryption/encryption.go000066400000000000000000000210221453374237200230140ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package encryption import ( "context" "fmt" "io" "math/rand" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containers/ocicrypt" encconfig "github.com/containers/ocicrypt/config" enchelpers "github.com/containers/ocicrypt/helpers" encocispec "github.com/containers/ocicrypt/spec" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // Copied from containerd/imgcrypt project, copyright The imgcrypt Authors. // https://github.com/containerd/imgcrypt/blob/e7500301cabcc9f3cab3daee3f541079b509e95f/images/encryption/encryption.go#LL82C5-L82C5 // encryptLayer encrypts the layer using the CryptoConfig and creates a new OCI Descriptor. // A call to this function may also only manipulate the wrapped keys list. // The caller is expected to store the returned encrypted data and OCI Descriptor func encryptLayer(cc *encconfig.CryptoConfig, dataReader content.ReaderAt, desc ocispec.Descriptor) (ocispec.Descriptor, io.Reader, ocicrypt.EncryptLayerFinalizer, error) { var ( size int64 d digest.Digest err error ) encLayerReader, encLayerFinalizer, err := ocicrypt.EncryptLayer(cc.EncryptConfig, ocicrypt.ReaderFromReaderAt(dataReader), desc) if err != nil { return ocispec.Descriptor{}, nil, nil, err } // were data touched ? if encLayerReader != nil { size = 0 d = "" } else { size = desc.Size d = desc.Digest } newDesc := ocispec.Descriptor{ Digest: d, Size: size, Platform: desc.Platform, } switch desc.MediaType { case images.MediaTypeDockerSchema2LayerGzip: newDesc.MediaType = encocispec.MediaTypeLayerGzipEnc case images.MediaTypeDockerSchema2Layer: newDesc.MediaType = encocispec.MediaTypeLayerEnc case encocispec.MediaTypeLayerGzipEnc: newDesc.MediaType = encocispec.MediaTypeLayerGzipEnc case encocispec.MediaTypeLayerZstdEnc: newDesc.MediaType = encocispec.MediaTypeLayerZstdEnc case encocispec.MediaTypeLayerEnc: newDesc.MediaType = encocispec.MediaTypeLayerEnc // TODO: Mediatypes to be added in ocispec case ocispec.MediaTypeImageLayerGzip: newDesc.MediaType = encocispec.MediaTypeLayerGzipEnc case ocispec.MediaTypeImageLayerZstd: newDesc.MediaType = encocispec.MediaTypeLayerZstdEnc case ocispec.MediaTypeImageLayer: newDesc.MediaType = encocispec.MediaTypeLayerEnc default: return ocispec.Descriptor{}, nil, nil, fmt.Errorf("unsupporter layer MediaType: %s", desc.MediaType) } return newDesc, encLayerReader, encLayerFinalizer, nil } // Copied from containerd/imgcrypt project, copyright The imgcrypt Authors. // https://github.com/containerd/imgcrypt/blob/e7500301cabcc9f3cab3daee3f541079b509e95f/images/encryption/encryption.go#LL164C11-L164C11 // decryptLayer decrypts the layer using the CryptoConfig and creates a new OCI Descriptor. // The caller is expected to store the returned plain data and OCI Descriptor func decryptLayer(cc *encconfig.CryptoConfig, dataReader content.ReaderAt, desc ocispec.Descriptor, unwrapOnly bool) (ocispec.Descriptor, io.Reader, error) { resultReader, d, err := ocicrypt.DecryptLayer(cc.DecryptConfig, ocicrypt.ReaderFromReaderAt(dataReader), desc, unwrapOnly) if err != nil || unwrapOnly { return ocispec.Descriptor{}, nil, err } newDesc := ocispec.Descriptor{ Digest: d, Size: 0, Platform: desc.Platform, } switch desc.MediaType { case encocispec.MediaTypeLayerGzipEnc: newDesc.MediaType = images.MediaTypeDockerSchema2LayerGzip case encocispec.MediaTypeLayerZstdEnc: newDesc.MediaType = ocispec.MediaTypeImageLayerZstd case encocispec.MediaTypeLayerEnc: newDesc.MediaType = images.MediaTypeDockerSchema2Layer default: return ocispec.Descriptor{}, nil, fmt.Errorf("unsupporter layer MediaType: %s", desc.MediaType) } return newDesc, resultReader, nil } // Copied from containerd/imgcrypt project, copyright The imgcrypt Authors. // https://github.com/containerd/imgcrypt/blob/e7500301cabcc9f3cab3daee3f541079b509e95f/images/encryption/encryption.go#LL250C5-L250C5 func ingestReader(ctx context.Context, cs content.Ingester, ref string, r io.Reader) (digest.Digest, int64, error) { cw, err := content.OpenWriter(ctx, cs, content.WithRef(ref)) if err != nil { return "", 0, fmt.Errorf("failed to open writer: %w", err) } defer cw.Close() if _, err := content.CopyReader(cw, r); err != nil { return "", 0, fmt.Errorf("copy failed: %w", err) } st, err := cw.Status() if err != nil { return "", 0, fmt.Errorf("failed to get state: %w", err) } if err := cw.Commit(ctx, st.Offset, ""); err != nil { if !errdefs.IsAlreadyExists(err) { return "", 0, fmt.Errorf("failed commit on ref %q: %w", ref, err) } } return cw.Digest(), st.Offset, nil } // Encrypt Nydus bootstrap layer func EncryptNydusBootstrap(ctx context.Context, cs content.Store, desc ocispec.Descriptor, encryptRecipients []string) (ocispec.Descriptor, error) { var ( resultReader io.Reader newDesc ocispec.Descriptor encLayerFinalizer ocicrypt.EncryptLayerFinalizer ) dataReader, err := cs.ReaderAt(ctx, desc) if err != nil { return ocispec.Descriptor{}, err } defer dataReader.Close() cc, err := enchelpers.CreateCryptoConfig(encryptRecipients, []string{}) if err != nil { return ocispec.Descriptor{}, fmt.Errorf("create encrypt config failed: %w", err) } newDesc, resultReader, encLayerFinalizer, err = encryptLayer(&cc, dataReader, desc) if err != nil { return ocispec.Descriptor{}, fmt.Errorf("failed to encrypt bootstrap layer: %w", err) } newDesc.Annotations = ocicrypt.FilterOutAnnotations(desc.Annotations) // some operations, such as changing recipients, may not touch the layer at all if resultReader != nil { var ref string // If we have the digest, write blob with checks haveDigest := newDesc.Digest.String() != "" if haveDigest { ref = fmt.Sprintf("encrypted-bootstrap-%s", newDesc.Digest.String()) } else { ref = fmt.Sprintf("encrypted-bootstrap-%d-%d", rand.Int(), rand.Int()) } if haveDigest { // Write blob if digest is known beforehand if err := content.WriteBlob(ctx, cs, ref, resultReader, newDesc); err != nil { return ocispec.Descriptor{}, fmt.Errorf("failed to write config: %w", err) } } else { newDesc.Digest, newDesc.Size, err = ingestReader(ctx, cs, ref, resultReader) if err != nil { return ocispec.Descriptor{}, err } } } // After performing encryption, call finalizer to get annotations if encLayerFinalizer != nil { annotations, err := encLayerFinalizer() if err != nil { return ocispec.Descriptor{}, fmt.Errorf("error getting annotations from encLayer finalizer: %w", err) } for k, v := range annotations { newDesc.Annotations[k] = v } } return newDesc, err } // Decrypt the Nydus boostrap layer. // If unwrapOnly is set we will only try to decrypt the layer encryption key and return, // the layer itself won't be decrypted actually. func DeryptNydusBootstrap(ctx context.Context, cs content.Store, desc ocispec.Descriptor, decryptKeys []string, unwrapOnly bool) (ocispec.Descriptor, error) { var ( resultReader io.Reader newDesc ocispec.Descriptor ) dataReader, err := cs.ReaderAt(ctx, desc) if err != nil { return ocispec.Descriptor{}, err } defer dataReader.Close() cc, err := enchelpers.CreateCryptoConfig([]string{}, decryptKeys) if err != nil { return ocispec.Descriptor{}, fmt.Errorf("create decrypt config failed: %w", err) } newDesc, resultReader, err = decryptLayer(&cc, dataReader, desc, unwrapOnly) if err != nil || unwrapOnly { return ocispec.Descriptor{}, fmt.Errorf("failed to decrypt bootstrap layer: %w", err) } newDesc.Annotations = ocicrypt.FilterOutAnnotations(desc.Annotations) // some operations, such as changing recipients, may not touch the layer at all if resultReader != nil { var ref string // If we have the digest, write blob with checks haveDigest := newDesc.Digest.String() != "" if haveDigest { ref = fmt.Sprintf("decrypted-bootstrap-%s", newDesc.Digest.String()) } else { ref = fmt.Sprintf("decrypted-bootstrap-%d-%d", rand.Int(), rand.Int()) } if haveDigest { // Write blob if digest is known beforehand if err := content.WriteBlob(ctx, cs, ref, resultReader, newDesc); err != nil { return ocispec.Descriptor{}, fmt.Errorf("failed to write config: %w", err) } } else { newDesc.Digest, newDesc.Size, err = ingestReader(ctx, cs, ref, resultReader) if err != nil { return ocispec.Descriptor{}, err } } } return newDesc, err } nydus-snapshotter-0.13.4/pkg/errdefs/000077500000000000000000000000001453374237200175365ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/errdefs/errors.go000066400000000000000000000024471453374237200214100ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package errdefs import ( stderrors "errors" "net" "syscall" "github.com/containerd/containerd/errdefs" "github.com/pkg/errors" ) var ( ErrAlreadyExists = errdefs.ErrAlreadyExists ErrNotFound = errdefs.ErrNotFound ErrInvalidArgument = errors.New("invalid argument") ErrUnavailable = errors.New("unavailable") ErrNotImplemented = errors.New("not implemented") // represents not supported and unimplemented ErrDeviceBusy = errors.New("device busy") // represents not supported and unimplemented ) // IsAlreadyExists returns true if the error is due to already exists func IsAlreadyExists(err error) bool { return errors.Is(err, ErrAlreadyExists) } // IsNotFound returns true if the error is due to a missing object func IsNotFound(err error) bool { return errors.Is(err, ErrNotFound) } // IsConnectionClosed returns true if error is due to connection closed // this is used when snapshotter closed by sig term func IsConnectionClosed(err error) bool { switch err := err.(type) { case *net.OpError: return err.Err.Error() == "use of closed network connection" default: return false } } func IsErofsMounted(err error) bool { return stderrors.Is(err, syscall.EBUSY) } nydus-snapshotter-0.13.4/pkg/fanotify/000077500000000000000000000000001453374237200177235ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/fanotify/conn/000077500000000000000000000000001453374237200206605ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/fanotify/conn/conn.go000066400000000000000000000011341453374237200221430ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package conn import ( "bufio" "encoding/json" ) type Client struct { Reader *bufio.Reader } type EventInfo struct { Path string `json:"path"` Size uint32 `json:"size"` Elapsed uint64 `json:"elapsed"` } func (c *Client) GetEventInfo() (*EventInfo, error) { eventInfo := EventInfo{} eventByte, err := c.Reader.ReadBytes('\n') if err != nil { return nil, err } if err := json.Unmarshal(eventByte, &eventInfo); err != nil { return nil, err } return &eventInfo, nil } nydus-snapshotter-0.13.4/pkg/fanotify/fanotify.go000066400000000000000000000074431453374237200221010ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package fanotify import ( "bufio" "encoding/csv" "fmt" "io" "log/syslog" "os" "os/exec" "syscall" "time" "github.com/containerd/nydus-snapshotter/pkg/fanotify/conn" "github.com/containerd/nydus-snapshotter/pkg/utils/display" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) type Server struct { BinaryPath string ContainerPid uint32 ImageName string PersistFile string Readable bool Overwrite bool Timeout time.Duration Client *conn.Client Cmd *exec.Cmd LogWriter *syslog.Writer } func NewServer(binaryPath string, containerPid uint32, imageName string, persistFile string, readable bool, overwrite bool, timeout time.Duration, logWriter *syslog.Writer) *Server { return &Server{ BinaryPath: binaryPath, ContainerPid: containerPid, ImageName: imageName, PersistFile: persistFile, Readable: readable, Overwrite: overwrite, Timeout: timeout, LogWriter: logWriter, } } func (fserver *Server) RunServer() error { if !fserver.Overwrite { if file, err := os.Stat(fserver.PersistFile); err == nil && !file.IsDir() { return nil } } cmd := exec.Command(fserver.BinaryPath) cmd.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: syscall.CLONE_NEWNS, Setpgid: true, } cmd.Env = append(cmd.Env, "_MNTNS_PID="+fmt.Sprint(fserver.ContainerPid)) cmd.Env = append(cmd.Env, "_TARGET=/") cmd.Stderr = fserver.LogWriter notifyR, err := cmd.StdoutPipe() if err != nil { return err } fserver.Client = &conn.Client{ Reader: bufio.NewReader(notifyR), } if err := cmd.Start(); err != nil { return err } fserver.Cmd = cmd go func() { if err := fserver.RunReceiver(); err != nil { logrus.WithError(err).Errorf("Failed to receive event information from server") } }() if fserver.Timeout > 0 { go func() { time.Sleep(fserver.Timeout) fserver.StopServer() }() } return nil } func (fserver *Server) RunReceiver() error { f, err := os.OpenFile(fserver.PersistFile, os.O_CREATE|os.O_WRONLY, 0644) if err != nil { return errors.Wrapf(err, "failed to open file %q", fserver.PersistFile) } defer f.Close() persistCsvFile := fmt.Sprintf("%s.csv", fserver.PersistFile) fCsv, err := os.Create(persistCsvFile) if err != nil { return errors.Wrapf(err, "failed to create file %q", persistCsvFile) } defer fCsv.Close() csvWriter := csv.NewWriter(fCsv) if err := csvWriter.Write([]string{"path", "size", "elapsed"}); err != nil { return errors.Wrapf(err, "failed to write csv header") } csvWriter.Flush() for { eventInfo, err := fserver.Client.GetEventInfo() if err != nil { if err == io.EOF { logrus.Infoln("Get EOF from fanotify server, break event receiver") break } return fmt.Errorf("failed to get event information: %v", err) } if eventInfo != nil { fmt.Fprintln(f, eventInfo.Path) var line []string if fserver.Readable { line = []string{eventInfo.Path, display.ByteToReadableIEC(eventInfo.Size), display.MicroSecondToReadable(eventInfo.Elapsed)} } else { line = []string{eventInfo.Path, fmt.Sprint(eventInfo.Size), fmt.Sprint(eventInfo.Elapsed)} } if err := csvWriter.Write(line); err != nil { return errors.Wrapf(err, "failed to write csv") } csvWriter.Flush() } } return nil } func (fserver *Server) StopServer() { if fserver.Cmd != nil { logrus.Infof("Send SIGTERM signal to process group %d", fserver.Cmd.Process.Pid) if err := syscall.Kill(-fserver.Cmd.Process.Pid, syscall.SIGTERM); err != nil { logrus.WithError(err).Errorf("Stop process group %d failed!", fserver.Cmd.Process.Pid) } if _, err := fserver.Cmd.Process.Wait(); err != nil { logrus.WithError(err).Errorf("Failed to wait for fanotify server") } } } nydus-snapshotter-0.13.4/pkg/filesystem/000077500000000000000000000000001453374237200202705ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/filesystem/config.go000066400000000000000000000040271453374237200220670ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package filesystem import ( "github.com/containerd/nydus-snapshotter/pkg/cache" "github.com/containerd/nydus-snapshotter/pkg/manager" "github.com/containerd/nydus-snapshotter/pkg/referrer" "github.com/containerd/nydus-snapshotter/pkg/signature" "github.com/containerd/nydus-snapshotter/pkg/stargz" "github.com/containerd/nydus-snapshotter/pkg/tarfs" "github.com/pkg/errors" ) type NewFSOpt func(d *Filesystem) error func WithNydusImageBinaryPath(p string) NewFSOpt { return func(fs *Filesystem) error { fs.nydusImageBinaryPath = p return nil } } func WithManagers(managers []*manager.Manager) NewFSOpt { return func(fs *Filesystem) error { if fs.enabledManagers == nil { fs.enabledManagers = map[string]*manager.Manager{} } for _, pm := range managers { fs.enabledManagers[pm.FsDriver] = pm } return nil } } func WithCacheManager(cm *cache.Manager) NewFSOpt { return func(fs *Filesystem) error { if cm == nil { return errors.New("cache manager cannot be nil") } fs.cacheMgr = cm return nil } } func WithReferrerManager(rm *referrer.Manager) NewFSOpt { return func(fs *Filesystem) error { if rm == nil { return errors.New("referrer manager cannot be nil") } fs.referrerMgr = rm return nil } } func WithTarfsManager(tm *tarfs.Manager) NewFSOpt { return func(fs *Filesystem) error { if tm == nil { return errors.New("tarfs manager cannot be nil") } fs.tarfsMgr = tm return nil } } func WithVerifier(verifier *signature.Verifier) NewFSOpt { return func(fs *Filesystem) error { fs.verifier = verifier return nil } } func WithRootMountpoint(mountpoint string) NewFSOpt { return func(fs *Filesystem) error { fs.rootMountpoint = mountpoint return nil } } func WithEnableStargz(enable bool) NewFSOpt { return func(fs *Filesystem) error { if enable { fs.stargzResolver = stargz.NewResolver() } return nil } } nydus-snapshotter-0.13.4/pkg/filesystem/fs.go000066400000000000000000000546711453374237200212440ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ // Abstraction layer of underlying file systems. The file system could be mounted by one // or more nydusd daemons. fs package hides the details package filesystem import ( "context" "os" "path" snpkg "github.com/containerd/containerd/pkg/snapshotters" "github.com/mohae/deepcopy" "github.com/opencontainers/go-digest" "github.com/pkg/errors" "golang.org/x/sync/errgroup" "github.com/containerd/containerd/log" "github.com/containerd/containerd/snapshots" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/config/daemonconfig" "github.com/containerd/nydus-snapshotter/pkg/cache" "github.com/containerd/nydus-snapshotter/pkg/daemon" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/pkg/label" "github.com/containerd/nydus-snapshotter/pkg/manager" racache "github.com/containerd/nydus-snapshotter/pkg/rafs" "github.com/containerd/nydus-snapshotter/pkg/referrer" "github.com/containerd/nydus-snapshotter/pkg/signature" "github.com/containerd/nydus-snapshotter/pkg/stargz" "github.com/containerd/nydus-snapshotter/pkg/tarfs" ) type Filesystem struct { fusedevSharedDaemon *daemon.Daemon fscacheSharedDaemon *daemon.Daemon enabledManagers map[string]*manager.Manager cacheMgr *cache.Manager referrerMgr *referrer.Manager stargzResolver *stargz.Resolver tarfsMgr *tarfs.Manager verifier *signature.Verifier nydusImageBinaryPath string rootMountpoint string } // NewFileSystem initialize Filesystem instance // It does mount image layers by starting nydusd doing FUSE mount or not. func NewFileSystem(ctx context.Context, opt ...NewFSOpt) (*Filesystem, error) { var fs Filesystem for _, o := range opt { err := o(&fs) if err != nil { return nil, err } } recoveringDaemons := make(map[string]*daemon.Daemon, 0) liveDaemons := make(map[string]*daemon.Daemon, 0) for _, fsManager := range fs.enabledManagers { err := fsManager.Recover(ctx, &recoveringDaemons, &liveDaemons) if err != nil { return nil, errors.Wrap(err, "reconnect daemons and recover filesystem instance") } } var hasFscacheSharedDaemon = false var hasFusedevSharedDaemon = false for _, daemon := range liveDaemons { if daemon.States.FsDriver == config.FsDriverFscache { hasFscacheSharedDaemon = true } else if daemon.States.FsDriver == config.FsDriverFusedev && daemon.IsSharedDaemon() { hasFusedevSharedDaemon = true } } for _, daemon := range recoveringDaemons { if daemon.States.FsDriver == config.FsDriverFscache { hasFscacheSharedDaemon = true } else if daemon.States.FsDriver == config.FsDriverFusedev && daemon.IsSharedDaemon() { hasFusedevSharedDaemon = true } } // Try to bring up the shared daemon early. // With found recovering daemons, it must be the case that snapshotter is being restarted. // Situations that shared daemon is not found: // 1. The first time this nydus-snapshotter runs // 2. Daemon record is wrongly deleted from DB. Above reconnecting already gathers // all daemons but still not found shared daemon. The best workaround is to start // a new nydusd for it. // TODO: We still need to consider shared daemon the time sequence of initializing daemon, // start daemon commit its state to DB and retrieving its state. if fscacheManager, ok := fs.enabledManagers[config.FsDriverFscache]; ok { if !hasFscacheSharedDaemon && fs.fscacheSharedDaemon == nil { log.L.Infof("initializing shared nydus daemon for fscache") if err := fs.initSharedDaemon(fscacheManager); err != nil { return nil, errors.Wrap(err, "start shared nydusd daemon for fscache") } } } else if hasFscacheSharedDaemon { return nil, errors.Errorf("shared fscache daemon is present, but manager is missing") } if fusedevManager, ok := fs.enabledManagers[config.FsDriverFusedev]; ok { if config.IsFusedevSharedModeEnabled() && !hasFusedevSharedDaemon && fs.fusedevSharedDaemon == nil { log.L.Infof("initializing shared nydus daemon for fusedev") if err := fs.initSharedDaemon(fusedevManager); err != nil { return nil, errors.Wrap(err, "start shared nydusd daemon for fusedev") } } } else if hasFusedevSharedDaemon { return nil, errors.Errorf("shared fusedev daemon is present, but manager is missing") } // Try to bring all persisted and stopped nydusd up and remount Rafs eg, _ := errgroup.WithContext(context.Background()) for _, d := range recoveringDaemons { d := d eg.Go(func() error { d.ClearVestige() fsManager, err := fs.getManager(d.States.FsDriver) if err != nil { return errors.Wrapf(err, "get filesystem manager for daemon %s", d.States.ID) } if err := fsManager.StartDaemon(d); err != nil { return errors.Wrapf(err, "start daemon %s", d.ID()) } if err := d.WaitUntilState(types.DaemonStateRunning); err != nil { return errors.Wrapf(err, "wait for daemon %s", d.ID()) } if err := d.RecoverRafsInstances(); err != nil { return errors.Wrapf(err, "recover mounts for daemon %s", d.ID()) } fs.TryRetainSharedDaemon(d) return nil }) } if err := eg.Wait(); err != nil { return nil, err } for _, d := range liveDaemons { fs.TryRetainSharedDaemon(d) } return &fs, nil } func (fs *Filesystem) TryRetainSharedDaemon(d *daemon.Daemon) { if d.States.FsDriver == config.FsDriverFscache { if fs.fscacheSharedDaemon == nil { log.L.Debug("retain fscache shared daemon") fs.fscacheSharedDaemon = d d.IncRef() } } else if d.States.FsDriver == config.FsDriverFusedev { if fs.fusedevSharedDaemon == nil && d.HostMountpoint() == fs.rootMountpoint { log.L.Debug("retain fusedev shared daemon") fs.fusedevSharedDaemon = d d.IncRef() } } } func (fs *Filesystem) TryStopSharedDaemon() { if fs.fusedevSharedDaemon != nil { if fs.fusedevSharedDaemon.GetRef() == 1 { if fusedevManager, ok := fs.enabledManagers[config.FsDriverFusedev]; ok { if err := fusedevManager.DestroyDaemon(fs.fusedevSharedDaemon); err != nil { log.L.WithError(err).Errorf("Terminate shared daemon %s failed", fs.fusedevSharedDaemon.ID()) } else { fs.fusedevSharedDaemon = nil } } } } if fs.fscacheSharedDaemon != nil { if fs.fscacheSharedDaemon.GetRef() == 1 { if fscacheManager, ok := fs.enabledManagers[config.FsDriverFscache]; ok { if err := fscacheManager.DestroyDaemon(fs.fscacheSharedDaemon); err != nil { log.L.WithError(err).Errorf("Terminate shared daemon %s failed", fs.fscacheSharedDaemon.ID()) } else { fs.fscacheSharedDaemon = nil } } } } } // WaitUntilReady wait until daemon ready by snapshotID, it will wait until nydus domain socket established // and the status of nydusd daemon must be ready func (fs *Filesystem) WaitUntilReady(snapshotID string) error { rafs := racache.RafsGlobalCache.Get(snapshotID) if rafs == nil { // If NoneDaemon mode, there's no need to wait for daemon ready if config.GetDaemonMode() == config.DaemonModeNone { return nil } return errors.Wrapf(errdefs.ErrNotFound, "no instance %s", snapshotID) } if rafs.GetFsDriver() == config.FsDriverFscache || rafs.GetFsDriver() == config.FsDriverFusedev { d, err := fs.getDaemonByRafs(rafs) if err != nil { return errors.Wrapf(err, "snapshot id %s daemon id %s", snapshotID, rafs.DaemonID) } if err := d.WaitUntilState(types.DaemonStateRunning); err != nil { return err } log.L.Debugf("Nydus remote snapshot %s is ready", snapshotID) } return nil } // Mount will be called when containerd snapshotter prepare remote snapshotter // this method will fork nydus daemon and manage it in the internal store, and indexed by snapshotID // It must set up all necessary resources during Mount procedure and revoke any step if necessary. func (fs *Filesystem) Mount(ctx context.Context, snapshotID string, labels map[string]string, s *storage.Snapshot) (err error) { rafs := racache.RafsGlobalCache.Get(snapshotID) if rafs != nil { // Instance already exists, how could this happen? Can containerd handle this case? return nil } fsDriver := config.GetFsDriver() if label.IsTarfsDataLayer(labels) { fsDriver = config.FsDriverBlockdev } isSharedFusedev := fsDriver == config.FsDriverFusedev && config.GetDaemonMode() == config.DaemonModeShared useSharedDaemon := fsDriver == config.FsDriverFscache || isSharedFusedev var imageID string imageID, ok := labels[snpkg.TargetRefLabel] if !ok { // FIXME: Buildkit does not pass labels defined in containerd‘s fashion. So // we have to use stargz snapshotter specific labels until Buildkit generalize it the necessary // labels for all remote snapshotters. imageID, ok = labels["containerd.io/snapshot/remote/stargz.reference"] if !ok { return errors.Errorf("failed to find image ref of snapshot %s, labels %v", snapshotID, labels) } } rafs, err = racache.NewRafs(snapshotID, imageID, fsDriver) if err != nil { return errors.Wrapf(err, "create rafs instance %s", snapshotID) } defer func() { if err != nil { racache.RafsGlobalCache.Remove(snapshotID) } }() fsManager, err := fs.getManager(fsDriver) if err != nil { return errors.Wrapf(err, "get filesystem manager for snapshot %s", snapshotID) } var d *daemon.Daemon if fsDriver == config.FsDriverFscache || fsDriver == config.FsDriverFusedev { bootstrap, err := rafs.BootstrapFile() if err != nil { return errors.Wrapf(err, "find bootstrap file snapshot %s", snapshotID) } if useSharedDaemon { d, err = fs.getSharedDaemon(fsDriver) if err != nil { return err } } else { mp, err := fs.decideDaemonMountpoint(fsDriver, false, rafs) if err != nil { return err } d, err = fs.createDaemon(fsManager, config.DaemonModeDedicated, mp, 0) // if daemon already exists for snapshotID, just return if err != nil && !errdefs.IsAlreadyExists(err) { return err } } // Nydusd uses cache manager's directory to store blob caches. So cache // manager knows where to find those blobs. cacheDir := fs.cacheMgr.CacheDir() // Fscache driver stores blob cache bitmap and blob header files here workDir := rafs.FscacheWorkDir() params := map[string]string{ daemonconfig.Bootstrap: bootstrap, daemonconfig.WorkDir: workDir, daemonconfig.CacheDir: cacheDir, } cfg := deepcopy.Copy(*fsManager.DaemonConfig).(daemonconfig.DaemonConfig) err = daemonconfig.SupplementDaemonConfig(cfg, imageID, snapshotID, false, labels, params) if err != nil { return errors.Wrap(err, "supplement configuration") } // TODO: How to manage rafs configurations on-disk? separated json config file or DB record? // In order to recover erofs mount, the configuration file has to be persisted. var configSubDir string if useSharedDaemon { configSubDir = snapshotID } else { // Associate daemon config object when creating a new daemon object to avoid // reading disk file again and again. // For shared daemon, each rafs instance has its own configuration, so we don't // attach a config interface to daemon in this case. d.Config = cfg } err = cfg.DumpFile(d.ConfigFile(configSubDir)) if err != nil { if errors.Is(err, errdefs.ErrAlreadyExists) { log.L.Debugf("Configuration file %s already exits", d.ConfigFile(configSubDir)) } else { return errors.Wrap(err, "dump daemon configuration file") } } d.AddRafsInstance(rafs) // if publicKey is not empty we should verify bootstrap file of image err = fs.verifier.Verify(labels, bootstrap) if err != nil { return errors.Wrapf(err, "verify signature of daemon %s", d.ID()) } } switch fsDriver { case config.FsDriverFscache: err = fs.mountRemote(fsManager, useSharedDaemon, d, rafs) if err != nil { err = errors.Wrapf(err, "mount file system by daemon %s, snapshot %s", d.ID(), snapshotID) } case config.FsDriverFusedev: err = fs.mountRemote(fsManager, useSharedDaemon, d, rafs) if err != nil { err = errors.Wrapf(err, "mount file system by daemon %s, snapshot %s", d.ID(), snapshotID) } case config.FsDriverBlockdev: err = fs.tarfsMgr.MountTarErofs(snapshotID, s, labels, rafs) if err != nil { err = errors.Wrapf(err, "mount tarfs for snapshot %s", snapshotID) } case config.FsDriverNodev: // Nothing to do case config.FsDriverProxy: if label.IsNydusProxyMode(labels) { if v, ok := labels[label.CRILayerDigest]; ok { rafs.AddAnnotation(label.CRILayerDigest, v) } rafs.AddAnnotation(label.NydusProxyMode, "true") rafs.SetMountpoint(path.Join(rafs.GetSnapshotDir(), "fs")) } default: err = errors.Errorf("unknown filesystem driver %s for snapshot %s", fsDriver, snapshotID) } // Persist it after associate instance after all the states are calculated. if err == nil { if err := fsManager.AddRafsInstance(rafs); err != nil { return errors.Wrapf(err, "create instance %s", snapshotID) } } if err != nil { _ = fs.Umount(ctx, snapshotID) return err } return nil } func (fs *Filesystem) Umount(ctx context.Context, snapshotID string) error { rafs := racache.RafsGlobalCache.Get(snapshotID) if rafs == nil { log.L.Debugf("no RAFS filesystem instance associated with snapshot %s", snapshotID) return nil } fsDriver := rafs.GetFsDriver() if fsDriver == config.FsDriverNodev { return nil } fsManager, err := fs.getManager(fsDriver) if err != nil { return errors.Wrapf(err, "get manager for filesystem instance %s", rafs.DaemonID) } switch fsDriver { case config.FsDriverFscache, config.FsDriverFusedev: daemon, err := fs.getDaemonByRafs(rafs) if err != nil { log.L.Debugf("snapshot %s has no associated nydusd", snapshotID) return errors.Wrapf(err, "get daemon with ID %s for snapshot %s", rafs.DaemonID, snapshotID) } daemon.RemoveRafsInstance(snapshotID) if err := fsManager.RemoveRafsInstance(snapshotID); err != nil { return errors.Wrapf(err, "remove snapshot %s", snapshotID) } if err := daemon.UmountRafsInstance(rafs); err != nil { return errors.Wrapf(err, "umount instance %s", snapshotID) } // Once daemon's reference reaches 0, destroy the whole daemon if daemon.GetRef() == 0 { if err := fsManager.DestroyDaemon(daemon); err != nil { return errors.Wrapf(err, "destroy daemon %s", daemon.ID()) } } case config.FsDriverBlockdev: if err := fs.tarfsMgr.UmountTarErofs(snapshotID); err != nil { return errors.Wrapf(err, "umount tar erofs on snapshot %s", snapshotID) } if err := fsManager.RemoveRafsInstance(snapshotID); err != nil { return errors.Wrapf(err, "remove snapshot %s", snapshotID) } case config.FsDriverNodev, config.FsDriverProxy: // Nothing to do default: return errors.Errorf("unknown filesystem driver %s for snapshot %s", fsDriver, snapshotID) } return nil } // How much space the layer/blob cache filesystem is occupying // The blob digest mush have `sha256:` prefixed, otherwise, throw errors. func (fs *Filesystem) CacheUsage(ctx context.Context, blobDigest string) (snapshots.Usage, error) { log.L.Infof("cache usage %s", blobDigest) digest := digest.Digest(blobDigest) if err := digest.Validate(); err != nil { return snapshots.Usage{}, errors.Wrapf(err, "invalid blob digest from label %q, digest=%s", snpkg.TargetLayerDigestLabel, blobDigest) } blobID := digest.Hex() return fs.cacheMgr.CacheUsage(ctx, blobID) } func (fs *Filesystem) RemoveCache(blobDigest string) error { log.L.Infof("remove cache %s", blobDigest) digest := digest.Digest(blobDigest) if err := digest.Validate(); err != nil { return errors.Wrapf(err, "invalid blob digest from label %q, digest=%s", snpkg.TargetLayerDigestLabel, blobDigest) } blobID := digest.Hex() if fscacheManager, ok := fs.enabledManagers[config.FsDriverFscache]; ok { if fscacheManager != nil { c, err := fs.fscacheSharedDaemon.GetClient() if err != nil { return err } // delete fscache blob cache file // TODO: skip error for blob not existing if err := c.UnbindBlob("", blobID); err != nil { return err } return nil } } return fs.cacheMgr.RemoveBlobCache(blobID) } // Try to stop all the running daemons if they are not referenced by any snapshots // Clean up resources along with the daemons. func (fs *Filesystem) Teardown(ctx context.Context) error { for _, fsManager := range fs.enabledManagers { if fsManager.FsDriver == config.FsDriverFscache || fsManager.FsDriver == config.FsDriverFusedev { for _, d := range fsManager.ListDaemons() { for _, instance := range d.RafsCache.List() { err := fs.Umount(ctx, instance.SnapshotID) if err != nil { log.L.Errorf("Failed to umount snapshot %s, %s", instance.SnapshotID, err) } } } // } else if fsManager.FsDriver == config.FsDriverBlockdev { // TODO: support tarfs } } return nil } func (fs *Filesystem) MountPoint(snapshotID string) (string, error) { rafs := racache.RafsGlobalCache.Get(snapshotID) if rafs != nil { return rafs.GetMountpoint(), nil } return "", errdefs.ErrNotFound } func (fs *Filesystem) BootstrapFile(id string) (string, error) { rafs := racache.RafsGlobalCache.Get(id) if rafs == nil { return "", errors.Errorf("no RAFS instance for %s", id) } return rafs.BootstrapFile() } // daemon mountpoint to rafs mountpoint // calculate rafs mountpoint for snapshots mount slice. func (fs *Filesystem) mountRemote(fsManager *manager.Manager, useSharedDaemon bool, d *daemon.Daemon, r *racache.Rafs) error { if useSharedDaemon { if fsManager.FsDriver == config.FsDriverFusedev { r.SetMountpoint(path.Join(d.HostMountpoint(), r.SnapshotID)) } else { r.SetMountpoint(path.Join(r.GetSnapshotDir(), "mnt")) } if err := d.SharedMount(r); err != nil { return errors.Wrapf(err, "failed to mount") } } else { r.SetMountpoint(path.Join(d.HostMountpoint())) err := fsManager.StartDaemon(d) if err != nil { return errors.Wrapf(err, "start daemon") } } return nil } func (fs *Filesystem) decideDaemonMountpoint(fsDriver string, isSharedDaemonMode bool, rafs *racache.Rafs) (string, error) { m := "" if fsDriver == config.FsDriverFscache || fsDriver == config.FsDriverFusedev { if isSharedDaemonMode { m = fs.rootMountpoint } else { m = path.Join(rafs.GetSnapshotDir(), "mnt") } if err := os.MkdirAll(m, 0755); err != nil { return "", errors.Wrapf(err, "create directory %s", m) } } return m, nil } // 1. Create a daemon instance // 2. Build command line // 3. Start daemon func (fs *Filesystem) initSharedDaemon(fsManager *manager.Manager) (err error) { var daemonMode config.DaemonMode switch fsManager.FsDriver { case config.FsDriverFscache: daemonMode = config.DaemonModeShared case config.FsDriverFusedev: daemonMode = config.DaemonModeShared default: return errors.Errorf("unsupported filesystem driver %s", fsManager.FsDriver) } mp, err := fs.decideDaemonMountpoint(fsManager.FsDriver, true, nil) if err != nil { return err } else if mp == "" { return errors.Errorf("got null mountpoint for fsDriver %s", fsManager.FsDriver) } d, err := fs.createDaemon(fsManager, daemonMode, mp, 0) if err != nil { return errors.Wrap(err, "initialize shared daemon") } // FIXME: Daemon record should not be removed after starting daemon failure. defer func() { if err != nil { if err := fsManager.DeleteDaemon(d); err != nil { log.L.Errorf("Start nydusd daemon error %v", err) } } }() // Shared nydusd daemon does not need configuration to start process but // it is loaded when requesting mount api // Dump the configuration file since it is reloaded when recovering the nydusd d.Config = *fsManager.DaemonConfig err = d.Config.DumpFile(d.ConfigFile("")) if err != nil && !errors.Is(err, errdefs.ErrAlreadyExists) { return errors.Wrapf(err, "dump configuration file %s", d.ConfigFile("")) } if err := fsManager.StartDaemon(d); err != nil { return errors.Wrap(err, "start shared daemon") } fs.TryRetainSharedDaemon(d) return } // createDaemon create new nydus daemon by snapshotID and imageID func (fs *Filesystem) createDaemon(fsManager *manager.Manager, daemonMode config.DaemonMode, mountpoint string, ref int32) (d *daemon.Daemon, err error) { opts := []daemon.NewDaemonOpt{ daemon.WithRef(ref), daemon.WithSocketDir(config.GetSocketRoot()), daemon.WithConfigDir(config.GetConfigRoot()), daemon.WithLogDir(config.GetLogDir()), daemon.WithLogLevel(config.GetLogLevel()), daemon.WithLogRotationSize(config.GetDaemonLogRotationSize()), daemon.WithLogToStdout(config.GetLogToStdout()), daemon.WithNydusdThreadNum(config.GetDaemonThreadsNumber()), daemon.WithFsDriver(fsManager.FsDriver), daemon.WithDaemonMode(daemonMode), } // For fscache driver, no need to provide mountpoint to nydusd daemon. if mountpoint != "" { opts = append(opts, daemon.WithMountpoint(mountpoint)) } d, err = daemon.NewDaemon(opts...) if err != nil { return nil, errors.Wrapf(err, "new daemon") } if err = fsManager.AddDaemon(d); err != nil { return nil, err } if fsManager.SupervisorSet != nil { // Supervisor is strongly associated with real running nydusd daemon. su := fsManager.SupervisorSet.NewSupervisor(d.ID()) if su == nil { _ = fsManager.DeleteDaemon(d) return nil, errors.Errorf("create supervisor for daemon %s", d.ID()) } d.Supervisor = su } return d, nil } func (fs *Filesystem) getManager(fsDriver string) (*manager.Manager, error) { if fsManager, ok := fs.enabledManagers[fsDriver]; ok { return fsManager, nil } return nil, errors.Errorf("no manager for filesystem driver %s", fsDriver) } func (fs *Filesystem) getSharedDaemon(fsDriver string) (*daemon.Daemon, error) { switch fsDriver { case config.FsDriverFscache: if fs.fscacheSharedDaemon != nil { return fs.fscacheSharedDaemon, nil } case config.FsDriverFusedev: if fs.fusedevSharedDaemon != nil { return fs.fusedevSharedDaemon, nil } } return nil, errors.Errorf("no shared daemon for filesystem driver %s", fsDriver) } func (fs *Filesystem) getDaemonByRafs(rafs *racache.Rafs) (*daemon.Daemon, error) { switch rafs.GetFsDriver() { case config.FsDriverFscache, config.FsDriverFusedev: if fsManager, ok := fs.enabledManagers[rafs.GetFsDriver()]; ok { if d := fsManager.GetByDaemonID(rafs.DaemonID); d != nil { return d, nil } } } return nil, errdefs.ErrNotFound } func (fs *Filesystem) GetDaemonByID(id string) (*daemon.Daemon, error) { for _, manager := range fs.enabledManagers { if d := manager.GetByDaemonID(id); d != nil { return d, nil } } return nil, errdefs.ErrNotFound } nydus-snapshotter-0.13.4/pkg/filesystem/referer_adaptor.go000066400000000000000000000026511453374237200237670ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package filesystem import ( "context" "fmt" snpkg "github.com/containerd/containerd/pkg/snapshotters" "github.com/opencontainers/go-digest" "github.com/pkg/errors" ) func (fs *Filesystem) ReferrerDetectEnabled() bool { return fs.referrerMgr != nil } func (fs *Filesystem) CheckReferrer(ctx context.Context, labels map[string]string) bool { if !fs.ReferrerDetectEnabled() { return false } ref, ok := labels[snpkg.TargetRefLabel] if !ok { return false } manifestDigest := digest.Digest(labels[snpkg.TargetManifestDigestLabel]) if manifestDigest.Validate() != nil { return false } if _, err := fs.referrerMgr.CheckReferrer(ctx, ref, manifestDigest); err != nil { return false } return true } func (fs *Filesystem) TryFetchMetadata(ctx context.Context, labels map[string]string, metadataPath string) error { ref, ok := labels[snpkg.TargetRefLabel] if !ok { return fmt.Errorf("empty label %s", snpkg.TargetRefLabel) } manifestDigest := digest.Digest(labels[snpkg.TargetManifestDigestLabel]) if err := manifestDigest.Validate(); err != nil { return fmt.Errorf("invalid label %s=%s", snpkg.TargetManifestDigestLabel, manifestDigest) } if err := fs.referrerMgr.TryFetchMetadata(ctx, ref, manifestDigest, metadataPath); err != nil { return errors.Wrap(err, "try fetch metadata") } return nil } nydus-snapshotter-0.13.4/pkg/filesystem/stargz_adaptor.go000066400000000000000000000171321453374237200236470ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package filesystem import ( "context" "fmt" "io" "os" "os/exec" "path/filepath" "strings" "time" "github.com/KarpelesLab/reflink" "github.com/containerd/containerd/log" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/pkg/auth" "github.com/containerd/nydus-snapshotter/pkg/label" "github.com/containerd/nydus-snapshotter/pkg/stargz" "github.com/containerd/nydus-snapshotter/pkg/utils/registry" "github.com/opencontainers/go-digest" "github.com/pkg/errors" ) func (fs *Filesystem) UpperPath(id string) string { return filepath.Join(config.GetSnapshotsRootDir(), id, "fs") } func (fs *Filesystem) StargzEnabled() bool { return fs.stargzResolver != nil } // Detect if the blob is type of estargz by downloading its footer since estargz image does not // have any characteristic annotation. func (fs *Filesystem) IsStargzDataLayer(labels map[string]string) (bool, *stargz.Blob) { ref, layerDigest := registry.ParseLabels(labels) if ref == "" || layerDigest == "" { return false, nil } log.L.Infof("Checking stargz image ref %s digest %s", ref, layerDigest) keychain, err := auth.GetKeyChainByRef(ref, labels) if err != nil { log.L.WithError(err).Warn("get keychain from image reference") return false, nil } blob, err := fs.stargzResolver.GetBlob(ref, layerDigest, keychain) if err != nil { log.L.WithError(err).Warn("get stargz blob") return false, nil } off, err := blob.GetTocOffset() if err != nil { log.L.WithError(err).Warn("get toc offset") return false, nil } if off <= 0 { log.L.WithError(err).Warnf("Invalid stargz toc offset %d", off) return false, nil } return true, blob } func (fs *Filesystem) MergeStargzMetaLayer(ctx context.Context, s storage.Snapshot) error { mergedDir := fs.UpperPath(s.ParentIDs[0]) mergedBootstrap := filepath.Join(mergedDir, "image.boot") if _, err := os.Stat(mergedBootstrap); err == nil { return nil } bootstraps := []string{} for idx, snapshotID := range s.ParentIDs { files, err := os.ReadDir(fs.UpperPath(snapshotID)) if err != nil { return errors.Wrap(err, "read snapshot dir") } bootstrapName := "" blobMetaName := "" for _, file := range files { if digest.Digest(fmt.Sprintf("sha256:%s", file.Name())).Validate() == nil { bootstrapName = file.Name() } if strings.HasSuffix(file.Name(), "blob.meta") { blobMetaName = file.Name() } } if bootstrapName == "" { return fmt.Errorf("can't find bootstrap for snapshot %s", snapshotID) } // The blob meta file is generated in corresponding snapshot dir for each layer, // but we need copy them to fscache work dir for nydusd use. This is not an // efficient method, but currently nydusd only supports reading blob meta files // from the same dir, so it is a workaround. If performance is a concern, it is // best to convert the estargz image TOC file to a bootstrap / blob meta file // at build time. if blobMetaName != "" && idx != 0 { sourcePath := filepath.Join(fs.UpperPath(snapshotID), blobMetaName) // This path is same with `d.FscacheWorkDir()`, it's for fscache work dir. targetPath := filepath.Join(fs.UpperPath(s.ParentIDs[0]), blobMetaName) if err := reflink.Auto(sourcePath, targetPath); err != nil { return errors.Wrap(err, "copy source blob.meta to target") } } bootstrapPath := filepath.Join(fs.UpperPath(snapshotID), bootstrapName) bootstraps = append([]string{bootstrapPath}, bootstraps...) } if len(bootstraps) == 1 { if err := reflink.Auto(bootstraps[0], mergedBootstrap); err != nil { return errors.Wrap(err, "copy source meta blob to target") } } else { tf, err := os.CreateTemp(mergedDir, "merging-stargz") if err != nil { return errors.Wrap(err, "create temp file for merging stargz layers") } defer func() { if err != nil { os.Remove(tf.Name()) } tf.Close() }() options := []string{ "merge", "--bootstrap", tf.Name(), } options = append(options, bootstraps...) cmd := exec.Command(fs.nydusImageBinaryPath, options...) cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout log.G(ctx).Infof("nydus image command %v", options) err = cmd.Run() if err != nil { return errors.Wrap(err, "merging stargz layers") } err = os.Rename(tf.Name(), mergedBootstrap) if err != nil { return errors.Wrap(err, "rename merged stargz layers") } if err := os.Chmod(mergedBootstrap, 0440); err != nil { return err } } return nil } // Generate nydus bootstrap from stargz layers // Download estargz TOC part from each layer as `nydus-image` conversion source. // After conversion, a nydus metadata or bootstrap is used to pointing to each estargz blob func (fs *Filesystem) PrepareStargzMetaLayer(blob *stargz.Blob, storagePath string, labels map[string]string) error { ref := blob.GetImageReference() layerDigest := blob.GetDigest() if !fs.StargzEnabled() { return fmt.Errorf("stargz compatibility is not enabled") } blobID := digest.Digest(layerDigest).Hex() convertedBootstrap := filepath.Join(storagePath, blobID) stargzFile := filepath.Join(storagePath, stargz.TocFileName) if _, err := os.Stat(convertedBootstrap); err == nil { return nil } start := time.Now() defer func() { duration := time.Since(start) log.L.Infof("total stargz prepare layer duration %d", duration.Milliseconds()) }() r, err := blob.ReadToc() if err != nil { return errors.Wrapf(err, "read TOC, image reference: %s, layer digest: %s", ref, layerDigest) } starGzToc, err := os.OpenFile(stargzFile, os.O_CREATE|os.O_RDWR, 0640) if err != nil { return errors.Wrap(err, "create stargz index") } defer starGzToc.Close() _, err = io.Copy(starGzToc, r) if err != nil { return errors.Wrap(err, "save stargz index") } err = os.Chmod(stargzFile, 0440) if err != nil { return err } blobMetaPath := filepath.Join(fs.cacheMgr.CacheDir(), fmt.Sprintf("%s.blob.meta", blobID)) if config.GetFsDriver() == config.FsDriverFscache { // For fscache, the cache directory is managed linux fscache driver, so the blob.meta file // can't be stored there. if err := os.MkdirAll(storagePath, 0750); err != nil { return errors.Wrapf(err, "failed to create fscache work dir %s", storagePath) } blobMetaPath = filepath.Join(storagePath, fmt.Sprintf("%s.blob.meta", blobID)) } tf, err := os.CreateTemp(storagePath, "converting-stargz") if err != nil { return errors.Wrap(err, "create temp file for merging stargz layers") } defer func() { if err != nil { os.Remove(tf.Name()) } tf.Close() }() options := []string{ "create", "--source-type", "stargz_index", "--bootstrap", tf.Name(), "--blob-id", blobID, "--repeatable", "--disable-check", // FIXME: allow user to specify fs version and automatically detect // chunk size and compressor from estargz TOC file. "--fs-version", "6", "--chunk-size", "0x400000", "--blob-meta", blobMetaPath, } options = append(options, filepath.Join(storagePath, stargz.TocFileName)) cmd := exec.Command(fs.nydusImageBinaryPath, options...) cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout log.L.Infof("nydus image command %v", options) err = cmd.Run() if err != nil { return errors.Wrap(err, "converting stargz layer") } err = os.Rename(tf.Name(), convertedBootstrap) if err != nil { return errors.Wrap(err, "rename converted stargz layer") } if err := os.Chmod(convertedBootstrap, 0440); err != nil { return err } return nil } func (fs *Filesystem) StargzLayer(labels map[string]string) bool { return labels[label.StargzLayer] != "" } nydus-snapshotter-0.13.4/pkg/filesystem/tarfs_adaptor.go000077500000000000000000000050051453374237200234530ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package filesystem import ( "context" "github.com/containerd/containerd/log" snpkg "github.com/containerd/containerd/pkg/snapshotters" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/nydus-snapshotter/pkg/label" "github.com/opencontainers/go-digest" "github.com/pkg/errors" ) func (fs *Filesystem) TarfsEnabled() bool { return fs.tarfsMgr != nil } func (fs *Filesystem) PrepareTarfsLayer(ctx context.Context, labels map[string]string, snapshotID, upperDirPath string) error { ref, ok := labels[snpkg.TargetRefLabel] if !ok { return errors.Errorf("not found image reference label") } layerDigest := digest.Digest(labels[snpkg.TargetLayerDigestLabel]) if layerDigest.Validate() != nil { return errors.Errorf("not found layer digest label") } manifestDigest := digest.Digest(labels[snpkg.TargetManifestDigestLabel]) if manifestDigest.Validate() != nil { return errors.Errorf("not found manifest digest label") } ok, err := fs.tarfsMgr.CheckTarfsHintAnnotation(ctx, ref, manifestDigest) if err != nil { return errors.Wrapf(err, "check tarfs hint annotaion") } if !ok { return errors.Errorf("this image is not recommended for tarfs") } limiter := fs.tarfsMgr.GetConcurrentLimiter(ref) if limiter != nil { if err := limiter.Acquire(context.Background(), 1); err != nil { return errors.Wrapf(err, "concurrent limiter acquire") } } if err := fs.tarfsMgr.PrepareLayer(snapshotID, ref, manifestDigest, layerDigest, upperDirPath); err != nil { log.L.WithError(err).Errorf("async prepare tarfs layer of snapshot ID %s", snapshotID) } if limiter != nil { limiter.Release(1) } layerBlobID := layerDigest.Hex() labels[label.NydusTarfsLayer] = layerBlobID return nil } func (fs *Filesystem) MergeTarfsLayers(s storage.Snapshot, storageLocater func(string) string) error { return fs.tarfsMgr.MergeLayers(s, storageLocater) } func (fs *Filesystem) DetachTarfsLayer(snapshotID string) error { return fs.tarfsMgr.DetachLayer(snapshotID) } func (fs *Filesystem) ExportBlockData(s storage.Snapshot, perLayer bool, labels map[string]string, storageLocater func(string) string) ([]string, error) { return fs.tarfsMgr.ExportBlockData(s, perLayer, labels, storageLocater) } func (fs *Filesystem) GetTarfsImageDiskFilePath(id string) (string, error) { if fs.tarfsMgr == nil { return "", errors.New("tarfs mode is not enabled") } return fs.tarfsMgr.ImageDiskFilePath(id), nil } nydus-snapshotter-0.13.4/pkg/filesystem/testdata/000077500000000000000000000000001453374237200221015ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/filesystem/testdata/invalid-bootstrap-file-size-133513.tar.gz000066400000000000000000001356241453374237200313260ustar00rootroot00000000000000YkȚ~;sz {GTlWDAAT2EZ5UsԇmJKd "s_Pޮq41`8F/}tTEi/yG۹g I'1oi/`17S ( Ba3RTAg;a񂲓;njvONt»O+}i0}aqo=?>,?z|t (;=uN:heAՆr[,STva">ڍںG/iIPS5a>)&hUh|{Vύ[c"/y_ePKn*ub80|xԹ?6U "TXFE((,:_Y:(nEwP?nIpS`9OŹ((ߗ[?>5ʰĆ]89BAđP0ҳXLJ+g]h0>U׾ '|(e Οi?讯n6<e' to7\6w3zI i[wCFꇿ?vϝv`s!?ϼ3o?q ^{5vNXuw wM6 ca\]%vf 3_M*-\gr6<1uK,PiR8hMkK_P9x*Y`/tDgbIӵ`#cAR=/IYI^M xkAFG (Q)fgH{YF a?e;'GA/i=pc7C!Ff i,Nqtס;h/^漛Zi& K^z.Tyqf#kFe- u^[tm^^fQ49.ח.b_@5afWZ7Od'o5{=X2VDZ l1­`'Kae&жQEDtN}ҏtOr>Rdd|E8v$:=eTdFl3㨭A(*kJ|vZEexT׶<ħ8ra.ˁ>~_wmk6B3rrЫ~p _&zx 8@*882t% d 2;FA֪cૈa"cwCR~߰>tVM49 єdBw2:hfI 5jc{')fRI*2},16` E$Aوf#4Cm}v>a]e{3s 1,2b|fĕy}efD H^8D=WaN e ʍ𜜞 `Y-p0-IRޥiXkNEo?0拆1(\.3>+FַyV`.\cذxme%cp  .mAv\ <FIU6b9mY3d>g|\{*wPz&yp1lºW-6nD q8 (c\sLlxC` NԈcQK $M;I5$%(:X' M [AZޜI`J e  0]@0Ѯp  ZIX$ڣaq_]T\ OͅSuhk 6sLqFygQuIw.Dz/% MWk~w"#>{ip3t:uS;YXTY8+][T$i0šTXG'`&Sty# j-pTe L#hn%Kt YL9ZD0ScBԶrAJHG` ~erBMfD;񼉅פVo/ԝjM0CF8Wx+ne} XT;=].qrԐuգBH%k:E*5}hvʓU%,bP8_`߅)L<.!}qF`r9'1%mEhR. %\Bw/]_. E "E> rs*K*ɦt;&J`7NŴr#2n/7yY%.`\F{)ll" yyt,0s ',\V[^eVqmdTK8v@];AkZpH1"@ϗ$Bcd2]b0 6\WHBYl=7 9(`,A(ơ K6jF qj nfn׵(`1鎧x W3psG1Co+o'/]m {#{3OE]1,5ځ{҂ 1>ybSbŭp ԰$ayMQ8p(] WPc9KjrTed,dxd.GҹcOuUPtH^ۼE2]˜LKk&ZJv`5-%$.kiS)V2uP"3CX>͑.Y/-~9p:jY\nJD$V=UⰦ[TnDoVz(mqʌuF$cC}R7J +t"\ei=vۄ UY0 7bKg[ٓG6DNv~65=8?r$u="k)IMwnNx6+}&g(ǫ 8=7+fc2pJR`ˑ`{ˉ]VJ_02φ#Io6#)7vcM=>kFk~{uM]p(1]KeqQ 9X}{f(f?ѥ+w;)r  PI:VST3 ^ jz)aሧ 3%9כD* r ԻovT~ڠs.ES$em!j"=}YQ`M`ѨH0prv=\N|݇mv6JdOhroy|M˹S/LJL{mʱ#6p^Om3v.{QxiyHFR#[ZVN~ ʄ[0pFWՅ/fֲiTKTdV{@U:uW3a.e&ܶ}L2BuNGpb kܘ&ä]6s:8nv^cq ' qP 6U^O=_ryUt+bks#ᇁy~8p 0m#+stDF~fZX/T X*~! fUiANT9v?J(\ڶm03 !',\[vjwP~ZT+DAY&KPAX}ΰl1{ kl]a;\$ˆM19V6N '*r'T0-}ap扷(fVE맸TBm5*D8ƄF&(8F򴥾ޚi{\\ň\oC ng}yڪc$r&Gq|vBO3<`'+DE([!gmEQbQ /3k h7}2y.IB{61dn:5e*[$3_߸g̾aVg'ɝ<<{spr._:66H|\Bw|JJ©%2 PG|`pHI^/Ɉ.CZ/?X(\{ˎ+s wNDڷ >h!a}F|{Ԭ.WWBV쬃^=K ١DVI\<˚j³bϪǏsEyGs%_;M|$Ől|xSbl:jqv:d(<]cl{XCpٌCa~;I3]/z hN:O\Z1UGJ˨ۑۭn#WY~y6*h>#kYA] Gh۷Ĕp>Aex J[h1WP_v.eފ¨` vc0C0 _-ߗ?~>G:Dh|d E|瑗Egpx'kuaJU)n^{1~L 4F,a|mm\xU{NbSBD2Yc+M+xR(EJ01pa*dw*SU 'xt,&lˉs߇:?}cDGH<ݍcŬnqYn6šy6^*o_>ӨÎE*KV{6ry^ZҊt@ȈX#=ր_1f 388 ro} Y⃚}}3#(%`  #5R}r[)Y_ljv(MYMQ80+qhչTKY^MlCVU۝LU,}PC_ec)d|(6g=kB c+9*aMTbM5qV '%ktӽqp ÷W|I9[:ڿq]Y \;$5b1O!_I6[т"E C#^@t/ˋUK3R+\c}< <[CRXBk) dIP:Lw~4[.bRJG.>~UM͊ t0HץxN.}t;LyVG.>hOޏp#%y Q)مČa8L,q @r-{D<߾$nK1 RJNxԷrtz| /qhϧr/]^g#1E\\'h;ɜ] ]T{·(/"@wFGF'L^Ӵ=F<+x$oO!}Etԡi$$R|ܧJuث'/%@f4K~<ɻ^c _wnNkl ݙ. y| MC[z);\@\q }Z{1Kkc7#qASҭO5ϐ>;_@R_ FN0>0 ǩ4hgacHq%5#jDan    a‹N# 9En^ `hS.E^cxϡGM F@ n ^@M#LScS}_a@|1 Ɩ`$4 D ףP>@6 /] G`Un9k\kq#P (ѡ|slr6eY;O˲duX>vR/axQ|PY>I2;?cɻ]=/9nQx4n绪^UU󸉕1D0.V =E+)_WDne(6|qAɹ[ J<A$Pj8_a1a87I!gA`] ;gS(k@aW,[wdf] ׷{v;_E@A%EZ$=wYxƛR35/0P5+MiWs!Aʧ0|K1Ә<{"v݁&R='rX%xǂcZzzY{8n30 ĒS[mһNӧ!jy<o7"`%.MӾMRX1zո m sikyE}]?` -~mt[:`-p(~e=˳>r9HgWp5DDo3\ 68=MOlQ n5s 7 R_opvma¶G+XxB V6vPUR6ίm^&ٍBÿ,8|nQ T J߷NquOļKev쐅7us@Y6M3tΙGh!% B$eÔWH]lnY%zOZ<%Z@^x[;8T8:."\;0lp_2ytL=8 ֣Na+{tΘ+]_ccMpCsOfu ڧ-țڞ/~<{Ծd!m;(4SM;8GgƇذ*XS;_O5!{MZZJ'0Ks0ib_Qoc`ml @ZQp%nw|5\=O!?-STp/ADh;D $ l= oFyDdu³#qOϷï9vZ[Y" Tw2EBJo&%`JgO[esŻ.%9wWNG-*'0Ԁ8cK@X(n= FrIh[L%y؝1W԰}`nq\Q=Tq-ܫ(DޝB&>9Glk'r.hgu2- dTFAR3i6>}, \ʴԾ9#9~ IUs0pidw;~O G$y0cy!]Ӯ2bY馩o*FMR/|!pe(8 :chPHﲂgPu m'=gb&mQH2ਓ(2/1vguA(Eڎ: l=%׈HIZ>5SbToK?@_<-EEaױn)7je}B9'bQo)٣Gʪ#Zm6u0ݣ=:ַ*F,sSUy֯k9Ҩ~-+a؎J 6jXrmDx4qU9OEg7!,e|rbaj:ު&UvlV^Jߞ_qB,2 |lSK;Ott-R9H.mU^jZ"rŮAPwYe9 "\Qz t:l`\L^0M@%Ӝ3"BN]~w*r+o;J̯`xJirpBXYE uɊ`nԳqXG8xFHXӤWPʝkq6ZYe"o}Y5QD1\GDtzqHq-sH wjUf ߖ^}GJ)9kaPl+<}+T?]Mfɾ҅h+U%Zmږ)Yi^:s?dۥg#WG@͙7'?h5:|}xo_x{-tmBhC$b1F R*=Bg%Lwc)Z[>9Bޏ?u| f ~ i+ݓVpnEg(ok/:~R_sj n͹ܦI'hEXmuߴAp1/:sT zɠ 3>ͨ ÷@nE<]ySUOWO]g?Ic 1^S.OШé4fD8tuS:sLM#@˿=*osdxc7^l88UX);+itspߖC- 4آ0pS8ps:̶3VM#⭼kk䉺L]@b)~XN_I筮:|%! ٣ Wm%=_v%@X&`rwnSvT#ln۰ʰQi TM)m:Xf+:dt38zM:+[zdCȮä'18{RɘXo )Re?MOF>0Tjim7%UإO3gZFļe B#3F#&-iv4] Z{wA,( 5>``ӳ^OQOqWvaA1ac=-_-ݵa ~J9|Ԏ V"8>F!H _ߕUf=}+o7n{IP*)Cqo 3kM#O7QrwOHa#6|Korg ˥lv g:T$FDNNC»Yʝ荬:x7ň*m;-|.v[|7NzaX*՛l9#4{JRNJrt vj Ґw'RkL~S-'4(G|w. oNѫql;O_͑_PpZ|RV$J'&y`N-ʘk5;_y{6rau^1\H &4 ! }D/(7>BED)<9jo\W#uVGs{+M^uń0jF:Wiwu^yvR {e;\{SΟĔ#+hHvXd.db~uJymu Pjdy0}'^a&'U'؟<^О|߀8MF`" _.8v^_XE;<^ 0T^0kkUWK9hn t/CvYN 3<:r'j.(JB%Iu<(<,$8y\S3bb/oWݨD?HG!I B#y71U72#o;5 P7ʼnAj4/m$|hD&}9o5fAVyGHX'+m M~Қ蓠( 0ƈPHR?pۮ6Ԟv˝JL-!fc&e=k|u y쬜H77*o{ǘ4DecGr5.H熧is)$K& idg6C/$=p߽ rߜyθSb~8Bv\ ?b1l6 ЙĄ`gsG<)((7^Ol:l} 5?~% IZs]T@"EKU!`f_GN+*(#Q1˕/X:8vfIZQ 'G'1)AQ5MlveߘxQ6< B!(ܷBʄMC Dbϯl B zBOni%%&E,afav> -o S! 82,jgi_'ڈX};uTuͤ=3?#gFf35..#9\Ml[_4GՓnFlSODiw|PrK mw$sO;.xcWkRא\K E\[d~Փ2_t_l }DkjC[ U(3b.Pj"%0!c^~^skh㚥P$MŚFZtddE (iZ SPtX3P6BVFF =\OtcMsJEiӻcruu "9m/Ly?9hz ,Aa4$߆p׎:s_CғC!4 W Q}uF296!\zIȥ.(yZdkcEHiqDxγ?֏Lwv$Ȝh- =:T=CY)Ume]\Ϟrq;i;I0VuaN $šq:O7YzG 8qoUnq`2;vi#!k9;l';kHn"[N Xƣ̞#i;t܇i aYƜyK2Dn!s) xk$K3MZխ$ʂ GȿVTKeL36ATgMI8yټ!@g%{ bp m*JZ2SLm IEkC3`={q/s@ 7]LyD)^&Zph$dl~{uX+{2sZc"eYݻBgi ˵z wF~ygri2M=A k#Nhڪ9g'Lst}mkb 9QP#),e?G~.Xxi[[]pX&6wҐ3Dc"+kw2*IDP.{9sǼSّd2Μuor"VyaU&淖@SsAo#N+?]܈"퐏~kyzs69|{9/n@`m=d]W/'y7ZjУ f-f,=?8_A&?}rZQ.rD $@Y :y*UVɾM{tFA{LߦSwO ~-A3wފA ^pA5UfJ}vYp'}ME Hm$aƕ[Dv4T_'WYƆ6%NZn"t0CR#D &02hJkl5a8H|ok5cKAG.^ĆDI+}*QLW 7k2cȋ}YtU9$)8)!hJ[{Ḇn9/sVKZC!Y(S$HcEhCwiGA~B]kf͓⣩1n0(DBﺮ8q#{FJoE݃{gX:VT׆Ɵ,)8zhsı ,tގ%nͮ/bdW@3p (<=<1sK-d/(F~8~@b8Nq7*;+$rF>*-AP)7]-CpD^!ݕfqT?j5y~ܨ>(ؼS.%urjBi^l12e/Bm>0,5}^rd>)K,ɺz"sV305$"Ꞁ?c`Y5u߃=Ɓ'tvЃ:\"ot vɒ H6慷 V8EaUh`@vw<'@[Ϲ?6!>ݳ˛\Ih곃 Fᨃ=uuFVmadRP֧>ɜX@x0Zs1z$T깣f1Vt xXrN:yb򏈅p2, gΣ&20:ݭGPXx>D v]rÀl-q˩DnA(xw 0v#"*-p}HgÇ_/z-Qa˵Wxu [N[5G0z5^_CM@fTJYdvQz6DnU1N̙0/gg{ssxƞsfJQ neof  XpQ=V ֗Hl'U6 #Up?jd}~+ H$gi][ CHRa*`'XGLfpsV #̹+E9U0mAJN95_/\ϻ+.jk*q}}(=ƻ I~yϟ}{ȝ2{@wc>Q礨z?*g(DL`4F<ڃ; vQǻEZ x1.ؕS<ֶ  إ)\ydb!⻙ÖH )ǚz??u? ,3gJ콟hPk1~C=c~\Ǘ*fo)ADs:i0&,ĀRVrкWnT5`E$0ƤFi3B;% G6,wn#<暬#$worhSDoLwak:hU##m'9(v}𴂅N©dny+ko6cC':Lca`{0v*0T_>j2AG0'{'L# xW9m;B*CTI/e=w =C2(|D )3y*%RہuSb =NlM>.Ekѽ/]] ur '|(ȯ#wnx2* 1COIFdz|XQ֞.q>#.,δz`Dڂj"|p5跲iNQ;VnwE)^[Mj%ps _5R~nNضqR@VxzgW${1غ{7@$s`Im V{&>*l,:m~Y{!G? ~H[P= Pݺ<v=oJ\ѭu;7?wn)+nh9f;cQ\$=e %T Zt_ ; ʚO%l *AGA udy:z#@o^kHO Tpʥ/}x"E5ySj#%#giz*|3CՉq mp!񕶌sq3 xe0&V,XA,<>h10th'˞>T >V jԕx[3OӢ{ü>w0B;.D$eU 9LujN~F8 ͏^ҧ|BNH DT6 jb"EAŁ4B0*wbE CH dn_g?#n$a$+A7q&q VFz_{qN- ]_gMB)†KcnJGO`dmz#`1^-cBĉW.'ΒC67·TܹY.ir8荟ǐB:UCdu2.4bzP@ve-!#aqI[xky)9X9+&ЀLɻܑ; !nKMZ9|+4г7۬c߹X]1TnnLJm/z}?'E}6?y? h{ b|c* 46@O;+!h3kpä-o44 )<ߑЯJǗ]&k(#N( C͓^^ȁBQi0,W?_]]%y )gu!͆F@rt`#}{{ MuB2TJb\Eй AL53C'.*hmVBfj˸e̴A_%5VW҅.| 7%V *g7+:Ao}".Lr CLlA\Xʠ3/ ;#e9i^SGGT~$yF]jӆz:)g%Nn_5jEn{Ո[3ԝ`h 'yڟ9q- Ȳa|gi!ZL0|%]ґ\a31/sXqlQ/LnZT;Z~ʽ::7-_*G܎Ɓj3`L sבmWA^M#4Il6YqIe`}C(aԴւj"|qZ) #Q v9Zm105,'@i,a5R=&wh(-cֶK߁] $jE/>22{>\G%\O঳_s@dMJ_ۆF6dWI<#<ԍ"Y1M;Sne_,#wwƬ )z`zvPstW>u߃~V<Zeݜ.^[xPCmlsE|O1}=_Yt>eLo NumF{Ȳj@eN,?'N&JwRm*SmJ x ~cO~E;E]$tln5Av~BsIV?!37K]DUXi ˬt"zkťc/ Ñt{ n,(B7Tߊe8=]F5MlC(mduk\/ !/ jK2j/[ (YvC>ca[JƶGxj Q~ЁxϛLHE̺d.|At[-5 aKW\ejWd3ѽ.pPfa0{f :M*4nJlk+ gd$(4(t=l/lM?aYWٗGٮK:M-VgyԏEƷ1&y[/>1p p֮,w:bJ{WeC-|sRnK]+i@6İڌ땞y_>+m_LJU|bndgx$9r0=~IIn S-B]'WuGTJ-jUy3['_ 8CA{8pb^msHIhר|MX' NMEmwatKS§Qmx_%>yC}FnCߏ$.P..=kN#s)v6#-*3'?k%}s%Q s r?0+0庤qŕx߲ If?zڽ"+Y}%> "J"7B:4+{>%~ AE~+LA) IF; '].RC"?Pxk@"~Iv`+[}M-gn}Z3B!1N&f[b H0 F7jߐG)%N9cd~'°7˴&]8\^5Kgj,41&H[=i\Sb/<ؐ 3zx8¿jt4q?pD0C{ᨮ"h/Uț0TRq`aԤ!d쐯9kpL8ݬ/頬K*rMk>fZj U!^Pjtn*۫gi/ܤ[Y>^L&‹E0qlxWM~a{.+&OcjjwPՅqسEЛ`E51%]߻]>oݗϧi&>? } 銽8Ы6gQ*YR}6A= V2vǼ>V!Q7i_(ٱM_\(t@E}X1xEM2G?ǞQN.]?R@.gP~H EeW[T[l:L?iǜ2+CaUsw> }ZvyLfL߳^ "'{z8Q0:NږBTT:ϳis4B ߃|yK Ũp`J4fis]V<^x"R:p OKc|4wOvx˞Pq7˴EXy؁9JBe{]`Bgl#\*mg\p9al-3@3a0ܩ_cZ AʄVpg~y¦^SLO0"~hʘF>B]LH8 澁3/ (7Ff}C] = 6)c|PEj[1K#)L; bgBЋQV:0$¡?: f%cUnN0gSK`PMA@+>䵐7e^۱Hq H`¨GM$NEkqx_hA5X{Zk ;wR8#MSh8 !yav%&q7I0zo s+ q 7m//K#ZGcdY)i_{Mx[I(ƒY0֙,Ɍ7'GXklnr_ʨrq8sKn"% ''_tqh [h+MŔL!T n3W{De2nÉ 4* )rZDcO~zYzF 6arZT!ckXhc` 'hksE/SKpK\؃vK+kJ?K!' YOS5Ղ-{rjZB)IҶE㖎D;EF[ޖd}GK-7:OJ\u +9WB1MNߐ1鯽kv߃QCuc u޺&Pn9w5k?x^ZOƳ͠fګ7.JήG1<-F=|9ےd ?@nh9+'߰G*w2 Eq{p8=HoDOևt :6>--c^4n;ly!0Jaۤs6P؄yy{(\`=ɵȬSq+ /E\hklJ &7EԆ^I`]dx34Y.vrx=] ݧ/Hx6uYF@] .FpWumZ+U'%@ d=tFMʧt8l7 ,'&Ҥ Lܛ|pYD$MPEbv{êk1GX{+Ht V>3Yo &*=aOX:4FM#WTC`+^A/֔9Vvÿ1<,\8 O+xifpwMsrԱ;WB9awc9Pe(w*$dA8HR$p(^g=y9(abA8_ֻ C?E-" M}8ަYS/R7y. wj <զ^ {s[GĹV0<#gIhkizhnɓMc:Y(x[Mc4pܭRC0h˟bL$a40{AG._β7y(v%'31YT%]<@9ϡu8OJi>iT-QQQQAdV<( >{>+yik!M:9 "Ԡ4\M@K*k5;4>LS%p{&ce}7gßțhl&~/X8i (fU,[ot«ϬZmHQ$FJiG4^&7gly?Ld2o r6` g9Eb.vv V$[ٟ軽bII|,T$*y\/%$yN=TEq^K>ʑS[sϥVRUR4fĶ`\d%Vl7;2m/qAW$d Eu:.: X%}h˵ ^>j/JBϠfcy3ot<â5ZO zAGbg,bs^yѽ.*sL<˝vP֕cO`p5שּuv-%WBېgaӚkwiLȓrw`ou 077Va,-{hhSx0~ܚ$ ժag ހMÒ89٦ kfe)VN7(:+õp?K+^0p-+_Ma+{׽_d+pj4CPf `:+2~|ҚzfY0_9(7)q(;'qnn.q /VٴaSv-ͫęې6Ցyt%a0H~3uV5.qFR-MeLmt 7p1/撈bqG3ӷhpymrI1yMH/XoOn}<?7l4¼vK?|^nnS ås᛺\uwGj,|i5,:,?V&Um׵x\^ebO+?;8'sk`tW>q5KFVj,~<!bfn\0՝ELʭvdH<3zt٧{x;n]a=d@rX`^GϞ1=ǡ![5J* Q(+Ճ_ߋ7wNChr  ]bj+l#g VG+v =.+ oA!H +Ծsu]:6yU+!U0qrŊç`FӐt;UN7*RIr`H*A(Ē~H$?qpE6].7]Pl<{>9 d-er7`sW./{A-/GtA\2cdY8s)8 :m9P~:mQl0i˫"⼜ǬP]*G䶚z@(zʃ; ab bI\4[>lafvx;MgH4iP@pcznaZWg;'dzRU˞^\Mzm֮š@%h0 ح;N΄N] Us3\`ݵitjF\zC zb+aY"~l@ȝփQ;)iA'xP3pW .K˖HRRn ]b_ՙ{` :XisI9uup|4"('v`.%%nCx~6+fYzܱ7\K_zŇ,rBXONq`A}CJk^D)/hl#bC^7zjpE l'B(4#T}f;O'.7E>a}U_c ˀ$$Qnc_a[{΀(}<ݬ3ىts* xt[.bS4 KBrqdU/m&  J>EfӏVHer(.&3Kbfܣ}E#s􎨥nd/xٵAD#c\;6@@~b;zxVi:'꘵>0D%*/y/pزTKke`>1%8=Aq0fkδqخ-d 󉮤tԥw7ăGO1)#48ć`p w6Mq,|p2eB8Fɿ؟;}X^=׏y*$QGM9]N_:A$:|L- 8kr2 L|q⤙Q3o]d-ays.  b#7:c3ĸ?>R13̛P8-M+hI ElHQO>׏ȳf`!}pO_h̀st|7~VFc\#yE^# 18.бeKTnʃZn|xi)=غm '{ɾq6b!oNf[}J_4"b?o n 8_:^F٢*xW묢oI,e xh* t49jSm__qZmxn|2V3<7(ޞng/]m~|biwT"c)Կa]V0RQC`6l"נam*ڟw 7{{=Wʫ8WkU }z@VՂa0L\ M7%9~]+/ x6璼N.nfwFa~yF,L{_8WkL&I؛Ͱt0:Lr4EkJxfRX׽~5yϕcϋC;Aƍ[7-aØک{m We[שּׂg z%MdKrCf`j!,g!_IqRͩP\:(KNF+U%2UΠٗNr$kn Kp޸F(ϲ~$\Kb=TnNa%?68R߾uT_ס/pP]em´*:x^ɸ^l֪_]*܅IigA4S~FO޺Z㹤žZZdw @"x*>8^aa a'=ay@yÈYY?-Ev||Z7we%x/֞gkJ/i 2[,-db-_çK\2Bnepe?_,X?nuto.3+,Cebio!}9] gj8} ?A8?N+˜?խR~isUvT\;nt+̓ یlquYSZkid{0v䏭JpGY.x-뵃iyWfuF}i5۽\wѼipv<W2y]yVNMPQ<͙:>{Deoa~`2 &_)eM׹q~XnqQhČgn[]%$D"c!nNQl'ڱwYbps,XoiXfߨ+YUs?GM7w۶l/sn}E\ j3h?X* |_3ws[vת˽{tU'{ K>/]o,,@U=mE%E':/Ųr}nMFAF.ͱV۝xuۇڂs28%kWk¾}Lw*9X]MmEװ7{=vKo*;x~B}7"3_HcDZh5\HctP RCw&!1QzG$ H h՞d >sle= =`]>:j~w4SRIF&ky9C9]x6 ץ*+Za!6qYMw4j\yF# Y4{8u>,\7p8%4k$q7qOIͅ_" 9`apYzj/"XO;'7q͆N\o .5~FHc$tJhaf( BDYUn$cH>+k{ pV:Q`AbEJV1ʈKF m%CȨ.sw`a߻wX/mT n&s7功AdSJu+mG8[RֵqH&jwͲU0hG|aB}?l-0֚#`9x7F7,Ѻ z@BK b@pcPv|ߙ5nBI$=uߓ&&*{'nsuKuSqZ׸ukga= %($gXb(hدICpv^[i,r7@1|+b?Lʵ.+Ph*n^ώ5R([5p1WbRXG>^X0;={}<Yԃ|攗~Y(&_5h)gTn|Zmdv۠oA}o`erVՇ+~PfQD@}W(j]fWToVr K #E$F%wxӋݥM'z?#fTȵ dݽOXA֐y0J!I8Uv@y>=W7` ѝ2;U?+,UOX.ngk4% T81 Xl~$ ),7.޳QjZFzt?**s1k[+,Ƶq+n)kEwmrp<8epd*X֑֠h2B >ȣ:2&~kMRs07C¼PDV0j,/2n 8-?zŝŪXVBw*H-p\{ih.Wy׶=nOJP|\TaqWK<^a.?w~8NfϢfu!CZ^? 7ce.7UzFoNCw>T?yyePu>Yc6ثɨ\^O%î'wZ\,tw]2lf~i\Eb/g X}vdlj~X'/פGn5UJHc_Z2d^u]:s(2v:`Y;n1r\7SR<9(4~>3mݯT^5V)BH0 Daׁ aՃ@eZk0 -@a*P_+wZtr 1=Q4SP4Z,b,hߒ4YЩ@A|;`.gײ\E砐BȺY"jbqj}'zj!ō:/;o޵;Y'D*I!Jb,?_g'0 ֌EF4QA(wiBuʎ, Tu\afR}޼:` ߧE*&jL$(K*+_F$k mN>JKYR9ǧߡ mg15ULChxb'uG\ asY*Pc8R8ο@A7kLPPTN##T W2'H*BDklB(N@ Ync.JP98ӍA\tґj_hcL?AY>/ mP$f mѩNIaZ0̊rLdsͤܿ_Z_WW_F;c{y2+ýV+ ičA$:"?C/Ƿ:Pa xKv?v QUǠ^bk=#>[HSyoĞغ;b^Iiz 6|"v4m7ϰx~'"l`|qv开o75kv>;lg}M'E\\{Jx z1}(d - (%NΞw<9Jm4U7=S _9G{}B7JRBsB[+FXqISAs!WG =̥4WPղad217h&yMOt0Kl[/FwF 4b]pyRB UZhm}Wt3G;=b8mr[@ݜf_[kw572ߟ~5ttv<_w5ɸC+!Jg$SrNaˆYׄ>L@^9jڞ(d,d![+f T%E5מ1b GQHu X5ص ؇JĥưУkxA?wQ,BKlbAA=\JTE(|DqPsi6魼_/*LPykus;zΕS6w z밚кB̞+B@S%./^jD!Yj)a8v!F+,9OP]q$9(+ʞ*-5H"㼾5$/DPcP.Q̞_גX2#@r~*.Z $"HT.i ڽ@FCL YD-gw#&\*. ^~+o (ۛft)7Kؖw(>!ȐYDE TF*E\gx"CdIfa|c)A2("B,0`ҁVcfϕURjAȌ!@QgK fRBWԅ;-=fD+kґ@j$R*wś^^`Z.ۓ%JG_UbaGnQLՐʾ5OЄF!OBj5ÒriM)\It]w0$a*{\IiQ,]rW3/X1Hʞ*.\PKuq-=cݟtNWJ*K )v[ tܬ@Jr-~qS baJP.iaPQXBwkVRi^ 7KZH |5rwk 1jIUp#H=;KMd8L ;dϕ0Rf8t:O vb:"*J9L { R@_P.Kۧ@01U4Jq7g+݀S?LG_>GL穬]Q8Q!SD R_!Oȅ]3WʑY'1N})SRL>ºLc_Vyhι6"  ˆL`T2fH K |"̸e (w; !jaeJP.mu˩#dn-IGKv(4B(%zv@@ahiJ/Еu4!KRDUL.>gRH3"%^} =m Cs+W!lMpM2AY,ֿZV'^$LkJX7ŢDS uoZ%C!N Y]@H+4F+Ň%s5Mqv{-QJ-^YQA%awzۺfArKP.@-$Ś +pvku Bj-e*(dyuGOQmghy^W3zgߛFľB DeC0 a_Ce:0{5@eVw@# ߡvbZŁjM2tD(sv{J6|1~r$E [+(%;E %(Έ+$E&9(˿8e!FF ӁBN ]F1iH:PCk,H!KT;~?r!B8 (˖ȋa-TdPsP_*(ޫ˛jB0L3Xk\s ݤƤ K*-G笏۟( lnj uD Pj _FZ(Հ%}-MQB_THzlG#AMbiV)I!~aPz`N nbJ4+MT : RP$~³-z+A2[G=ӎl(~:&xnjR!ѝR-#Hx{,* *۷ r< b +mc)!?e_F8_G#Oe쳐a|>sďؓE{e4t6Yy\[ך?ě#x1PYt`Yaラ{LZnq>9 A7`={>ZRiz'ׁ+|LlZm78C  R3Mdbm￙*ꍥWP=*UQAׁnp/>6y u^j~m+L/m鉺~Vi_z'DJaINg@Ϳ:wٽd-ES4J;,߻}LCN$S$T0 Sgom~=hݾ#4̿!`vwW/"/b@6 D骠9+=G-3hR( B\mEqV.m]Gkɳ#'"OO|<|"W,s7]Ivɶh,VeݘG+gj(LTq[ZC_an69;0ǾuwkC[l48J*RW((C*#S DRLJQ[ Ե}F'5)E/UXwx4ȷQR}V.{" YL!.kjRwiHTk$Uh F.kzi[.7c݉c{[Ia^H?*> ,q;f5, bKȶn"ۄW`bE(T41E+4o?OCO}hMs6ʣVzv"ꞩuh''HqϵԞuG: 8zy?a2?@շ|,K/U4ܽži$?iGVlLuxuﶍd,a|o>豁. h68n=Ep53DJ>:g\eTBxa.Ǧېr5awE#8W{vѧmD"=Q1T#L&\QlS#=e}UGYC4Z5")5wc@waQ2A*: @5V`R.'-Qڣ:ubd@ɵy>X,NƋV~J 7 Z=RǑm>ۢ'w18< b(( Vo̻ز)<{uVƥ/C4k9_Z^虝vщ9(r) H=vk u5~U\Ǚ/e;Rwd8NN' ­ڽ߬&U>#yMmwy83oiҿHFIL|#&}c`_R}DW߯h[~GcAUB:w\y{uJ$&idZ i{2H"7N{3{Z^YrI6y$.Џ+M܁jȰG*=6eyqipŐ̎▙+syvQe # S$:@-V 0 *4TФ2 ;6veZJm I"dnΣtJxG85(W 2 ="@w;ՇFڻ8r{iޱ,oN9HCcELX3Ԋώ]"5l't]'7=1i߂׸n6${s xRټBsӝʼno=oqMsa?w~WWoo *෵*T<Я5{$XRirPvT=yxT2ټuNy=D Ϡ޳ nT5>nxo&ek$E bJ)Ι&j]s0`TX_?Rѵ!g&b4,RP(b~$\ T< /O3=U=EEXTyL}!*euWK@/"urAUkߠR$Qp͸mf2 Խ# a -cbbm+UMܦ"+o*J(fU` )).'+ բ1?lgۿ׽| Ͻ¯C.2j+@}_:-/Gݮktc%s#kl#8z{ŅMBU<,?hX@2SP͠PՒ&➙!.v\%k 51U;ve&I<É T.vǰC46 ,#k]y2*ٷ9oAE _-͌;2ALbM]̻  [3 s .ݵYKqS y\r%c>Raz*ٞn܋[$=εr% g)'cj9um1?Gsv<.zgM X&J7;nFOYq#pއiAO|uѿ`,Q}*=M {w@5\npwW7h}\ZMʒ!pnF~X'Hjr\7ZG7dj<LE;VZ͔;SEoiݐZyk~2amTPjQf{~ x>T_H)yy{h|$ '3ZCR.s喠ur/u{TTks$0ﻧZARlr*ojAICܕl$ka !3}Oȅ}k]ot`pN2 Du?A~:NOgeSw!GV쒊lmݘ#?Dm`|VM֣%h(IxWߞxqFNW{g=#Zﮱw$}Ip 6Y! w֝U]` `w@*C$ۃoG</A6e{*LuՀhw۪,qMnlQѨI3|Gowm,-7c_g0Nj9 08 c'#lUZ!/kӸ+gdQtԇ'qcȗd0,aV=Xe֜!->u)Z.[cԻ9(z}KŎ5I*51&!^ܐpN2sɈen_ C?/6s0+æo7W,c͓n)rRE%Xm%][o "S{8NYBZ:%0 ֻon n8pCX6;g:9(+$뉭T9L#UӒp! t vqdY;~n}^Ag>d9ع`S7Jn^2rĪ<̳"?j>Y51$]0A^'{yMR]J )ǖ\YьXSȇ'ܕun<@Dxu{t©ɔ7&_m*8;B|;|]lُbbв1m|%Q[D&S(e}j̧m##s,Gf@ ͉H=H6/q+h;>eCXUz^pa .p翆[gg6͜Q1t`}tvq"έNN  km? ۴OVX?S#0+`W#!6r¯[z9-}Y/9,T?@m~6BafN\%7!Lݍ!9 5D?-~˷2ϧUN!vmi!!N2uS4 / p ͢H =[Iyf7摋k\)yuPlfip IHLzk.j6qqwL>=j}~A׈̎B_ NfnTۂLb.g#z)+w2'*N^04jӄd,8f>g;w*4t-ٳVxqA l)|Ngwc̀&vP1_933o 2)~˗YGww-äYhc({PJKyݡ67HcLaFTRvΛX-b5ϩ> b<Ԗuϼ>!!^AGcPw=g)«9ߐ4,: חcA9n !1l?F;.fWv̈́\ ?Yg r>5*$dse|)3M\#Si{x |nbxIq hv=L:|efA*q Y _3=b7;HcߋYFk$sey*MsUh[mזM4 !:]g{ O8"-]xQ\ ꢭtgs}RqSc!_XFG ]W~jMojGĄ K;Eޙ3% }nZ_EL LzemN=Nk.5J_E?,no|=/ 31ue90G+ho+,ʆi+R;\hˇǣNy__jJq8ky/[DŽ7; k X~?%$sa.飓,y2\^~o_h+o^lj*dz(SFq;TЪ/\Bxӱ[e~JKPˈbb!"*] #by:ם(5|nb^Sh'a 6"X9m_ZJ7 3J[TQ~6UB{ڷm@.ғ`7\\84F1޽7?.[2:|ߢ[z k m!nx3rwh?ώ۽|IFkIxRGpS=a%t~r#1zn!vҡ RֿJuh*o(}>H9s"t@xӶ髩ĺ(G5hJ *1ٗJ xi%ҵƩTj%0;z|(o8X7*h``GVK.\z+z_[E3-:_E`ct?mt@Q=BQ4 {{F4fJmbz ьҧ/.t?ٝLt(8W%yy|My.-\\.qk'XvVBS,Qfl&ȭ1I5xnF̡80O̔s/C/HBs5 @۠hNmңWtG^D O5h X6t"i=B_}$>xm`MhBb9Y߃Z'\}>ˀ2~I&Pw Im,@fn,°kP~sȮ)O;.e2 1|gntMvཚuOۏjD4o34g0Q%AKV aYGZUI8sowS3ÙK(jX7y/8sL ̌s_ሧu3h%0ih}[$q}vz]v6mqq׷ڛYYYYYYY5\M'X(nydus-snapshotter-0.13.4/pkg/filesystem/testdata/v5-bootstrap-file-size-736032.tar.gz000066400000000000000000011034351453374237200302330ustar00rootroot00000000000000wpeYw{Y]*%@iH H B#^D*"tPzN,ߟ/g޿3wyf~N}-g&1۶~)M(UOWO_.QxXJ}hXAm~nݣ)tԩwш)?}oVĿ%KuZ4(Rh̯y# 2xPgE~~x?kkƆ"E(BP"E(BP"E(BP"E(B׳Y)'I{3y|dOeMs:3|&NrكЀ6 f"7?A =F+09(ɐ3HqjӞLSrG%BSz\R3\A?Q*4"~f&I$dQҎb%[8w{x0ъ`>{gSXc1[9C 3DАna&&1 c6: _L 1O&<6p;-dL@=btpd-&(2 YvFSb,>Ky/R6 f&I$d|F)A iK/ֳS\% E/&9KT5FNpEiBXV b"bFgDї)b/ߑ9m' 85jRHbD"ke2&1bI\eݔ6`&M*A T%*pKy~ ߛrKUч,e;bԦ=I$=\$C?Xn\M ‰+c.ҸO47YD2{8=7>j01'WT\%k hN& t-Ρ2iP0Y:t lRM{39m򼭆Nk2$q |jq̭필ӌLf{H6P1qg;H%][24 YB uH I/@-bR8-rw^uZ3$qdG |jqpћɬ`Q)Kc2vJX h.N3z3"?eiLYRI&N#6sCF0 6yzmjІA \%k/sJDч)b gy@޾:t i,a=GI>?^brkLy g5[9 rRFc(YnHI^brGzWPh1E|i"D>fڳ(E$t>cߑqPR4 =,&ݜ 5J(F%Ӛ3Ec_sG|e*I+,$;c(5h Y~.iqX3'X&m r+d\Dy8Lv >pΡ9/"hA_ݤt{$%_\S1q\3B4x[[2ԧ#YFNpܳ1JKewdN)Gz07]"p+ԡc'CyDӆA$\!|Ny҃,c;yDޠ=ØM2NT)Swsd_FDrvJHF]:\R8Mr,VWDЂLaI%ƝDKqnk }VoILPtb$ nc5CUZҟK.@^Ňlkg;6%2P qc)۹@\4{, ԢCIJOT)=Rq\m61 e85~f#<ugI0ɶVRfb" ߓs5O-V4ؠ)M$$0 7SҒLe_r JC2l(N$Gl4)Y=<6p;"^m,9Mrn1WF+Zrl[ʴ7Hd-I6Uk"N"$`\QHbI`>9mr0/)Gg.8m4ǩF:2l8ȵKB4<>c?ɼOu9ǸE=OUfX^.KPg*\&W/ޛ);( E6h aY!{dD6E(#]Ut|sέl؉xRXoFa؆D<7TN}H dA9%؁$<8~N/# ȇM9ڡ'0Q1\C (A6 zG;M#a bqO 5R0GqPKVBlb@c6V!gqy=04dA # BǐTxJB8"a-'h>#VD7 |A$.*\kh~19,6SG1E.trY; (MCO;.E؄A|ߣ0؏B/=a@ l1++x\TFy0 |XG*rQa xb6"9zS} MXTc/!PM 3Gp XT?,$9ĥĢ: +c O55> a _,VC䡪X "8|DE zA~\kFi4,z4n9r)U_sAC4 ^:FstF?ba7pOf脾 wLB.u<hjE1BB 2ĢFh3 Ӱ18 xPզn 'c>`'6^"a oc%bp WШ@Bc8\1aX8G*!(1,D,*JW-L1nX=8d uClX8+xШL.0 .EF2* [x#+p*U4F{ yB, -ĢJhp`"qUnapF ppY(@bQC E80." o k֠S 1xR( 0X]Ь-51A6$ ]]a_ {pPK +"8|=^Tc/"j? 0ޘ8Hg4_1kqZ c0WF a ?,F,)fcs 'OiB@?8cn-#z` &cpPkF+ňy<7lN_BoX 7(}1c1 xPo\~LE"j-9hx"aF jx3Ab!P5' XC%n poP e'1G2ޢ\[- D"72z]vp5Fv_0-&b2211l1  a X=Lh50 &b9*2с`Q2%d@# Fc2x .zGjgO '!gP }0JWr0c)vҡnHN0-&a:Սu` 3M8FbQG /`.!dc?n Z&38"kqʦKc64{N5q,h 1qiz1?b0[gP1c|:\scs.<Ɨ}xP%_S_q}.6f.n)jGouML?Fv]a(L1q _U\ ." J5AEUG*)qr8q(QN߈{ܟšW8{Awݳ7T_p^a_ٓ`?fiJ\‰e\\nC>gt]BUE?oC:=*ơeqsD5["(L)qNގ;?_m{\R_vwyu>-K_5E.)T (⽿돶;-@c^x{Xq5_<& S9A%kk]o !҉JrUl?շ|^sƋ_TL_3jPz+nO3ϩ0qĄKBCzyqW<<ݱW|Ÿ{6ͷ3rMlfohpJ뛳bV TQXDWnB.Z?jN -k\1ftl~<%Bܵ[\xE8VIOS(?7/'o8o?]{Gw7_>y麣Ӗu wΌ{;Y ~lh7ۻ~ 'Tz4P W6q>Fg6: L<iG) y)"ߵo?y,}R{rub|93ӅKoO85wݖ̜ҪfcmSBu8及Ea&=h%3T\jId,tqoh9߾.Sx?5!CڏqyzivqlKGܹ4a4de/$+MHB:c3S3}XF+lkuB!'վԋg4,kL͛jWF/i{de'$fЫAޭ;7[d/;mc|WKIB~MOW sb.ՙ{栯֯2c$q?&rR^B{xv{+VzmA{ ]vnNŌ 1)G^֯žs%Ptw&ޝ;_~ћ VRbs=i}zڗu_j}&<ţYhYDC_կn߿ V2ݤYlq\F023-V ﳑ+ D6an{醣+&z\(yPϙ]6GfTM布GZ\U~ IH\XkP #EO899]cGE<6u]aqT:Z}y-K1n%_s[+Tڕ%\-i,2/]/s |َt}7cfYxw (wCR~uJwL㻻KA[TYS\두5z'&퀨,!v7i=_TUz},']_o]G{GEEsڑ>q_q3R'WluVE YOT}5S>=춪Snꯇ.WeȎNt^j1B~JՏ_#y'~ >i*%>a#{Ⱦ~yIjDzNּpB}B e6N&MӶ~.B~JwPQ|ú'D=ΩZ5ݳytɞR?ж[e|!FzLy^ӬEa7Gdl8?Z,ropKymcbY!Z.__[pɡJ?2(:g:GyO2y=#ױ Q 7o7/]'ly&t٤$512 볬UxGՔ=N>_|rc±|Ƥ|fMgdrA u*""ٸ8)_ ?o?{?Tlq۬goY8noj{rB>mcz}ܸc62i=2q]7 ^]l?e /Ӻ_qbI>'3E;M%+)h-3ƴSf~] t-&W%.Xe<%}|ɩѬv~;FK9,N~ĸHaOŲ=Nuzr3/2ϗDIIc>bz2zo ɯ)oVJ\wS%)ju򺥤x+¯O;aIJ{]I~kyuHk*kS4;ʼʖ׾ u+&?bdIg q2.bc:[IS5=jFݳ} l&Nqݺ)y;Nk;t䝫fSckXMR/:Tȫ{1y (鼢> tstZ꽞iUpwu1չxS2sڄ|ۀe>mIJSOYq~7Ε?/oM{ož&/Lmp'P0."_0^gIqJCcźc_=mSOj4]VU>0uu)ioLmOcK+zMyMy!Kj+xf)؎[hܚcﱔ48(>8Q}gqQgqQJ8QJ8:|cRZUӯ.5ߜt.-Cq(_hyS!TEQ">_oCη~fve3*v&'Zйpπ"ʔ?QԺHUazeqxgm}%kkj/{-Òϩ˱mwq ,"Ϗɮi)~/TsG7 ?| u\#n~t~ >n%1㐶p W|Ȓ{.7I?h}s/,.z'1XὊ?qI*ҧ{o[ݴEAnzo<-'8WZ6pYUCphD~OU>kCơ@>7$\MB}LnVHj٣+ֻeN;GևwTȺ7U*oߔuM'?~"|ͳr}IلRBfcK&Kˁ=蝲+~m!s/_ͺBLqFĚ dֳޜ`j~OeQPDmDң4^8k͖‡j Cftm˼dB2;HZu?d=c`#$\%!iU Qw?!f;g١EAJ1I6M'H;r]-&6i@N%7SrϷbSch!x@EmR+> UU=BtOJݫoѭv32DAH l([SLz%O{[& d} vqM^PU=5|-SCI&bqzV+Un\ڈ0ʃP,Ί}2'nצ+S'u2M-yY7mgR=@megCakfTzڱxcpћ=ߌ0sI:/dC=, .B,ǽUGayE3]`+pIO'vn3 2|?mWx͏N{Εd85<\OnPTj;@ 콬ډm',+)YE*z@fecJ< HGe kȳ$v'J Jh yQ 'YN:Aog?a ^+tn;zr^PrEAGۀ.DZ[9%1WX4g$U0(\WmM㎓y6Z-3Zf#iEAoKvcV(h"G/Lo/gGlwcb3 ? gi,/-v"n5d\KJnƦ2;6E@HA}x~GwK6qIx]On ym]e.h %Bno)'so [mTH\/B|~lA3ƪc f1C% ؽC|#@t :wzAdA qWeZ)*:S[ b=a7822/*ZA}m;/)XłAooJs#Y'؏*n~T.z=^*1ɔ`3Z8,]-4[\+ŎYQ~/9]WQ܍uZY-)b,8֦񆿨: 8>Jj;@}.߲O~UmyMw^x8Ot5rqr61Yl9<I)]]K!-cvnM {_ig cK&>6GGy+~9)lE!uX(z>sq:*,"t]j4Km5A~B+~-:nb%GSkBn??mdag_j_2w dU~wI@U tp ڽjEMsPN A@EC,, R'=~mY1e;JG9E{w몱YK:&_/XO[海_]$יy̫#yw0%(%y};0FoƧ(o*qG1uz(9!xH 7{ģ&|A˦֋]T

z)kWU9=û3"qZͤ5KYH"EjoȆ!15QT3!dJMFn܏@?7rTjE+-U2r]esZɭ0R5͓N#أ k X=mƥlh17ٙ"6L]!9.?:GJ.zco;)3յjZC=3TemdI2Nv2uM"@=hN(~*#P;M/9VwZyp!Һos+O7;&(~P4Aj 5 ;tN8g,Vj qz*.&G/Ս4gZȞ`_ꅛ(o7>,,ذ4ݢzi63@y6 [U٤9b)d9P^r.À+W qP9ggmܠvЛ65H.U?mtuBYpїw3WyrBtn"QwNwκ}_8 R:(}\Ɏa'nˤ)]4(cUwh's>auG<֯9$v,-9-^8IIC~%;Go/~.4fDz.u˅ MV  EId3u߉!ˉV;Rr ꑵDF܋0~.ߋG#II’&p6V]ک!>ۃ[m::G$LBdNrSzƮLq)86oU-ܙwVj?co|44g<k UO94SӲt6<V5@lK`^'cۂ->֕;LQ< 'ǞB c:vql~dENN<}0IHKFK] s6Ѫ6zR~.Dz+e!t y22_0 j&VʅrȊc 댂.P'k8D{uګ ?1_?,iEOQcTkJ t%SlZ95"ͥԚAD-+%-.dn/8ҥis\`]2{s2[Kyr*Fzo_H9ΐ`v~rڵj/6=^/}n1Bqu8 .4ȳ.fR0iY,jZ|<^*dBy+_0j @}d\ER ǻYn4O ^}+KGoV .k(|$x߭eOYwN~ZRp}{toW-Ȇ@v Nu.Poyˠ; 톘_:%ފ؟IgBp]?ssLueJyD#J޸-k))HJ(_!K c5ħB"[5KR5)kRHHHwe4}<1w{ϹGW6cGT"x>a' dAC: W, 7+oH j_#(ɉ/ljϭqEO~! / xCoQVh{ !|>Xou7U7;oܮ}e\Gu:}"Nsc=dowƏ輆ut /G ߡFG/'\"+ N wwu/4xDub/_> K-SnPח5P;fLR$?4֞&1d@Պ\7;,Dn7L,^o-ZjȄ A{HD(ZӞD-JXw)rzH1 Ӏ_<~ A;KΏϋGgKXu<%4Rs?F_Y2qbt9Ƒ?(ܓC^ |[wO[/N Kω[}c.d; '>/+& %1M =9%?;?=ضK, #Ϻ4vE_B?yKijm] kA6yE}m|2@`cGq~)Q+ꂛŅLhfpW;X"3&%rk[ 2i#R ZKkTݥaE[1^/Ow0brR"~#^+I%1sbu֐x5`)y37n=-'YMjVԛ𒠡"<)uأ؞|۬gi[+4li}dmbu6փן,Hĸ3q|ΝFEaIP9Txb8=PwsvokSEOO0As_tSڸK"2MR^?{Q"4v^R-Ӳ̧3<4xR9LC@~4h5'\؈13աv Ď\-[~-(/ Ⱦc Ds&ޡM4^πW^ӵ#ߠNg r{:̗fFYX0$?MJ ':8ZM-1V>GK3)*l<$nEN0ڰj٩=WXv9S4v,ȬuaM?.P";蚳6y|26A=!m0 xI7@hm}pY8}J`7q>d1e$ZjY^!W@f:[z)i<PrqvI$LSc] _w֓nuzbK/Ղq­.OJ~K8GWa3[ju߾H-^E$ %G?{&HPp@!:P-} E<MŸȺq.tG }4/HFs0F{KMM D.7yh~DpxSPzVZeGwO$}nW UR"ί{FWRnɛ mqb4_:w|6.v'g9)0wR 6:v{EF^7O9@fG΋s5Pq%zGtD;r؅ҧ[4q迅ǃykB\['?y?4b K>(y01hsW |LZ bӺGRu_։U,S)6=橕t ߾O|eP1¹H92*MmE`{yJdЌn(J~ P8XQ[ 8>'Q%MM%?~T% h(]ݟ ?vl-zPgȖhy+՛D68agVR~\-cxVY=y)lm"lu5 ;2a+QZ~;"b3e+]t_~ ;a b@ ?P,x{WO*kD> 7 ~^ԚAQR #X~e8 FY#qXînl۶&+@m2/DXdxڈQ|~Is7{VcCא!Rx4Z ڧC )5瀹."\XfM& /hŸ@b;VߜzMiow /Jd˷F[|`L33cr_'Oq߈joM/P{:ko#c5L\VGùn5Y;ɮAH+ 5Mjw)3\{=oӷj|tElyIO$K^z9{D7LJPdg }\#%N4vpQñH}O/v.-8n98b<:ѶS:u{Z5'Rv7{Ja?8H8 y _J=H 8rVeL%J~O8q#p;kp*oc pౕ_=`ո$IM= G„{X^W:$px@eEݽҎ'W}^WoԿV3rK-vٸXAܼ9|xvWϷ3 8UӟeܾM~e,ps^Az}ӊQY1sЮr[F.?!2jds@-vq41g0F=!!~ cx&vSi5BS^i5;;F%'~B8f fOLORsQT׺slJW 05c d:da?&10dS~aw,{܍l00M= /R@ ;jcx4nj ektγVk8*:bu\y >7 ־wb+>!Pm/9 &8+h -ω݂]6wL],Hl*p.@ٟkPM 仔}ccxW lQsqؐmi^϶^TxG6[0ܩttAߖ-ْ<ԩsk_5^D{QĜ\]+e 5p66_b4d2A??.:Ngp٠<=1Rrf <Sc;~$_\0ewU+ok~Tɷs|S$Zn6^w/f91zdmmqLnGWVY˪\$C|\O\.(L?%Dba|h,tI0> h\ޤ* f fG~!-^(}\C{ĄߡމE15Xc#ra:Rk/^8>N4x֢ѰXJf[f['ԒrEw`7_W7wh~1ިYf\GpǦx / 7lq#/ (ZedQ`%m&җ1b3UD~C:Y5e 6 ^tBF:[NS_ 'R\؉f?~ٯvo)(/r)n9sd-Hk8 }cSEK8}Kwe\Yzar㦩 p0 .-PfM@.L_^ cӦ}94Էd,1wtja5 0GF_00:Md2P>2FRSuzC Te&tXiCvlތ\[$tYXcCND딌':Ftlg㞍vޗmpdL`9mS7'Mj91`"fnK}'~T.VB\Ϣݕ$6(lf#`~{ D BNĘgtiwͨUӫ%,ʐlb!^"; !UOn -M-0mFޱfk)7+OfՏL|&Gڪ7=8j91T]1!yΟP:lu$-mn3oCPRB??% {uJwK5;HUEcΉ,CH~19ۏBP ;9Pm;BR2} =z|4]A   .LvAJo/~V|p>2v#٠^|pm!{ͷ9Ym&(b܈г:l>y[Y } Z}ΩbR?C{6#uJ2POW[S@ȋ &?ڴ_ڲU6jyג_~1ŢFg5?s]Qg]#}E~͒\ֻ;B#~ fqk ~Kv]zs):6gM^n\S$< xE"EZ:s!W4\Jqn7 j9?j۬Z‘J?z~$K)G,(3ZKKf &ߗ0/o:֬>9hdFգg:s4c ^4"k^c ۝_;)Kb_-SReenm~e;]\DL8.5/GVNJoμK+֭K3yڄ4օ 2YX p>]m,ߐl)5;enݬ^Dq6m7.LyPBv!h;*!ìz}=,Y(hoП Ժ buB./otVHrFWSC3&הs\Z_khGsh/ЧQ{\ajDRa4lrx<b*+xp:B-]wqy4f)u{0q/9X1r}'>V[ܕ XdDG|` .iiF0ՃZ fRzLus :T&͕{0u/y}C k5*ו3~s`~0Q5$a%~ T&+SqԴ bKaB>$_*(ӓۆtzlwgPue{o'K?T~l1~L5=ڢaڦ[њLREƷC= L\vp>Mu33_cQ򒮔o\ $ѱ{b1 .KiE8z/eMaiAj yj񩁘k `n_~;sBvOV%5{ӱ`FA2kBﳐŸq ;!.ӏRcۨn2x9-e1])2R—k닦\_4U|ί}g>A w^xuI?ziU/,nbfMu jib{VcG*a|9 ss0472$W!͈8Wn ).ѱ56y*]Uol<+\04j8NQ buȀOAf2*=rĻ9\6ڊ1C*4uWpsK__.=+-SZ' Edr$*7̰Tߟp޷.mS {xCk]VB8nJwLm R>-|9_Si]`q(}X1 Nl|җ}lv[\h\X!c\yusg3y Nm*l²l 4l;]{Ji}cAxpiC"G]Nƿ,X/‘t ΍tDHq6 紲wwNt& wv@dLY6glyAgP4=86~2!'uu\Nh⥤ws+(WxV+anWަuW^֭_s}u¬Wv_~1vAC"6_GZA(>YBDw2>vSI'/",-#łPo ;311ƸʃyeuV/GjdT7:(9BN/z"Ir@)GQm}}7{"'i '9 sBQ_%ʼni[!)kZ cΔt+T?==楛ӻ9*αogT4㘉j(nu! Qg;߸ _t4[=R?3la`y ۛuan{P[_u&S|js|oDByYy$aD@>J|Wp‡rA:)xZHEZ, u* <$ҡ& Q|˄|wԮ%@/=߹S3^ ǞxUWg H=]C9ú>- jC r,J;Kȧ,:zb̢C3Pk`Տ988 9hOT\TN%jK};F$l|;jgBu$8yG$1{sW,0ZRKLlf:Rj%|D bsj> 8ҬxtAL -52&"c5[nR:@$ufu>fQ5SwdR*9}й4^T[ ZA:]eD}K[[t^7}o*YTU>ELW  5 .upgl5“m·9N b&O/0h\LE6>۴p <2T,W*!+CPc_Y#[l,YQLcl }#[RI6|'"W},%gϙ9qzzϽ}_TK~$'RY}4ʕROӁ~΅S|@78`62/bVR 4xIi-ǵ`ew,zjmWBUi0"ž[c ;#~:[Oξ(4^h?7u.Mm.\ppq ݯUtP5Ҕ˳|OhM9vVg > 2'#ߜ{VG`ck xZ5XHK?dZ7%޵6cK].z"oYS1FTMˑ)ci`vǸ,h-4JRvYlvivО)&=u`a[yʻm#7N׌#>z@Wl]7s_)x|5~ɹRY JmJZgڷ\߾)a"](yͧl@}]WwP+,3=xGl[h*gԜ){KW7tN\yy. 4D_oU<'Ũ)5,/l1=Jjw 4rD6<,(3 tlqM >u(apu~p <rqiW7~84 ͏]1.GNVr4H58WI]RZ7g,3 %zCxLw99?gybx a"_[F-*'p0#Ix!v4]3g`ovȷ/AkFn֫݌fǛZ1!8+?stKfşZqi^tHD߹Q}9&PL l CD!>u|@q ӷ?l<ϓ,XVkV''L$E.ãŮ qmRWK.G;ƯKMf zN7ڐ4uln D)$i}lESΊNUmrq m堧i=lp;buE ([9l ߭YXnO"*oZq!O< 7eIJP|"4P?#G;%Ԧ<œ-ٓ|_«Z b8l >W.rs^qΚޙvuo㽇?k/0.QZ/]܉Y۲^uhg;V-3'~du8]'ʗD}Z&- -b<-;н~2 .1*9y8RL.`APd'T ~1 w6XM;Hhf$*9X֖ \Z>AaEt-88R][ P(e=t̶u#qgQgNA˷Va4K j6)}(ʉn୰+qvU֍jB$h+oG|]gsS&Ǽ6u[Oʟ V0P|vNdN ȉ,:\`WO9tCోdgko*$66{]reK/~rؕMv| uN*ȧ7gG%7rO f<^⩨%Y맟I-X4 < ˌE:<ժÕPi!XuI&g}i1vȯd,!*$=JO&{63f'w'Kk|^A=-E%KA}: N~r%}o{H*l )-׃f&mJENrהJ(JpD5s+`--rB+XJn"E0>+muzr;O01usmpz'uw"RipZH/š?+iwǮ#hd4KR}]G⒣& I8>l ̏;}_ttm Po-.Kعk ^Gl-W{b0&↟ Do ;\@UyJ=wDnk@טxV蜂/CY)toZ<*n߅,TK+$ _;#;a hpiP^~ԳbwXn.9M}zU|qmzgɜ?#qHZsg&jDfu0 EӋܰKa2lS%oI%OZeMk"P;Cgx1k 62Y:dPu{4OC LIsAipáCsvٌVw]|bJj9{;p`^i7C :Dn26vk w͓vk$Si\͙A91x +7Q(0h<.,F(g,X*8q樔<t[&[ G1Y>5"gh71Ŷ\qӱ۟d^gTip I.Å^$<sتsd.-$ Mc'ἱu/%@n.>gZ|=Z`3WYڔS2?q"9uȅ]Z7[սqME%B,3H]F7J%[wd g bGrsnp١uB]#B-R2NGIhԗZ|V_^\!(g*TwGCo*7և[S|~U@6xEg#% >=EnjffS%`kt1*A $Wo4S? qC;b͒a5CqGQIjGwXzyG!lq3} -R`O߅bebFf\icnyYHQ!\OWsMg:%'^m΍oLj3 (?oՊ${P~^p?_w:JL,?Ңk&ABG5,[4y3œbҊ+\%$=Ȉ!忠wn+98-n}{WÝo ":啗ˍ^-4HG!cI/HÄ =xǐ#[Ϙ81ٚV3l$ӱ!RxJd|VkA\fJ('|=QfKXMP.J[Ln#cgO .AK >C~?\!hcYxԒ> rg -(QVv>l|ZC\m(>226.)b}B!6>q%IœXۏV1"͸JVWs_/N@> 7(օ}zi`zH?^~ImsKVAJы{q ~?0 ,fM%36/| x`LW 5wu⺢!76#EG;Mb;'2}4C/ܟz6-R<Wf-W+9V^rH!OoBE [yEtSV? ݧ9[pgx`̬4gWCk^IыȟCPo|ӡGۙC|"d)HGv Y0}W%%%PbHD*Od6sԝs}y{ޯqJ^,,TEо8f%؉/5z`#oOphJ ]U޷:|R \GKI_(I9|@荗;z!3ѮAA"wѯG֥<;7>3Wdg8{u K6\ћV*kz6P(V 2N|utA8 _O靅&,2q҅2yh|e+aN=*o|[!uvjvo ͭKxT>t6ʰHڡ0^CXg7\•(iIe{I t"{6n!f6s.jS#  W(a#i18|9N" wû#&gG*7]rkXf3O|oS;tW s_U 危uLA'U3ӑ^B* 4 m8@Uo}"x;rEovВ\j7deО%Srƀz>]S}]Bl/Ri3NuVP풙-́# *:PAI:qw;å,)wJ%ۜU+qM8@[ncId@=t&qI݀Dݷ):#dNEbJ/yd22 :dH+n94V&$݌lTZn:tb|H򰣣$4m|&\b-\z Q놛8.%D,#u;İ5vw~n,m} :/!&;8'_4S^ʸitC_yW%Yoqּӥ *P%ߑ#h~MOmuwJ[o1ڨWR҄7  &xJghrfRQWY]lWd o] u)"YCK,;bݎ"FK //$!U_~>'vػ]%'A25T  3s3vw"Gƃs_.=7 ҆s/ˎ_ղݡ>2=?̷< /o(G../=$SmBtfKF,WWe(;ohk$s!0bˤ xk9t/-l^ӫ)4ch(lerp7#"~F>@ef-ar SkQP5J [>ɻfI/s{Ĵa~RtlX ͔1\>ZMp5Nu]R D);֗(/s՞|dwhp-'O߱@{A[w׾]ã.DhAO86SejiQQehEbh+ )쿘X .?EWac' 2>fHN !{C.`71x׿wYs*(W@dnyOW  D2sj i ]0\Mq'OJm:&ϷWsUۼi2'i 1RsfH@}S›"8o.XRO8~^X1kEo-e7Q]K?e0R3VO.MSmZڢ|. ML$￾8`27uiײm_R0T- pn7|w$<OS6߁C&C(Y>瀇 ak5lVq.W4'uCh;G*ExX]f{]k.+9ܼڻ/=DB1ysٻb)ΧK"^ΧBi6|>fQ{|\`/hks&دN 9H}_%N6TohIn-+*m[䲀">BPmߙ{RNm7DJZU*3g Ds5[A:Á(x2_Lu(_P_>o>BbK>?&?$r`6e !ܶJ(mp^W_XMDZcsc_+'-$ppI؃6>٨0_ KV&-WL Ijf˯jd 5\/Jyq\`^T_l$(] )/*@[NO?I=kIzڈsGM֙5cTU;|T#!h69JY(; dI@= _:m=߻Bhte# Kl7f_5I^n'؍6)O5W1VeKvM]uqso򉚇2 =o^woK3?|?&Y5̪Z{~Qr8@޿XC( wV.)f5瓨Fz VFeR.pۗ\7sޤ #l`D\h~z#y.u=yYH臶)Q {AC2>S\R.PϟQC;ke K4疛=8׍2Pp=Y>J=rDrޢ04$vDgJTƐ.N?O.R4ݙT?UϪɃmyebA8/ BcQ ֚3) Tu3}{+DA)|[r[siNnQul?38>\R.P\PUCӠ9l^Q mbTch j߸~WA)nuC _XYb|l |W(i@uE!NSg` 5u_ 'tQ 1ck'}y5˳Խ'|˄<$=n\.p*uWAғ!+OeZKQ~}OϩlvMnwRq:,g`cQ=@/2V$$2랽5~ ̵+gOs)fZ}cQ.uz^[A[TxsW.)g 1Ņn+ćc׼RÚ- rnk%qbhx@Q 9gׅ[>v =YBʒleBRIF&."JaIdd m"kR7Μs7}?=^1usw;u}uSIS&@[њOk+A+.7SZZz]~Yn]/[oKh^nK&&}Լ49iP>%њOYl{7@QQCtd-7[Lgϸr*gOhxk6WW#%^kdq*2iT(}h0bpw1 hA y;貋53#xy~U-xk92HC.<r!-fu:_8ǎۆ_侷 o/.q)tr>ey c`)+S!RS5-uLz^j3P#.l\X#W:Y9~iĀ"sZ0OHbɥD4ּW >[\~Q0c #~;myn*>e޾Ft?\NnFkkGq;%dދy !պ7=3#_d<p _MbSo͔+:->U)~ݨ߰+0 wNGv;X;]*kx5xfLE==6@&ƔnA.7uƾӺc`ӆa ( -ʔbN#߸],Im`q$~w|i.cqAnQ_~rzXWLS u~\o|:cNH?iZZ$L:8Ŕژ_ s0dg n6*X¡\} HlV sH5=o*UwqbDFyt}~4;待qh?/_eX9 1H~)‡R`Q9EtV*vr$.㚃_V,W6X%8,2uBk-V(oxx8AKK޾nHaYp<.zmFd'HoJwK|ϛhj+1|0[8N c=*u .D(QP>OsGػ3)7<\S=-PS6MlHo:$Mm2Ojw\΋Gwi= Y8XqioPǀ+%QWiQu~E%A>M6Dpq?ttm bض눻w!Çrc=v=+fηz-*#n 4[ uw5{D@'9{~t}ܽ-PHB?d3Qg6lZ'PY7(6vʳ'L aknSy[ސއ|JBSjL)Zx5niyd}c ۿH3g8?ݯ$[4܆Yѵz^f~`tn7uc%'jҔS*KbD.e>i 0+\ C)& t5v@'|G9o|MLPՊHDuܪ`ΫQfz[a8%ΛGǫb^VR'\甬Uxs$T 05h/z/ӽhg6vSpiug7-7jWln?o]&W#\`_/mvvROf|5w(Gbix?YHcmQ>5\6kwE~}l:3\" poQ=͘:Q1L.׍&Pq shϠ-4,0O*u@}{K&IaV_?JG=\}G%QCͮyH'zi:/Kr!N{/ ^7y!zAά u5#B^|Ԋ1bU iwQ\ H+oqY+q & mM^N0P'3&#f|jKWuHTb0U Fhվ"3_D+E["V}٣o,h_Fi2 s .PlWm>|.fN\syKdlhdvʦ>9k7mm#c# W0~٬.6x>vApmcmѕItHarmÐoէ+ !W VͺY#jSe R`T5oַ!Dgq6hL4ڊX+[Z |&?1Xt=hi<GS]TT*Bݐ:Ge*|Zû_V}\$`>?3IpARc_ r{sfaެ:S0Fkdy2_fk d314X>ٮ~!;ZT/T~Þt˵=9Hg$tW%x[1w4Qݝc἗\7 is<m nc?`K3 əVSEԸ|Ay晛hA#kt`:&BR^;yYY?ܭq+ hkV ds~;z'rIGd_HEh=:|U4s)C=5!GS!av"Ks)lXԠGӀׁI|.P礜5:P E)\(m|m'I(&|GwͣEhNէF͵ cGާoZg|ަ ]jc ޘ#ԃ" LqQo(rԎ&F+?\F#VC*XciSq<M#YV?\=栺Hf'S3r'olyT,Ja".M'̓]_/h-{YNvD$%lOj5CA~ re[y-ޮme˖q/ʂ߃sfNAy緷0h]wyTM̙b8i8c6#{dEpeV[P~+Ũ 2H=B13 ze/#ɓUBA,7C_CVq.ufwBֽt=ޑktXnStVT0ijh1Ag6sq)w.$ݾ W! \𳉝 <"_9mrc=ȀcZ-<a izz+*i5h~+̸xPǽ}^* s&immǗeSN.>au cvZ1%Eڴ3|'y@fzɩ" ) Q/Uֶ ?1|mb^i&zꜛFEȹHL؟=<9 %SZw+ fŸ)\FH:d &jhA:"azm{k+"9Cw!2Zz7A>.ϸ &Ĕߟ >:ђ9񂎦`ȕDK8гUP>Xi^x^r7PgQb1= Z /[(V}N+IfHK@OOI:sп.(0ؚ{Po2(젵3.nmzAy=qAa\{I_}KY_7kz1T!{E"h2{q,MĂpsȵCU%ՇUU|Sl amÂ;˷sC>k{%Bml@#5_?#Hrc&ټ/) "|w^z:,B 3&pOAItl& ?='۱>XUGFk1$q4krKrh@Ii% oc9%F4F`iDGpޮ{SNF|;+?GR^o]!mgUq%j-"P/٢eXЂP$7*n*D=de.[ɾ) əs3y;{|u}|o$}ny,à,53seq^c-㍢?.3yg"_nhK&5#w$އϵ]j?1{mNXcl[Gf- P63#}YhδexPxx2_k+R " ~о` &*~JݱeR`USG2Lҕ^x ➧EUji1\O^s,8ӫL /'i|n̻/Vj%\X? ;E~$-F)T3{#t-7ʳZzGo4G _UjφPv ?C1BYdžFT4=/KzO_ej ؒ~N`iwz>OĿHY`RL$Z(2VP371N;'ıM?'`n` &^^$KX %;Q7tb0ҨC['4c'yM&e!_\Xi A t}ZKȗMj7|oŤCtDCG>1uLS_ԋ$tܽ ps6RnbrZ!r\9M.Es? r<\cî%@ bN%Õ}"?(@u &^=I(%or .J&D&[622ı99:?v2Y<3-%5G\P{f3E\:k縠~k@Y+B9ȇ(Cmˇ>OA=gcԙqJ Mp/;b7PN,PLמNG+j qu-rP?=P|`ү8Uv涋;vBywe$d4o/B#׷sNRY^`rەm[;ܕ[vV$ "5Ga 70*~:ը%딪cƱ*'u:D#_'ԡ?,Aɤx|1̷u#i1Qz"+p %rMHԥ_{O`, |lMK!J%5<{cj2Á;B vy-3vb9J~եz aB7; Y,<"XDdb"4?\RbJ\@) %b|rO?/h1}>U&~uSsp3׹.)bc?]9V` j1.^e  c }5V/$Wd!]/ȅ%M:.-c<U'5rزklZL9Sӓ@Ţ%5lJ2.!;i8ê$Ww.?i,Nū ?|Z t3)J?i|[j.5ё>F/ '/YH_.1$w(zWj 8..rh'[4Ւc =ڢzEq _i1$ MZ^@y? M ё~H5=̫%35Xc =-#ظ|uZ\߁6m|G;&x奨hexD9Vd pai CZ{`jkcgx}DEf!EYU<<w7j&+)!aXU3c/A-eS0 *M!nf-ኞHӿјRh f rH= ߓ|uFBqR̀]l%6w׋㯘8k~ CV2\Y=J#b{BroI= 7|G:m|x`K3A*Cn0Psz79؝.S ɢ|>GA_˅>iH>8Mc]isV4!- .3d~7%]O&#t|TȎB,>Z'{\&DG341əV9BtiV'u(XW'׷ kJ y`eW+p?bTEPK aVsLgho~n?xZp{PJ cL6^M7$N##&?vR1Y\>LDG3|8RW=n1.Gj^ziذmZj\W"4m˔6T [DvuLS6ύKjQk1_&\C\/u׸}ok*?1[Eaz.CM_:9կZ+Ѿ¹ZLveǺ3SՄ1(/ s93tprK]GN5RР#:^.RCM'j*j"{?/d_W 8Gޕж;g072A-~|=-ws~L԰T^mO`o*ϡ\eEE@R\}O> j'9eR|{7,PeԂ}\,DG1WڵN5pj0 Zo{=Vn|+ ..Y ؟}8ݖ:4x,ͤcuCrRtzQx@?&n9:'e]r_LYҔ_TnHpyS07/{8"\_V('*hە0B! }:W/ơ|Z1 HǢA2= bGgpU3bTg5@BY0|h?#سydQ񈳷9uJ}@A% ~j\/gqZ޹WT., F_%pc5gQƥ 1M&d5>~ܺ-'bN' ?>(Q꧱pOg[9 @c;fKx\wYH'57l3|SV-fWY KY4}<YA"WWFi\p[9)Xn%&V^"b8vNkAZg);g@wjzgѡ׺,b$;w{t3W+z3J|XHVMUwİ,}/|b_T'HKߟ AqиVK/?]}fp:**q6Bn2\Q qu@éׅ0ibt82zBY&6, -ImM <8;Н:/-^AGtބcڏR0qL!Ե+gKs2/u=qj{;&\?g( Ϟ<֌&*a/a~fdP:3{oc!I]B̮t)S匎i"gb. Eztl9VަU5~Լ@@+}W6/>oq;UrK|=/n+?\<_|jvOk5}o4sî=b.K2^(uuNo|3ɩ9\H5҆?7_>s*Bؓ8y Ch;Q;s|l&槩vaz7miad!lpNF1бBEl.y:JhND]bŞʰ~B+?GZpӨ|,GTeN`r6p$8~_4IdS_ %DR+uYokL3ln^q-y *#Q9x-ϛ!i7 򦳆PFO\nUt^Uټ|⢱&:Vt?gZ R';H|#pp ]EDdbk./ʱ6KSg~T`d;o J9 4N=#:V׶x_Uuiv 'h8O1&y㜝 ? )S:O糤,>R;N6Ʀ9MЇ |7 qqyGL:V36ߺ=N|dhQCRUyGȐk !Nj8W8=904ήY\%.#WZJVnol_nHAYZ!:VrJN}-IڳQc%ۓo&~4Izr5~=t勸}]-ݧ錊B~x6pwd{~9Rߓ/{ wtsX/|nDVi@{\W}.y=VҀ=i ݠ|s%n jI-)|շ{8}Ni\\,W9F>WJ8Wh"?`E5ijmξ}g JEB6g!$b.\7M2nߠmɖ 6ZRRo[D9yG?n?{sav܂u^=AmA욶rh] e>"πVAAcLN_ zG>=7g&o5`oLuRaX">jGTyYk̮JyZf%2e^S̙8g\'Fe!'>Ku#AV wEUN>2l|Ңlr&-#9lZ=m#j?N~M~Xmc.Aa-dVRſ}32BZ[:K42.Ҝ}w,C~UB|||<֋E&?g@kNSdj(;z; Tl YZںk nݒs 'O&+Eq$_wLaMVְnANGwJ>EzȦfD<zf܄Tm?ݟR2j3L`:s^IgbK!_sT\οyd!!a>kR`p} n>gK¾Z:fs/'M̰;Swo6 2k`'| łHp㶜iPcmW΄UEOdP6zNЗV al^y qIs=7cݚ`f}܊3}2d:)ˬ"]o[,)־w(q}l|ӰJ}c=̭~lԵb$h+A6C\򻈹' g7M1Gmֿۙ!(.0_Ez\K~x`FZmyŃWW VΜlN؆,?/; b.=)V ֜]=C+4fEE: $Ƥqe>E--χ;Wk*S2mMN? _G- qIp=.(nrsADs&GYhx%G. |L)e.zX:冻wٔq^>U5A+Xx J܄$zhz^~6[T?wVxeXb2Hyy2\9\kn7Ӈ+tW &hM|2PyRe٤s=Ĉ+YNg8\ʦg֑)h\p"(r!}~=Wy78?v)Fs9404 T!.6b.%Yh!6Ú9HXl)! s d6_ȅ(?r5坅Xw11J kklXl[a„o)Ғ};!b.i33wfiwTWUkNE2\7fk=Sr>2PL~$’)zz,M+-1Q`8e_:k`hnǕTS enx_~ǥCEXL$ז\9nH^ (7/}3+ n2S_\7NSǒm _z?=ݗ#Tg @z>1yI Xn'zoҋ, ҏ ?]DŠ̩yڞ+('ϊ4èO5Gq7Fo z&L*_ޗ ~qy 0ЯI*ZNB`%*o =W *A ]M޵nK},{BaZ8N+=9=F G0m ;Xs]J:-7ܥ*'b@KoK_CA,q{yw+I>5CHkhj`)ZqҟkfI~c|1N^EgTW\eHԋ y̶/m~Hڿo_15G:S5>zbwal0'`CqwҌźH8~(6kkn.( T)|ksK%gMB/4$(IE_i by}76o:]ݲdPtB[rv9?Xg( ӬHjS,fܢxtc`l u0_M}גA#v֍2z jMncޡ=)PTSr?`C?$=iTc?y6Gv:Zz2]!~oYݎcyFZ A;~S!2s2+Kxg GxİCw{t}-OƢ5vu)"i1l2)yv'*;tⴷ\a*4E3BJ Y)Eg7~ji4kVR;gMVQبrܢ laȇ A"N/l] 覊'8`bgB(dzW3$匡ݬPzX<n W<&\.K` ?~/p15jV9#)sZ2mG˿򉵲eH:0` ?/A!vܜ3=EMoRqC%^Ic miP\L a{isrFNg16{zeӠ @Z\ "i&.o@/ U#v.rU-[W<7DžKUNar0kTa)M(!".0c%Xrh;p?OքAlBȒ5KIײ zIQY-(dNH٣D"Hw̼;><}<3=w={}3fuq?E&b؞?ąyR:tг5~^79ؒd(7l.A\JOYh7bwڕwvk+ΓCWE zg}\q!.%[]eJ/R.le/@6W .6,.7 N{sj"r7َ듂_M? -t~-So}W9&뛫JW942<\__ٔNrdz_E08:F`DxݏPV4;WWh/\&IشY<.z<)Pj:qVqi*~~d=;ټro,@OG42RtqBMGvɮ7bK ~و/#674"%4:k,NO[Y_?g\Q )kS9#2C[WZf#(@Y&MskSOXq\_Jkԉ/LjsRf ι*\xLH^VJ A3I_;[@3~~m#/t3~1//"/LLB ጮp?ɋȒ. X»4X]n 8m7ݡ0g*kEbzswum)ԍ?eC6}_Ƀu=}`ٽ[B/0n!,Bqr׉g+v3pb;:1EgתH#4ndE3W\fc_\qT1Dމ69 d^%ͱhnkE.6<y  +O `jz[M] ~+{??۬%]vzNe,OO2eӗj8lv=]i\޳Lx7:W |h͵5;g ڃD f=r9x PKK"{Ϥ6L7_Xz=/rȦ Bwgac| :RgN̫ Y+H{%S_|8qmnnxv-dZu ,,[~p3>fqiO`s]Wn#o1]lIG'hKWn?Q/ŋDB[n@8Niho,:TU,PS:P =ɇ^ajf( t?Pёq+͢$|'b&.rŇ1{r0XD wy=ek-5e)D!nW*?ЕP}G3p\*"cZq&WSt̯VĄԅ(?<N :M;lрU%(BH,Ԑ^"K>L9:2}7I?k!䐤-GIk"E\gfi!#_.6)^gTI*y zC٤bs}kc03?~4(<|~q--E= A˝s/t])WuY6MxX, (s)d' l<03ySHsK*CLqKw\zڎ&-mѣONH۩yh!arw"x8qوm߀󘪢Ic?iW\uDX5Dz_0ywDm幍IHw7Yo9sn-H]zі)ܫ{uhmƇy܀O[*a@:1úE6wݚw:mnkP? m:۫8Ou{0\xv\[IMe{>! M>7wit>PUI#A(w|qnxTʈCN(xU#9i|xv\GQGv:NA^iIYR5yZz{#==bdU[ K=GmqvO$.0e؀KOUKUGEni9~eT홄vc:պ A좶14_>Ԃv+e%^*3oJ;<"Di>)<|59ξ_4^oWyE/=$*0)Itz=&ds<5t>ͅ6)E '(qx*\wN\M7^K؈ SKXCcK<<3r,< WQav\]fK{p(z\`|@?d=wYqm[n,o6huه +uڸbptu9/h:,y#Ƕ}{ÿ] } ,ʤK-1-RY_-O7D_1>zSl>a i-fϛE8{u<؉l,x_!fsQQ!O[w+W!?#+*jMʿ#8X5[&šPK_;L5v6 r[rbN٩b%ԟi|rxh0瓤 @ 9; gsxk*;q |tȀGd!Ί.lNsr3jOYK@Bir'YCƎPA㼒':Ang-m=5Vy5cj*j<3|ۛ}y<|Bi7X/~-g^~ZDz$5^EcI|Q/z? d[ vu^"v[yfw _ި!{H|0Ǵ9,0ݼ$+:VCm3i'uwYw8_ePP6S\8\@o]PƢ͔?<ޓA4/ZĬ<:ñf;@ߌ Z }u٢0"zeT\(q 滇vhXMly,,UgAM>զe`>ƀJv!7wWJHCfkhdH|/QǗb^gi?9\-S#6'_GSOpD˴?;i:f/tMi䊿(A}W_ߎuYO "٥1H:!LOA1xo&7ZnUfnic+a i>r8GLW>)e5 ȤUv6Pz(_YÎ;Ѕ4GnvsXRR%K[X2x14̋ʋ_^u)R*3x^=_bX!ν؜@^li.QPrYˀҎ(,,Szu'N}~UQh60x0Ƥp>3C7Y(q ( 6s+K`W[fwzӯ/>a1D8Uppmĉ c{p=d{DjJNom"c;8.x?cxz!5 FpAٹJoNp;>5<|Q1bnuF&dc%d߀terҧ5C88[( dgNle М8@?R#D n ctmQ3y 8p^#pN2~=E{d"2 ^>LbqvT ׄ!ԟzT70 DR$QU*3Dz}=JID${l;#[f%-VvʞI"34leߧӯ?q8Ύy~?<}^뼖/4Hʶr{7p*"pDW|zi%fa. d]łط AGnwtO̎>Q.ۙ!V(O/5lݱ'-U,+w  5*Ǎz=M>1Z'RL+q}ƹaǁca;65Mpj\:xIkuoo :_BszNcCCqT]'ZeHSV*8pcHhOtէg62 YTew;~]QmQ( qlg<&g.l5pH3v̐g{ۿ'ƚ٨s`p"}nq_?HVf.\#45ϊX-Fg zPK~Φ|ϣ4\a8 09`+tWk-#Sg$i7`P('Ep!p؞'z:Lnv I^ηDxo9'kLA]Py3*EL||\jf2HY[Yz2zoJ_O"m~%+ߛ󆎰E)2An;9?%O)8_&_lD630tx1-Q{Lz%^=µ!nd[^CtR`^ iF'TgRoԪ6n8X|[Rl{U^m;9[-cfNvݛg&g*y2'( VU,T{\&,<>CR0LBتm*JaQCYYGWxybA&`&"zޱj ]~.V5-5Hqz :El:@#=ho"AlRN.#DjthoA9<.M\O0]O>%Uih6H~5K53g ok{0t.ܗ幍G.o\t-[aծQn~|'^ׯ,S:[aJɭG߾I%6s/СК:l:zLK4DCx麣"|ʐa8<7rM9w&_xk)GAc@t@kͱVW x H~1aɇ+w}-踄uKFOW1RG+*RN6|>-h?qn : :Ftx "KA*" ,>3kb┒k1{!(u~qU@鶢2 =y eL3w=}FMsN~()(G<-շ4lz+1/5NeguF2jЌpElG##ygW N v*{sjƢ!=E9\׮l!bwa;dN0fG?m0Y2ܠz@ȓTA@OpBM(^7 g U*s%Vk9w>#I{^U#O_ͧ8[$,fpB_g.>pʱ'2U73M ]r#1>_BA|6;1a벚aQCʛUP!7-z%|l 0 MwKv ҡ.k#lg7瓯B1O@\:\%2؉})ĮbEۼ`^o OBba'aYz8jog,ix7|W)ՙ>#+٭cu_ TpIK~?&T-~.pR],+"Uk!QrO\\R4WeJ}Ni)RrDՃRgus>U[oJޥd-,#Jh)Uh6ԭkFKƏKMs_D &(NG֦Hhwt#鑨'gT E2oPԞm"ͯI堗L*i=)'#?^½8֖7]gtQk0~Wxc\M|7b++C|||UeY"Xt~:7)tѲ>[.z*&njil<6j+ܵ`,J8C`;E~MM/Z)TLU+MiVF Y9-,{Ԯ\qx"qghThuys, UٚAҙ D=gM;W[ݟyGrj! )Gnp7b/~o 6:7 W/bedz$ݿ}gԣN1c6je?Sf,q}>U [/L^VUE :z<ovy$=;!pzsz{>`,-fKnSGKE2K p J ֆb0–v1|áA$N=kGy'SU >ap9#pā [;37sNY&r.S|%"VmwN*BnPle}/&_l XZ|Cg됳xvo9+ugwI|sAgY$hsO}QUSֲ]FQR#? jry41R>p)>?pp5L++U׍B/'L>]vՓd=cY tߍ503 Z/zCjcA9w{+lSz7dջ[+k9+8|WwljiBr"7g<'9[5\2@e> A 䬇-}a;sCfl>+s}4m~gZUg/?sC!/޹YZY?,KTxt{`o\"NI˩?AB(Ei Yw&tzc#BMV.w78p'wKHM2|O>qe~;-DCP>9ص&_lM5J}]';\ʵ&=LҼ7fW |>>sxFnqx-N]QYuQ›uI[n+Bis8\09ak<Ձ]ﴊeWV0u8pbkaN"a+Mc8$j5c}ӝB )4!7G:--Omwȸ!ծ]65-LEQ/8aa>7'Yl.a8S7 [ eE=r/7}A1F\M&G&KOݟqԶP-ci1GŢ̯5.o. ƀD~]ek5&)מNy!:^ ['*M{Nd ; {di,,L6 s若\g7,|za5̼ l0~+Ow#i6.2K 3eTY}w [4"S!Ř\`ZYYη~kSW/!\\).>ײ#%t,=]\N=&&OB13 \bta/$ q7n(0?IQa q'%(z^s0ռ#m'JEՆ2G6tB1 #\&/n􂿪PkPͨGC^cY+i v[~ז5ߎWN<=X;@=$K$ǒY*؇^J5Jl% IE"IJ ^)%[R?]}u{'#ش@=@)Eǖ1 J)z[K>WlUlpSu+OJE7+mk#\SBlk".g5^OlV7rSc8=k(Z66ijVkݽYc\8sC(*Z2I) EʯEpQ"o:(o#SKpkcb/;/` ǹsTS;d#oD/mn3X,sh6+ !s=_"xCXy|=ZV%)ז}p<:| CYtN.]tEy]U ƾo||[~ V*f#$ /O{[⒪W))Qq-z[vno$pډؓOƟ_q2@p) .G\䌨NY9hr"CWhƷ ?/z(K-K [&~uvG}n0uƫʸj mg "\1%\G# *1)M)?pK8odNl6#7D/bxmr{y1S#O1x1-CngJ(4sS8g~,u:O THE;qC. =񉭤kЫM/.rsfFhěS[;ktWfѾ`wqf8ڑ,Q ,54(vK͋XM4lBAI 5_+lx蟈tgVjn2LμI~čߩ?/Tm&Z)IZ{5˯0_ůKϾďF(GYB{y+@2#Ip0L>J딵ڀ݋ݑ*5L`<::,alj2zT<**As@ p_ζ}N##E.|<(̖{3W^'d9t4JrUlKVJ H=t۽&CAE4mp_V1'&dJ0)=?.ě$8 p@B4Q2*'؏xm=sIGS{.G?nɞMl/7-L[&?fڕN[ToyPݙ[ܶa1Pf$;\GbyL*NQ&펷Z:~FI} ԗc_sHLT鬃e< *Y巰'o}++{gUÕ2|ezA12f?sNP~34JK &FV+vt .2ݟpf"z~roivuy5|^Ftfw!V?TVfŕGG܀?hhuo%w>{>:UlޝՁxO3H] Xt),:gnc*M4,obJbג-5]TF&}DM#=|i@mO"ɬUv?g׉yy-ͨU~#\>(W:~3Zۘ4#n`7⫴ H@c4hcBwWB*VE[ivw9FlyUPl⟩at 5]);?{֘o 4䂌Z[ݸo}< ׁ/mP$(}Cӷ\n?;|R5hQgE/ʓ'A&!CR䒮ޞ~15֐ ,&-gյ Ŋ_\o!. <Wl=/S[<>cђ+^JZ_\EܧRw -7<X{%^r}kNb;uݪ8D>9,7eLXNvWw}y>x&52i֯$Js)Qǝx;2>ӤFOO ˬ7 lm h2bb焸z[* N'$kȮ;D*% W\1;͹Ŷ{t>.sA)52'ݙ땊szoʍ)TPw_9l"I`3rR.9xv qKОC2K۞{xڏ{JW$]<.Ѧ]K)Ey"]X=3ő(}} hɤj^-1&=rNEˡk&Ro/loř vU* X_j9lUi\9F˵Mn]vps\޲B8}?Y\FTv-=i3es#l9Mc^^Fa:] X p.bG:K.S_T5n]T8$2yWݥ $ r]?Pm_C&5'2fvf}DjybuKpN[Z쿜B~~r^?G8p{,+Eo//(fWf] t\:_hW|<={ꘞ6{=|xqt-zHlFO"wglD\+;B1Uח}klN;ATnNޚQ7 |Bʊ}TaWˬw笤Źoq?Bm勐1=:6?T '?Gi+BR7<&o\޹&vm qt~jؾi:#:֦9Gr|rTjSsV0,?L)@%'ԙmRWHeʏ$[Lt9ȥƹ@>w")Ϝ>.)xG X3M ] @-cӂv:K7uqUq0]nlAߴ$0}Bdn\2v|[*EC/_a c6@D5n3KJmW{L3Ll(|Nt-R]wZ%޾/1v_Bn9Lʯb%Utc}gO(~،JҪBV8uzϻI@o.B>փFKi:ҔZIסEb75d_l1MP9,7 |ߪIɬ?T<[U#$?C0D/t_| SIU]pWDYl[JQqz506aUVjm4"*Q7}Syΰ]P~Ɔ t!EJ4(RֻtR/9rvPϥҒ" ўCeYc5'trlo:H_e[QlY~{5ѩ \zJcN~d|k-+ *$ Z)Zo˄Zwc&TOWtAc (ו[P')SQo|gV)yR nV C(?R)-k yW&}_h4'%YY(1(?hppM&-r޺FƂ[?2{x ֈF] Ch;xd'"d+a,IvP=N,!)GTH*)BYB*[6k3͌f?}9y=9= jna VWmO)@|UMIQ>'udxV}xYJqU^zO[[Ȅ1F׺ýAQɈc?4SZ &ao+?x63eR'9?轱]0^&vtŻpÌʲ `]q}a_JjLDMW.Gt뺜PQ@ySX/A^ظފRe[Ti7^ KK>I)L4Kf\?!*ÿm{z8::`+S :EE{קk?z U?Z`/NCntpFp8|`MƏnn>|[_ Qxe>Ư YUx=P>~_Io`H,hdv=VHs"WDMSzdewIW&lބO&K󔵛%QU;.X91uk% 6Z;r3ĀqY; a)FYo!g۸ FiT9KVm^%{ Ƕ;N,B!*}7$fϯSlۧ&#ھ]fs5;.#.@Deay$<! Y&,2i`+) =:psTijcbAeԒ^ۮxVt_Ixz8}>^Nh4"~[#gڹg_y'MpWPHE-p'Տ] ʓ~ÉzZ#UyKÖUHSJ!lo(m:%5;xn۬YY0ݢVn~c9%wnQ;`g?[K,ߏ)凫W;'i=K9'ow ֻ "R񠥅( 2R ˉǵ;NN|pi_{{d`u衰>L\J- ,E eZ=t[شo[WnM{o`l a _ۉ3].!=;}0.Vg{T1zx`u/b m+fƌQ gcJ4}gYySZĽW~q??-û:{< 9ɕP^4vC}rMe>2!}a} >?iu0'%qT-iܾx%os덡;Aw/‘QaS.Nnf\مN~;ߩ&vw Sj7G"Gj*-?DF |\;!=deJ|8KI.~}Q}G*.lѡJmLwnB 7j!W|3h&?T/ϣjM/q,.STO{]"؈&Ї^P&?FZ}VoYDŽ]QU)a[Io`oRzYao|BNX^N3WE?zfЪergYHwB?kokRx}7TydC#b[}wqQl>١NmOU4#o9xR#\//ȝ#gZ`OQ&MA>S} 5Zdq#ū<9@Td@:};,:Mro珎vMz*f!x\?_N2y'1<"b;vLRfk[ڂX) !Ç9 r͍ ;՟t-cH?OWr#9C,FP5_[gD~`S7u7֡'C5J2`_ n>~_w_,yӷhٔlP*XwMvG 1ONfs}Z&Z{1NϪk RΠO S7'Vb޿?)jP'FˊL̻ xO_}hWgu 4b;nel6gSv[ %5>79g}sMZgJچ  'i\E&e7{ ۄ5xlz:>{N6@$H{axJtm)2w#ԼT9t.ꖋ\헡=_0Ghv!{ܞ Sy5bn/@^2ؤΚsϏٱ _^>+Um}A {A$!sDe|K<-ZsqJ!/{l㺜r*}{F;qn%y.lUlgy-6uuW6i2B1%v T ^}7"9sc B CؔϽȟٻuoEYK޴.~xrغ!(7LH(ѬNt{ɼOyDDG^ lJQs]WPT G$  a~~78.oM}ogҍ,BfWu) ,Ӂ:N@ Nnl4`B]ܴX60I%]ЅH2+lD zBz,?v>ecyCo\q0_/x !e)R4Wd#s% Ox`icvgIhgUW?P͝s@gx(UتFP2ÒRίتE5DS\=@pm(O=ϕ}Ǘm@de)YxHj&k$S/|<ӡbZ+C6ƟX|pvǏk2?_ÉB TոdsG^j<}T 'HHVs) , ϗ8R~ѕgx'oZj&>%V! Ka}<jXgPpr|Q']xMc/^ O;ksMoF2H:>h0FߥdaѦBR=tsM!vݽ%]m)7 *DAeg兹M (ҷiٰx ux,txR`RTUvH’_w:y_ grO𤖞UNsq{- ގ1vuŬd&?-9~d7oB^C$m=s.'#*%uЪn^^,{zyeߦs5E㽭u+odgE) %+ա\L@K%ȼ-&r*:0Y}*.:h0 .{:99B- eC檵E .[,j2uKzՀԼ'BR yp⸮5;gzdgJj 2l`f2&'2|V9E@B8=Øuj[Bk=b.fz|/ϫepMd)(GAOo7ܿY8xFPf7@ /ATF*? LJA5MVTEZr鍸} lݎ z9-찔ZaG Iޱ̋-EC%9Q|}}?3_mw,8f۪./VEUF狒(?b.ˣFH÷v&*?Qt{ϙQ^\ Cgn[G&{ txA 6F*Cwr, Bң2w{_Kk`?]x֩Yjҍ8ʻ]#XVۂn[Նvm*WupOC,Q>'~W g*!ag Xx7ɚd/K֠"kviL/))KJlYSWP֊I$,2wtG_>y9dz~Aa=cC9FzXA(%JF?i $HcV%5+_k+EdKcH֊) 4oz) '_g;jP$w> ꨔmqǟ8BF`ڿPe:o"oIWl/˽mV,F85*3ɚ۠NL%v!TC>\ÓhWyj!8{TַLmݴ9d*3 5f@\ao<ܟ u &kN1lֿfR-}|n&I:mr#='o HsYmr1y?/-g J&I@|p |7^t n s/ Sl AjC߇~=mwB+zzmw`0yj7AGb 68i'#U2vɿ,?S)rm q 3~f4At>)?quA>xA^!|gͧMᦜ׍ueQ1ȹ&=y =0%jRqvuKfFl;<0yNzȌ'[o 8.Y&ガYys6aYY8A;M%[G"?!z@]۬%h0[> (bĸTF/hN\W|&kdS'm>j˶~~(2 N" T85Rf)Cgt \c4v.ғ P^iyFSg-Ei9 7;s?32H{tDKٷ-{t>R+5 |g2  ?qp/if'weT8"mSeKgs&YCHO H%Ex*_0c+1ތ )[}״._y^K{]0@ 2rkW c=E9:KT{@|0~a!20t>Or*I\k]z=ԛe\@z]9d|ҸtiWAݤ7Bz2 A4/r݌:c:YRMU*w~&QEנCႅԡߗ;.P]!EYoYz@qF:wP/xS+IOۻFX|خ Sctj[s hi!6v/(_~ҋe|#cTE '7(ݭW=uG>| xuġ|x<*|8bBwzX>lp0kџ?qUON\;`K"=agAA vEEYq|{^+f7M(Mn> ǖ腲|:?M1vQ_T6ŋfb%PSnECNW\HOLlKh:*:\#q;:שkjh) D\P?u!$c#%lF:&LH30K*)Dě$=yG\_؛WÙ>ru*Sy]1/A0;a7RT[2(FqO+83|O9-@٠OS e+ehd3h^Z0ԧz8Q˄AXD#ȓzkx`]m!DK_݁Vpd8eH*7=8AAS gEЦ]=wҒr"UrC=oA40u\sw'ĖH֛ p2nK0LGF +?['WI6 @iV{O5[mM+!쵰_ǗqR̋ߖT5Zq8QP߭ (Yo%`gEk/4 Ѡyۍƿ3Z ieߑ3ɺ(#QH)Ӌo덖9v; 3?aT_yΏ#EON:Ikp*2xފtc&P>Ult뎂:#bdվo1ikd&; LȊw[2Rأj]Teg>w?|AFM|^ 7}upDWDV9/9[%ngiQQbu_0(DZI2[>ۤ~%^]2\&,A0pF4O44߂(>XȤG\5'RwݟoLQqǟc&胟݅gBMoD:?=QYF)b%{9U}uϹZ&n= r5꿘/uq8A?/QmCvr:y׸Ssp*u `AI LJYC~m,Cwh3sE=/J[Ie!3iA|zE1aRuƇ"<9F$:^|&Y晿Qwt7„zaiu]TJ46U~& H}blݤ A7s[Cg*.j8C7ۆ%mh 4(#dE1β-Vu5 zھ>d&x$ߒ ťkP֑>YiucHNz҇ AzlvV(b6admDMmf|0|yJCd.C 5,4ۍٮ.[HIE|/Yz3`_Hf_4~D\>hRFojHg$x+;ԝ`c7ƛ&fZMsp$5($xQ 4h%yOa;7W1C2IdS愑NrdxDMFuAzyoCחKX2?وYKQ#~4 A) s6 =;+d`Wtexc%.SG ˃܊A0~Oj /SOx iKbMNˬM[^b89a* JYt .NAO\M){NzJҪH F>I_My\W-@e2_+CTwZérK~xhF}&ȓ ?08ycc [WOLUl<*y {X5uyUJtNq%*btz~)hu%+rb&znPyJ)27`] u]L-N|gDT3량4eiI$ pMet3(v:HL}de7~cLbgUxwiu 1l?ض9FVFʃ̿j'Ҡ3R s ~8Uh"ŠH>TFJ\c_Ǽs_ #m2dsԁ8y`PD8\^ 4 N"ǝNMMމ-\G[lGw[h)(}@IybՀ[-/!_/sН_}^b8^a)IKğ\t]2V",iR޺U{qM\,\{ou$Rm2M I+YWjՋb̓R%8%)m-i6yw+K8{m\7\`oڀ`ֲm O{$?mxz ԙE<= ȑVW$HjtNdswQz&@o+(?彩_ ⊝Nq rD~$%QZ fYh=Q?yJJILh%Q~|r!ٍ =s$G E\q["lvuB_'ވ? 뽩nBۃU6E0%G t| {d].A%2Mbi/wR78%Dւ0 ÛT' fߛXYokZYJfK5}_,1"H&\Ѕ2/a^hg\j]FSv&Pu$kE-KHc N%Xld'E Md(ٳV=KO I%̽w̨QϿ׫cssKL;?+X':)=t 8wx3M!J0AF?؝G(Mށp>9^SxSy0U\XkhPxz0׹Yf|>qgX!dK==:Cqpt.RO:ћBxHNǶh8%m8I3aKNڅa元(j4/GZ4/~d"~a |(?g'QQyyizb`\.3̼_֥wrB?>yFH0x >Ϫ,A:8am+77D$jP\("Ix&Ks U۸.%MΘfB62IG׃" nR`k5&sEـ|[R O(D.j^),W({ ibfEՒRCπ5vUKOL -S9UGkӓVnlz;"_chM; qyy8a:]Q|~6V<6gNu⩕F(9눬_]GqGyQuiKfd鼍sWET,T@Z 1k#9P71WFFvSt wQq!s<߉e'*ߔm}r 4p.d$y-KA.$|&$ɴ3r5(?;bmziX^Sf{JVT-%&]a0q.OB"Nrlbj\wgV%B~?sr&~ ĢOy9gt2XYf2=ΐB7 >H&$zwɽ<ݦa|b%+:uRm+ܺ7%NV,ոG<2PgĨ{۽}n=>xD>NȐL5g 翛Ccͻwܿ>x;"NBC?wQLK _R6CMS4"6]g37S5iσ1S0 E0{shʄض`C#&j!N_@rr0-Mpc/,?SKWzfv$##/;!}Ư?!oYbDf7& St\m}^Xn ێ,+)K*랞TѴZlZ|1 ÒR5%!/opy?}%csO+YOO*a 6ϖ-- ]7rO~/j99zCc'6PCE,Lū 1ؿ"m=i@>0qRO$VadS5O$.`q<)D \ĽP<ָooGW_9~܁ʟIs"yh]h1g YEr՟#k[x H~BqW6OݍGCul7Iz Aalo#l[7;`56=ID|Sͯ?"~S[\-Hι!*/''9ʐ!~P#Cw}57ƿʿ)ι]eӟQ9GFY=8˹ňRns@{'m#Xw!UwϟuDD26 d.3iٗMO *߂WY&_)pG 2E(M4mp];H*9?p.kg:dz0Z\&GOm4L-ǵY!9yAuPm;5UVR:`zՋ?#g:l3PQ"MJ7`ID(K%䇑n{y_K^!~U4C }r@o﹆?ZK߲zRlS)S1]uOJ@uۖLlě!./r/O>O 7+tz5M$VW$sɎ 3jy}߭>v@⏨R#v\m4fԺk^(Cng&_,72Uz|($XVR5{+EE|ѾRÔ}0gaIJ T-S, }]{+NuYDuW尩K$sD< (o?_JϏqb$H|/%O2:1&~a6H:c7uwk1l.WI~2#픖.pWrpgdq$ hae>lE@]AiPi x ` Ng0ň M-5Ev W+d?*iM?G\=巧gϺY42HA=(v}cS85~,a\<.^9 ;Cg j=R^C}6-Ti9i#bn9YGrpqXh$lG&F-H ե4(4VH@u 6WE)Po!=_hiz2 _88>k}+ĵ< +'kyy;8#}orlˠS~06>pRmXV a?`#Du+׵lԬͰd00}꧍>_.vs qpv:"T8XUuL&̩ o[1^c.㨮AuNXI=Qnj}2%ڮNhBtnȮ{zAk'7f:v_NxzcOEYYnVo΄I8`{V:Bg љ^GM)IfF-1"'5_ ħO'&5_E.7T|Xy;Kn-Zggz_ {Kr0)!]$.^_+_};w}r3yݠ3&zaG&w^=ރZBdCu s?%H=Va~Iy _rS ?[~h` ޟI|)ZVh-'S0/Ћ]Ng?aSܿ{#ڽz=p#[SwP%oOڠXG qqe.m=3u3F dh; 75[`% o{o G}e](+]bS "-+ݑubG?peA|V|R0Ф(Kbf0.!azۀYN-O3%AYߋ,?XIǩG2}d~'g`2+|\g$&7hއ@3ow`ncɏbh 鶻10XǼԄ:@|OjM/ϜQw_3U斗0R)1wy'>T%)D)_Eɡ,=83&kgeeB|$l;v}TB5I!犬{#e2B_(pnC':JR໙B yNqn"ϚY;'Wץ.mY>38aub٣؝t4ץP lgD+p0K>^);'Ѣ |XOW(˚T[dcܐ|ZPhyx'*D@|~bC>_ xO>;&L%XuGaWw>&P&^>ő!Aj9(Z j2t ',Q xb39 '7e,C9o" }Aſ%* p"'9i O xS{I#.n gR7R=Eߴ3ĪNy T)XYI;b^g@ŻGwU%a歚㻡:qmM #(tu&K;{%01uָe'#+32n"v\H$deed],!22.DF!$8}|>>G/G=^qyy3|Dv^ӇkdrWExyfQ?;\P{ hGTpyӐN,A&Ci;aA#J^߉~'Z|*O *U: $.ʓY- O_:y"K'ZfBY}hÏDc_-|~(n0CR}YH+Çwp(p%6lGy=jn|I+~VZv3\q o*:@yx<M.8ߧB 馴NJF2_zj ~y e}䈀C33$gR+~9X"SNӊ#e9 ҆]r吋e +/TЋ}.PQPy#WO{[ &/iRQb`Q ov2FIXAWX-k([iKn/ǼyV2԰ͼ~32eǴe3.VXmc,p0 0_87zwrqK yP&%hXzt<}F.m_p ww&+E\k]%1Lc IN/Uve,Ϛ>%a5֣cw wҖm/ 8"U WcNk}}_7Zݝwܰ})EԸFr Ka{Ƒ>8RԴ3[^yIO4(eg7tPb6Yg1CF>ibt+waiW|:?q!(-эVl qdWӨMߴz,[kvn ]0n>؝݂*SbVKzKFa]l}󭨭ns;y&X"f\wb;Qf@'QUwғF'ٞr*C\kxCgW)XtzK3M-XwO;c[_!h5;\S~}X;GT`-)/j[a2|}7kdh>pޕ]!c [ea)7Ήj> |NOϟqmqwݭ咹7Mc՟>mtn4~1_GJO, 7xs{0*Lb CY9R΋pB#]-˚-&uXM(0:k9^G.,T-a8Ɖ1x0^"H/'t}.3vKq]&Ę~ն'wkؖe-|s!O8uڳSJM Jv@zn4P}[yZ8CW{AI˂ }(} HCJs%O P-?at"9oT/o*L쥙z]+`|j:u>jJQ:}T}`Kfrݒ}#zqN{+k`Fݲ)f}-Å"!?kȗK>~핍6z% ײy!o5-G'оZIsf6뱕?TZ˾Nxm0'铓<Cm+@r7V2t;m`u?+jFD媺{q ?}G0cb+O p=rޝDWUW+5n|&k!_kqgycƛ6ί|֐d6k>ma Dj^ֵL&I]T9%pJ3lţ ~׿Y ϫL2=Ɨvg_7"о%n 70Au{>z9:H4au6܅^Nh>hNx08Rq#ݟ\v˞%7}XܺB!K\Iay2YUXTk6яĔ8!r)KLNiΜйŸĨrǣlL)*T}:˧kunm g*262iy_$g@>jbdwa3{TW=0uֶDj)kf'_3,_GU~^ ~ly:[I|# Kt -' wΛ9e$}[! f$gt3~]b _"T~XvGD eu;v4al8ېb~|Ɠ-{ QJp8o;#Yi&w+.4#vĜa̅4}?O?_~|g'BtwKpKHn g!i{z(!dtb6 _Qv3JSȁO.h#`QJBE!W$rωt}XYJwC۬\JHW$H*~3r1ͺ6Zjer4/^~^ֿ\h-U2Z83W#c&=xFRiw/ 7zXd b]n7CVBG?+%ޅ\'&!Q[P^2- Г ; j_i\| :ޖ?l5Jg̯~dH_46^?CFMgŞH>ȵXYҜ(KWjtMĤ$^ߟ 9tVUHsU~u2V1?þ\罿6g/JZ ybU4]qo'/PO +)atӂC ܦ]\NJaN<Eg7҆|lJv#\胏#Qd l@Tupdu\wh?w') d4UzL5|K?vgP$_yӐ4jLTޒ byb]~cFWQ%lzS*ڒn{fV؈{LqS#) Q% T?f>[$E~+9a2 G@\*<@"u}\dD4lմ׉d۵𪕻?T,1~x޵anH\Y8<:B/λrpd"̭n~R\R'ښYMP{hi(h|U)+N}Q\wzYL~t0"2OQQI<]Rn-ǟ+,hFכ}􁯷NaһotpQ9w.;IKF_NÚOOAD8N&'qdQثm:A;R]y4Up3)S25Gd2Oɐ9RRJD34pIL2ʘy  9λw}OkUֳ:g1FBa_0`Bӓ23$u*0ͽ{OILDf E'&_wHI+M6U޼ 6|҃|H_La[R s7 *+,Ba79KK_ie/Jڄ>UۏBm 9.A>/[b>BJ' oK9ׯD?WI05h|bb aAJRC\g,)Գ| }3 D|ዺ޵ɰk<&!W.d$_N} )c-h&e}Wnlę]8DG6E.TDz/pʢ$s&xOY7M . Ժe}_nl1R4a1Eh: j0{/cz^xfavJ5*MF#׆>%3ǿvpw:z`|qfV-|C>Z/̋Kg $?ZG4{,k9U'/>솔aO*#z4meV~g%5`/uļ MY!wә鼘ݏ}DN7ASLrOD'UjVLu-aåOuWbCkTHV/_aTORHN ??MCoCʔeIM b⿊7ղCV(næSv)[d9Z%OB6'Z\0>JWYzAaW8E8Iv>(sK=q]maYpþy hrcT %S7LD}-#ԝP.c"ƶna}5KĩS/ͧ㙢6Aeh;IWuEcgþoyѻ;t4z0>,{5{LCFsI5o$+mA OG3Û/4&/Q˰ /iOSH8UNQIC :c"NkRշo6`q>_4:" D]#kvLj ۝B9PL(DM.n%EN Ю |/p>_$BL_Pwv ?wܥZv^ b¾0rG:8UgirE.ZE1xq#>.h ߱/λNmofƒmVeG+,M_*N}؂ x8X[(g||H~g0L}oJ!<)8+.?ZJ(wY<]C/۰KAƹԯT3< =<?`Dm{0.~'Si0`Iq{ Y|o([6;POq\DGro=kw1^ԇxfՕH{vmϼôk & _5{ ɺTgZvp[{^Xt\eԇ9-X1uNstn}13`_KFyO-{i 7nP"KIr; >OWM{$O0zq9)hiXb>ȗCXN|%&ma_:]O*5}`Rs&eԇ?o~ƦS|UϐE''wk_N}Fi筅o.oHpVQ,(>_SѢm*Y˔/D @LR^Ec֏LL$F8~à̒"g[XdkгFRjidE*8omcix|<Ӥm|ǎΛ ĈuWn+>SBmxGLDпBcH_57(.}X;Ko7bԇmLzG5*UjS\kqY OBV'D |W'T iO>-gV0sW@4uw'f}AN}x(ɤ%e4ac-TmL] [Nx~~Fj_NyO{*/S4Z/^"oSS_P8bΥAr^UXJ1(aO)g%NVIn0u6M)ObO0ԇ߯>՛c~'#m "wWc.0+1>[9hw-+U0e8O(obV1Θ-=vB_JUg62C@L0d |>p-) -?|)[oFw _)N}Oξ-wxیYZ 1uΜ`IF㧍gZ:9vg9 0O _֟'! ٬' %@'3Fu|I,6) /Q{}/Oq95u,SgLtG330Ӏ,=r!}Mpoe ,_ F -wxu_s})'O٘'IxG%cH4QP_#g*bi7ŸWef8VV[Q5ݕo)ɕwlq /6'}?D0ye)>^Xޙ(. &+/Kd%8znsE9=O/Pj'S+W|nǿ5q/׭ֹFS-,8ޒL5%,a 9O?M56 +~oJYe;{-jy/qH @ҽCgt0p~@GĪBt'"[8 }gנ w+t@É;'͙Ey/nyRj>?bv%ΥQ=-Rx*&„.Ki3OT+ڞ_Md%V0?y4-JSCzR[ s̘5[ mP1*z8]҅Bf٩m˓ L*VDVi@ x5MȿkX{Ѡ:)ONN!šOK*,_SrXݷߦ]},FbF o#ktC3g̃| n{|uUo6AˇqJcV[|hivR{h˨*p HE9JHH !H("(R%uSJ$Z̜oYsf1=bAu'q'-KNXZ4;QBbarIͬ~}ٮ}a_€SXIS*^-m_;)KPLGЧw蘑܊޽C]ECseGD *0͖] ϛV֎OOv<`s~r7iXky{O?9}98-0 o)O7M/\wa]pW<_b?E'eXEFy4HЧy #}` =~̠ Jc|]}*. 51:r?ئ΃T.>(f,4?o6{WpLw_gcFZ1,͐K-YC#>ysP 慻əNɯn\6Xj>J_]`ގ^<2N|L ~W4}ֲޒ ]#'W^Ⱥ | =+Qg,~mX|.ww }Ck?]?K8-33!JU8z,'D!Ie,ӄ v^@zSᩍnvLh絥e]?yV9ِ E@h._QGģ, (#Cs%[cE1!+y_b83"1O/iY#)diM>w(WkUsx-Mn‡Q{EPL̑>0GհvI]$:*=b{=H]?o=iǿQ;"&h'gcbJ^*+~8O4m,ї!wAL}Im^Ei;>fwktQuEݏ|ŰJIuơ5eb;i]6\oHvi;ʺ{+K_Mtr{Vl(#vB/54?kY_AVNC;㗝3P:$tdzF7f>U dÛbZ|V2KiVR\IT\w zơz*X||y;~:!v[rOQDM3 wǭݒ{xCn"r$dc\Ioo?|voj/ʶ>\auĴ)"`<|{ׁO6?[G 5%>j"DE-!yjPYt-| #`ޣn4*TW#ELuXrOc\5= :QI Sgnfo"'>I16/X9wi \[#}?ucVj SwG8ɜϼkh*>>p[LX[>vX3ỸQξ˷GjA_&CFJe $3gp ]2!c 0aA.QXMvc%E@nv#fS,,› }_, ֑108wC4 VRx?o;Ύݍ?cנfM$E[UŹdkwjKwY _AV&d |xr~=伇Bl8mkG+<]kp05pKΐdnm;=) ńg|rH.x&{5߮Cc#d )˥UO{/>yIdy( bN:駾wNŭpcl=v;7 - K X!mBlw T9캫*C[t,kfȌqzrq*K/PwM~e>|ʲ80sI\;Y[[9 I#[N/|h`19OQ}tq` ȥĬͩ iuMe@_a) 'xAa/[3gcL9M76Zfgʩ~#U(->ߢ\m(6p>6io@},gu#Uc0ݼ 76?/2<"sIi@.~}x5o;JY?Ɖ͓S2;O>{B{fTA/Xw|mt(]c/1o?, SsnG ]ւh~ R0UޗN.' !0>eI-ݥ&+*ƔSA1WB"VѾN1e.`rHoѧFP{pU`u,cvPu.vPZ(j ې90o#V^[>3&-]jaX28d4Ox!IA$. ugL:/?u3 +WC .1+3?Th,J $5)=O|h`CvG;oǗye zzަP'b>3Cik0U|ǮGLKwu2982On>_i݆ & Ev.jtLP(WU sEk%Iy:_ڼZ.b_ q1Sw.z\?5o ۛg+.YtFn=ݛX늏˜ou >XD`zhI#6R]/I`^+ ޿=GEVV_ jsktp n+eE'mR\"s;DEHc#0mH}:CAqݚBݩ~?ѽ v訌v%;8l҈iN>d"m;%{C5I>IFOY7G5=-ZW%3:qE)cBBSh^"0O)gjɞ{|>}2 me7 +qPz6oҷ7w~,^;K=ẕ%|I wq7OR`} ABcKXnRu t rV#*"-Y"}`{-IqF D"3D{LݞcB 3h`/DYɂ-dqew?Jg_Wm@:;s ˢMjQSb.f5~~~M;U4qHdr#h})(&Tua'7ly3 Sa8!HA0[|Cn%O/Y'p}M(!Mpmy'OXp%xfO& )8?G?Qջ2;N{pfmą5Z(> Z?`ށ28HӯO'-Hr쎾( -蓄=J '5_TWǑ-udD^jebobz`">JSc4^-a +_d'I |\ܖXϨXD`Eg i5S߱tşc,^՛"}U&Ct&R3dOR?dJݤ@݊O6>hVe;sېtLIuqa{/w}O#?1^s(ؾơ/>&Ģ3=ϚI+)'Ne%KUAe4}CS$I9|/H_?'gE(&M|Uo{p⤠܁dbXf F6'@$Z˞Y,T[DxԆ/$_UA)3 ߺ$d=hM|4|wʅ보8oVѼϞㄤ]i#u Ŵ,?7d]|aH>wSи7>xcW\/0+!z ~"ҩ}74| ]F&YAl(& p5G׊@c>梅Ȇ/>OyTnjL0[C >}Wk(fI89X{](@@ }<#O9R%u; \v;oȚ|(?Am:McBcroy v6_'>{ %\[ -kO83>U|(`_BsNRmCOFmB=ۧjSbx@1Oo&ArMdMVwV"ȦdGD! "EfJYY9:P>usse6wۤŰD&\Ƭ^#ɭK1!Ud>i=-Ϋaf x7*Q<>E8%i ?X2h&3ؔF·6f"X;/ y{ K u e̔ s]TjĻ_{)'O*^O-5긔Ї?h׷o tC|q$;~ _E[),)5L]iV乻v}jooS ivC?VYM˅g.FIA|E>_ .5ݞ.JU{wͰaKgf%S k̮m \7pd|jRIL73Hw{+tiфgev tg22!C3u`OhU<}GNb8f-ʋ?#yg8Z;o4:&oNR3[Ȁ[8uD3iu"'ߝWg$~]`GO0:RZwǞ*i%jL8ժn/H|}ޫ UjJ`_I,Tx[4V"O]}RWwKcf;ućuG+j?097g}2|`'m>pI%}Ņ'J+yM1Z"NJw:f(Cz{9p _Μ\iDL`DUj&ĤfiG绪jRso|pSJbM̫_OQ{>uV݆O W!>l=GxTtyoPP1!U6#yP52A g?s @e5SCIjW(W o")퇃\>A!rljgǾ+}躝8S }άbB a GґY5D@>}]eK/G8~3C_+D֣( yŁ,l˧j'|up> P ;KZ[ݎMo~X]!I(\;F9G9u5zg^vb(+%3i؍;q̧%|sJ;JPmP.`H0xLU%+VmE8# kha/Lk~$|~GjNLϬ-be{"o> TQnb(ŧ~\dR;5iaDIM8> A3w3S JTM9)Sm!>BdsrD H|m9ꖿ 90ʆd9y@`h 4ZX !'[QoK9j-ׂP?Al>Wԉ?{8$Yx2]^G r|"XWmZV#ݖqN])2/#\#|Fs~H;}UхfZz^:Y^1A)7'Y ]a.KaCFb|=zj{L%K]CD6G]8=$b'p-w%;pK\ N-^EѤx|!Ar-cEX2zJ*ό9Iҳ|wj}O>2t5gO< *ӥ?ĺPț?FS [/E$E2DhBLks>A0J·'NDY~$ 'P,೽c?CX,G+kءyj&xBp֞#ox |+9j/Y O2WZǣ挈FBP~xM.5c;KJ~d̽ ]Si,"c!WuK jYZ}+{=3u'4VOb[B ߩw_< T,2sLdtEr{aW~iD9#ɏ1?>hz@#ےnkQD} ϧk=[}i * [[o uW]M=Yp/ik@|Hn?Kns:T2%Ĭa04ݺ!O?6;Ɖ+,hjSˌ#ܨ`ʏtBwF2NjO$&qB|H惖xYoV&q;isqW< WCOe ;v4 ȇ,:2 oB2 Ŵw6cgEY4QYL^mr}WdIs\uV |lm=-\SՑZԝfmV7"R#W K殼0jIt+`ryŷc q.;~HT-k%e}|\Igd^e k}^OL_(ѿFR3 (4#7kH)Jq7t~H77 Ө n2Y?-畹b)2I4gW'h%.nċf 9D/dBPQ]QnJ6{ oq !>"G0;+.$ Mʷb4p7 1$*O|_zj;|jp>^PٲS%ч-'~Kԍ#4=\6|jv0~ߵ&Tž>㗸+!O./g O8lOŗn'|Y2dX;F q{~c>>U-eY~ϒoz*_<_V:۸1W='P#us9|2 %lQXx|e),ǸRRs_\(O}P[.}>d@jb˫ %19D5LVWQ{XI!cp/i>oY{Ovm6|{duo!\wW(K{{"H=\3NPΧ6f~^َw~O9biIś iJeEqн⊝z ȗh;x*>{CHI({8ֱ9ᔭ"+"l"%ɪPHR2*B$y=>}]ڿk|p>qPjJeEB'{#z_p.1'je߶WN{7t;{b%][VҐ۬TBLYtr $@>AO}H\ÏUMD)$A[CW껻,Y튮=ǐF8ǶhC62!`E ||1@4mΰ=}׺,gu@|{hl0RS^Q;ɼv~t{GJ/:Nw:ӷCJd^eTNIA땞\(3z{Ƕlbj@, nxaZ"23/r(X*N[rԵ~^շrnaLH'G Av| s⽀ ȓ/{{dIgΞ&|(a8E֔\qu ÄW=IimwC|4!S:.7}3mJI^ׅhv߁8r+_3MP\n,O{)'trc%K0>YPE2W,8YT5urnFޢ~*FY J\j6֯mp{<|-s)AM `|۬|rSFDq{ի=MQ*]}FۨBOd D{ݹ!nRt+B潅y21Ͽ䌾+'>8<4o[#3Lod_]ptC:ؗ}Uog*3%:eͫy+gw5S7ʂ}.jI[J崵W%m5>@MmOp";:Q|ZOyyJ+St3Sa\ I?y}b1ɲkgF$Ì1FXUYOL8Fw6* fN/4ena\)Ҵ!rp?ڶ0T{ͼ:3n>m%FMXƤ(&evZ"KhHo ZWfH'Y=)ALhH\(SyvxbFY*O|Em򿴾SyXWtG.=fS1M8? /Mi0Pzfe~䕼͓ x,d"cŸ_݃'Eu9W9 k!xE3q mu;nS%Ljkd ^?UL)U2\ InQ{ ap;ź$hG'fh)RF5q%~D) çɇRrR/iHۤ6zHY#q^5qR!'~4vZh~1uUm:6m鶰#gQ!竽Fqqi? pfL9QT#]U҇szﱨ8lv#6w4f6[/zeDr]#gA |p|c`9uM,6`ܧRI5C3ϲ,z Ҭ7;޲3$:?f\")|TT#_M8Z] ݟ34HPۮd|p>ɀqRɎhk'1$?*%hR#,k .Y|pe')-*-T}~%%m ꣉{K$*,hFm˅t _L:(0)9ZxUѹumcىq~\?Zn-hԺ rS Csfq TPT~IYޒvHg.ZH8O SjN>J7} z@iT[F;Aܬ3ƠЫm9ʖC&E{I/ p c{EfdDM EkΥ J;xyd:0'?f!?1;nB߮w|\o&j-Jz\"rlUEWZY2`Dk6D ͗UcMyb2zM{2P ,VY7{?vRb{! Uɠ=.m^κvbUز_DHi^,ݓ* |er`\TsF`sli䵝]#n.=Rl+JP >Q9޼H?7qΤ٫=!3=4@2OWb3|rҲWh"QW4k<S7 :-7''7`/U9wX]ur$@ ,CU8.8GX9xWO5 2Ik RFq5m⿯0؄"|P_Kwo֪=eQ%%l޻ŬgP||wrW o x;YseT ENyF٫=,QZ(L${j]7ջ)/Ef;*󎹰a,'әƛqYԁ"~& us`u||, ~ŧ:?~EUG<*w^pB;ߐ+K&cH@>`~)Z̖Ӌ`\F4=ף~.ɆPJEH.5PDаeuK7  f}(xx4lW[}ɩT߷f{N'>~Hg^`;Ոi-$0> (* u c !f܉KǗ <ڄzq?;XJ=SXa0Ju_Nf5rۑk1vg Js |?7yY:o#bwmśo$˛C?CG \C"챥.Z^ܹ!?ۆ:k1dB]@󨾻[pDI/7VbHR(9KGZ<ħ oOZ7Zc2' <̊2|^fKȴ3@:3 ۏXb!_ 31|Kh^FY!^IF\g3oPY7؄e>X=. O.%}-|1]!Gl;lIv(yN@kP@*:g{﫧/6<틸_\{PCtFw\b}nl_鰏$XT o( 92EnD?]Jxxlnh8;!z{+TVs|D8鮻}}|x; ox]=|8vU | >Ϋ8%dDq }V;%v}f;L.U6G_yv'ɍ0D ~Y^SO;|uF[cnK^)NvcL?-!/JYgA/ҞbW+Y~5]SYjmxda)au}Dx;iS\}2e"+x>k|sn,!|ͻ&i2Ƃ\`i`f3g/GX>ֿZ||ț9u&9N% nuBNg>?X;K9a s7~x~$9d^/ A8d[7JY3|_%'c^ 6{87(g .c<\نg߸~1@YJI=5dxq\%Q)a$+u%nTH'+9`;m/U*:7,K+%G^b6mxmfK#/g'rd2,B ƛ-F},R4D{l[o-AO%)ioHFbne$d1otT㔧!>S<|۟a ssv^%$3C<}N /-A[U!/cRM=!"_1Ia,($f2_}FWgoQm·ޯ7Ckvg2c7[?ׁp.&N{Zq6;\]B0.;PJ_'haMauAw.A\x0&\KvPoG-k Q'[(V 3cÍBʵdk#KIRdh/>s&ys,A֏ۘQTE/S׾"҃&‚jZ3 dt܅ZegI$j;K/t^۩yBĠ+K!z'gFOBP< @B;)*_k{`zntOfXnyHS) -_k(үIUp&v[XR)=τv#CY3RE 1j-d"ԏL7VЂ!P N qHx{=DN,o[^LD#.e 0~= wnis);?nް{KycHW4 IDE1(\"?t[iBťŽX[M[#U vOZ$e,Z(6I0:u6;`[wPG''_{\q(ҁZZy-LO7N| vw=Dc~m騬d@grHRR,7EۂiD7=GwṘf|NSHhuO4|v sPGmh`mOv`h@ԭևLFoENZu !P;ⷳ=XM(^2tKSl]~˅Wt"#[3 k1>p`'Dv"dwg'Yv8)ލ5;mF0OlP4@TfTIlsb(Hb^i 9 /)[{ڻ-Io6D}t.t9/Cܛm.5B:ѿץ U͛ ] cZ_LX0|@eq2x wA|ٜ|(Vb 1^0J3: ]#bݔ/c_˾ۜ:=BI{Rqe H6Y/?X'E~il4LHҕ}VbO)|dCcf1{m"c~w7]ZN7?#FFBq;`uٸl8z >kƟ}&tq =EA~#`3bw;M֯~IFKrnFV(%~=> sMzjo53,A&x/, SˌofaDtˇ#\}BYꈍ'ah4 wˌ<uR1?4oG=?~ZʚC*\L =:-ȹ\j(NXSv8a2f.ahu,Zy׶{l;<#VX vo1d9~8@ssC60ݪ}'!a,᳅b!(V!b-if UT4[('kak$OƉ6l|3%o2 }e=M?Tqi"?g{_TD0uY.s`KlB՗#cFjri-817rJGpy6;Oqޞ#'kq<^UzUC:)AC @&') 畆χCg1cz7uY't'L6 ݖW:$Wzu"/$d!V'bQ{Bp;>"qm䳇(8nVkb~̧}U$?ŰNxgMzЂ,gǎpyvS@:9" \б]7-ܘm/Ҭ.?ls)g䯅׎ɉԢOdQ#L雷k0[StB|£|hl.T"wQ덟ψwpGDKs u{'8>o|Q/Po#vDZ9_;Gs.˛jS xf( d.PCo$C|_<i+3ʆ)i.-U,Pp>2 |5b:>Gt8$ eU:HݼUBqr [m*lD$)%t]D)*<`ٹ?}|oV6#rEb]xח_f#֭O%v1T?Z%1#=>}޾2#pABC|@0#6.Vt9rm$(p~1g uӁ)^ܢZrdT \7DXiOѴ)qslܝ9!ah&G^gӱERS|4 m7_uAߢ{U'}/^#yݺm;ys{ ٜ^?yZqwӪW/P:-u|?I18 #uuG5;sE!S v柫.QIQ ȫ2?@' >F|>gž9p]ɶBhM(^mSn 1n6wF- Zl;]ȆkŌ¼7~hdY ƖJE|l ?GE~kYMBvYyW!Akz"! }~Kߠ<~8zbV8JvEѩ:Zq[}\"t]b uy~-qb+ /̸uT?>Lc2֘xȜߴ^Gycݽq<[$+!#)DVhޑMeȞd-[~qy{w﹯sӊ/]ZoD;/j81/A(>]]ϫ@A}qhߧf6t-̉#үL3⻈Dv$&qW7e]?ǜovt&%t'L% W ./ cwjFFz9g>3)Sd%[?QUq:ߵ]Wudxd>zz; 3ɒk! ;h.PoP}'uV!~T琈83m%ro䘩^owyD@{iw/&Q4ݔ>(UlSaQ^I|n՟5/)ҤH%VFf;WJ~6<+"Ν@c|~ :|4.~ݿSbdh-2T@E y9p5yb_*R*ba3\ahٓdT[`g4 .zmrJW;^suoJ'\@^w6 Af[ǶFpX@悫=g1tEލ!&T"OSd |(<0]]yk[1W(`Ti%-IBMF-ڃ1Ц!f|E|p#$=Vh>Kg١8jbPu= 28$"?Ԕ4w Z/FvY^f mw5md.XY'f 5w J ygr9 !CT< qxB .$[ K:oVXؔ;aՏ4ZCd.XOJ?%[|;膾96)gkq힯\n.,ځ$fT’2-:@[ź+%#"3mz2eKe ;z+Z`a6J;nl}~NLW/ 1TXSܽV͠BEE߆m><_Pm&JYIZKz0UD'~$1qXv9sMQcmwf6UMgz1~:oBN\t8@-ҫsLbwvk&I8/9~`2_gkwj`]WN.K]r}،}X4xb8$Mv1`ju&MR+eT|sЏm |_ L㽗[i}|]͌)knVЏm|+Tߛ3jӞ'\u*}9;C*Bf Hۆkݏ>Ûv#)a/{.S6\OTLH;I߆?\}rdw[MK\|Kh.PPoQ^ |fx_0k6o}o7v5{mBQR8{o՗Dnk=}!UjYMQt/,1 Ǐӹy7E|DeR|X;yD 5 !X}`K">c]mdkK V9mM-*seOR#eБ5)߅**,sUbm\70=kmYhDe̡O'~I! ܽ8v ~.VxV#9)x?=M%.lZVL}a_XF^ꚲŋە+K`m7oj+ngHdvMw2 yuFZOXQ´?~/+QWO3] *.C~ɞFяwek=X@Sėd9:6͛L%zF< n Z c$bH(s%p|֍B^I| /k97r`2U 4 64K`uO9%g}zȋ-fʵk?m\7yphwTZ&zsNHgx"%uP?E|+o \C8eR((ۦ*gzL&p 7%u h^+_Xג\Xj$?|'IÚbX!~SGa? M Acw"/gj9VkRr1aÖѨj˝G,SmwͲ\eH\:n{wɓNc+XOps:ȼwM=o E(. mE ڻ;MG_Xþ>ߧV~v!`V_ 9gO#F<~=mM}F򫫘zc'V ?f8 -^ v\ګq5**:nkC }thvH5_;}؅;;% Ә%c},Q+Dw  Pp-.0--ӑʟ{:ȭv6Wa?5 oCsp DJKs|iJr7ӻŨ/Y.վO<{ O7/=7c~eەuhSMG{cЏ?cB?r;aE`9ڥ㈙r5Q)S~;O|2qxMBĮ;-e`nu{*F%A ÍL.=8`tPhX̆?ҭt@7CJ[>$=gWg!CM8˙EZunRНV&`tԙJc;GW'sM l*_͓(fdRD4!q%o%.wq<`!Wz\948'9S2*E/"Lzbh溔Sl=Yf^GI%ϡ(|Y ^!sl-beeFX`l*W$7*Cqf\Jn'd1{+z70u^M"ʍ̕ ǙNp8MwsQ1 *Ge&Lh_roܟPUiRvٶ+6; ԍ[\@ pGհc%Mǁ?0ʐl5u%ͪr=G| a<ŨmNni3[u?A%l`Kkliӹv$n':?̥prU*ĠuJ/lS>8aqI-g vY_+sF?l]ZT5h0@!?| W% .& Z#m"O4[G0pS!~tI 4W7I3ףͽ)-߲ni4-f=CvQhBÅ>wpu }lasG%+*zyiԵ\:\JyҏNT4Df!e iK8SM@l3NFׄ|فXwA3o޼<zmwtYKL2n퀫` VW[J&!6ۑmo2mh^bz~-,F'Upbof Χ^5>ᵚjU,gE)QhόW$ͽ= +Dcǥ$鍐 )dHUKPKу6o ]2T;)q./mƌV7[oHv S| v̠Yv̬osÜU|yb=!_= b hѮd23=2uJe'"$+#'PٲSF2Isn|=ury_gs/ĺQ]:]UocOk}8cr:rL 夓zٙ٬3wƊ>>ɾ‹hwdCazĉH!Ռ*E*PdtԞOߡ^!MQ3A^(g& $\XŞk0e+iraKWR^=Y"W7hk|oQ*C 't]Exဌ?kj!ZMؒs%4<0wd10NdF!~uTj5+E2=AeqNfc+F_q0?vxQ*Kۡ">(oQi:"P=F=h#E-w;äeֽ Vℐ.r>_O~4ųX0<~WPOFL{;ȀPȯw9~ l/_xybt|{Ϛ 6iˋDЍo%V$ +{b<"IUC9 W!^M;wY0G՝q3ʱ :xa; "T1tRpg.OY"r@bo9>uܙ+=| 0 [4ҹֱRxi 4Byx0 l@GRUgL~x.  ; ?d f<" ns\W yUz=4fKƯH[vH W,X]?>[u]& [>V?]oSZvPɸgWUh2(Ěo9.yݟzzi) +M>.zx}Hļ$fn냍=M<,ax/Fq >ҔS@PNKck ǫ 7Hf~s(eLY3C WIuS5ǫZ &]{~٭wio 2wW;Ur !/jW3v/ȌW9&ϗDܯp5אf/` mK"tQmگ>Uhax,ǁeL͇+d"LA?TR@,E%('j( 4y%ޯpwbnUaF$0mkrh^Cx<Bۄ't,Mgh_WZ\em?}ԎgYi!cw;S7r~~vx֦֕+߽-}~|x k;0B=hDWSfLB]ؕO2n&%GA|($ ^j]x_^ia|Ρp%n77S#xnEv࡯Y (mrQuĈzt>Zq; tɣNpr4T3AW!/{2̜/V,lw &Pja^!]8]t ?G#XPp;x:3^TQĬrWA~t=8~Ϸ.c9bB/E[{#>Ӎ$j^pO$pq<6b^W&YI<՝uhz g80 +?UR^dk/4tx*( XBש4cFQ5;2/xgT'I8!agt]V~|%q1-Zc3 t"賕'.u/ $c~5Wy:8I0'oY(;ǕSc UL}TSnso8,׿8"6<%[Ab6_Yno]o]Sʆ k|cq.0!ؤY%æf񊝕߱ $pXq"mtWjdo]<>4'lH3*mɜT1KqT$qթѝ|\bc# 5뙢~s$p#*TЈE*\MiLWDZ51OQPL%'w23鷋;D|-2&r;X Úϯ#=R KܽMȜovlי78áp)hܕK bt>;V/ΦN8Ip/oOZM%.z5^U-X0Pm8FTȳe-;bJfLy|ӑ Cu 6߷?I%>1lov:E9{cmh픽L#* ap߸~:87=Vi䖕wZ}]&?On9pn yPb/E}Զ'z\zAc5n0ׇ&ze?ivNl GETz8~qh=^t3uPnp;4Eܞ/$ }<95&ՄNɿU]H~¸Qr~)T<%Il_j&BG s?l\51AtQjpFknd$pD?6j=7PmUyqY%oZ-6}ANaSml=۱Y3=&ZE[[%Zq;_b"ھЃ,'y2W[0;#LԠCi>?p8J_}+U0j`Nڸ@msd"ь9V$7$p#~qh >='G&ڙb:)$pM35fk2ŠiQx~CO k/+%C'%y305ƏwH u?e-Zin.AMG9CWj9 ǰT.gxԲ-T!(%a '5INqHr4WB}^AK}8Kh]]GS;G7~aךn=KI -5E+igNUq\.P$d12)21S2Rf-\JRHeH(eʔDy{}ZGjS6dX5: |C8QU|}"ᗎD(wB\>SapߟACMܯc0mR /oy)Zi) ?C5[GC]KYWVG5,KatqKN&qǴԷ&'@8x__cYvjEͶBSYK]a X'=E [9s2FQv8+tHp=$7JޓGP Mв_r(Y֏t ALSS>qo, =W^KOJcfEjCKMC?8 0f+T\8doV[xjrZNͻ6~#RӵpQbsBubs)"2>fЖ=&nCyX0-s,E-28 $_;ZA^oWM"6WdiF(RY|DN*)n=90 W$r% ܆3>7kE̅*1ơu6,#OZ(EhWTL-;3\?lcJz \DJQMG y{p.iDMⱙ+Ҳ[wk\Ӱlj_$41l,EeşXq.%ƙp8 OR՜Cm_l">eZWCl.x~>[wgk<%jOՉqg<jj$T>J;5#Q4G%d!Vب|u.'\pvFcKËR?24 ޏHu!$qp m4ylwI?cNKGk0ng0ɦ'F*)hF{!amK uñĭD^ C/NFR~2l0|Wsp=,悳<ӌwo4quQ4MϢsca.i\[K닙TKݨ}7v,^)~:L^3gj[r3Ss=e;7?qg{Y'%qח$WKFGLP& ITs]EHg<%71>Cy/e\Uhm۞*rJ.kK(s׋Rʢ`.Y\[$Wؽư\q fφ) :xur' Y00>>\}uR?̣e"|rvI\9I0.ҭ`ޠfi.X[r%^'X͸| :Veux<]$d{t{lO;qp_t' (6d11#؛!%,[]d5W"0"[\ۂ|XM[ߦo@0d.rg'ಞR[-~84FU&sac}8M 8k̡?_efvEs컖dC[Eӂ}[X_aJ==YEڧF piWm-WNj5ֱNͥ+Jp~2X(0*2#BIl9q q WŴ谵]A|\X\E lI^/im~­Kf Ca.\$[:S0M`s\4x2J{R2,1]_ \cHSѷ>w鲥̉Q8ܒYx"+K&C8VO]gQHS-q"9!9n&>CWvlq$zt6;qmQ\hϤ3\j8lq@ONͺ+@mi =O]CLRIOC!5ƌ #.[wַ AIǙRL=sr8T5\$M/'dVn.fzz/ .l2ꢀl'6dU #yݵec;rM H ={ӊa. \ԡx5R =Qrc$r-6g=661U0>-P3dI;ʾrtFm ! MW"-2<\8ԷN/9=49Ktg%*R)lG$>$nlI_U#zuDzw7K*y,a8Ʒe 8TW]1s}Xer)qEh[t,W( $ sasMAV]cP+-wvj\̿l̥+|u@͇EԪFf ̾SI#ړ}reӳ7MgF}3e˃Ne(6Pܩ2c?W#n]D7Lv_K&㭗f7{F;&o-EZG$e ̿\3M.ݨK|*j Ylr쓠UnďUɁ!?F᳗tppiAE _7yCab8P-6c3*mV~k-qs*u pjasMCG=HTqw Z;"njG\86~8td7w,트:}AY H7p_sb3暁E 4S^^E]?ީB̥Kp44t>?4Uf|=IjKޏaVp_cΓ dN.P <8vʒ Kևe ="5$dRK%JBY%[RYߥu>e̙9 hhVhtFG?]Ž~ (.f|6s]|: ǫK)SANr(sr,ixKک;}2NtWLv7ץ| p?!} [q)~ " >h8_ޓv:J2ۜ 55o3y*ׁxb꒝M[uA{8¼ j? bJtl|~*S\ۼFe!WIk^ONjp?Nspys%PXҸgxaJقO laخLa^I79J"L&@>aV^隃v2?$ݵ\]uNn1?C4Ofv^.YeQ%OQv\ Nnsu2-@t[{XT?p01rN;Q27t apؓwGuiK֝gMZjn1Xۀ'clfaH%e@.\"rͲd-M~PyLS鯳֑D8AmEoiSa*5欒~"nR ,Ԝݻy>t`2SB>C3źm̬Bl^W ]rUYݸ~)f(ّTahaN!1,n ƌe#s= rg#]KV`kli`Klxnj]iyr Y:9sD$FHkU?Q"C;;L| h5ނZP&!"]p)F!>u {Lfu-~.(tR,,|@4uاkn~%l>e2 ׾k 8&F+?tc#-߭tpAKO}Fg$k>'Ǟ]=2mjyAc W(ҵ oytF7HUestv}L Bq %})_Rt5Ň<ᰜ"u]&eZOQ/G|WoZ˴5p4X\.JPX0[Of~y՚St9vj Ϛf%9Qj=2vp#]ye+F;lelɏ .G01Ņ9D~,NTi}u5왏A5o?a"^y>즂2 לEzx_SsX_I6E&"擄3k.+C\J5Zm<}~Ʀ"2Ù!W8K^k|~*\m‹7?}]܀I ^pz'~H 6gKdha"4f\$.rxW񾶰QeP %~]qev| ?=fY'P'ҹ}:7i#d| VZPr-K#],y'cY+e(B>Q\yp?1ɐ\^gJ%{`7v[%eO eC.f3r]H/(ଫcb7Z$9-p}pXQEcaueRz'1q&֯PT}jϗ57کtQ'+[Qģ(K6> yw񶆹ZP/RBNO Gs15IwReKg.+cOý":_Ҫ'c]i]+٦1yV@D r领{C;ylek)V~ ?tғQ\KKG|%: _cJv0^ѻ'AxMe2@.U/f;xFמTD$JpjXCHqp2p9Nx\X!fnZsw'W#M?ާVjjmnd~\HopTThZl^]͞ߥ[V ǎhFCťM:qx)tdٶsIfT/LTx#J'Pk}s+Ng:c&۬z##Z 9ϊTm; qH >Ti;ڢJ/ X|Y~x{1ۼ"M ef\=Hv8f4fXd+j;s,&5RDɬE9 ?++/cG2Z<Ue=@繽kt|tvW-<2@r1E 7ɜy>̑HXW$Q2O56ǡ2Rto Z9ldA.h KZs{'m#DX݌us ~XgE<~0ףB;:Dc) r}|K8zȡL,bǛj"_qU̍:/=~!k&Z ?yc 񽋞},S72S;à#9:rNܸIwu/"}tNxeWyT_Nbif"g\ o @ْx<փuKCTG+ & Ug\x9o@x5p MTe!vVKl•JJ5ܹZ}-\$KASw]{p-;;|&+t3VpZTRKAv9+3vmۙ"`< sTt΢HvyvQHxʉVGқ_ayڛ'^RP+e\iH<8~f1Wn|c~ j[T su$w3ogU3NQ懴Ӯ^J7ȡ9oxtq2œqPN& S,V=} {A x΅y7z49*'r8DdbFDž(vYl3)N_喉taa8P4|?fڼcYbaA`__cČt/z2zX檅B)פإyf=\\6.^p=C,uMCi&M5էLZǮߐN\<)!MYO,z 2p[F,U@ ebA\kX93axo|8&&?{(.:஝$7${w?U^ܾueyo0N J2B!Wz1WIdI\UwhкvH ID-ѽ=GڰKKr_P7 _a&XEs#A-ΡuT ]`}pQ_ԶqX`.!*YRrlY}b){ =K."Y"Y"dI=e]dX#3;sLΌ>!W9sRu77Am+I_pPY tQ\oE 'DFul>0bR7+ M\;i\=\ MfmPUb "uZ7zuÂۈ޼:.+u\)p)r=/jEvd_Uh䏜Eqs[Q֟[}_ˠݓ466gVYoF(Z4 5~DQ<:O~x(]/gWc915>(QCoyGyr6+F*fSl?dzWK'҅QX{/s'C{zdA m3CP\uYEBsŮ6-C|q5N)0}B E%fd> &l6-hLڇFWݻ(geX82=WWP3tޖi{Mq/NKjo#ަ:t M*i\NIT2o-*ưCqxPNW[k,^7\OI@K%#K<\˚dNWG W|~Aw O5BZOGaW8kW_Ԡ7}^-*uNZ^l$g_R)ǖZ$#)Q.Ax>7*#KȚCb5kҏNػ&a!ǰ&+ 3ԥ =\/tɮ(\~=dgL}k$7\KdJV2%q `Q-RvoGR;vvIpmuk yaq wME:ןQ.7pM7p C6Z" 9 q>?M*ڑkqvEI}KD͜!y5F_\^Q(A.yW,K"\xE,}H|S˘vFqrc-\[}y˺ibOk_ ,N^z0Y6ӇgЛ^pk\dJ W?%- zh0{{7?~}pZs+ŕ)[^+caN7j*ds=ʶײ<钀i'$'N`K={UwS3vTgu9캃j[orTiyo[. \)*{]a{Gwį_UZA5*D$'"saE'b%ٷa}aώ^z6Avš=#OJPT*$(:r WrɾW@\K\.zK k, f\^;1O4+/uԺ4Gq[[ɥ\Jb{!/^V:? +z曐.iUz&y5M;MqۉPY'\P\I?ߚ&+^㷲|F0W \n\HpbCݴgb8Fv%nB[a_qvI#\o Xݝ2X?y/hosO\;#]2PM}jH)-Et-~~.I'wK\B4 캋FbߨhO!KMuPVaYy?2Q=7{Zqq7O0% I?AoGwgqafSf+ CxCp :gRxeY1jɑ#g@W?.rO.HjXI@&h!:ܡy(?Ɣl*>3^y)3JFqqx7({FbDgcw /e>#ȴM.3%?g﷉)6~&؁Jntgf?y !]G#؝3URZiA=/aeZ_uEDx㙵gG2̩Gu,vq[}xI O2c+NR\!bXE3fOny5Z巳Ĵ|RQ\{;]>6* ϰҎb[qU^ju$&Z=U%C HTyGoO)5Q-4yF I"a?R1{"*j*kyg'ҢBe*t)Ca.\l)*`{8U4϶1齡4ؕ$u~}7gíd~tsE!fBR\A)|-/f ~JW*.C|? mknI2p-b/1,pmttI8YJn/j^JM/KTGۜGq鐸_1t>\޴}Ӯ3b jx^cÃZ u?tCt>Q ^mhkE_=62d](#$GY@獁ygM֎=7<'-L`~9rI\.=(LOCG3*|}TREEr[BuzGaW! Ky: _KHKl .g2fk*ܯ+9ȬZ.lҥd>$* ,ЦWJ.?ހpu>cW8f'e_)#\5uޢ<)QY23~Ee5QMm<74EcG Һb& O+*Yo?ahJ+'J:}BU:̪?(#Ȭ52rW;,6.3t'0PzLh3QC'(.V2ס*aQA﬿WT;zKg|Rqsr$ \5UH x<Q}jq} jcf:_nW9GyQ\ҏ<0:bǔ^f]RN1Ҳ\t3A\Ny \5H|+WbO7GwG)(Aq}%z~}ctsU)mfשxYN4$Zľeb(둮é>#wvQ콩=RDa$H Y(NVf*eDE>ܿu:^O|{EіT;ЙZu^[2'G4s%0 Ic!aa?Ø;#ѯ]+<8=-gu5~HY=p-@ϧh{O U\R(VC{%pe^op3d? s}pܼDwEێj/%串PٙBVɠ);{ w; }S+ry SP\#7*3qQa4Ly"Og]G]S?S5P#cQ8^UlOۗ4񇿋Bs-ji̺gzx0j OcFw*e`"9]B̥Ʀv/W-i|..~͠qd*mq([ oȵv}5GAXgy>t(UE.z}\JaMݭ f ..U l)ė̋jӧ׈$yF/z5jp > ] `:NؿTqIR,U%!Tmඳ1}Ji@f;b,r7k ߍEʨh2߁->|=0̳_/<+hڸGΛѢ:K:L?Dㄅ\7^O}Ѩu‹g:^&eLC_-Ӷu7_~/Y[XRFEt7&rVaYj=|!>{'kYpLX'd,O(& +5WW1{g{dpmf;-S]։OI g5I@v al\Yg (jSyY=K6z-yl^ZA()TY=vg^&eũɧ<577_jMW~,vO5b:qMvu:KaX#Ԉo{BzS9kap?/"k|ex~K=hCdƝt` zO y>q['-!nw:;gMv<J8~J޶2 <)r6Y ncN#4 Fݶ,*Nd#&b@4+J t5p=$гAT߉3&FZBR:sDu^b@p1Vc׃ㇼC^_luB𙚿əގSg.Ib̌of9jc,Y(W{R`~}i[Fb;v9".;'Zhp-i2st%'iAWv}_.OkG?7j?ZQj^60+[ d$7 q)sbBE[ᦼ(ޏQs~RCW3m#qlʠ^ 7YכY+G`-cvc\sG\ypNqۯ5x۠$O{[o T^kcOԘRc\_{f[`-K*yb\`zܾ_J. ϠSιqYYj\<%'wEޝIU'+6V5JbQe%+ȗK] >uqdEcH) g5ޯfHpӭ+r<$>}/"zFff s']K1W Qdv]*ڏu8 ^p5"kFE#wߚ\I}9BmZ@7ls)wN8]}U'i8̱pX+@VES@Qe14'eO 22K) 厸̥7* sQQ6#ݡ55F!̀[Bݾ2r9Dv uK 3!p'b<WX*^յ 7M rX*? $d4:>U\;꒡ )եk֢2%^B\.{SiMf |R<қ+08\LuUG{BOÂP6 /Poe@QS8ZI {lvy#udJnWDaUNg0n turma ~otLJtsEmOgK9,<U9'd$q7-s?!LEetlE= ˟|w^ >,?1 q5vlhA}G\vÇgc{XZÌ _k._ĥ#Qթ4|wi KQ-ِ#Ս弅sM@;]L۳SۏF.9E䒥":f-uq IIs-0"܈8 zzz1G2ʥ ~TywCTi}^qU.Zl?⊓8$e9Mbsk&w8yxa}8\V[CF?8*yȤDVt= Q>˘Y@9paC;N,DƶYSv򐎥PֻI~zõM<|-F3XFt'nX\a)^^ ZAk|w v6i4[K2kIeߝLFAW?m7ϽlYJ5+"ԏkZoXAfhp5e`y=KĒ*ԯ7?>̓thBܧ67&OZb +WCg 튐4o?u9JvPyco G g!Tr-Rꚯs1vh9Ы{ruWDF: 8!bI8? >ZpD^sm>z1'ꔓ'XslhG|%&Eqr]_%:-x. +C V'ahΤ]f_?:ܷ4C^UXٟp8[]+w^o{7C;_ʬ+4/&RAytۼn.UdA̳˔uD]Unz96<$> kn>ڰ}!p|I`pȴϿX9*SD6ut; |U8?uE6=Kd]„8vj*}vQXksOLڎ E\.Gٝo~z~_&]P`w GͲ5żfs^S{&Nܣv%D\'|#ne 600'R3!Z@{[_/?\7.ީcX{OI9yF#ztD .Ĭk:E 2UW +q-^"*(9~5G/Q~UC9꼄kK~ 'ؗVn{둾[E`sd ] \>خ p}7gd; P| zY`/# p8׿o#jy"嗿E(78MN~3.NJ2L?|l{0틀f]9oyhpqiB/EZC߃7÷}w$B}Hߥ,̴'KXԢ0"]ؾHŹ2$.Y̊[鹢b<ِߢ#oo+oRr@O3s-VmNe?9f52^q([J摽2WdWeP(:To6egPCVLNg9OQ{rā[=}%SO|:0[5cErCX/Z3vK : ]۰oͦ5s[Vukȋx?U$--o! |vpa;w+lz~K}Q'x$Ο[@̭[B>H_ sRS!,8=-(rWBE }CMH`0XkW c憵=bezlW^|yr{b ؗ@Gp/sn^e11&{'V&u yluz5Mbf+IW1blP|rr)tLl +b(r"]&7x_9(ZLʅfQN|q65BevS::8M*ǃ֥k]7oQd!`P+u ~ ."7p!krEyeS[S"~ޚʧDoa>g+NX{0^ AtljXis}~_= [A |w`\<:PsDݹT1>;|ë^8$D1sJ\KjbAL4;Q }%FՉnN{{9q'|֛n' |3^ey+r9E)QQ|и$SQP^ȷ@>Tf 17àӚEuP2 w/$9Sg.6SS{M&?l Z踳g%_j!n/u՞H?8Ks+COF&6Ms'|6?Wmᝈ(H_h3w/ s^xh?iދo$K`\5>/Yr C>:/0v妫l@,OäQQJWρoо/_0?qAXtW9FNS]2 ؃ŀ} +&>yCǩ&%dSJ|w~NWl̯CUFrd:Ox=ɧBFtsWm19 ؐXg`p8isT,S}bGA.g&&QºvN w{Ƒ~D yG6H/,k2i:$bk`dۃ ܱƆ Һ c6>q<ܼ9kf aNͶI3k;k9ALOb(w*%/>I٘x6IblZź +ܡOɐ~PBQmczKVvq'N\~skPn1rG&%>nHPfJo"n_ v_Gu< Bwdu`ՑcN0M}v >\33;:h(w.D6浌:;zхFXk>@2}[W#~N. y Nq#h[՛U CL@R4i7;%%2Q 4YtTE&TOҲ|ݧҷuxW#>G6 ̫-TqJS%Pnw^K}'^g$F*ଢRr^ƶst/ />7=-:bq]5U滬Һ/ }x-F_oE* ]).frBшGT[5%6nLs8k+bnRt g@Nu>w CIY)&"zlɠoZ KaI|0޺Z$5<-s_=-5>P{"xgJ#y4"uwLˎȎx ^Es#}i4)nHɽM>*VʍǢ̚?e9:߯ԑn_'Yzel'Ys#qֿv){> iM'}wV.5r\HW:52&lpcTC׫|1؁k}s?nR\Ӈ{ß4vWX+rɟC2`S ͥյM|*"@\tpm:wuꐉXb7vOI3k\瑮Lu~&2!֭}=0@ULx)g<-gl@.MnW5+Oq#vs֋\G?Yl}oO}FA9\9HW80?$_3nbG~(:Y!gH)[d]pvNubk7'WZ w5 W6AK%bʼˆ}S=sI#iߡsPŔ9jS7+zml%_if6K㪌y~1X| Cvc+v= 1op_Ira/4XLsP+%: hoT{ wRB3F /%#hSV/sCiVi3?V5dt.k#gކPGzy<解ik?ppiu > RP-IܓLwh`%|,4aȵʃ]VY`We<<|Yy*b;EJX'[+[9~ sCNze$!EE9~A+ YYZ }¾pٲooFR=MDud2 {$8V1>E[&[֔B\!u uHrvTYctOD3sxg6xobÉ\1I^.#lgpm9[ }Oamt݇]r41&SiuV*M=DGO\\'~a>} 5g['[䃏ָ8$*%$fpmY˝>LUh( Wd=6L݈51gZsF!KV@mMGmX.hrjm:ʂO4̔'!׀#'7`snCS?|VMcR$RڡK~(w-IdWZ4z;it?} c *村u]cQ4E8C{qV؏0r q~\S{b)gרh7|޿oT͓ >J@.qWvIY-j-QxK J(7BpQ=8_qa!M^x2驒O ?nIZH Xc{T r!]EX'bi]MgQoMͤHy<匾aeSQܳbD%ɐ Re U Es&L,U{ZD \k{ш9ppt *9%Id.h\IQ`n_Bd!WU*UmZx6+B~6O1.<_ճ?< v B39fqe_FT7 ̵A,b 5NVJa2!ϠNl3g'U\pɘ~|v.PX{081d9 7xϕtl}Gm+yz 'c88h~J^s0U_z9\\> |?ʔ/ΐ}#'fJW:a{5t=2 i<|άjn _y*qb a{%.B1)Y{(-EU^I.R{kRӅDzuk+*s *p=1HgͺY*q]ݟwP#Wӂό^Š;î=uphp2>ȦOHV=RFF-+%3+%Ie'efdw}uu}>^s9WÊUDerCPۨK&%ymhRѼT3,*ġ6hwmׁ:V/ :9lc G!(r$!]o@7$M։hr y#AzR)԰KZ?7DՔ0[><dwf]Q=>9im &_ ] Q1+MHbuW\t#qxR!a<\t\_9߱qo j&e~pdFŽLPf|} ]o|'ecΠw.CռvgCYQ <_zʐ.5]íR5![EIrR"2" \UHB_GrĺGxno3]t0Nr.z )X]k|AmPPO"L.]ґ${YwۻՉ%ܾJG⏔Gyz.}<_bs)\\.Dgi{>aVb'rJ+5c!a=xȼULGD|&ucf[,\5'V|}>cף$!m9hfgEܩ֗~͜\ cHW9J5Ժ"AKZ挀 mFezňCH.xFg.d)?&&'c-o=y>2}oM89 v& 0Q˒:Jk'D3OҜ9K\L\?y})\9gxZYV|"2ݙS]y?9o۽̴\eyVJt)Q Anٶ"EJlŌNla:*"NW8z9(^s"53~739]C@_1"}Wkb]/YFoIK mRhAOOClCє<muAGܦR+P۫:eV\HW5~TFלY) ~ j>ҸleD^RX1pωoxK? ;:s%Uki<7u0]]4 5rNˮ-Tǰ]HS 8#cYb(.xc!'c[-|l]W$<$i^3yDo{Hg&Mm40.N .\bs]7hQMءEz}-34G /~+\(zE]<;U(B~ߨȂm;PẂ8>5/A.'))j~Y$әOv$7>UE`鵁MmD5Y# d|}d]~b:pۯ ~/Nxz94O;M)uA;Pf{- GaVOnMo;luncN;Qc%[8>]Z@5O+]SCIwiSPk[neʈt5e;/;c~lZs YڠSKykǬ-v DN+ǟԺ(C>i>2#]`^NnϮ$hoLrG |= \<\,`sŗgX<-Ҙ. :?o& -ї3݂`z(J+bGZ`9A';o$ٽ݂ͫc 8ŋ>ۀS}5_$_k}LlN#|^:(3 AZ8J81̡;i$7jQ ņE̙3ia68eX? ?bέқf99A-?b(rr\E0t{ulmE>ݎns;駘t1"p/<; CmE*CK ?P1hsZ08 <" ,pX_ʝ~#'^(5:em!>Nbp6'J]t^ rwS$N-_UP+"Jz;[Hۦ{[lA`R(rF:AD|E lJG87yqz%E \u1ዼĤi'DyAIOw" y}{N:RZdPf Dఇ4+-2iWϬLgp\RJ{ \0}O1.K4عޗܧ뙑^̺A=/qAerpC.H]ZWfa"9+t"=^1f|ls`'rDKZk4 4h0Ck[%r[L H e.\HW7FfBh5B/Ȳe~~%\]~sS:&p٧ ڶ@{n: ]ը ͘/\R.ZʔPTLG8ȮΎ(fr){DH8p al# n%mu 剮Nn+3C_ȯa]TP'>)AuGҜv@Д{ߋEvҮ.IL_8u#xPsn״joG29{w{f߆\+HZWy=BpRԙWn>$ɸ\0p_m].pSy@QBFZ糫A&ufbj@ͯ /ȷ >֌[fGӛ<3ߵtx`>) >};ãg Wn s<}nS>ٖEZ[Z>eVyC.Mkvu)4,g1$?>'BWiM;%\p$JlZZnT|&D-78b٣-_5jn=S17Tq+,r}C q/WԚ]vAk Ɖ]oVĭk,gz%J/X5W;\\;#qͷtNvqD_>eʟY@ח(S3r!].*U nQFCmYkw ɋw(^Ÿr~ $;0Ӈl2=[9zt]wMvw̲w"de%> Y!ٛ2:v]]z}[2.K+K.л.\kAj/{ɐe?C7ĵ{ffic Fk"Wzx TG㐱6I2CxʅZy?c!y kvn fc5ܣZx3R3L%L9}.XW2KĦ{T=_:R˕k:L\9U_kD'{lJ,_me.?]Ѕ9zsq<[ZSF+QF=.Z9螴<&.H^0=h:ු4eտFR.p)`.H6PNMqe:lkXEvd`S1Wsle|"tO$>Z]otY mT:7X鷈)*.E .( kS1 sXk^T}=C*ZښOj<| 2鑮E̤{IbN7Ls=BK ߀qrtI//9)d5p<ϙ~ UR8w=|az;G1Mn*txup||2K{15s Wkv]Il-( 1)Z.?V{q kMT1,? @=y_03*zdsdJXןy lco?[.ZA44{C#72wDV,fSZ2ܠH$&cf.#\wN&2~1g))HgsIy'#Wkn| sC +tm.oӂՅNtz],*)%W".}+piS yH*[-ⶢӉ#x>½r$rZZݰR D~.yO8yӒ7 zz^B[\:t_)WJ]v{4}m>vd](Ť.w ]I05WBH-~6ʘI"BkHnFא1}FO7Xኟ opNOsn>jaaC= jem0?ֶS+J1yoy;jGb|TKW 9> Or{bY8AB/_3ؤ+e=A-c|P"t:d ^D_[blfWBTk72{OdF'pj0 v4nRL=#q+dAD]] բC6'Ut®B2cR)*rzd[;}!8U# .w5Ա„ynp_XPϴf密tu{};o|4MN]{|` )Pi ]k-:y(x▲wkCSmusZ+ur^XbWɤX./qKM#9IZP \L[!׸&uCqĜVRW;P$B(s'9panCC#uy[H2I-0ZcL,%up z(P;A zW 3Qg8:82,c_Q/ @mgCd Io\ |^ӱ򱡞Eݐ‚hSPD?bεN.r&.o s ,n*6 }-O7&eĆzB  Wt1)EQT^{3kZ29¥an\sCù( ͽJbY@OK[o,'~btGzPgx3NI@Mw+Zޠ Bq|ˍ+pnH +}/WՇOz_*'ΎQi|+P 惐…w&kggVA̗r~=mwR.b`}B ֮h?Y6}s~oXE5.Ou~6)<6#]pzIe?y2ӊ-kSsm%jKpn_ދ|`}LJ2.cYM"x/])RV0(A&& Oul4s$}P6Vf>#%v'k =PmsUқ.H!|ܱ.ڶɒ)$plTR ͜_UI*F17X[yy ?Hۏk_|R|/H>}+gEo#?F ~ dyѯkKy~>5:PEIQ!&*y1#Lf'lkÃz ODGgCz5! ɤq1xrD5 ;^{~Ͽ&Ѻ .p툱&,A,5.kl0^qt.="pn2<ثQ*ʝ8s.c:)"٠z螻 S E AX03닭'ed{rC .od3L5%mw6ڔhC뚶.5Utw&|@RC:^亊qrpr 9{Vٙ&S[zer(ZOOK+:ͦ%ˋ4g${@-|ltOS~ֻ♅>aW}i^! &Z}9g]W< \x\,Nm'3q O5Ku- ӿ͑讑0 jXLuacXz[(2u,ۥyDzlT~J EvθJaRpٵZ>%߉> n%e[Aw40Ql F] -9$~-\sfln=%KHI:Iq~KF'~(~ZthtL Y{\j8[ۻ/n`5/.싁WGZ՛Mƪ#f2l!W=u cRˉ-TiY\m $t⋝~ pR~rD[hߊ_x4V֛-Ջ(xcĬҠ&!_( Yg4+'E5ZJ4 plH y)ԶvhkfNʢ~䘧UըɌlӑiU5mg~ \p~"͉/qLhw9O$Ъ~[LPf_╂ر'p{2WWMDgo mT0pq;z؎s4h \4{`vD"笌t;%6cɉ3!_ wQ<.3*/,0+)9fd[I}>= SEA 9-蠩YY!NpH #qee*/w]IDSR RqGҼ''O 9Բ*Â}DvgHpyfPv33]x힡fBlw?bruՖNEpߜd%ڲ ci-]GK-c/ qSw ۅ:׿#Sӥ_ 7?g@B:w srNud \E ȹznʫ58ֶ@^ިMG7?'B|$ %M( (Lw|TDT R)vlz`=&VTT̷Bgt7Y,W+BKƆIqNQH V1H]|$)vcLؙ\޻wAwruOX~59~(M9Hʹzi~Pʔ\[pil㬣)D2 4y*3W`J"-NzCEǼ8qubߞ3,ɭ";M=ʼ" 1]"aBTXC౯I[%Y5LR1އdKsLy# wM]Su:e@-AZ(Yr9`ØVV8CΞvQ )j? E\x\_w]e{ܯ0~3en 7w64kdxpMeņUm|`lG ?iqk/JXx\qs:'-)E{ȸXE>a?Y3>?3k.h]bذVz' |CYbZyvDa'^Ʌ^W"eںCU4% 3̊ga .ޚ1|+q<ǚY:WJp%qi 7q{Y?Nu !Ԗt[÷92c;APȕ{: RNTwPC6^k9՟Cv1͸wu/ĕb5KP2T>@q]~R;H(K8*5<$:LV;-IP #h-]quLh6MXqq8T7ք,^hlBiLeOevA'p =z~&uS6IisO^MN=xb:xUN7df۴WY4zɑ H#j "xCMoB2E% k]ͭ%q]6OSE|T<{$gamhPФ?[i?-BssX|į&@ A0n1;\*\ypx>('fz ZyF$ ec<.=Y lj3As?HIkmHZ-v&S?,5_✩& Yu>2w0< p=]οg1(af[XĆ&W֓PF9-٪:vqVrnOmʂ鍁+v. 0.J24rcCJ4,\JKMX=&2a-q+&c#Ǿ_+*9@`&0mpkΚOQ nS/XajҬToa'om Fg?͚J{D)O\Oڞ.HP$ tn.Wj.+ǏdK}}$i\~p*_.}#̷^T=we.Y4ǕW3%QabI ֽUCi<#^Xt Zlg5B5pܥ&CEq ^\KwK=719;O^P&x\r_]8YH -uH4u>`\7cΪIjXؽv9C!X'RSvIMTJ#ǐW-|O|WȔC\x\e8$vr_Gab[5Gi5*xgkFA9G {4\H>񬈀 r:o ZԳWt?I9N")rniUƗ$rzA.QʳrfxE-3O/uűL|ZN886`7Wf__KMbC8:3tl|)x}=xü'*5kFpUls?n޻fb$jG4цV!{eyR~4\)9 Ǒ.#hR5Z#e\}uOr)a`ls6R0r,pEI8Fk\[g,5|\H1\qKBI *Lv +W ̒1qJ<.!B]>Qo3"X4N%Q/YOY01|rtyTD{"~u.-(.L}`DpUmӼW7Ο񦖷0z_AA_ziZ]Rj)LcK`2]mh2Kb\(J"#z˖=<]'R)})srrHیq2"y<.B]v篁/J#I C+⸮{7ݚMW|w9_\+H\/W`s{#̇v޶ri)J]MRjZ<.>Q%& Wx;2с6"sc]>"nD :Ur~\|HYЧV49Ta&{SY+L/ZFx\Av㾥[Kfu5\ 5zG+>#lfpPN5ȥtY~[]̟$u ֢J5:dEIG`:^n{Wu7Z#iV5%bc_8WFLT)޸ ba lcDp)-I.+ީC7M'\pjYys[ z<Ѻ@äQSwP鎤K9s^ak|"i9MdEA2$}ߑ2Z{gr3ol]}0^lz9/PCLVBن=p57u9779~+e6qBy=UBޕs[b/lN2*Ht k\,a"u)yo_69i֗=FkYD˞c]|e0zGuT6M=+@+x8.7ۻF`AuW]͹L 2w!]pz>DaØS-wIUFJQW6]Gp=.O+zf_* z&{tԭ@{%=bFz:RS^-a|ܸwմ$C ZX uyx➿E_'2)^0;D${VJ7xkd~O؜Ir%k`j~_sුF;YW+.AtuBloԊynÂ✷3H]ba9]wA4 +x8Däq}ϒgx8R~&mG9Kksp*myG T8.wg߿BMc_~1zD9R +EW;4.qbuO '"t6Q!'M|΍[$rzBH+\o_B {lV 9ѱO=cW~6B]NVu2tDn n==,[~Q~O؜6ht(z&eY]uٞs8 {EVjف6o 5_V#Qr֓$(){̝b CEˇt:)Mw3LE](%쩮j{N|u D?]fq-'>NE[9* [t\KI!嵻1Gx#6kli1~qgVWmA_J[;Ny{=dC0:;|k&D@a7a ^s%h0J-ԉ* k<.B]p_jJTPl1 X*sylN/ދt:\h1;F$ut8ӑy{'ݚvqy]җ"Fcs\~o[ I~}GiiHba79Y!QQ mr(}ݔZ$СoSݦ9grC~O)JU  xoq9!%1<\oBs)Z#]5뒸/%#&?\x\o@ s5#x>{AsEru#]ޠCQ {ğơuu -L5.pqR07$k]4O^Q-5Ȳv5,0 .iͺUiֽEM ( UJYe W!ܗRQ@v,y +db)ޢ kX`)f$(Ecڴfpq= z͎W_УS=$QʘhΙEA9Kyųݺ" ZjT_^xai̋!vPsfͧ5 a` j>ס:ج.rη^Wh@QB5]Sܚ p}US.8O~Z0zߊ`hwpLhciniw2@ry*r S'TEA]{}i/O3Hhӿɲ)1W0X׈҄Gj &OꂟW<Ť6|ԇ S_E=jÿw]Lp}'T>ќ_&&E~;O>vo@ŒV\> *^[_nU<8l`]{G|mpm߫da "rB?\ܬ)*'k٢VV/HlaXM_eKC +y0hCc_s ~}}6yE p hE _{'uve?wP]'wyGA\FH.ߛ\aWr4|v4DI *5k_Jf sv~F(Q^yiěQ[7-{Cc$W/jˇo4ssqB(3(xzA%^c3GqPec qǒ(oփ1vftǃ  {u%P<ȃ}w6sxڰ43O%xú9,=ei qu!k3ob9\)S#aխ<+]h,{0űS.8.FtATV݅2}EAn{#2+J{+"*#-l~/V&s kcJA7{t 7#5>RhƂk /B-y;-iZwg]vK/,^{5Cj߂nX!B@>woDɨ2qOlʚ*GSph {c4JM دjh$/[ _li$&$e]+ {4W !6%qފ,Jz0s6.c@W :;&}Νyx<)䊂Uee-L˕e-wl5lMe2%:f7(%#=ˆ&G6J|V[Ry'r6h1s 䊆~eA6m/V珷ro<.sm-u޹kRm~Գq0n 1]'C~[Pf@rzuZ(quaZZs_۩ NoӖZV3hPJֱuZe >Uv>YA\^HX_Skʽ%(?9*wePxe,8dR70%^&kDk{q[mp< 5t,"=\5Q iڻՊ쒗f2k\}X@q6m7%J. >zRwEpy 1h qm!a){^?Wޒ&~%gac&^5R\K{^Pr4 CKX?b?LyHS~W1 Dr k5?45|m_mc_a'\[)M,Q]cr?uü+hʛ%T+ʼnR[(H#`3W:22,ZMJ~(ƖBvw=Zub\9s4YhgmcO]eV;WbFN}!\zHdc+DsBy؈*kaY"zՙ=\{]츔˫EA?8v+Jg~j$w&)@l^bxE;mGl{]^V,h)!0rIy2\ Qכ($Wo x9789s.`5AsSloqq5+ Ε̖B2B>VeKEǎ'O7XՍN}J +ұ"8vbe*8#\5'J <M:m7bo+%ct]pE 3LOF[Oe'\1Gr=>-x[S7"= cnc'P$[ުpm(Φvpu6Q&C:uO+-}oZLK]Tcn zq$W xxg_'p-ehs⢛x3/o\Z~6(z~y~gNeh6Xvb58["1o䍉QUsVT:Vm젎~߸̠Ǝ?+Rc[M-\v=!=٘"1zJbjdN^`r4.5kwB? O?\;|^Ri5͚ 2,i&J m=̰H + WPn 糣ו%$UquxH1j;u#ӵ-Zi=uH䆨+`(HSy9`Kq%!<3M#GS]M/i |勢pe2Bm_߿>sr_̦xb}OT4gT!MH+%ɕ򃨈CR`69oaHc*o荃y]pÿ:M)f q. OH,sX;bs6!gjʁ`[\ C+E2QGĈy!{A`Nn<\y(%J.SַB埚b/zJ׷֕[da벱W+7O8ߎkYji(sJ9ڃkuA~ta`RC=Gs*ueߏXO i?nv!r&gqgUj\N)żr*?r\lqJ.؇|4U)T-ڸ!͐&k,9̢X;qH\yNYN)]vbOt[N]X 9-eA~`eJ;)&b5Z!%$W,B*uR3L{n ыyޚ婂 6O&Ts[a-w2kh5T0𤨗hK¾ ͚vKqɕ g&mya(-TxxVRi#"忍["#v#gd=bΠX!<Ʒ70Gż'BHC*mgvW LQQKɕQ-6Vqgx<;4U=]ey~`򃸶mt0ڏKo\r<~B_C{3u(P,jrUi\=(H{U.+,Od T3o'ߔ#zpQ2!%@n-ŬI{K JrjqbpsXM _Q$W!,cW$\;{_vZ s-':(ܛ)Kټ60$p׭_M /:uҌ!VqѮ| w<X*NBJlE%k*>1 YǚR(RldR_̷<<~~{=gg}k&o6 Db_7`Lu dѐ+Q6X\LDsHgcQ߷@9T~R@yd<_|,k^-uڧzr]pҟ#KY0n>Cl◳AI U^s?h) FeN&ǁUfRPᔒFZ/sVZou\7?&h~0a"u+nK{Q9R.\GTB0O\*rŤ%sE*B _Y]kc=Egm;Z},Ͷ[ NI5{*!W:L[I)>x=ex]Vmo;s_bZ߭F kD< >>a?gVz+(k篃}[aBUnpɨop^z'@0u2q-4>oGwr%ӇK誒hvo(%uz~(g)JCAF1S~;,7k?^_5u*p.B/\yk {IzWƆ ;0nv NJ/;HB.k{5]tx9h֔G8J_LXp.οo\3IGvk[*UMemSl+5 O(7}5tjfO}aML| ?Ȭ'(Żk/b#V>LImrgTA*#;~BGAL_(kqZ#IϒeN8u%OƭՃoߴeߟw׫<1GG,(C?@0/q;">pMy-3JJt;,m{q2DzXމnt/3T1/sqx(m:em,"h&qqLVۺĜfr{FB =|$}U\BLHU=T1oHߟ}0uG<Λh51-h6핃{+^)1q Pn$mBvܬ%bΌV嶍sۙfs>JBSq>+ D2ofRz˼o) ):.@LuPː/{%-{6FM#u TcFv}~m{~Ȥh5?ioB> Yjߟs|x|)vɣ)]e"X۾=9R~Ōt<9lb6Cg! YKe^˘H=C)MFg,o 8LwM0pnZ>S b7B LW^oF'N|fYG.W}M /~.Տ:< Pӫ79Z51vJʌ\eַǙ:Rw ʭM0 |հ/眂FXhs꽼C)E,v()8ZqGc7% UX!:mqJaT(.;aq8o͟%ULL7ѼU ,2l}ܯa18|oc<]ih)Gj[/oX">CeRY-c!hCvrWңaὺH@ ( 4¾'Voœ4Gj Rr&H/Twyjг"O<G'-˧)k7]ݡJyv>eĔrS{ac_-zy{ﱠuGt2#eϥ?1w)KtzO;4 rSgivqPs?[ 簯ZBAxg9 o_Y*X˯e` P_:s4g/>lLJ3iϫ髇}2eMRX^!sa孥q]7ROr%ˏ9͗{ʠXT䚻od0)\_7O]Kq@s!o5!lKMRd{Ojg`w4u*UR&ݴPʤLc-?>a̐F0>Lmj63lGeE_ .0xi~a n3I`tws%cp)ݠOr杄ʷZ=i{߇%$bݐp2HݍOVЯ2HIMrZ /ɬdHNjCelťye˩t|V\ڑLn?(3kAG#*^2MTweczo>г"%zb;>v2Q:"g=6?NZOĴrchk}WL~y3JLt檴:$=Wso _<{EʎO9wB1"R6KQ@Z3Nx^ >?qN/1 :$i7?-(FW]6}F55`&[Z u]oOPt9t rϢTg?LqmV*QkhĔb$ȗ=}#'+Fɟ-^إ'Tu5)#t56ɳ 7)4Sv}Xӻz,Z}$ˎ!|mU!ٽGng7mjڃ7E3o Xv%gYbM<"8ES܇s:Ǧ@V(eȗþw|nOjNmiFIM$^d\I@"A>ɉ˜;<]^#uF^;a kr$: ;.%!}\N?DsS,.t}%1SqdFe$ D7D-eq/-C4u[Iʜ.֘~8<|QWNds=W;,%rWz޹o.xZ&EYw>\, $8_;Ĭr{B6#|Oזy'f~]~7?u2DzЧYsߜk&31+Is2>ͯB_Pn_*~B^>ߒs,:qPWFx-A>93o.n~eΏSQVo7m"1 ܑϫ}|!R.?xv*j!áxKy2S^:\kowmS7?>6q\Jݯa}iot>kdzb:'j\HpeD&}6=+ BҀH+'>bz=z &>$i8マYWفOu!>X='%]>u7zd1^qbz;h-J~̨`']:| ;Nvq )3d:-(JTnUcNp-=R&D:2~6B#Cc&Ot؆YGr@>> Q`h3 o88Ҥ37͗,["k,~_-5$^"VR6=nMtm]0xv[ K {GQG.1Iصa߰NN6Xqoq=PVXٶL֢E Un$"q+QI_(!H_/QŐ,LoHKWAlXDbS}1Dxz]:}d՟j 9=] b%o3\%9C s##u.]W$:\HJ*GTD+ 刐ff;jO31z3_8_'4WyKէ(QKx֋Mj~o|ʼnWpS#W'U<ݜ|w"O:ƧE% 'YFO 1y;&_|]~ S>r~.˧=uNS6Q6BaO Kh;Ey9_ŬmU b 1FBq;u 3o`gp(#gF^%Hqՠ@_ys=?\'\8[lCiYl҇0.򲲣<>zkBm :az6Ҿѹ!nY2g~s|.o_̓˕Z\dfESm;l~Q^9!J,N(S,Z|q(#/+.+3O)!Ilee<%ݍ@>=XT8jTX\po`E (O7_NzbyEIYϷְcʝPyi5Iˤ~C\<\ܜ\|19O >RyŧdIeZjʔV϶o Jvn,݆c#CUP;L&r,fu f~UoF|oF:.:) "huT|Sc[cǙy| Tr4;cW4z&/4~+dWT9笯A'eEK' HEZ?ZGgD-XCoSlv گ{BS)G [ 1N@{w{~Kh(HQ |ʟ˝x22n ;HHSZ%mgD@!h3p % #O/xY{Jn/@yzndKӫ/9bGv ^2Zp<:4!;5J GگiPTs7yC/|7H:O( , UZKd8XjE|UǒC\6m~IpaSz xRGQ!^2NaW2™&54 p9N¸\V:SfF߸B{^m,‘^dmNL A9@z.>WʆxyY0H5ؐP|,lDu~|)Ddo$`\@.C]1AqCwIHV; EQ(܂+E}x\'뚟] 9m)lޱ(2x5nùFAa*ArWKc*ĢXe3حSq&uZr I x¸.Y&\0N_^n3Ȟ6Ơ8渠ިuz\Yp7P*߾>j- !Q.7WNZӨ5²GcT8H-!d*ˍq5 +ud3G+?7i <͸-֤C1b3ˎ & JZn@Veޘ}"꣹VcLE@yEc7REù&@jb~):Å28'4fm!..D֧E:Yr\:f{*k›TEzL! \r/l`>k4|~cD3J|!.4q,44!R^8L; $hge#E3Jgl=('WߗJif|}qb{Ϋw7Yy4_MRu 5.n97ls'*z7wƽq% W+ȍgx_JStESu7֫g ~ƒjQŻ'ȵnknVv f!q)F;}?E@\h7_`ߗNj7]d-EY%q XpB8^rmIMP,YE9)'9s n!>72|rKo~G@  D9״:Q5჏LrP^ܩeV\w\( ߆59qSojo?fڂV֢ۛr'i@~JFA\sAּcI˛3Wk~;\4ʳ};]gNdd.raøV\oggdno0Io`?};$ą~W.,n~0PtƄ+q9BsmRh"%DEs>P*>8Xтى-6#q3*/n7Md(׵< ' >&O@=,! -OC45I7"ﴲÆ̉SOJұY {I{↜GtcZ!..N.ȦHE+"/Jm;qŸQeF vCyJg|#p>jnE =[\G%:"߮ك&s<ȵX?yG:(* |c<'mdv? ʫr S6%E +7>%QǶcjE/\%=ߠo6z  .Or?ʠGq큒LB~apHXbS1х9R2'_\Cp p$~0)!sʃgvv4s(EȠ{+0rXJHo( w#=P^?H#ZÙ_#|DT\qsNtV_!.o2\,RqXлPn)F:ղoJ:C=!;8 ȼȵy?#jmg/-6TF1).1ƿ٠fMIo/q^C.?N/c~}…b[OQ@&U$G(vmgU$EE2)e uYJJ%EP@$$,BQA %D sY|w?~r]w>Νyfgf7$`mwI0\g9y9.$)5hZ 2: =-RP:p@G~EYVW4Ӛ48U4Jz2@lM\ͫY)ײw{|ިtbiz!c YY'{>yNOLfT2:NOE q,/aP`6t<}B  "հvce?o\H3$bR bԃKn(Y8qUm1=磃ijJzg#E{odlF/YQ#xϖPX(]g\!\2rryp윲Bߐ "Q" d3;ɶͤ'& #浉-k)u$|t%XhZuRcY¢!Q33> = ùu+ zzJ݊G*8g~s('a6cjxRt;vX|gi|{ {ѻ.+OȞA%>Ejdno q)Yh .NŨ6iB#d; UX2 Dze}e=d>B0 Bm q]ZeBGro A) /꣧SՈU:M،KH/hSGϭ˫y4@{*gO= dń{ n=kO 9oQq- ɏw͕EyLwG7~?6dϪ YEp;f跶psqA\BE8BG"̿N9s8[cȫ[U0W.$4X}JrWUyvh=n@Ssҏn/aB<4(sl $J)] K&\o#·^y~ _wvGa n7m0=u5=}pr*ZhO|O6A|cO D' ґcl( FѲ7׺X/e,b퉛qW2T)t W#վU=gt%o p qM}mM]^5 krq(%vuPW<<~KYAX "fχE\Yx.|{L8uk3~{P(nU/i4U! ݳhӂ$r \>l*wJl\: ]F;# $e*W!DEubœ]>BB@95vK[Gy!J+[壔`"H9\G ϐv5п=ٛo<m)MAOyirqmNɼE&6 C Ҽ;dBp'خG)}̕F'hJW1(QaщWnASeјG T3nJ­\܀@z|X;^6N}sS?fZy\G]O}מ7 )"%dOCAt]n |'BiM2(V;q4nF~c_C|X<8"9a?LG|ڽ\0; $a[@Sw5'ƻO!.fwτsT֚=4zG/k9:Cp5rzh%d0e:m^.?Icd=U 4,vdN-z.p|T ;Wm@y\g G ArՋKhgt_#ewda,|k4i$ZyC'}S#Y֤7>[%N=gj/)./}-+c";^T ٧ynԴ>gƐ'/4Q*O>_V]qC\11äG] {Tt8 ?8n9Gx,\:be[f!ќ-vǗ[¶"M935%qj%0vroxQ{]0Wy5,s9ߖ;9shQ,܆F*MSG6Հvc slddyF kd|IZ0߹X[߻+/K_..gP[s=/-*M6yYձ^T@/("˕C/]8rVmF8w (o_#$IכZpF7z%WO['[5hS}C2)Ƣ %W}p{e۹<( ǧuo7k}sbAjh`SdglS|p)MmW+'Ԓ(Ԃ^L^t9rBN#rez'tZ:+~*|mÍMo*}aL@[DuD!bTLDx"[ !/P>P#!G,~(7ky["8Y ˝ȯ+[st Ov t hslbSL'T ŦV+\Bq@pi/IPEb{3yv .IygG8k'ū69ep:(% q1|BRjgW=ev|TɠLҍ;`\qB)he#+o"';Eu2;%{8IqA\dQQ~~B~r>Ē)T+DsA&Cp-Lke%.&vSb#^3ilNĦ~K+ɾΎ}bpOuk,+ݜ+}2˾!V\/oj[k ,&4 Sa'4Bm>hy3QC gkl/:NRepJ8%qcR}\&yD׉!<~=v :sPXx(;@=ؼ7iUhy75JCaqS} O *Г0=[]J;7LGhK5.#uD?]]Q ⑨)FN?GAI'S,Dw+C`eh<9!r\MS%{վ7ޘ끖H6n]\_ZvځK? )3BV_->L,>1)6댒"@|j 7]J#vk9ǺUkRqq2Byګxo8iu ٥3GJK[g#UW8VwxmJT 1yCqQ9)~WNȿ^CzM?GeW6d־K}KDσ/FWʁ_7&&FK љQg0Y9O=zsij0cn҉0WpV_nf[7 \*2KLl4yR_z2W/`j|u/K^E%n7O=~UR1v!`jx%:ƼLroh3b` _ 4K^paA YG aWJXOJxQ{Jg&N olԞ*ll_ij+'a5ޮ#&r ܨi z:1Z _> 진;"Cœ\~KzOD#`k=%NL=t^p`}G!pOjp XBOg='LtV<^5+ %O4 \{#6yDO$I޷pSAdiA+d-]0-`& ]\cC?#4 v_Zїdȫ4/?gtzAad:? 6Aѓ:Yx/=^.LMh=&׾!6.^ܜ1Nsb872P7ӋBdPa}~9`S;ϧ3Pu|IGo7Jφl5 + g_ \!ˇ~p?q ]*nY~Wpr4]^fq#:>ʲ~O.li@C)ϩlXBEV1BM \f9va['6{PWӌ9 }`dĜ&phJ [S\AWo|.Up4,k} J4=xzG%p߿k b૥Ȝ%ѹ;|z$xGbsB.;il+|S hSo4; sN Mĸtw-e>[[2S63KUB1oBXF#d LA9pQ(qv:ۉʷ޷|7[+UXS>&ԁ\O\Rح6[Z%)yuV|cu?9%[?ϥ1vLܝTIطO?ۙ=iwϵ\%ĸ6nc< 1@Ѫ'*Z1͊e˂]+C/kJӔئ|Ԋx|༆geǒ"bgTn ;*oT+%7?nWmA'9GMˬ -Zٙ>^=v,`S-4ߡ?0FRg[}wx,z~: p˯(dW7@~LDCƷ7E)̪O[i5R6+J\G1$9 z@6ԴDG:\gĪeˈOp؜-02[2E¯F (7l5،)0\Ų4W =ȒWlW;ǧ mы2́i l[yQ7f(l9V {zȦ8\sypي1%mhT$m0Swz{_2`{l3zϧ`I6`7u,:YUi_ߤ&!:|n#Vı{%_<'*:s}&:ЦdkܥO`JL1;=T}y֌#}Bf2Iaw:6Nߣ#5:|cSfwBbhSCy 3/ix|"|zfVj.*9Ii!'Ql|B {^<78rp3')ȑYnq ԦG&D|9T1||5'~ y:Jq<57d>j[kQL/lp`KO8ICuQVu,v@~Uv~L/$ ;^~E$wH{֛7udkw"oH%ݍ9\m7,հZ`SⰚ'4gw6N)SΕeNPc" r&oO7O*a [uMsFKFӿ{g`]ҎC,ֈ`ӪU2s8暝v:ю煬f9T] Tpn:rϯÅ'+WH=`c/2R3wʞM_:i$6T+>)b" ;*y)t4ɌM D\o6:.EBV"w=v7KK9cd+y HqgD4}7l (+cnj~p;LǨ9SSZnؖj}?q{7ڵ\v<ڈ[^x7XF'V:G+ue!.PkbͫTB7ٛm2Yi7^B :HȏqZ;^Gx_L ߺG?`{.pp @q1ww$虧~h E6+,RʜKV+(9_ i$h?8"`pg *Dg-e1t?$02@=MQg#:݀ft0jZEz;2C].?X)spv_nXd-|lR0A<>]fګ#\Ca{lYJ"n"\P"B[?#"ko :Հ9 :+J 5RB!x1D 󣣖pkLe |6,(5GZ8WÕbx"5*:4DI&|۾;sx{2B+kmJǟ׃!Ve[#L&K/2P!*UMeN2[ς~o#y A F SȮ=n;>3B, z--,EkX_{)kȚ7$D"%=BE$[!{~ygϽg={7~|MCRBt1Lu{}Ag |ո4 3 ]wʴ?)sW;erD#؟9J& c5 o z'yöfCcnG7{Ʌ0Em˒ Ķ~+tV$ɻ\: .s3 3tP1/c3hYp{/+}FV&+Ɨ֏lmiiwa6cB*e??O-?Y$#WSb d֏Gx}Xuj^.pDu:7C—+j+w.Fp|bxX¯E?i-2a@lW$ɤQB-fEm:8bLYڬ)h&!Ǘ_/CYcd֯' dp?Ājr[2.Pu;g {㚡vTDl;/.Gƭ*k0UšD4r=# ym:b'ppsZ_'ۧ8"-&rE@Le *i[=spQtԴ眏3>K\Iv‰r9Y"j:mG 5'.![ʷ j?>,Rn@W]"ݍ?1ƞG=D n Be+^z}ޮ>Au6r)\ߕ&Bt]-Äj+sM`@= N m|YlIvݼ^;'R'z .-/]eXl0M)x9S|Oඃʺbn6,|Ӗ^ bN9exT&'\r.nsAɠZ #%"!=ptήf|;?2O݈E@v >C҅:?^{z 'TіN+ %&>_*Fx#޻v+>Z81sLSTbQ̲Pf?Xi\>{kzw)5Z5 ss YĎOֶreA%$w8)pGm;a|No?sk)u\Iq鑧AeÁحOg 82́'Pȁ<aA})-! 3s癀): -.~Oށ+yn5[}Ce#hq&:e㖋f[>Jk\~ )Ès4/S4{>b۬$|QW)j_}<ǂ>2O/ʼn]o_Ϟ_xNxA&>* b!#>VqKN4J% rѠx)Z!2oiz sßV^8jU[PDokjE \ 1$n=tծ'oB3>} +˪<Һ3k&שɫ>!Yk8!c;S˟2m%D1딅:T}8; +|I}Siف'SϴOlVP|I/Ɩ W}bo뻓.c./:ou5?H?{m%50iߎ8q?:rd0&*<߈xihW 2Z',hʾ V hHav"oT5(#Qr)헿x Ľ3^X!v9s_"t4a~T G\[I:8_Ġ+?>O)Z W"Dfͣ.^gLQb|b_\5EE'|1l諍L<nf`hI_qza~I|UAJ/sݶ}}>D)5## ˓ GF99-v/lFH?&g'cEr!v rёp!m C(Zً祝'=rs9J>˃1.Jbl4{>*cal7up -KE3Uъ\gXCTƽ|;c˰Rͫo ߕ?m7~%q!Maj}ΚG*`C8;@"F/"f$$Àj"AK˛Y.mk|'xX\`{hN2^/ul8{ ~vp =BÃ{cUG8Y*j|(|g rpi d2E+o'؊U!Zl-b  vN^%n=ۋ Rv%˱4RX_Ѕ\$\!5; "˺wdji*{Mڋ}/@LGG5/L9[jR}*?pնQPߑ~.b;]K3A.6XPn;:Y] ,3trP1rm'&Y=tz]lvusVK{2zF.PY">R"vB-D)RMQ|1.IX& R&npw_["*:w8ִ-;,ɂpctfbW/;x>䫷C.ua(4uytrqp]q.ox; ǖ^ P-.;^B'VpmO ]wi3.[R88򝻠1 rqWq6Wpxx)x}lKZ`|U/pw&a=Y ]Aށtݻ-8Ӥ僌0ejV}^)Br b(?NlfO TM Ǎ~#/hb\JĮ`ekw;xU3e] :IpSY%m&X&~ Z.HŌE! -XӼ̵ Ce gW2+RT6c#5U43FS>_QT;OT)U{ܥ܂uY*ΰZ6)$\(`+O5.%6[mKAµsGn+ήT=ĵY;utO702H陡mT^lj弧s]9˚4%!?Q f"v\|V泅{tQBkCёbi0y8Tpc)RDHٲ$emdebf xJ컬)-BHZ [JLgμyz庾_g9ﹿa\mpmu~}(,&2NQH93w ͨ%s_< Ni@]^SQ$]\Hǯ >Ooݪ-Q]p$bl/9t{as+(SkgC V:|}Ghpm@]\^ٗ#6q`*ϐÙWFo#r. O?⸓xxJ" cΩߛdPi,B՗`\I/bzZYw{>ؘG}9bNMc3Ֆi`$ @ju\37MrtZ9欟BU.a\28^[_CF\!ۑ+1bq>WaDŃ𪋫t`, gF0ʳ| .mǨ&0cיWޜ9|ڸajqH`dr*:zƖy̟}1soPX]m6\clYjUwɥFT" k)>geM4o |/+/~OGb+|1Z'tq |~O,g+{ck7% =WpNĢShb.0r R$@]~WGqi]' a4(|V'@+{-'tޢ'Z])eS^ݑ]wZV\8Wo?C7|Ԉ`\Iڙ;8ؠd E)}\ ٴ#-Q/dXcq"BkG,}}]͖3b"޲HnpR8+M@ YV^Zݯsc&\ϗ&%ȩ{{YEj/Kc:k>绲k5A+y<w[\Brb/ﵧMU^ O=6c> u1sHiWo-r<#unRG:ƥWZGثwv@;8{k&G=j1@TW= Jק-sK7Z ۶VW=aXaUǺ!1wƇq7rLlYdd>i.%_6ҪTl͂Y$ؗU$#qb瀵O O$4c.>ԩ*?qy͐A'Xq@δl %rQW$hD Y.GS" yoQBݨ^]'׶q?<ûP:9*GP:Y z9g~&B]g7&ֵ-M2wt^R2T]`\)$>cGhVڞf?N rфX5S+ Z%rr.T2j_]21+vDSÓ Yu$,@i~7EGK~[%r毈 XlAA{YwJ柵pG0;pQC]zՔls2AOUv5Aؽ o.vUј> cȫO5X٠֦CÈ Rw1I,D}7.9f7R]7Q Gz@(6VGG-Lf_<.8#.:_|~[(BM˕iTFȁ:4Jݱt4[kꥰܕf'Cƈbpg$~Al΍_DVE~jo1_]wzMh'G8{w)1-/JC_?^6(T~>JB]eCH6ݧ/sFKiHʄ%Vwntf('AcM4q(2"q S+5U-f6 2 @^)įsG5 $ M`KGi֤&wC  [Y)~' c&w"K7a`4EX{#2Nyc@ά u%'L"nXQjBK orD\yo@.@kh6 ƅwX4T@6B@ԕFNI*eAms 7 Vb|-#Hg Ee F_;I%Lv Wmr|/v%ǒE9:W~ԕ _(d5Rό'QsveF7iYܗ0uAHp[isu*'V<\N*2baYnE銭  nt>dcRSjEվb:<@6ίRߧ {W/_dsݹ9AH\JS]&7@>Jl܄o{;XPSt5*ގn|`Xt՛ooR|>rE?C5kBt8?OP=S\{Eve3`\$}ZכǴig-ܨPGEaƢrr,.k7^F+\PJ Aq%53/a  I^%w1A]W+I)S!L>F"e_*[^ʾ/I!0˜-DY"E ,d+-ȫ"|VwN߬yzs;_zU6Į1 R@XRul;ֳy)[1?'{Sjډ|ns ^`V8~"Q9h]r!;m͗q785^M~\w}C:H Tq[L( ?xXfcYs7" 2fc7 H97+xAG#/z{8/ |˾u)3 So\Wy+ದNN`0x~gɚUU/yqsanZ̭z[R n/Sߣ$NvO}e {'.VspkRJK^}qftk pQ'>DKOyl$Kة)r`Xu); Z"G; >mŖXwa%کLyl¨4ū`ѓ23Cq -cbX|FnnyRf?R C!ihoֵƸ9.jRO3(?_`)S Y8 p_DWJW\*kl6GEhW`5QԧbUO~v4֒Kyyt[ ix#-]GŒ"쭬}=&HW;I'e0ނTya ' j_-2xC4TV)ꏥ"Fc/ !ſOH.ټi+! qQvо1ZSrɁO1fps0_$0k&`Pvc5.ΫqǍF9KW ;F빞2é1qZ~DPɷ=<9]VF -U(Ϟrf5#)*Mg7;& w"|?K[MV~;㰕w˝)о ^+]W!/y3"?$L}z 0/8,Yk%u(O%g L۴sTDV/'b:OY>?*:kP``DAyBQOp?˃W;JQ볌~>~~HB63)k7e!j.[R ;L"5?>()ڒTխoCf4Ы Gc@`PAk!?R:߉MO֡v 6g! 4c|a:7iW+gyx9`{*:SwQ^ t[]m3Ǭ~d.4WCy;C~K~O ~RɌkWg- O K qi>4W qH{q8X2;U01 3Ud f,^yu&'xݜ_gOXك=X6 yelfOח>Yoy S_YlBt$ayFA^Iä^ )B1  ߲ttK=ϡ ۲ d|T*}܅\:ը|,A$+w/9c//Ж~D+.qkGC"EhG'̬0z m$ Nߚ|T#B4G70?֓5]x9£Z#se-8ByyK(=t8|] AgPn6/VwI,<]8}ΰ G %F|=݆cwTxOQo0wIk:  V(rMe8:89ݗ#>\ۦQd-XQO̻/(nFW]p1B (Q"+Ki~/="))NCj&zs(<e҄.xiXrNȍ .v0'#cNV\|Dc=]Tzb„E/N뿋*<'C/1ybƸ..|(A{c/htShQkG+,_9SK§u>M,bnzor>-j9'sVJ'_lc[e0:8X)d(?Сjr/ΔŽJ+r y>[EIN*=Ot+dT3%0b1Qp_ :Mxq]|a5*,}Jf\ɎK{l|0%N; :8X T808ϫք<3{sb߲yIHd{ޱ*Jƒa凇&7U|cF=5GeA3.uǺA"%ߏO#=]#O:8xX)Q/rj6̏68b|:Db2Kx%+#OYۯIc֨pbcJGdxH];Qc~]g =&XJE//Yks9Z\LVӚ:D:x6SiG.<2m E fx0sļulkD(c=]p@]I7/$Gưa[ss}D^5St!׸D*$Eݣ(s)@5ɒaqP|@KVnSH߀C6>My8H|:'H4lm.?U6˘Y>Ǔ"K[c~gpNJGKwO<u /GN4+ok{#ڣh=ZuDesEo =@ .wp!tA Uwf ٤? pBƁA(?vYu> Tqʅ/HrhSJi8A?+9*fyDN.6Jy}5,qIU<x@[38R..Qxབྷoe|\U;8r;; Οm CHzr==P^^(U,M4Qǟdm Ņ"[U?kNɳdB_CAx 0sE]u~U#(s[U%̫o8n&:>EVr`n.3 ^>_lO`*39&ES>s;)L]kpn=`Qlo%a8F]kJzgAs& .+>גmPMB~uQOVgG|IY=30@P'_n Xt/w V2p1^˼A4;)!GJ\ϾCA|FisQ*&XlHlrA8f,|mpbi9Mə}m`F wnʅpuΰCչ~(ek %$/ '(Lߖ\k1~[ Z9NO^xA9!'JB0is(uFyȶI ˌ^ZyN1d;QǿŴK W Q _2-@J2Qoq2݌Ձ:qF3 wu9h0F0X=g|cl^->UNoPOz3!{[}լEב},RPӅLOd8)H&fai£av ;o( 6>C5BO2>y+8<.(8flb͗wjcf_{g{&  z'e@סJިUrP۩ [=ъ  4>|ge yF6|Q T;=^ 'n(bD *O[|G?-(!UMHd/.i2?Wq%Ff,$s[Mbr 3uݿ0?d[YoL[7C`(|qbmfwݬ|_r~P?g:+}* h%㫋|?/8HR,\]nû_-ǫqzzQ&f\+Wc)g{啗Ѧ}K" Н'OY:nbq k)Z~ò--yYYe%r4u9{XiFi&/aXj Y/S+yi ^`MyND 2Dxb[0߱>aYzg/IUb"8,%̻=$JtLO)&Rn$e]e<5ǶAuAOrS] p)T;?3YmP'Gg\f&_ߤmTW/C]L¼Q`=usGuK䷼n@kGl5"`6Z[=jt7%v!S3^2]gXԃ]ှA:DWn0^-/~sNsq)?\ -&ue 9d4ا:#T5=z~V޷Bd؍l v;" ' }u6t.GGNuEצ7Lt'OzUI:l"|- dX˻ZN \BEL :MZ:sF24vQ>5e4XqVx%3nGk\lJqRQ OY5>$r}d}U& nuq)FWӵ?:l+1LG߫UgEmGu񟹵cM?OZnG.ħu%$ _uO(OltZ.B\:iJ-[c9:Gy xȏ~8Z:(XGr;6ը7~>ex[;N'eFXMn=y>%SYo֙1|pۯSz?u?Z|j7Sm|XcUSj;>aUvxmwW2(x) k>.|>qS&ܓ\gYgjQ6[nY#Cl|G&mctt~&_ozE24vlHV~۾-/.ώ^ΈA-P%>rf#cK_OaJJg&I&T=`=q:$ӯ"iKgG\Nm5W1х N= :m^@9kH:-AmU9knAvs1]kT, :'D^K]Nr~.zś+CyEmsDA A$Dd%ȑ$(  $ HIa%lS goսV}ŖEetr˟ytPi 6[7-Ck{:Lv9b[e>nVy1{'(C1s&Qh!8?8L* VjԚ}8{<\(]-@; B$qNn`@:J$nҮÌҩ{1 Ew촡@/᷂G"ٮfP'? 3Bur;bwb R(N ܐy4YlGWF3c::xHd]r/ O*H06( ܙo\$gg)OS'TY5l'>2*DqpDܻyq-M}>_]:&06Wwd\O0|TH _X9>lj=5 _z9Q R͠qŸ7OaxXt[R(n(9 WG]<֍d9!9{q.>Tg;-4*QY՜d(y>7C.^9VdJޫOuXڥ=>LuNP]Ӧ ?zf^3Q e_ ^Xy2 c^'<*H 5EZݙb0~I"WoC wn<|@Ǧ$Oб^ ?}pǭY|ѦPg<% SV<ߞcWh yAϷ%0Өaru0D9_w价TQyuŲdQLEך&daI=N^G@ypׄ9k^!98uUcd/1NjcPIU0=9\@|Gg^FwH'b ]^tOT QӹW_ھ:vS_81Z\nL3nd3bA~_(|,['m\ύ#v}V{Dky{{qTp9>;`ΊHί}1YQL`Jlꎻ=< 8pZQD~p/|,OaN/ڈS”DVH0 yIe8#;A?p SA̺ z/u'TG_`%5kyrx Rx:aBoG;K#4ՙ&42RWCE:pOz661^Gڨch72]p<SQq*#8Nڢ=#  eM'K5avܓ[}9\Ab?tU Gӟ%Qg;^~|۸%] Ftn WӐNmnCx« ds hr^P;e2S(V :lq/>YuS^gw\>'yH6Ӊ @Z4EUKu*]Gj\o:N->{tZ 871ozcT֛B2 [w:/ڹ0.$t_V=Ǩߜ9v|wy>wzuO~q Z{ $R H9ը>NH:M~m3ٌikۗ@P\"q|L~aARՊVNZ/#BỶ|S4xtQ0N'sT\.?1ujaOsoǧ3(URу} 5|a6c y=|(|XRj_pp"Çg6}%tR% ԸPzb8?sWھİv!HO#~yY0~Q$vIF# $6z;֒J7od};P9Qc#%cT /U$r.p|fHi?|(|xS3O)٪&.o'x#֒434KWqchu >v?$Z[{g(Yz.>`Mm>qy&B{,,Ezwȃ~YJy8P8/=qEe%KYN}<1VC$ĿT61:1mwA"55Wۖ *Mϳ O25 ߕ-/~HcL~:˼g~͸4~rW [[g C sy 9gqqjz&Z *o yq0џᡣ- yf' "E6mz<,̇st ynr"nvӦNX;PAaq畯cLqmlJt:}$IΎ9nFXuҴ(|.!W;dr#ECw++W`z,7XG19P҇iGI?#* cD$JZ'}կ68ڰG_ Q5pҊ^0E L|$}*X*-U"DKԕ<ǂ8 8NB/r+ FȊ&N&6pʡ3 މoxwٵo؉N2hoxbiki<خ^_/(N?&Λ3[fծ/Zs%XA-jfUh.{:@B"9XlunX{$lҗ`+ԐS@EE''BFhA^|V?%R 39֋{ǵNq8sgEp.}CG?`dY.]w:X__jc `G{C~cf:M x)p+Lg~-wWq: CPtƍ>.8Id;=0?t[xr6PKm(7@cGpn1*e$+`hU+߭=cŞ3:YH`m@OJɷbRzH0 5 RN_m`?-7l4Wī=Jس 3hP-M7J]l1P҇3Er8m#/hRPVa/^59!W夅} GD'' ';.IՆch>8oׄvb`RW=Kg5RA18CPœn*HNprH?1Z !AH^R..N.N-z;#w1V*9eǒ*uuB(kH>Bee|?-׮KQ.\`F/ف6OX\ x x5)6n#^K\-W CPL?9 uD`ߙ 1l'wEzo0xgk pr`?l8_87h|@ٹ>@zbcN!h:14C'#YGߡmyw5_)«{9tNY`>->svCh)KpW+"]z]{AyH3I4iaҚ'`қNۺ;7sXܾ'/ )w"3@pnRۣ=7o_cpϩ-ְ2ݥ6P*%/1~fʐ) ~TeLC?|ED( " EoGg]ܳdC|5H>rO> [SEx4>>XGcq#  % (a$_i0lwwgҤeoGgÏW_w4`’vd͵nNoЙa,Sǵ gWr!NT$'uS:I{uf >5urn 8 w<0mE᫃;D|At>qWtsC,*D1FA+8bؐԑ_x)U)2t?aGm; +ǿ:YJGڪ12C_ˆ Ҥ2(/=N-ulC|9H>!*%^ɔ3q4 *dc 89KB(|V=oW|OOJ} p p:OMs16bf"u5F"Evb:$Pgd{|+GmqVU2V \1/\T4f A$P:]y]g I2fmme]!#iyip>>Dm9Is5{$5ze_s2ϮT|(I[Q9*;!Kk$*h꼿M#!6~4^|GM$;IE~bvwiҶz_7sԥvShj~?b*l^`_Ib8( sV\G,i,4oZ7͢ϥo(0qrq4:v ]ړUۯ$lC|uH>&P2Q_]>7 s#^H}^y@#j63e\{waN10o uw=<Nu*Yg,mq}:[>AWCӇdM}&ɛ\$sjex_&ȯjDS^ cFaЇgQaQ-O $ TGS؃{(ϟV~?_ }Jۙ"|~SebymFAa6n K "Yu M3և̴WS3%6,EDmc!ɠN-&HH}6o{4hxN֮nCon<ǗcmLUoXu|:@ם\]o+r}p>>8j 891rt_ &In҅1ḷQSsB! VU: iC||,0ݩⰥ#CQW#x<?zOeP3c^_Rb}kť˦ZfPn>{%=ݶ镫 , /q᥏Xy@CZaw=۝U>ZLfgFgWzCl/ bƨrՈsb0ɞ   $Wqîǧ>t΀ĴMDn/ieT{#\ |8FiVG;NJ&x)}amdΕ`>(#yPla y{Pqrkk-z]J(sԊBpQh4ra正{fJsuRBs @?$''E./oJD_T>DFӈUF[H`׽M7'4a]pޔ.&^pb_󇳏+_Y Np$'{ iOPщK;3ȃʜ;C\2{ω*( ͫX(ޖc^u~嘳:?~Yo;=h 3.荷|~g+؝5tF𱚒)= /* '}^Jؘ(bCԿn:\T 1B"A +7!8sjuu!; Jre% |^_cb*|(|_dCAlW:c04S12_+zʐH7ÜJLdT<7 %7O['ڳxpjp@9WCӱ3f[h ˹<m߸-M|]NMmߛ6$;2(t灏MsZ'4.aa6[1^H)cf^;]YjY;7y09|;qԪQ0KV|#~oc\CύֳK^t\Kg=SB+ wM[4UzxHbpZp7r໎\mqcŹ/ |?韛g_觟mtXWU $r }F +,sɹ œ0^v{&.)W% |K-b! _tlHQ@"Zr'IN1Kpun lSB|NH>1/ؘwnA~'|k1mͯ+1 F$p&O36ǝڕ<1)I7&=|'8gWʇ琜aNZ}ǃ0jg]}d,-س7pA?N [Ԩ>^snɋ*+n)!ۘOviLy"sv"CzVY=!PGtlL4:d\s|裻|<dAq<q\) r.4+l^z3į+{]K*Fk#=|MeG60|K8昇ER[Aw ۵O!-א| ѾC=ח?5B,c:E:s5[`>%;g zV!47avbXyʺ;}\qf"9%pڮSDeܩFFo=ە)6Pö߅C'PNJdƫgyE| +Y2$dI"QI  $+(*A2Tr"9$EDP_{3C9yVu_7==Shi%5iQhvZ)\f11e_'*sE^躆$=tb&]r$氬i}]6inGd}ק6kkJ~PujJRĥ{.O>"8^?~jQ(sI?@hDSƳŠ{l=v[WЧv?uiInsMsq9Sp/3|'8ߘ?)m>BSbevmkvf-TJW%+ ?8yKu6N܁tz]n8~YR cקokآgoٶ||8jKicG@ˈ^]:Ic<}WߘYٕ?11e;<VXgGLjh>q:!pF7^ M`Thlg!fyZE /B:_yߗ)8ʋ(;QnaT{vڽәJA>g>|U`9IpMAGVh̽Iz]!C!FkGnP0$ȩI2U@A`FӶcB˲hKi}~f7a?9S,W5?񇦎G:JʍrTMC:w||R`2 S60?fQ\L-:3t 23ؽDi;XE=u2nwtQc /ArlI 甆 wǾh7y1,A ) _4,RoWlTsOZ9盍뷖$bx͈b+& d@>ᐂ]'vgKd5s5ޟw86ґsCCp g9y/^/󯅊9,R,s?_11_|'甅]H-wqmKcHЬU~6pW/3Z !Y˦~+z+pVKSE@X1!;WÏ %>%8&ն-*qwoi<*EBk+@>ُqa4j-Ӈy,)ԏ 䩘yxHծo ȏgSK?BXQh.h Yz+'f(ڇ*A>y0 JTW]5ݮ:礶^x=WVoc6y<<K9e|Fm"ƪvڅ#[>?FHX }q<27b^8@68+Iθ-\S'dprL%3jj6u1x'R)C~ג"/g1i l:W* Vg¯7S'qlpӑ`F~Z|3D?kzE6F$2GJpVU|~|ChF@JEYnk \{C#Dꥋ88,7S6S u/](d;HLg埭KE_sL3|j@3|qQXG❽R#s'?T *D^#iGA R?[ !tPٹF]+&8hO$Cg8ip8VW6yIꀷq q/kN0 ەb8 =s>Nz T/hr]!ʲ !Y_6yRJ:6j\/I6ޗOԦn0Π,11e^<g}y{H|>v4i_3{M7MU3Rs{S"<"3;ׄ2)@ؖD| _N,.;ɟ&0l&i @ׁ||8qP+?fȠǵک>Ml{߄'Dmbzb$))g 0t^l ɽly_Mu-R}%zP)ɁQi.ƒ :=\e6t"%q#m">r6O:4S;l+ 8ߗQmбsBf`mz<_:Jb`xM,~%j\Jo!y}LrLTF3 {k-4LLV'kESY *Bg5x,*@ Oz"iRCNJZ346$)e a|Fs$Ds^ղ:<{$%5"{t w8EKS/c>BcZ:c+͜9/WZtnlW|T$p>My%QrD4X gy%jsf#wO89ơr%{ N?.69ǔ&Ӟ Ωr=m24Pi0uabpUШ67! Eǀ)ωa  F[x 3|ev-. `{K`ic7F̥!(yنQ׊ڻNޟtGt??&:w4 YI;䐲88kgp~/m#+kF97SXa"H穫)/g/(D:Y̍^`קh}%'m _"B<1!O2Q1\,WURml.V-^{FP4T$B g?_6װˁ<_@*>A|W#>%$>U 'Mws'wt \޷ogJ9ǼK12XqK 'F'UGՌ๜I~ ǔ]A@^qX{ANMV.]Tj;q p`BƧ9SS)ľwJQu*VG$Dvg17 'l7|^OߵOҟ*%ocl兏I*Qo*P:B;cfБ\攋4CNke䜝@ |.U$)ڡ@;O / qv|6 oM^7E8 "7eQlڏxm}\vq vʡl8٫+0N4y- _|%>[ޚ`:B736p~Q49INwWJ7囝ѝH^WH >OyRxs]x;El3VIH'q3&w7z0(0\D M78ƻ,͢ĻL䃹:ǣ*|mMra-u!$)28t>0!=GY\^P.PqBqsּ9fQ [wZ}$KhfG]Bsg;#9rlۨg{(k CltY4̗./:qF CQZOL1d۲n&̾.|_| $Em2B d)G)4.~ґTp1O bNpl5 }'|x~E=+r+ V8 ȧrf^d~qIDQ!e/)_ nMޛ>'Z[ʻ-;x OViʍb}໽g sFk/ȱh\\ kjFRǢe"3>X~o9YUh֯RUʺoAtVUIqɕߑ1c;?.8|W֩PYOש!ߘd؄0Ķ9n666BN4WïATUzr6K*Ey˗u#Tmz5k=[GD!y}LǫxG+<igU>pD*$YBh&)[Pd+D*fX3yQ],ْh&KG mT/77s͙|纞k<}9ftQ TU0ԃyLr1,i6HgSs} ꯏ6xRbF^?ߛx sT5)lu9w6n% O:+^4#ƒsEt<'Ju}PV_E"ya$@;+|;EFUwA`hJdVBA}d]t*͛x&$#)Q t^^ 3c\/[LW^tO[<w"!(-wvNnSvuGnv:{ Usqw*±%z2GG>۳c\ N8 .XD(HfG-S5\ͤ1Gۯ,92Z {\Pld}vWW›6I/pԨ5hJpi0ЏZ AG(96@fC+h/ Z f [ IAs#C_Ok"qݤåzZ.K뎺&n۳@0؂Ȍjt\8PXYK+K_NxD>(:9۴.$@\F}UBKS_v /q_3(r8~!H2:mcsouXS~ysXO6*1Fm66yhK9f [>ζZ;IQgYc;=E{jdr:| YhG~5ۅ\(auVO\6{%&u0 ~2A(I Es^q.usO( | 0QѲ4ޅd=M3ձZ, GJE bT"Fx G%f'c1]6׉+l"u rWڤ?6QISxrzLM\5wF_B3k5w6+>:-Y˦k1a?h.>] < ?ef5;Qd+b$ƔS#ߖC6(?pv.?hgI8XUI,7u]˧;t|~bעSvW#'zpcU2zPʬuhqwf~eXMBUԤ:N.kzIoćNT2mVpYOwhxNʁdKP}la_9|ȝeKpJT47ukQ_Mq =:|X7qKv)T/nŗ]F5r@yzKa@'ϱ Y4=%n:8~Y[&9\oK\Ж(w s_)1E>dV/5zzg2/O^;QԀP%Z}ߏ"rv8USw<ër7MEIK-f)"g>>XLXqimJGf9_Y>ٵP Jr]H)yFbE2je t8٦co{8 1c9kV\%rt]u1c=Cȷ}Z_`}k'ԿdC ܄-:v/~j -B t8Y׎gh87~!;RuWl򊀩}/a6EW+&DWr>O6>GŃu>-ov֍I{}m} oB\p1NJ+pS]瑁yTZhStOfKLq#5ژpXE|/E v(e60NP %Sv|=^㛅 ƔZg#q|@T'"vRP5R':_im[/gXs,Xm@u(+3̫_^{{)7ySCrl0h+x.S9b)Q-)'ݎ?}? k"Bb:ʝ&p*6n=ZQ._=<]>0>WЄKAtkmkH"Z[W!dd ; #z|_{l{MB"{FlώZ! #\fxֿ֜:;lYJv_/ ^>#%8 [g* "Â>85ɇh =× =j>~Aw|pZA}㱪nyI1ͭTs\}tJ}W,$L)|J,;=rw?ϙ8Kn-#THa^ Jow/pu{v KL!7m|dphJ "&yu?MEKv-QS-87 qq)y=}{z#̎|!z/z pPo>׬`z=c!q>K8;p#ϾD1YCArK= Ɔ>޼?|GPx0^Oovk LM6>~x8gOM@Gi7|}&ħO|[VT˙wf x*PZI Uq.űwMo;u ;m_b\IUtꩰъy㐞tlg`H:POgGgcJ`յY8Ҁ//": l ^zocpAǫPٞKxA>t7Z0c:10D=l@"y1H v`۲B*!մҀ=:폝XBؽlX^oqoS٘h^UsH:>T~'}""׶G@'/H_ĈD<GϷr stڪڪ4HPV ) +#M/7# NSn(ZS~=q={5@׿ၷP_'=n`״7+y.d--_(nU s)xz!_+86P/|mf[ߔ֜0qbH=^qQ)Χ;W=T۲LPGV7Jnk ̡03 3ps `a.ulOܺj{(K;YGYa>rn.^aWtĄOqN^1R nWg|Ie|)1q!]=애 ?TWB|}t)-eFjIE'a%&s-q!ؽdg&|V 8MrGzKtT_lO]qI|߄mw!~z$`1IL3H0:QZ8[[~vn Dù@y3OȌP|>J=}Wk2B5@o\Ԃa^WnƛcMW3X>=S[[:ϋaߠ@'\ pp\]K6iʑ\QIQ,?krᘮezsp.R#[yFl7Yޓ54jĤ='oZ_g,B@2 P̸礀|;ָ3SnA\tA*ՑҔqvxXlE9Q\">,Dt W0fKɀ',Ujt^h< q a+~'8%[RjhOl3Pkvp?@ڻ|Yfˊcј+ST;=qu -e8Npa]E'd[翦}q lvzbߜpZμ>b<+:7yI;?TA2kTd)Th**um_,mʞ}ׂd Q&&eN]E{~vW=:ݤsu3gyNcO?Mo;ԸWVrWy *_ _4շҗ?DQ>z)v2~܈𲙗Ʃ^. I7@GkphņziznnIif6GWmancNmNkS6$mZgԻWvu)|i)ﱴqv4IKpppRi$G} luZq+9Y#P_uIW>n]WV͘-xL Vv2 m}O 6W>oG&Uu\ÐοwWWywW=q"#E9aJ_Upu7E֏tnPےQ_Q?}>ﲘID5Xȉ/"G<ϻZf3STMt<[*l[p= `&9TjoryO^mK:1]nIU_N)gRtQ}NוÉPtc Q+1GvjZBTϚ?cOz ۼ־FS7շҗ0'*4?_RNTN= 騛Uw:`R>{.E!q]'jHz`Krea^6NЈva[ršN uhm`ƽGցZu9LcKޭ@ )|tH%z"&YbCORMZgzQ\ a[^aeB]MuNYoQyz㯽yW-|>"ۧ\jJ'C_ B4z ˊio6˰u=޴bB=,Mnw<*^g堦>o|Z=N-ʲHW[*W9gLv=dEB|<{w 1"'Czj.nev//r` @p Qj|/?\*8QeF*gk۞Q`85QEC5 ʼnz K[ɏ?I1?q 8H8(?HsEO:?\h1oIsC2`qYHϏzF~zh@p#0%ُ}DpL$ ; G=Fq̓Gj 8F?O[!A|/z~##ݗ ?f@Es >Z#G =6g7T.-}xOj&yÓ<ȓ+NK;D.^xǏoE]W"_\4?rc֏u*$ }~8~ApđpO!r'şfPCp!_h"8H>]BwV48 8qL}Q5G6cÂv8Kߴ4qUqx~<& 88,;Ldi syG,}np4pt{ ?H`grR [Z;tg4KSLm{0·!gDY6 x:vϿ< +!# k"|b!Ga*G%#9xmoX`0. xtg<MM`a3$S9B 2#㜈͜x&!yH0wo,ca*Go)#98b+o,<<\$S d]|H>7orys>2#EBa*G/#9<o,ay8'q%WdG"xXg)G~-g!GYa*G\Fr V |[BTPCFBTP?FFr5"|[BTPl@g#&wٌm+ 9$S9BI-lCAߠķ?.?D0#%#9zHXO"!xY>oYx3~N+k$}9*lje>D`J?<#O^dj±&<|,+lC3mh1( '}K98o#KJ3<x i;=h$cRS:JCC|k撆6A.~RS{~\@RH "p#Cψx3KF4Cgs8pGzs}:a NߞE%R@ AM9yqHgԏ ? |io3z~@ʺ~\DQJzq Gqo'?*)?Dy&^9#땷ԯeD~EB.Az,8 H8: #<8A pdA \ 8r%pG0!(=\:?'C|\.i.q=\:C}\G p`M8r@ _#=\~T6~{,pa(!8 8A p<`(_Yt? zxp=?߯@pT2JG5 UqxQXq/)[t#93 &v_ꌧ'g#?$՟tؔF?Vt~s:5x_mEN*嵝wȊ&hS1ڀwԫ6*k/+XT_=usk%;s:ߧ4ꘃ䴽+ 7}R!כX&::{ XRQ[UC3F V]7QLH*EAȲPzwS:|>"{#w[yS~k To5$xB1mI*O"?n%鑺˛ƒ] 7"} [%eK$K*H}iEHQJ?}2sߝǧ^s~{>9oOږ~ mzI`M^1`O)kRs`Dr;d~Q71BML Ed}Iw]B7't|`᩺*sګ9, /yk+1S.Ȁ?08g.?_9[CVctKLLa8zwKRÿG3NM8=yy"Q11?IfE)eBIGeM2E"H;Kw* Y*g57'2ݠTF HeÇۈqq_4 N3u .M++uT<ɞD@<T6W/#YxƻFAs˟ɩr[Vz=pmϭ޶v"_R紐N^hrnE뙦9(~K5 ?XoamF|pCٷYW8>擜ռT06<  2eCe@:a=>7<^OM%A>NJn`s}t׵Cݞ=_^>`=TFH5,nTeBrJv]Gp8\' h7Ql+=w4Ă&+ غ4 .T.6 X,NnXR&z%-%hLN!Poi?g]%nkzIϡs Cvu9]h)Ό~P/ ~5BGsf2r@B,^ID TBB?d6/BfCP\9qMkonT礦,m>O>tǍBG#'t8Ƈr_~OZ='>Vt-y 8Zy]lg!c||δNr <.K(chR}d}_}s|Z3Vm܁J%;:2 c"L聭ibH(o.\0WA`wԵQӂ/Pih2nHD/&plA mcwY|轵}09+9@݋Jt~Z ] ~≯2d8/ ĕ&3V8K-ժ3Wmx~ (·| on4U˄L\QyŇl~f2#Gi΢+X*/'̤6tL4 K'ߍw jg̤_ x6YF*Oi]1(}$bH3߁UsŨFS,24ۺt82F)K\xc?dq[ "ڬ!K"+7/QV M6k6W?f<-T:#}\8-Wl>(/&H!Ӊ nbӓ4 U6s.vOC:>8!Qfg[ܕY+=.n qᛁ7hgڰҨ%ײָ ;c X>-K~ٺdp %*]Gn:FlYxKG|??ęr'q~8Oc|[ SLL &Z5O~Q\6/o8`ǹڌϻ,s'=;7_R_>V.뒙/*M+F5ޢgHaylF@!;6|r['y ƁSW1W'|鮈_63܏!-anmu?6s83}\vyQdft@Z`s}o];l7'mWǕsTûB\O=͔Er+A? 6O5zOi:JU4rJJR$߬Ш\eŇ6f뮦kST}WRTwΝ&IOe-ubHD*kf Nv oi^>cShlb G?$g~袽NTikz)<@fkvʾV-1ØPnq2h&Li: o|ѻV6~xh둎"d_wT_#\x 6>2N~?\1訌[=3f4)blMFbH{ħpkDM<iciW~sdȎwOf sΟ|csKl#.WWIlgNv?م'G 7۟TyVˉS||$Ꞌ$X+{um`{;"{)vܛ'i(݀jeOxR'nINY< Աv#zcyiiN'MH-߆ܮo2y=rT̡-^_j͇Rɾ>-Wy 1IYƄAcf~.їEU /=%Ͷ~o؏p0GBB=V} !Mh2[灉W-z_L>f}6!reVu3ݗ}^\AWeP`sic~M=ޏWVU9Sڪ۔YCR37\)Af󿶏RtF HmHQbr"`iJj鱹Whʟy'^2K)!EƱJD?dUd+$Q3wFdDFQ1"I~?=}<;|>Wު?K>mI^ی!:KrJ+$@͖P ȷlb>uer)E:vF幃-:cnjԹ(awb}:m_SST[5\A-rp]pXmO;_5JJ3)I=wet *^-?CC^oce |&0gv4anEBpV6یyov6*O*掎BDX7Υjj5Iکe 5\j)# ~]5YvlW@[\W`ClBE~xŒ2焱& A#(_"l j~e'GC*6\[.ٖ@MOq1E${mNur#!gOGuA̘|?;YAr\9ҙn:#~;AQ}?Z`l]葹cK=$؞Sm^n2!J> /GnUr~IʌA4?j+6Q\W+x>,(WӰb֩/9HiVzO5>~ЂGu}M}Xɝ_jjh(5 >9{?XY=C[PȌ?~bk'{'>}\`Ox`;8|W;5xb?Z x?\̗]/θz\ONӲ!&)4H_,g] .u\ 壺*-92Se ʵ'<ÈimSuȧ~DCݙw ]Lߜk 'K>Tcqj0OJINK2Q$0`7E[L\C'q]pzcaTLc'6aq3wKk+}<w߶ 4ˇ5kMkvV%[ \o6[}yMi 0TҳG-2 ujoOi~o}B޺Kbg(O}}޿r# \<_qS 5iηVW?*tusW"ӟ\oj|!KhP|!\. >guuaPs9,925fdhW1RW6=U,O{t="F2bU@dЕ~ĢlL6Ӕ>]Nq˵̺v1U,o|dQ>E_Ǖ{hnH6N^,4ʋĸ$̅\dq]}S261q8kr)1.]p)!1>Pz\,,׻ꜳ4U lHhE)T*TPs竄ϝHԮeYrLry/v2O >:"oç礡^!Qv2FEq2PbxY SӨj* I:N'~ L&W#5cRApmz2Ec,dwj_v=f:jƣlW,sa0ĝӿ6Y]&>-> ?RbF{\u +oheHKU1Pvc) H=jwjg ~wX\*9߁Oײ}\AJ<3CK}JA˿^09|h([}}R2̓٣.u6 02\h(Oy|>x|>? @gO{^"$p^3D5f ή|X\ N!Y#62dFq(D˓L9ϗ̧jҁODzM}WeyB3v3Ɏ4#tQ'#AưZ L.6NRe]S*ϳFw&.\Pn`o έAk+}j/$ })㨰){xdsl죄@59<sE_ L yAei@c >h^򮖲ɺb'tiCztP $zq]ðk~U7|y)Z퟉LNh&|&ǟ\[2F˻$oFDr~ ҎmzMcr3?&i|Wp}9 oHZ h[ $ΰ2YtKy,YZvBç7|l)+)wmQsQ1σZPf첶u #D5"ꢮ0Kh Fys #M.mW>q %Bѯ|4}.'dcfJ}P3o|6>p_6є)%}2GnRX1S+\p/ xNnx!J`wNajK A%} Ԡf]Z6`NPέ+6r5Ԅ(|M}A_H$5{-7븩 PPQ΍qF:* ^vv>}M?cdVA~~KIpfXm935CKp]_`o/f _5g=yyg*w<@wO.W6̣'!nJ+C}VzE!U=(Bٟ`븾i!p<>Ds^-?; fm^>;H5kDf7+R_Fj)LN,<{5b-˵XM~7`JODI\.m^vn-g~݄al܉Pe_톯SfaGiH+xfLTǩyխdUK=QoG_ EXVqn2esBOp}s;l6\Tbg<){/ d,e hӿo* bzu?b˙k~w0&z뛇_P ^u-^{]n~C_M(G׾|ۼnS%JZbzʕ_7Z=9 Į\g Z'{R"nKmZ4 y5] 3Anz (j`r />3>ϝŧM%dsD%^qx=| Iȥ;6ҤA,QKXQ{&7-.s߮W7O%%nJmMx[\LŮ{(([} Mm-þ,cMZOXJu5Hn(olg˾M}\S-ֻMs#l(b-ca/@ ( O}*$ϒt. hfki$"C>K6='5ʹ#b\e-ҁ缿yZ!ߋ$\ ;&z=a0gXăœ ׎s+}u/֌V Tמ\@{\}cʭ5Yx=׷ ]mgU>%YRdEE.oB$4}hV"*BRBRM!Q*eK%?ޣѤ~>>w̜>Ys=e'e{Ύ޻ބ 1\WT}A-;bQfs8Ӱ.47C -^郸2`a/Cz\Xem",:EV!QvuU`4vѯm)n֌bj곔2Lۯ?smRkzXM^p I쇸Ps~/:rDU_Z֥>$n_`dz7Duj)z,\Gh(oC-U7)Ou k-d~||ƨ r+7|f\荿:+Yu0cFKݜE"J|g]h4H <qzNEGkkZHʱoJJN9\l;_XhDֵ7 ':z/#| { ^&H54D{/?ޮrdt*A˗:g1I*B8׿t沞k޹d;v"6oy=jy03}i|bÙBHEw-;g~%pzN~8ŋ<*R,XDhLb\p^ ;j' 49 -aNO#Y'&oXUǼYT`IOua84>N&VW4?;w,ф&^KN3L̇dߒP1 H|]2Kf>[ ).^e-yݻly#mb}Jn;Fr]=li̓d뮇8Q1|<,wR$p⹛m#Ѫ_G`=όrbXx}hZ #U@gWGt|QBdX`JFwm/oshϝkƽ6n|4R<3] g[s4]7Z2bϫ67Wkiwdjׅ\aH}rYcFB4J?ְ4|hpU.X᠍?$FJª XZ2-Hf̥D s%RoKcZUw@(cf!stXkԱ V։7[dhk,)]e]}B!|l0fn7eY/IA[$`!*x[s$obD pR)8_`CdgMF.s}?ԃ k:7/m 9ښksЦU4@v# r^^`w+iN=t8ddC7;l@Z%%Jv8?gX/{D>ǔ19;u.d߉(2 /i  }5FRV4 _5̗+dҴ{=Σ0?_uBxkn9_U x x(d<IE\.d懜 ~YwLS˚AkRӒvHG} QArz&{?#E{Ѯ1;CdPQ{`ŏD9@f3nkw~ ҿ}L4-c7w}IŨPgZ+*т9}sC(<M!q!w~O8#<Crbx-]  FɾQ'vyb{tO|X42.mâbPzaWGE1eLϷ*QK4 c֜O6 hDCgf ߔ@L=\%-?޾F^aGfScIaoB2 qTd= *ݕwX<4F̡!aYMCR O_ ֚~l%,da^֫7Y/U|-@RLOwzCQΑǤߕ/GڹCd'ay"# 3z_hR>lndL-#uz 5z ͣk4EYP dsu%ɐ'8D%dHUil3O"KKaz.ϙ987%> MV9ajd{ܱ8eHtsn"ʸY~\$o6ᇏϊi4@/BSAv6S{{WȭmvUR}bF^բ&%|γ?Rb52uyLv 4erHXqPWEIjPQ=ǣ3NA#.j.9o֝Zy->Sroni{Sd<,Eg! R[,WD*p- tx ;1bz^k6NKNe9BI/O޿ٶOI?2uޘ᭷(w@Z&(H&A⪐̾ XqoMyǞ| mZUAp򤃋_el7?⠺?1zDٲy\z "7dw`.y9j.Hn-6 \-X1/!F0AG)1.CFQvT/EYYeeD6%ed$~T.$ Y##2dYds{n=x9 YX]EueЗS&U_!X曑ݩPYc &?zb\O*=xmeyMnѬvEʅ~w9M5ogmhv+q&k֬ǖ J4֊{0+M@ߧ'w45.Nd51;j4cot+ه9އ~N$NHDpTh`Vq֯ b/w蘪OI̾@v|j>.GqޗhՐa^ b%}.A2saX\s@a5,W;~w=uĒ.Ѥ*P@Yl}ojd0l;HyjDa 'MʇswB $77W.uYKrOP{[?2P}j*v<+7@y4{īIc C vQ\)sv|0(CɣxB7=]݆pzp_3.ېq (DWwC7vNg@*Tk'oOū׎NB k+'xw>hScO3>\ܒCš*B ? 0{"'R=45u$_.>'^6K({;fƇ'|*0-":kB#-g>ml"x[J97>+ǵ f!~;A%; 87 ΦSprU¸h%,۸0tN?a^GuBp<*./o#<~}& `{+'anNӧp+ehvautu.b!ӃkBͲ]s]IΧL:j?(mjA:`cA߯k^ _KulTiRNi];{>`m`|C[PzA>*[Ni٣n_)ԋ BeCNw|?`@_!w"Gd33eCOUݒja 7g+ߟOYI?s.LLw2[F(pʷe"w\ԗ"iva>vċz2ڏCȼCiC::?hnlh)ġɍk]Dj f L'-?:ep| oŧoJiމS*T{Y]);7$)n#ϧ*-pֵ"7CAjƌnʁh BbkV=?!:d4zemU4_\d36GUYnvb8]Hn[~\{!%r͉RD#X~u𡍛ABPD@l3WՍea8HL;aSԙؽϢk96G,e͏j8:s_>=g': {ΩAlX)=qޗ[fWWpN=lɧux aω#Id,Os9,hٙHd@Z|~8 /ҠT`X |Nn!;^Q3t;`9,dc%Nta;]||_F"޷sVv9e~!s&S?lѫ+j&ţIytԭ܁Rh^ZBW0ZVN<[nbوa%ZDcu4Aj9P٨]Qu88EXN -^;B銎`ˤI3@CCƲ;;,22.}|-0<|y'zJև`EIұ3R]q~~^ *u{$Cԡ"p$vJNىS7K,s\^8|qA3JLu㹐 } =wff`;'f+18}y"r#*nw ]$vh*ZAe#xp`;A'g%Gp[Ney?e+)x_`'| ܍3z9xĐX?Ib#2xyo<2W}(牀:NSOgq]M:FpN&/bVxݎ?mtbsTɪp\OF5ؔFDr"{uŁ:r3]ie=| Zt5!ŠW_ T<4罃qj㸶rbΧ1w8m1{w*_;Q1~wiBi1}" @.џ]:^̉~;]R~d/]t}N~{̾Z^],0y#ͦ$w@#Dޛi2w7ρ}ZIk`N[U Pfg{|*D *3 b6}G@_f~ ~ Qi%ݣIW&;#?:|0>.<|9[?aQcDm3(F? U>gwtQR:\*o&P-_/lc}g2 2Yވ//քK!>Kq 򂧇#1!6 #z&cB,5t 12Qg;bMlQWLw.q/>uw>1.Wx-uUwKRL ^F}kWeWI}aU:3P},cKv>w[#656:@ْ$#=MT!걂珦bo{QS `dɍ=gaޏ{α$kY{-"7d6)yTLAآ/ޏb7R>~sl:,J;Wս}Vc*8( zZ^BI}:kQؗoH1.ȳyI!Ȋow}.p(2 J~CKiOP+/xٖ|~),r=ɪ5@!_Ga}`; 6, >rVr T4=}S۸2jR >i;ܚG~AaCxܟѭ}'AOt$74*8m-O*3] =}ZS,{-^OzGeX(+F`k:gaLX<78ūU5x8Oןgyy8UcBr˜2UH2eL2EE*J(A2Cfd,\ex{|AaCcQ4)z矃ba:KN[H!йdZ\fyw6v RAZBF<@R qMy}NP(uO$jAHF *7 s=GʃB= |)0Oc+0voKƵ b|_P1L >q|?F U&IKrTdBhvH,K '"}FRYCu ~w5bJii#- (3 :^;?M|ueWk257Xʾ*^"}Ơd';MÒ-gRޟ9WϯMY}~I ІY^6&{}ߵ[NS[ZXyjhB.{**;>ЧxcOվ_ɨ+P#W_p3+͐ov#f2g09cVB{]$ݙ^WUH~}A@Yu> T?tRw!Pf6'Ӧ;"OhH(4 9GQC ގ#u=^b>&Ȩ׈2GkhS0'wK z3}g.ɨɚ?B@Q6|^GP|9Ğop||<3[ ҼgMc+ @.]POۧap&ܾ< : k5]#oZ *. >b.r>)XElp'||-VNLd㘦DA&1z:m Pl jgi:S1 .tߙf_y9┢`\ ]fr{c̣Z@mzº螗*q$'qOCO<:.񾲓 ruϸOo1zb?'9I(`2ׯNX_ҧ!ˠRS7jxq4YrFfML%!9 p+ S,W\0MĻ[9L=g!l(,NJ[x^\(᥯l9.9]ԖT W' pD@ߗ? tLGK{\,'7W˾IGTHS(x=[;9OO]7.=?dRK}6ө5PLsIJ@"w}K%Qy7%^p{}=-^s% yoH ~f$rqQd4KSBEKQd#Krk#9U vBU:Pgn%zO#N‡m t&Цrb׵.V9Nގ-s6}IS#3"ǙV4> Y(9({#}yM϶в`+m㦊l>tгĦ#I\,u0S[֧u7xfݦ=-"}hkܮO)PL,PvRFA_uGVenVCu<儕cRw?B9_F;~~C센Tff:7 WsO}b6e<|VHqU"ȇqi1ϔd㜰/,%m㩄|Pƍ\ OpP ;|+aRI5[>zףIE^SO聲cj_-GM,\vSY7:hpң v,Z/U!<7ySQI;_մc{ov[IWXzoI$޽ ]">[wM-QdIO ق}Zȷq~-kp8&44T f-U3%1@ٚ-:}GnNM4"ޤoM%s5)?|S&{:'>!{ǝNx/gp̚Vcv^FzC7ޣ#rg4sX°Hױ؛8S[MžԡpV"'@sұ:P_8!^t~G9u(hG|݉(樂>PPNj.{cNVɶJ( P\?A:Ag3*/>0DWlmc$]@q|;p No%|v;[d\%i0,Ŵ~MA@vs#Pk!t&NCG+..ȷ⣡_xEcjK3cR'a8hR=n$@_u`H3|S,-2/5iĬ)CJB ]s)K[.pynϔQ6'^~bRQe3H Oh+,EIʩ5$B"ĊBU~ǑޯN,Z88rn= E+CHehq((y!}o}˖=j>uޑw*) ?NYDQ|~55K&1m[Sy}pthASe.(v=5X1]t :n}~D!`ͳw]|5/58_Ò#n4kT:c覰v懺ubF.%c?K: ;fU,yyn @FS%KD-:HP~~+KLc;(]5M'u_ -|ow`ֹMܼXFй =eY8?7sctdk`\fF%C.)߆II?9y/N8<@SVVvβn@͔UìH;k|\|TL߹/1ּKiQ|{(hOWk>XnslӧqbxPIOSTxǹ)(&=Pv*3B$o??WD]:l1j)$3ww%UuƎP6C<[]U%SM.L8mg{sLQcD<~.`}[ӆE35t\An;@S 2*5t"\{i5agEڦ .M~.U6,fW !ս:գT«Y/PcdNu;i< P%w}GF$rm`\>0p)?t}3W>YT> u5-E k cfv1_{ٳ7 b$]:>=e3#gZZ7)m>-_B{]b)f/{6ƺ8+pa8w3s[ҏ?4׸=R0 C!;>< :Sb/ۖZS95J8f+XCN[`ggW'&Ia7:Vtl=yyϳ }ȓ@]-n?1HZ*[3W]Jc`TȻq7-;7Yĵe;idsG"~E)gE<@wVPp PUYӏt!1ƹ_*cqЩwxz?s dEqvRL@E3c~]mj8p"a_\¼'pP2 PKkzytf]$fLb⌋z_CN6N;IE1 Y+ܕqaC)B"PlԈu8 ?tñumVj909h/[JʏcGq`==܈'moyvivk>&>a1M|vX?w7O.fQ[:8Kmɑo@qBP:;&|Tl DY;J ~ܩ:6q8 t ٫lT_?4@Ng.O>`'d`sWݖAC,jignd2"!vFJ&ID ȌH%;[ҠQr( }ǹ.ss}=2cjzJR(Ry ;mjQv.2|Ԩ9[j gd"`8=g1' y>g27l RYTŹM_w.Mw0 9X!<sL!Jm F%ZF?Q//8}_Yrx;eF$ߥ#njq*_!$ >K8-B}{.=tcM"ȿ <^HHWug ۠daE+E֍8o6<+f<^BγXyc=م#/حcb{|bl W 1R^d9s ]|WWSC52u6*ׂ׎X?)Kate=6֌uy9kONV< אiu'f`1>Ch`oS©öiǶFShy W~[ѹځ&߇rY'bNdL>1a}T)'͈Zi^mD/fЇMv}/so(gY!=ez٫u#'!< K81%XfcbGo/8ߙ̸ҏlm:sWe<AlgaH.HyM L~5Ɏy )}c#IYT=8CE4Kw K=ӓs61C6Ov[aXEE=SrtM:m-QѸVL:y0/s&ey~Mx,D^gmϜ~LՔ%4\I4>0Php2Nf欢'h~}> u>;rA!dl ,5[t>X~}a:F%߾o''^MoVZHC}nҪf—ǔ|29u9#gy1P8@N9t@٘5 wJ+҄ y{^ylXٗs'w $ҕy$'ԧlj]T|-{I:eAەDP ᰓ.yvL0wd&\6>Zj\cf,fɅ9MO}fQ*yڧm87%ͤs?mA1h:Bi1V)ţ;QA`$O_kn<^#=Ǚ6X#ADwL{oޏ| .RHWOБ%)83 "K׉zJt+h(,~w(r<t>!{!mG<.doO)N>|-#u^, #}c|ʆ* |3"Cm;ϴ{D|6']ǜXeإd75iTf_x{^ ԡx)==UZG/t4Kݶ1?$朅:"( yy #-l7M7#UuM(}&Ndbj\ Pд!cg.'2>1Ĭ;t ~l!3v*6 }OgAEg``Jx@l#88 o%uHZawh7/D=e|ҷ舁yж.9C!lqF :UX G爓c;߲6ɧ"&ZPNUm~ Q x $9> =\'tB; `;/Neaqܺ`siP0qChMےn.D Q%EN͎8,)y}ME>).O3/3)3zOU|?e\$[dTEOZ@2Om0.O$=#.lvk+jۄnOִI[~ Mjh=F/xc5'W`c!F=Gh|sDYGcd[8; ޏܗLCﱆѮI`~-&Hl='rMYhs )o35.$-L*Ec32f/G ߠy})xןޣ ɚ(OLj,XPmA]p6cba} h]lMY.k?Z.S3L\LO5">~_ U*߾Gjw|t!ڠ]0n0B1HC78IzNjeϽx`p帤[Z)'9q,62 ":&^ÏSgk^ƥv~ :@Ջ팇vV"ýKw8_JJ7>潫{pJz!r|S?6I5׬ۑN%(ӏD41npɿ~eAΫ`(#Ld̺iT-rgMǸ S}sKE b:1!BqW]'jGAAtZDpKsgIEkn}8"H1 qJmoN󓨛ByB+0H2~^‡~T׷ }%6'һ8 :).i%צowA1\iOa9a~w.>9uԯ;y'^[[k,,SOLyRNd *|zvZ-YV^͓ EslmbV$y@TVHAs\ ]~U1ܑ/R;(0xH'?a C.%rO^T1^x"s 3xۙ ;թuDeI-]xY&YfM׍)9 oy"K@m"#G%_gtm:P -3\v+i4"n@Ŷ[^¾~xpL':D()PTͼr,֯X<S"t mQb(1ȹ 3vߦO{Ϟ&黾Bk/e6an8wq셄8'rFf~KjSނu ^;UwIqۇJ6cփb<}Mk\Aa$ 5Kêw{w}'XN94q6y8g_,`YN>Ӵ0ϏS&/_IvIg_lH*H'\Qv~L 3|B~F=~f:s* 8uJ~ 篙K!-N\C6{Q0d*+۹F8s?z_:{ș;v4;3.:\st#MBy{37Y1ϏۍǩFُ.5$9q)EMqg-Qa/%~4:Ĕt#zc3=gJ'H~6b㥒*T%yUP()2Ti}+|sf{xRv<mے@1W1.B^\qg{chuS~-(z[_/Wx9WGsv!wWQ{OOZ$.=뙙2[KK7mfAX`h=4CPsv>s`'7L-*Q\$l s D/ v0 U\F/xľ>ҼYtTZI1 [%)ZЩ?xHŲC^QEaJϠ[S~7RA)ܺx|xPMP<ܾу5ߡE'Z0#bWVmA1,N[s|S`yM;o)QKS8R+ q0>ZY^2ꏺ,=n,U$r3hm󻈡XxT $7o$U,(qihhhֿGB%XȘ!sqk5Oy,)xPJ eBd($\e*e]{9seey78oC")Gc<:S2wi&uzE7#ǼkX'Ӥ~dZFe z>6tl7dTkջg1T,?tg>dTnOz^H$>]=wT ĪJD3ۈuukZ쏓Ae#Bp]FwNRL{4y}Ly;1VE rbq0΁jq#ap;,B< +0b^"م,f>RA>B}l儲n:$ӣ&mp|nk.+5#׋]0p"Ifby7eV]G#>>}Xq1T\pZ;Až#7|o+F6UW+ !չQQ@lDv:j^HY[v~H]PuhùR7Y~.k(:.,\Z^R XB|m,c8ܷ&7y>OLX8Y9{` o//{s6ВT +lUs{㼈XFzQ3kxݟq 'CU/|mM="Myux0|yP;c 3nXz Пa2r*L>Ȯ'9[>xt:D,6 4 [zW<~&h5eВ+4Jr.6f2T:\닃Ѓ+sTEE\nvx1D,\w[zW[={: D/ %ܠ@a{4~ MmZ_\(I M5}4E54a@,.#[v̿] DZMVd4(I;/Єx%qWˍCcس@2g%Z ZWNR֔*sT6bs^k%dz-Y} KA}]Ϩ yT[C;rj$ :Q[^O*^ Lx"]%)uT쑎UcI{ŧ%jR f(@N &ŏ3ҋ^=T.hI~6*wulI tИ)w|jjzEO:bFX Q & ovb,mF/QK-QEF~`(;pVo3|Ԗ<<ܑ&"s {t /'^R&X8xQ磬6#kk; QagmFZ\g3]#Pو}mzG^e9  ;v U ٗUEL59M8qp1zEqo zb ʠ0n2F>@i/.(: `@ @''t3Y)8)w+A)bF-U^4:nGN6v&5qGԵJ砲a@ v3tj%ֳ6U&$3yQ͢|#} 9mGmD *~˫q uVZR!93y*xCpm3YҹU}Vpݐj+Hl\EzlC1{֦'9-\f z~IFD14;I4^EԲ5!Pb.|]ֲx#=[aqBµy3Di'$%Fx $z#AhYGه|:XeDބ6KytF(n=n9/nmNv+'_( `TtxRC i3+¡?VhA>CɩtmgO.H6pvDr#&oV䈳,?s&MZQ3^K.%b0Oݥ}[9׾4:< V d(E$ ϙ*T][' fʝ&{[]Er{_:kԼ{ k녿]e:9GrY}D-!&o3/H~Wn>8cvOofٰ++TPو'D {cD&iٰDy˜LUxea)uXDct a}^ܓ,̅;$$ZOcem*Ʒ@׈!bY^ޗKN;K[{;lh3p506]{iE yݨQ''Wano1ϣ+ᦒx yML 7 1Dt^f$k߼Rӣ{ެxhdjrӜ!>yIyCՉLNwN9ڰ'9[TSO|==݅QNGE>{N+ߟ$/1\,ҴX`$X& :3?i-)keS+e' r{ͅuM rcq*osՔ̆DwǏ*0k˴S! ep{@w@1axF GRfpk{`c6j -Wd ߑޠ~'?Wx.r_b"`͍l ϚkTk\01סelw[/Ķj 9?۫W{ޜh/ԁ8^Nl|k-2>=>8Oy/cIrw7sup3ݰaJ?m" |7ӡAk9\{ nf"gDK`-P!z>7!?-Mhw"~ 9ϊGĢTxDއc%$L_ ^N׈6~9[rK꿼\p"~, `Ku{*iHe)k^濂Qb$rкnS4?'I/h Tt<ښfۭ!k׼ĭn Բ4afZon͞ZEƖ{Zم47e|~|Vݑ۟2]ۃ/QoYANj|%Ǭz\Z.j!љYtE̴5`@,<(%sNl8@fxQͷLǼі[i*V1ܫ2(`l@?_+Iv/ci xv҉%B2̒d5X@'n!;w3ky֩ xQ}D}cU@K~ō#[o++KWpρ%@g21=jՍH3VF!blǣ-4VJԜHS7YeRWta`6s|S6b89ܭJ6J%O8 _<h' b),w艡 odOg%1+fyñ}/jhk/?9 fkjȘiE i2W$ y+"' b p`8@%Dd5jkq^OEd-y+ᜬ+z>t:G㖧oF6>7@P%b1}m槫4/ m#c_V wI:_ _ߑO0@Σ-#XR, eOB( ْ.BiH*ʾ&lgi0Wsӽyϼ~VJ<%K=wz㫷m]'ߛFG$ -zJ!#W8x^;Ģe4aXaWSʗGϸ) A8pb#ˬ93R0Vqԣԥwmu.K|0-z] ms:'mxgwx\4]T=s  /'yj85(zlTm(֐@M}3sBڨwIT ss0MB)2۴%noqB6)oe;8\/J UlҶe`1v;jvx~TÎO$ `=I'sG2 /Pqj}hLS?9p8nio@ fnQ |LU g[Jt5 ?~Rd]Z/0/u'=Zˉ|Y5sXm&d,)}쨰m}Ov*!k^*٧?o=j=Pq韬AftH:˃{1cnP^Ǒk+#w3|TL#͠{#X;po?=|~EQ v t _:)@n0SUtgwWxFu*!@,8ꀮt л; /u>sg0K1n܄q#i>]#~2ƌ7·¬Sk)#G;[S SBdqsx;|ݙ9KwElXr6j#YT }@^Jy' s{k6;P{G:M}Cp8{pb~s}^K1WlUjΌd]_ijob$BsGB&OA㴘u /Nyu"pAu| _JCZrl9EQm'T, ; z#d+3y>KHw$j#$$#T'8 ypxؗ|)a6,(.(WZNMphMI8>$brT&)<N=~yrAEAiDл[AG\j1{sF:1a:`ހq%SDez֯Tǖ}xAфZx^G@gZJl_Kzɑ\R|e+"_oAHβ z`:"j՚S&RJbmS|n3וPȣAȅo`FĐ> Λ;UDv;Rz ؟Lck39p8ٱ\k91sB)oͶfu=˚meSCi)AϗA7bL/Q)~l2P3LDN?GamRyej|>F +{?pf?i:^3sꮚJ%˨T {Asl(fsD$uTV]Ki@l ِ3'?m:dcwU, r RZڊR"S5lxvPڽFQT,{I{; ʋZ/t :¦)/E.2 pxDZ|kyZ$`;jˮr8HOD{ d=Pb)g׾THXly07v$ e37 b/ĿϷ\\GQkL^ <ꄨrE7B@@bAxe K=K`}]Mr &V1+qrFN&0B^Y<6_MR—ɧ_@@ma_\yZ {oZ$=X@ Tԩu'-'yv޴au3QOJP 75$܌$ rpB91ɯD&:>;z+.q>6C/sZC_D{[wKǘ[#iUnyLMW{ 9Sq8idqn 肴1D:20=]=(YB{?1rNomT8ڼ-y|;ʙ"+[c*2BC3SvfVl ]FQj;޵Aq3Ⱦ}$>: F|@=.?dzV cYŵ03;HpF޶ ]*4 'J%y~XTsSgvFM\ą=9Z @ |9:t:οV4il:O%g TO>򎬕;}nuFϭ]\.Yۊ#Zڻaռ;e9%5+^fˡ }|΃Nβ{N}7.ȭ,r])/{Z˹90'TuxLd5]+n%o6ʹCFǡbX91x)g۫s&g. jQ<&"rԋPrfpn¹0'TL6Ĩ%OwFi[ΦGQ,,'tnിw.N漢Ow~ J9IYFąa>fsp8[ ~7oi# Ֆ;ZZQߎa)4rM%+5Cr.mnR?zοՏbx36Jwa=BD mg{뺺Y^jcdG9:7q濟t\R/?W pT"tm$x| :EϩwݗAquV_HZ@@ 3ÉJZ G)orl:bSáPks u:{oS(XKJJ/*Cț[ˋ] T$;o ɓv5z]7~&Ώ\rj  >w"ȁTO5*}'z_=. gu( GI97%6l9[6CIn[x.%ct: E;%;zI#MjwsK"urVo:5Jy qxk-p'X2U&Zt26JesǢNCB1,I0'!WjwO-ґ1DQGj"N3â>!o1o1o-/~[Dh]N~eEɍLJ̷sH=`PxJދ p/1;4e{%=e UW"SmW=Yo_X*y1~ݰԉ)R&ίcBcbz^ ֩P0ͮSedIjr#D]ҵޗO9yKqbCQlm-4, Y>,?۰{1vZ??9#46jCT RZ@^w̫~4R߿nԮpw'<AYisp'Xfzꞈ!)|QkkW~_Ʃ+~;_B=^D:NRЩMLAeJ(wύE!.WOp89\k91;:=ur -- _8io;=i~Cmb;8kN2й7d ɒv*\SX;'0"OK}܍v6~Yù]/—F<]$/^]gtPxpv5-6rN|*}n6p'>›^),zmB{sXGznz".}rXX>ry.$؝#='e<ӣ'20i@F`Q12:W 0Su</[5@Q1Ѯ+^6\MGk<~ &StDG+^G*1EEtCFz( ġkW!op'%/-pI:sÐT U W k/WS)Xqǽ9|*<:Y)j1BMP1PN t~_%O+~-x;-z*E:EmLSVA֓~x_Mcq7#5Ui3~v`anYn{ }nH=1rRo=z{THk@g~ I=ꮏ=ϧJuBZN /yCWbQ:%XsmRnZRf%nwUG}cwl*${$++ T2=J)ىBEvH﹟sǝ۷Kyy9\u>:Ac1L '%O=l|b'ZS &i߶hOޓf$R/O?p9|RuMMp2j7}xAyvL$@,7i ?66\XRE4YgKlOak/Pb%[i"a+vw闶D¨.^('C;AyBf[7.9%i,6!PapŢ/i{y/=KPJv؅z4kOb=YʺGc.| X@/6ҫ?lƉ\"KO?yx )p@O>XsnRl">^"n@ʍ:\v}P7K|5B ݫfQ@ >@^.`^vO+m(YUe WD0y%90݇N>i6:a*Elcd8q'Pb?xޝ|8E=KizSK~whkĴof^{SZ#cfmDHD0} !Ё{LLxLߝc ۮdp/蕴esTIqK}Jn$ؿ$2^'aQGf;ID'@ T3{ k ޞ ͼX{ݝM%\_v<&_I"s|t :ʀ!q2 7'ؼSN\NR0F' G,im/U03㈂)T SLCxGb\ _&ht骒>qͣYeՙvҵL"tAVLi~_Wod}nP#U;9ZeY'|;%`gܽG]X$_-6Z^A t]醉.2VeIc8ՠz^@/czy;#J33]u?B41vMJhlK3,H;Y@gZIŻ(J=рr@Ei vT]ntƢNWn~+wan 32iRi䦬m?_\l?݀ İtdT*tYVDYIJ<-;O 9bpډv|CiT˃;Ayk9a UYFE=҉u',^i {lfnת+ 8N5A Ā 8-NЩSc40c:/sO1W=7g ]$X|@_Gi\PKV3SӋq()X/!cm%p.hbdx\8r:Pv(^S-MS%YszhX+[R_#-"hÞ#4 ÷n[wrNlW疥z4Ůu;wDGtcpEa[qǍ3s1QmgO)Y^,GR084aN._7L] 8UEOCk;lmQG`pbqn]oQNT}pGq!m5Y[Q3wʥAc1T gZpne}E>D|hVzcnoc-Q/b|ZZʟ8('VX>{+WMU.8kJăI6xK@ xG[[B._xAK}9 OprWY9)TZǴ/unܔ*pQ~$ifZU͆~GZ|z@c#1q'eRV0kR:˽jiǽN{Vpyѽ߮{ $N@c17eI޵r6Y <;V^S瀟~r+mCW]ׇjv7^)P3qv hlkM EIwmsx7=O=Q]ȦHAC;i<3*N9)}tMv"2nYf?F75j_DJ*mh /ugw\:hl^a]Ʋjb\CW' <'8?Fw27Yr`p‰[ɺ'lW [/|m}QhRB_+{po2䦋 q&OwمeT~SD@ 6E_ /lH(/aMC~ |ĸ:>B$11 X*Cwe-=+{%H`uKǽ-^՟懲_+, f~a7;Ui(t܎Z_Yohq:F1>"f}MaYDy!βDw7 wlΛۜGl^6n;cqΰ!.ܙx)I]b'Ez&] ~~04Q?APJ|WEssNyDyV)o%2p4ċps 9[-Dp NQ|St,Л :_w:3ÈreU'A[yϷːs3yk3'p '6]ZfÏVuSJ~!xSC<5vȶ?d QStұ< "'z2`Կ8@? r~/z6I$NJф$E{M Urf}`$ᵞ؍@ àSf=K[8|Z{StrI E$$:}dPYb~FnR<<69p}7q]-A Sosq{-ܹؗqrb|)泏 qS c2VN)q*@Ω_x^ }Zs'X8Ï,Et'cTuKݩBp3^Ȇ{A2p6⠳Pz.3M?umdjgdcsQוϿ?#yDA*MG 4{EU` RQ'=8"9)o/Vǥ:5rYݟ`w>~k񀓌 :Y 3gĕ?e4y*b"3܀g|ża{y)<b8Huj gݤO_#8u#@,@m֧w5&&7vՍE*Ù8qZȻۆ>lV\|w`h^tJN `>طQ:[^hl? k@^w*5W+|ሲ`јQ*{z*fˌ,١}jqfy9s!L\5%znP͜ pC t d;2$ljU?7Rj٘B@A*tvփw W /z} ' 民Hy7>'j*ya~mMHӍ\YtP? yb߈Uq/^䟪pwC A2 !DPghIzKA N8t + Tq=u#9GBK7+>zdZ/]:xf 2\!ڕT`~ \n՗pD@gAy\AaEXc~G޽C/EE"Q SzXVEIh(U%F.e8>WSww`At 䐱 p7[GTYl^KoHymy7xy}8xReA×./&t{|d.jg w? %e}K!;Y[dɒ%d⣢HZ,eZ)Yv7{4wr*8gNN<<{\y&6qN/s7|Sa2c (s p%/ܿTMh{9QZovfbeSZHX^ۭp[q4t<]e@ -g=]gPق]7pg/凷XηiVIE]U l{`cbY^ л:h\?~Kt4*mwHCaCW3E/V2^" pkݷE_ypVc;Z-hf/zOÒb͙w럅X^W<&- =/?e~_S}TZ4{Bl!]2K; u6cꔿ/;fF J-^7rcP鄙^GBmc&j n^wn[U~׎PEm> 9O p'~O sBE%Ҫ%-Fio3$~q_}.f#&S;:#%]*s>uɛ/aԶWZCBz3!'9ZMJN8} gSh+_kй8¢z1MhD[;k'aS tsN+ xybPt_Ks"wY- #!*1 5k>}6:y o8s cJ|fw҄ھKĐ:UۉGQpVr=r|:L)6|f.:AC_bSv~FיDr{՞.x$)P }wsh}D01X6lSsx>d$}ǼӚ;]kSg݂߭9Zʉۿ,q/N1ڔ;=ejxK]0=*8̅;&a;rSNeNPnXw*ͷq[]Fqw)F!/ך/a9oIy7%AǕ;qǬ Wޯ̈΂L,MWʙ\W^0:%xR>F7 U< oUJ̈́2cwh#xp=o:.~8'[՟ ^7I |V> PۘyU:7 Hp?3zW3dl[HQ}09r!} p :#:q VlKbi&R `)tfAcl- đ1lip褭v#tI CMrw9o]߳0mzi+y>6U=b&gry?6abhkzNCh]tJϛΩ)QqoCȼg}I)gYv:M? RXK"]GS:ZP2{jlNP0$aϥ!bxDLj$;u:q џ>n6,A`lQUT5'Z?;ZA5Nrk3ur:˲4] ϬD^>'Uгǎ/SjG=|Pۘt11\jO#0cgVh OHz=8reBpͧg2ΟSXZ_|Ugc+L Đ8zNc9_+y1c廷KuOiM'(ɼ/cQuqΟ+2ZxS͍ڢOTP!@ ;N~ӄ'k?C+;}pz8O[GwDÚbæN~Zctv! 6:v,F *3&%kKb33umDnS;p|Pl p{ȧ<;|2_s$f%"=VoHw0)ȹ ]ƩR`6[4'x=gRx1,M#44#r<y;D /)kcݫekG-iY!'~`*!?~w,9Or,U2Vdje\yx  6 .s4?2f}P/|Ag"ӊzw>qE_^Kq?47d62U?;9K "x^ϥ^cGI4ن#rQc|?`2כ{1`b=# kT5q"۹PC#fWh udɇs-ͫ Nc" Yfh\jnHjr<ϡmA{!byz2^k[ke?'Pvs5sǵ.~wᩴ\{̏%\ʕ@aJIcO`X8eպß8sC~1چΥ̟4Yp twSV"zy55AM4OkeLyR{fwa j F Y߹n-@,A4ז$ ޿lx@s5j7w}Ӣ'FGPpDžE's>IqaK瑺rjz),an ݏ101ɹϫWn]f ǘw͡[.;yr !89.lu^S]1ߩ]NZ)?7a/am8Qsy=3Bjۈat&Ʉ9A'OS_YULE\ZKs,ĝv膭Ngd'S\ѓ:'ٌfw1NS<#HVt`IW-dd'G}%o]y|Oq#/Qy#WMٴ;t짰ͯ=z[Ys$@ @^yu;ˊB+~\X2YIuS? u@@ ȹD{sk`Nh5MXk:{䐟L,5bB@v>')'L;AgO<Σr\ql3Y֭ޒxV&Zr#8]\K9qǿ+9;5ztO>TwbsxaWEP|Z1)Zt*\oXluJz*7l̙:u"H 8㕀xFInL/XPfbۥj[1>b$L8X jsN"&-gbhCv2 A:FW]g1[rAm,:ߎ̈!dߩWAS)Cd])PuVQkQ[oa!krW @m!bX-8N,)n<'B3gҜ#mR% &:"YOSr\fi!'# =2cYˀ#Tс;=ȳdxeQ\)by)ǺY)O aǁ2N?OS' @ ?n/oa* |o.lzmsY'86&6Ns]s #QM(Jcy7^.ȷ[2SiZ ;l'ԏReK/g6 ko67s|j[Cp^&ըk5 #i r/4ȵE /t4rNO!Pae\? -a!yIώ!t69u+9:uy SoT_o2tk6kP 02.=&tU[ 8q?~StnOk|_m 79g]6_2ڎ%b>x>}|ĩ>6vI>~8X_cM]mݱϷSDp~.q׉,&^1#kHS;E8?jUK`4+\^5RJNB?{h'v(l1+Kkh@(._ Rrb.cLĠ8;νs0$,8h^mJ]c}m6u#N["Jo$Vd-[Y'DTZd'RBzX6{yf^F89{s}ws{-1Qڎ<.L^zR=J/]avxbud&q5΍H"!%C~BWkeMkE9Rx;d]ˏ{̑89eiy!;/'7rVU&322s6[Dۦ.*?Ul){5(6^pPtSëNIE㎒q1靕>76ZӦCNeZoosgbr)*>-zdŜmB7YBe@/Hg$:#8+iwFn)+ف%f_!x=1^z[nr3+_fٛa:ν@F58n>w-A0 zgIya=snxI.}BX(^-"γXlgdISŘky'^–KW20-lЋ%z-rAa 1b!wxm2svv{xVYG֒噂w2KES>NK) 2,^ъ&:q)A9gYc ^C|P}z땼YEVvS} 멿3x! 9)_= Ebs,WܻKvˁCg0P` 8Cs֎l4-ttZq$ȹ ũJ/>܉"5&T$=zVfهW5ކbK t$p@X_,L*Bnr{53#rG)M"N4K^WYϹ} o*- I,1dEcϳع5HNw2Kp%E/9cL < 6$>sz=Er8)ȗ#l{G}ijeғיUeò^͝'+~RCq/)PCS ɿw7ؙ? *s5Z'_N'ҽ.rJPeciϩ}|ԪطHk06 N}έ4eB1#1ߦvl99PD8N'z~08,wGHƎ$QP>9a3t2Xiצp+S-0ycJwțڒ3vGKO~?7PZ} љCz,yľz d O`f tP|YK -%ͽwOX}ُkO,"_yQ)_7&i uب›v'(&?x"Q1䀵~~i/l"}_s#E.;Ԝm:ͣ۝j9zhgOPt@-6&Y:֪2#]!6kQ]=y*]O} b5o=C]oy{sui3{wMSN܃Pۤ@1^/e#3Bwמ=Iὀ7z ȧD[t~OJ*˺K+!p[=-{m 3({!W̊E.ҧߟAg Q}9-PyClʙ&oP!JBY{;uvjχ 7We ݷWytT[+3fCCWI /K 5BMJnj\p\8ۇE~=|]\ƪB }.sk{GG?C1q/>IvʡawPcϽV"̨eqZ倩1w4=~gMxm-dW_۷_#8j6=R6FS(Fe\rO}$4b9︚H42&Z)|(7Dip"=~GaN X y+'ȁbe}H_4swOͩ q\ rmJJ7A_nxqArT+#KIH4/?vbƕkHg"Kp¿ :Kl >)x+[K|[rUfM Ӳ naz^:XX~~J?S & g*~w|.J-ZIK=9>SIč]f |s2)c>؄Mxy[*]eh(ϊ»UU $%^8׮r6H$vWފ6n㹬W~ VJg@i|D`}CqZdKx.~UY2A /|+~ F>a!?oy5wwyXC ,?ç$:(p+薟ʗ+:AwumY(&=0\z`&ŃS 9#Fļzcc5vzױk;0Xۧ:"'WMsq;>k#|;F퓊DRMG*(+)PW,%@vrps!ʬ/E{8'~r"~ 8ş}O/߯>-T4TȪSW/Ubΐeۅ>a1/:jnH:SkKV]RSU榵 .>zGw^^nF~uWڜ37zʢG3?#iWs&Xʣu% gE (VzNjν7S. s|"JD5GJ][Eoxs75cL<[`ڠd5$Й}Բm=e|a>de 8kO}csϦW=Z)W҆ mjќ{_?E\t4T@:AgUۅ҂86gw]&Tzq*e$|j4#b բ'8tToX#-ԦS[E =IO>/= G W /&N`CȞ{r6d؜?|-gc%߁Ϡ֣&N7 QJukJzm3zS3(I+e_`c$/>~ve֕-vmQ|{u@qspg;)Ei*0\j:[Á+.4Ї~ɾ񉿯DpY7fG(FCSЇqo~mao樇 p'xyhP\YWLK}y*E.s%dU *|UN2 P|'^=_f>|ԟ&t *i ̺ TJcGVB1l|W" gMrR\FGeRYVkD(m8oZD|} e0W6tnT_5ԯTxL@WH F"}Aߥ?yqq ,$(r`wGq|%of}%c6V2g51hĪ ~li&ʖ|u },GDt-| S'k=`~@vu>VmC\Enh)w|JyKoL8C ٢5i2s43([;r GƮM' =3kLp?{B|}[?϶eޘ~QGE7j[Y/)D5TN[ 3 tN1InԚcX\\}2KZLdT⿈@NvB o݉0-|]TXl#FMc(v p g"Kp󙅝^quno9t۵.O9+O9ݖ"cs=yw;D7\eP幼{Oa ͘@[BKZҦi+;onnW&܃>gl]rnl`xVח33 &6M>:T Kyw=}F u=2W!\"&vT+!UbPe>y-$ *''a}<"+^/:xhE4sXв6ʏt͠hʸNBR_3PLlv]a傾gicN[ڐTRUBR("`bf,QdY".[BREIY"}ygozz{yxf9_s=jrBGƃ-(Q5 ;׆U|0Xph2h3x+2'_9.W5wNQ*anwC7HK})۩V$ EF1:?VuQpJ^wƧG|ݓ/𺁄C|绛1C+) ,H}q)g/}^^IIB))*d1<7P8!a|(Q}S<vGZ=YUj(Tֵ@`R-߻cS㛺ZޔMu/݌mAnxpܝqi Nݿe./V7?H?_I MK}UzZװo WcKɭާ7/Cj&-B+e97L},IƱegPr)7Z)v,u*`%+tM)|?-QgrY2 .<'6r]qPpx\&H%8eշڃA5 y-us>XR_2nR9*yr@qz*}R7Mxykb1sLy?5mdB8أ-ƿu z/Z|Gܨg.P@ 6sG6) :mEIr%*M..9+tq6QEP~32'IG|ͱ=S,'+t O|3o'̯[08:AuS1JyaeƦ{sZ9#&pvϘNBNwg!q{֒3m'o ڕ:j`ƢG)x%J_A8f:3@n9 Wҩˇ'+؎^4.zv ~ K+'mOR'=c.}%ɠΤ"ڔI"FypZA݆P=@ LRg&ܿAȎCfM;G;)z9˹YZ dIܯ֓=O#Jgͧh}|F+R352Ixn55PJ!ue>V[Gh# Oc6]+;ry)Cܯ>"W.~5dɰsUV޽1ŹMXfK[[2hG_i.\ Y 8KOm7׌ W܇].,f|3~AC#>Z<1AZ˚* P+ emaz;v! D"[ ]V7q%G|.K߿l7mhߨ.Vlheg}_W!/Tr0;ȹ%!tb%yytng;xԣs()1 TU9*N.(yFP]&W[iLgGԂP@ O}Rg.󼄶`$qħ~u5f{I|qvME%3Xa==_F4r+%B 8:$Dxx07w;q?V4`ੁ„0HAJ|bPSšK !恊>>H>'4#X^GOPuW> R_>=&Fr]{'^pa>%åb.puUy(LɸO[[zODDQY6i(t`}]wc4N,J@erӂu|/I}oVǩ&T9Bw'Z?$ |7`SO SRX:yeۜ5 5F¯L{|{5fNjN=PߩzRg!T?Q|]KךTz8$v*N9FcKsq~"NYI0Fe{y}҈|0Ur8u(?$ڦ:|VٶK T-GEWXGmwN:ERg)KnOۇ]Dpc/Eք=u\;#ۺ{ B8 q֐~p%5;Ğnڞ5K ws,:qCJ4V%uHi/5{#o~ J;y8vQ\}͕ g7X_1.iz͝"DݰGvP9U|g>Sr([G֧pٝjR"kvJ{إz?ȏB>$_],F??/CY hwdłSይ1=q+C'qdiwiLW|,:.O$3Ce!:[cD~5`3qKN`J|;_knҎȶ1n1# \d.5c߉#8ywše6ؚv ⸒V1yx\~GY@y}Ӌݵncb̂i̗1l+\@W\N \޿AB̡b~skHir9? 贈KU ׯ9~ͲY(9eڙClrBD4.r9؛`\k;h{ilv{$T,o:=c>^T=)j;{!r0* tLhC0^ yadě4URx.ĕ|c3ع)@'a~B!,!s6NUP4P/JǣȔϽhxubB+ g_D#l-L&dؿ?_i:ʛ}dR5|lv¥GV¡:EXb@?a\ \ٜv5" Fޔ9s-!oW/~&MEa1FHK˟cpu;sEum|ܧɖ5C:m'>\1S_'s3T,Ϩp7Ey3ax΋A!m(#ELf4YymWS.{hggmaLeX(2o+ ==c!kJIeR[f*hzU$͂K|>B潌Ons&蝼JWf}UD{3{׀UǠ :o9۠uFA 3 ~OPt3#;pN|F0?Nw|7AXdԐa׻5;#3Z:ж;!V>UCy͟ljﻱcyYJS1%EʧR "E6=;*Ekx1YS[ Lz%E%zy% b&gU,>c=-BmZ>{l } dk-/dyI}](ԋQpZCA?y=wb  9 Ghw]g8E{S)!`t ܅<+]M8Hy '=\fx9k}Jʮ_C~CNOV[گ،=sWy}}F0BM zIAu~_+cO ֜`uT\ߏk3fiY(:_0#zh-9b?{$4`ډ%l[@[X1bX\e@زm+'lxo8a}#51@kT] 1?/\P_+Xo?Z커kIlOtn{+vH7+L.49E^ǍR3 E^2,r+;U[ʵxs Vj'p>%/B9qM k6umvjk.WLH22K**Cap߇ 3v;WpHZ窇;vn)ZkT]oeXM|N=R?vIO-sOO/q{BDgA Rh/=Ӈ1G(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 `"h nydus-snapshotter-0.13.4/pkg/filesystem/testdata/v6-bootstrap-chunk-pos-438272.tar.gz000066400000000000000000006245531453374237200302710ustar00rootroot00000000000000] ՙAd_yl& bU]TU?:*nGuˌQK܈r&.1s4:&qWWI߄~_}Wnuj)>8--ſ)Oy Ds"2ۍ 9cF\ ;Oe䷔D|folj7oL44GƿZ?}ܡ͑w4,So]d A~~Wnf%bhl$I}zK!ި&V0$f[7%M#ڒloޘxؿu jjjjjnWyi05#g_w_^sR*}-B-B-B-B-B-B-B-B-B-B-B-B-B-B-7ÿE"}ٶu=;\m#ހwQu#[ ̈́F|p儧p[ӵFs^"x᥀Te& Z«k>~5X,iٸ0;MOOfJ' ?]MYӰ^).\:& 4G﫛"tQs:k}R`s;Cr'CfP}'Jݐ,1L/wYSҗJGG;У>L_*cߓ2h]߲zߺȫ3Lss;—ιι݀ߤss&$mt΋p /w "Q"!wEutN[@xO/s>Oa ٓp;&|c\&r<&0<4_)Ŀo`d7Qtz?_s>sN&ܧH၀6 &cۄ@x!" L9 x&s?w9+? 뀷6N#8 ~|]{)\ i,шerzftbzn2ؚguᏣCae8ۙ9^,zP=1լ&LLQ mZ90۵BLfF#e6SHMi{%SUSNOimLn:zEeMZ u f'f^d隞6 µe32fJ@i WRlw99OL8MF3cj160EpCcl9-hgМȹ-kpmv+cҟqiFiŸfi3e:jNsMX&Z6v3q3)ˀnru/S R5ĸ7 ,4bFycCºzR F#^ \nGWq}ϭ{.asG)ՕgWذ{B?V?}+bY!e-g ͟~Eq>V3 `HHYs %|P_hDf =?_K}?,0 ~'ӟBC*Mֵ䟑Tfx?CZ>L?ʖE@(?Wa+\o7v 'DP ?wYw~H0`I(PUp`@7|_ eO0^ShvdM)Ogf\]~; f🽁-"LfOg` ~_1̾١~J0F;F?b}(ޟ}_‹ _a[d.=?X= ԗ[Of?on ~m߲f1X"̮z+ 2~Oq /lz}@NOç =رc7G+U U/dJWzq}? z'w0<׼?3T,;bpp.Xl.9\aÿ2piKOGcн1ְ ^$4vAeQO( ۘ}_;TEcJl\__Q_c+(.QQ):Lj+xV-?y{~de&>/5k hyⴂ&anr,;tL[7ݘ |8fxNL#ʧbxtV~X^P8`'HxD1eKTW`>v>*>U$9>Ӏ/$/&Hq74m#D ɂ &ds8 9teK-R&9Yth1ل Ւ37+gXz8$k+l2v.T =Wzfcq``'J~'x9$ ? NA}1f]"Xҟ!>П T _UOv*6*E~cٹQ6fK_iLEcLgw+7lEa%҇u?XQ=k~w L# 1lCF~»B؞acǼ"?tƮ YK0}]5>I‹ ҷ0w:1oe6KOG2e~So VʲKEPN`YinH/ ;3y g-y4 yK iV_|cA#a `v/!E*e_"ѿv2z#o>؟)#~]__aOcu t /`ǧ3,β:g[mU_G/' ˿?ʿb95q!}Ggp3c^Q^~^78[*qZp+QGg2g `gHY̮L /vs>~$OzϺO>zPkxfvU3?2U '%<ԋ#[]Ds8A+ IU,0Y+$|P/'qPv!X (ƩT>ٍx? |4ᄗR[4]"MGfg3#w1]~>/4P*>yX~x~bhdh|vsw@oq8VD> ϱI_ \ /X|s=b'>npzP=ϖQMsЦGOg]ݏvζlx'4߉V܈7MǿS?ь[p @y7XΕ U < ? },Kw_h?v?/B %|Px~{{x_a ]$1-U/ Vֿ߷>TGVRfW"`@˘]5`23*G{LgP fWDEWVK%|PAe]mĈe2_]>Ï Cc1wXD<2fꂞ.[w WL?㐡U~[/yyOBqf/yyOBg*^LoW/1>/&*޿ =W" cb|-OTԯX`^_ZDpٷ?7+T%|P+BX`WGwKF\KbށKz*_D ?$~>Qs}? _ֿRTͬzk+~gfWj /B~ex _ST/\Q.W_b=u{W8"9-sg憯9ؓ%"}G6+'ւ?cχ\L.+x~;F+H9ǮvAwTk%|P+ &EOwϏWObw w;?O6AQ/~ x'Nx_6ģn:MP8Dz[D4XIphZs ӶZң& (ZQ)ˋwΟOY ~u>+Zj><UkMJVwk%|P_9P*ۀ} eoV؞sa_׀ݥ'?/Wͱ o}/~|&(3zEOT/fqcG\BƳ?z165F? |>b8σ=Oϧ,c3;?x.}1'ᅪUdb u޿U~W~fW4+e/1? yE" FO/'4Gg0Л m˴AO 7Hŀ} XDnB8C0Ѵ Ӏ zf!e[YQ!'YOA}֒"scUAGQ~;uA}?*?)`^ R8 _A}_j~M}/~5*^jT-ͨ>oFU>jLۿs dc2qBizhO0Ie}1O2K;2} ؜Aļ:WpuѺ5 Z h-mf-ilfZ$6SOg>|&s_p~owe.`f2g%̷3_<|%k:*?7Ɉ_<y>^{A<6y ^e^xp py=y _̴-̴mw2͜W#/`e X4;↑ѐaLJǣe?\v OXeɐ,x'M0|wܧ|sw]2|!>~1?ld << >y0&A8\0CmpfG}G!^<<>H;'b׌e<|+n9?xr;}5IOS׀F,w2c [N 5\[NKr ?>i/c>s;*.{?c-u_3_ ^<:a ķ1; Gfݲ\| 7<3mp嶥#O̳M3  woɼ |*xM+mn8-:pwc7/>{}/b>4c>scW17k|"2 <#& sp|pP p`\̜1ÙGou;vgǸ^7O'+'?Oq#x~yx&N`8,JIt lEC馆DyI(DЌ XA+(ZF.أ=R˭/L$LC>xmX.ٕo"f:THCET%N B ?yK(nBӾay8l1 ;T#dq*fKgf*BMndսP,\fX`,nmq"Q|0ҀRK6JSL ' +V4+Eis0kl+dF RxX02 .r~q2+KvNbFÎmF#u{'崴lf`N) ME,i/&C)S'v! )L؅x4Hx2vˈd'Fґbr8sH&YMGʍRJ;A*֟Ѱ{#h^=PGNKFҴ3E}1t(ÃPR){(%uăM HEahzt' S8fB, }(Ye ǭx,nҙFYbF"n%D0I7HRX%; ~uM$b(2Xa0%SDΚt͜o4'u^3}YrAjU"g< ?Oѩyj?eCuhG+?J<៧dD)? :/_/gS&?jkq,Dwzo&^XS?E?m.h ro/f#z?~"h{":tFg}/~(H܀WL>I p}{o"E/#*u Ox?;5jDsNiͿu/eY㫕z539C? ^Y.ցÙO~s5Eo3J%hUlW[+[[4<;E䷾urj5 s,Ay3FI՟y:wvVD+}ZÿlwEPrUPh1Ҁ7,csҿu^!/xr*oOA_K?xsr#g +=:VD~i*6>྄I8Ge)s\h~Wu~#ޜ\~~|)U @#OotWO~ !HAMwHKxqo'ׇ!ZS GNqXʟaW?b {4G]?#0mDho3Oy_🬌O,?jwZTיH #hrA@h), Mk:w"8돊۪ d ՠ.s=*x߯ުG3~-ڶ'w?a*a93_Lv{CYoR??/(?jBl tk=WTP֏+wZR$@ï|YNwne<'ҟp zok?nA{pYO^lF,5z{M?i:W^( / }_eyCp~<u7 ÿIK  /|"k=:ۿo !5͔Et~oTņJWQD|\ + >DP>/_O?~oO_ < \}ASqW~-(Q__ x5\?Uk_!H@)C ~̣ JA\E_P_ï_%_//mgE *D(@% CO'*x>Q/ADNNeG7TUt}}5_Ao_ a:|6>Ci1P#|,~~Y:EX>? 5igǂu ?WX2!(?%[?i"4Vq }S?W;Jl_5:{eA]?k g׎NaJ?a9F`)k.A|ǟr7f=o?{xguwSpF|۽~[ >|/{Јl}f]#>||A|*?@#>j< ew}%i_%񹅭љGJVn AjϱY?FYm/ m,~k0ao~ 'iwrg֊0}&na޿HNǿY֌DF=Q7|b7@?Do>Jz TփnG=I Oz3oq z=@?N~tznB!NˈS ӫVB%>Ak8CFhj::|F}/@kۨ>#XfoG_b/$AA3edsmc@X&ZQc1SЏV=A iAg驠aS17rP\n;gP묬4[S6?!WSӰIX7 |F gɌ' ;XFGXAҿNuI&]גƹH -H㜨Med>&fB#譤N$ϙv|G@y# ߄'\i8m*yADU2 d(4Py:fa*+5v6 g Mkq|[t/б?M:߬fu^D?thrz4gbE.b D\W#*~mo#L- ȿSN߯12Rks݀mK̿?աl/S8x~Z^9i҉SwmeIgCOm?u*vC OSHOݔt)f+lt*OFȅF<02‘@${߃SP@Q sqa>f 7Y-Mta=|cUiʧbw6֔R}̲v|{h3rF)g̐i'4  [O#zh|'?NTc?/]9"Ҟ)ySYl# Z4iя4Az7pH:fHBqqaqw!=I6xpnq>1yÆBܢC 9UT;0vȰŹc@;tЂ=6g~{ O).57ܑ~jڞz%T AEA/n+n{QR_Z UeB\k,~7h0 Q?_j`?,iod_{?b 'p,w$? O#`i?Ӎ^ϯCgc,7k2p9~D۸뉌&FƮb?mjSE%ֳe󟵠^}Τq]{@_BIc4ϫ!>H`m.wU5Is4,6>cw_i>y.7oU>#II/Qxϧ:u#W_(*[X|un_o_u {EKQ7mֻT M6$6JMJV $=HϷY{pK@(#I=4JX۴ JT>OGM^,F6|]C^#?b6ib5E_% wP?k?osş*}l}~FП~'TM|ңI0/R)KGNcs&X-oOU/qW b-*?i|$=tX3U,/*[ctw50_#_4~־V7]G4G?1AP>jfߵ{:ߧo:cT#~;i9NO%b)V@0.ҏB[C^@- c}E?5$DNzMiv*؍>s۔5F%fׯwo?&|?1A94MA??G ?uڷ?W J/  ?QUMKW$_~RIďy* Ucwf77  {>I3~vG_dׯ/5W~W=d͋OϏOm0~4寊﫵Ww;qD}S̿[k TѿL4=Ek +@#4 t ۍ*7ސJQ˝x=Џw$h\4J9CoB ˿߷_F՗͟]4G[΀{_'R:_("?`{; v;_قo;~1KFAbHGa&~ҝe7$-4zJ";]Y]SS m9z:!1qdGBaw]==0^| i W$ OUKҏ$_CAO LjiovosBМ.3icٿDW} >F|T YO7ePj}8*fsA0|6On??r t>(ԏ؝wF/'|qZ`v+Yn?Gjy%?6/=l}a%eA _PuvRo՟? Uh2?_SrU~W-!?V3\GLE?mBPg~ϖuӷbox}l Itz+ٞreuZX.5WpFW1I珛9u!o1MA&M2AӇU?K)mʴ m ~ښa)85%"y6saΊv|s(l]{?*?kcmscTO]&q|>]/|=g3r{󁶠tOjl*٠gettKbef&= tHWAz{s@_@اE 2g]IBŤ5ȴ!ݤAH!}K!tG>H IWAz?>NI? N+!ݭ|2[!} 齐#;+I7la n0VM#_jC`!8O m@z}!HoHz&7&} 7! F HoNeHoAmHoE#ЭIo}ڒ>Hki@F[CZYs! BHN{IχH?W@ !r_BP !tӓ3mH}rm,鎐>tHlt ^J 5%=m?B)H! ҧ^I3I ד> z.?ay*/gn%ݦqvҝ!.~a~?I,$Eg~ݠ$(%~ZHz3/%җ8;8)ϊ}DRPnAuCfgaكY.ò;,+{+ %h01j<1hmA*FE j<5tjq!lOR`{}B\1o'n@ #~'Z+\7!~}"ށw"~?!`C lB< 9|l_W"[:W$܏jl;B ?[_wE8qaIģM%^LR|x."C~ *zğNg߁0_J9 3'6Ɏd-H%ޖFzʀZ\v:ۗ'oGJU1mfbZR>6=]$9Kz #n۴݌^ш6 ַ7ln\-MJʸȺHkg9]ĸECr[F(gǖHhaJkw. dYY å흭u EZ&0ӚI&.GF{+~pt\ImbhBwcSG=!|J(t)hC!3ʈ\޴"h]S6d"M .'Vkq "ܸUdwGG{Qf˅g,  -֋WernMv'ؚh6S 1Z&)5M{3@D'5tw&IQE[m9.2-)Ok.)ڒx#27%`eKJIJDc:NfY2jF:[e*aak@8ڜlPpa_RؖhL2FiJu4"v.U  n %hўl^R#ɥDveF΄XS֭dA'Ale\ ZRh"ZnT}Ql qaLo%$.qvN ӕO9Y ?é̉7.a]hXo 3S8@i EET%nk.#&x4ՖO/< 5Q`[k׾4/ԋef:_v9>]C?_cwEgi3YCC_~Ac~uz#5 =?h7#{/o3_V>p0ky29?D h iسKo[i-tBU a}yߙy[?Pa^M\x5 wx'>'쟇X[/~^Pߣ4|w!K_spDu13_#Oy7)#]O)?Zo*矴{ty}W:zP?؂?Eצ5OQ5Y6e~w z8?AONu~?|32for@mCU9/V/,WW?ez[>c}Y?w]࿧l.w75o.?Y?G([-`{QO?FC eg̑1|\_-WcgzXzz? חc5}|靖B8W2@u 5?h| W}~/sCN7 S3 qGYb| ~Y,o?POR{x~xeo#{ J6;EC ?ٞ#!`TE 9G&/4τ^GY'*_: _?|9I lgx>O13I~3'/o35wlΚWj<5*#]-3/~_޿ ~_X~~K)zss:Y/cqh藉n,|$;uze/-W[~MGGC?a Nf~iφv _?vsW7m4O hWFx'#>r'AC?uҿ\{^$moQ4D|$/foX't j/3NϗrC}xL _YR~Ez_l?4yb}*xTGYSbeO%ۻ:I;vcV*%w-"Ǻ W]ʎ[v('7xY8W56-Y#J5Qu/|Me1X{7_~4%)^{ qx-T^/oץDg+XoK$Bs5ĸG52?(?-RO?_[('pkj)-%^n& B|#p'ě+_&~| ğ/'.8x(Jko H|R-ĝۈ/I|%x -? 6w!~_?ME "NA߀?:i[! %>O-x lCGG<| dhb;Xbx<@\L\F|xqQGf_7O!"% #8FnGL׍D.eWKc;=*j);~3rSǗ@;UvP] [(T$;n^TN';w9q7H?~nCEvJc19X^V[RRaQUpIU64"Qh2BXGDbrSEšjhIؤ& gmv}~TTv/WŚv!>"!s q9#^G B௉UˈׂH| W 1#-z'A|3_xc& ~{?7&n?F,{x=)⟀7B|/x+ς_ I*7~qA(wQS=W?'^>L-EX>zp?!x8ρGK|X/L .%N#p^\G,[@|?l? 'n$5G>XA8I<`HU ,:RUċ?"n_G)Jψ/j/o:.p%~ |?V;~ > +q3ryyy~bUN,/|ĝwW'!5oF| &W|̂!~!~|bC~{ağ&x$qa1_ >x4x 3S]gO".۹ v/Ӹ_|&.!Vp%~#~]O}$FT8ZwNO$l4v(\ C1{q=a!{i,WU_7"`ITMD(L.أi?kD(A7#Q#QeHBfʐ=62gNDtԅS]^4#XcJ&0ʊaՌ [R][ UCPqIB5FUGcqg ؍"KÑXC~{bפN) ULq<X]mE$ZnU:JdŠz$q4BFNc)Ȅe[GR$p-R#qJ[x$$S/ IzJTJTJTI>'O*\~nE9w!\.8e3+`p2Vފe.xL :$zusA: ./7 px\:.gyǂ\FB^4%"+W who?M~ߦTC? ~~h/9yi诀~r oo_5[5/mZS]C"п4пWjwj_ k'5@]k~AvMC}ep:* BVɅf h__`)L5 ?g>rUkAK5Pv'MT]KYDdyQQMeEZhK!-iچIHˢ,. );‹"(9ə̭&M_L&ɝ;3cw8N]:g' 'L>? x=O䧂d??\#?g>>П/?g@/$_^y VgRs%sy?󀿂?|_ǟ[AE_MN_kJג:b_߿@ o_7/ 7n_/n_n_n_ n_y|7 u֊r mW w_7NˀF &>_̀:I~gDwo['L$߯o36_7_9_]6:jMn?J~{cA[@M?[@?----6[@-?-?-O??-?m?q6s6//?OYkoiAc??AAS?۠As۠۠%۠_m? mm??s6p6 rv0Q۠=_m? s6_?+ܿ ?ܿ *ooOoπ7o/AW*]*~)AG+]__L D |~~y5@LU+~%˂K˯L͠_ o! G~kh~iJ~mjet|e:-4ƇM&:?Uk/O _dWvWZJ_|W:|пЯ! U'c@Vo߀Etp\?n~-oD"Я ߘ o_@GVп𛒿fߜ:~ ]ߒ!O` 7?~+σߚې+7CMc~3oO~9oȯ-a~KH~Mп;_ ~+@5w%%[c[^WXvG~ _=F{Fas%JGO >@3$ wD,'? \>~2cG(ckە qߛ:~- _GTVϛwԚO4B~K~A q~.r.U8'8WߺL[;-asGgkA2C}xҬ'P_?^jBoR؟n ԧ[hr"?~W/qƼ{JnE9Yr༸96^Öc%EpϿ16b~KOV7X7|n>ŗ<-ѢؙӃ?!W-_i|ݯ,H7:wZk@\,(L/ew_Vig,\EoR_0?H&fD9(|$i8|߉y)O6 HcM!2[2=ϕΗ]|@2;RZ0_%LKV}e5n|Kr4PW,BvՒy:m?@HnCy܇H^߇ >)t2ǶJ~vvʻ$W(%O>ZR>,W~Lb#y5J~)(|'eO<._IN0H9'/w%I 㾅7by#8BaHOjt"-D|n_z=>g\ӤnvNm &tw=^-/;WB/bItSzYM cq9{M7T54/6L;nK/ N \ws_4X?yn~{+맳kیn4?h|>jk7}+ka? hK~?74*M/׸%h568o-Vï_t~ʛ 7~ Rtw;?LJj,˴5lWBu_41ULCy~i'2}ȿW/= r|7W4|gM?5^鼿+?g5Q>/Ꮼlo5)L/Da /S^#87iH/~LhA~E ߘgH>1qߣ+!Q7?2Nk s#WVy}{7b~YTmMW{,B}~Ǖl34W%)Gz2rEɣe%%OM-(\֟bgsa@C7\گ}"~cnx}P?OXkk$ۯ4f)?ǧhK?˯}n >e_g.4zwT&R}mUWS?5ח tE-`}ՎP_<~7{c5[g֯F?K/rcj*k<'Qn-y&_ !KN>G- uGh e8 hԾ5/50?x YJ~ OSZg'j'1ـ >r_?w2yu\HF9Nr!!9.5%.ҒAFYQ5ڷn_ӟɷjKʚ\i4?<HhR$?|zyVLgP}?3|C:o7/o`MR^/ T gSoF}~ToNɉ]Slsa+|VKUsG+{c, i6ɒR.E%/\2$Eʻ$o|@fG% ~QOh_'T4oSpk_sݠc|m 3zL~;М5<-[79B}O/8hqkx PF}MF}Y$wlоǟ<X t6z}_K@Ώо /jnw_EI54xw#о/RhfJ}ˀGhK~c>Gos}P}g9Pߦ2о_c3׷oWO"~c{T׀xfZ+;CSxѨee@}KxL/~[ w4B}Nj ;8?J/ùׁR}oig{"n c\?O> gql\ץz\P?[5qtth^PUrRQᔯHnKݖu1|dxe%'Q./9rE)"9%,9r (.rɣ(ד<+ P2|&$9N[Ja>(ϝF2gd>ÒK%8%{HcK'IȦH1V||ʾXt$[&q5D2(K8rğ%nɼ/0ɼ߭_rohu"7/LuǿbXZBCǕAW-1|wvѝb \YWy|p=o!yZg84w%wc座M1E@2yLf2.R>W3`ٴt1+4/W׏>>1ϼ4yN `}f0!?m|?\+v ^f5 JN_IOwv2]< wm p ue_C~}k/O~euSzM17?K3s4:_&MY DÿW_T|n_9~L r_'?t-oV~Ś?m+wNvToX戀 RYON%ß?x?H9mL!χ4s#}k(Ӏ&5/&ǀN?V>_}o* ? y_MM~xay|z|ޏ?C_/ߢ|~8 ׀7+KH 9Fk1%F1&m=7[X?-J|^h?I@$ƒRJE9V=%ϣG|$/䥔$얼rGIDy͔7H{()y?ÒR>!05(JOPU)u$v)(w|DWEH'/S>+*?/Er2QK.G9JKr9ɕ)W|ΒR|'yP>"{NC%7<^rs$֔HnGN/Jxѷs2媒S(_܇#.Q Q6C(gKΠ.R?&o\3g+D$o]." ?W> >K~FS/UKD2RH峷(-D>_9??;Ǿ?!wؾN4??)'G hяlcL:+0LnkC|ܣ"2Fa^G)g_c~ܐMp#w2n /-w` >T~ 7oЃp.O)rbO+7L}7(>? ?G%C5ha*!{_!sv{4C|k%Gyc|{2C|OP7_#1=ߋ ^4!W21b k^Rw1!>3H'nH6wۙ?%x'7b Ou<3SMcTHid@vgC4y; Aأ"Bo8B-,rT*ub2^V61f F f'DŸ/O?7#?i7--[)?? MyoVrQ; |%p|rW>6.qߑ=c|k!Mo!1wp^O7 mQ:!>wDpk^>j< ܁y&38t69fz\{Ei@3 6oՌmP,Dlh?6n{-3l/Q1}b#5^_oc|a!Sc|Yf1k\C|g_-C|?2GF1'cOf^ >yxũ|*tV#&9OKt:^STG7%;bNjBΌYڿ 6,_+?? [bv 7 4B?o_7j?wr1>Zp_˼1Nc/b^>ae2?E̯b~ob| ۙb|;7aKcen^4gݶ) -/33S6sZ}Ӝi ܕ}-3 =%q>ni :]}k -C_C14kqxdz+ u= w5_lwK \T\j^fi7Ӵ+ ?<?$*'*KMW[#O\c? +.7{Rԟ5WDl_'UPJQ7_K_n0O8? : [|d_W$gz # g7Pj/wf?AQ~n7?L`); !..(&}e? by?=(=EkŸ-?-zc8t9ܾؾux!шYA07V!8Q| }!̭SWu}AC|z50S~7 527Q!8O54{2amS) M@|- 2'?)nP9ϐ?p/bѾ!&"ZTv 9ﺊ4x9@澩XNoqx"%b|??joS. cdUwcFu2.f.a<b2303G d^>lKK/_|%b1 1.Lc377Tλ<~E%4wg7gI7gIw3ӧ=%=%=xI>{:{94˧[^jzOYC*F^Py_is fo%/?M_ > 8>b?PNU?`\?T+haGiX_\~?^"?Q?d'lo6O51?M.O5?CE3?S#{[_OG gXc 9=/\LP8ΣcD W&Dg|G_פ@< D-;WPr~ +rV!~, ៥o?2πD?TcLK_E_@%S,g+g)r9~9bC P?/o3_q|a?_2_ǃ?}?\7lc<hWL|.x7?ߢm`/C4fu_7`>3o7f ܄;p3YtO{sT~s%1o)V ' -*㑰7/iiƞiv. ENdYiO[N:c1p$:A#eEԑ3;8GΘ7MB"sAu?pqm|e(|G d~~9v1_?o O( 'Å;"(r~o_ \_֟v?O K/WG2+9 H/T_ +?]e_ 1~WjT U¿_Y -g+s~y? _*K _}UwQcqC۽O}gp7^ nb<}]LLGvo wŸ/ {B+~y ʘ U_?\_[߭,Thj>U?(/%9erfd!s|&\O<f>{(hȟ?ThG/M GA_"D IXlf??B7})/[`k_|Z70`{m*w0W2u)߽n-J.kM?^;ow)~s$+':VGGNK)Ueߧח27Jӭ g_? 8~5!_hg "6_}oo H;/?U?;_tT*WAfFSi[rr~N1P'C|!T!6g}c|9WgC|ߓ)C m8*/ĭ"U3LJ.XC|#uWѿWԯ3߀}5!eȿ"7FUlC|o"O-_U0)򯁨u16PM|bFWT*3ߞ ȿ$_ی&>|5~7xnȿZ<.r~0O倀s *w^Us}iQ7.*n{7jw7߇jǴ0x}][xyY>ǂOd <7x0s?0c'3OOb2Og.d`?|p)2%0Ә/'2|;tE̫0?^x __¼|9૘/g|=woa{L{z3Gq3ݳAf#tǙ$k@3 о}||j{zyx-4c ?c__2X2xL doe[{4SΐZz8Еݗ8\g3j.Rͥ35Roܙθ\g\mL/f7>0sin =f>/3_E㗙i~B{i24~:y#_f~/3=T'2{h2sZYS>p%a& 0M381Xpr$܂41cb0M]7>8SL$vS.w4/^E.P(_c 1d$]+Rn(G6R^j7[Ÿ'7U/4`H+Ukk3 6P/2?X2R' ?R"7?[. ls~9>B?. 4Wb+ ib^bŸg߷2~c>"RC|y/_v:?)Rcnp̭C#UIU 4,_|/eyp<7K #DcG T?Gi☌UmO>O7E~N nwW 0CSs b R?î6{[s|1o*Ek >? QDO:I^ ǧǧbt!@c|m ݘ![(M  E|9_;C|sEڵ'x9iVn=.Ӽ̫i^_)ڼ6_[[?ȼ 473́[}Ladnxs+n?qx/spR\y(̓O7a1͙ܖQ?\Bh cԪ6?$n?B v^H_Bfwo&U q>3}Hpoy o¹E T伄ed#S32 c>jB(}AS\^^^S°}1X+7 -!C~ٿV~9m@+ G(0#~y; !2 VO0(+n8c5/#g?k/g/7Yeo/7?`/ۏ4?Ee>\|4ͼbey ̏0? .gy 2>-4w4wR0edмiZ4+3Wp3sKg ܙ?dΥiO9ܘ|e#k*PtBtCҲ8D[F,,unaP&26PevYs(nJ- s^BtTRF9r _ lU3*r Cy/?7 lφ?UewW 1f7a `Q~49 R4O/eٷ 8 }~7 +r 5"1PW5¿J{*/3֟5/rW({bT%_e̟ KZw?|d_rcl_ b_ u.*7~5cf_6/~7J/a_-ß j1!f{C|9!"x9݇ hppw橩wUs ^{5=4t4̳0G3/en] , ς_f~V;o3\v}m3?c>%to/G0=~c>{ż/,>\y>o~n0 >(9C>l1dn\n|=B1KSCzC3>?ωGM(YRrF4bxK Lļɸ?zfyb[.#2m H{~2"Ix\/ ~` H+p_)YKd߆(J#!qf(pq}q4.ꏅ*R[DbnԱH"mH$q3 %cD})Wnmܟ8-Ixݷ`еڋ'.3xA" '!73Iq7upM ^qx(ʹޘ sK~7/yRGsCzpwo*K{G߬9~L[Ot4*CGL'oe?om? nr?뷭< ȟv U I6_#7_ A":&Kc W?˜? okw67?~3ߠQgoŸoL=ҕimO0OW\3Íghc w`w3߃Iƿ 4ʘc{10N0? Q?kJˍD3ldNk5#/0?WԿ`Mv>^m_/5C.>oSC-e#oR?G ?[l({^=#9yԩ76_` 3{t_( 'ds/\毸PUğ OH/'`8ZV~"n5onZ(OO%gUjrNEǧS*oj]U"!ߧeoQVfey}eh] 0 OYm|[srWV?\$^~x*t "LEׂ3߀mϼ˃̷+SZa_0YG yq|/񘯊ԧ Eck[)GT7<7I?7Z?4/ hHJ ~ d8BJ Hτ _Uw(?9.C_0C|ъ̸U&_T|75w!LW_԰~h*0;Y7Mmfu~oq1]w_rU:S M5韻~4ŷI|FMyW7}|Z˩Z9= [ԆCc<#f:gpG@++?;k<1| gC/,Hǽ6Nt[f < ܐp#Ys0 #/wb܆w;288)pW=!p6I;w=~}XVX>#x2s̽3 2Gg1O%sc^N2/c*7bayk3o_9RWW0o_1Z70^߿V,M+|4~1e^<s- 1_~&+̷72 xw_oqa7c'[3Ƽ+w27j`.0w 7+e n<? pc&Ip3͙g|$5 {Z3_W;0ļS(p:[B}BEY&^,+}ޗi~$w>+I_iI-!_z%1_4:חN= WhgJ1@OYqV(~S[I=? ?6оJ!xԴ!?+it'k/g3ji)/c4wQšKS]9 !R_%/27~ui;ߨmt~XlH?U2?tfYK^Ԯo?J>)T?`/Uh1~oWn*b4i#M3de)g֭ ~oG ,5xD ~_o J&9>_vW g KԯjS+iץ66M_& r1`G3G*Xn8>6¿RA_#swJ?,4?zO!Q|.2f φk͟פ_ kc?WsWUņAH4ES?oP οM_?9?~yo e!co jhP./mO_EF Z Obߪ/(H/[vyoK?l_b^fm ? s+ 4+ t~z?_e EO6;ƮۯVCk( o_]kwK^gSSWP? e_ϛ  D~GV;ӔQo6Og)֦X*;:??T*6? g\8 9.i~YS/i(]W/_my.h/+ σQnCχ'P:8Pÿ^SXgSW5~1~y4G7^o0_vaza7;߇C 峋?ID`?%JT!z*,C#{ +}Q6QKƝU?V ROpEՖ}[/]6O*&Em!E{OI4~>X'Q?Y/oQ?e /uӆgai: á+/W_?+~׻Zp+F>H cqf<- iK7V<^6hf{:T,?M_5?ikRִ!oVMwf_]/e<p9 ρoM0o/bn~tc>wT?19V-σ ۧ1)> ܲ3s{>s'T>V< ̅\_ğ]Ӛ~O;_C?T}7I| 9t7b9wɉt"{S_!>wX/͏p yH2p0?ͼb~erę_a őDm10*O-b4o؟+ p֬lgPH,;e;m{Z??dQǧR,4I2Xy!W It\/ݺi\TVڿ{'Ր?-*Wod XJPn*SO~7OҊ~OK 'Uh~3󑪳OJKRtTT>7D1_NC(7 :N3ԯ:.p|]5]tҿkX4C^ܼNg3ͭsǂ_q x#sOnob~y(ؽ7H̓0Rsw1oc93|&x'O9xUwZ|.\ip3n Vp3O͙g>Gpk]v;0gEen>p|"sp?̽inXi H1㙽I~T4)s<\ļg2ӽ˘龹afGit3i.3h>u{Ng1\0ӼKie4Dž4%4rfui 35uL}Doax3S=tz닮2u^Li7FXb|H/\,%eq/Eø}ބV Lu<‰Y*ƲW&J:7#aPpys wtyqA3 d0<B#qD!Np~1k)E6ԿR-_৹)4>5ԟH3Sc=RH?Oml{)W_F"A>/G }"0 S"4i~[ 4OR71cB.M 8.bl'Oof'/T7bӜeby? ȟ<__"'- rߩ?fχD7?TL# ӔO- i&Gg?BU2τ%/Zwok,GkO?+'5ϡq b3?N?? ]_Bb? ~_J+D1?YC;6?w6/¿SXBOV"?MI? 71i> /w1/ ࿌*+'SC%~/7W_w3ߧ9~?CY b2 o_i5~ͽ6|"-n"} "g+W2P? /d?J D"UYhi l`LsR?h\_/ ;O(׊lӽ( n9 4 bf<4I&?# 7i( ~?B?? ??s;CI.Wwj ߆_2B 72nT9o4AC VxNO=}Ѫ'q)Ɗ<`A?c@ݼ~R6/㫶+v^gN'kgf@nE|g/X^;pe>܀?s67f7anܜyH~ERv^N~D PX5;7AFǯnj\zʣ|z,K=:#k9#e]?{ZXg+6O~!?S ~y # 4>Yq~*i&5p DMst: _ȟ3 _Ns%hȬHtg"j? ei_GοVG!G԰w3=QVϭ%iO_RO?ĝxTƗT)"/@B*D"R$-$@ HQ EAADTE^Df;/랙3y¾{ؼ;o̙3߿?Y3op>7Q\5}ߏt8@u<֙k'z74#+)7WQ#\CqL Rj~ R5?!-[_4 M5ų=Y(|zxP~*?lFT5e{}lߨEK'(7HLMFl ~jԿ|OO>΅_HZ>#c< >]\zJ?=5!G,zn=|G Z;oKVcY5Y?@\/D=LJJOrNMNq=6P?} S=i;?Y_w~o9EcrPs g{~/kk055\:}F)^?4*8_Yؑ ןit"y׍3C& VA3B&k'XI_wp~49daTZs|m-Ozzv'g[qC4+Y <;Ia]twuHc݄mHF:u_XǑzG^)ҫX!]8Ɨ[ :Z҇YH/>@wGI=xOUXI:uXŽ֥Ib]tW֕Ia]tX%=uSSXw =u7 Y uY"u齬3Hb=IcH_`=usI=qO7 IMZ|mΖ6r:+b+J,{dWr^rӕJr ̊Kwbz Wp&''s07ĻVD1bƿw\BbcO+23WňHgvGftyLE50S9oㇺgMmJ/".wG?JpE{^LGŗde{޸ȴF*%+yә$R)>%Ra(G Xs={ϧ7f7W|q 317t7Iw2"ȴTKۭsG>5}W?Y&f;c"zR/Hwp]|ۙ()qAW'm,/۝.X[xķĻ3#n="ە[I=Ď^&ngҍ{R?7)^77-\ͫCH_b)ƇSKL&j|'{+|KYI+΁K|) |F;*}/cwq"ޤ~̼,a)7  /1 ըD5ϟ8"XR? %H E[[Ƨl )o&|okQ֡]^^ҧz>wE |Tߓ4V Fo |#њ5C@TϿ+|w0*x>˯WGMOvռ;qQjcVk?.~:9_){4^|>ռ|?.֡=j|*_J eAw*kW 5|XtOkgY_Zc}W,O @G<:*rجҷ֧c׉o&ia_c^m ߟ(YR~p)-_{W|U5* oO+@cJ?(Z>3e$߀Պ34":O`ak??ybPBY{ɞ,("cK_Fh_TUK0N oWw^| mLv]lໍ\/_g[o3 |] /rVoY~) M6M7"o_F7%?V4JKM Lm;ւ3R{ |O@[-;h||uvu ;Z~߿.7|Կ wDWh fW&lMK {Mm6zkU(~-muS&ew&|C|ʆį⭟ 8==E9{ڄ9(m(͡~qR O:ɿ&|m{w')OGZ۳߿3BZ?T#|Kq`F+?k bLbwI֏: R>|+Ώp;B} OcK?a_yl*dE{z'ZZu:Ѩ:!?U;ٸS>~콾x :gܤ{ HIEy4l =kPY~zd?Ғ A7"|C6#YˌO`Y'CP~0W@>&oA*]ۧh?W7oU Oj`e|+` |a~[}/ ?I*;S5ow l/aESGw~o'k}>7)6= BȟXboFix>dmM;K5o|6 4:>g?\i[i} Q|&?>IOԿqiۅ~s|Ǚ} NwğVη?ߚPăGS|3|Wy Msm MM?7|+7.o3Cϲ";CyЀgk]|(.3 ]a_ܿwDC8>\ZPw >awCH_ n_S̟oD;W| )o0 fu?FK_c9 -~4_7EMw=]ńgw |{CD:"Vʷ)?9.Bߌ.Umw=`BpfbלQY!2H{wa6}._|͖pɓRVXeS&|s67[_wf VmCK5n|/|7Go[&}EwƄHkoy׷v5o &қ 3|o_P~G@)W,]GWUM w V7pqב_y7G?+| w5' Ǥ]io9ȿuR0[ֳo[/_ߺP, c7voWC Mosnc!cEIv߲7fHv'5~|Rme·=d py_a۵?ՄoPX D~xȿI?ⷄ2B5 [;c=LKX=??|:얯I|޵ ǒ: GQ b~b~ F &0Go~AF} O@wQo&o$ ]01Ǒ6\kFCtߚas?љ?3|oby?W|vukO71ɆE@Q~oP_SLꯙp}>aYm/A};ڷF%>:ǧo._S$jՏBg ԏl8~{|MB>K߇߷P>+;F_Y7X+Y+kY۱~_Y9ࣚǽψ2C=p?o~?9ߦx>k-%|}(_MMPoK`3VR}~ w/_o׌f!KhB / ?T7wBۆ#_ڮ"{"RL@]VKڤihܤD‚ʂ"+(b]Ape'hQ`*]I{&_9;ܙs7[.o~.;~ڕ黖V?﷑>5ctq K&2G?޳oI|?Ðρl4F| 7⿇K4ƿ&-!??.7NXK=0>[o/͊ 6=jߓ_` `he%iwkR52?5y8+';E߳b|7)ʇ֗X3}!om z.gx1_+?f1~@ 5Ev~^$yN/7K /i?43 2?AF~N 7/ {ķW7̕6 .w򅂑<#D#%.?+?jYR WZHw8J#w?NfE*YJ\yX理{uC5 ~/agFtE6b@/T,E“W C)FV,}1}i@~ɏ^`aQ*5yYEj&'g~/oji`=&3:ئTϪ/> mKZ?S*}vBߵоH5ľX |*֗XGTIwI<*ּ?I^ Gaa/ר^^O?h7T 6d+?2sI~H8 =f_ϱhOw#F(ƗMѾ {ϨwfоfwMٕD&|aBY۵K1)]Sڧtjy)Ac%P.#s(j%_BۭNv>?Oϧ^=(2K %DŽY%>M%˵Đj .Κ̬FH ]n*MN%vu#" yx? o#_%U+ۀ7'[K5Ou4)ʿ_V@B>{E{ů=?u;5]}|#{43'}57@}5S/b\ 彫7 T ;?d5X-h~voWH?0Iߠ[&4WͯWv^m2}&`,:2cwW}_\jF6~mR6Lގ/%]Ӫ KRBB~ 36'UX[\/ױ51|&q:/$!G≄K$Jxď>(L‡$CL' KQ_ |\$j§$~p>-ҧ{ %qWn$qzIK| %nJ_Am7E] AiYj0/\[#,J7p==tb1S(3ľt'KJ'ߗ2:`!>>eCb?{@???[Aq}8Ւ=k?wG)4}~)tw/A_ Bowj}\07Liw33 k෻?,_ĿT0߶$KLj "l8/? nb J?A_- os"?q|+?'P'a-?:ˀ|fkK'w$Uv/W >%/ט?SIE[z՜J -W#~9pkh_E}yX NWPھ}&zK~7)GHp$p;O3%R Jz$Yox.pć77p3#Vr$>BWⓄ%pħϔ7 $&Z݀>űI|CXs #GW/ H/$|M_-ńHܔpė"S%nNxWNZ$nE@6J|#\(zo$Aw"K.K%F=o[ԯ:?p7ݗnd37d3C>/'+x;;;;7;sCF = 4uim!#? ")Yi?w[Z7 ?.?Ckֿu-ckӨmPh?<~rg/~?~)o ۝JIlrˈ23Qu_#M; >~W#~h1s}w=þq` 0?~dG}>ю>h?v7$ ?I~ZV_mH,ַ%sF,ň/+`_o C|7Nq Wg{ ,??&9?*D'}3MQq_ѿ ? ##~gc;%> 7w!(vfo@s1>[ ax~7~/~K-& wM;U`f`з] ~oJp}:woO5w#}߁\~eo6}X8O}m6[#~N}i͌q\*{&%` [975o?'-- }O)Le[ao<7 /q<J?1WC[࿕% }%P_:U[Ơo8{#vfUBߦ`}X_mfUo8;Uo3M}ogmr 7 򷭉.з}w8Co[з}G$@_uI'ǚup3jhN{B}wd#@ȟAqΟ3fb;u Οf?#hGBYc?nO^F!hw @߱ Οm?AsÿAh?k8oZFTȟ88z*O~S?_կXb:7#> >!>1>D ߀3Mc68Ƈ_ΆQ_\w&;߁{.C&.}YL@.}K蛕o8~.79~)3[/t aCCu!@uo {#~Lcd1Wdֿo}Կз-uo81>6ɟԇCAÚBF}8bbq!?ǡ#??; 1ï&AmQy^ԇxQy_9W!ObħCEO-.) / 40.ǫ/ .T_ςWת֎,g~im*~Ō$~[:a_9ki_S})&ut`C :})RFbRn;aFwѬ?0Ooз ԟ~e }SMg}g0M }`}1aݠqwC߻A>^w@ }M }}o}A߀}`}`;D|wr7\A 4>@}ѳ9C}g⨯<3@ } }g:+ڟ`}~߯5)8Cߧ@߹>w.ȁ x~\_X] o?_3 ._t߅ Ο?0cIY+#VAjϳ }׀Z.J࿚~$ޮhoz о 6طɁ}gط `a5,2-✟o49F~n} ?w8\e_v-K}wi껔o @oKF[Ye }@RM}3-}KAc}1b{DSoE]{BSߗV'@$?vga}k|_;Wp{_Jʶ/o,}_I7~3MB| vJķ(#%pJ??cP}1>/C5?McߪoK?L>}ΰoؗ߯3;lߓ!.C~2֌b6v݌ 4S }1w8;ǡ{We?^/s4Ubԟy&:~ þy[mM:EvׁM_gÿo1LΦ0?@ykq?_1節+45:cɏ8~5Moc7=`2~N2Q{Lm~ۇ`&M~ȏ-u?ߦɯocWwמ[q[_aF|k[&?F^P⿌1w uHǿ6Yߊ5Uujp0-gi{7EWXŷ׿29}|_wcE|7-##q:`7g3ya_3 Oo~?!E4>ZF39M4>+k6< 3'_ pArҫb ov[?C5/eq!Ac-C+>M|$?pO|KxT#p({_(ŗ:0t'EPX8†-f!Y4S/>m? W>eWߠgh¿QKC_Y[u*{eXEoSoYoWc7ߡ ;U, Rw)UW&[m{O5oW߂O r)fK4+߯?^__ ,# /bXÿ 󳮴<WJ1?J6lNf?v~͜ կWu~M4D~Y25'gX^o"Rm!~ xx';xx?GA9s/?">m>ga$ fQgAt6L~# F0ŧ44Y7XpG#H]%'?7w?*C,e5Rb񱙆-ik߅s_ o/Sr zRo`[i7+?˶Mo w -ZMZNgU1&3}1/GZ>J~ p뜢H?M|<,%>F?ˍhy5 ox<w8~IDP^ <1`2b ~dtg,ysXa񩃆 GIPg񯓆+GU?lUÿ c A}o_v/hVVc~$Tnˏ{> nˈmv[&Bpuy \x .p=i{ 8o?4O$n8TGJ93F}UڷF@7]ÿ*GJÿ y7'3?+Sÿ_4|m6I^AbmK,,f ~jb B.Yk4Z O+_3 cϪa>N߇_ AWf񡟆P95^3׈?}RğA, ag?9,bg ?w3`4Oq_® WVῨ& n-?K , }n YshROG"Y aş{XşXϔ9,EAW߇|[+(WE?\=+0 2l #5?_Eߪ? ?U#^Y#LMf9f3ş,cg?m_M,h WWoehO_C4~oMmwhO_K9ܩ 3-]_௣gu=Y =E#,MVşX,leg?Y7ǟgX:47}c7PgۗSK{,*e🃿+w)5Xk yhO*ğ,ZF0'?t:wNq(~ L~VjkOދxwvbq1'XX?+~/I||nʴrXk"욗t{(q"p [3w;dkV(e&@3DEj_3 E[(hl~tߧJ%?5eB𗅿?gmYjN/,X_,h+A!߆j_J%itB%IÎ_4ꗁuT<-Wۤy]>$'jRxqM׻\k>WTܞ|uX<]gQlqMV:e[m_J_,1ŏ?;Ic|UAvVhn~GwהO>'"~.a,%Ş?G~_KE~`KZ_#?~_eX{V[+6~:Ʒ?(L(6"#ld9<bna휘 IU]ڿ-QӶsHNSuJϟ~֍ߙϏ>EX}O<$޳˟?YVC^оwc*MzS=(A(U!9Aģm 3. w. wζVY3~_jr'#ik]_࿎ׂj!?"q6>?B}#1~ c~G_}߬b?9R8vROH@K^x=x W-HF|N)s=~à : BT/2X<y{;QL{៦OdO7~lȾN6~Qߝurlb~Bb~">Ҽ vE_7q9SԿ#+ߓ|{e9Zq,OIY &%/Oe>٬MNJ;h 8acB?hywWw2tV]iEX]{~oѻ̗`2&> azi$WG2ϲOM1?+=DfhoߞN19"YfMVQ?;{wFկ.Ra:1߬h+#7X|q;qG'Q/C; 8!h+mہ/#nA|܆x =pGĻW 'qfE{HD<|3=#;mn%&A, %187 . .? O& D >vۃčw?F<X4bIbSď%~x>BُE'Kmq ,[ UĵG|x04]s_ Ns_WIk#> Dܓi5" nJܜrc pNē] N Zpom?%|9@̪v`[É$ 8x2A<"^ 'sl_vխkyN!_n8V"f_"=T %'zs1J|+KAr22TVfqEIVn<5Y\b,/ʳCKLg&~d\+ďx"nWbuY˙ZD+?ʲ*..p 3OOe2>e:)NO2䩱xbLwl.j\C6Gb)%샠aET,eܬ\n3a,3oldA1Ԛ@J.`k9seA|H0dXĥ%$~/*EbL"s-!#7B/YOCEn;WOÎ͒dQM Ԅ#YD/$vBEBȀElA~G.XE9EfiZV+%OBXB̊OBL\e 1Ih&z=yBcOpk.;?R 'װo34G.gFM˿J?>[X7Rج )}6׃'G|Q}0knUukģ7ջ!*ʢF{] HDĪCjJCHaYsB H¬>j25}BC jl?OkӘnr5Rc&pߤ;=.VMD0|_MNm0F~'<&WHt m2V˴Nި@(6fSA^ :/Q]Q߁EKvc+-Gzv=fQ=-)1:;. z>ꚠnz)0˕@D-fؗgbMzܭJԍAB o#AC=E0@C-'=3>:-/. ʠDMԾ(=@?TbnPB~:5cߢ.ꊠaӠsQ WgEtԇ@F}t>NbuEP]uWХPǀ.z*h@>О?:oF!曕kͨ{fbuoFX7s-QQͨf5|3buoF=\7'Qo07AGuOƠvuP=uzJ[A_V<jϿ:XZ(=.@uźԃź3ĺ)(L.ӦŻJRC-1͈Z w~ ~ ;)%??ܤI𻈽I%] kn$S_iP~87_8oi ҧ'3Cʩ$k1:~i ~bR ь2Wx. Q&cW"~?c3  }R?~2`ObA]yu/D %=WqT?570?8G?bLgZohx~i:gbR>{G Ad" +o%1? &:NhaL \ߙO~Y:$'+03 ??0 ?? nYsJ1}K"V;Kd-7//r^໘T~ `drI `k(w3yI\[aY_DÁGr_I?G|>SD-? (?/rg?~1okP~FgK?F$\d+OebH?;ʯ* +)?$PW__L5$ F)_ ~VjK[pBǧs- >~66w7.~?~-~9??ו/~y'_|Wԗs~ab!t|w-wc~# wgɍ%+^{!oAwy0o4?JfK~3 j~Ja{񇖄 yK+ߘ{׈ ~;o-_+'3IX,m%FA~uFoO~~ vo%ώ|nINcň)3.zw\bO$.-#yus// .#~Hw1t~;3S{o >kMf /~?~3ߍ%ߜ>'[ ؓdJ{? w%# o&|Q=í/ ~62 ) s3 w1G_~g;T~;0aww0 Ҿ '`=Ό)?Z8[i0H֟}%(I we߂_Ƥ$ǀߝ^GKdHK O?C? 0I~8_+ʏ~dK;53ˈ y!_kbGW, ~,?(F 2_\J_~0 >=) A)}r q 3Ꮤ_~D TR /e|n$? _#ل/Vp|+1 9509+$d/Ϗ"3L_MFGrHFϏ d$F_YK dB?"?ĤKMLk>*g xZ |^A737Iğ[&Y[1*_wdn ۔6f  [za;$Bg>0>I" ?$Wi0"[G?+J >7 7G[ gv\?_'Τ{@'%w >7 AOsd|8xpn0<%#? },/:*>gIO<& >}q > xG%* /K ?igP> &tF""(? ~QfcIvV_ w~;'/*b@ $f ()?c*+#Y]7>t+|g'?IdO >CN Y##J\ojm>ܔ_/tK_|%mG;hjF .6kaT_|^ I݁N2z@ ğ?~Hp~x$~F,>OAW31MJ?V |o ~ega J?|n"? B/AՀoC/%ՁN/J_9% __È?oA~^῕1t};z_[^":/ Y}~A@}Q_$˿)+-߉g/Έ"3_SK$?U姑7~)M+o>R?#Y/͈>?4~>և| b*?DM"$N A6s҇ ́߬?C߲I[ߍKRuŸk ~wF~y:~?LS\O'sKt<EF+oJ ~j$/Ys| ?X19 I;,#~da ~gcH~d)*疟$E0Om8w; >]QBM0U~I ~w?R|no-#UL; =/iR%A_*# [VA$]AS~97Z-ڤpB5|1?]%b~ۯ%mvw(?~biԠOoXA"~1?"|_fa S"@1$~E ~`Q$b[P'*b?}]UP17#j01̡KÁK2k| I?o_`O߼>b~$}ߒ?-:|JBE%zQ/KF?5?FK޿ ?jzr6"U+Ƅ3O/0?bǐH,y6/o3 ۜr~ GoZJ"+8/gT ' r ~߯DC_m%CʤII~E9 A.G|?R'b~!_ A#%o A0J̏0wIw#3|K٠~e!Yؓ~F&~U-O~5F#Ӈ7xW|?珼%_H&&_?} ALk17"$%: ~IH|N~]? ٿ%4c$CKo3C$3\a1?] A  *?oNݤ#%+̷|UI"|GߏBt~|3WPH?]J?II??O%  'NJts_'?vRm%gߐ@eRG0A?a#$F~_ߕZe00y(f2Hv3(?+Ÿ._ hxcSHc"Q_7WGߏ>'gğ@?5H5cI3-c_kHqu O@F4?'˫ 70ߟ/(Fcp?Q n|Noʟ, ~>rNo8өA>;Y >}w'W%;(9?8Co4?(MW U>T)}p%| hwww _Y)?~gR~R!)7mE{ Ax ;ijn)<(7Wr&l?H$_ '27#!]䀟RDAg/!=F <8ޠGR}`P:Tqj+w޾QQVklj6[VkP[x(7*(lϾ~ EKʇkB( 7H/ S|yI]( $Crcq'G)O²LҠ磽^3Y[a~nHjthS^cġ:jԣ!֠^z=]7 z ꗠd ݨ92CS{GFyw xݣw?kw5~^g pq ԝ4WZ}z{~n5[b|(KP/"ͱV=:4*-Qޖs{wx5闬Szx,Fw;qT'!Y-#Z$ wb[K6g?@ ?G2W|Ose%1h&R׈M}ǧtCj$W._O>i>9F'P} IUY)T*(ZjM|Rkߗ~'?zEzXm5+IVK.KGAD{<\K `:PЏߤ\?Gu(4ýEs'"۠hcHQz[X8+3,Qiw*D?  ";GT,Q?0_yo?m V\0xgD*W3<׆OoJrxY^u%1&~WE&~qA֨KqD@.'!.3u}C W i(R.eN8cT?R~'W)0?A΄//^֔^ /8N'w d (1> |||||||||||||D>)ĺ/v;TF5[z\S Sޝ#lkp k'{\bZ8zDoJfia)91'UxV.]hmXGM}:d^w^}qdcv?!S=l^3Ɨ{Ck͜~ߴ.|7Ae$(7xmO^B&>3Tnsģo:xVn^Has͗7q2/NxC~rǜB] 5ڽuhNwx2KLEx95mI4ețz{%{/Xc~g* E䨦yw/I a~o] =;bi;?gxjr#U\ϑ-}3Vxb?PTkGëmaE]V{bxh bV?UTտ_A?<9\ {Ӈ>k_Ų7J?T{'jx x֞g6%vq^Ǟ3Mieӽ݋\P o"6GB@gb1$ېV%֘?<Ҕa};^ @ _H־Wz880WDU\(2۪ľ=_קC Cmz5.&C՛_g S緹?SSup*e4׫w*{-cDWj6yfC %{{,~?ХhFyR}׽ sjפTjGKKkޜJ<7pz`aj=\ކΘmi &SWO=g#?+]aQL/N͌K7\_rYbݥ  //ܻ\[9gswC<#yxޏeқLXm35<t$nڱ|Z..GLN^`]}VǘSWjLUX<--ۥ~Wgiߚ \n0kjם3;KL[O3#2(OoYOuɤV/ys.vGὀ)?jb~E^H@Lc 4s;kȼ{V>;C懳sYpw L%s#owӯ(ˮaKO/i䏗f^4*MX<*XhzOvyaߋ]kkf y^9?#ˈMo(;ݒw;u?sH`m&x%hx]~8qKFwx养^iIsw.><7ɔ㠓iM}8㣈Sz\>t]l <1?5&X^:j{?nrW|zo幏3 Gf&Slyt7Ky{uAK\]xbL<|C}6^sU_EY̒٤̲3 e'3";# eD33*[ԜeNӸP_{\C!erߟOx'/ձ#M Vy|^u |KuTHIMŃ=A*ow3<&ln37*/e xKЯ wRIJR$֩1U~x]tï8w^/C𾝀x{N[/ɗ7Xӌ]?Ce+p4xN?PeT>W y,<5ꖅDZBfkurQy$C{R$/x'UNV;Uv~^_^n}9Kf򓋠E6vA_iIB'wm[ZvNvE!JÙsb+uIjL`TқSCd)yIg&/ B口ۡ1 %]ÿ#s? ΓwԿRԪܬeNۯz z a8䷍ǘvzF~Qu%:Xlf./M\i>+zˇ~g&D|AR*<'&T'F^JX~x;P߆=~wy4pp $i<) n]+`?xQp8d_~Xu:2 Ncw鳞 x0ryQ@_H0Cn'C_w"8\^Z_L[t!ٞ-;/#<86L_ztch%92Rh P?fb;U|EH)8c vNQR,Pygߴo؎੐א|n6 s q)`9 YjBI3TGzߑ~  54FmӱϚ+wxvhg7%JQ鑾11UaCӿR.nhY4fPEvظӢDmn~r^`үc:\WӿCGbX~MЎNdbjf yao ̅ ~f}3S2)3 =eVԹ{K.Ɍ|ˀX&0Ei'p΍Wغ8H+O8L}cփ,{׭7{a7ccN6fa4@JB_@=?ENshB>Wa';I\ٻC䚈5 xq$wg;&, */%?$%E<;tw4Bcn! 3ƭފ-G|U8V/Sod0oܗ㮧l9Tkg.*OY8FBЁv X0+..>uk&N'0{U+䛻pSq83å#o w ʜT}SW$< ;܂W#s;=F=w)D GE|>9YN'd}ϐyhl}zX wa b~izdleѩ'OR9;/!?X%5wq}/hC#H,ظ@'ll) 7vnW4jE|S`Ƌp_44SpɶG@1AKD^8?)!D.EȞ3׫[>5x8\DRbAsv ?dZ笞w*֛і<`Ny / xjg_)?oпٛ^lsk+v ӽk+q)_knx^wp~Ӱ0oSJ\;0=KT=r\i&eE/r?wz:f} xSG{ 5z(ܑS.$=c|W Kt͉F.KRi xAf!f52}Yq)f#ut Wtʼ &!xx93F1S?Ur=iW2(*xݡg) xĬ]maa;zQMxþz®\fo3n#x)Lx|xұo!Sڿ;cĻA?)sQç|mS2<Z Y [&6R(Vԣ@QO%8dtkMݐ֥_>+C:⹃)!D_: f-ާ51`:"g8.ulub_[{a9 _ ;'ձ3`&>K|2)Pfy<q6չၧ|UJ$ aĦ% ~ g.1s.ё9!xF@_{o.f9ifeهnxRF7ߵl+%I~a0^SLNޠvwL7)eNږc8$e]ۏ1G!V =P.Ɨo㨨,y7$&.+%jF*_V'@w+| i/߹_dz|R:τ qn5BB!$ q? pb~.-}w^nXc7!r?IC8o^_)T( -U,*`/6s5(o蟗&koϋ&53?6*\mPʛo7XxEAC&cnE=mĭ>`Os^ྤSy+[!?EX9RP_n5IsQ 7M'KNR B%t3s7qȍ }.BkM G%|(oO'$X %xvӟ{#xak0Ct!$CvRӄ(f{{)\/ ؓձK`x4zfs}FC/%>ZRul2$r .y1p9DRywV RNy])AA~L`q˫׋y5d7[׭$0OI!hK^,#Ǣ^u hۤͣR) (smpFbwP1Q E2EEczCf;sqSQe (%o2tJ4|c4񝮊S/6")DO׈ޯ1go竤. '[RX2|~o!! K`mi罥gBBw%1$c(2SG~_ұ!D;ɝs+X7ʣ'RH},DKxHW~8[ur?ktKm- Q_Wf;dN8ߐ Z춛 sgԔ=kn>C +'=ořI Yѹ~Mʄ!ɛg௴8EGpGD&i7Jn(6}8I_!Ge0<;3nAOЃeaD/ Rigw 7ɿ .c /Ë_&b'wf##>?[1U.RH؃­z&%2Ud6(ڱ<. sǥ=|M*qVf Ǣވ,v#f;M'64[{iF|~+ 6tLuS+يo(ى>/~9sп(m=h-A}[vveZ>a;qmL.k9/˧sL²`"%~UK;"Q~h; |`mFv#O?_w3H?}Ew/Q9 \ U' ^ϡ;VֹSc?'*jl7鎦ȾB=ss9gv7Cd&g[';-cdX>VVdG=ܗvn1DV/4y tߧ$dǑ8|lF6դS@ NPR 6xNv,S=xPV%`ذ?UNq}7)_0siom5mDCL?WXzu+[PZeENX Ucc 7fpu9tRs/' s+oq_R~~Wy7;ﶀytL?t`r0hd`,'}-RB5K;ٴ\(`$GaL@KUrpa]S;ߞb 8QNA㡁;^0fgJUR@kD75LܧZH{n4HT-\;FF23q詓:y ë+.RII#s$3^+3b0iO3D zN]nh!~mGN|jnK8x1siEjG |1+ɾi6^Q@u1 n rN19U3?(}61y6:0gs1 X@/Voe-$DUS4IJpu#x7\@. ?`8ϟk]UXa71UOgySK7[YM#gN]I݅q>[^U#xe4_ijc|.b19&Xsdn\id%9Qvo`=z0IJnc#uQzƻv+IBg3E"xloq ^r[ztw;Q)"x=.͇lf3S໊ҪOOM\}&]x2z4^U@*?H1끬_?Yq5>Ɲ?/^T3C^B'% Dh9b<1xL?z?s.aEqvQ'B< BS5$ߨKvѢ4k13vMYWWxeJk!PZn1RZ:q>D._Yc‹JJ~2}v#ֿ8 i6'KNЏ,G4 * OHS1Nog 3 ) owC\߇GH1E-޺^Zk}#nB3uSc,|0|S/o6$W'(壍`M^@#SX X^0ޟwuHx|LReLP}]7JTdzcTC|З+4KWh}Xq{qׇϼm5cv1CK1-?~L`ЧLjn5f<*z4JOjRzWգ_$|&>4b|!n o8ַ!grroaʄ_Z)=^c(_e Gvu` `9&`5x FD)  9'1);|u]ے W5=<_ oGe[MJ:$R.y e9U"a〿"Y=C8񽞅0yOӬdԱkP}G%0 vJmF;fd'iع邸I.y x~x5;=VB66"vɫW,uS/'p8FN1xgj[OsU{W9tŨ.q@N 3!pә%C%7<|5-GΫ%R/`NORrAوTʳ)OcFR&qHwPS Paϯ3.>\?M/ !5V8z^e%!0G;CgD><_W_hy{us`T{~q-k95N _][Toh7<8&\%SxBX6@8?U}PO olϊ4Jۏ$Eg_׺᤼|\ᙬYSϯVJˤ'$}aC_ 5GHϢRo%бux\ifia= }_?%wy~e[%tV95s%Ej 8}+ʰ2tgŮI/g{G=L~2r&]rǽi#}HNH,sj ڗXHzM9]~&@0jzTL9aۮRmEA.gi"V©Q5j@?CMFlvೆOe1zp Cf9 =U&tpJ2BÏ7:%@f`$R?G@ޥ-+.1S1&q]|\ /葋>,ѝQ NO5 xVFsqJ9G#o n,ćunӮ'X|͑bmd򭊋G?RO»0v7(ab`UW\$5Lk 9 J[>/Ufb51ZțfR=A]/F=52򻇡A AC+r,|&ٗm:{͍1ʏ%\_c]Im0`҇[vxLs@{2X̏:<ֵHߟ*R/x@{p~ӱʣUszb`OM_*{=uu0O| !"fwP^ߘ~N XT;ƫ 4vb,DAn(BP҆oxrdd:t -Ë^-t aݶhr`@˙ R}A,3[:Mzw>ϲp%VAhk>%W}1kA k{0R9k9" kaޙ N2ޔl@&HBQ`:cgPKrtâ˒gTK:9ȏ0x%>Wvk. =֫oֱ:/#|ogS0D%E%4[]ޭIb TyT|.L.J_=oi)o ;,XvȄps|(et/hP1i )(-4~TNN:Gp F=_DA1$ׁC{s7o3q#W[߷4|gsG´! p!S jsF\`,g&)?RjԹOp-|)WQojⶒG@(:qu2/2_?uW;q+ׯu}|s@gX0o\`ػ,C6G4HUAWT\P2B@R_;/) kY{7"_d5{<`Cu73x;YVnXa͜$VprF{|/TR:sU\ ~g O3Une4-"_W]YW2:c] /K0^w= Ыe/GVݛs}m=O6W\jXeSR/,0p>-)42:mO^Fg~Wtҿ"#HhֱĻ`]vq_&?~5VuƯL7m2l뇢*?khc|Ѓ#X h&Y\'mpĉ*Vm14>d2NB'Hxp8vQ?ǰ!sޜs$^_C𒶉qT:7̚ϒ={\L6"L!xЕb9H1ZGdt5|RE<כ5qK@oeՈt8w˅mF?*?!H$w,ou`}/%"#D9aPM j4Bq+aHƲJ4>'p_:aK"@6>ۆ}n\SIa`EI%1<\?.4Sk?ar3T݆jTJWX}jo] hBx#|c)в GX5VSW}&1`bѠi|_ד_ >=st9+ E5ssh둗v?]Xq5ߩA6aq@>_ɚ.x?=x=$X@QMw?7/!% ]i</&>Y\e.QI<  Mԟ*ě@0f[NҘ _͒z'ݏ*(Rul .}Sg!?KcϧA:8CNҶ+lG&ێZfAh j`3Zmm[c>N,pdtNrSՑ!A.z.S`=Z3:EX m>‘h_>4!ٱϗɋiDA( >|'6}Z$FXŽIFh6:qӆg{7 q?QuDi<_8\/%أ%ߖ@Ɵ;߈G7/z!70w/<[xYQ۸jEYLzp+S ZTN|5wz35zR(]Ԟ =L'?]@_tW6۱!z7ʜŧ#x&/= 8ag¶UJ잻_%++ʭ\?≏>e\_#l0^ul>>05%I^ʌvN#@gG)v=2ؓdSW_SM5-G1Z*ty&AgS*_ٖy[-^L:VL¿0% w(,~ Bt 0xH=k!| ً.4tÐSԱoyw` y:6JG/I*p2VVm;#ier/B~Mt:I҆ZB}q24B CDk-rá*g/?7)?'{BS{}D"@~ߘCMu$mXR ¸y'~KyX3{xzsVxޚЯy9b9"W ܡ3,Da + xp783f*| >e. :^2ͼ#R+ϯ?3BY|Yʗ؃Տb:hF jڶ1P"s#wgnKyՒ-JY+ v@zu+ԩ=\?".9sW6B~%8l<6#h8::~)+]@qlB=X{h<]4KÛ͸aJ8{5c/#߇x:AAH~'*yn,(%%M3ٗh4>tT@/ wT [Sl֘9~Ѵ&M#6^*Ax8<߃ӿH}N\kmNݒVQ2kMh<|ˀ_6mխWmX~X^+c6):W1[ V=.U=LK-kW{5\xˎfIF!ZWwDEb@h2Wdcc}9dqvDxfg(J_>p(f ӇncTq-NH|>=])y=߀rI,ܗS`RSi}SĒ$DUƁ$^}*_sv@4!^#EC|X~$Z(HŲ㜁{H梤ާƽp#xt dBNX] u G>'_o:6@ZL>*(V?揆)6`Scz8 ]Ȫ[X0/z[o9a[7H/F'M_YӁM&sptF7n,f?$tg.`\SC^. f!/ x4G8ħTwK5}&8tcD ])iUm- : !xD_Arvi/Þ LK,{NGRz05 j#n~23eO++0Eiv okJ|BL zw4OGM^ҹ.|T*.a97䏏kA%}1Nu\0Jv*y ތgf/}Ssי[RM–hY9_PEcVC-l€o1{)lsrl^}w4{7ڃ/q/O.F,ip>`ߍwK}y-JDsCf W?ŇmI[k,|tA~7!; >ҌwK't0 ?j`J {1.dև'8y"-֓OE6FUT8'yۛ}|  V.Eַbij=FSŬ[/6%9rH!:= < ->.fmvUKT^T5[架/.Uҟ9C >.@` bO? um]Vvh,Ḷ4Ҷh)wA cb7#7ąGGd=#o5[-lb3ì:|bNG/R؎bs~NO@]բHU'p8G _&hI]U~BQ̮E? έx'iڱv0|T{#x}6,/=Mʫ! XJQ7ɪG z0ߣ |Nx}OO{ѓV_f:S|~GZi- дBwbW!y |B{c㏾nInUE/{anЭfϳߢH>#h9'Xm3-IV2\bj}"Ch|1x @}'l}w;a尌BU(,>pw_~7͏W#΀x1'. ęv)~,iS'6LY,kh!lظ=ׇzy/!Z zR/ m?Q뫡M'ݵX~^vxI <R Ly34cɘ\-ͧq#; [}~9-}d+bŌC ҷN<8x1'f`)QH8R~WW\ ssLkzkS^z\8+z$51`ﻫvڽtɇ@ƠL%Th|?t="o}wd9# q_9nzgC"izuAw n*B}~5MrOpd馞qЗ#d:b=ܳޯopDl3D!j ۛlb Zk#{|"\T%:7A(GWCP$^HVy/z>o8)OLy>  |=ڄk0Q]Ek7yn%WȮ^h.BRLIE",8]ugXm+~Z=lncsIэf<8W_'Pk4#kc͆wZڸ8Z!"U c-}V}4nE#oH$JYQ7YsVB?:svnKq7Oi%GO&kEq-ٰ@)0uqw; _7F 91xOi2np9Mvn G*!rՀ5K%Lώ[̚yiP=' W#gr|oTa%k`'aDsO'҃Wi +QW $jI^ɿIeyȩG7Q@B}"ç.cӣx-UvHXvA.N6Kis7^`)<\h>y"& /TYhxCg=-"#߶ 'SJ0I\Sa,&=؅#ԸN&,M?PGmі=G_YKg)AaIW"^˗ 82#b3}D7a}p>6)v*)blP]*{3WϥTgB)=X4XX3IX0Iz՜q81茔z?mp\};]uKcڍDVM@{Ѫ] _2=ioe<&6;8o$ VdUH} cɮWghw#_W m͹ɟ({GЁg:$ 1V%\1 F9\!ڲ5p~1x`]VQo/Ͼ粹=(y?ϬiydIݢ!ypS+!f1"ٯS_ O:0o#AN!ZL?|2db.{e Q ##ژB9FOe~Kef_:<ib֜(;\W!#E@>iTqϦ.^cϭ7"[j j'9#sn"-ǵڕ2_p䆬9iZS$W|ERrjFaͽ$ZiGOID]7'}D֗!m>|C.\ģ<)7\yVx ɬ{yV`4[\apnuYn. Ɔ~`1ԇ?tH4~#b-Xz@Sl\n^sWIGc3 C;MM5Ny\xO+1rmӱH`/e8'Sj]׎e3̲ve.SNf{[]<ؕ⪏Dm%{״vq{OhOV?qA:ow?\գId3EU7N ߧܯG[GM*yͥJ=8MOqz'X_' \֪R\gb-{ݝB~2/PzF?R-| wr\vȋvh֠_ $ rI\>DE}y>8u,_]申vFʡ^2Yz ^7{fvi zc;_U2t-/"_)vg =v#4a"' $-Z_{L{aesgR)^x2'}_!Oc 2> ~|ݎ9gN[N$RPf!x.?/ u#ջ1//s;UUL+-FsJ++ֿsH#g^! ^ZǷ?^W# s5cI-RZO礁?eB#+)k?v@m]A @j>,/X? 5UgOmh0YPձK~1U^%!-VS0 }F,3Tji3똵n@~z {Vm6f`~OyXg {kTr~a4(? s-'SS%o5?_o:.MBmp^?NzeWԟuhQ}rͭvyuЃR,}Q-IWO[g kuEEZOznJglh>_cm]TQF+{MR8N@70+sLp 'K4/x>,RԙXB!Y{5Q]*_CxbOlA+v-߫˃-Ei#*ߋzA#يc$ ֟dVۊRqՆE?F_L2Uoo[:7l /Oa?"]tDފV[,QSoQ ֿШLo9U!yaFq% E獖 Qژ\JTX]:ZKnlםd^?>ǧ*+RNKl/՞׽䱤{"cz(!!Iم; uLsH4|\=|9 K&8)^|^ INxrY ֩Wh؆"xS؟/A+~rl[VxkUb$\AڠvX -rz&^Vio]mBU\ oOt f}?^5=b4좑#@L%Bv|Z͒[exV@6h1S̬U=_}9{i%”zX."i0pْT-ʿ`v _<1/_T4kN;}kzϊJx k<+w ˫V,}wg3zQ A+Q3c i/30Ȓ}#~['^Z׎۳4z {/"fu?V[7?of|˔d`M܀wst6Yn8˵/T(":`=KjC\4zR".ZMHBio|bˊF÷Eݾon ˑn?B7W_P>[xxKW-}.eCr;vypU9|Xrw7,9 UkԦr]~;4vsO'o+v \B/ eO,`cr^\KYfuj&x58Y]6ʽNZ|wtaT?y+rigw7i+7o5/7nAzq;v<bC;RRhN%q';E "x1x{)Z5m>Cwv4i?9^oL@ gCEOl*@Koݶ?-0 4.KH)M)Njr"#{Ͽ!]E†D]'oE';~F_Xւoz$&w!K(h!&kwgjs:JKk+8 ϥXe#N"NJN}O ?xʐt~y[YPqE6;noBmmNҲ V5z^J|Я G+`=za#z|/ FvGVɑa$;y{{ ՟u&<<`/>'_=CZGL1bDوܠZ -jy;?^#Cп<+3n'%_+ג.]hsȗX{1п9is'W>|6zg GEqzͥ/^uohħ4bS@ζ,bpnXb{E2n`ovP5COe9}FH _J>wOl*))F=VޏOMu kA]"%aFÀ qѼŰg*PGB N r. x+p WwTB8D[q[lVK>̑|SH[^rgtɿyu8P?~Yk[r,Ʉ_[ȑjrR3^8XhX1+9Gbv"(=t.)-S/[GXڐ˼!M,:;d?R67@Oҗ\vd73&=5Ȟv5͞HD:?`l%g5c>T&esw>O?"õ3O ½t7^ޕ!|ͫQ  R,/ /Z>JP#; +EFhȳh1 5G|> NnVe{ȑ(kŻS4W>%qp@e_郖˼,\ߌcԩ7S25j-JĄ4V; Zv,ArK[7uD/~zl֣'ן:!*`HaG:S:QS|l)?^":)l*D[c9/Ic]XnUYhwAEMƟ3W*zkxQ㯟5.[dK=C)=Dp}q/+Uu9ou]!ܿƚɯ]xf9'ݶ'j#`}${rmɚ8wb cyW cNj- $&^ n'Iߘ#zP[]y-\*?}K)T4wF]>Z %}!f@= ܈sGS5ܙG/ɞ2*z[Ua:xj2  MI o\1>Z7ܠ{DWY>HDXu*e`?WK|$M?U%ϊVIw-$t \Py賒?C`I)geƭ?8%Z/p,5GeomQvt4G)/K}g'ACSܚl7%T({?-5RM]StvySAj4萁>cxZm/\Mj.57[Kd%eށX79jU?z\01`Ye'f+UFLeOJ ?! Q%D8͡;Gz'MQ#C&#{쥶 bi+&1l},=`Ji"/_+vj͐}4S/*XL#϶)(8?Zذ̈́g7vjd!/rDω_~R7>ZB0nDJOa5/4VA&F\(ycX-3̓ča /@dd7 *fs|/ dgf!L!X`u[y?@,5ܻxӣ юf{69~ iVlo\sVjnqǃHxy1æ"O^L@E7fcR`P+8ggԈu= / p4?3SX$ S{ϲ?z$)`yDp8X K/=; , yZf]ىU&):'3ߚ_^ìo+`myXf4T3{%LIo>k?+)1%t^Yp㿅z^%seu;"^EQ=Ծ3 E"1B\DH̳N?s9]?٭v/ņ,ބxAv~Vw]xo*U躶o@N:Zq~njd!ƙjRdӸ_>cK&mjW!A !u* qsj#eZ+Ho$jGJ$_){[;2U+CQ> p C{#9Ÿc0jÅ:oM(qi:r~:7OBoO@4UܗX{"u&ND1?wE9WʋR]D@_Lj@. 5x2Ѩ FܒXw(XO.<2ewMzDykȷE틸ٺ__LeG*8I |Dn-TH˺gvV(?;x;8YӱGo(~p$҄jjmS'lZNG#8PiG:Vz Һ)4o)IJpM|W} ͯBjhYLt_[YlҰYSM9Dλ|Ep?z4F`77Z⎖v7d~ [|H#&S?U>hSR Ǐ3q&'+#Ahw'pӭ܅oa*eiͳeu ijAi%hkT8j/Y 7vF 74[,iw| \B_Ao$# `륞1}pQJN #˶ WN3ˎΊD#}ݪSHJ =82m(筦MmGTc{Xù^?C#`],쏉s@ϱ[^:NTxb¹;4Spf=S@ jH><}*+ܞhP!%7p}~٤+3Cz}q@> tKIQ?tN~#|rYc0t=i㔣eTWs|p~B ^/Z69G.CyǽdQ BaQ^fRbT?W-c&^)=7eLu˒ +jou r>Ts`bؓ?L /K:fmIrURS:Lx"م-C W`f4a@uAtli薈8}^?ZTkJx8?f<;xфs8Zm覱gOlvaAV;H}vl`}N N#e$|vrYS{jW6_* lEo 'KE3Q9qRv- +WZkuYV[OA`}WC= i.LYVh{ M{ߤڻx{Q}D+e8/ :69hPlfP㴢^+;3kbDAƷyͿJM>JS_p|B^sA1>]3ވpmSo@'h]l\Kuj#J|2sR>Q+_rϣnQ朋 ]\&zYkbhD[9`Q>;_FĄl^y2ADdg-!#`8I~(<ϸ.~}yMkejD&H٧:ߚ'_R{]6쌁/43A?xZ:f=g_F]~#32seڴ]y <-$S w|'EOY-'r'\8gxP7}5 ^) O#>ɼN>5'={71c/Ze/Z-͎#D"W|-:J7|^K,V4µ]U ^uYBD $!N Si0 䈈yY5C?]Rxxw֕){4 h*˗6@~l~~R 8YCjB!`}J)[x=^-t@g5T{I2! /7mK\Us7c? 7l50Lݗ9)"Hfڸ#{ZI;k!1Z1vt% [bǘl=g%ZGY3r, {YQVyeD:Eo7 Θ!y)’ / .BqO K|RwfddB/x@YH5{"D$G _TPy(0/6GoJ+aeRPaznVקNv M,9RG:'ׯ=A'ϹF}cf#.D>E-E CDݥA4jQ uNU?:0Q!׌C|&:XWGӂcjw +Ej 3ߪw^#fZ0u*AwyԿʯH<}%-WB)>8oXjWO$c&'6at>ՌͷWa}|xW2Qy13#n*? qGGIyG>^r9~eX#qH@[X{s@+)\^d7L`T@-T_l8V _#/@.zP\l8}SZ!7ohlNƠ{؁ GoB}濒>tvc'3#㖑{ < &"x,ݫN_0xcEmWXȭ͔6ZeCR 'oaA_ PC\~?xƫd]Wz]bhmj]{ */Q  V3 w=Wj`*K&mHU햐sk)'|9URhJ*̓=~r핈'8_^sovſn *OGC z? `AI[m7ݛ?b?Ƽ_2ְV@eԟa&3@'kTn0/7.U͖fefޗ#&5\?l Hl~lв{)8hɰ.J>Xt9<4_gHQh#x&F bb@ lU%0gyᮿEڀ/K2i}R| ̟^) V޿Z?)?l_H!^oc[h:}["Xz 62?3?xFg7δB9 6]ǷAe_8j[]p4qs_|4MCL͇|@<[BiK.0?MS4vGbąK+x ‘Ԁ>Kc@\VaGE=gj~_QiRG҅;?q$ ]Hݨ}-]%KZ_NyD߽}6= ʿ~BHAz`H|YmQw/|J'ouT_%g VBst=4)bvDH|>/b%&?R?5b9S*}L0xAwo]Pĝr/\-HZ"GxG˰wρzX=.B5"Gm ,_˘[B#bHTB,6 8R}lWJH8ꑮVe1LzOVvȗg 9/&ݎSW\xX􏗗< <;) IceH`pJL[4δݥ/W҄645A_E 8a%Ksm5(Tg@geιlK ;MP(z"< #VxW)S;fS=ѡ.>9QJ #'lVw-G, R9b ƜmIO_]4p.<\_ wdihmv7Sw㝘Qj{ }OdsQ:XQpQ. X{ j4p1zڜh*&2.-K._lk5`B/ݙL\-Kf r ċ7b/WL=WBYzphyZ%&w L2)6Eo" fd~C(J}dy&T\SizvfFK?uPB+l}cLA &噊[{UP{'+=6&e!n$ DKna@õX9pXy8q>[Nm6qjS?``8*?*lK-?TA 9lK?>Y6^uzBd,K-47”?Dww]Xd+΂+At1ʂ鰙d+OJdx_[ W1bH;/wks3ܗXyU;%|A\`W6'_7A6~ ~w w+xMad7yJ``OE㠡ӯ.i(̘PGp<—ᐰwR[e11A3/eDOc,@_4fs=U;DlϢR7 22S١I^s~T Gݪ*z3#{fyuoRlCzg9ЙtNXV%pIrĥIПGBXNSxT%w`/E oyU '%(`ZSi8zøWdv ЀQA:9ЛmE:I ҃B3A7/7&uWI̩ԌPfnIZ{v84/$; 5$>/j;SqE _MJDާ~󥫬m@gׇ tMQ/5WWTxSRG6n|ؗGpx$*x@d*^W]nW),w[V?|]3 ݗ(Ri }/FO܌]9hm($B̠ O LHA~'N=+k%tbHfb,~&_6P2[n']xq&(7f9yo;S\.9Ά z hA>R,ztKQŌ#rtՔO+=XBO?RWoP)qL%}s{0p~YfĿ$=8[8{5/ǯ\zw^ꝤcT$ޖRãG ;}9pQv- HG0ϭ+ܿX_J@ *эۏP0_L(N`7tmp*^l_8_#\WO^m M^&j k_ӑCʩoش;BdOz0>8w}Y@ kN" ~(EB#.Ioۉ#5%қ zAem =81}z;\cN}qhT|v(!PL $S:BE ۝HtT1{5o_E`yR2Woy]*ZpBsS,TXzj)KaXYJ@Sk_kO'}Sw}7!8~0W&/>xM'Z''' H@ p|Ii_M.w,4N8,qF1/ߚTK"QЯ ?cm|7LS$>}~[Puݖi";qDoHT94_{7SSE)(Ymӻ<.T]lsI[Om5_qq8|U%%/;]Ew䑫GrUhJPtU IdJ\۪LGs'4`~k-* };恼k0^Fշ,oxT+}hUoo3*gpt"GOP2% &"/xc=6!ݬhJ}&п`$}_uޅ(jʌ@ܴ́: ψ>ݖNq?_M*n@60JnF,?D˓\6W:&ԨGaJ_l'p~-Ӂ~@`F}_%uQ-ftߌ ݇D<8_=\҆R,Zgu=ejc4C`>; O * [w%139w4%=-q?|y7RG79K&xҦZbM  ucvLe9Ky%xZa8fӸZ <,׿e'2,d@}9Qx_c&y">OͿ5ȆG Uֿz?ԪRg@<(<#&,dRH9~c1yME١tCV ˽pħ[>>ugap_FŎ'%S)`'9¯moZbx#O;oX|%vW: _И-oV ZxN$s +WmmQ%Hg25[?` `1^JOoV'ȹG7dLaܗg> <2ɊSJiV٧CΥ${voRPs=3'Qh6J$V<.& 2_ېwUL>//iL[Xy ٴMP_8k>Aĺz"E]/Ru#!?_~FsF23`5=rewz;R |;mZh&O_|eV# |fɿMt/lNM)\a4U~B J YYߴ4 |m#̹%׳H, 1E $8r[>JHy-d\t噻FN،'mx!=hT84]{q$]|Eͷ.}_Y hE|46 6rصӿ#ţSH?dZda\Xɤ(9(2D3z11v+- Zfd 62gѠHדl3I%i6qH6ya s"3yY?z*Kd(#lv} DGP>@ƽͯktm2HNVS8WKoNq_8y{peҙʊQ9tA.b#@ĕcLg&T Vy".h.W`mƂX&WAOzo{^R<-Οh` nc+}Zz#n2OܗlӖ_uHqԿp=JACH<?A=Ȥ/'zLu1N{ό*;}bSl*i/R^>0' g,hOïu1\l~b\ΊfE;zhpXi0^  Wn>|YJ+}4#8R  bd(g\qɊהMN*)sEhJhnp `1xәCPiݕl /&R}`Ēօ3h>>_-YYpdHe&CB{"l|Q< ?\)V728ŧʤզF_~E?LqGABL*SpEa s][SQKoX),Oq   kր>`~cE'ӎxYgJbP ~Br'$i@ fNWpɵ-b ür$4?}MP0ܖIUjT& )K];K7h<5_q|.7<>]KL+|]-P}6fl^d!K%8X1\lwY7{W K 0WU_3d?s Q?Ia1^!`ں<7b]c bU * @ԧӺK'iLTT ;3K ,R|3YaY}i-{Gt@{Ãշ ?RǦ{_qc1$MnE(UW|,<8\ DI> O-=r.̕mD᱾Wc~6Q-SA$?:V/zëeۧI1.ɇ=-ws;SaǑz^g^š48wh{pf/wxw 9)yQScqB&aۧC_e<ȿ 3Ǭݞ+vRex-ͩ{ܫQ8[g$jhKiH_8$mZ(wwG+v^#]1(*]~-4-8?54g|M(!q՛)d->x  3 jb_p2 Zdɻǽ=ɫfrhR \S"x~Ppړ~Зg^qiMus;1juљȘ^TNk,|H}Kai+_}8YjIY"08Ϲ:Žpx'¢Fw K6x {H"δ=xWY_z" (Z%5"3ؙQ%dpxPǗ1ӥeK4tjq/Mm[]\)9X[8s,ڇ|_-IT'2Pv.A_\&rh}ek>c8`7;:c~͊TXXgZR q2,]?'%u;DoUN=(3 τ ?$Y˵z?GrԴRKٴua^ZC)cp7b}$jJ4}AvL <_M]F«|ү(zF߄Tѽ13jobz!O?g}wAɪ!C qI'+u1٘uԛ3UE~3ۧJwO"' _~[g|?\O YoiǾy;TݒԿhN l` RV\qn rĔז.?/]GC,x~?)h 6z1DNJWśUGl煮A N:*}FZOdZ*:m6ͷIU[e:5t2A/]!wDžWW|o/\-a-[ 7W] 78i7Ͽ KƟ#Ď0!Q 'vGΞ&*$ rkᷭ_hxIhMQpL=ڻAYw _!,.E=Uܟ@כSm35jcyrv{_'ԩ_rb>E]]/Pኹ٘Y}On|tilKM*ş!?K i$Qy>B;S \ C-''^ʾ#K.>T_x7츻X~9K|I[. k/f"x9qG+@@|n{KI878u}$Nt2/ уyh^#kzZtOxx]i/SF+P}|bJAҫIL0v+w$-g]B7e( Wx1x15@ƼpW`UŮ:cY5Z`vfAT!Q~,"[s#'ť~c>O {Wh E* <H|M>#ϓ$&yʮmx? {72nGᏍxǫ#\2v }OԄR+ +W?a b;v.O)cIU\ߢRcgm:"xDҎ3;@lnԟ-̶%f/~bux_*Kce΂B(T`ޫ~@s{L4E35)#X'>ωq D >{UlMo:> P\ma.n-R,LI'_m4zwg߀gw {.bn,[49 nJE];R≻J_>Þvp}& 7v&U9(cI~ ;w@鹑vCoKcYpP|=qZ%b_0U?^مD!C*E2BYEelBE*#^s|}u={+ZNv=7-RoH-1j=55Rfc\ɷϠLx[|$jI+'^7MbhW2zY#oh(4O`}kwR 3cb֌{1*L;}EBӯsLI C_3m,tIjsf0&Gn'`>mCO]Ne /ʦ/܂T]/K؆~F7sQ>36^Mcg_()gqsu9hغag|*kz?gX fkO\ꔫ7֊L4Q$DŽ9upz|W}Y|ަZ軩_Pڧa/^} i }xD,M$an=`k uCD< ЯBY['ڷ}'撉µP9D>Bŵ/'!x0w++dl`7Ria4~~p8k9oz'oQWL2V^YqzSf\^A`d}$kAgT0"Ev?Q9{-MqCR(g[dr3ߗ'Yh}v_ZH"QZl}S yeXꦣ k9!|+Û [u?z/k45؂n^OỸdS2=Q=̄s}T_"[WzTdr~x+@wauOACQ~惘>n*Esj>1OV1Ӷ[`\nfꊓ|+F,fD/|[|4N 'IdK xdV@,0|e0|u7圲ڃ{Iwۈ>G29Ķ};zSooyԷЦqȿk{nTY_`xN)p6\ϗ\P cjH>U}og),oShv5֏*zx&a)'덆DSO wu]Hwoi\xA='6*+JR6uq35s-3mNu}ׇ@x8ܦ^]r+jf:I4S~'cZف>+w.oW)(@aY#6}t] "[ߺ#qL ×vy 6 2;jZ"oҧ$|^\-F,dn_sr['FGN8km̉wGueۏnrS<(, =ws__T_-:},8oʇw[Znآ|B%K5o;,wgQzCgE~ߓ@/*rSNWY_+qZs-w@j8X Čת6(byG_fW_'|~ٹ6w&ze/Y^?$dcQk%~i{YZkV;)Հ!H=%z|D,i4hatIZJ=48>QjeȐ@oj[Q kB>܌kBH*_q>˕Rå*GQ x,p~(а4(׮*n[SC +n5EL"xj!#^I])1:\=CSTh^\? iSkX)n P(x%o}}km̮ y0 y[~/ǟslяNYĊ L 5vc6M9ʠw+4 /YRGƇ@{BG=OcAOtfP[~ަOoRғzO-5=?|,Z 7#_~&p>t!;g?ܚ\෾#09d{>ʏ3tAw<\T̓ev^L X\3"H*NQգq#./Ŭ/Je뿞j:rGqdWLzMaCʟ ̺r_h4\A~n})H?WI'7(Ͽwįr*c8a&Ax'_yŸ94O#rϐ1xӀ ~}!0.+s6gpg }h3MM)B-n:SDYu!N6{VL\s>r+[=ԑ[1Rtz] k⹼k'ΡD3!%ܴX \>Y֧%[-"g>J~wa뉷) =soz_,\h^xIDIKsʼn5̩Ms$=f79ϖ~5\[]Ҝ3i6!VzAkh s9v?#c.]G]DV) mƵd+) ~rZ 4Xэ1J_XFk[~<0e[yJqB|.KH de;/RՕ9/ߵd͓5ZҐ3>Ӝ惷78\7Rx3_oE W ^ZQƓ3QG*kzsS>Зptܰͪ}|KK˩'<#FJƆ#x:<P4rXk7y1N@S_&ze*K,_oo!7lswIAc'?xQ#NV筮|5 (]T A,>NO=Oc+BIdq?&Hxy.+z:+<ὯT cί}2\?+H~A"*?:4'Mу4 6 uΖRi(Roνn ?rAp؜r;!Jě7X \N<X}j-l/ |J᷷t%T q;W֏/M1O!x0)J? 'Vj >8}B]*a& |R5i.2't?rBF UCw|ѹɡG~w@=۬)mxWI":`UOTbV%smE_Vdg1KIi4zuW;^Xkns-0>AmgQfvtl2[_$+W=ܳɷ7r˱@y+1/ ЮvByE`c|nY}ݻH~imŰORy\P,W4ٗ "O!=_NkwkL!t?#"_d`|1xRf]UK%ZwnWEH 8GQ h|8y95 /Hc滃GO7қu)49l03Nўyc\A2_0Xð˥我~\ṯS^!]n ]lIQk;5Q` zAmS}Un)1m5 c/X];oxDpA'jgYxꏓ֠{_UdylE(d> +I{I/ XzYJzDy%'w}dCgkD x[ >G7Ίop]Jl3,Uf2<}"VH5o=AMvo٪ZF ·=3o.+3.B8xS^ܼdOps  _!W"ѱC-/^7?sIN;[LZ6*B!b<O\AH oh?.%+x1)LZ$v$Aog կmb)I/⍸T?;3ԵA:oO+e#'a>_k4>vtͤU#}*l`@H>6?)e)<92BW p.!@3؏cl Ods{#{kSQ6FUL>!%V{ߠ^잖+ƯG&,< - ˳PM41ulY|e@EAS؛qag~ e4g\9B"ӟ}EGݸ.Mzp=4 S@c`Iӧ*饖HO,,EQyp)#D3og>Cn;z]?<^P0J_`{ FʱFzQ<6=CM损-;Ǵa<2V\$C@]/ qљܡG|l%;dGF1XזOb8Klgj˸>1[ͧy@O{^f|2z0of4+Qns^6n Tʾ8 }֛X=[ ɂg s{h[E΃BC7+fZ`}a6Su /ox>\S߼0YuBC`Kّ^ 14wΓʷB ֞~>VVP?B[X(8T|_[Ud2n#-8W'_T˟ġ!քc7~-yF4;_?@ ;u7!h(fl?aL?)zwLk>GâoocqjͳL9K^'nҏ|ɧw]o=q+9\egdz S̏m~b xCηwg8؀4-K36w;6rT%88"?/Zo d]qcVۻ؝w?dBjaz' '3ujIqmU+VUxot~G+`??Z Rʸ窬I鯕zpWxK~\h1>'}vgHw |8VIbN79O#ReK~F *'lmM*zYSNPT%K|yTڰl0Y9o2ގGKܜ]ֲ :PSaAoUd8T7ӉBמ?md&)g@[ ɏgz4>S=夾w7bZҤcf'=0ɿ'[_$jC)' ?w|E/Zi 7gAJgI"/e +YJO:ܗ V 'T"R+z~fZl{RVӧqyr5<#Y}& a[#qKu?).^A2<D'ЮL&v8&[1j+Y`Ffw9V\!߯4k;$o)Gz5LJߓ Ezc(h;A{bW_ Û|l+r]f-;q4  󠖽[ 3l)܅xZ] $(wIo/6 gF3q*?b/sO.klItg ț0i9mVȱ/‡.ovRWSO!R0@׃CK1-7$scNɧ}X {~1n·ʯ;8t6w_GҢ݊mg=)fMJ̯{9} h~[* Sfe$ khNy;v<x4^0*c dr>e481x 1Zm6Uq$1{6,آXΑkSx8xNo ]b}8Wr^ԟdz͟6.3YaO [VD!)?;ĵL3+Ɠ3Ƒ5ѿ7`E/?,?ONc [^[40|cYM!3^S5i7{B GH|7Je|#OnU%͠/+QҟӞ6}m?1B4C" /קVgLHu1n|H]MyHWoC}%+LpE|BBێ:J=:y1s93Ho.}YbOw#?Xlי| w=?δݴ3_?2HL7,;!嘠Z؟H_@4+sIUW$NmhHs㋭Zj^94\ B# :Un"{AvاC]͑93 N59UWp~O^>3 ^'D(VvO/m^RkӵL!QGJr}H3O6S1Yw)\f޹dW'# c#^a)/r3ɨ5-w>[4;JϛqLՠw׸oI?4d/no 0I?GK+V}wLÏ$]{1ؘCaýY"xw]e3[|XHdl=`' gRqj@8tݤ5 {s!yWz}m%E1-s&gtn]Oz™8Q|`W+ԩ) #S73r=W{+3X1Y3iWKESOCM:Xxs_Mz|d%IbfoI7jYj{Ҥ`21l|88閭b0 b}9>dg"J(Y΃Ji=),(҇~)#hVR*t~v .['2ۈOMẇ W%̛ɼNkډ0+!‰O3>У[*z2#%?k8OϿ#צJZG ;Ԃ }$ߠ4NAޝlBۂ~k4"[,O=!HTkǢWx62ˮN(~hv\C[q@g$d_"h*wr;z]yj48Ga}0P9.IzhEy bEenrT 'r~hI͠{L@AS|kgUϵGG$>3Ams? 0_jOFo͎k?YJw H p~1Dw77]:BAtSޮ`uC8k ,\_]zʛ?-!wvjݚ@ۣܔލ}_:/z5{ ǫgKn I(I=>|hzdo3}۩7`zŜx#)f맞$+m1{λ/]6T%83pE 'xbwJ("p臭sz< t?32>}xcQsWm'. z84EHZ/ 8xcp8$+ۉ3s0"k}K穅er@c_}0!#Sc@-֢P.Sm-F"YèiXc1U~ c*f*8T"g0烷L{v%oLt jrsY@JWe;m67{2xQUh'`/ .ɘ@&"hWO5ɇ3ᚆ)\D Bh}E0>Zx-3`|mV*b]d`%M͸)mԾ 'Vs<{9>ϥ$Д$Fu1'+ <9IC'_'m7 ˗p:ݞЙ[MfjK/yAuP/kjBM( !lAnEeVLȉT1oп7x⿻d("x86dpbzaUd8Hji$\ D.\u ͇ [Oz):d1l}IJn#9f9ܻ~W'" Q{g\EK;Er\+nu _*(Vu%}Ӫs428ϕb&x 3_7( L/K\ zX /[a7 ї:$ zE[)|%r-2}C'+b[7ځ}woۆWيC'.nq-d8]C iDGpaZh,NsWsp%7DOG&84WU0ћ(USl 7+9&9˞i~!{ʱ'{2h-fuHՠg"IL }/[tTi$<^L5Hz}I2Aw'fZ8y2D\o}߂hBBH=`=rzeN[HLe8ov^a5\WR+o&~{ ^n!샞Y!¿YN'2!otT+ Oܗa>sƣcbϑd$#OL)#um3?&śAxIH}13!T9G^yzD.D u;B/4_ko13k?I~L*j1eO6ZEsr{}..HBL^ 8o/ _ ;7X1`w_v 7?TzgnxgđӄJHb&Ru߃DB\hoZ K&>5;8[2Q+;2AyZFμ$Jj[o' WfUNب*W*n Еq:G2Ŀ ;츄]oJYG)0ގBc"}u@'hS۪kҤ$}iTq\C˟q]_ToAa1` a;@o@-A.Ww,[*hS_ >դ%Cx owTwhj!uC7k慻zjl|P9 /6l6?8yPaZ AjT?RU{ʵOQ~ K?m_U[>{gkT_(?mNWz+<᜖jE@Ԇ7!76Ɨk Nf% - G=sUs"P GC:/8Y+;}a9#ʍ[J*<^q x|hgqN)ĸ<Y q]5!"up&l*_$>`xX[>OrbH_jڤ#_C.{GZWU_i.2tא"xpU{":/ʍm}>+YU 5[svF> /_ s]b'Je*_eYREgՑEF`SRs~T2xB[\DfPƤ8ZB1z]lO߰{'pGzk3b'[8p]̩%Pyߦ ΛW =nn">)UkafR`z !Wy ?rOpIy}Q?b➨OM:f}U_$(y+^;xq7cyg1o)UPOtN@i`k* xrQ{Xlcp(Jsxx1@- 6s _[+rۮONl.|wzO :g`sSkqSN#%tE\^C~8zІ#߰j0>NM BKȴSxˀOś1/19GAW7_7eJj352o]h׭=dtӤ- Ba# Y0K)z[qr;Z֎d(RçғI=ӊ/L"`%7 ]ޮ  +7J_RP/?B?Wn*BK ca_RWizPp&A̘rO'"zr ґx'^ ?%[tzfl k+<~~ljZwk3IImT3 |~La˃yBe9`-XYro$xь7wE`+ 42?{`aOg1b”{̷_n_DHpz)qbC K=b1sD4_nРنhGPΎ_+Wmd ǴS N~ñ߿OZ"F7t9 tspcs*_prkuQߩICSX-;w"RC̄Lz* v E=ʫ)5\+,ۖXnӖ3d = ^7pKdu\Ds, YbqZߏ憚4~QV^~[ǙA}Xjdu/P 9OK׏I?9#4ߗ:4'P )G#l">_v Z!q~OPRƬN3,#UL_u;vi5q5lU1GF @ŸԈzz#6Xy$-VWG3>'IJ ~ʨu+m q}'6t_YJ7Kҥ~mKM˧lLEwqBÒ@cShVGeiEo}"}Z$ȹ}A34GӾ98^aPWZͿ=s2qbL΢Ɨ@-:o cD?_#q>'jm.Wt{1?v &ϾxIO;}hSWw-Ufb>y"x46i&O3 BsVPKW;#26N5۬F°(+ yu)ߢ~•Zq?xr|ž89kV;f|.50]MUs${͑H}zV׶GsH" xc$Hӯ'q]01%X?Ya? ~i};[:2eD!zWe!&c)H O}^Ntƪ$j{y+O\I8 =x7⧫w|"w x(8_8ʒa\/=Ky%>'q=yޡXXesUh0 o0W 0["PCޖaM7IvI(/)` |K&hj|O} ۫ 5d%ިeaex3.zjc .X$wUⴤXK{2>,n!vQ=zPyZOg|vMS2LGaE%LkX3/ ؃z /'˶QWoZ_.:|_kHa>6%g|uUٸ y%dYJc#+2-Kְ%AOEמJ oWdmq[T+H47OsZE xp[5zW~$)7WVsٚLu#ݰ}DŽ0faX}b3iQuNK=> y/\R֟;3OIejb*u$H}UG/aEW<--Eupk+D{>f]&ذFߡ+_/G$y3t ީ! kdb&wt3-xHLq:?Yr]G$gOcs~# Rޖͼ,kOg\*]O)A#Ls׆vF9l@fOz&vZz#({cƮ؆p_#NfF lk_Q\v|ld۟ JHZ<T "KTf!/)^ZګOzfЯo<3WìVG.|&S{-?|!a s+j4_?9ʹ6Eu_g G aK(`O;Zd8~ VnD>Iz@om!Nľ/F⏎ֹ|#j[msJ8Q5].ѕ$4 Z0Gz7\|0 zt͠3 [SKSq6ilX>Co5Bߧs~Gބ&ln&{]Ŀ6m+lDhp;) >w>=}xD]0bIsz^蟸X6lj;Ap[Y׳<*:y?E"`6u8,P)+̲ci~ә|5oȶK?4BFa:۔\geg}%SORS^Ɏ/>nʈgK_,U3B-Uf^)q~~40ĥf-x q bw4wīqW>Wsx:5Sߣzz|w.i4EE[> ܋Avl{4SZ-OkQ+h^DUգa>155+^z} zWo/Lf G[''nF!xhFsb##z?h%SshwёKU]Py5>[wOCdMV_b686B}_ʊfHjNb^>X*LҲ-Je6'AZD82h/CҒbD J~םk~(WL>{YǽpG x;EqaZ F7uJ{iE~}̌w`#.'/f}^;^%1Sf:X[E(`C_lyz)f&b~Ek8ە8=1kVG4OwlAEl#xľfU!VNh@ÙQtjP`Skv ۿm>v.4ŀ@@`37xk**]F8).=UykM6E4^B_!W`?7KXj\?~+-L5%3n _^ҹ(c8/GF/h.Ȏj07Bb wP3/OUCHc6HO{ A'˯HUZ$8V{*/NЫ3vLGBf9uD^.Gn:i]nCt+ݱ25l4rٹzt:W攌xl858(ll_'gm o!wZ[MBn Ǘc Rz|<>Ӣ.v|U`|41S~d[4MsyNG^S .CMXpM_P3fHb˙6ÝfFW|ˇg=,=+!yݼJi]eɧ]8$'ȿ FVzGOꉂdEN% [T(z{:=Ƴkҝ?_rJJ9`6R=CSw9_/)34' ְ w͗qrZ?7VvyD/yV Jf}N7rLXL@d<¹FJʺQ [ϫ ߛ؝ \TYz[Q  $9I ⍟M6h vxqDJn _TF`"/h~gZu\=iczNJkHY2ژYw?,QS>j}> ٣k}q} x ~_ qo^.W?QdhpLB݁Khk/{?,W[,QNw85^`ƧzCNG5R I.6;z2RIԿH  @ *L¬b?,8n-=jz:i /o9g N,"u>ˀUsYTHJb\Mv?Amwt]~ ;x#Xl;?/)]g9f*m 0JW՝sлWt֐qW҉5?v8\L7$70aC|A9`|'>f`ķ)1bgA[o^K O䢨>}> ~+cZw||1 g9f=AGCzv׏Voqxf Ǿ-*O~>#W?<4X~՝e.y,FŅ}@3H39+qunFQ?Oǎ7K7>?bZ!N~C`1>Kcğu'oTl_Ŀ'+%Tn ߇a-aX'Xԛ#rոMH}mޘGף "~,xX> f=L@o>>#^4rBKʴL[P#Q8 t6޷]8ζά2tБ؍U ;^ԡصχ(FCK aO>/f`jtha+ *4=@;c)!dMqg4Ě<_~,jgt AQ OarE*<A5vƩ$ rz?g|Ȳ|<@46 Y3Rf۲0ݎsbu'_]2x߹ `륒wUG*<,0A\ť]?6&?|E\)0E}K·sێ89 UNAW_RȮ;̄>Ʌxx8kA{믌i}0vlS^D)mM3XjA/9K:G$b?@ﯜR>}c,sov'6]*ş~Ϳ:%߽o40x`Ը2A,ʵብ5QZjw5?ֿ3 $Gb"?p!z'oĩ*_=WHT(zÁ踘k,ÜSOt |cՅop(b&ãRWJ٪xÅk C=DP1o3U)'l7Lf%6XĠ@ q菳"?ĘAt vr915GH\COӓCO} g+VX3:fӨ=`_v~3jdwr:Ԩ?N5"R ^)vVqOh]1SV54K(fnNMx0c X,Xx\+v-Rkoh<̅4zcHp~{&]9- 9Z"`x6fIM| wj7kFx}"" (2ieɳDOջD[떢@,P» ISzV-~Pd?ek= f {h9;ia/{\e_W\Q/E݀i/g@dNlj=/Һ7E:,hz|zY!w'qu*qaeV7/ڍ6ݬCŝ ] >XOz8J]?cƩyHh[Vf/Zɇ "a !:+IڋnSI-*o׬Ԗ/H DW1xJ5&с0ڳqV_ǖ_t Zk;Ry 178QH}Ԍ\xL&$xdw SM;h v!KUl͕:>1TVk22PUMJRC%@c`ɘR)۽-blzO$c~ܐ ^-oAT1aamF3ɣeRA ˂FcA3e V85ڑE|j/(y/6ۣ{s;dg,}S}Th. UT/->6PX@Ms%[1o9I58=M E+ig; /xWvIE˧^ NZhw&H6=ڰ)_*~|Ͽ,'s~)$,~A8&_aUd|u҃Vψ7LiIܻs=^\YѫlhALuXv>З}qr{iuQ:ݢҹ?Uo M$[1tw%!X{rR_mtUA( %5LTȕ],!xq sTQ6~ſ|i^r\⠃-m9"UA:Y)])yw}&.WFUt{mZNfzt_TRV)Ծ=m1]Oٰf|ʶKETmjB=#*+ j7ԏ(g, N|}Ȫ"rbQ&й{i o6`>/G7F#J_$~;TESb #"Cf|`?z5)}trsPdNwb5C)tO)Bɸ\!*P8=v3.u=nbBOyCh<'l臃17nOlf=Ҁ]Ƿs΃1{6Z&19@(0jK^e/zBؗk6dڬHNT!x0kH H>KW9Ë3e儺oPs+0[ˋWWbe1A<H8&Џw;FAdOvpڇRI:: Q߯KڃkbD7'[#J?>_C~HZ3f}/z4V19d.DZ+yMk/gs W 3>b0>i~ڢIOBY3+9x/#:} ͷ,6~2&(%ułb69s޹߶?"s^HJP ֱ.u$Bm˾L :!eӾ:h֛Ht9Հҿ_ܓ<'ƾSm)b8~ϻ^fağoܿr|ۼV񷛉e'KEzU?zmu Zex!ng7Q8{C2`H޵7-Yz^pOv"3;KAv¾-Op}ؿone 53x=,w^שa ׂQz++ϡLKvMGa;[Ue9AwrsXB~ջ=V-h>i8QbCd$1?OZߕpc|Xsb /$"[O) U6|RM K׷fi$@Ƴgo6_)RJ13&,;?b[6y}YV?$cg"f=>^':UF\_lT|E:ɉ5gK$CAЛ [}o~WۋT< ~zW$` $-V? h:WOR{m̔9XIYN :ڀ _D {^!ZOb}36':%>ADN>뫇A`}|C N뜿~ 5ە&*y /Wˑ:蟭{׫2a_)I> $2$m1Pҿfh>3 a`@$jS)ٱɏa2ʫ)PEz:z緀;;>x J.}`!4jz̽U#Cnr1 sfOַ@;f<*c7~8:~WhM8>F'Es?|Z>iv\1}D7Ã?-'kg,a`}cqi7n6Mi%qpO^ʅKa#*>zDJgw#EeV /L?C-$0lAC1 ʵ2_ޑpCQ\\7|;/>jƋZXH6l/?d_aRZ:qpUg/_``Xi a:Hş i!u{ N>#M9*v)& |/ |փºw Uҹ\.+A{)m4|T0,U,|l>c&ie|)0 xYGk 8J})U段U^QY̔N֒hM׉{^<ӈfyAŒ]q?Jv A֤_=;ȩ1b)w_Iv4e|\#7zs#;/TU=D X4hMGbe+  2 Bp=pg]r)OFڭ~#4{ Z:}}9= gU[XLf,@ #hy>)pwЗ3wu?l^ʷ7{/]p._b4 9lF 8cVk7J7pƽK2)[ǰs.mq..#`= j޹y1k+줏avMo 0W}4GΛtXeowƤ2U{$=\ݚKD`=9 1* $;ǔi[4zƒñ.H g.t/9 =+k"dSu\N|%[Lt`pXX4n6*B!ĸmJ/< q: /<ۯNBT"aZ[%(P5>Z3ܥ_иw7_p9ð97- Zagk-Dqg͏we| ob,/f%[V /zGBI>-q9px8]Bzk`!$_,]hd7sKT{4N$xa(#ϙ7qg&̊$>za1/_ gǀ[< Uj]FŴ%7xx9XH|9Asz %ðzE,}|=V IOO[(c: 0vO'}{"#vb94Tc!:ƛ*1tdAr&X[z;H ֊#L8eQ34+gOzɿdoX65gg_4NLغR'8wӮ mWz=vor[ N>IZcJ/ $Ay}0+W~᲏ ȝ%JL#z:~^)Db{?ρR̼ZdPdC۱FD=|bF"B,>f<bA~6^|'z+ѮFt 3p5,Mx  :\> ɴXo2 (o??w]5[s{{h{8('"KZCx'_o}.ŝO^o ȗzXP$/N7QryRUnxF_ϛ@>盔3A<-{6KbգY#YY^0z_„`CaG0 l²Vti-.h|M);C>AۧMkผl+f?xoa L!"M-@=׎lK 2ݼ-?r43w [ Vv~B4'0 z{/<<9bv(NlTk͇yBmgNlq/7 5zו8&k*90y~"^>+fagp^o HP,n~?T+TmeR?1nύ2KVHU)Ke5Cl'pT|J#Z<L͊/~ǂRL5e zY/czFPԹo&C|p 5l  |/ ΄lS^ʴ-!wqsh-.E6f<ƊY_K;MQ&%3iTgd?)(7/@{ UCalՃ}n7"*lC&.f\ g x 3 M jI..}v*=Յ-B=?}ZiԛaAdVq TF;͙NO?ʽ>c([x8R2|ѷUz4_6f C6>|%DŸJz'xX엟RΧߺ!߮ej?Nؠ0W-C{ Zo1:lx8 P3pirjsDZ>'+(#L~]bԊFir샞Sy//3-+NN|/gP9\o"!9 F;bHݰf&c'ܝ:K]f&wh%nܱ@`Gzȓ؎>MzNJÒnQ9oE|=&2\RcaWp1zv z5Ǝ:Q(;P{(fwqwe5zh*!\"uaЗ+W|z W#*>}WLDwq yX/5|(8|ywc ʈ5s'+ I#x\@^x`fy*~"܏38rZFdd(OpeG/fCsM̬5.G23-W:3vgjjyUqoq LSxVn>y؛G2]f9ye ^–jn{R ᗲ ==a|Io,=L=Tё/'Si0 z"\MRdSVmHu=AfV?0cFj/*,'G{%|* 9|X{nԙ-t@*/ob_譒r;)eߴR#St ϞA LF]/,IS[W,/QUR)Ys xp>72"M0Ϝ|ŀ>7Y(^\&6ޮҗXzLj1i_/cX_H/6en]>)#<8(D_:@26}$l?pصj>'ڌ6Zg7婌<;dd筪{f>`dWgEhWݑdljݛR-otm4a<]kqES$<zM?2^:Nռ{$tS|+ps7dڰkWkOF  )kt+z ߇IUs6"koT~xu՜^ПvC9:…wWsrVқt2>ׂ:Owg Y 고~([? r)Z_Npv?$IȞ5!x@ߎsZqKlPp0Ox~:1t >\V^R54.G1C +Hy`-i;>'LoC Zx /">9g! :ate^H1_aU#*j9~Ok;zY^˧RgR^̪/v&ZO s,#oky5?U콻[L̏B[Fv.RE\hCɛo8l%LdcŞ ҋ-ww~9)}~p+0xwKֳxͦ=&n  Wdeg8tu7IjH4JDZ5r[]4zf/^8 @#}T% :u5AATOh~Kw$4˽Fӧx37C[3i!Z ؓ9b//Iҷe$cYgAtA7 x<zO|Caɕ+"/l G(nz9|Ba$C3 !Dx},F iQ^fAY>;o??&/N g':_--g,"m2q)(ߙ Z%롟G޿F ~[o:ɷ H"i:Z%ɠhnŹ?Wp _ww@oL\n>i!ܹ7ֽM'H,P})@mbeL=k_{ [;\!F' =ufr:KNOw!87 R ߢ 34L,#,"xN⟎ƻ9rX6}?*`<+ %vlC/x",hi{>{տ50i5/3g/GHD *eRfr?6H_*gq}n-l ,x e<t wR;j:팒w39:qc @b 3ė+PŬ:սo8XMv|컑jYHiI\nk[k<ی 8`Wbq6[$LEև^VemT){<Ͽ҃猠L~$PL|S!LPwcuƂO #z. SyyF )B33SO_V]rx{FGBN.D{7VBчN:8ۉz,/sm&h2v//=v*!<}p=m\+w?\䟴ˌ2OQfJ)s_% J/3_${wq+i5h_{5*G8D-`*,_Gsb`_|"q;S;39G`/Ȃ+ { 5#VrDW~5[]1zu9N'j(͊uCwQ ?Up M$z>^n>mL6 5_Wn`g+>S⏹iR:]BCZv.p?ع!İ^}t I ;k6)YӏB/Y `{,WaYw{V4 TWاˠxcc@;W@_fe=s%(ǔ1,㝁,;*h#O ][L)R"Y'jQ<'%'.H<$om %a,ar}{}`u3Y'D *t^4zsGAVu o'7vOa/7fwYh|AL&n??+Tk.&oF\P+ZD`?sS{g}tÌ8|;%dX_܆/蟌Tscy*K>STN|ﶁvl K- {/HQ!C:JJ? 5ʗ5}Qy֟q/~;VGj]ѳ?xo3?|X~}7Op{ػ۰AK.Uڹ2vDfZ n}T/^Gt o@Owз`yugj ° JkIRWu;$* -@8rܿ ޴f}m=Վ(%+Zlq䮄gKG;Q p:XwiXCtXlF%wl/:g,Xq} WɾM0XH\8{8OZnP2˝ $9#ܤɀ\?9D=pP#3lG`RsE}~ї\Kga_;ȭ[h\Prh~c?~{`ٲ'$)ceeynUiIqWzRzPc z5wY*7TVryԽ%@oy3yKMA/@wC]*Nc_ky)"ES ֥Kkz?S{2:i E)\wN=wҞl75ZRr.3n XV.%%7Xj:-n Hv>@);W{Y or'eq8~2ݒmSxs#߲_RDuׇ;>_:U N 7jp䨈;(YqSS#yK%|)ӆKitNDcJ#6.}8<@Қ&bNSv~s'֠>.Ivs.Gš: }G$9*S~*#Sܺ\Ã9Ńx~t>wkމ ?Kq՛W{"w@ί z섥)mhCپ7ݾs5QW`-?\9/OKJ<6_3LV6υVͣ+U~qI*BI-[_ yIE%QoŢ'z//_CgޤyXЋe~[oXɟ -=5Z. ReXJiyۅmVLͥ7Lb\VHX>nQC3 Xa xupz>tӝW=փ$vκ ?q{PYe΍)i'">ϯ;*L[}K D =X:#{SVnp!dgFxhK 6 |2#xFBVj8[,a"8Ŀly!_="K5EׯG48/ZNuLK> iGՑuA K~{oGK6$~X1 *^E3>zDoac-|Pypx5/\ih"A cui>O^ڴՅώɟ}%+CICGL xBv`.~5Z͡*[ڰ(!*Qmг~n FOblO!xmP+H}dlWByH߾Q{ow9q%C T1 =DzwY+oENtDj!iEvoTu;3h) -?1kMm“U#{9^!YO:ԟJ-\;4z%a^Y}c)MxinT!BϾ6}fŐzXekbDhDa2$=Lvd;ؼ%;&7s?yPDXF\G >h?aȨbGkIFE>QJ ؄S8ZjjH~=l`=NZ *`'IK̠JKo;tB 㞑L%fwV+Dۘ3[i{(c89R+f}얍q8S*2DccoRjDޒ|p}A a Ae픮ޫK$?z9;CZViᱏW ,.H}wL_C.%IsLkp6P X<@8:hJ1q~W%K`.葮~uؐD\3+Qo7Q]wy `Å-5o| 5.~W?Z6!n[| ΦW7 F,gH(@[Kއraͩ#]A榡P 7Gz>095GLP';ή7"/]ZζR4(;BZƧ _P6_P$k2u4Nj աqU1#$_<@㏮E &3Ӡәyg‰"OY3A aeoay0>ه[$UkgtY|-@K .@~} GTD37T  m1v*R6.@q B\=T {>?rn*uG|>/GyrH6|=[q80x@JąEq>fαK {$XzƬCӘ^53!qr =#wŻ"1g  ^FU?'<`&T܍,Ï6>]NShU."[ADsll~@_L1+^*#0R}[#3I_ٔA>Ň%%^m8𯵺ŻZzDQ!ĆgBҒ W+mayװ%GOFЬl<@P+jrħ轩r-g,-<.pT<^O劧IWڟF4Yy'%C(ޕ>W Vsߦ@-GGNх-$9VoNm{ Iz_9ۑ}un8ȉOȐgOl9/ "kX}1̷pr7MXSa۹2g~FǃfkQy(fo˹^`.Q ]h)qkEwV$?3^©?2S}@ d)Y6Q{Lhk5ұ;73y`<1!7Q vG_O čV[+'jWEpL)Kp#x ֟|fܱ۳$)\IoYbڗGq} qU30U KޒbMًLiUTF+*x$%> U>ʱX_  >S7MAs>]_핌mO} D]}q[ юG c.I/HyUy=:sG{s*{3JNe.* 25(+H*9/9sOrϼ?/o˭ R B v*(Z,YPU_Uw3N2Mm)2@"c>p~]E!8 'y}P jmEJqwb]?2/d/'6 OrR'#>,?,JH8X1YA'Zɫ| `o_n(k!$93N[;vOiU}_}k!`|x."(:HU?-h{:iE)3Cߴޛ\?s C#|P@_׋|ґkQG\$I XVY͋Y$X.x t ǃ/SxX^&N hyal?ɔíKIW ^Y.e1[a!OM ['M"ģT TrP~o?tz$%1igh,i$a_ŹE]wxo?޽vv䯪wHmwudfTP((]j({}dqj C@_eHr-y|t8zSK>9KvJ6ăY:{`}4벿8k&A ?򓳙+F2o_=(XF=/Xw*/7-v[6<:e̾ RgĠxH}ǰ3̕oTsNP:h.l+*@cx`G_w *Z[{t*IJ4CDvx}!{ ?1)['C<w8'ݖHm#\[u>w\@ޟvfsz)Zϔrulkr"ko0{62_O~0|:v0R#g!Vj1T+^&Gn*"{xjO\ zZ˶4ѿkYC!_xJ`})Ku*<nx#tkBQu6#QϿytkzAJ&@sG5k37XJTٍQhck`}=`{1Y"'p٣sY-.TN(+->F=~H8_BFDŵ3Juz/^|!I$`YNGrGTd%vf+YE."`xG0ngəBr齽SSWwj;cT[g6'<^K;yŞOHml7*06(&/I]9BKV{5!@[>{xDkgS:-|IT\1&uXw~A+!'Pj .RRBWI '?w7;}!G@>*>Uк1xiO:7:|V|pZGn40_850>a2Bz"[}eSQwq^k`%u5TZ +t6M$d)j"+^׭%1}kO?ص|y߫ zgJ_nb7, rznK#yp•%KROx!T_{?_y`*Z,>A˿mU%Oc0c2{ s<9hu?t;_Uڮeo'cuy X<xXceۏ"@TjJ@K:O)0)fq;("OE׿``D{" 7oSLWn-2+$P N)Ƶo/q?굝 <5CAJ8-u$|\ď}_3?sAF4A<>4t7@F{/"x9n&id}^ƮÓ% 3-;BY2ke +`;NxNצ w?{0يX.η͢E7O0~oXCP2c揧NWÛ+*5Nq4.4.a(DU gށ\? gsvaC|\ F^G|3{Wd9ixl&r_ޱ:!v؁c OW=/ rTr+iZapʑN<%,5քuk3e3n)̸6}%wS% I7y?sNWV#|OW}eP3fQy[o1~b^4^GwJޣrt9DeC!}ݥE}$t}3Kg| [k'"ex>ᮍB `zJx4wñk)<ĭUĘ7A.|~N4-,AXn0?VABXzFoee ({xCL;dACҁ:ͧWNMueQni>fȢ 2^qCցbgVϟɫb Ve|)`bۋRp E/3Z5[Pj %{ щ nKP*v^ł}aX.lQ< }K9\]ٻq&E}6sZB_:[ƌ[~_9F;5\|=Ղ}0WI=qR qxGAk2;_Vb}eLZn`_+%@xNښ_|Fb4-DB=1ŸZC=k&hە 7CI($]̀k<@$@+7Y#] 9Wy3!:QLf7]m׀oOQW@vכoWE| h wjsbʅAe"UätRӇ;vȍS/(Xbgh=%|O7_r_ZA{hd-_I2_⽀7!͇.C"RS+ҏ!~[2Vz&tٝGɱ"{>_[a h2){1?Z;nSQ4 g/F2h=RVL>-ngjP31eVbm_#7k`~Y[`A};2"9_TQ@ӑwUQ<xgwR\ [_ߙ Ŭ3N+ zI⣻c/YĜRfzjy~-޵=2}oKlGs#.2D͎Q>KJ[3?>TH|ED$.%>E7qCGDzTVbvd5`' w>0 _R=AlSyH[a'oL4_䗟F0UMxѹ;D9zܥ/hۢǩHl+{q"t/gxTHx Brw;vS1P'")~\?iC"I)xYButY!(BؼyQ <߿'MDyU'.A`]#|Z`-D^@5@J6|a[d dΊQ7>^f[=ocZ|I)x{lhB*ׯVXXe=-_}Db ? Vx> n>;X8+N6|3ѳU5فkvRHTr22zx*ߪӃlfϜj{pAa؈'-0{Axg7 x76s}'nV$6Vm5 _lS` 7~ vɩqS,k܇aN)G<"^KSk/Fn ho >F&d agqm=i(OI? ^4Cx~,6mZD320?'yN%uXd<F*Ȅ_8h|Zpji)2j8/;};o gD\|zhy“1n7eh\Lqzn {ů(+gel}+⑄W@ih w:N>7O(c|K)ߐZ T?lKv*]aaxdXalx-%ף×p?2Q*.Xt & @=|~-zweOO #P֤#"VS$c"w_B25P%~χ SLFnV)~o`;߃tm7ݔxwP r0~Vd4=xL&f䕣rj DFWBu ^Oc}$~'Zݏ0TWϹGWz=ƝE" sX=r:ǸoXV^h7Y(?KK"Qܟ".Fr`M_ޏLA^ ҚJ^Bė~O[ݣ3*[Ok>?VNG#m;tqE>X|b=˜1{CUE@!-Ǎ 5dU# w{ ;nݗo䦟;,_aG2 .%_c, Ksϊtgway}7'mZ(rڥYi3YO#x^ۢsmn]c y`Ֆ/ '9I;'~C`;Q+nGHF3D[sƃ21_~eM9G;|pSlՂ8Շ4#|E˻'KSQ&Hf_'Dd5{*x,`?軪x}/c?\e.SsծŎ|n7V1}BpM4副kjig0}u z% W~)\~oM;,o$5k5|EDXD7aY_ l OȱxbW$[.:V:N&;ցut@)ސN3ĕW |>b'\-˰v_"{\eVQŶxL70A$?oIc|7A/CWA^f -p4s3S`e-:lX:[ Ry~?w+KF: n?%X.y:Z![5Bs;>?׽y w^HSA4gΣ?ļU$9|?UX[N6{5z,;vy;"֩(61>0 NO|2%yDE[wk7;Q F)0ugTݑzq,Z]#^qGIbhKW{/btcdz rqx1ّ=GKYۛ"Ns:k@oWևٿ`?=+0_ڟi$~NX˜Cԫb+ rˤH]8E²>M=|_h9Ȓڇy/坔vw#&$S>Ci!V72&JޮvGHdaaf./7,,m_7Oݡ甦L~ҳsIb~b|H RaUh4eVƊF\Su(n,ŋ}/`}TiӮ:pE}K.!hF^zO֚ ONxuVC?0g2ȿc/V^ɛP/6b.]GR5Nl@ cXou" )"9F:yE[XnJ |Q0ߣ^?E ̗/#:O^L3U* gP_Rz B[l]X|vj= HQ46 b]W *"[n^~ӯ}KpMtV|P=5Vj.fcZ1^, A OP.y9Fm|?qh=,]N U[diqkûwH\EUĖ=Eag}ɠoLvi%-0:wsqc;{%AJm\@KC&t39[Nv#~W9kX|, `\[?蚚Ȍ jNc٤ϖ)^d8Dfuxw8sqkZ"˹Տ [W+\3 @DD/?6F^j"N]w۞!T2׾M~~,IG?fqҴ~e)ci׊ճ&nc*b,WQzYtGl Yv.XӾ+)cXSp!<1/wqAZ)Ti}m_hsS4sZDF &i$cngXzў2jV͌_UjX*MUNDR҃xBZw&0pqz;~'l8nOGHkެ0C@+6Fֈ.hnJ87>\%HͲy ޢ OJÔw0>[ {m@o?8K]0' <#f˗7д,׉[US !+ڮ}ןAq:*f[ݏ~\~#,Jƶ봣{_k*{ZA=|=E>b m6aA Ͳ;0~o+s|a!CNZ^$K]ֿpKI_壣0{v+K:\4A\9,{;y3j솇Bm躗hDЛby<=']@cmĦ` 5*[ewǵQuc _oho(X>z-?~vmkIЕ1P:ȵʔ;~ևh~4 ;iҪ$[WHa{/< O' (v*{r-hfgOjV y Z<89|@Di<=ܗ-٬yBv`xX; zf(>^@!ժ!Cb(-N?/ 63+eNGKgCf%z(hB||>9d };~""YŻ[?5qyxhh8JsfI/}$ =0hh{Y67Dor¿e.nWc$Dx7x]zq] 'lۿp5:B+ݸG?S|%\7flf6>]WwFE 7ͣ `| x,ݒysCfO/܄ܹrb(-DTW_9 E >&^t7sZH)\h 1=G/{h;T[=? Bud OU *x!x76Kx#g:"{ɏ ZzLchlws}{ OW(Tms4/g$%윥ysZ\FWGq{>mzJQI(kdXALy_s cvJ~ZDr@}GPA}M4--lvaIÏ=܌*Bm蹅Ck 4=c|I]7*Ei]ZU,^ ,a=Vލ+j4a'ȐpO^$Cf/U;O a` ߯szۦ+g"uzFI4ݡ];w<AM0^(ЯqΎ͸RZ/2"IZkݯ k~^sG@ ;!||_D?bkfcztcهx,{`<ãx7)߅%=H'U_:?{f10{^ ۤ! CǮ R}J6,zF6$kJU<-Q}ύ c|zh祅p6%(\IAGA)0Op_eZ8QLZEw lޕdRedIxJ+Uo " B0!]pb xr5=U#WQrWw|4Gߒ8MR++~w3^>PsޝaOy!42GV*P{f1% υS0 HH <͵b_aqpu97V!l6VKIuZ^RGӤԗ_>S ЇL\U^x} 1=6Xwlv I4t (ª:1ۻY]?&NzS~6m,Ԙ/¿ Ҁo泩hz[k_-Ž'[u D)9 GZoD< ϥV jÅJB4S5+/⩑x=X(j]./b/:g_I:Uh1 H,X &}qe^ݻQ~T~ͦsx?{ -[]sX%; ɮ> DZ>[8|_O|> ''I'ہ>E)6 >db$IjN yWE禅w@ޝ| |IJf^.׬v#.(^ܫbG`ƃyﲦ9W¨8,n6>ٳ7𕔍yZ8|3JN`xi`"Cd=ծA< >$(;$тA٣[mi"e!T=w ׹ood7ZOK?AZX! mcӰCXEri'^P uIזS{\${K{zC I_Xgr_'oE:ϺH|+ؒ@1As$r1Uyߎ?/|Ij/4>+HDQsH-feH'Gx%y=sC3??z3\╒'m|˄t%'jx$;4VV{2ZxW=57h}0|}&ooKZ뜝纖tݟVsiٶ 1 '!U|Z ŞGO+i|23ZwVjҊglD'jS^b|ȦȾ?]cܻqH˽@~]lǨKk*1}ލ1C瘃iw >=xK y sY/}34'=N< >p"c^Ga7ţbhĶI,z>tp%rU`n$v> u R0<?j6 *9Sy>+$u4^jjs:*=[x|q9y4nwE BكxzO<5A@z:m.|: >EOf1dR`Dhd܅/c$3 =>(]$D}aq~DŽ΢E ;­meӝ,ZxhZO>sM ~_z/qqŴX|6{Io(h%6P^>vOIM/Dɑ|`~76#'&+wBDqP|~h>͡nͶތYMXe?w~z%>>6ПhN'[xԮf^?C(b˪g݂mZN5J翴K1dny(9Zx|<K=ik鿊o+I@>S {tKW啫 *>ڬ> \[%:>sfE/ϠxW7|0J艗Bo8TXA_PhgTWY#܏rx} ;Sp qlį3Kk>Sg61dɟ.X@>= Qf9DQݘWp>{4M*Vmn/U]=*CևΫf+yl8߲ƣdߵO^t HPF5Jw9Μ5IL!gQ9JDITA=j 0z>]N.)QձGe&c9e YpU8 .VG ]( Sނv/] ܪcu͗BO+1L)""\}Mou<[9cF~ꉏAZ<,,^%;abiϹҦe6 ?`|o&c+4|ݥYޮLKY6*#Ћ+>xt4ԭ$8>{ܺ/~gَ3r`VZq@1`%_Xy zN-ևF\>қs?)~!SgV'~ OgHVvNE0 MѠ ;\lM 4I|L/NIiX39bY޳ =|(T ݼ~uK¿$?e ض=tcˆu?Fx ׏Bw;oFլ3+GN:MQW9D |J0j#`{'C=vۦͧbn[S>}5LJi1*xAnލ m!LB!DzR?s%gCL&>z wM#UG\5i036X<8hld~8rj\E[P'ُ3^a\Wm#%4?[!q4ƬLUFB9ZoCdY|+o Zt\B1Udt?5]mpkٌq*Lo/F߱I1Nv"s1Œιs)5=W>N3%rW!-]_+P")={]9FrH;GS&n+WТyYCh$,NT_~Ib{ֆoLׯÍ?>3=V/>u%=r5_bIJz]>rG޷Q(>pD=CUH-6Ծև %apQ=q/3(( ^'>~e+_)j–ƫjFH_zPFto{DfȊ{ѓj53%{[L3ss 5O©?0w9`< &~%_]`ߟg*$Jޏvg~_eեGUUKCh)aȹ[1a]Y+/TtgE ]NRΧKhi{Q0~g'GR`|}}{sz%vqĢsVvMk\H_c냅2a)2GE2;gYV˧nVX=c&0{7/fqS'':'uo=<1FXx9~ ]_:h}?<E=/DŴ39Y}?JXKcF)C(.n<&ّ/ <1ri9Uϗ>Rh2Ch 4uSCx ^oj?ߋ @t ! DPNWUff̼6-?QɱdSGb$$R>;0gi[\֋0_맥wG9}Vok|:u3;'7X|KPZ<ˢb:U4kM _d/FAP /ͮz% yb"'E,d:K0̲!Z46\v5 tLkvcNfOh붢)">r>nuDrbKѓ' ~x} a|z ox{;K}\_U0w^w4}fۘ?3[7=?a3wqbٿ#%ʔו1=8mս PviWL?10vwL:yT\kV YfuW|QzrtE7ikI=;uT',lsY*wb)|nȪ<00Y'IkXKqxѻϠ :۳]wv:o49sښQvdG߃(c||xO88:9zv_Ri}:ۮGz3t'U.(m}#B716$TK40e,ZhkF7+j>+ ?1?7֩X1OCW=jyۈ9A*CM rg>ɯ.܈\Wj-8+ʓ|8BY~I?P[,yldVNM Of̷ꜣ6Wca[aM8 ΃px=`d:1?ȭ n%/A$c,1~ujS{kOToppލz$+UX}+q CU}/O^l0"FvfU$$r+|m`ԂLU𙓣k֮\MFIVigyq$gHRNNZ8,&-ɘ m8!tO^~HHEe_gʎ[U&ի>Ob+KEsţhy@_󍴂VpwdUIiz`RL(w|xO*ڟbߡ 6JeG\IGa*>& ~ .Y%͋k٬ޕ2wu ]Eޏ>(w^8/۶;O$=cujy;|^x AZT ^e^8zk&dRI*ұeO+r9js.T8D'A hQt3{.Ur l רObC `;Qޔ͵>Yd;yt48kIV^77BgC IR| `>_2~VeFLm|D'yAӵ,J} PA/LL`]ᩀwarp˝65"wAʄQʕTkLFoocL$ 5n e1"Gnl_M|H{ߣE1@[@^@qWBE2UV3d#I.BOb P<6 ./ 9z e$ϴoey*}# J$4k|˿\+"˫|)*tB%zP]NwB~&QKC͜.UIv9૊?]XUWO7@U4}$RgIس5sA~!RĿ%=u@kOUL,#Zb FB˞K+?i<"ŶZnͻV@'8uNb>MH ^VCifqsA'ܭ}OD(B=5ˌc,ՓF_W(;L_H93lW<) qWBM^ Xj`$@oXoX{vk$ZXJ~r硁uEAH7,H= ss= ZePP<+ˤcOn݋FFʖ͸gĆڟK _Vi-x1%v {Hu[<]07 <xRXl:-klm_sg$ڻ́?%, lsݒ4{gRQcUQ!$Zi$HLĖD+- ̾ e(R&3P<^+Cvqwzg{'ђcǷ[Tk)!kqA만:8~?su݉8EI=-(GɛnlG'ᵼ¥)>7רFTm`|>B \m6HPj`|qӫ+I.(#>SȗЩW sʛˏުVɿW 5w5|xO|xy^p7tc.NFzRVԱE|KbMU w3AɏÛyI-BȧB-s6J컠lF*$cm@wÅ#,gv_Tb8KQр+|Ljy V(qhO=[Cc >0Axn'AӝυWEib;S%$8;Qe8=o Ο&ÿn|M9 ]@\2ӟKDI^weT1n$_\H>$"Sg r gM@JH$$,vǞj=Q_e2 ;(4?}xU 3#9G |bȖR<K.Gu؏-'N|$7v|R;mNr~y׿!0_ʱ]:x{2,G+d.$bq4 o7ׄ W 3^Gx bMilF7x#4{em|_;=I~Z {eJb ?/{1z^P9,{'W.׳<4քlsZhqx`4v?0Hgݘ EVg?h~q|70FM(b+2\ΰ}xFO܃U, t~m͗,%Ar<3^GLq>UpDEܬ}al>'+EM `wc&5enp&PU`+̧=Švyp~ *+9Q uncZrWQ Ky/C8;~y*_YNIڨ׷VT}\y-OA5WPjy5DZuxtkNv ylt2l7I=dL[WC ZО]䛊+E mS" <saC '/Q!fy3SUQx$qWgJjj^L~J o倠 0a%'2mƝL{PrOXa| *z>Ǐ/y^D7V.\4>S7;Y/.ԊKU@b1CӶh G'ŵdka)sx:^(zo%sr扮$5XoxC4{#a#M"/FӃq$^m bf~a|ҝ _Pm7}X-GEJԷ(+Y<Ç-2J/?l5IcۄT }XKSy=;D/|O cк3s-R GSBOiԣ᭩6ϋwx@$oXҜvK[qy\C N;Af. ZO&~<]1+1Or| uAG7#҂wG0Oޫ=PQ1YStF\:!;2;'~h|9P? >ojFS^~j#ǎ+{H px h8[)gDPr/Lro$'\ /d⡪@ _='Kʻj|C|X7&Bތ0<SXoTg?Tomt?BS$.l,}y:DD^ ݙ;tXZL&RdW PϘ6?;[kT)|>~]nk<{ 3X!nJQ ]qyNZO0>#Ró&&r֋(-Gg7X?ߠzڟqm,ɉȶӛe.SBY( }gxOdxbwz#J,_ 3I_1tU^.GC> C|o'g35n)?#ᫌ(e0!"\( 䃵PG19xZ.VcQݬ -Aޔ#F-~S(NAgLRV%kRhyR8u Fg\ߺ ^NQ >dW5rNK ??JuW*\y0B[w}iJ;XF{mH*Ig-+..]}Vl~|6 l)(?¦O+%"2 sgݪ"Y']90h9;L#M7J z6o,yKP[NM&Wt7T֚͑Wo\N:>EZZǦz+yϋ^MXb쮧y[ݫϏX\XҾz~0vPO+O@WnTsqY~q'~/%5Yd/H5'js^> Ub?npok4KX|"\Pc6/4VRfQ  `9𔓃ߣ5^B\r7}ҋ4CѶݙDYv1S3xn!ydrqOw:(l5ܴ?] ReQpG`GfիUΆg/"OF1VD,=-:?8}%w |C?WJ_I3GFy F˓Z'}#V$$c=|KAK3 דLH:IȜw??8ߴ\R~U$ΕӝůP8k \Z']U= lӓwWWdӢ!-vP.J-}xOpd8T} 4/7oq.\0+|ѪOt:B*Mi7NHcAA2Cށ`TUeJȪJ.:QJӟ'qA̽g @UV/ ^cbA;_NVφ!OIa2jJ)M2:JBO ^Ӱػ3׿ rwѻ_H4Em#I~6͖-2{sW WYPlU^OLӓξnyuFBvOz@䲃xF\L@+r|qRm='.T2;5 '!E! `|+]R,_[*y9n;Jq|R75u?|fq`U>;W yV2YC}K=T4zo=L: (5^LkdG 3΀W`e c*{q;{!k}~8|>K{7VYZL睐D7MKjhxWq͒S/iPEsʀ|VlͨpU\HUY.5Yzp={${5$ 7 gjEE=d; djeN7gtuT,׫?ED1=pMмꕂ0e^짏ƀ?B8E-Xh}k9ġV4qŃnqNj5<aDT]p?w_Xv_Fi'@.!_y:}Ynjmx$?KPOX<'VTf SbLGdQ((iՏ`/XB'b}C4]3Ήw IXɁCSP0_*2u>RLE\pY8C`ףǾw%k_q@_19 >G؊J%_?hgX\Dω%J2>o68_.2E"sXpx"X8PKQHET6Ffҽ'Py K_髆t[H˰ȅ [LV\乹Q(^)!oWjoþc|Evu5Ӧυ칕$a珋>:0q<6ϑv񿖮 ݶ01胔dG3Pyey$xP~ K~ShonVo!܇+IZ&>4/b_5eq уeb.UțwnzXPEǃƿĘ- n4F@5o5n'}߇ X< `/N|Do:; +ލ N%E$ ^VWNw#Ⱥ,5 ?;ϟ NMJen0¸d}r!wu&,IuݎW *<h%DO7Q&|{g4% SPBr60ߔ@<-~Y>/KǬf1 '+.ъ}>zWX`$PaWʗ*ž[>TpMǑ|WT-C+H?`] Om?* 'ZO%o4c+?m-TUfJ'i,$'L_Aw  傈s~FtqTK2A?ZYxclĵ;ڀOEểlFms??v0 ko(nCoUf/4w}qEk\V{ ;@GW[5z'(t{?ыu \VE={5 oy1Яx  n=W1 YE(WG[4^>j"N$SMx{nՑrS D}AǼBj=utX<:X6'P{\^=Mc1q엝ԁ3 G&Ecˍ仰/-Oh4gm;JW}gGFy(aJ^zY.K .ༀ/a O`2}םHag#g&2LJ ֡Guv[Te|w;}ͯx[cG:3JxdaZetԠ !WqUdj#ޤlZ\g;Wv4#((|>[7o4^`:ä>4Bh+S^͒;!d?_Vc㔋GT0;u&B]sk 봟< VuEo/ Dk,ZtVGۉBuˆu7!+J$F>fDh>Ato'XSʮ9m{[\TU~>E oFfw:.XN-y5/%Cf/݄ FUAXFxB&+3/f95`}$&*Uuc|q19=W^?Ձz&j{7Q?b?#4Mn O'K7*>L{߹>~\'?@'%K1؋Ew$?SSog;$$F*~(->{"Ūu)u%+435AnZc| &MyR Q0 XZs\88ۍ/x,pwH yfu>/z'%1v\E/7:oZ`)!y Tq; Z  W'6Xxye1{_((Yb?A= BA4>*A N䉋Zd/ {_P:xX%qG(|lkwd6AET7)uݎw͚g9+mbH=ra|3 7q;7S3_3;3W|^;'oAbLO &n<^5[-sϳYX] vK,_vNHp ?1r]ljI]J_8oqпqv jHrv?vXJ˶؁5cHDo(BCwnŏry%۽3u}`1N0#EQXSVVqe{맬d_SKj=SR$kҥǘ9jX~ܷ~Ofc'?hH8uޔR #sqU}ܔgjY/Xqo4s.IAu57ijj,tj4򷶹@>A+tk"orOEv ~B9l4a~xU}YC9ǽU~@5HxtlS*#w)zΡxW=@նGZct94d9 7+2q(R&΃U| Јq|e=)9h?BV9Mcؘ qj bK|7+=BtGD'fo9̙%οy@^A!Έ@Yt/;umem1ԫ?NI'AJ `yfZS8]<)g!SC [oF`=~^' ?}LGZF~x z7=f^}<@]Qz[U'9A<9q/*=98V}ؒ*s DqbȮRέeOGX~.F"hDtz|tq7v,|\@ﺠ4ni~+Jmngzr"vEvW+롚'Of^ lfkAÐ =1hxWEMɧV~.x٣ǸsL-K&xɤ_Ϋ7 k?@6X|yH\JW^#|r3) ,q%(9Bh^|Xp/5YTG1wo<m3akFj4E( Ub!-YȆ yڒbA^1~$^ Cz~.&cr}=%ߩPD{QWSş@Ko5M 8hG '{:1üqE)JrW?_Q9y#s=7gcޞVÆ߻\ryi:RW'\(W> vypL[b~D!ܨ: 7'ٵm@0Tlu M'DbpY|ˠZW~5({ 3['^CXGW,x x]]v`ٯJs+w-_gM`~lOAnT5 4Iy"*gCEmbۻS3CZ<' ,)'97 i8KҦ]G4=9!ei[ :wƫ^ f3YM٩P*7>zZ5:)m%}0o|Tn;/D a0<*>Zڃx )?}m^~v oi/20; զTU%fXD:KQޓ\,H4ۦMIEځx^1 [)xz7F+y|(xpUƫfsfB=p?!؋}F oC޹F(GyWߨ?&O9bxUxhG;z\^U^y]\d}>l⯐|C$>' KFyA;w,^֙ ޾p~?߄ ~?:p^-^dld {"p9sPڼpXkJ+ߵo~ w!|19UuLj͉%X86}tu~ k !o$r$Ur5r瘒Dpk7Qwϛ vw›͐= 9넷BbU@LP<Rxw-M{~yvlSYybBFJCPߊ 8y*z]<:_HqV  7*5~V+{Ec H,f:cC})1}%.̀8[ޮ/f,#(úէn{v ZRT?yl&bqk|TUnaH,U>(aF_i)j) HcYGY,܇Z[ tw)~9p/2}Gؓ.)K5Q3Y|OOj߉Z̟S2q@cU =ƘB!L Wɠ};Xݜ!B9bxOi1^?HQנּg:La}i_MTtZ16a9F7.vy7_U~~cG*XѸXM5g~猞'`{@|b >>-TcԯkZ;3\}tyJ+3!V֬Ǣ`.*z߁gip^U烹zNZ3W ަH#fBt>_b| >6ȧr:S}[˷\]{3b&- eߞkT9w)71b4{^Z;~5\My /xK9u|-CԳT).:嫍cmx-΍r>RD[?5 W<^&Mqm߱½~ӱ')r/\g~ :fQX}+;fx}? <ޒy_=db'[2G5 +/Cxb0_d$u+G%(uA%7S\_A8h-@k[ZyZTI"΋鍊g$)2%իDȃmJ2rJ| 9|JSeAWMġ_;ihEsߙsSnMhu 6v]9{`C5"c;Ń׿FOO-fs.?DA^:? |rm>,<Zu.(%5iuka>u_ϡ6,` 1u`̀3cxnIM-ُIŹ'cwg{|缰0yX>e(΁V|(mԎЈ{ т|,4ƃ~[FUr WoG{^>~w]ͨk˟FvoNXgJ O: 7=9zȠ.&uz{ci;D'by5Kp`^ܙ8Hi`vaVx@L'7"" ,Ჵ!V5Gj'2ZbuVU$XǵUw4Nb"E60`{ZVn.[Nb,O}p){e(ԁP6(;|zܽ۲*ۇ_(PzU{+qp#SIgթOD,]&Ca&V׻=N=/4w'&^|~\0II Sqp4Ik`>nN)O݀-ŏRBuQEܺ4;2"^RcmvmB:f?@zD'l85-ב4i'D,Ws, E?-yuV8COMk?n^?͌(R)Kg@pAeӟuUW`yMA|'ok{ 9XK"IDQxXKDxL.j;>CMxݿ*A ecx0!ϢP>}|652999h=B|J/+i12-$IwL;@7X|B r{t('wkW:7M|>d֗.B!ý >X K-8mj E9qƷG ?GϟZRjߞ=lHIjߨbrCHɡxQ>{L;Ԏ 'I^q!4 &+X" Hx}F=%?AlzRgٓG[jLׄO+ޟ2 Z)EBRtzyxEo9Az%u#ֱ+ oxL $">:Uy',5WP3QLv / !%|Xcjȁo CE=kdE`;p' j OeKýο'yr%4Won@tDkN-ʹ|Z;_+h1$'룍^)jMmh%l@5m>ϟxoo x6.L~XS8Η.xYH 4XgV}nw:űC2E.3 z3룩n豓! ǨLϬz2sy5{ #bpo $̖hZ>uܺAJpQ,vAv?Y0ZOJW,W7_K[txRYd|k wߨluRns!%w %]S[ mƂۊ:(3ɣim4_.3No߿_T瓀cw,9TA:Z.|Rկ*XSϻS"/L?m!VBX:2)K]yA3*O0)`}#?pkm|ϝ,Lhߟ!6> Z|ޛ֪b[-oz$πo8T/4 > ebW+T||4`J_z3GS&J re&w_ϵQT^?!oM{7>7UHT[nlN9]!Fs˰*|IϗP0_~n}T7̟^];W?TF!+IAV압U>^-{DFf&Y s> u=\9ϼםؾmCg0{>|5U%42ݞHI:nnK%W֍焳 YL5&HSzR  I31e[/x{#kNL^]z(;GnOܧdEHPBܵ4& bKyP#k A&6f;1h`<B3 t#L}VH&|Y+ ? oFT=AۇlpGKvcg~yOTf@/VNLQ<'̈_xe;ϒ`L$2*=<ŒlQa5FojY4$^%|[J3B/$%Ųo3҅X]%+WG<#bEONŃO)}ܾH@SQiۋ(Iv$h1q|q"Ɨ1(KpYO{}槞H:~J*iz׻ xv|U NARGԻ-O;/eOu8} _0?t[5s&CXcu3->TF D3j4=}!9EGoͺ4e{7fuq,?,·0GG2XoOeH *QM ,T?@(t݌m-` :/e~0>|A2{c,WїCc( DS9/J) G5A>hI\]6TtAjT ׃ x9末W2?CX͗NPcʍJוE&Iߌ6YLq♵5ڝwlJ4WzQ'^xХ]ygsk 7Q؆U@ &22~?E5?!WbTkϹMBYkgQ_nӝ|4djlI^ΩoV Oi>.աx6ErA7 \j$T12%ҋ:d'?3wc%b8C|.}& ᴟFPW(z4,Brq#|r Ƚ`ULgͿB;fȦ756%s~m @м#ׇo񠽰EDSnjG;c$DAtw% g~Y}e}}ujM^oX<9;q>'HBG|9'% F]RH?S. ND*(,y@%<˧{lϞ6 _RْKd;sD=xKCe9,AP YmpɠMD4*fq{aH&$cT%ҦoHUS5_ $m/()󱯍Wܢ'ŎG w6qeMW[~HY@٤n]6|^n@LE%Ğ2C$u}Z5>J [I;U*OerTLa+//cx}ȧge/&W[mpNC6!eGXGp, w,xA 染𦶴e㤵,HwfJh*h_0is+Uꦓ(5n X`_}XKw|_iCj;l*p5vNhFv,6 BP*dqx{Xex&Arn_-Ocl;R-$7ؙI^]Rr;t - Gl>ǘrK]נڛ[FSgVH_d](_ԆO-4ok#5-UGMOo1B_oϫ^M/?{~ݍv/ s$.F)ϗ6B!znVt| 戼}q7ϑ.`?CQkWSK95!'C\/5z(G]O[EJax'p$}˚ދ;'c2Q|^JdV(޽`> x0cTޏM*B5]7Fz;RM`IC( `}* L';-ٙ 2te~aԈ=[.S ;;Plq4ŋhI|}Ƶy>5۪6K79UO:\GEiਦ}^;ab˻y"t̶Ų !\S;fصL?8aɈx=$j'o/ Z?/MuU',/x@Fa{wo̪25X34sӋScy}{[ ܭ4>}1l}&89=Yo%OH8!;Oe)\+t=}c浭+E,1C6k_&h Qfy6דޮt=S]YHBpZ(Sqw%5ȝ3# XZ4ֱ{A B>:lR#`dU҅]{6U5Kc|2Gpy`b?Nc0җu}~UL")Dրd.XoXo;&]/<5u^\)ĸd/L/+RǑ,|xF ԂZk /1TI*muq^=('p~ FnlUձ+noE]M#⬟lb+eh10rNm۹8/:7 +~r7ykCt ṐJϦϺ<7f?6T%)˯j 'xt}.x /ڧMҡaB[^/}5-n#57/! lO#T/"(̐4f&ޙZ+ _B4-Pፑj"%i̼?hJfSfG㧙~OYqde1@5c"(Sӓ.wu+%?疛Շϑ!K:s ޾lLύZkYauz%ky],"#+NGx7T`36Zu c/^,X$cAAzҀo55ϱk%?J*UYycHhf BֺRG#4=Μth\碌aG"*lNRy+7A\'3=k8iYl%V ^HlGZE~C'}b3]תC;hOj^>ٛ:jñәnd:X>X޵=;E[R)MRN8^dDƖ!?240/9[+>'Lve{뀼1ƴRgbEۼ{krʴrXlՑBZ{^/x wRL9)}{].q`l0 {Y _EWe.Abx޼7o+:k<} kȔ#x~1x@m]@F0Pp>u _KȢ#/] b?E4BŁoI u%݂4Tsh^Ua`F,; p=ƟG{ (X u Ix(j}$`@8"cEΤp쓟,{Q)|xZl\ +l|B$ GY;{iS#DVr>׭ =W5[$y~7Vh|;xŠ]Rba [^O^4peu%|`>;yX@Fz})o_f؁S#($z+|_[Ϲ$_>H&2&fͻ"ƃ/Ljnh_h3BmqK tӷ/PfY#6VGE|i5Ơn3ް~VyYGmLwαސ6 (K_꿁7[ _fvP7|ʵ[֚[6qr4,e~TDZ@Ur?6ߦ)ٱ) &""5Š ~.*;rVv?j<:dR-%~ Fw ZMg0WS&T -1ϻQ΅ů9c|x>}:_lsSvY|Pl;>P-1+S ˗5#ˌrp_|f|~q??F"j[&O݋9]P<$4P>7<*j}+H%/Ʃ^ #ukyh!'nx{DdԳO$-[T?؜qK^zUapl=7Csӕ/TxYwf[{r>6*ًh>)Eu?劣M5d!>Eh_F-C* @ݭ:܏2E_'&p;_P/(r=P*kc(pQ#>)s>Y?Nw=jSE'Ćv .!;"=`!j 4AoPq[w"æ٢HY;v.vv g 찾`zĵO^+QmuK.Ʒ~,?WD1iji#/ /47pxJV$4';|Xڅ(po0j:$L|Q,/TkDhĮNǔ%V k¡$m ;XK_< Pco-'}HhdA4-6}5IEgq6b|a` Ef{k.".qG{fn 29l9cլf¹!F{1 !:~ _}a' 랮U{f.W[Jg0u1AރXف}χ ,گE~u4~E 5j /?>q*>dBfgGp_oDJ~c9j}Wk-9)W3GMT^w۲ Jr&(_8XIٺ#ɫU LiS=z⍓BWjVu;KGn-悏׊ SeƱ}$ִ.!@'yO_tIoN%Wm̹ROH>ޡhpx$/O84b2ͺ7od/51_2$7ىA篍Q+,aa2<ډkVucvT'jűǬ_v@#Yih/|PfqvƱq _!fK?LFaݖCmXm~Pۯ~u:G{:5/I鹭!O-=m/BΞX֏y( ʉU\`HMHX1pzo׮-HքEz|~I4h^ɍQ@"ݘS>ܺyf1 ˿R$I`bY[|wNE읬1$Q>nj'5Fv%?ue/Yi\,ިUқ)4kS)Sg/J-Kz~\hSIfR̀mCbH % _9sG9,#sK{tWTðd9z&, O'DpW0P?3:ۅϓ^ʟ5{Z4޴'˽<R^?ZK-,}[aḓX<1 ^>2( *JOĺ4's.7mY.<zZ `x:v@|vK-gQ„nauH| ?Lí4j%nlEWU$zpd17@O7( 4D|_U 1 k2>禕klsD޺YϝL?\!qgeYO}>}>  nydus-snapshotter-0.13.4/pkg/label/000077500000000000000000000000001453374237200171635ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/label/label.go000066400000000000000000000064751453374237200206050ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package label import ( snpkg "github.com/containerd/containerd/pkg/snapshotters" ) // For package compatibility, we still keep the old exported name here. var AppendLabelsHandlerWrapper = snpkg.AppendInfoHandlerWrapper // For package compatibility, we still keep the old exported name here. const ( CRIImageRef = snpkg.TargetRefLabel CRIImageLayers = snpkg.TargetImageLayersLabel CRILayerDigest = snpkg.TargetLayerDigestLabel CRIManifestDigest = snpkg.TargetManifestDigestLabel ) const ( // Marker for remote snapshotter to handle the pull request. // During image pull, the containerd client calls Prepare API with the label containerd.io/snapshot.ref. // This is a containerd-defined label which contains ChainID that targets a committed snapshot that the // client is trying to prepare. TargetSnapshotRef = "containerd.io/snapshot.ref" // A bool flag to mark the blob as a Nydus data blob, set by image builders. NydusDataLayer = "containerd.io/snapshot/nydus-blob" // A bool flag to mark the blob as a nydus bootstrap, set by image builders. NydusMetaLayer = "containerd.io/snapshot/nydus-bootstrap" // The referenced blob sha256 in format of `sha256:xxx`, set by image builders. NydusRefLayer = "containerd.io/snapshot/nydus-ref" // The blobID of associated layer, also marking the layer as a nydus tarfs, set by the snapshotter NydusTarfsLayer = "containerd.io/snapshot/nydus-tarfs" // Dm-verity information for image block device NydusImageBlockInfo = "containerd.io/snapshot/nydus-image-block" // Dm-verity information for layer block device NydusLayerBlockInfo = "containerd.io/snapshot/nydus-layer-block" // Annotation containing secret to pull images from registry, set by the snapshotter. NydusImagePullSecret = "containerd.io/snapshot/pullsecret" // Annotation containing username to pull images from registry, set by the snapshotter. NydusImagePullUsername = "containerd.io/snapshot/pullusername" // Proxy image pull actions to other agents. NydusProxyMode = "containerd.io/snapshot/nydus-proxy-mode" // A bool flag to enable integrity verification of meta data blob NydusSignature = "containerd.io/snapshot/nydus-signature" // A bool flag to mark the blob as a estargz data blob, set by the snapshotter. StargzLayer = "containerd.io/snapshot/stargz" // volatileOpt is a key of an optional label to each snapshot. // If this optional label of a snapshot is specified, when mounted to rootdir // this snapshot will include volatile option OverlayfsVolatileOpt = "containerd.io/snapshot/overlay.volatile" // A bool flag to mark it is recommended to run this image with tarfs mode, set by image builders. // runtime can decide whether to rely on this annotation TarfsHint = "containerd.io/snapshot/tarfs-hint" ) func IsNydusDataLayer(labels map[string]string) bool { _, ok := labels[NydusDataLayer] return ok } func IsNydusMetaLayer(labels map[string]string) bool { _, ok := labels[NydusMetaLayer] return ok } func IsTarfsDataLayer(labels map[string]string) bool { _, ok := labels[NydusTarfsLayer] return ok } func IsNydusProxyMode(labels map[string]string) bool { _, ok := labels[NydusProxyMode] return ok } func HasTarfsHint(labels map[string]string) bool { _, ok := labels[TarfsHint] return ok } nydus-snapshotter-0.13.4/pkg/layout/000077500000000000000000000000001453374237200174215ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/layout/layout.go000066400000000000000000000036441453374237200212740ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package layout import ( "encoding/binary" "errors" "unsafe" ) // RafsV6 layout: 1k + SuperBlock(128) + SuperBlockExtended(256) // RafsV5 layout: 8K superblock // So we only need to read the MaxSuperBlockSize size to include both v5 and v6 superblocks const MaxSuperBlockSize = 8 * 1024 const ( RafsV5 string = "v5" RafsV6 string = "v6" RafsV5SuperVersion uint32 = 0x500 RafsV5SuperMagic uint32 = 0x5241_4653 RafsV6SuperMagic uint32 = 0xE0F5_E1E2 RafsV6SuperBlockSize uint32 = 1024 + 128 + 256 RafsV6SuperBlockOffset uint32 = 1024 RafsV6ChunkInfoOffset uint32 = 1024 + 128 + 24 BootstrapFile string = "image/image.boot" LegacyBootstrapFile string = "image.boot" DummyMountpoint string = "/dummy" ) var nativeEndian binary.ByteOrder type ImageMode int const ( OnDemand ImageMode = iota PreLoad ) func init() { buf := [2]byte{} *(*uint16)(unsafe.Pointer(&buf[0])) = uint16(0xABCD) switch buf { case [2]byte{0xCD, 0xAB}: nativeEndian = binary.LittleEndian case [2]byte{0xAB, 0xCD}: nativeEndian = binary.BigEndian default: panic("Could not determine native endianness.") } } func isRafsV6(buf []byte) bool { return nativeEndian.Uint32(buf[RafsV6SuperBlockOffset:]) == RafsV6SuperMagic } func DetectFsVersion(header []byte) (string, error) { if len(header) < 8 { return "", errors.New("header buffer to DetectFsVersion is too small") } magic := binary.LittleEndian.Uint32(header[0:4]) fsVersion := binary.LittleEndian.Uint32(header[4:8]) if magic == RafsV5SuperMagic && fsVersion == RafsV5SuperVersion { return RafsV5, nil } // FIXME: detect more magic numbers to reduce collision if len(header) >= int(RafsV6SuperBlockSize) && isRafsV6(header) { return RafsV6, nil } return "", errors.New("unknown file system header") } nydus-snapshotter-0.13.4/pkg/manager/000077500000000000000000000000001453374237200175165ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/manager/daemon_adaptor.go000066400000000000000000000140501453374237200230220ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package manager import ( "os" "os/exec" "strings" "time" "github.com/containerd/containerd/log" "github.com/pkg/errors" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/pkg/daemon" "github.com/containerd/nydus-snapshotter/pkg/daemon/command" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/pkg/metrics/collector" metrics "github.com/containerd/nydus-snapshotter/pkg/metrics/tool" "github.com/containerd/nydus-snapshotter/pkg/prefetch" ) // Spawn a nydusd daemon to serve the daemon instance. // // When returning from `StartDaemon()` with out error: // - `d.States.ProcessID` will be set to the pid of the nydusd daemon. // - `d.State()` may return any validate state, please call `d.WaitUntilState()` to // ensure the daemon has reached specified state. // - `d` may have not been inserted into daemonStates and store yet. func (m *Manager) StartDaemon(d *daemon.Daemon) error { cmd, err := m.BuildDaemonCommand(d, "", false) if err != nil { return errors.Wrapf(err, "create command for daemon %s", d.ID()) } if err := cmd.Start(); err != nil { return err } d.Lock() defer d.Unlock() d.States.ProcessID = cmd.Process.Pid // Profile nydusd daemon CPU usage during its startup. if config.GetDaemonProfileCPUDuration() > 0 { processState, err := metrics.GetProcessStat(cmd.Process.Pid) if err == nil { timer := time.NewTimer(time.Duration(config.GetDaemonProfileCPUDuration()) * time.Second) go func() { <-timer.C currentProcessState, err := metrics.GetProcessStat(cmd.Process.Pid) if err != nil { log.L.WithError(err).Warnf("Failed to get daemon %s process state.", d.ID()) return } d.StartupCPUUtilization, err = metrics.CalculateCPUUtilization(processState, currentProcessState) if err != nil { log.L.WithError(err).Warnf("Calculate CPU utilization error") } }() } } // Update both states cache and DB // TODO: Is it right to commit daemon before nydusd successfully started? // And it brings extra latency of accessing DB. Only write daemon record to // DB when nydusd is started? err = m.UpdateDaemon(d) if err != nil { // Nothing we can do, just ignore it for now log.L.Errorf("Fail to update daemon info (%+v) to DB: %v", d, err) } // If nydusd fails startup, manager can't subscribe its death event. // So we can ignore the subscribing error. go func() { if err := daemon.WaitUntilSocketExisted(d.GetAPISock(), d.States.ProcessID); err != nil { // FIXME: Should clean the daemon record in DB if the nydusd fails starting log.L.Errorf("Nydusd %s probably not started", d.ID()) return } if err = m.SubscribeDaemonEvent(d); err != nil { log.L.Errorf("Nydusd %s probably not started", d.ID()) return } if err := d.WaitUntilState(types.DaemonStateRunning); err != nil { log.L.WithError(err).Errorf("daemon %s is not managed to reach RUNNING state", d.ID()) return } collector.NewDaemonEventCollector(types.DaemonStateRunning).Collect() if m.CgroupMgr != nil { if err := m.CgroupMgr.AddProc(d.States.ProcessID); err != nil { log.L.WithError(err).Errorf("add daemon %s to cgroup failed", d.ID()) return } } d.Lock() collector.NewDaemonInfoCollector(&d.Version, 1).Collect() d.Unlock() d.SendStates() }() return nil } // Build commandline according to nydusd daemon configuration. func (m *Manager) BuildDaemonCommand(d *daemon.Daemon, bin string, upgrade bool) (*exec.Cmd, error) { var cmdOpts []command.Opt var imageReference string nydusdThreadNum := d.NydusdThreadNum() if d.States.FsDriver == config.FsDriverFscache { cmdOpts = append(cmdOpts, command.WithMode("singleton"), command.WithFscacheDriver(m.cacheDir)) if nydusdThreadNum != 0 { cmdOpts = append(cmdOpts, command.WithFscacheThreads(nydusdThreadNum)) } } else { cmdOpts = append(cmdOpts, command.WithMode("fuse"), command.WithMountpoint(d.HostMountpoint())) if nydusdThreadNum != 0 { cmdOpts = append(cmdOpts, command.WithThreadNum(nydusdThreadNum)) } switch { case d.IsSharedDaemon(): break case !d.IsSharedDaemon(): rafs := d.RafsCache.Head() if rafs == nil { return nil, errors.Wrapf(errdefs.ErrNotFound, "daemon %s no rafs instance associated", d.ID()) } imageReference = rafs.ImageID bootstrap, err := rafs.BootstrapFile() if err != nil { return nil, errors.Wrapf(err, "locate bootstrap %s", bootstrap) } cmdOpts = append(cmdOpts, command.WithConfig(d.ConfigFile("")), command.WithBootstrap(bootstrap), ) default: return nil, errors.Errorf("invalid daemon mode %s ", d.States.DaemonMode) } } if d.Supervisor != nil { cmdOpts = append(cmdOpts, command.WithSupervisor(d.Supervisor.Sock()), command.WithID(d.ID())) } if imageReference != "" { prefetchfiles := prefetch.Pm.GetPrefetchInfo(imageReference) if prefetchfiles != "" { cmdOpts = append(cmdOpts, command.WithPrefetchFiles(prefetchfiles)) prefetch.Pm.DeleteFromPrefetchMap(imageReference) } } cmdOpts = append(cmdOpts, command.WithLogLevel(d.States.LogLevel), command.WithAPISock(d.GetAPISock())) if d.States.LogRotationSize > 0 { cmdOpts = append(cmdOpts, command.WithLogRotationSize(d.States.LogRotationSize)) } if upgrade { cmdOpts = append(cmdOpts, command.WithUpgrade()) } if !d.States.LogToStdout { cmdOpts = append(cmdOpts, command.WithLogFile(d.LogFile())) } args, err := command.BuildCommand(cmdOpts) if err != nil { return nil, err } var nydusdPath string if bin != "" { nydusdPath = bin } else { nydusdPath = m.NydusdBinaryPath } log.L.Infof("nydusd command: %s %s", nydusdPath, strings.Join(args, " ")) cmd := exec.Command(nydusdPath, args...) // nydusd standard output and standard error rather than its logs are // always redirected to snapshotter's respectively cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return cmd, nil } nydus-snapshotter-0.13.4/pkg/manager/daemon_cache.go000066400000000000000000000043051453374237200224350ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package manager import ( "sync" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/daemon" ) // Daemon state cache to speed up access. type DaemonCache struct { mu sync.Mutex idxByDaemonID map[string]*daemon.Daemon // index by ID } func newDaemonCache() *DaemonCache { return &DaemonCache{ idxByDaemonID: make(map[string]*daemon.Daemon), } } // Return nil if the daemon is never inserted or managed, // otherwise returns the previously inserted daemon pointer. // Allowing replace an existed daemon since some fields in Daemon can change after restarting nydusd. func (s *DaemonCache) Add(daemon *daemon.Daemon) *daemon.Daemon { s.mu.Lock() defer s.mu.Unlock() old := s.idxByDaemonID[daemon.ID()] s.idxByDaemonID[daemon.ID()] = daemon return old } func (s *DaemonCache) removeLocked(d *daemon.Daemon) *daemon.Daemon { old := s.idxByDaemonID[d.ID()] delete(s.idxByDaemonID, d.ID()) return old } func (s *DaemonCache) Remove(d *daemon.Daemon) *daemon.Daemon { s.mu.Lock() old := s.removeLocked(d) s.mu.Unlock() return old } func (s *DaemonCache) RemoveByDaemonID(id string) *daemon.Daemon { return s.GetByDaemonID(id, func(d *daemon.Daemon) { s.removeLocked(d) }) } // Also recover daemon runtime state here func (s *DaemonCache) Update(d *daemon.Daemon) { s.mu.Lock() defer s.mu.Unlock() log.L.Infof("Recovering daemon ID %s", d.ID()) s.idxByDaemonID[d.ID()] = d } func (s *DaemonCache) GetByDaemonID(id string, op func(d *daemon.Daemon)) *daemon.Daemon { var daemon *daemon.Daemon s.mu.Lock() defer s.mu.Unlock() daemon = s.idxByDaemonID[id] if daemon != nil && op != nil { op(daemon) } return daemon } func (s *DaemonCache) List() []*daemon.Daemon { s.mu.Lock() defer s.mu.Unlock() if len(s.idxByDaemonID) == 0 { return nil } listed := make([]*daemon.Daemon, 0, len(s.idxByDaemonID)) for _, d := range s.idxByDaemonID { listed = append(listed, d) } return listed } func (s *DaemonCache) Size() int { s.mu.Lock() defer s.mu.Unlock() return len(s.idxByDaemonID) } nydus-snapshotter-0.13.4/pkg/manager/daemon_cache_test.go000066400000000000000000000030311453374237200234670ustar00rootroot00000000000000/* Copyright The nydus Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package manager import ( "testing" "github.com/containerd/nydus-snapshotter/pkg/daemon" "github.com/stretchr/testify/assert" ) func TestDaemonStatesCache(t *testing.T) { states := newDaemonCache() d1 := &daemon.Daemon{States: daemon.ConfigState{ID: "d1"}} d2 := &daemon.Daemon{States: daemon.ConfigState{ID: "d2"}} states.Add(d1) states.Add(d2) anotherD1 := states.GetByDaemonID("d1", nil) anotherD2 := states.GetByDaemonID("d2", nil) assert.Equal(t, anotherD1, d1) assert.Equal(t, anotherD2, d2) daemons := states.List() assert.Equal(t, len(daemons), 2) assert.True(t, daemons[0] == d1 || daemons[1] == d1) assert.True(t, daemons[0] == d2 || daemons[1] == d2) assert.Equal(t, states.Size(), 2) states.Remove(d1) assert.Equal(t, states.Size(), 1) states.RemoveByDaemonID("d2") assert.Equal(t, states.Size(), 0) states.Update(d2) assert.Equal(t, states.Size(), 1) states.RemoveByDaemonID("d2") assert.Equal(t, states.Size(), 0) } nydus-snapshotter-0.13.4/pkg/manager/daemon_event.go000066400000000000000000000071071453374237200225160ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package manager import ( "time" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/pkg/daemon" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/containerd/nydus-snapshotter/pkg/metrics/collector" "github.com/pkg/errors" ) func (m *Manager) SubscribeDaemonEvent(d *daemon.Daemon) error { if err := m.monitor.Subscribe(d.ID(), d.GetAPISock(), m.LivenessNotifier); err != nil { log.L.Errorf("Nydusd %s probably not started", d.ID()) return errors.Wrapf(err, "subscribe daemon %s", d.ID()) } return nil } func (m *Manager) UnsubscribeDaemonEvent(d *daemon.Daemon) error { // Starting a new nydusd will re-subscribe if err := m.monitor.Unsubscribe(d.ID()); err != nil { log.L.Warnf("fail to unsubscribe daemon %s, %v", d.ID(), err) return errors.Wrapf(err, "unsubscribe daemon %s", d.ID()) } return nil } func (m *Manager) handleDaemonDeathEvent() { // TODO: ratelimit for daemon recovery operations? for ev := range m.LivenessNotifier { log.L.Warnf("Daemon %s died! socket path %s", ev.daemonID, ev.path) d := m.GetByDaemonID(ev.daemonID) if d == nil { log.L.Warnf("Daemon %s was not found, may have been removed", ev.daemonID) continue } d.Lock() collector.NewDaemonInfoCollector(&d.Version, -1).Collect() d.Unlock() d.ResetState() if m.RecoverPolicy == config.RecoverPolicyRestart { log.L.Infof("Restart daemon %s", ev.daemonID) go m.doDaemonRestart(d) } else if m.RecoverPolicy == config.RecoverPolicyFailover { log.L.Infof("Do failover for daemon %s", ev.daemonID) go m.doDaemonFailover(d) } } } func (m *Manager) doDaemonFailover(d *daemon.Daemon) { if err := d.Wait(); err != nil { log.L.Warnf("fail to wait for daemon, %v", err) } // Starting a new nydusd will re-subscribe if err := m.UnsubscribeDaemonEvent(d); err != nil { log.L.Warnf("fail to unsubscribe daemon %s, %v", d.ID(), err) } su := m.SupervisorSet.GetSupervisor(d.ID()) if err := su.SendStatesTimeout(time.Second * 10); err != nil { log.L.Errorf("Send states error, %s", err) return } // Failover nydusd still depends on the old supervisor if err := m.StartDaemon(d); err != nil { log.L.Errorf("fail to start daemon %s when recovering", d.ID()) return } if err := d.WaitUntilState(types.DaemonStateInit); err != nil { log.L.WithError(err).Errorf("daemon didn't reach state %s,", types.DaemonStateInit) return } if err := d.TakeOver(); err != nil { log.L.Errorf("fail to takeover, %s", err) return } if err := d.Start(); err != nil { log.L.Errorf("fail to start service, %s", err) return } } func (m *Manager) doDaemonRestart(d *daemon.Daemon) { if err := d.Wait(); err != nil { log.L.Warnf("fails to wait for daemon, %v", err) } // Starting a new nydusd will re-subscribe if err := m.UnsubscribeDaemonEvent(d); err != nil { log.L.Warnf("fails to unsubscribe daemon %s, %v", d.ID(), err) } d.ClearVestige() if err := m.StartDaemon(d); err != nil { log.L.Errorf("fails to start daemon %s when recovering", d.ID()) return } // Mount rafs instance by http API instances := d.RafsCache.List() for _, r := range instances { // For dedicated nydusd daemon, Rafs has already been mounted during starting nydusd if d.HostMountpoint() == r.GetMountpoint() { break } if err := d.SharedMount(r); err != nil { log.L.Warnf("Failed to mount rafs instance, %v", err) } } } nydus-snapshotter-0.13.4/pkg/manager/manager.go000066400000000000000000000246721453374237200214720ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package manager import ( "context" "os" "path" "path/filepath" "sync" "github.com/containerd/containerd/log" "github.com/pkg/errors" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/config/daemonconfig" "github.com/containerd/nydus-snapshotter/pkg/cgroup" "github.com/containerd/nydus-snapshotter/pkg/daemon" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/pkg/metrics/collector" "github.com/containerd/nydus-snapshotter/pkg/rafs" "github.com/containerd/nydus-snapshotter/pkg/store" "github.com/containerd/nydus-snapshotter/pkg/supervisor" ) // Manage RAFS filesystem instances and nydusd daemons. type Manager struct { // Protect fields `store` and `daemonStates` mu sync.Mutex cacheDir string FsDriver string store Store // Fields below are used to manage nydusd daemons. // // The `daemonCache` is cache for nydusd daemons stored in `store`. // You should update `store` first before modifying cached state. daemonCache *DaemonCache DaemonConfig *daemonconfig.DaemonConfig // Daemon configuration template. CgroupMgr *cgroup.Manager monitor LivenessMonitor LivenessNotifier chan deathEvent // TODO: Close me NydusdBinaryPath string RecoverPolicy config.DaemonRecoverPolicy SupervisorSet *supervisor.SupervisorsSet } type Opt struct { CacheDir string CgroupMgr *cgroup.Manager DaemonConfig *daemonconfig.DaemonConfig Database *store.Database FsDriver string NydusdBinaryPath string RecoverPolicy config.DaemonRecoverPolicy RootDir string // Nydus-snapshotter work directory } func NewManager(opt Opt) (*Manager, error) { s, err := store.NewDaemonRafsStore(opt.Database) if err != nil { return nil, err } monitor, err := newMonitor() if err != nil { return nil, errors.Wrap(err, "create daemons liveness monitor") } var supervisorSet *supervisor.SupervisorsSet if opt.RecoverPolicy == config.RecoverPolicyFailover { supervisorSet, err = supervisor.NewSupervisorSet(filepath.Join(opt.RootDir, "supervisor")) if err != nil { return nil, errors.Wrap(err, "create supervisor set") } } mgr := &Manager{ store: s, NydusdBinaryPath: opt.NydusdBinaryPath, cacheDir: opt.CacheDir, daemonCache: newDaemonCache(), monitor: monitor, LivenessNotifier: make(chan deathEvent, 32), RecoverPolicy: opt.RecoverPolicy, SupervisorSet: supervisorSet, DaemonConfig: opt.DaemonConfig, CgroupMgr: opt.CgroupMgr, FsDriver: opt.FsDriver, } // FIXME: How to get error if monitor goroutine terminates with error? // TODO: Shutdown monitor immediately after snapshotter receive Exit signal mgr.monitor.Run() go mgr.handleDaemonDeathEvent() return mgr, nil } func (m *Manager) Lock() { m.mu.Lock() } func (m *Manager) Unlock() { m.mu.Unlock() } func (m *Manager) CacheDir() string { return m.cacheDir } // Recover nydusd daemons and RAFS instances on startup. // // To be safe: // - Never ever delete any records from DB // - Only cache daemon information from DB, do not actually start/create daemons // - Only cache RAFS instance information from DB, do not actually recover RAFS runtime state. func (m *Manager) Recover(ctx context.Context, recoveringDaemons *map[string]*daemon.Daemon, liveDaemons *map[string]*daemon.Daemon) error { if err := m.recoverDaemons(ctx, recoveringDaemons, liveDaemons); err != nil { return errors.Wrapf(err, "recover nydusd daemons") } if err := m.recoverRafsInstances(ctx, recoveringDaemons, liveDaemons); err != nil { return errors.Wrapf(err, "recover RAFS instances") } return nil } func (m *Manager) AddRafsInstance(r *rafs.Rafs) error { m.mu.Lock() defer m.mu.Unlock() seq, err := m.store.NextInstanceSeq() if err != nil { return err } r.Seq = seq return m.store.AddRafsInstance(r) } func (m *Manager) RemoveRafsInstance(snapshotID string) error { return m.store.DeleteRafsInstance(snapshotID) } func (m *Manager) recoverRafsInstances(ctx context.Context, recoveringDaemons *map[string]*daemon.Daemon, liveDaemons *map[string]*daemon.Daemon) error { if err := m.store.WalkRafsInstances(ctx, func(r *rafs.Rafs) error { if r.GetFsDriver() != m.FsDriver { return nil } log.L.Debugf("found RAFS instance %#v", r) if r.GetFsDriver() == config.FsDriverFscache || r.GetFsDriver() == config.FsDriverFusedev { d := (*recoveringDaemons)[r.DaemonID] if d != nil { d.AddRafsInstance(r) } d = (*liveDaemons)[r.DaemonID] if d != nil { d.AddRafsInstance(r) } rafs.RafsGlobalCache.Add(r) } else if r.GetFsDriver() == config.FsDriverBlockdev { rafs.RafsGlobalCache.Add(r) } return nil }); err != nil { return errors.Wrapf(err, "walk instances to reconnect") } return nil } // Add an instantiated daemon to be managed by the manager. // // Return ErrAlreadyExists if a daemon with the same daemon ID already exists. func (m *Manager) AddDaemon(daemon *daemon.Daemon) error { m.mu.Lock() defer m.mu.Unlock() if old := m.daemonCache.GetByDaemonID(daemon.ID(), nil); old != nil { return errdefs.ErrAlreadyExists } if err := m.store.AddDaemon(daemon); err != nil { return errors.Wrapf(err, "add daemon %s", daemon.ID()) } m.daemonCache.Add(daemon) return nil } func (m *Manager) UpdateDaemon(daemon *daemon.Daemon) error { m.mu.Lock() defer m.mu.Unlock() return m.UpdateDaemonLocked(daemon) } // Notice: updating daemon states cache and DB should be protect by `mu` lock func (m *Manager) UpdateDaemonLocked(daemon *daemon.Daemon) error { if old := m.daemonCache.GetByDaemonID(daemon.ID(), nil); old == nil { return errdefs.ErrNotFound } if err := m.store.UpdateDaemon(daemon); err != nil { return errors.Wrapf(err, "update daemon state for %s", daemon.ID()) } m.daemonCache.Add(daemon) return nil } func (m *Manager) DeleteDaemon(daemon *daemon.Daemon) error { if daemon == nil { return nil } m.mu.Lock() defer m.mu.Unlock() if err := m.store.DeleteDaemon(daemon.ID()); err != nil { return errors.Wrapf(err, "delete daemon state for %s", daemon.ID()) } m.daemonCache.Remove(daemon) return nil } func (m *Manager) GetByDaemonID(id string) *daemon.Daemon { return m.daemonCache.GetByDaemonID(id, nil) } func (m *Manager) ListDaemons() []*daemon.Daemon { return m.daemonCache.List() } // FIXME: should handle the inconsistent status caused by any step // in the function that returns an error. func (m *Manager) DestroyDaemon(d *daemon.Daemon) error { log.L.Infof("Destroy nydusd daemon %s. Host mountpoint %s", d.ID(), d.HostMountpoint()) // First remove the record from DB, so any failures below won't cause stale records in DB. if err := m.DeleteDaemon(d); err != nil { return errors.Wrapf(err, "delete daemon %s", d.ID()) } defer m.cleanUpDaemonResources(d) if err := d.UmountRafsInstances(); err != nil { log.L.Errorf("Failed to detach all fs instances from daemon %s, %s", d.ID(), err) } if err := m.UnsubscribeDaemonEvent(d); err != nil { log.L.Warnf("Unable to unsubscribe, daemon ID %s, %s", d.ID(), err) } if m.SupervisorSet != nil { if err := m.SupervisorSet.DestroySupervisor(d.ID()); err != nil { log.L.Warnf("Failed to delete supervisor for daemon %s, %s", d.ID(), err) } } // Graceful nydusd termination will umount itself. if err := d.Terminate(); err != nil { log.L.Warnf("Fails to terminate daemon, %v", err) } if err := d.Wait(); err != nil { log.L.Warnf("Failed to wait for daemon, %v", err) } collector.NewDaemonEventCollector(types.DaemonStateDestroyed).Collect() d.Lock() collector.NewDaemonInfoCollector(&d.Version, -1).Collect() d.Unlock() return nil } func (m *Manager) cleanUpDaemonResources(d *daemon.Daemon) { // TODO: use recycle bin to stage directories/files to be deleted. resource := []string{d.States.ConfigDir, d.States.LogDir} if !d.IsSharedDaemon() { socketDir := path.Dir(d.GetAPISock()) resource = append(resource, socketDir) } for _, dir := range resource { if err := os.RemoveAll(dir); err != nil { log.L.Errorf("failed to remove dir %s err %v", dir, err) } } log.L.Infof("Deleting resources %v", resource) } func (m *Manager) recoverDaemons(ctx context.Context, recoveringDaemons *map[string]*daemon.Daemon, liveDaemons *map[string]*daemon.Daemon) error { if err := m.store.WalkDaemons(ctx, func(s *daemon.ConfigState) error { if s.FsDriver != m.FsDriver { return nil } log.L.Debugf("found daemon states %#v", s) opt := make([]daemon.NewDaemonOpt, 0) var d, _ = daemon.NewDaemon(opt...) d.States = *s m.daemonCache.Update(d) if m.SupervisorSet != nil { su := m.SupervisorSet.NewSupervisor(d.ID()) if su == nil { return errors.Errorf("create supervisor for daemon %s", d.ID()) } d.Supervisor = su } if d.States.FsDriver == config.FsDriverFusedev { cfg, err := daemonconfig.NewDaemonConfig(d.States.FsDriver, d.ConfigFile("")) if err != nil { log.L.Errorf("Failed to reload daemon configuration %s, %s", d.ConfigFile(""), err) return err } d.Config = cfg } state, err := d.GetState() if err != nil { log.L.Warnf("Daemon %s died somehow. Clean up its vestige!, %s", d.ID(), err) (*recoveringDaemons)[d.ID()] = d //nolint:nilerr return nil } if state != types.DaemonStateRunning { log.L.Warnf("daemon %s is not running: %s", d.ID(), state) return nil } // FIXME: Should put the a daemon back file system shared damon field. log.L.Infof("found RUNNING daemon %s during reconnecting", d.ID()) (*liveDaemons)[d.ID()] = d if m.CgroupMgr != nil { if err := m.CgroupMgr.AddProc(d.States.ProcessID); err != nil { return errors.Wrapf(err, "add daemon %s to cgroup failed", d.ID()) } } d.Lock() collector.NewDaemonInfoCollector(&d.Version, 1).Collect() d.Unlock() go func() { if err := daemon.WaitUntilSocketExisted(d.GetAPISock(), d.Pid()); err != nil { log.L.Errorf("Nydusd %s probably not started", d.ID()) return } if err = m.SubscribeDaemonEvent(d); err != nil { log.L.Errorf("Nydusd %s probably not started", d.ID()) return } // Snapshotter's lost the daemons' states after exit, refetch them. d.SendStates() }() return nil }); err != nil { return errors.Wrapf(err, "walk daemons to reconnect") } return nil } nydus-snapshotter-0.13.4/pkg/manager/monitor.go000066400000000000000000000140011453374237200215300ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package manager import ( "net" "sync" "syscall" "time" "github.com/pkg/errors" "golang.org/x/sys/unix" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/pkg/metrics/collector" "github.com/containerd/nydus-snapshotter/pkg/utils/retry" ) // LivenessMonitor liveness of a nydusd daemon. type LivenessMonitor interface { // Subscribe death event of a nydusd daemon. // `path` is where the monitor is listening on. Subscribe(id string, path string, notifier chan<- deathEvent) error // Unsubscribe death event of a nydusd daemon. Unsubscribe(id string) error // Run the monitor, wait for nydusd death event. Run() // Stop the monitor and release all the resources. Destroy() } type target struct { // A connection to the nydusd. Should close it when stopping the liveness monitor! uc *net.UnixConn // Notify subscriber that the nydusd is dead via the channel notifier chan<- deathEvent // `id` is usually the daemon ID id string path string } type FD = uintptr type livenessMonitor struct { mu sync.Mutex // Get a subscribing target by the target ID (usually is the daemon ID) subscribers map[string]*target // Get a subscribing target by the connection FD. Each liveness // probe has a unique connection FD which is listened for epoll event. set map[FD]*target epollFd int } type deathEvent struct { daemonID string path string } func newMonitor() (_ *livenessMonitor, err error) { var epollFd int epollFd, err = unix.EpollCreate1(unix.EPOLL_CLOEXEC) if err != nil { return nil, errors.Wrap(err, "create daemons monitor") } m := &livenessMonitor{ epollFd: epollFd, subscribers: make(map[string]*target), set: make(map[uintptr]*target), } return m, nil } func (m *livenessMonitor) Subscribe(id string, path string, notifier chan<- deathEvent) (err error) { m.mu.Lock() defer m.mu.Unlock() if s, ok := m.subscribers[id]; ok && s.path == path { log.L.Warnf("Daemon %s is already subscribed!", id) return errdefs.ErrAlreadyExists } var ( c net.Conn rawConn syscall.RawConn ) err = retry.Do(func() (err error) { // Don't forget close me! if c, err = net.Dial("unix", path); err != nil { log.L.Errorf("Fails to connect to %s, %v", path, err) return } return nil }, retry.LastErrorOnly(true), retry.Attempts(20), // totally wait for 2 seconds, should be enough retry.Delay(100*time.Millisecond)) if err != nil { return err } uc, ok := c.(*net.UnixConn) if !ok { return errors.Errorf("a unix socket connection is required") } if rawConn, err = uc.SyscallConn(); err != nil { return } err = rawConn.Control(func(fd FD) { err = unix.SetNonblock(int(fd), true) if err != nil { log.L.Errorf("Failed to set file. daemon id %s path %s. %v", id, path, err) return } event := unix.EpollEvent{ Fd: int32(fd), Events: unix.EPOLLHUP | unix.EPOLLERR | unix.EPOLLET, } err = unix.EpollCtl(m.epollFd, unix.EPOLL_CTL_ADD, int(fd), &event) if err != nil { log.L.Errorf("Failed to control epoll. daemon id %s path %s. %v", id, path, err) return } target := &target{uc: uc, id: id, path: path} // Only add subscribed target when everything is OK. m.set[fd] = target m.subscribers[id] = target target.notifier = notifier }) log.L.Infof("Subscribe daemon %s liveness event, path=%s.", id, path) return } func (m *livenessMonitor) Unsubscribe(id string) (err error) { m.mu.Lock() defer m.mu.Unlock() return m.unsubscribe(id) } func (m *livenessMonitor) unsubscribe(id string) (err error) { target, ok := m.subscribers[id] if !ok { return errdefs.ErrNotFound } delete(m.subscribers, id) var rawConn syscall.RawConn if rawConn, err = target.uc.SyscallConn(); err != nil { log.L.Errorf("Fail to access underlying FD, id=%s", id) return } // No longer wait for event, delete it from interest list. if err = rawConn.Control(func(fd uintptr) { if err := unix.EpollCtl(m.epollFd, unix.EPOLL_CTL_DEL, int(fd), &unix.EpollEvent{}); err != nil { log.L.Errorf("Fail to delete event fd %d for supervisor %s", int(fd), id) return } delete(m.set, fd) }); err != nil { return errors.Wrapf(err, "remove target FD in the interested list, id=%s", id) } if err = target.uc.Close(); err != nil { log.L.Errorf("Fails to close unix connection for daemon %s", id) return } return nil } func (m *livenessMonitor) Run() { var events [512]unix.EpollEvent go func() { defer log.L.Infof("Exiting liveness monitor") log.L.Infof("Run daemons monitor...") for { n, err := unix.EpollWait(m.epollFd, events[:], -1) if err != nil { if err == unix.EINTR { continue } // `Destroy` should close the epoll fd thus to exit the goroutine. log.L.Errorf("Monitor fails to wait events, %v. Exiting!", err) return } for i := 0; i < n; i++ { ev := events[i] m.mu.Lock() target, ok := m.set[uintptr(ev.Fd)] m.mu.Unlock() // There is a race that it is waken before unsubscribing, // so the target can't be found. if !ok { continue } if ev.Events&(unix.EPOLLHUP|unix.EPOLLERR) != 0 { log.L.Warnf("Daemon %s died", target.id) collector.NewDaemonEventCollector(types.DaemonStateDied).Collect() // Notify subscribers that death event happens target.notifier <- deathEvent{daemonID: target.id, path: target.path} } } } }() } func (m *livenessMonitor) Destroy() { m.mu.Lock() defer m.mu.Unlock() for i := range m.subscribers { if err := m.unsubscribe(i); err != nil { log.L.Warnf("fail to unsubscribe %s", i) } } if m.epollFd > 0 { // Closing epoll fd does not waken `EpollWait`. So ending events loop can not be // done via closing the file. But liveness monitor is running with nydus-snapshotter // in the whole life. So we don't stop the loop now. unix.Close(m.epollFd) } } nydus-snapshotter-0.13.4/pkg/manager/monitor_test.go000066400000000000000000000036001453374237200225720ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package manager import ( "context" "log" "net" "os" "testing" "time" "github.com/stretchr/testify/assert" ) func startUnixServer(ctx context.Context, sock string) { os.RemoveAll(sock) listener, err := net.Listen("unix", sock) if err != nil { log.Fatal(err) } var conn net.Conn conn, err = listener.Accept() if err != nil { log.Fatal() } for { select { case <-ctx.Done(): conn.Close() return default: time.Sleep(200 * time.Millisecond) } } } func TestLivenessMonitor(t *testing.T) { sockPattern := "liveness_monitor_sock" s1, err1 := os.CreateTemp("", sockPattern) assert.Nil(t, err1) s1.Close() s2, err2 := os.CreateTemp("", sockPattern) assert.Nil(t, err2) s2.Close() ctx1, cancel1 := context.WithCancel(context.Background()) ctx2, cancel2 := context.WithCancel(context.Background()) go startUnixServer(ctx1, s1.Name()) go startUnixServer(ctx2, s2.Name()) monitor, _ := newMonitor() assert.NotNil(t, monitor) time.Sleep(time.Millisecond * 200) notifier := make(chan deathEvent, 10) e1 := monitor.Subscribe("daemon_1", s1.Name(), notifier) assert.Nil(t, e1) e1 = monitor.Subscribe("daemon_1", s1.Name(), notifier) assert.NotNil(t, e1) e2 := monitor.Subscribe("daemon_2", s2.Name(), notifier) assert.Nil(t, e2) t.Cleanup(func() { os.Remove(s1.Name()) os.Remove(s2.Name()) }) monitor.Run() time.Sleep(time.Millisecond * 200) // Daemon 1 dies and unblock from channel `n1` cancel1() event := <-notifier assert.Equal(t, event.daemonID, "daemon_1") err := monitor.Unsubscribe("daemon_2") assert.Nil(t, err) cancel2() // Should not block here. assert.Equal(t, len(notifier), 0) time.Sleep(time.Second * 1) monitor.Destroy() assert.Equal(t, len(monitor.set), 0) assert.Equal(t, len(monitor.subscribers), 0) } nydus-snapshotter-0.13.4/pkg/manager/store.go000066400000000000000000000017221453374237200212030ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package manager import ( "context" "github.com/containerd/nydus-snapshotter/pkg/daemon" "github.com/containerd/nydus-snapshotter/pkg/rafs" "github.com/containerd/nydus-snapshotter/pkg/store" ) // Nydus daemons and fs instances persistence storage. type Store interface { // If the daemon is inserted to DB before, return error ErrAlreadyExisted. AddDaemon(d *daemon.Daemon) error UpdateDaemon(d *daemon.Daemon) error DeleteDaemon(id string) error WalkDaemons(ctx context.Context, cb func(*daemon.ConfigState) error) error CleanupDaemons(ctx context.Context) error AddRafsInstance(r *rafs.Rafs) error DeleteRafsInstance(snapshotID string) error WalkRafsInstances(ctx context.Context, cb func(*rafs.Rafs) error) error NextInstanceSeq() (uint64, error) } var _ Store = &store.DaemonRafsStore{} nydus-snapshotter-0.13.4/pkg/metrics/000077500000000000000000000000001453374237200175525ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/metrics/collector/000077500000000000000000000000001453374237200215405ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/metrics/collector/collector.go000066400000000000000000000031461453374237200240610ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package collector import ( "context" "time" "github.com/containerd/nydus-snapshotter/pkg/metrics/data" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/containerd/nydus-snapshotter/pkg/metrics/tool" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" ) type Collector interface { // Collect metrics to prometheus data. Collect() } func NewDaemonEventCollector(ev types.DaemonState) *DaemonEventCollector { return &DaemonEventCollector{event: ev} } func NewFsMetricsCollector(m *types.FsMetrics, imageRef string) *FsMetricsCollector { return &FsMetricsCollector{m, imageRef} } func NewFsMetricsVecCollector() *FsMetricsVecCollector { return &FsMetricsVecCollector{} } func NewInflightMetricsVecCollector(hungIOInterval time.Duration) *InflightMetricsVecCollector { return &InflightMetricsVecCollector{ HungIOInterval: hungIOInterval, } } func NewDaemonInfoCollector(version *types.BuildTimeInfo, value float64) *DaemonInfoCollector { return &DaemonInfoCollector{version, value} } func NewSnapshotterMetricsCollector(ctx context.Context, cacheDir string, pid int) (*SnapshotterMetricsCollector, error) { currentStat, err := tool.GetProcessStat(pid) if err != nil { return nil, errors.Wrapf(err, "can not get current stat") } return &SnapshotterMetricsCollector{ctx, cacheDir, pid, currentStat}, nil } func NewSnapshotMetricsTimer(method SnapshotMethod) *prometheus.Timer { return CollectSnapshotMetricsTimer(data.SnapshotEventElapsedHists, method) } nydus-snapshotter-0.13.4/pkg/metrics/collector/daemon.go000066400000000000000000000016741453374237200233420ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package collector import ( "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/containerd/nydus-snapshotter/pkg/metrics/data" ) type DaemonEventCollector struct { event types.DaemonState } type DaemonInfoCollector struct { Version *types.BuildTimeInfo value float64 } type DaemonResourceCollector struct { DaemonID string Value float64 } func (d *DaemonEventCollector) Collect() { data.NydusdEventCount.WithLabelValues(string(d.event)).Inc() } func (d *DaemonInfoCollector) Collect() { if d.Version == nil { log.L.Warnf("failed to collect daemon count, version is invalid") return } data.NydusdCount.WithLabelValues(d.Version.PackageVer).Add(d.value) } func (d *DaemonResourceCollector) Collect() { data.NydusdRSS.WithLabelValues(d.DaemonID).Set(d.Value) } nydus-snapshotter-0.13.4/pkg/metrics/collector/fs.go000066400000000000000000000047151453374237200225060ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package collector import ( "time" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/containerd/nydus-snapshotter/pkg/metrics/data" mtypes "github.com/containerd/nydus-snapshotter/pkg/metrics/types" ) var OPCodeMap = map[uint32]string{ 15: "OP_READ", } type FsMetricsCollector struct { Metrics *types.FsMetrics ImageRef string } type FsMetricsVecCollector struct { MetricsVec []FsMetricsCollector } type InflightMetricsVecCollector struct { MetricsVec []*types.InflightMetrics HungIOInterval time.Duration } func (f *FsMetricsCollector) Collect() { if f.Metrics == nil { log.L.Warnf("can not collect FS metrics: Metrics is nil") return } data.FsTotalRead.WithLabelValues(f.ImageRef).Set(float64(f.Metrics.DataRead)) data.FsReadHit.WithLabelValues(f.ImageRef).Set(float64(f.Metrics.FopHits[mtypes.Read])) data.FsReadError.WithLabelValues(f.ImageRef).Set(float64(f.Metrics.FopErrors[mtypes.Read])) for _, h := range data.MetricHists { o, err := h.ToConstHistogram(f.Metrics, f.ImageRef) if err != nil { log.L.Warnf("failed to new const histogram for %s, error: %v", h.Desc.String(), err) return } h.Save(o) } } func (i *InflightMetricsVecCollector) Collect() { if i.MetricsVec == nil { log.L.Warnf("can not collect inflight metrics: Metrics is nil") return } // The TimestampSecs of inflight IO is the beginning time of this request. // We can calculate the elapsed time by time.Now().Unix() - TimestampSecs. // The inflight IOs which have a longer elapsed time than the HungIOInterval (default 10 seconds) are hung IOs. totalHungIOMap := 0 nowTime := time.Now() for _, daemonInflightIOMetrics := range i.MetricsVec { for _, inflightIOMetric := range daemonInflightIOMetrics.Values { elapsed := nowTime.Sub(time.Unix(int64(inflightIOMetric.TimestampSecs), 0)) if elapsed >= i.HungIOInterval { totalHungIOMap++ log.L.Debugf("Record hung IO, Inode: %v, Opcode: %v, Unique: %v, Elapsed: %v", inflightIOMetric.Inode, inflightIOMetric.Opcode, inflightIOMetric.Unique, elapsed) } } } data.TotalHungIO.Set(float64(totalHungIOMap)) } func (f *FsMetricsVecCollector) Clear() { for _, h := range data.MetricHists { h.Clear() } } func (f *FsMetricsVecCollector) Collect() { f.Clear() for _, fsMetrics := range f.MetricsVec { fsMetrics.Collect() } } nydus-snapshotter-0.13.4/pkg/metrics/collector/snapshotter.go000066400000000000000000000047071453374237200244510ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package collector import ( "context" "github.com/containerd/containerd/log" "github.com/containerd/continuity/fs" "github.com/containerd/nydus-snapshotter/pkg/metrics/data" "github.com/containerd/nydus-snapshotter/pkg/metrics/tool" "github.com/prometheus/client_golang/prometheus" ) type SnapshotterMetricsCollector struct { ctx context.Context cacheDir string pid int lastStat *tool.Stat } type SnapshotMethod string const ( SnapshotMethodUnknown SnapshotMethod = "UNKNOWN" SnapshotMethodPrepare SnapshotMethod = "PREPARE" SnapshotMethodMount SnapshotMethod = "MOUNTS" SnapshotMethodCleanup SnapshotMethod = "CLEANUP" SnapshotMethodRemove SnapshotMethod = "REMOVE" ) func (s *SnapshotterMetricsCollector) CollectCacheUsage() { du, err := fs.DiskUsage(s.ctx, s.cacheDir) if err != nil { log.L.Warnf("Get disk usage failed: %v", err) } else { data.CacheUsage.Set(float64(du.Size) / 1024) } } func (s *SnapshotterMetricsCollector) CollectResourceUsage() { currentStat, err := tool.GetProcessStat(s.pid) if err != nil { log.L.Warnf("Can not get current process stat.") return } if s.lastStat == nil { log.L.Debug("Can not get resource usage information: lastStat is nil") s.lastStat = currentStat return } cpuSys := (currentStat.Stime - s.lastStat.Stime) / tool.ClkTck cpuUsr := (currentStat.Utime - s.lastStat.Utime) / tool.ClkTck cpuPercent, err := tool.CalculateCPUUtilization(s.lastStat, currentStat) if err != nil { log.L.WithError(err).Warnf("Failed to calculate CPU utilization") } s.lastStat = currentStat memory := currentStat.Rss * tool.PageSize runTime := currentStat.Uptime - currentStat.Start/tool.ClkTck data.CPUSystem.Set(tool.FormatFloat64(cpuSys, 2)) data.CPUUser.Set(tool.FormatFloat64(cpuUsr, 2)) data.CPUUsage.Set(tool.FormatFloat64(cpuPercent, 2)) data.MemoryUsage.Set(tool.FormatFloat64(memory/1024, 2)) data.Fds.Set(currentStat.Fds) data.RunTime.Set(tool.FormatFloat64(runTime, 2)) data.Thread.Set(currentStat.Thread) } func (s *SnapshotterMetricsCollector) Collect() { s.CollectCacheUsage() s.CollectResourceUsage() } func CollectSnapshotMetricsTimer(h *prometheus.HistogramVec, event SnapshotMethod) *prometheus.Timer { return prometheus.NewTimer( prometheus.ObserverFunc( (func(v float64) { h.WithLabelValues(string(event)).Observe(tool.FormatFloat64(v*1000, 6)) }))) } nydus-snapshotter-0.13.4/pkg/metrics/data/000077500000000000000000000000001453374237200204635ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/metrics/data/daemon.go000066400000000000000000000016511453374237200222600ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package data import ( "github.com/containerd/nydus-snapshotter/pkg/metrics/types/ttl" "github.com/prometheus/client_golang/prometheus" ) var ( nydusdEventLabel = "nydusd_event" nydusdVersionLabel = "version" daemonIDLabel = "daemon_id" ) var ( NydusdEventCount = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "nydusd_lifetime_event_counts", Help: "The lifetime events of nydus daemon.", }, []string{nydusdEventLabel}, ) NydusdCount = prometheus.NewGaugeVec( prometheus.GaugeOpts{ Name: "nydusd_counts", Help: "The counts of nydus daemon.", }, []string{nydusdVersionLabel}, ) NydusdRSS = ttl.NewGaugeVecWithTTL( prometheus.GaugeOpts{ Name: "nydusd_rss_kilobytes", Help: "Memory usage (RSS) of nydus daemon.", }, []string{daemonIDLabel}, ttl.DefaultTTL, ) ) nydus-snapshotter-0.13.4/pkg/metrics/data/fs.go000066400000000000000000000036661453374237200214350ustar00rootroot00000000000000/* * Copyright (c) 2021. Alibaba Cloud. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package data import ( "github.com/containerd/nydus-snapshotter/pkg/daemon/types" mtypes "github.com/containerd/nydus-snapshotter/pkg/metrics/types" "github.com/containerd/nydus-snapshotter/pkg/metrics/types/ttl" "github.com/prometheus/client_golang/prometheus" ) var ( imageRefLabel = "image_ref" ) var ( FsTotalRead = ttl.NewGaugeVecWithTTL( prometheus.GaugeOpts{ Name: "nydusd_total_read_bytes", Help: "Total bytes read against the nydus filesystem", }, []string{imageRefLabel}, ttl.DefaultTTL, ) FsReadHit = ttl.NewGaugeVecWithTTL( prometheus.GaugeOpts{ Name: "nydusd_read_hits", Help: "Total number of successful read operations.", }, []string{imageRefLabel}, ttl.DefaultTTL, ) FsReadError = ttl.NewGaugeVecWithTTL( prometheus.GaugeOpts{ Name: "nydusd_read_errors", Help: "Total number of failed read operations.", }, []string{imageRefLabel}, ttl.DefaultTTL, ) TotalHungIO = prometheus.NewGauge( prometheus.GaugeOpts{ Name: "nydusd_hung_io_counts", Help: "Total number of hung IOs.", }, ) ) // Fs metric histograms var MetricHists = []*mtypes.MetricHistogram{ { Desc: prometheus.NewDesc( "nydusd_cumulative_read_block_bytes", "Cumulative read size histogram for different block size, in bytes.", []string{imageRefLabel}, prometheus.Labels{}, ), Buckets: []uint64{1, 4, 16, 64, 128, 512, 1024, 2048}, GetCounters: func(m *types.FsMetrics) []uint64 { return m.BlockCountRead }, }, { Desc: prometheus.NewDesc( "nydusd_read_latency_microseconds", "Read latency histogram, in microseconds", []string{imageRefLabel}, prometheus.Labels{}, ), Buckets: []uint64{1, 20, 50, 100, 500, 1000, 2000, 4000}, GetCounters: func(m *types.FsMetrics) []uint64 { return m.ReadLatencyDist }, }, } nydus-snapshotter-0.13.4/pkg/metrics/data/snapshotter.go000066400000000000000000000035251453374237200233710ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package data import ( "github.com/prometheus/client_golang/prometheus" ) var ( defaultDurationBuckets = []float64{.5, 1, 5, 10, 50, 100, 150, 200, 250, 300, 350, 400, 600, 1000} snapshotEventLabel = "snapshot_operation" ) var ( SnapshotEventElapsedHists = prometheus.NewHistogramVec( prometheus.HistogramOpts{ Name: "snapshotter_snapshot_operation_elapsed_milliseconds", Help: "The elapsed time for snapshot events.", Buckets: defaultDurationBuckets, }, []string{snapshotEventLabel}, ) CacheUsage = prometheus.NewGauge( prometheus.GaugeOpts{ Name: "snapshotter_cache_usage_kilobytes", Help: "Disk usage of snapshotter local cache.", }, ) CPUUsage = prometheus.NewGauge( prometheus.GaugeOpts{ Name: "snapshotter_cpu_usage_percentage", Help: "CPU usage percentage of snapshotter.", }, ) MemoryUsage = prometheus.NewGauge( prometheus.GaugeOpts{ Name: "snapshotter_memory_usage_kilobytes", Help: "Memory usage (RSS) of snapshotter.", }, ) CPUSystem = prometheus.NewGauge( prometheus.GaugeOpts{ Name: "snapshotter_cpu_system_time_seconds", Help: "CPU time of snapshotter in system.", }, ) CPUUser = prometheus.NewGauge( prometheus.GaugeOpts{ Name: "snapshotter_cpu_user_time_seconds", Help: "CPU time of snapshotter in user.", }, ) Fds = prometheus.NewGauge( prometheus.GaugeOpts{ Name: "snapshotter_fd_counts", Help: "Fd counts of snapshotter.", }, ) RunTime = prometheus.NewGauge( prometheus.GaugeOpts{ Name: "snapshotter_run_time_seconds", Help: "Running time of snapshotter from starting.", }, ) Thread = prometheus.NewGauge( prometheus.GaugeOpts{ Name: "snapshotter_thread_counts", Help: "Thread counts of snapshotter.", }, ) ) nydus-snapshotter-0.13.4/pkg/metrics/listener.go000066400000000000000000000023721453374237200217320ustar00rootroot00000000000000/* * Copyright (c) 2021. Ant Group. All rights reserved. * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package metrics import ( "fmt" "net" "net/http" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/metrics/registry" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus/promhttp" ) // Endpoint for prometheus metrics var endpointPromMetrics = "/v1/metrics" func trapClosedConnErr(err error) error { if err == nil || errors.Is(err, net.ErrClosed) { return nil } return err } // NewListener creates a new TCP listener bound to the given address. func NewMetricsHTTPListenerServer(addr string) error { if addr == "" { return fmt.Errorf("the address for metrics HTTP server is invalid") } http.Handle(endpointPromMetrics, promhttp.HandlerFor(registry.Registry, promhttp.HandlerOpts{ ErrorHandling: promhttp.HTTPErrorOnError, })) l, err := net.Listen("tcp", addr) if err != nil { return errors.Wrapf(err, "metrics server listener, addr=%s", addr) } go func() { if err := http.Serve(l, nil); trapClosedConnErr(err) != nil { log.L.Errorf("Metrics server fails to listen or serve %s: %v", addr, err) } }() return nil } nydus-snapshotter-0.13.4/pkg/metrics/registry/000077500000000000000000000000001453374237200214225ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/metrics/registry/registry.go000066400000000000000000000013071453374237200236220ustar00rootroot00000000000000/* * Copyright (c) 2021. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package registry import ( "github.com/containerd/nydus-snapshotter/pkg/metrics/data" "github.com/prometheus/client_golang/prometheus" ) var ( Registry = prometheus.NewRegistry() ) func init() { Registry.MustRegister( data.FsTotalRead, data.FsReadHit, data.FsReadError, data.TotalHungIO, data.NydusdEventCount, data.NydusdCount, data.NydusdRSS, data.SnapshotEventElapsedHists, data.CacheUsage, data.CPUUsage, data.MemoryUsage, data.CPUSystem, data.CPUUser, data.Fds, data.RunTime, data.Thread, ) for _, m := range data.MetricHists { Registry.MustRegister(m) } } nydus-snapshotter-0.13.4/pkg/metrics/serve.go000066400000000000000000000115171453374237200212320ustar00rootroot00000000000000/* * Copyright (c) 2021. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package metrics import ( "context" "os" "time" "github.com/pkg/errors" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/containerd/nydus-snapshotter/pkg/manager" "github.com/containerd/nydus-snapshotter/pkg/metrics/collector" "github.com/containerd/nydus-snapshotter/pkg/metrics/tool" ) // Default interval to determine a hung IO. const defaultHungIOInterval = 10 * time.Second type ServerOpt func(*Server) error type Server struct { managers []*manager.Manager snCollectors []*collector.SnapshotterMetricsCollector fsCollector *collector.FsMetricsVecCollector inflightCollector *collector.InflightMetricsVecCollector } func WithProcessManagers(managers []*manager.Manager) ServerOpt { return func(s *Server) error { s.managers = append(s.managers, managers...) return nil } } func NewServer(ctx context.Context, opts ...ServerOpt) (*Server, error) { var s Server for _, o := range opts { if err := o(&s); err != nil { return nil, err } } s.fsCollector = collector.NewFsMetricsVecCollector() // TODO(tangbin): make hung IO interval configurable s.inflightCollector = collector.NewInflightMetricsVecCollector(defaultHungIOInterval) for _, pm := range s.managers { snCollector, err := collector.NewSnapshotterMetricsCollector(ctx, pm.CacheDir(), os.Getpid()) if err != nil { return nil, errors.Wrap(err, "new snapshotter metrics collector failed") } s.snCollectors = append(s.snCollectors, snCollector) } return &s, nil } func (s *Server) CollectDaemonResourceMetrics(ctx context.Context) { var daemonResource collector.DaemonResourceCollector for _, pm := range s.managers { // Collect daemon resource usage metrics. daemons := pm.ListDaemons() for _, d := range daemons { memRSS, err := tool.GetProcessMemoryRSSKiloBytes(d.Pid()) if err != nil { log.L.Warnf("Failed to get daemon %s RSS memory", d.ID()) } daemonResource.DaemonID = d.ID() daemonResource.Value = memRSS daemonResource.Collect() } } } func (s *Server) CollectFsMetrics(ctx context.Context) { var fsMetricsVec []collector.FsMetricsCollector for _, pm := range s.managers { // Collect FS metrics from fusedev daemons. if pm.FsDriver != config.FsDriverFusedev { continue } daemons := pm.ListDaemons() for _, d := range daemons { // Skip daemons that are not serving if d.State() != types.DaemonStateRunning { continue } for _, i := range d.RafsCache.List() { var sid string if d.IsSharedDaemon() { sid = i.SnapshotID } else { sid = "" } fsMetrics, err := d.GetFsMetrics(sid) if err != nil { log.G(ctx).Errorf("failed to get fs metric: %v", err) continue } fsMetricsVec = append(fsMetricsVec, collector.FsMetricsCollector{ Metrics: fsMetrics, ImageRef: i.ImageID, }) } } } if fsMetricsVec != nil { s.fsCollector.MetricsVec = fsMetricsVec s.fsCollector.Collect() } } func (s *Server) CollectInflightMetrics(ctx context.Context) { inflightMetricsVec := make([]*types.InflightMetrics, 0, 16) for _, pm := range s.managers { // Collect inflight metrics from fusedev daemons. if pm.FsDriver != config.FsDriverFusedev { continue } daemons := pm.ListDaemons() for _, d := range daemons { // Only count for daemon that is serving if d.State() != types.DaemonStateRunning { continue } inflightMetrics, err := d.GetInflightMetrics() if err != nil { log.G(ctx).Errorf("failed to get inflight metric: %v", err) continue } inflightMetricsVec = append(inflightMetricsVec, inflightMetrics) } } if inflightMetricsVec != nil { s.inflightCollector.MetricsVec = inflightMetricsVec s.inflightCollector.Collect() } } func (s *Server) StartCollectMetrics(ctx context.Context) error { // TODO(renzhen): make collect interval time configurable timer := time.NewTicker(time.Duration(1) * time.Minute) // The timer period is the same as the interval for determining hung IOs. // // Since the elapsed time of hung IO is configuration dependent, // e.g. timeout * retry times when the backend is a registry. // Therefore, we cannot get complete hung IO data after 1 minute. InflightTimer := time.NewTicker(s.inflightCollector.HungIOInterval) outer: for { select { case <-timer.C: s.CollectFsMetrics(ctx) s.CollectDaemonResourceMetrics(ctx) // Collect snapshotter metrics. for _, snCollector := range s.snCollectors { snCollector.Collect() } case <-InflightTimer.C: s.CollectInflightMetrics(ctx) case <-ctx.Done(): log.G(ctx).Infof("cancel metrics collecting") break outer } } return nil } nydus-snapshotter-0.13.4/pkg/metrics/tool/000077500000000000000000000000001453374237200205275ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/metrics/tool/common.go000066400000000000000000000022351453374237200223500ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package tool import ( "fmt" "os" "os/exec" "strconv" "strings" "github.com/containerd/containerd/log" ) const ( // Constant value for linux platform except alpha and ia64. defaultClkTck = 100 ) func FormatFloat64(f float64, point int) float64 { var value float64 switch point { case 6: value, _ = strconv.ParseFloat(fmt.Sprintf("%.6f", f), 64) case 2: fallthrough default: value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", f), 64) } return value } // FIXME: return error func ParseFloat64(val string) float64 { floatVal, _ := strconv.ParseFloat(val, 64) return floatVal } func GetClkTck() float64 { getconfPath, err := exec.LookPath("getconf") if err != nil { log.L.Warnf("can not find getconf in the system PATH, error %v", err) return defaultClkTck } out, err := exec.Command(getconfPath, "CLK_TCK").Output() if err != nil { log.L.Warnf("get CLK_TCK failed: %v", err) return defaultClkTck } return ParseFloat64(strings.ReplaceAll(string(out), "\n", "")) } func GetPageSize() float64 { return float64(os.Getpagesize()) } nydus-snapshotter-0.13.4/pkg/metrics/tool/stat.go000066400000000000000000000052441453374237200220360ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package tool import ( "os" "path" "strconv" "strings" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/pkg/errors" ) // Please refer to https://man7.org/linux/man-pages/man5/proc.5.html for the metrics meanings type Stat struct { Utime float64 Stime float64 Cutime float64 Cstime float64 Thread float64 Start float64 Rss float64 Fds float64 Uptime float64 } var ( ClkTck = GetClkTck() PageSize = GetPageSize() ) func CalculateCPUUtilization(begin *Stat, now *Stat) (float64, error) { if begin == nil || now == nil { return 0.0, errdefs.ErrInvalidArgument } cpuSys := (now.Stime - begin.Stime) / ClkTck cpuUsr := (now.Utime - begin.Utime) / ClkTck total := cpuSys + cpuUsr seconds := now.Uptime - begin.Uptime cpuPercent := (total / seconds) * 100 return cpuPercent, nil } func GetProcessMemoryRSSKiloBytes(pid int) (float64, error) { stat, err := GetProcessStat(pid) if err != nil { return 0.0, errors.Wrapf(err, "get process stat") } return stat.Rss * PageSize / 1024, nil } func GetProcessStat(pid int) (*Stat, error) { uptimeBytes, err := os.ReadFile(path.Join("/proc", "uptime")) if err != nil { return nil, errors.Wrapf(err, "get uptime") } uptime := ParseFloat64(strings.Split(string(uptimeBytes), " ")[0]) statBytes, err := os.ReadFile(path.Join("/proc", strconv.Itoa(pid), "stat")) if err != nil { return nil, errors.Wrapf(err, "get process %d stat", pid) } splitAfterStat := strings.SplitAfter(string(statBytes), ")") if len(splitAfterStat) == 0 || len(splitAfterStat) == 1 { return nil, errors.Errorf("Can not find process, PID: %d", pid) } infos := strings.Split(splitAfterStat[1], " ") files, err := os.ReadDir(path.Join("/proc", strconv.Itoa(pid), "fdinfo")) if err != nil { return nil, errors.Wrapf(err, "read fdinfo") } return &Stat{ Utime: ParseFloat64(infos[12]), Stime: ParseFloat64(infos[13]), Cutime: ParseFloat64(infos[14]), Cstime: ParseFloat64(infos[15]), Thread: ParseFloat64(infos[18]), Start: ParseFloat64(infos[20]), Rss: ParseFloat64(infos[22]), Fds: float64(len(files)), Uptime: uptime, }, nil } func GetProcessRunningState(pid int) (string, error) { statBytes, err := os.ReadFile(path.Join("/proc", strconv.Itoa(pid), "stat")) if err != nil { return "", errors.Wrapf(err, "get process %d stat", pid) } segments := strings.Split(string(statBytes), " ") state := segments[2] return state, nil } func IsZombieProcess(pid int) (bool, error) { s, err := GetProcessRunningState(pid) if err != nil { return false, err } return s == "Z", nil } nydus-snapshotter-0.13.4/pkg/metrics/tool/stat_test.go000066400000000000000000000005151453374237200230710ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package tool import ( "testing" "github.com/stretchr/testify/assert" ) func TestFindZombie(t *testing.T) { s, err := GetProcessRunningState(1) assert.NoError(t, err) assert.Contains(t, []string{"Ss", "S"}, s) } nydus-snapshotter-0.13.4/pkg/metrics/types/000077500000000000000000000000001453374237200207165ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/metrics/types/ttl/000077500000000000000000000000001453374237200215215ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/metrics/types/ttl/gauge.go000066400000000000000000000033131453374237200231400ustar00rootroot00000000000000/* * Copyright (c) 2021. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package ttl import ( "strings" "sync" "time" "github.com/prometheus/client_golang/prometheus" ) var ( defaultCleanUpPeriod = 10 * time.Minute DefaultTTL = 3 * time.Minute ) type LabelWithValue struct { name string value string } type GaugeVec struct { labelName []string ttl time.Duration labelValueMap map[LabelWithValue]time.Time mu sync.Mutex *prometheus.GaugeVec } type GaugeWithTTL struct { labelValue []string vec *GaugeVec gauge prometheus.Gauge } func NewGaugeVecWithTTL(opts prometheus.GaugeOpts, labelNames []string, ttl time.Duration) *GaugeVec { gaugeVec := prometheus.NewGaugeVec(opts, labelNames) res := &GaugeVec{ labelName: labelNames, ttl: ttl, GaugeVec: gaugeVec, labelValueMap: make(map[LabelWithValue]time.Time), } go res.cleanUpExpired() return res } func (gv *GaugeVec) cleanUpExpired() { timer := time.NewTicker(defaultCleanUpPeriod) for range timer.C { gv.mu.Lock() for k, v := range gv.labelValueMap { if time.Now().After(v) { gv.DeleteLabelValues(k.value) delete(gv.labelValueMap, k) } } gv.mu.Unlock() } } func (gv *GaugeVec) WithLabelValues(val ...string) *GaugeWithTTL { gauge := gv.GaugeVec.WithLabelValues(val...) return &GaugeWithTTL{ vec: gv, labelValue: val, gauge: gauge, } } func (gwt *GaugeWithTTL) Set(val float64) { gwt.vec.mu.Lock() gwt.vec.labelValueMap[LabelWithValue{ name: strings.Join(gwt.vec.labelName, ","), value: strings.Join(gwt.labelValue, ","), }] = time.Now().Add(gwt.vec.ttl) gwt.vec.mu.Unlock() gwt.gauge.Set(val) } nydus-snapshotter-0.13.4/pkg/metrics/types/ttl/gauge_test.go000066400000000000000000000033141453374237200242000ustar00rootroot00000000000000/* * Copyright (c) 2021. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package ttl import ( "sync" "testing" "time" "github.com/prometheus/client_golang/prometheus" dto "github.com/prometheus/client_model/go" "github.com/stretchr/testify/assert" ) func TestNewGaugeVecWithTTL(t *testing.T) { defaultCleanUpPeriod = 5 * time.Second g := NewGaugeVecWithTTL(prometheus.GaugeOpts{ Name: "nydusd_fuse_connection_waiting_count", Help: "nydusd_fuse_connection_waiting_count", }, []string{"daemon_id"}, 3*time.Second, ) g.WithLabelValues("value1").Set(10) g.WithLabelValues("value2").Set(10) metricsCh := make(chan prometheus.Metric, 2) go g.Collect(metricsCh) var metricsSlice []dto.Metric var mu sync.Mutex var wg sync.WaitGroup wg.Add(2) go func() { for m := range metricsCh { var metrics dto.Metric err := m.Write(&metrics) assert.Nil(t, err) metricsSlice = append(metricsSlice, metrics) wg.Done() } }() wg.Wait() assert.Equal(t, 2, len(metricsSlice)) metricsSlice = []dto.Metric{} time.Sleep(3 * time.Second) g.WithLabelValues("value1").Set(10) g.mu.Lock() assert.Equal(t, 2, len(g.labelValueMap)) g.mu.Unlock() time.Sleep(3 * time.Second) g.mu.Lock() assert.Equal(t, 1, len(g.labelValueMap)) g.mu.Unlock() metricsCh = make(chan prometheus.Metric, 2) go g.Collect(metricsCh) go func() { for m := range metricsCh { var metrics dto.Metric err := m.Write(&metrics) assert.Nil(t, err) mu.Lock() metricsSlice = append(metricsSlice, metrics) mu.Unlock() } }() time.Sleep(6 * time.Second) mu.Lock() assert.Equal(t, 1, len(metricsSlice)) mu.Unlock() g.mu.Lock() assert.Equal(t, 0, len(g.labelValueMap)) g.mu.Unlock() } nydus-snapshotter-0.13.4/pkg/metrics/types/types.go000066400000000000000000000035501453374237200224140ustar00rootroot00000000000000/* * Copyright (c) 2021. Alibaba Cloud. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package fs import ( "fmt" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/prometheus/client_golang/prometheus" ) type Fop int const ( Getattr = iota Readlink Open Release Read Statfs Getxattr Listxattr Opendir Lookup Readdir Readdirplus Access Forget BatchForget MaxFops ) func GetMaxFops() uint { return MaxFops } func MakeFopBuckets() []uint64 { s := make([]uint64, 0, MaxFops) for i := 0; i < MaxFops; i++ { s = append(s, uint64(i)) } return s } type GetCountersFn func(*types.FsMetrics) []uint64 type MetricHistogram struct { Desc *prometheus.Desc Buckets []uint64 GetCounters GetCountersFn // Save the last generated histogram metric constHists []prometheus.Metric } func (h *MetricHistogram) ToConstHistogram(m *types.FsMetrics, imageRef string) (prometheus.Metric, error) { var count, sum uint64 counters := h.GetCounters(m) hmap := make(map[float64]uint64) if len(counters) != len(h.Buckets) { return nil, fmt.Errorf("length of counters(%d) and buckets(%d) not equal: %+v", len(counters), len(h.Buckets), h.Buckets) } for i, c := range counters { count += c sum += h.Buckets[i] * c hmap[float64(h.Buckets[i])] = count } return prometheus.MustNewConstHistogram( h.Desc, count, float64(sum), hmap, imageRef, ), nil } func (h *MetricHistogram) Clear() { h.constHists = nil } func (h *MetricHistogram) Save(m prometheus.Metric) { h.constHists = append(h.constHists, m) } // Implement prometheus.Collector interface func (h *MetricHistogram) Describe(ch chan<- *prometheus.Desc) { if h.Desc != nil { ch <- h.Desc } } func (h *MetricHistogram) Collect(ch chan<- prometheus.Metric) { if h.constHists != nil { for _, hist := range h.constHists { ch <- hist } } } nydus-snapshotter-0.13.4/pkg/pprof/000077500000000000000000000000001453374237200172325ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/pprof/listener.go000066400000000000000000000021431453374237200214060ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package pprof import ( "net" "net/http" "net/http/pprof" "github.com/containerd/containerd/log" "github.com/pkg/errors" ) func NewPprofHTTPListener(addr string) error { if addr == "" { return errors.New("the address for pprof HTTP server is invalid") } http.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate")) http.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine")) http.Handle("/debug/pprof/allocs", pprof.Handler("allocs")) http.Handle("/debug/pprof/block", pprof.Handler("block")) http.Handle("/debug/pprof/mutex", pprof.Handler("mutex")) http.Handle("/debug/pprof/heap", pprof.Handler("heap")) l, err := net.Listen("tcp", addr) if err != nil { return errors.Wrapf(err, "pprof server listener, addr=%s", addr) } go func() { log.L.Infof("Start pprof HTTP server on %s", addr) if err := http.Serve(l, nil); err != nil && !errors.Is(err, net.ErrClosed) { log.L.Errorf("Pprof server fails to listen or serve %s: %v", addr, err) } }() return nil } nydus-snapshotter-0.13.4/pkg/prefetch/000077500000000000000000000000001453374237200177045ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/prefetch/prefetch.go000066400000000000000000000022751453374237200220410ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package prefetch import ( "encoding/json" "sync" "github.com/containerd/containerd/log" ) type prefetchInfo struct { prefetchMap map[string]string prefetchMutex sync.Mutex } var Pm prefetchInfo func (p *prefetchInfo) SetPrefetchFiles(body []byte) error { p.prefetchMutex.Lock() defer p.prefetchMutex.Unlock() var prefetchMsg []map[string]string if err := json.Unmarshal(body, &prefetchMsg); err != nil { return err } if p.prefetchMap == nil { p.prefetchMap = make(map[string]string) } for _, item := range prefetchMsg { image := item["image"] prefetchfiles := item["prefetch"] p.prefetchMap[image] = prefetchfiles } log.L.Infof("received prefetch list from nri plugin: %v ", p.prefetchMap) return nil } func (p *prefetchInfo) GetPrefetchInfo(image string) string { p.prefetchMutex.Lock() defer p.prefetchMutex.Unlock() if prefetchfiles, ok := p.prefetchMap[image]; ok { return prefetchfiles } return "" } func (p *prefetchInfo) DeleteFromPrefetchMap(image string) { p.prefetchMutex.Lock() defer p.prefetchMutex.Unlock() delete(p.prefetchMap, image) } nydus-snapshotter-0.13.4/pkg/rafs/000077500000000000000000000000001453374237200170375ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/rafs/rafs.go000066400000000000000000000106441453374237200203260ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package rafs import ( "os" "path" "path/filepath" "sync" "github.com/mohae/deepcopy" "github.com/pkg/errors" "github.com/containerd/containerd/errdefs" "github.com/containerd/nydus-snapshotter/config" ) const ( AnnoFsCacheDomainID string = "fscache.domainid" AnnoFsCacheID string = "fscache.id" ) type NewRafsOpt func(r *Rafs) error func init() { // TODO // A set of RAFS filesystem instances associated with a nydusd daemon. RafsGlobalCache = Cache{instances: make(map[string]*Rafs)} } // Global cache to hold all RAFS instances. var RafsGlobalCache Cache type Cache struct { mu sync.Mutex instances map[string]*Rafs } func NewRafsCache() Cache { return Cache{instances: make(map[string]*Rafs)} } func (rs *Cache) Lock() { rs.mu.Lock() } func (rs *Cache) Unlock() { rs.mu.Unlock() } func (rs *Cache) Add(r *Rafs) { rs.mu.Lock() rs.instances[r.SnapshotID] = r rs.mu.Unlock() } func (rs *Cache) Remove(snapshotID string) { rs.mu.Lock() delete(rs.instances, snapshotID) rs.mu.Unlock() } func (rs *Cache) Get(snapshotID string) *Rafs { rs.mu.Lock() defer rs.mu.Unlock() return rs.instances[snapshotID] } func (rs *Cache) Len() int { rs.mu.Lock() len := len(rs.instances) rs.mu.Unlock() return len } func (rs *Cache) Head() *Rafs { rs.mu.Lock() defer rs.mu.Unlock() for _, v := range rs.instances { return v } return nil } func (rs *Cache) List() map[string]*Rafs { rs.mu.Lock() defer rs.mu.Unlock() instances := deepcopy.Copy(rs.instances).(map[string]*Rafs) return instances } func (rs *Cache) ListLocked() map[string]*Rafs { return rs.instances } func (rs *Cache) SetIntances(instances map[string]*Rafs) { rs.Lock() defer rs.Unlock() rs.instances = instances } // The whole struct will be persisted type Rafs struct { Seq uint64 ImageID string // Usually is the image reference DaemonID string FsDriver string SnapshotID string // Given by containerd SnapshotDir string // 1. A host kernel EROFS/TARFS mountpoint // 2. Absolute path to each rafs instance root directory. Mountpoint string Annotations map[string]string } func NewRafs(snapshotID, imageID, fsDriver string) (*Rafs, error) { snapshotDir := path.Join(config.GetSnapshotsRootDir(), snapshotID) rafs := &Rafs{ FsDriver: fsDriver, ImageID: imageID, SnapshotID: snapshotID, SnapshotDir: snapshotDir, Annotations: make(map[string]string), } if err := os.MkdirAll(snapshotDir, 0755); err != nil { return nil, err } RafsGlobalCache.Add(rafs) return rafs, nil } func (r *Rafs) AddAnnotation(k, v string) { r.Annotations[k] = v } func (r *Rafs) GetSnapshotDir() string { return r.SnapshotDir } func (r *Rafs) GetFsDriver() string { if r.FsDriver != "" { return r.FsDriver } return config.GetFsDriver() } // Blob caches' chunk bitmap and meta headers are stored here. func (r *Rafs) FscacheWorkDir() string { return filepath.Join(r.SnapshotDir, "fs") } func (r *Rafs) SetMountpoint(mp string) { r.Mountpoint = mp } // Get top level mount point for the RAFS instance: // - FUSE with dedicated mode: the FUSE filesystem mount point, the RAFS filesystem is directly // mounted at the mount point. // - FUSE with shared mode: the FUSE filesystem mount point, the RAFS filesystem is mounted // at a subdirectory under the mount point. // - EROFS/fscache: the EROFS filesystem mount point. func (r *Rafs) GetMountpoint() string { return r.Mountpoint } // Get the sub-directory under a FUSE mount point to mount a RAFS instance. // For a nydusd daemon in shared mode, one or more RAFS filesystem instances can be mounted // to sub-directories of the FUSE filesystem. This method returns the subdirectory for a // RAFS filesystem instance. func (r *Rafs) RelaMountpoint() string { return filepath.Join("/", r.SnapshotID) } func (r *Rafs) BootstrapFile() (string, error) { // meta files are stored at /fs/image/image.boot bootstrap := filepath.Join(r.SnapshotDir, "fs", "image", "image.boot") _, err := os.Stat(bootstrap) if err == nil { return bootstrap, nil } if os.IsNotExist(err) { // check legacy location for backward compatibility bootstrap = filepath.Join(r.SnapshotDir, "fs", "image.boot") _, err = os.Stat(bootstrap) if err == nil { return bootstrap, nil } } return "", errors.Wrapf(errdefs.ErrNotFound, "bootstrap %s", bootstrap) } nydus-snapshotter-0.13.4/pkg/referrer/000077500000000000000000000000001453374237200177205ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/referrer/manager.go000066400000000000000000000047451453374237200216730ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package referrer import ( "context" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/auth" "github.com/golang/groupcache/lru" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "golang.org/x/sync/singleflight" ) type Manager struct { insecure bool cache *lru.Cache sg singleflight.Group } func NewManager(insecure bool) *Manager { manager := Manager{ insecure: insecure, cache: lru.New(500), sg: singleflight.Group{}, } return &manager } // CheckReferrer attempts to fetch the referrers and parse out // the nydus image by specified manifest digest. func (manager *Manager) CheckReferrer(ctx context.Context, ref string, manifestDigest digest.Digest) (*ocispec.Descriptor, error) { metaLayer, err, _ := manager.sg.Do(manifestDigest.String(), func() (interface{}, error) { // Try to get nydus metadata layer descriptor from LRU cache. if metaLayer, ok := manager.cache.Get(manifestDigest); ok { desc := metaLayer.(ocispec.Descriptor) return &desc, nil } keyChain, err := auth.GetKeyChainByRef(ref, nil) if err != nil { return nil, errors.Wrap(err, "get key chain") } // No LRU cache found, try to fetch referrers and parse out // the nydus metadata layer descriptor. referrer := newReferrer(keyChain, manager.insecure) metaLayer, err := referrer.checkReferrer(ctx, ref, manifestDigest) if err != nil { return nil, errors.Wrap(err, "check referrer") } // FIXME: how to invalidate the LRU cache if referrers update? manager.cache.Add(manifestDigest, *metaLayer) return metaLayer, nil }) if err != nil { log.L.WithField("ref", ref).WithError(err).Warn("check referrer") return nil, err } return metaLayer.(*ocispec.Descriptor), nil } // TryFetchMetadata try to fetch and unpack nydus metadata file to specified path. func (manager *Manager) TryFetchMetadata(ctx context.Context, ref string, manifestDigest digest.Digest, metadataPath string) error { metaLayer, err := manager.CheckReferrer(ctx, ref, manifestDigest) if err != nil { return errors.Wrap(err, "check referrer") } keyChain, err := auth.GetKeyChainByRef(ref, nil) if err != nil { return errors.Wrap(err, "get key chain") } referrer := newReferrer(keyChain, manager.insecure) return referrer.fetchMetadata(ctx, ref, *metaLayer, metadataPath) } nydus-snapshotter-0.13.4/pkg/referrer/referrer.go000066400000000000000000000074351453374237200220740ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package referrer import ( "context" "encoding/json" "fmt" "io" "os" "github.com/containerd/nydus-snapshotter/pkg/auth" "github.com/containerd/nydus-snapshotter/pkg/label" "github.com/containerd/nydus-snapshotter/pkg/remote" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) // Containerd restricts the max size of manifest index to 8M, follow it. const maxManifestIndexSize = 0x800000 const metadataNameInLayer = "image/image.boot" type referrer struct { remote *remote.Remote } func newReferrer(keyChain *auth.PassKeyChain, insecure bool) *referrer { return &referrer{ remote: remote.New(keyChain, insecure), } } // checkReferrer fetches the referrers and parses out the nydus // image by specified manifest digest. // it's using distribution list referrers API. func (r *referrer) checkReferrer(ctx context.Context, ref string, manifestDigest digest.Digest) (*ocispec.Descriptor, error) { handle := func() (*ocispec.Descriptor, error) { // Create an new resolver to request. fetcher, err := r.remote.Fetcher(ctx, ref) if err != nil { return nil, errors.Wrap(err, "get fetcher") } // Fetch image referrers from remote registry. rc, _, err := fetcher.(remotes.ReferrersFetcher).FetchReferrers(ctx, manifestDigest) if err != nil { return nil, errors.Wrap(err, "fetch referrers") } defer rc.Close() // Parse image manifest list from referrers. var index ocispec.Index bytes, err := io.ReadAll(io.LimitReader(rc, maxManifestIndexSize)) if err != nil { return nil, errors.Wrap(err, "read referrers") } if err := json.Unmarshal(bytes, &index); err != nil { return nil, errors.Wrap(err, "unmarshal referrers index") } if len(index.Manifests) == 0 { return nil, fmt.Errorf("empty referrer list") } // Prefer to fetch the last manifest and check if it is a nydus image. // TODO: should we search by matching ArtifactType? rc, err = fetcher.Fetch(ctx, index.Manifests[0]) if err != nil { return nil, errors.Wrap(err, "fetch referrers") } defer rc.Close() var manifest ocispec.Manifest bytes, err = io.ReadAll(rc) if err != nil { return nil, errors.Wrap(err, "read manifest") } if err := json.Unmarshal(bytes, &manifest); err != nil { return nil, errors.Wrap(err, "unmarshal manifest") } if len(manifest.Layers) < 1 { return nil, fmt.Errorf("invalid manifest") } metaLayer := manifest.Layers[len(manifest.Layers)-1] if !label.IsNydusMetaLayer(metaLayer.Annotations) { return nil, fmt.Errorf("invalid nydus manifest") } return &metaLayer, nil } desc, err := handle() if err != nil && r.remote.RetryWithPlainHTTP(ref, err) { return handle() } return desc, err } // fetchMetadata fetches and unpacks nydus metadata file to specified path. func (r *referrer) fetchMetadata(ctx context.Context, ref string, desc ocispec.Descriptor, metadataPath string) error { handle := func() error { // Create an new resolver to request. resolver := r.remote.Resolve(ctx, ref) fetcher, err := resolver.Fetcher(ctx, ref) if err != nil { return errors.Wrap(err, "get fetcher") } // Unpack nydus metadata file to specified path. rc, err := fetcher.Fetch(ctx, desc) if err != nil { return errors.Wrap(err, "fetch nydus metadata") } defer rc.Close() if err := remote.Unpack(rc, metadataNameInLayer, metadataPath); err != nil { os.Remove(metadataPath) return errors.Wrap(err, "unpack metadata from layer") } return nil } // TODO: check metafile already exists err := handle() if err != nil && r.remote.RetryWithPlainHTTP(ref, err) { return handle() } return err } nydus-snapshotter-0.13.4/pkg/remote/000077500000000000000000000000001453374237200173775ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/remote/remote.go000066400000000000000000000073151453374237200212270ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package remote import ( "context" "crypto/tls" "fmt" "net/http" "strings" "github.com/containerd/nydus-snapshotter/pkg/auth" "github.com/docker/distribution/reference" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes/docker" ) // IsErrHTTPResponseToHTTPSClient returns whether err is // "http: server gave HTTP response to HTTPS client" func isErrHTTPResponseToHTTPSClient(err error) bool { // The error string is unexposed as of Go 1.16, so we can't use `errors.Is`. // https://github.com/golang/go/issues/44855 const unexposed = "server gave HTTP response to HTTPS client" return strings.Contains(err.Error(), unexposed) } // IsErrConnectionRefused return whether err is // "connect: connection refused" func isErrConnectionRefused(err error) bool { const errMessage = "connect: connection refused" return strings.Contains(err.Error(), errMessage) } type Remote struct { // The resolver is used for image pull or fetches requests. The best practice // in containerd is that each resolver instance is used only once for a request // and is destroyed when the request completes. When a registry token expires, // the resolver does not re-apply for a new token, so it's better to create a // new resolver instance using resolverFunc for each request. resolverFunc func(plainHTTP bool) remotes.Resolver // withPlainHTTP attempts to request the remote registry using http instead // of https. withPlainHTTP bool } func New(keyChain *auth.PassKeyChain, insecure bool) *Remote { // nolint:unparam credFunc := func(string) (string, string, error) { if keyChain == nil { return "", "", nil } return keyChain.Username, keyChain.Password, nil } newClient := func(insecure bool) *http.Client { client := http.DefaultClient transport := http.DefaultTransport.(*http.Transport) transport.TLSClientConfig = &tls.Config{ InsecureSkipVerify: insecure, } client.Transport = transport return client } resolverFunc := func(plainHTTP bool) remotes.Resolver { registryHosts := docker.ConfigureDefaultRegistries( docker.WithAuthorizer( docker.NewDockerAuthorizer( docker.WithAuthClient(newClient(insecure)), docker.WithAuthCreds(credFunc), ), ), docker.WithClient(newClient(insecure)), docker.WithPlainHTTP(func(host string) (bool, error) { return plainHTTP, nil }), ) return docker.NewResolver(docker.ResolverOptions{ Hosts: registryHosts, }) } return &Remote{ resolverFunc: resolverFunc, withPlainHTTP: false, } } func (remote *Remote) RetryWithPlainHTTP(ref string, err error) bool { retry := err != nil && (isErrHTTPResponseToHTTPSClient(err) || isErrConnectionRefused(err)) if !retry { return false } parsed, _ := reference.ParseNormalizedNamed(ref) if parsed != nil { host := reference.Domain(parsed) // If the error message includes the current registry host string, it // implies that we can retry the request with plain HTTP. if strings.Contains(err.Error(), fmt.Sprintf("/%s/", host)) { logrus.WithError(err).Warningf("retrying with http for %s", host) remote.withPlainHTTP = true } } return remote.withPlainHTTP } func (remote *Remote) Resolve(ctx context.Context, ref string) remotes.Resolver { return remote.resolverFunc(remote.withPlainHTTP) } func (remote *Remote) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) { resolver := remote.Resolve(ctx, ref) fetcher, err := resolver.Fetcher(ctx, ref) if err != nil { return nil, errors.Wrap(err, "get fetcher") } return fetcher, nil } nydus-snapshotter-0.13.4/pkg/remote/remotes/000077500000000000000000000000001453374237200210555ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/000077500000000000000000000000001453374237200223245ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/auth/000077500000000000000000000000001453374237200232655ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/auth/fetch.go000066400000000000000000000142661453374237200247160ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package auth import ( "context" "encoding/json" "errors" "fmt" "net/http" "net/url" "strings" "time" "github.com/containerd/containerd/log" "github.com/containerd/containerd/version" remoteserrors "github.com/containerd/nydus-snapshotter/pkg/remote/remotes/errors" ) var ( // ErrNoToken is returned if a request is successful but the body does not // contain an authorization token. ErrNoToken = errors.New("authorization server did not include a token in the response") ) // GenerateTokenOptions generates options for fetching a token based on a challenge func GenerateTokenOptions(ctx context.Context, host, username, secret string, c Challenge) (TokenOptions, error) { realm, ok := c.Parameters["realm"] if !ok { return TokenOptions{}, errors.New("no realm specified for token auth challenge") } realmURL, err := url.Parse(realm) if err != nil { return TokenOptions{}, fmt.Errorf("invalid token auth challenge realm: %w", err) } to := TokenOptions{ Realm: realmURL.String(), Service: c.Parameters["service"], Username: username, Secret: secret, } scope, ok := c.Parameters["scope"] if ok { to.Scopes = append(to.Scopes, strings.Split(scope, " ")...) } else { log.G(ctx).WithField("host", host).Debug("no scope specified for token auth challenge") } return to, nil } // TokenOptions are options for requesting a token type TokenOptions struct { Realm string Service string Scopes []string Username string Secret string // FetchRefreshToken enables fetching a refresh token (aka "identity token", "offline token") along with the bearer token. // // For HTTP GET mode (FetchToken), FetchRefreshToken sets `offline_token=true` in the request. // https://docs.docker.com/registry/spec/auth/token/#requesting-a-token // // For HTTP POST mode (FetchTokenWithOAuth), FetchRefreshToken sets `access_type=offline` in the request. // https://docs.docker.com/registry/spec/auth/oauth/#getting-a-token FetchRefreshToken bool } // OAuthTokenResponse is response from fetching token with a OAuth POST request type OAuthTokenResponse struct { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` ExpiresIn int `json:"expires_in"` IssuedAt time.Time `json:"issued_at"` Scope string `json:"scope"` } // FetchTokenWithOAuth fetches a token using a POST request func FetchTokenWithOAuth(ctx context.Context, client *http.Client, headers http.Header, clientID string, to TokenOptions) (*OAuthTokenResponse, error) { form := url.Values{} if len(to.Scopes) > 0 { form.Set("scope", strings.Join(to.Scopes, " ")) } form.Set("service", to.Service) form.Set("client_id", clientID) if to.Username == "" { form.Set("grant_type", "refresh_token") form.Set("refresh_token", to.Secret) } else { form.Set("grant_type", "password") form.Set("username", to.Username) form.Set("password", to.Secret) } if to.FetchRefreshToken { form.Set("access_type", "offline") } req, err := http.NewRequestWithContext(ctx, http.MethodPost, to.Realm, strings.NewReader(form.Encode())) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") for k, v := range headers { req.Header[k] = append(req.Header[k], v...) } if len(req.Header.Get("User-Agent")) == 0 { req.Header.Set("User-Agent", "containerd/"+version.Version) } resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 400 { return nil, remoteserrors.NewUnexpectedStatusErr(resp) } decoder := json.NewDecoder(resp.Body) var tr OAuthTokenResponse if err = decoder.Decode(&tr); err != nil { return nil, fmt.Errorf("unable to decode token response: %w", err) } if tr.AccessToken == "" { return nil, ErrNoToken } return &tr, nil } // FetchTokenResponse is response from fetching token with GET request type FetchTokenResponse struct { Token string `json:"token"` AccessToken string `json:"access_token"` ExpiresIn int `json:"expires_in"` IssuedAt time.Time `json:"issued_at"` RefreshToken string `json:"refresh_token"` } // FetchToken fetches a token using a GET request func FetchToken(ctx context.Context, client *http.Client, headers http.Header, to TokenOptions) (*FetchTokenResponse, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, to.Realm, nil) if err != nil { return nil, err } for k, v := range headers { req.Header[k] = append(req.Header[k], v...) } if len(req.Header.Get("User-Agent")) == 0 { req.Header.Set("User-Agent", "containerd/"+version.Version) } reqParams := req.URL.Query() if to.Service != "" { reqParams.Add("service", to.Service) } for _, scope := range to.Scopes { reqParams.Add("scope", scope) } if to.Secret != "" { req.SetBasicAuth(to.Username, to.Secret) } if to.FetchRefreshToken { reqParams.Add("offline_token", "true") } req.URL.RawQuery = reqParams.Encode() resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 400 { return nil, remoteserrors.NewUnexpectedStatusErr(resp) } decoder := json.NewDecoder(resp.Body) var tr FetchTokenResponse if err = decoder.Decode(&tr); err != nil { return nil, fmt.Errorf("unable to decode token response: %w", err) } // `access_token` is equivalent to `token` and if both are specified // the choice is undefined. Canonicalize `access_token` by sticking // things in `token`. if tr.AccessToken != "" { tr.Token = tr.AccessToken } if tr.Token == "" { return nil, ErrNoToken } return &tr, nil } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/auth/fetch_test.go000066400000000000000000000054601453374237200257510ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package auth import ( "context" "reflect" "strings" "testing" ) func TestGenerateTokenOptions(t *testing.T) { for _, tc := range []struct { name string realm string service string username string secret string scope string }{ { name: "MultipleScopes", realm: "https://test-realm.com", service: "registry-service", username: "username", secret: "secret", scope: "repository:foo/bar:pull repository:foo/bar:pull,push", }, { name: "SingleScope", realm: "https://test-realm.com", service: "registry-service", username: "username", secret: "secret", scope: "repository:foo/bar:pull", }, { name: "NoScope", realm: "https://test-realm.com", service: "registry-service", username: "username", secret: "secret", }, } { t.Run(tc.name, func(t *testing.T) { c := Challenge{ Scheme: BearerAuth, Parameters: map[string]string{ "realm": tc.realm, "service": tc.service, "scope": tc.scope, }, } options, err := GenerateTokenOptions(context.Background(), "host", tc.username, tc.secret, c) if err != nil { t.Fatalf("unexpected error %v", err) } expected := TokenOptions{ Realm: tc.realm, Service: tc.service, Scopes: strings.Split(tc.scope, " "), Username: tc.username, Secret: tc.secret, } if !reflect.DeepEqual(options, expected) { t.Fatalf("expected %v, but got %v", expected, options) } }) } t.Run("MissingRealm", func(t *testing.T) { c := Challenge{ Scheme: BearerAuth, Parameters: map[string]string{ "service": "service", "scope": "repository:foo/bar:pull,push", }, } _, err := GenerateTokenOptions(context.Background(), "host", "username", "secret", c) if err == nil { t.Fatal("expected an err and got nil") } }) t.Run("RealmParseError", func(t *testing.T) { c := Challenge{ Scheme: BearerAuth, Parameters: map[string]string{ "realm": "127.0.0.1:8080", "service": "service", "scope": "repository:foo/bar:pull,push", }, } _, err := GenerateTokenOptions(context.Background(), "host", "username", "secret", c) if err == nil { t.Fatal("expected an err and got nil") } }) } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/auth/parse.go000066400000000000000000000114351453374237200247320ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package auth import ( "net/http" "sort" "strings" ) // AuthenticationScheme defines scheme of the authentication method type AuthenticationScheme byte const ( // BasicAuth is scheme for Basic HTTP Authentication RFC 7617 BasicAuth AuthenticationScheme = 1 << iota // DigestAuth is scheme for HTTP Digest Access Authentication RFC 7616 DigestAuth // BearerAuth is scheme for OAuth 2.0 Bearer Tokens RFC 6750 BearerAuth ) // Challenge carries information from a WWW-Authenticate response header. // See RFC 2617. type Challenge struct { // scheme is the auth-scheme according to RFC 2617 Scheme AuthenticationScheme // parameters are the auth-params according to RFC 2617 Parameters map[string]string } type byScheme []Challenge func (bs byScheme) Len() int { return len(bs) } func (bs byScheme) Swap(i, j int) { bs[i], bs[j] = bs[j], bs[i] } // Sort in priority order: token > digest > basic func (bs byScheme) Less(i, j int) bool { return bs[i].Scheme > bs[j].Scheme } // Octet types from RFC 2616. type octetType byte var octetTypes [256]octetType const ( isToken octetType = 1 << iota isSpace ) func init() { // OCTET = // CHAR = // CTL = // CR = // LF = // SP = // HT = // <"> = // CRLF = CR LF // LWS = [CRLF] 1*( SP | HT ) // TEXT = // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT // token = 1* // qdtext = > for c := 0; c < 256; c++ { var t octetType isCtl := c <= 31 || c == 127 isChar := 0 <= c && c <= 127 isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) if strings.ContainsRune(" \t\r\n", rune(c)) { t |= isSpace } if isChar && !isCtl && !isSeparator { t |= isToken } octetTypes[c] = t } } // ParseAuthHeader parses challenges from WWW-Authenticate header func ParseAuthHeader(header http.Header) []Challenge { challenges := []Challenge{} for _, h := range header[http.CanonicalHeaderKey("WWW-Authenticate")] { v, p := parseValueAndParams(h) var s AuthenticationScheme switch v { case "basic": s = BasicAuth case "digest": s = DigestAuth case "bearer": s = BearerAuth default: continue } challenges = append(challenges, Challenge{Scheme: s, Parameters: p}) } sort.Stable(byScheme(challenges)) return challenges } func parseValueAndParams(header string) (value string, params map[string]string) { params = make(map[string]string) value, s := expectToken(header) if value == "" { return } value = strings.ToLower(value) for { var pkey string pkey, s = expectToken(skipSpace(s)) if pkey == "" { return } if !strings.HasPrefix(s, "=") { return } var pvalue string pvalue, s = expectTokenOrQuoted(s[1:]) pkey = strings.ToLower(pkey) params[pkey] = pvalue s = skipSpace(s) if !strings.HasPrefix(s, ",") { return } s = s[1:] } } func skipSpace(s string) (rest string) { i := 0 for ; i < len(s); i++ { if octetTypes[s[i]]&isSpace == 0 { break } } return s[i:] } func expectToken(s string) (token, rest string) { i := 0 for ; i < len(s); i++ { if octetTypes[s[i]]&isToken == 0 { break } } return s[:i], s[i:] } func expectTokenOrQuoted(s string) (value string, rest string) { if !strings.HasPrefix(s, "\"") { return expectToken(s) } s = s[1:] for i := 0; i < len(s); i++ { switch s[i] { case '"': return s[:i], s[i+1:] case '\\': p := make([]byte, len(s)-1) j := copy(p, s[:i]) escape := true for i = i + 1; i < len(s); i++ { b := s[i] switch { case escape: escape = false p[j] = b j++ case b == '\\': escape = true case b == '"': return string(p[:j]), s[i+1:] default: p[j] = b j++ } } return "", "" } } return "", "" } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/auth/parse_test.go000066400000000000000000000051261453374237200257710ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package auth import ( "fmt" "net/http" "reflect" "testing" "github.com/stretchr/testify/assert" ) func TestParseAuthHeaderBearer(t *testing.T) { headerTemplate := `Bearer realm="%s",service="%s",scope="%s"` for _, tc := range []struct { name string realm string service string scope string }{ { name: "SingleScope", realm: "https://auth.docker.io/token", service: "registry.docker.io", scope: "repository:foo/bar:pull,push", }, { name: "MultipleScopes", realm: "https://auth.docker.io/token", service: "registry.docker.io", scope: "repository:foo/bar:pull,push repository:foo/baz:pull repository:foo/foo:push", }, } { t.Run(tc.name, func(t *testing.T) { expected := []Challenge{ { Scheme: BearerAuth, Parameters: map[string]string{ "realm": tc.realm, "service": tc.service, "scope": tc.scope, }, }, } hdr := http.Header{ http.CanonicalHeaderKey("WWW-Authenticate"): []string{fmt.Sprintf( headerTemplate, tc.realm, tc.service, tc.scope, )}, } actual := ParseAuthHeader(hdr) if !reflect.DeepEqual(expected, actual) { t.Fatalf("expected %v, but got %v", expected, actual) } }) } } func TestParseAuthHeader(t *testing.T) { v := `Bearer realm="https://auth.example.io/token",empty="",service="registry.example.io",scope="repository:library/hello-world:pull,push"` h := http.Header{http.CanonicalHeaderKey("WWW-Authenticate"): []string{v}} challenge := ParseAuthHeader(h) actual, ok := challenge[0].Parameters["empty"] assert.True(t, ok) assert.Equal(t, "", actual) actual, ok = challenge[0].Parameters["service"] assert.True(t, ok) assert.Equal(t, "registry.example.io", actual) } func FuzzParseAuthHeader(f *testing.F) { f.Add(`Bearer realm="https://example.com/token",service="example.com",scope="repository:foo/bar:pull,push"`) f.Fuzz(func(t *testing.T, v string) { h := http.Header{http.CanonicalHeaderKey("WWW-Authenticate"): []string{v}} _ = ParseAuthHeader(h) }) } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/authorizer.go000066400000000000000000000226041453374237200250530ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "encoding/base64" "errors" "fmt" "net/http" "strings" "sync" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes/docker/auth" remoteerrors "github.com/containerd/nydus-snapshotter/pkg/remote/remotes/errors" ) type dockerAuthorizer struct { credentials func(string) (string, string, error) client *http.Client header http.Header mu sync.RWMutex // indexed by host name handlers map[string]*authHandler onFetchRefreshToken OnFetchRefreshToken } type authorizerConfig struct { credentials func(string) (string, string, error) client *http.Client header http.Header onFetchRefreshToken OnFetchRefreshToken } // AuthorizerOpt configures an authorizer type AuthorizerOpt func(*authorizerConfig) // WithAuthClient provides the HTTP client for the authorizer func WithAuthClient(client *http.Client) AuthorizerOpt { return func(opt *authorizerConfig) { opt.client = client } } // WithAuthCreds provides a credential function to the authorizer func WithAuthCreds(creds func(string) (string, string, error)) AuthorizerOpt { return func(opt *authorizerConfig) { opt.credentials = creds } } // WithAuthHeader provides HTTP headers for authorization func WithAuthHeader(hdr http.Header) AuthorizerOpt { return func(opt *authorizerConfig) { opt.header = hdr } } // OnFetchRefreshToken is called on fetching request token. type OnFetchRefreshToken func(ctx context.Context, refreshToken string, req *http.Request) // WithFetchRefreshToken enables fetching "refresh token" (aka "identity token", "offline token"). func WithFetchRefreshToken(f OnFetchRefreshToken) AuthorizerOpt { return func(opt *authorizerConfig) { opt.onFetchRefreshToken = f } } // NewDockerAuthorizer creates an authorizer using Docker's registry // authentication spec. // See https://docs.docker.com/registry/spec/auth/ func NewDockerAuthorizer(opts ...AuthorizerOpt) Authorizer { var ao authorizerConfig for _, opt := range opts { opt(&ao) } if ao.client == nil { ao.client = http.DefaultClient } return &dockerAuthorizer{ credentials: ao.credentials, client: ao.client, header: ao.header, handlers: make(map[string]*authHandler), onFetchRefreshToken: ao.onFetchRefreshToken, } } // Authorize handles auth request. func (a *dockerAuthorizer) Authorize(ctx context.Context, req *http.Request) error { // skip if there is no auth handler ah := a.getAuthHandler(req.URL.Host) if ah == nil { return nil } auth, refreshToken, err := ah.authorize(ctx) if err != nil { return err } req.Header.Set("Authorization", auth) if refreshToken != "" { a.mu.RLock() onFetchRefreshToken := a.onFetchRefreshToken a.mu.RUnlock() if onFetchRefreshToken != nil { onFetchRefreshToken(ctx, refreshToken, req) } } return nil } func (a *dockerAuthorizer) getAuthHandler(host string) *authHandler { a.mu.Lock() defer a.mu.Unlock() return a.handlers[host] } func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.Response) error { last := responses[len(responses)-1] host := last.Request.URL.Host a.mu.Lock() defer a.mu.Unlock() for _, c := range auth.ParseAuthHeader(last.Header) { if c.Scheme == auth.BearerAuth { if err := invalidAuthorization(c, responses); err != nil { delete(a.handlers, host) return err } // reuse existing handler // // assume that one registry will return the common // challenge information, including realm and service. // and the resource scope is only different part // which can be provided by each request. if _, ok := a.handlers[host]; ok { return nil } var username, secret string if a.credentials != nil { var err error username, secret, err = a.credentials(host) if err != nil { return err } } common, err := auth.GenerateTokenOptions(ctx, host, username, secret, c) if err != nil { return err } common.FetchRefreshToken = a.onFetchRefreshToken != nil a.handlers[host] = newAuthHandler(a.client, a.header, c.Scheme, common) return nil } else if c.Scheme == auth.BasicAuth && a.credentials != nil { username, secret, err := a.credentials(host) if err != nil { return err } if username != "" && secret != "" { common := auth.TokenOptions{ Username: username, Secret: secret, } a.handlers[host] = newAuthHandler(a.client, a.header, c.Scheme, common) return nil } } } return fmt.Errorf("failed to find supported auth scheme: %w", errdefs.ErrNotImplemented) } // authResult is used to control limit rate. type authResult struct { sync.WaitGroup token string refreshToken string err error } // authHandler is used to handle auth request per registry server. type authHandler struct { sync.Mutex header http.Header client *http.Client // only support basic and bearer schemes scheme auth.AuthenticationScheme // common contains common challenge answer common auth.TokenOptions // scopedTokens caches token indexed by scopes, which used in // bearer auth case scopedTokens map[string]*authResult } func newAuthHandler(client *http.Client, hdr http.Header, scheme auth.AuthenticationScheme, opts auth.TokenOptions) *authHandler { return &authHandler{ header: hdr, client: client, scheme: scheme, common: opts, scopedTokens: map[string]*authResult{}, } } func (ah *authHandler) authorize(ctx context.Context) (string, string, error) { switch ah.scheme { case auth.BasicAuth: return ah.doBasicAuth(ctx) case auth.BearerAuth: return ah.doBearerAuth(ctx) default: return "", "", fmt.Errorf("failed to find supported auth scheme: %s: %w", string(ah.scheme), errdefs.ErrNotImplemented) } } func (ah *authHandler) doBasicAuth(ctx context.Context) (string, string, error) { username, secret := ah.common.Username, ah.common.Secret if username == "" || secret == "" { return "", "", fmt.Errorf("failed to handle basic auth because missing username or secret") } auth := base64.StdEncoding.EncodeToString([]byte(username + ":" + secret)) return fmt.Sprintf("Basic %s", auth), "", nil } func (ah *authHandler) doBearerAuth(ctx context.Context) (token, refreshToken string, err error) { // copy common tokenOptions to := ah.common to.Scopes = GetTokenScopes(ctx, to.Scopes) // Docs: https://docs.docker.com/registry/spec/auth/scope scoped := strings.Join(to.Scopes, " ") ah.Lock() if r, exist := ah.scopedTokens[scoped]; exist { ah.Unlock() r.Wait() return r.token, r.refreshToken, r.err } // only one fetch token job r := new(authResult) r.Add(1) ah.scopedTokens[scoped] = r ah.Unlock() defer func() { token = fmt.Sprintf("Bearer %s", token) r.token, r.refreshToken, r.err = token, refreshToken, err r.Done() }() // fetch token for the resource scope if to.Secret != "" { defer func() { if err != nil { err = fmt.Errorf("failed to fetch oauth token: %w", err) } }() // credential information is provided, use oauth POST endpoint // TODO: Allow setting client_id resp, err := auth.FetchTokenWithOAuth(ctx, ah.client, ah.header, "containerd-client", to) if err != nil { var errStatus remoteerrors.ErrUnexpectedStatus if errors.As(err, &errStatus) { // Registries without support for POST may return 404 for POST /v2/token. // As of September 2017, GCR is known to return 404. // As of February 2018, JFrog Artifactory is known to return 401. // As of January 2022, ACR is known to return 400. if (errStatus.StatusCode == 405 && to.Username != "") || errStatus.StatusCode == 404 || errStatus.StatusCode == 401 || errStatus.StatusCode == 400 { resp, err := auth.FetchToken(ctx, ah.client, ah.header, to) if err != nil { return "", "", err } return resp.Token, resp.RefreshToken, nil } log.G(ctx).WithFields(log.Fields{ "status": errStatus.Status, "body": string(errStatus.Body), }).Debugf("token request failed") } return "", "", err } return resp.AccessToken, resp.RefreshToken, nil } // do request anonymously resp, err := auth.FetchToken(ctx, ah.client, ah.header, to) if err != nil { return "", "", fmt.Errorf("failed to fetch anonymous token: %w", err) } return resp.Token, resp.RefreshToken, nil } func invalidAuthorization(c auth.Challenge, responses []*http.Response) error { errStr := c.Parameters["error"] if errStr == "" { return nil } n := len(responses) if n == 1 || (n > 1 && !sameRequest(responses[n-2].Request, responses[n-1].Request)) { return nil } return fmt.Errorf("server message: %s: %w", errStr, ErrInvalidAuthorization) } func sameRequest(r1, r2 *http.Request) bool { if r1.Method != r2.Method { return false } if *r1.URL != *r2.URL { return false } return true } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/config/000077500000000000000000000000001453374237200235715ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/config/config_unix.go000066400000000000000000000017611453374237200264350ustar00rootroot00000000000000//go:build !windows /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package config import ( "crypto/x509" "path/filepath" ) func hostPaths(root, host string) (hosts []string) { ch := hostDirectory(host) if ch != host { hosts = append(hosts, filepath.Join(root, ch)) } hosts = append(hosts, filepath.Join(root, host), filepath.Join(root, "_default"), ) return } func rootSystemPool() (*x509.CertPool, error) { return x509.SystemCertPool() } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/config/config_windows.go000066400000000000000000000020451453374237200271400ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package config import ( "crypto/x509" "path/filepath" "strings" ) func hostPaths(root, host string) (hosts []string) { ch := hostDirectory(host) if ch != host { hosts = append(hosts, filepath.Join(root, strings.Replace(ch, ":", "", -1))) } hosts = append(hosts, filepath.Join(root, strings.Replace(host, ":", "", -1)), filepath.Join(root, "_default"), ) return } func rootSystemPool() (*x509.CertPool, error) { return x509.NewCertPool(), nil } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/config/docker_fuzzer_internal.go000066400000000000000000000017711453374237200306760ustar00rootroot00000000000000//go:build gofuzz /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package config import ( "os" fuzz "github.com/AdaLogics/go-fuzz-headers" ) func FuzzParseHostsFile(data []byte) int { f := fuzz.NewConsumer(data) dir, err := os.MkdirTemp("", "fuzz-") if err != nil { return 0 } err = f.CreateFiles(dir) if err != nil { return 0 } defer os.RemoveAll(dir) b, err := f.GetBytes() if err != nil { return 0 } _, _ = parseHostsFile(dir, b) return 1 } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/config/hosts.go000066400000000000000000000411501453374237200252610ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // Package config contains utilities for helping configure the Docker resolver package config import ( "context" "crypto/tls" "errors" "fmt" "net" "net/http" "net/url" "os" "path" "path/filepath" "sort" "strings" "time" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes/docker" "github.com/pelletier/go-toml" ) // UpdateClientFunc is a function that lets you to amend http Client behavior used by registry clients. type UpdateClientFunc func(client *http.Client) error type hostConfig struct { scheme string host string path string capabilities docker.HostCapabilities caCerts []string clientPairs [][2]string skipVerify *bool header http.Header // TODO: Add credential configuration (domain alias, username) } // HostOptions is used to configure registry hosts type HostOptions struct { HostDir func(string) (string, error) Credentials func(host string) (string, string, error) DefaultTLS *tls.Config DefaultScheme string // UpdateClient will be called after creating http.Client object, so clients can provide extra configuration UpdateClient UpdateClientFunc AuthorizerOpts []docker.AuthorizerOpt } // ConfigureHosts creates a registry hosts function from the provided // host creation options. The host directory can read hosts.toml or // certificate files laid out in the Docker specific layout. // If a `HostDir` function is not required, defaults are used. func ConfigureHosts(ctx context.Context, options HostOptions) docker.RegistryHosts { return func(host string) ([]docker.RegistryHost, error) { var hosts []hostConfig if options.HostDir != nil { dir, err := options.HostDir(host) if err != nil && !errdefs.IsNotFound(err) { return nil, err } if dir != "" { log.G(ctx).WithField("dir", dir).Debug("loading host directory") hosts, err = loadHostDir(ctx, dir) if err != nil { return nil, err } } } // If hosts was not set, add a default host // NOTE: Check nil here and not empty, the host may be // intentionally configured to not have any endpoints if hosts == nil { hosts = make([]hostConfig, 1) } if len(hosts) > 0 && hosts[len(hosts)-1].host == "" { if host == "docker.io" { hosts[len(hosts)-1].scheme = "https" hosts[len(hosts)-1].host = "registry-1.docker.io" } else if docker.IsLocalhost(host) { hosts[len(hosts)-1].host = host if options.DefaultScheme == "" || options.DefaultScheme == "http" { hosts[len(hosts)-1].scheme = "http" // Skipping TLS verification for localhost var skipVerify = true hosts[len(hosts)-1].skipVerify = &skipVerify } else { hosts[len(hosts)-1].scheme = options.DefaultScheme } } else { hosts[len(hosts)-1].host = host if options.DefaultScheme != "" { hosts[len(hosts)-1].scheme = options.DefaultScheme } else { hosts[len(hosts)-1].scheme = "https" } } hosts[len(hosts)-1].path = "/v2" hosts[len(hosts)-1].capabilities = docker.HostCapabilityPull | docker.HostCapabilityResolve | docker.HostCapabilityPush } var defaultTLSConfig *tls.Config if options.DefaultTLS != nil { defaultTLSConfig = options.DefaultTLS } else { defaultTLSConfig = &tls.Config{} } defaultTransport := &http.Transport{ Proxy: http.ProxyFromEnvironment, DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, FallbackDelay: 300 * time.Millisecond, }).DialContext, MaxIdleConns: 10, IdleConnTimeout: 30 * time.Second, TLSHandshakeTimeout: 10 * time.Second, TLSClientConfig: defaultTLSConfig, ExpectContinueTimeout: 5 * time.Second, } client := &http.Client{ Transport: defaultTransport, } if options.UpdateClient != nil { if err := options.UpdateClient(client); err != nil { return nil, err } } authOpts := []docker.AuthorizerOpt{docker.WithAuthClient(client)} if options.Credentials != nil { authOpts = append(authOpts, docker.WithAuthCreds(options.Credentials)) } authOpts = append(authOpts, options.AuthorizerOpts...) authorizer := docker.NewDockerAuthorizer(authOpts...) rhosts := make([]docker.RegistryHost, len(hosts)) for i, host := range hosts { rhosts[i].Scheme = host.scheme rhosts[i].Host = host.host rhosts[i].Path = host.path rhosts[i].Capabilities = host.capabilities rhosts[i].Header = host.header if host.caCerts != nil || host.clientPairs != nil || host.skipVerify != nil { tr := defaultTransport.Clone() tlsConfig := tr.TLSClientConfig if host.skipVerify != nil { tlsConfig.InsecureSkipVerify = *host.skipVerify } if host.caCerts != nil { if tlsConfig.RootCAs == nil { rootPool, err := rootSystemPool() if err != nil { return nil, fmt.Errorf("unable to initialize cert pool: %w", err) } tlsConfig.RootCAs = rootPool } for _, f := range host.caCerts { data, err := os.ReadFile(f) if err != nil { return nil, fmt.Errorf("unable to read CA cert %q: %w", f, err) } if !tlsConfig.RootCAs.AppendCertsFromPEM(data) { return nil, fmt.Errorf("unable to load CA cert %q", f) } } } if host.clientPairs != nil { for _, pair := range host.clientPairs { certPEMBlock, err := os.ReadFile(pair[0]) if err != nil { return nil, fmt.Errorf("unable to read CERT file %q: %w", pair[0], err) } var keyPEMBlock []byte if pair[1] != "" { keyPEMBlock, err = os.ReadFile(pair[1]) if err != nil { return nil, fmt.Errorf("unable to read CERT file %q: %w", pair[1], err) } } else { // Load key block from same PEM file keyPEMBlock = certPEMBlock } cert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock) if err != nil { return nil, fmt.Errorf("failed to load X509 key pair: %w", err) } tlsConfig.Certificates = append(tlsConfig.Certificates, cert) } } c := *client c.Transport = tr if options.UpdateClient != nil { if err := options.UpdateClient(&c); err != nil { return nil, err } } rhosts[i].Client = &c rhosts[i].Authorizer = docker.NewDockerAuthorizer(append(authOpts, docker.WithAuthClient(&c))...) } else { rhosts[i].Client = client rhosts[i].Authorizer = authorizer } } return rhosts, nil } } // HostDirFromRoot returns a function which finds a host directory // based at the given root. func HostDirFromRoot(root string) func(string) (string, error) { return func(host string) (string, error) { for _, p := range hostPaths(root, host) { if _, err := os.Stat(p); err == nil { return p, nil } else if !os.IsNotExist(err) { return "", err } } return "", errdefs.ErrNotFound } } // hostDirectory converts ":port" to "_port_" in directory names func hostDirectory(host string) string { idx := strings.LastIndex(host, ":") if idx > 0 { return host[:idx] + "_" + host[idx+1:] + "_" } return host } func loadHostDir(ctx context.Context, hostsDir string) ([]hostConfig, error) { b, err := os.ReadFile(filepath.Join(hostsDir, "hosts.toml")) if err != nil && !os.IsNotExist(err) { return nil, err } if len(b) == 0 { // If hosts.toml does not exist, fallback to checking for // certificate files based on Docker's certificate file // pattern (".crt", ".cert", ".key" files) return loadCertFiles(ctx, hostsDir) } hosts, err := parseHostsFile(hostsDir, b) if err != nil { log.G(ctx).WithError(err).Error("failed to decode hosts.toml") // Fallback to checking certificate files return loadCertFiles(ctx, hostsDir) } return hosts, nil } type hostFileConfig struct { // Capabilities determine what operations a host is // capable of performing. Allowed values // - pull // - resolve // - push Capabilities []string `toml:"capabilities"` // CACert are the public key certificates for TLS // Accepted types // - string - Single file with certificate(s) // - []string - Multiple files with certificates CACert interface{} `toml:"ca"` // Client keypair(s) for TLS with client authentication // Accepted types // - string - Single file with public and private keys // - []string - Multiple files with public and private keys // - [][2]string - Multiple keypairs with public and private keys in separate files Client interface{} `toml:"client"` // SkipVerify skips verification of the server's certificate chain // and host name. This should only be used for testing or in // combination with other methods of verifying connections. SkipVerify *bool `toml:"skip_verify"` // Header are additional header files to send to the server Header map[string]interface{} `toml:"header"` // OverridePath indicates the API root endpoint is defined in the URL // path rather than by the API specification. // This may be used with non-compliant OCI registries to override the // API root endpoint. OverridePath bool `toml:"override_path"` // TODO: Credentials: helper? name? username? alternate domain? token? } func parseHostsFile(baseDir string, b []byte) ([]hostConfig, error) { tree, err := toml.LoadBytes(b) if err != nil { return nil, fmt.Errorf("failed to parse TOML: %w", err) } // HACK: we want to keep toml parsing structures private in this package, however go-toml ignores private embedded types. // so we remap it to a public type within the func body, so technically it's public, but not possible to import elsewhere. //nolint:unused type HostFileConfig = hostFileConfig c := struct { HostFileConfig // Server specifies the default server. When `host` is // also specified, those hosts are tried first. Server string `toml:"server"` // HostConfigs store the per-host configuration HostConfigs map[string]hostFileConfig `toml:"host"` }{} orderedHosts, err := getSortedHosts(tree) if err != nil { return nil, err } var ( hosts []hostConfig ) if err := tree.Unmarshal(&c); err != nil { return nil, err } // Parse hosts array for _, host := range orderedHosts { config := c.HostConfigs[host] parsed, err := parseHostConfig(host, baseDir, config) if err != nil { return nil, err } hosts = append(hosts, parsed) } // Parse root host config and append it as the last element parsed, err := parseHostConfig(c.Server, baseDir, c.HostFileConfig) if err != nil { return nil, err } hosts = append(hosts, parsed) return hosts, nil } func parseHostConfig(server string, baseDir string, config hostFileConfig) (hostConfig, error) { var ( result = hostConfig{} err error ) if server != "" { if !strings.HasPrefix(server, "http") { server = "https://" + server } u, err := url.Parse(server) if err != nil { return hostConfig{}, fmt.Errorf("unable to parse server %v: %w", server, err) } result.scheme = u.Scheme result.host = u.Host if len(u.Path) > 0 { u.Path = path.Clean(u.Path) if !strings.HasSuffix(u.Path, "/v2") && !config.OverridePath { u.Path = u.Path + "/v2" } } else if !config.OverridePath { u.Path = "/v2" } result.path = u.Path } result.skipVerify = config.SkipVerify if len(config.Capabilities) > 0 { for _, c := range config.Capabilities { switch strings.ToLower(c) { case "pull": result.capabilities |= docker.HostCapabilityPull case "resolve": result.capabilities |= docker.HostCapabilityResolve case "push": result.capabilities |= docker.HostCapabilityPush default: return hostConfig{}, fmt.Errorf("unknown capability %v", c) } } } else { result.capabilities = docker.HostCapabilityPull | docker.HostCapabilityResolve | docker.HostCapabilityPush } if config.CACert != nil { switch cert := config.CACert.(type) { case string: result.caCerts = []string{makeAbsPath(cert, baseDir)} case []interface{}: result.caCerts, err = makeStringSlice(cert, func(p string) string { return makeAbsPath(p, baseDir) }) if err != nil { return hostConfig{}, err } default: return hostConfig{}, fmt.Errorf("invalid type %v for \"ca\"", cert) } } if config.Client != nil { switch client := config.Client.(type) { case string: result.clientPairs = [][2]string{{makeAbsPath(client, baseDir), ""}} case []interface{}: // []string or [][2]string for _, pairs := range client { switch p := pairs.(type) { case string: result.clientPairs = append(result.clientPairs, [2]string{makeAbsPath(p, baseDir), ""}) case []interface{}: slice, err := makeStringSlice(p, func(s string) string { return makeAbsPath(s, baseDir) }) if err != nil { return hostConfig{}, err } if len(slice) != 2 { return hostConfig{}, fmt.Errorf("invalid pair %v for \"client\"", p) } var pair [2]string copy(pair[:], slice) result.clientPairs = append(result.clientPairs, pair) default: return hostConfig{}, fmt.Errorf("invalid type %T for \"client\"", p) } } default: return hostConfig{}, fmt.Errorf("invalid type %v for \"client\"", client) } } if config.Header != nil { header := http.Header{} for key, ty := range config.Header { switch value := ty.(type) { case string: header[key] = []string{value} case []interface{}: header[key], err = makeStringSlice(value, nil) if err != nil { return hostConfig{}, err } default: return hostConfig{}, fmt.Errorf("invalid type %v for header %q", ty, key) } } result.header = header } return result, nil } // getSortedHosts returns the list of hosts as they defined in the file. func getSortedHosts(root *toml.Tree) ([]string, error) { iter, ok := root.Get("host").(*toml.Tree) if !ok { return nil, errors.New("invalid `host` tree") } list := append([]string{}, iter.Keys()...) // go-toml stores TOML sections in the map object, so no order guaranteed. // We retrieve line number for each key and sort the keys by position. sort.Slice(list, func(i, j int) bool { h1 := iter.GetPath([]string{list[i]}).(*toml.Tree) h2 := iter.GetPath([]string{list[j]}).(*toml.Tree) return h1.Position().Line < h2.Position().Line }) return list, nil } // makeStringSlice is a helper func to convert from []interface{} to []string. // Additionally an optional cb func may be passed to perform string mapping. func makeStringSlice(slice []interface{}, cb func(string) string) ([]string, error) { out := make([]string, len(slice)) for i, value := range slice { str, ok := value.(string) if !ok { return nil, fmt.Errorf("unable to cast %v to string", value) } if cb != nil { out[i] = cb(str) } else { out[i] = str } } return out, nil } func makeAbsPath(p string, base string) string { if filepath.IsAbs(p) { return p } return filepath.Join(base, p) } // loadCertsDir loads certs from certsDir like "/etc/docker/certs.d" . // Compatible with Docker file layout // - files ending with ".crt" are treated as CA certificate files // - files ending with ".cert" are treated as client certificates, and // files with the same name but ending with ".key" are treated as the // corresponding private key. // NOTE: If a ".key" file is missing, this function will just return // the ".cert", which may contain the private key. If the ".cert" file // does not contain the private key, the caller should detect and error. func loadCertFiles(ctx context.Context, certsDir string) ([]hostConfig, error) { fs, err := os.ReadDir(certsDir) if err != nil && !os.IsNotExist(err) { return nil, err } hosts := make([]hostConfig, 1) for _, f := range fs { if f.IsDir() { continue } if strings.HasSuffix(f.Name(), ".crt") { hosts[0].caCerts = append(hosts[0].caCerts, filepath.Join(certsDir, f.Name())) } if strings.HasSuffix(f.Name(), ".cert") { var pair [2]string certFile := f.Name() pair[0] = filepath.Join(certsDir, certFile) // Check if key also exists keyFile := filepath.Join(certsDir, certFile[:len(certFile)-5]+".key") if _, err := os.Stat(keyFile); err == nil { pair[1] = keyFile } else if !os.IsNotExist(err) { return nil, err } hosts[0].clientPairs = append(hosts[0].clientPairs, pair) } } return hosts, nil } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/config/hosts_test.go000066400000000000000000000255101453374237200263220ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package config import ( "bytes" "context" "fmt" "net/http" "os" "path/filepath" "testing" "github.com/containerd/containerd/log/logtest" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes/docker" ) const allCaps = docker.HostCapabilityPull | docker.HostCapabilityResolve | docker.HostCapabilityPush func TestDefaultHosts(t *testing.T) { ctx := logtest.WithT(context.Background(), t) resolve := ConfigureHosts(ctx, HostOptions{}) for _, tc := range []struct { host string expected []docker.RegistryHost }{ { host: "docker.io", expected: []docker.RegistryHost{ { Scheme: "https", Host: "registry-1.docker.io", Path: "/v2", Capabilities: allCaps, }, }, }, } { hosts, err := resolve(tc.host) if err != nil { t.Errorf("[%s] resolve failed: %v", tc.host, err) continue } if len(hosts) != len(tc.expected) { t.Errorf("[%s] unexpected number of hosts %d, expected %d", tc.host, len(hosts), len(tc.expected)) continue } for j := range hosts { if !compareRegistryHost(hosts[j], tc.expected[j]) { t.Errorf("[%s] [%d] unexpected host %v, expected %v", tc.host, j, hosts[j], tc.expected[j]) break } } } } func TestParseHostFile(t *testing.T) { const testtoml = ` server = "https://test-default.registry" ca = "/etc/path/default" [header] x-custom-1 = "custom header" [host."https://mirror.registry"] capabilities = ["pull"] ca = "/etc/certs/mirror.pem" skip_verify = false [host."https://mirror.registry".header] x-custom-2 = ["value1", "value2"] [host."https://mirror-bak.registry/us"] capabilities = ["pull"] skip_verify = true [host."http://mirror.registry"] capabilities = ["pull"] [host."https://test-1.registry"] capabilities = ["pull", "resolve", "push"] ca = ["/etc/certs/test-1-ca.pem", "/etc/certs/special.pem"] client = [["/etc/certs/client.cert", "/etc/certs/client.key"],["/etc/certs/client.pem", ""]] [host."https://test-2.registry"] client = "/etc/certs/client.pem" [host."https://test-3.registry"] client = ["/etc/certs/client-1.pem", "/etc/certs/client-2.pem"] [host."https://noncompliantmirror.registry/v2/namespaceprefix"] capabilities = ["pull"] override_path = true [host."https://noprefixnoncompliant.registry"] override_path = true ` var tb, fb = true, false expected := []hostConfig{ { scheme: "https", host: "mirror.registry", path: "/v2", capabilities: docker.HostCapabilityPull, caCerts: []string{filepath.FromSlash("/etc/certs/mirror.pem")}, skipVerify: &fb, header: http.Header{"x-custom-2": {"value1", "value2"}}, }, { scheme: "https", host: "mirror-bak.registry", path: "/us/v2", capabilities: docker.HostCapabilityPull, skipVerify: &tb, }, { scheme: "http", host: "mirror.registry", path: "/v2", capabilities: docker.HostCapabilityPull, }, { scheme: "https", host: "test-1.registry", path: "/v2", capabilities: allCaps, caCerts: []string{filepath.FromSlash("/etc/certs/test-1-ca.pem"), filepath.FromSlash("/etc/certs/special.pem")}, clientPairs: [][2]string{ {filepath.FromSlash("/etc/certs/client.cert"), filepath.FromSlash("/etc/certs/client.key")}, {filepath.FromSlash("/etc/certs/client.pem"), ""}, }, }, { scheme: "https", host: "test-2.registry", path: "/v2", capabilities: allCaps, clientPairs: [][2]string{ {filepath.FromSlash("/etc/certs/client.pem")}, }, }, { scheme: "https", host: "test-3.registry", path: "/v2", capabilities: allCaps, clientPairs: [][2]string{ {filepath.FromSlash("/etc/certs/client-1.pem")}, {filepath.FromSlash("/etc/certs/client-2.pem")}, }, }, { scheme: "https", host: "noncompliantmirror.registry", path: "/v2/namespaceprefix", capabilities: docker.HostCapabilityPull, }, { scheme: "https", host: "noprefixnoncompliant.registry", capabilities: allCaps, }, { scheme: "https", host: "test-default.registry", path: "/v2", capabilities: allCaps, caCerts: []string{filepath.FromSlash("/etc/path/default")}, header: http.Header{"x-custom-1": {"custom header"}}, }, } hosts, err := parseHostsFile("", []byte(testtoml)) if err != nil { t.Fatal(err) } defer func() { if t.Failed() { t.Log("HostConfigs...\nActual:\n" + printHostConfig(hosts) + "Expected:\n" + printHostConfig(expected)) } }() if len(hosts) != len(expected) { t.Fatalf("Unexpected number of hosts %d, expected %d", len(hosts), len(expected)) } for i := range hosts { if !compareHostConfig(hosts[i], expected[i]) { t.Fatalf("Mismatch at host %d", i) } } } func TestLoadCertFiles(t *testing.T) { dir := t.TempDir() type testCase struct { input hostConfig } cases := map[string]testCase{ "crt only": { input: hostConfig{host: "testing.io", caCerts: []string{filepath.Join(dir, "testing.io", "ca.crt")}}, }, "crt and cert pair": { input: hostConfig{ host: "testing.io", caCerts: []string{filepath.Join(dir, "testing.io", "ca.crt")}, clientPairs: [][2]string{ { filepath.Join(dir, "testing.io", "client.cert"), filepath.Join(dir, "testing.io", "client.key"), }, }, }, }, "cert pair only": { input: hostConfig{ host: "testing.io", clientPairs: [][2]string{ { filepath.Join(dir, "testing.io", "client.cert"), filepath.Join(dir, "testing.io", "client.key"), }, }, }, }, } for name, tc := range cases { t.Run(name, func(t *testing.T) { hostDir := filepath.Join(dir, tc.input.host) if err := os.MkdirAll(hostDir, 0700); err != nil { t.Fatal(err) } defer os.RemoveAll(hostDir) for _, f := range tc.input.caCerts { if err := os.WriteFile(f, testKey, 0600); err != nil { t.Fatal(err) } } for _, pair := range tc.input.clientPairs { if err := os.WriteFile(pair[0], testKey, 0600); err != nil { t.Fatal(err) } if err := os.WriteFile(pair[1], testKey, 0600); err != nil { t.Fatal(err) } } configs, err := loadHostDir(context.Background(), hostDir) if err != nil { t.Fatal(err) } if len(configs) != 1 { t.Fatalf("\nexpected:\n%+v\ngot:\n%+v", tc.input, configs) } cfg := configs[0] cfg.host = tc.input.host if !compareHostConfig(cfg, tc.input) { t.Errorf("\nexpected:\n%+v:\n\ngot:\n%+v", tc.input, cfg) } }) } } func compareRegistryHost(j, k docker.RegistryHost) bool { if j.Scheme != k.Scheme { return false } if j.Host != k.Host { return false } if j.Path != k.Path { return false } if j.Capabilities != k.Capabilities { return false } // Not comparing TLS configs or authorizations return true } func compareHostConfig(j, k hostConfig) bool { if j.scheme != k.scheme { return false } if j.host != k.host { return false } if j.path != k.path { return false } if j.capabilities != k.capabilities { return false } if len(j.caCerts) != len(k.caCerts) { return false } for i := range j.caCerts { if j.caCerts[i] != k.caCerts[i] { return false } } if len(j.clientPairs) != len(k.clientPairs) { return false } for i := range j.clientPairs { if j.clientPairs[i][0] != k.clientPairs[i][0] { return false } if j.clientPairs[i][1] != k.clientPairs[i][1] { return false } } if j.skipVerify != nil && k.skipVerify != nil { if *j.skipVerify != *k.skipVerify { return false } } else if j.skipVerify != nil || k.skipVerify != nil { return false } if len(j.header) != len(k.header) { return false } for key := range j.header { if len(j.header[key]) != len(k.header[key]) { return false } for i := range j.header[key] { if j.header[key][i] != k.header[key][i] { return false } } } return true } func printHostConfig(hc []hostConfig) string { b := bytes.NewBuffer(nil) for i := range hc { fmt.Fprintf(b, "\t[%d]\tscheme: %q\n", i, hc[i].scheme) fmt.Fprintf(b, "\t\thost: %q\n", hc[i].host) fmt.Fprintf(b, "\t\tpath: %q\n", hc[i].path) fmt.Fprintf(b, "\t\tcaps: %03b\n", hc[i].capabilities) fmt.Fprintf(b, "\t\tca: %#v\n", hc[i].caCerts) fmt.Fprintf(b, "\t\tclients: %#v\n", hc[i].clientPairs) if hc[i].skipVerify == nil { fmt.Fprintf(b, "\t\tskip-verify: %v\n", hc[i].skipVerify) } else { fmt.Fprintf(b, "\t\tskip-verify: %t\n", *hc[i].skipVerify) } fmt.Fprintf(b, "\t\theader: %#v\n", hc[i].header) } return b.String() } var ( testKey = []byte(`-----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDa+zvPgFXwra4S 0DzEWRgZHxVTDG1sJsnN/jOaHCNpRyABGVW5kdei9WFWv3dpiELI+guQMjdUL++w M68bs6cXKW+1nW6u5uWuGwklOwkoKoeHkkn/vHef7ybk+5qdk6AYY0DKQsrBBOvj f0WAnG+1xi8VIOEBmce0/47MexOiuILVkjokgdmDCOc8ShkT6/EJTCsI1wDew/4G 9IiRzw2xSM0ZATAtEC3HEBRLJGWZQtuKlLCuzJ+erOWUcg2cjnSgR3PmaAXE//5g SoeqEbtTo1satf9AR4VvreIAI8m0eyo8ABMLTkZovEFcUUHetL63hdqItjCeRfrQ zK4LMRFbAgMBAAECggEBAJtP6UHo0gtcA8SQMSlJz4+xvhwjClDUyfjyPIMnRe5b ZdWhtG1jhT+tLhaqwfT1kfidcCobk6aAQU4FukK5jt8cooB7Yo9mcKylvDzNvFbi ozGCjj113JpwsnNiCG2O0NO7Qa6y5L810GCQWik3yvtvzuD7atsJyN0VDKD3Ahw7 1X8z76grZFlhVMCTAA3vAJ2y2p3sd+TGC/PIhnsvChwxEorGCnMj93mBaUI7zZRY EZhlk4ZvC9sUvlVUuYC+wAHjasgN9s3AzsOBSx+Xt3NaXQHzhL0mVo/vu/pjjFBs WBLR1PBoIfveTJPOp+Hrr4cuCK0NuX9sWlWPYLl5A2ECgYEA5fq3n4PhbJ2BuTS5 AVgOmjRpk1eogb6aSY+cx7Mr++ADF9EYXc5tgKoUsDeeiiyK2lv6IKavoTWT1kdd shiclyEzp2CxG5GtbC/g2XHiBLepgo1fjfev3btCmIeGVBjglOx4F3gEsRygrAID zcz94m2I+uqLT8hvWnccIqScglkCgYEA88H2ji4Nvx6TmqCLcER0vNDVoxxDfgGb iohvenD2jmmdTnezTddsgECAI8L0BPNS/0vBCduTjs5BqhKbIfQvuK5CANMUcxuQ twWH8kPvTYJVgsmWP6sSXSz3PohWC5EA9xACExGtyN6d7sLUCV0SBhjlcgMvGuDM lP6NjyyWctMCgYBKdfGr+QQsqZaNw48+6ybXMK8aIKCTWYYU2SW21sEf7PizZmTQ Qnzb0rWeFHQFYsSWTH9gwPdOZ8107GheuG9C02IpCDpvpawTwjC31pKKWnjMpz9P 9OkBDpdSUVbhtahJL4L2fkpumck/x+s5X+y3uiVGsFfovgmnrbbzVH7ECQKBgQCC MYs7DaYR+obkA/P2FtozL2esIyB5YOpu58iDIWrPTeHTU2PVo8Y0Cj9m2m3zZvNh oFiOp1T85XV1HVL2o7IJdimSvyshAAwfdTjTUS2zvHVn0bwKbZj1Y1r7b15l9yEI 1OgGv16O9zhrmmweRDOoRgvnBYRXWtJqkjuRyULiOQKBgQC/lSYigV32Eb8Eg1pv 7OcPWv4qV4880lRE0MXuQ4VFa4+pqvdziYFYQD4jDYJ4IX9l//bsobL0j7z0P0Gk wDFti9bRwRoO1ntqoA8n2pDLlLRGl0dyjB6fHzp27oqtyf1HRlHiow7Gqx5b5JOk tycYKwA3DuaSyqPe6MthLneq8w== -----END PRIVATE KEY----- `) ) nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/converter.go000066400000000000000000000055331453374237200246700ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "bytes" "context" "encoding/json" "fmt" "github.com/containerd/containerd/content" "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // LegacyConfigMediaType should be replaced by OCI image spec. // // More detail: docker/distribution#1622 const LegacyConfigMediaType = "application/octet-stream" // ConvertManifest changes application/octet-stream to schema2 config media type if need. // // NOTE: // 1. original manifest will be deleted by next gc round. // 2. don't cover manifest list. func ConvertManifest(ctx context.Context, store content.Store, desc ocispec.Descriptor) (ocispec.Descriptor, error) { if !(desc.MediaType == images.MediaTypeDockerSchema2Manifest || desc.MediaType == ocispec.MediaTypeImageManifest) { log.G(ctx).Warnf("do nothing for media type: %s", desc.MediaType) return desc, nil } // read manifest data mb, err := content.ReadBlob(ctx, store, desc) if err != nil { return ocispec.Descriptor{}, fmt.Errorf("failed to read index data: %w", err) } var manifest ocispec.Manifest if err := json.Unmarshal(mb, &manifest); err != nil { return ocispec.Descriptor{}, fmt.Errorf("failed to unmarshal data into manifest: %w", err) } // check config media type if manifest.Config.MediaType != LegacyConfigMediaType { return desc, nil } manifest.Config.MediaType = images.MediaTypeDockerSchema2Config data, err := json.MarshalIndent(manifest, "", " ") if err != nil { return ocispec.Descriptor{}, fmt.Errorf("failed to marshal manifest: %w", err) } // update manifest with gc labels desc.Digest = digest.Canonical.FromBytes(data) desc.Size = int64(len(data)) labels := map[string]string{} for i, c := range append([]ocispec.Descriptor{manifest.Config}, manifest.Layers...) { labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = c.Digest.String() } ref := remotes.MakeRefKey(ctx, desc) if err := content.WriteBlob(ctx, store, ref, bytes.NewReader(data), desc, content.WithLabels(labels)); err != nil { return ocispec.Descriptor{}, fmt.Errorf("failed to update content: %w", err) } return desc, nil } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/converter_fuzz.go000066400000000000000000000026031453374237200257410ustar00rootroot00000000000000//go:build gofuzz /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "os" fuzz "github.com/AdaLogics/go-fuzz-headers" "github.com/containerd/containerd/content/local" "github.com/containerd/containerd/log" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sirupsen/logrus" ) func FuzzConvertManifest(data []byte) int { ctx := context.Background() // Do not log the message below // level=warning msg="do nothing for media type: ..." log.G(ctx).Logger.SetLevel(logrus.PanicLevel) f := fuzz.NewConsumer(data) desc := ocispec.Descriptor{} err := f.GenerateStruct(&desc) if err != nil { return 0 } tmpdir, err := os.MkdirTemp("", "fuzzing-") if err != nil { return 0 } cs, err := local.NewStore(tmpdir) if err != nil { return 0 } _, _ = ConvertManifest(ctx, cs, desc) return 1 } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/errcode.go000066400000000000000000000161521453374237200243030ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "encoding/json" "fmt" "strings" ) // ErrorCoder is the base interface for ErrorCode and Error allowing // users of each to just call ErrorCode to get the real ID of each type ErrorCoder interface { ErrorCode() ErrorCode } // ErrorCode represents the error type. The errors are serialized via strings // and the integer format may change and should *never* be exported. type ErrorCode int var _ error = ErrorCode(0) // ErrorCode just returns itself func (ec ErrorCode) ErrorCode() ErrorCode { return ec } // Error returns the ID/Value func (ec ErrorCode) Error() string { // NOTE(stevvooe): Cannot use message here since it may have unpopulated args. return strings.ToLower(strings.Replace(ec.String(), "_", " ", -1)) } // Descriptor returns the descriptor for the error code. func (ec ErrorCode) Descriptor() ErrorDescriptor { d, ok := errorCodeToDescriptors[ec] if !ok { return ErrorCodeUnknown.Descriptor() } return d } // String returns the canonical identifier for this error code. func (ec ErrorCode) String() string { return ec.Descriptor().Value } // Message returned the human-readable error message for this error code. func (ec ErrorCode) Message() string { return ec.Descriptor().Message } // MarshalText encodes the receiver into UTF-8-encoded text and returns the // result. func (ec ErrorCode) MarshalText() (text []byte, err error) { return []byte(ec.String()), nil } // UnmarshalText decodes the form generated by MarshalText. func (ec *ErrorCode) UnmarshalText(text []byte) error { desc, ok := idToDescriptors[string(text)] if !ok { desc = ErrorCodeUnknown.Descriptor() } *ec = desc.Code return nil } // WithMessage creates a new Error struct based on the passed-in info and // overrides the Message property. func (ec ErrorCode) WithMessage(message string) Error { return Error{ Code: ec, Message: message, } } // WithDetail creates a new Error struct based on the passed-in info and // set the Detail property appropriately func (ec ErrorCode) WithDetail(detail interface{}) Error { return Error{ Code: ec, Message: ec.Message(), }.WithDetail(detail) } // WithArgs creates a new Error struct and sets the Args slice func (ec ErrorCode) WithArgs(args ...interface{}) Error { return Error{ Code: ec, Message: ec.Message(), }.WithArgs(args...) } // Error provides a wrapper around ErrorCode with extra Details provided. type Error struct { Code ErrorCode `json:"code"` Message string `json:"message"` Detail interface{} `json:"detail,omitempty"` // TODO(duglin): See if we need an "args" property so we can do the // variable substitution right before showing the message to the user } var _ error = Error{} // ErrorCode returns the ID/Value of this Error func (e Error) ErrorCode() ErrorCode { return e.Code } // Error returns a human readable representation of the error. func (e Error) Error() string { return fmt.Sprintf("%s: %s", e.Code.Error(), e.Message) } // WithDetail will return a new Error, based on the current one, but with // some Detail info added func (e Error) WithDetail(detail interface{}) Error { return Error{ Code: e.Code, Message: e.Message, Detail: detail, } } // WithArgs uses the passed-in list of interface{} as the substitution // variables in the Error's Message string, but returns a new Error func (e Error) WithArgs(args ...interface{}) Error { return Error{ Code: e.Code, Message: fmt.Sprintf(e.Code.Message(), args...), Detail: e.Detail, } } // ErrorDescriptor provides relevant information about a given error code. type ErrorDescriptor struct { // Code is the error code that this descriptor describes. Code ErrorCode // Value provides a unique, string key, often captilized with // underscores, to identify the error code. This value is used as the // keyed value when serializing api errors. Value string // Message is a short, human readable description of the error condition // included in API responses. Message string // Description provides a complete account of the errors purpose, suitable // for use in documentation. Description string // HTTPStatusCode provides the http status code that is associated with // this error condition. HTTPStatusCode int } // ParseErrorCode returns the value by the string error code. // `ErrorCodeUnknown` will be returned if the error is not known. func ParseErrorCode(value string) ErrorCode { ed, ok := idToDescriptors[value] if ok { return ed.Code } return ErrorCodeUnknown } // Errors provides the envelope for multiple errors and a few sugar methods // for use within the application. type Errors []error var _ error = Errors{} func (errs Errors) Error() string { switch len(errs) { case 0: return "" case 1: return errs[0].Error() default: msg := "errors:\n" for _, err := range errs { msg += err.Error() + "\n" } return msg } } // Len returns the current number of errors. func (errs Errors) Len() int { return len(errs) } // MarshalJSON converts slice of error, ErrorCode or Error into a // slice of Error - then serializes func (errs Errors) MarshalJSON() ([]byte, error) { var tmpErrs struct { Errors []Error `json:"errors,omitempty"` } for _, daErr := range errs { var err Error switch daErr := daErr.(type) { case ErrorCode: err = daErr.WithDetail(nil) case Error: err = daErr default: err = ErrorCodeUnknown.WithDetail(daErr) } // If the Error struct was setup and they forgot to set the // Message field (meaning its "") then grab it from the ErrCode msg := err.Message if msg == "" { msg = err.Code.Message() } tmpErrs.Errors = append(tmpErrs.Errors, Error{ Code: err.Code, Message: msg, Detail: err.Detail, }) } return json.Marshal(tmpErrs) } // UnmarshalJSON deserializes []Error and then converts it into slice of // Error or ErrorCode func (errs *Errors) UnmarshalJSON(data []byte) error { var tmpErrs struct { Errors []Error } if err := json.Unmarshal(data, &tmpErrs); err != nil { return err } var newErrs Errors for _, daErr := range tmpErrs.Errors { // If Message is empty or exactly matches the Code's message string // then just use the Code, no need for a full Error struct if daErr.Detail == nil && (daErr.Message == "" || daErr.Message == daErr.Code.Message()) { // Error's w/o details get converted to ErrorCode newErrs = append(newErrs, daErr.Code) } else { // Error's w/ details are untouched newErrs = append(newErrs, Error{ Code: daErr.Code, Message: daErr.Message, Detail: daErr.Detail, }) } } *errs = newErrs return nil } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/errdesc.go000066400000000000000000000116251453374237200243070ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "fmt" "net/http" "sort" "sync" ) var ( errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{} idToDescriptors = map[string]ErrorDescriptor{} groupToDescriptors = map[string][]ErrorDescriptor{} ) var ( // ErrorCodeUnknown is a generic error that can be used as a last // resort if there is no situation-specific error message that can be used ErrorCodeUnknown = Register("errcode", ErrorDescriptor{ Value: "UNKNOWN", Message: "unknown error", Description: `Generic error returned when the error does not have an API classification.`, HTTPStatusCode: http.StatusInternalServerError, }) // ErrorCodeUnsupported is returned when an operation is not supported. ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{ Value: "UNSUPPORTED", Message: "The operation is unsupported.", Description: `The operation was unsupported due to a missing implementation or invalid set of parameters.`, HTTPStatusCode: http.StatusMethodNotAllowed, }) // ErrorCodeUnauthorized is returned if a request requires // authentication. ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{ Value: "UNAUTHORIZED", Message: "authentication required", Description: `The access controller was unable to authenticate the client. Often this will be accompanied by a Www-Authenticate HTTP response header indicating how to authenticate.`, HTTPStatusCode: http.StatusUnauthorized, }) // ErrorCodeDenied is returned if a client does not have sufficient // permission to perform an action. ErrorCodeDenied = Register("errcode", ErrorDescriptor{ Value: "DENIED", Message: "requested access to the resource is denied", Description: `The access controller denied access for the operation on a resource.`, HTTPStatusCode: http.StatusForbidden, }) // ErrorCodeUnavailable provides a common error to report unavailability // of a service or endpoint. ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{ Value: "UNAVAILABLE", Message: "service unavailable", Description: "Returned when a service is not available", HTTPStatusCode: http.StatusServiceUnavailable, }) // ErrorCodeTooManyRequests is returned if a client attempts too many // times to contact a service endpoint. ErrorCodeTooManyRequests = Register("errcode", ErrorDescriptor{ Value: "TOOMANYREQUESTS", Message: "too many requests", Description: `Returned when a client attempts to contact a service too many times`, HTTPStatusCode: http.StatusTooManyRequests, }) ) var nextCode = 1000 var registerLock sync.Mutex // Register will make the passed-in error known to the environment and // return a new ErrorCode func Register(group string, descriptor ErrorDescriptor) ErrorCode { registerLock.Lock() defer registerLock.Unlock() descriptor.Code = ErrorCode(nextCode) if _, ok := idToDescriptors[descriptor.Value]; ok { panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value)) } if _, ok := errorCodeToDescriptors[descriptor.Code]; ok { panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code)) } groupToDescriptors[group] = append(groupToDescriptors[group], descriptor) errorCodeToDescriptors[descriptor.Code] = descriptor idToDescriptors[descriptor.Value] = descriptor nextCode++ return descriptor.Code } type byValue []ErrorDescriptor func (a byValue) Len() int { return len(a) } func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value } // GetGroupNames returns the list of Error group names that are registered func GetGroupNames() []string { keys := []string{} for k := range groupToDescriptors { keys = append(keys, k) } sort.Strings(keys) return keys } // GetErrorCodeGroup returns the named group of error descriptors func GetErrorCodeGroup(name string) []ErrorDescriptor { desc := groupToDescriptors[name] sort.Sort(byValue(desc)) return desc } // GetErrorAllDescriptors returns a slice of all ErrorDescriptors that are // registered, irrespective of what group they're in func GetErrorAllDescriptors() []ErrorDescriptor { result := []ErrorDescriptor{} for _, group := range GetGroupNames() { result = append(result, GetErrorCodeGroup(group)...) } sort.Sort(byValue(result)) return result } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/fetcher.go000066400000000000000000000220131453374237200242710ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "encoding/json" "errors" "fmt" "io" "net/http" "net/url" "strings" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) type dockerFetcher struct { *dockerBase } func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) { ctx = log.WithLogger(ctx, log.G(ctx).WithField("digest", desc.Digest)) hosts := r.filterHosts(HostCapabilityPull) if len(hosts) == 0 { return nil, fmt.Errorf("no pull hosts: %w", errdefs.ErrNotFound) } ctx, err := ContextWithRepositoryScope(ctx, r.refspec, false) if err != nil { return nil, err } return newHTTPReadSeeker(desc.Size, func(offset int64) (io.ReadCloser, error) { // firstly try fetch via external urls for _, us := range desc.URLs { u, err := url.Parse(us) if err != nil { log.G(ctx).WithError(err).Debugf("failed to parse %q", us) continue } if u.Scheme != "http" && u.Scheme != "https" { log.G(ctx).Debug("non-http(s) alternative url is unsupported") continue } ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", u)) log.G(ctx).Info("request") // Try this first, parse it host := RegistryHost{ Client: http.DefaultClient, Host: u.Host, Scheme: u.Scheme, Path: u.Path, Capabilities: HostCapabilityPull, } req := r.request(host, http.MethodGet) // Strip namespace from base req.path = u.Path if u.RawQuery != "" { req.path = req.path + "?" + u.RawQuery } rc, _, err := r.open(ctx, req, desc.MediaType, offset) if err != nil { if errdefs.IsNotFound(err) { continue // try one of the other urls. } return nil, err } return rc, nil } // Try manifests endpoints for manifests types switch desc.MediaType { case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList, images.MediaTypeDockerSchema1Manifest, ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex: var firstErr error for _, host := range r.hosts { req := r.request(host, http.MethodGet, "manifests", desc.Digest.String()) if err := req.addNamespace(r.refspec.Hostname()); err != nil { return nil, err } rc, _, err := r.open(ctx, req, desc.MediaType, offset) if err != nil { // Store the error for referencing later if firstErr == nil { firstErr = err } continue // try another host } return rc, nil } return nil, firstErr } // Finally use blobs endpoints var firstErr error for _, host := range r.hosts { req := r.request(host, http.MethodGet, "blobs", desc.Digest.String()) if err := req.addNamespace(r.refspec.Hostname()); err != nil { return nil, err } rc, _, err := r.open(ctx, req, desc.MediaType, offset) if err != nil { // Store the error for referencing later if firstErr == nil { firstErr = err } continue // try another host } return rc, nil } if errdefs.IsNotFound(firstErr) { firstErr = fmt.Errorf("could not fetch content descriptor %v (%v) from remote: %w", desc.Digest, desc.MediaType, errdefs.ErrNotFound, ) } return nil, firstErr }) } func (r dockerFetcher) createGetReq(ctx context.Context, host RegistryHost, mediatype string, ps ...string) (*request, int64, error) { headReq := r.request(host, http.MethodHead, ps...) if err := headReq.addNamespace(r.refspec.Hostname()); err != nil { return nil, 0, err } if mediatype == "" { headReq.header.Set("Accept", "*/*") } else { headReq.header.Set("Accept", strings.Join([]string{mediatype, `*/*`}, ", ")) } headResp, err := headReq.doWithRetries(ctx, nil) if err != nil { return nil, 0, err } if headResp.Body != nil { headResp.Body.Close() } if headResp.StatusCode > 299 { return nil, 0, fmt.Errorf("unexpected HEAD status code %v: %s", headReq.String(), headResp.Status) } getReq := r.request(host, http.MethodGet, ps...) if err := getReq.addNamespace(r.refspec.Hostname()); err != nil { return nil, 0, err } return getReq, headResp.ContentLength, nil } func (r dockerFetcher) FetchByDigest(ctx context.Context, dgst digest.Digest) (io.ReadCloser, ocispec.Descriptor, error) { var desc ocispec.Descriptor ctx = log.WithLogger(ctx, log.G(ctx).WithField("digest", dgst)) hosts := r.filterHosts(HostCapabilityPull) if len(hosts) == 0 { return nil, desc, fmt.Errorf("no pull hosts: %w", errdefs.ErrNotFound) } ctx, err := ContextWithRepositoryScope(ctx, r.refspec, false) if err != nil { return nil, desc, err } var ( getReq *request sz int64 firstErr error mediaType string ) for _, host := range r.hosts { getReq, sz, err = r.createGetReq(ctx, host, mediaType, "blobs", dgst.String()) if err == nil { break } // Store the error for referencing later if firstErr == nil { firstErr = err } } if getReq == nil { // Fall back to the "manifests" endpoint // TODO: this change should be upstreamed to containerd. mediaType = strings.Join([]string{ images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex, }, ", ") for _, host := range r.hosts { getReq, sz, err = r.createGetReq(ctx, host, mediaType, "manifests", dgst.String()) if err == nil { break } // Store the error for referencing later if firstErr == nil { firstErr = err } } } if getReq == nil { if errdefs.IsNotFound(firstErr) { firstErr = fmt.Errorf("could not fetch content %v from remote: %w", dgst, errdefs.ErrNotFound) } if firstErr == nil { firstErr = fmt.Errorf("could not fetch content %v from remote: (unknown)", dgst) } return nil, desc, firstErr } seeker, err := newHTTPReadSeeker(sz, func(offset int64) (rc io.ReadCloser, err error) { rc, _, err = r.open(ctx, getReq, mediaType, offset) return }) if err != nil { return nil, desc, err } desc = ocispec.Descriptor{ MediaType: "application/octet-stream", Digest: dgst, Size: sz, } return seeker, desc, nil } func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64) (_ io.ReadCloser, _ int64, retErr error) { if mediatype == "" { req.header.Set("Accept", "*/*") } else { req.header.Set("Accept", strings.Join([]string{mediatype, `*/*`}, ", ")) } if offset > 0 { // Note: "Accept-Ranges: bytes" cannot be trusted as some endpoints // will return the header without supporting the range. The content // range must always be checked. req.header.Set("Range", fmt.Sprintf("bytes=%d-", offset)) } resp, err := req.doWithRetries(ctx, nil) if err != nil { return nil, 0, err } defer func() { if retErr != nil { resp.Body.Close() } }() if resp.StatusCode > 299 { // TODO(stevvooe): When doing a offset specific request, we should // really distinguish between a 206 and a 200. In the case of 200, we // can discard the bytes, hiding the seek behavior from the // implementation. if resp.StatusCode == http.StatusNotFound { return nil, 0, fmt.Errorf("content at %v not found: %w", req.String(), errdefs.ErrNotFound) } var registryErr Errors if err := json.NewDecoder(resp.Body).Decode(®istryErr); err != nil || registryErr.Len() < 1 { return nil, 0, fmt.Errorf("unexpected status code %v: %v", req.String(), resp.Status) } return nil, 0, fmt.Errorf("unexpected status code %v: %s - Server message: %s", req.String(), resp.Status, registryErr.Error()) } cl := resp.ContentLength if offset > 0 { cr := resp.Header.Get("content-range") if cr != "" { if !strings.HasPrefix(cr, fmt.Sprintf("bytes %d-", offset)) { return nil, 0, fmt.Errorf("unhandled content range in response: %v", cr) } } else { // TODO: Should any cases where use of content range // without the proper header be considered? // 206 responses? // Discard up to offset // Could use buffer pool here but this case should be rare n, err := io.Copy(io.Discard, io.LimitReader(resp.Body, offset)) if err != nil { return nil, 0, fmt.Errorf("failed to discard to offset: %w", err) } if n != offset { return nil, 0, errors.New("unable to discard to offset") } // Subtract discarded bytes from returned content length to return body // size consistent with content-range cl = cl - offset } } return resp.Body, cl, nil } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/fetcher_fuzz.go000066400000000000000000000034261453374237200253560ustar00rootroot00000000000000//go:build gofuzz /* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "fmt" "io" "net/http" "net/http/httptest" "net/url" refDocker "github.com/containerd/containerd/reference/docker" ) func FuzzFetcher(data []byte) int { dataLen := len(data) if dataLen == 0 { return -1 } s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { rw.Header().Set("content-range", fmt.Sprintf("bytes %d-%d/%d", 0, dataLen-1, dataLen)) rw.Header().Set("content-length", fmt.Sprintf("%d", dataLen)) rw.Write(data) })) defer s.Close() u, err := url.Parse(s.URL) if err != nil { return 0 } f := dockerFetcher{&dockerBase{ repository: "nonempty", }} host := RegistryHost{ Client: s.Client(), Host: u.Host, Scheme: u.Scheme, Path: u.Path, } ctx := context.Background() req := f.request(host, http.MethodGet) rc, _, err := f.open(ctx, req, "", 0) if err != nil { return 0 } b, err := io.ReadAll(rc) if err != nil { return 0 } expected := data if len(b) != len(expected) { panic("len of request is not equal to len of expected but should be") } return 1 } func FuzzParseDockerRef(data []byte) int { _, _ = refDocker.ParseDockerRef(string(data)) return 1 } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/fetcher_test.go000066400000000000000000000126131453374237200253350ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "encoding/json" "fmt" "io" "math/rand" "net/http" "net/http/httptest" "net/url" "testing" "github.com/stretchr/testify/assert" ) func TestFetcherOpen(t *testing.T) { content := make([]byte, 128) rand.New(rand.NewSource(1)).Read(content) start := 0 s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { if start > 0 { rw.Header().Set("content-range", fmt.Sprintf("bytes %d-127/128", start)) } rw.Header().Set("content-length", fmt.Sprintf("%d", len(content[start:]))) rw.Write(content[start:]) })) defer s.Close() u, err := url.Parse(s.URL) if err != nil { t.Fatal(err) } f := dockerFetcher{&dockerBase{ repository: "nonempty", }} host := RegistryHost{ Client: s.Client(), Host: u.Host, Scheme: u.Scheme, Path: u.Path, } ctx := context.Background() req := f.request(host, http.MethodGet) checkReader := func(o int64) { t.Helper() rc, cl, err := f.open(ctx, req, "", o) if err != nil { t.Fatalf("failed to open: %+v", err) } b, err := io.ReadAll(rc) if err != nil { t.Fatal(err) } expected := content[o:] if len(b) != len(expected) { t.Errorf("unexpected length %d, expected %d", len(b), len(expected)) return } if cl != int64(len(expected)) { t.Errorf("unexpected content length %d, expected %d", cl, len(expected)) return } for i, c := range expected { if b[i] != c { t.Errorf("unexpected byte %x at %d, expected %x", b[i], i, c) return } } } checkReader(0) // Test server ignores content range checkReader(25) // Use content range on server start = 20 checkReader(20) // Check returning just last byte and no bytes start = 127 checkReader(127) start = 128 checkReader(128) // Check that server returning a different content range // then requested errors start = 30 _, _, err = f.open(ctx, req, "", 20) if err == nil { t.Fatal("expected error opening with invalid server response") } } // New set of tests to test new error cases func TestDockerFetcherOpen(t *testing.T) { tests := []struct { name string mockedStatus int mockedErr error want io.ReadCloser wantLen int64 wantErr bool wantServerMessageError bool wantPlainError bool retries int }{ { name: "should return status and error.message if it exists if the registry request fails", mockedStatus: 500, mockedErr: Errors{Error{ Code: ErrorCodeUnknown, Message: "Test Error", }}, want: nil, wantErr: true, wantServerMessageError: true, }, { name: "should return just status if the registry request fails and does not return a docker error", mockedStatus: 500, mockedErr: fmt.Errorf("Non-docker error"), want: nil, wantErr: true, wantPlainError: true, }, { name: "should return StatusRequestTimeout after 5 retries", mockedStatus: http.StatusRequestTimeout, mockedErr: fmt.Errorf(http.StatusText(http.StatusRequestTimeout)), want: nil, wantErr: true, wantPlainError: true, retries: 5, }, { name: "should return StatusTooManyRequests after 5 retries", mockedStatus: http.StatusTooManyRequests, mockedErr: fmt.Errorf(http.StatusText(http.StatusTooManyRequests)), want: nil, wantErr: true, wantPlainError: true, retries: 5, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { if tt.retries > 0 { tt.retries-- } rw.WriteHeader(tt.mockedStatus) bytes, _ := json.Marshal(tt.mockedErr) rw.Write(bytes) })) defer s.Close() u, err := url.Parse(s.URL) if err != nil { t.Fatal(err) } f := dockerFetcher{&dockerBase{ repository: "ns", }} host := RegistryHost{ Client: s.Client(), Host: u.Host, Scheme: u.Scheme, Path: u.Path, } req := f.request(host, http.MethodGet) got, cl, err := f.open(context.TODO(), req, "", 0) assert.Equal(t, tt.wantErr, err != nil) assert.Equal(t, tt.want, got) assert.Equal(t, tt.wantLen, cl) assert.Equal(t, tt.retries, 0) if tt.wantErr { var expectedError error if tt.wantServerMessageError { expectedError = fmt.Errorf("unexpected status code %v/ns: %v %s - Server message: %s", s.URL, tt.mockedStatus, http.StatusText(tt.mockedStatus), tt.mockedErr.Error()) } else if tt.wantPlainError { expectedError = fmt.Errorf("unexpected status code %v/ns: %v %s", s.URL, tt.mockedStatus, http.StatusText(tt.mockedStatus)) } assert.Equal(t, expectedError.Error(), err.Error()) } }) } } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/handler.go000066400000000000000000000076251453374237200243020ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "fmt" "net/url" "strings" "github.com/containerd/containerd/content" "github.com/containerd/containerd/images" "github.com/containerd/containerd/labels" "github.com/containerd/containerd/log" "github.com/containerd/containerd/reference" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // AppendDistributionSourceLabel updates the label of blob with distribution source. func AppendDistributionSourceLabel(manager content.Manager, ref string) (images.HandlerFunc, error) { refspec, err := reference.Parse(ref) if err != nil { return nil, err } u, err := url.Parse("dummy://" + refspec.Locator) if err != nil { return nil, err } source, repo := u.Hostname(), strings.TrimPrefix(u.Path, "/") return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { info, err := manager.Info(ctx, desc.Digest) if err != nil { return nil, err } key := distributionSourceLabelKey(source) originLabel := "" if info.Labels != nil { originLabel = info.Labels[key] } value := appendDistributionSourceLabel(originLabel, repo) // The repo name has been limited under 256 and the distribution // label might hit the limitation of label size, when blob data // is used as the very, very common layer. if err := labels.Validate(key, value); err != nil { log.G(ctx).Warnf("skip to append distribution label: %s", err) return nil, nil } info = content.Info{ Digest: desc.Digest, Labels: map[string]string{ key: value, }, } _, err = manager.Update(ctx, info, fmt.Sprintf("labels.%s", key)) return nil, err }, nil } func appendDistributionSourceLabel(originLabel, repo string) string { repos := []string{} if originLabel != "" { repos = strings.Split(originLabel, ",") } repos = append(repos, repo) // use empty string to present duplicate items for i := 1; i < len(repos); i++ { tmp, j := repos[i], i-1 for ; j >= 0 && repos[j] >= tmp; j-- { if repos[j] == tmp { tmp = "" } repos[j+1] = repos[j] } repos[j+1] = tmp } i := 0 for ; i < len(repos) && repos[i] == ""; i++ { } return strings.Join(repos[i:], ",") } func distributionSourceLabelKey(source string) string { return fmt.Sprintf("%s.%s", labels.LabelDistributionSource, source) } // selectRepositoryMountCandidate will select the repo which has longest // common prefix components as the candidate. func selectRepositoryMountCandidate(refspec reference.Spec, sources map[string]string) string { u, err := url.Parse("dummy://" + refspec.Locator) if err != nil { // NOTE: basically, it won't be error here return "" } source, target := u.Hostname(), strings.TrimPrefix(u.Path, "/") repoLabel, ok := sources[distributionSourceLabelKey(source)] if !ok || repoLabel == "" { return "" } n, match := 0, "" components := strings.Split(target, "/") for _, repo := range strings.Split(repoLabel, ",") { // the target repo is not a candidate if repo == target { continue } if l := commonPrefixComponents(components, repo); l >= n { n, match = l, repo } } return match } func commonPrefixComponents(components []string, target string) int { targetComponents := strings.Split(target, "/") i := 0 for ; i < len(components) && i < len(targetComponents); i++ { if components[i] != targetComponents[i] { break } } return i } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/handler_test.go000066400000000000000000000066631453374237200253420ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "reflect" "testing" "github.com/containerd/containerd/labels" "github.com/containerd/containerd/reference" ) func TestAppendDistributionLabel(t *testing.T) { for _, tc := range []struct { originLabel string repo string expected string }{ { originLabel: "", repo: "", expected: "", }, { originLabel: "", repo: "library/busybox", expected: "library/busybox", }, { originLabel: "library/busybox", repo: "library/busybox", expected: "library/busybox", }, // remove the duplicate one in origin { originLabel: "library/busybox,library/redis,library/busybox", repo: "library/alpine", expected: "library/alpine,library/busybox,library/redis", }, // remove the empty repo { originLabel: "library/busybox,library/redis,library/busybox", repo: "", expected: "library/busybox,library/redis", }, { originLabel: "library/busybox,library/redis,library/busybox", repo: "library/redis", expected: "library/busybox,library/redis", }, } { if got := appendDistributionSourceLabel(tc.originLabel, tc.repo); !reflect.DeepEqual(got, tc.expected) { t.Fatalf("expected %v, but got %v", tc.expected, got) } } } func TestDistributionSourceLabelKey(t *testing.T) { expected := labels.LabelDistributionSource + ".testsource" if got := distributionSourceLabelKey("testsource"); !reflect.DeepEqual(got, expected) { t.Fatalf("expected %v, but got %v", expected, got) } } func TestCommonPrefixComponents(t *testing.T) { for _, tc := range []struct { components []string target string expected int }{ { components: []string{"foo"}, target: "foo/bar", expected: 1, }, { components: []string{"bar"}, target: "foo/bar", expected: 0, }, { components: []string{"foo", "bar"}, target: "foo/bar", expected: 2, }, } { if got := commonPrefixComponents(tc.components, tc.target); !reflect.DeepEqual(got, tc.expected) { t.Fatalf("expected %v, but got %v", tc.expected, got) } } } func TestSelectRepositoryMountCandidate(t *testing.T) { for _, tc := range []struct { refspec reference.Spec source map[string]string expected string }{ { refspec: reference.Spec{}, source: map[string]string{"": ""}, expected: "", }, { refspec: reference.Spec{Locator: "user@host/path"}, source: map[string]string{labels.LabelDistributionSource + ".host": "foo,path,bar"}, expected: "bar", }, { refspec: reference.Spec{Locator: "user@host/path"}, source: map[string]string{labels.LabelDistributionSource + ".host": "foo,bar,path"}, expected: "bar", }, } { if got := selectRepositoryMountCandidate(tc.refspec, tc.source); !reflect.DeepEqual(got, tc.expected) { t.Fatalf("expected %v, but got %v", tc.expected, got) } } } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/httpreadseeker.go000066400000000000000000000075521453374237200256760ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "bytes" "fmt" "io" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" ) const maxRetry = 3 type httpReadSeeker struct { size int64 offset int64 rc io.ReadCloser open func(offset int64) (io.ReadCloser, error) closed bool errsWithNoProgress int } func newHTTPReadSeeker(size int64, open func(offset int64) (io.ReadCloser, error)) (io.ReadCloser, error) { return &httpReadSeeker{ size: size, open: open, }, nil } func (hrs *httpReadSeeker) Read(p []byte) (n int, err error) { if hrs.closed { return 0, io.EOF } rd, err := hrs.reader() if err != nil { return 0, err } n, err = rd.Read(p) hrs.offset += int64(n) if n > 0 || err == nil { hrs.errsWithNoProgress = 0 } if err == io.ErrUnexpectedEOF { // connection closed unexpectedly. try reconnecting. if n == 0 { hrs.errsWithNoProgress++ if hrs.errsWithNoProgress > maxRetry { return // too many retries for this offset with no progress } } if hrs.rc != nil { if clsErr := hrs.rc.Close(); clsErr != nil { log.L.WithError(clsErr).Error("httpReadSeeker: failed to close ReadCloser") } hrs.rc = nil } if _, err2 := hrs.reader(); err2 == nil { return n, nil } } return } func (hrs *httpReadSeeker) Close() error { if hrs.closed { return nil } hrs.closed = true if hrs.rc != nil { return hrs.rc.Close() } return nil } func (hrs *httpReadSeeker) Seek(offset int64, whence int) (int64, error) { if hrs.closed { return 0, fmt.Errorf("Fetcher.Seek: closed: %w", errdefs.ErrUnavailable) } abs := hrs.offset switch whence { case io.SeekStart: abs = offset case io.SeekCurrent: abs += offset case io.SeekEnd: if hrs.size == -1 { return 0, fmt.Errorf("Fetcher.Seek: unknown size, cannot seek from end: %w", errdefs.ErrUnavailable) } abs = hrs.size + offset default: return 0, fmt.Errorf("Fetcher.Seek: invalid whence: %w", errdefs.ErrInvalidArgument) } if abs < 0 { return 0, fmt.Errorf("Fetcher.Seek: negative offset: %w", errdefs.ErrInvalidArgument) } if abs != hrs.offset { if hrs.rc != nil { if err := hrs.rc.Close(); err != nil { log.L.WithError(err).Error("Fetcher.Seek: failed to close ReadCloser") } hrs.rc = nil } hrs.offset = abs } return hrs.offset, nil } func (hrs *httpReadSeeker) reader() (io.Reader, error) { if hrs.rc != nil { return hrs.rc, nil } if hrs.size == -1 || hrs.offset < hrs.size { // only try to reopen the body request if we are seeking to a value // less than the actual size. if hrs.open == nil { return nil, fmt.Errorf("cannot open: %w", errdefs.ErrNotImplemented) } rc, err := hrs.open(hrs.offset) if err != nil { return nil, fmt.Errorf("httpReadSeeker: failed open: %w", err) } if hrs.rc != nil { if err := hrs.rc.Close(); err != nil { log.L.WithError(err).Error("httpReadSeeker: failed to close ReadCloser") } } hrs.rc = rc } else { // There is an edge case here where offset == size of the content. If // we seek, we will probably get an error for content that cannot be // sought (?). In that case, we should err on committing the content, // as the length is already satisfied but we just return the empty // reader instead. hrs.rc = io.NopCloser(bytes.NewReader([]byte{})) } return hrs.rc, nil } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/pusher.go000066400000000000000000000344051453374237200241670ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "errors" "fmt" "io" "net/http" "net/url" "strings" "sync" "time" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes" remoteserrors "github.com/containerd/nydus-snapshotter/pkg/remote/remotes/errors" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) type dockerPusher struct { *dockerBase object string // TODO: namespace tracker tracker StatusTracker } // Writer implements Ingester API of content store. This allows the client // to receive ErrUnavailable when there is already an on-going upload. // Note that the tracker MUST implement StatusTrackLocker interface to avoid // race condition on StatusTracker. func (p dockerPusher) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) { var wOpts content.WriterOpts for _, opt := range opts { if err := opt(&wOpts); err != nil { return nil, err } } if wOpts.Ref == "" { return nil, fmt.Errorf("ref must not be empty: %w", errdefs.ErrInvalidArgument) } return p.push(ctx, wOpts.Desc, wOpts.Ref, true) } func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) { return p.push(ctx, desc, remotes.MakeRefKey(ctx, desc), false) } func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref string, unavailableOnFail bool) (content.Writer, error) { if l, ok := p.tracker.(StatusTrackLocker); ok { l.Lock(ref) defer l.Unlock(ref) } ctx, err := ContextWithRepositoryScope(ctx, p.refspec, true) if err != nil { return nil, err } status, err := p.tracker.GetStatus(ref) if err == nil { if status.Committed && status.Offset == status.Total { return nil, fmt.Errorf("ref %v: %w", ref, errdefs.ErrAlreadyExists) } if unavailableOnFail && status.ErrClosed == nil { // Another push of this ref is happening elsewhere. The rest of function // will continue only when `errdefs.IsNotFound(err) == true` (i.e. there // is no actively-tracked ref already). return nil, fmt.Errorf("push is on-going: %w", errdefs.ErrUnavailable) } // TODO: Handle incomplete status } else if !errdefs.IsNotFound(err) { return nil, fmt.Errorf("failed to get status: %w", err) } hosts := p.filterHosts(HostCapabilityPush) if len(hosts) == 0 { return nil, fmt.Errorf("no push hosts: %w", errdefs.ErrNotFound) } var ( isManifest bool existCheck []string host = hosts[0] ) switch desc.MediaType { case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex: isManifest = true existCheck = getManifestPath(p.object, desc.Digest) default: existCheck = []string{"blobs", desc.Digest.String()} } req := p.request(host, http.MethodHead, existCheck...) req.header.Set("Accept", strings.Join([]string{desc.MediaType, `*/*`}, ", ")) log.G(ctx).WithField("url", req.String()).Debugf("checking and pushing to") resp, err := req.doWithRetries(ctx, nil) if err != nil { if !errors.Is(err, ErrInvalidAuthorization) { return nil, err } log.G(ctx).WithError(err).Debugf("Unable to check existence, continuing with push") } else { if resp.StatusCode == http.StatusOK { var exists bool if isManifest && existCheck[1] != desc.Digest.String() { dgstHeader := digest.Digest(resp.Header.Get("Docker-Content-Digest")) if dgstHeader == desc.Digest { exists = true } } else { exists = true } if exists { p.tracker.SetStatus(ref, Status{ Committed: true, Status: content.Status{ Ref: ref, Total: desc.Size, Offset: desc.Size, // TODO: Set updated time? }, }) resp.Body.Close() return nil, fmt.Errorf("content %v on remote: %w", desc.Digest, errdefs.ErrAlreadyExists) } } else if resp.StatusCode != http.StatusNotFound { err := remoteserrors.NewUnexpectedStatusErr(resp) log.G(ctx).WithField("resp", resp).WithField("body", string(err.(remoteserrors.ErrUnexpectedStatus).Body)).Debug("unexpected response") resp.Body.Close() return nil, err } resp.Body.Close() } if isManifest { putPath := getManifestPath(p.object, desc.Digest) req = p.request(host, http.MethodPut, putPath...) req.header.Add("Content-Type", desc.MediaType) } else { // Start upload request req = p.request(host, http.MethodPost, "blobs", "uploads/") var resp *http.Response if fromRepo := selectRepositoryMountCandidate(p.refspec, desc.Annotations); fromRepo != "" { preq := requestWithMountFrom(req, desc.Digest.String(), fromRepo) pctx := ContextWithAppendPullRepositoryScope(ctx, fromRepo) // NOTE: the fromRepo might be private repo and // auth service still can grant token without error. // but the post request will fail because of 401. // // for the private repo, we should remove mount-from // query and send the request again. resp, err = preq.doWithRetries(pctx, nil) if err != nil { return nil, err } if resp.StatusCode == http.StatusUnauthorized { log.G(ctx).Debugf("failed to mount from repository %s", fromRepo) resp.Body.Close() resp = nil } } if resp == nil { resp, err = req.doWithRetries(ctx, nil) if err != nil { if errors.Is(err, ErrInvalidAuthorization) { return nil, fmt.Errorf("push access denied, repository does not exist or may require authorization: %w", err) } return nil, err } } defer resp.Body.Close() switch resp.StatusCode { case http.StatusOK, http.StatusAccepted, http.StatusNoContent: case http.StatusCreated: p.tracker.SetStatus(ref, Status{ Committed: true, Status: content.Status{ Ref: ref, Total: desc.Size, Offset: desc.Size, }, }) return nil, fmt.Errorf("content %v on remote: %w", desc.Digest, errdefs.ErrAlreadyExists) default: err := remoteserrors.NewUnexpectedStatusErr(resp) log.G(ctx).WithField("resp", resp).WithField("body", string(err.(remoteserrors.ErrUnexpectedStatus).Body)).Debug("unexpected response") return nil, err } var ( location = resp.Header.Get("Location") lurl *url.URL lhost = host ) // Support paths without host in location if strings.HasPrefix(location, "/") { lurl, err = url.Parse(lhost.Scheme + "://" + lhost.Host + location) if err != nil { return nil, fmt.Errorf("unable to parse location %v: %w", location, err) } } else { if !strings.Contains(location, "://") { location = lhost.Scheme + "://" + location } lurl, err = url.Parse(location) if err != nil { return nil, fmt.Errorf("unable to parse location %v: %w", location, err) } if lurl.Host != lhost.Host || lhost.Scheme != lurl.Scheme { lhost.Scheme = lurl.Scheme lhost.Host = lurl.Host log.G(ctx).WithField("host", lhost.Host).WithField("scheme", lhost.Scheme).Debug("upload changed destination") // Strip authorizer if change to host or scheme lhost.Authorizer = nil } } q := lurl.Query() q.Add("digest", desc.Digest.String()) req = p.request(lhost, http.MethodPut) req.header.Set("Content-Type", "application/octet-stream") req.path = lurl.Path + "?" + q.Encode() } p.tracker.SetStatus(ref, Status{ Status: content.Status{ Ref: ref, Total: desc.Size, Expected: desc.Digest, StartedAt: time.Now(), }, }) // TODO: Support chunked upload pushw := newPushWriter(p.dockerBase, ref, desc.Digest, p.tracker, isManifest) req.body = func() (io.ReadCloser, error) { pr, pw := io.Pipe() pushw.setPipe(pw) return io.NopCloser(pr), nil } req.size = desc.Size go func() { resp, err := req.doWithRetries(ctx, nil) if err != nil { pushw.setError(err) pushw.Close() return } switch resp.StatusCode { case http.StatusOK, http.StatusCreated, http.StatusNoContent: default: err := remoteserrors.NewUnexpectedStatusErr(resp) log.G(ctx).WithField("resp", resp).WithField("body", string(err.(remoteserrors.ErrUnexpectedStatus).Body)).Debug("unexpected response") pushw.setError(err) pushw.Close() } pushw.setResponse(resp) }() return pushw, nil } func getManifestPath(object string, dgst digest.Digest) []string { if i := strings.IndexByte(object, '@'); i >= 0 { if object[i+1:] != dgst.String() { // use digest, not tag object = "" } else { // strip @ for registry path to make tag object = object[:i] } } if object == "" { return []string{"manifests", dgst.String()} } return []string{"manifests", object} } type pushWriter struct { base *dockerBase ref string pipe *io.PipeWriter pipeC chan *io.PipeWriter respC chan *http.Response closeOnce sync.Once errC chan error isManifest bool expected digest.Digest tracker StatusTracker } func newPushWriter(db *dockerBase, ref string, expected digest.Digest, tracker StatusTracker, isManifest bool) *pushWriter { // Initialize and create response return &pushWriter{ base: db, ref: ref, expected: expected, tracker: tracker, pipeC: make(chan *io.PipeWriter, 1), respC: make(chan *http.Response, 1), errC: make(chan error, 1), isManifest: isManifest, } } func (pw *pushWriter) setPipe(p *io.PipeWriter) { pw.pipeC <- p } func (pw *pushWriter) setError(err error) { pw.errC <- err } func (pw *pushWriter) setResponse(resp *http.Response) { pw.respC <- resp } func (pw *pushWriter) Write(p []byte) (n int, err error) { status, err := pw.tracker.GetStatus(pw.ref) if err != nil { return n, err } if pw.pipe == nil { p, ok := <-pw.pipeC if !ok { return 0, io.ErrClosedPipe } pw.pipe = p } else { select { case p, ok := <-pw.pipeC: if !ok { return 0, io.ErrClosedPipe } pw.pipe.CloseWithError(content.ErrReset) pw.pipe = p // If content has already been written, the bytes // cannot be written and the caller must reset status.Offset = 0 status.UpdatedAt = time.Now() pw.tracker.SetStatus(pw.ref, status) return 0, content.ErrReset default: } } n, err = pw.pipe.Write(p) if errors.Is(err, io.ErrClosedPipe) { // if the pipe is closed, we might have the original error on the error // channel - so we should try and get it select { case err2 := <-pw.errC: err = err2 default: } } status.Offset += int64(n) status.UpdatedAt = time.Now() pw.tracker.SetStatus(pw.ref, status) return } func (pw *pushWriter) Close() error { // Ensure pipeC is closed but handle `Close()` being // called multiple times without panicking pw.closeOnce.Do(func() { close(pw.pipeC) }) if pw.pipe != nil { status, err := pw.tracker.GetStatus(pw.ref) if err == nil && !status.Committed { // Closing an incomplete writer. Record this as an error so that following write can retry it. status.ErrClosed = errors.New("closed incomplete writer") pw.tracker.SetStatus(pw.ref, status) } return pw.pipe.Close() } return nil } func (pw *pushWriter) Status() (content.Status, error) { status, err := pw.tracker.GetStatus(pw.ref) if err != nil { return content.Status{}, err } return status.Status, nil } func (pw *pushWriter) Digest() digest.Digest { // TODO: Get rid of this function? return pw.expected } func (pw *pushWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error { // Check whether read has already thrown an error if _, err := pw.pipe.Write([]byte{}); err != nil && !errors.Is(err, io.ErrClosedPipe) { return fmt.Errorf("pipe error before commit: %w", err) } if err := pw.pipe.Close(); err != nil { return err } // TODO: timeout waiting for response var resp *http.Response select { case err := <-pw.errC: return err case resp = <-pw.respC: defer resp.Body.Close() case p, ok := <-pw.pipeC: // check whether the pipe has changed in the commit, because sometimes Write // can complete successfully, but the pipe may have changed. In that case, the // content needs to be reset. if !ok { return io.ErrClosedPipe } pw.pipe.CloseWithError(content.ErrReset) pw.pipe = p // If content has already been written, the bytes // cannot be written again and the caller must reset status, err := pw.tracker.GetStatus(pw.ref) if err != nil { return err } status.Offset = 0 status.UpdatedAt = time.Now() pw.tracker.SetStatus(pw.ref, status) return content.ErrReset } // 201 is specified return status, some registries return // 200, 202 or 204. switch resp.StatusCode { case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: default: return remoteserrors.NewUnexpectedStatusErr(resp) } status, err := pw.tracker.GetStatus(pw.ref) if err != nil { return fmt.Errorf("failed to get status: %w", err) } if size > 0 && size != status.Offset { return fmt.Errorf("unexpected size %d, expected %d", status.Offset, size) } if expected == "" { expected = status.Expected } actual, err := digest.Parse(resp.Header.Get("Docker-Content-Digest")) if err != nil { return fmt.Errorf("invalid content digest in response: %w", err) } if actual != expected { return fmt.Errorf("got digest %s, expected %s", actual, expected) } status.Committed = true status.UpdatedAt = time.Now() pw.tracker.SetStatus(pw.ref, status) return nil } func (pw *pushWriter) Truncate(size int64) error { // TODO: if blob close request and start new request at offset // TODO: always error on manifest return errors.New("cannot truncate remote upload") } func requestWithMountFrom(req *request, mount, from string) *request { creq := *req sep := "?" if strings.Contains(creq.path, sep) { sep = "&" } creq.path = creq.path + sep + "mount=" + mount + "&from=" + from return &creq } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/pusher_test.go000066400000000000000000000254501453374237200252260ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "errors" "fmt" "io" "net/http" "net/http/httptest" "net/url" "reflect" "regexp" "strings" "testing" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/stretchr/testify/assert" ) func TestGetManifestPath(t *testing.T) { for _, tc := range []struct { object string dgst digest.Digest expected []string }{ { object: "foo", dgst: "bar", expected: []string{"manifests", "foo"}, }, { object: "foo@bar", dgst: "bar", expected: []string{"manifests", "foo"}, }, { object: "foo@bar", dgst: "foobar", expected: []string{"manifests", "foobar"}, }, } { if got := getManifestPath(tc.object, tc.dgst); !reflect.DeepEqual(got, tc.expected) { t.Fatalf("expected %v, but got %v", tc.expected, got) } } } // TestPusherErrClosedRetry tests if retrying work when error occurred on close. func TestPusherErrClosedRetry(t *testing.T) { ctx := context.Background() p, reg, done := samplePusher(t) defer done() layerContent := []byte("test") reg.uploadable = false if err := tryUpload(ctx, t, p, layerContent); err == nil { t.Errorf("upload should fail but succeeded") } // retry reg.uploadable = true if err := tryUpload(ctx, t, p, layerContent); err != nil { t.Errorf("upload should succeed but got %v", err) } } // TestPusherErrReset tests the push method if the request needs to be retried // i.e when ErrReset occurs func TestPusherErrReset(t *testing.T) { p, reg, done := samplePusher(t) defer done() p.object = "latest@sha256:55d31f3af94c797b65b310569803cacc1c9f4a34bf61afcdc8138f89345c8308" reg.uploadable = true reg.putHandlerFunc = func() func(w http.ResponseWriter, r *http.Request) bool { // sets whether the request should timeout so that a reset error can occur and // request will be retried shouldTimeout := true return func(w http.ResponseWriter, r *http.Request) bool { if shouldTimeout { shouldTimeout = !shouldTimeout w.WriteHeader(http.StatusRequestTimeout) return true } return false } }() ct := []byte("manifest-content") desc := ocispec.Descriptor{ MediaType: ocispec.MediaTypeImageManifest, Digest: digest.FromBytes(ct), Size: int64(len(ct)), } w, err := p.push(context.Background(), desc, remotes.MakeRefKey(context.Background(), desc), false) assert.NoError(t, err) // first push should fail with ErrReset _, err = w.Write(ct) assert.NoError(t, err) err = w.Commit(context.Background(), desc.Size, desc.Digest) assert.Equal(t, content.ErrReset, err) // second push should succeed _, err = w.Write(ct) assert.NoError(t, err) err = w.Commit(context.Background(), desc.Size, desc.Digest) assert.NoError(t, err) } func tryUpload(ctx context.Context, t *testing.T, p dockerPusher, layerContent []byte) error { desc := ocispec.Descriptor{ MediaType: ocispec.MediaTypeImageLayerGzip, Digest: digest.FromBytes(layerContent), Size: int64(len(layerContent)), } cw, err := p.Writer(ctx, content.WithRef("test-1"), content.WithDescriptor(desc)) if err != nil { return err } defer cw.Close() if _, err := cw.Write(layerContent); err != nil { return err } return cw.Commit(ctx, 0, "") } func samplePusher(t *testing.T) (dockerPusher, *uploadableMockRegistry, func()) { reg := &uploadableMockRegistry{ availableContents: make([]string, 0), } s := httptest.NewServer(reg) u, err := url.Parse(s.URL) if err != nil { t.Fatal(err) } return dockerPusher{ dockerBase: &dockerBase{ repository: "sample", hosts: []RegistryHost{ { Client: s.Client(), Host: u.Host, Scheme: u.Scheme, Path: u.Path, Capabilities: HostCapabilityPush | HostCapabilityResolve, }, }, }, object: "sample", tracker: NewInMemoryTracker(), }, reg, s.Close } var manifestRegexp = regexp.MustCompile(`/([a-z0-9]+)/manifests/(.*)`) var blobUploadRegexp = regexp.MustCompile(`/([a-z0-9]+)/blobs/uploads/(.*)`) // uploadableMockRegistry provides minimal registry APIs which are enough to serve requests from dockerPusher. type uploadableMockRegistry struct { availableContents []string uploadable bool putHandlerFunc func(w http.ResponseWriter, r *http.Request) bool } func (u *uploadableMockRegistry) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodPut && u.putHandlerFunc != nil { // if true return the response witout calling default handler if u.putHandlerFunc(w, r) { return } } u.defaultHandler(w, r) } func (u *uploadableMockRegistry) defaultHandler(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodPost { if matches := blobUploadRegexp.FindStringSubmatch(r.URL.Path); len(matches) != 0 { if u.uploadable { w.Header().Set("Location", "/upload") } else { w.Header().Set("Location", "/cannotupload") } dgstr := digest.Canonical.Digester() if _, err := io.Copy(dgstr.Hash(), r.Body); err != nil { w.WriteHeader(http.StatusInternalServerError) return } u.availableContents = append(u.availableContents, dgstr.Digest().String()) w.WriteHeader(http.StatusAccepted) return } } else if r.Method == http.MethodPut { mfstMatches := manifestRegexp.FindStringSubmatch(r.URL.Path) if len(mfstMatches) != 0 || strings.HasPrefix(r.URL.Path, "/upload") { dgstr := digest.Canonical.Digester() if _, err := io.Copy(dgstr.Hash(), r.Body); err != nil { w.WriteHeader(http.StatusInternalServerError) return } u.availableContents = append(u.availableContents, dgstr.Digest().String()) w.Header().Set("Docker-Content-Digest", dgstr.Digest().String()) w.WriteHeader(http.StatusCreated) return } else if r.URL.Path == "/cannotupload" { w.WriteHeader(http.StatusInternalServerError) return } } else if r.Method == http.MethodHead { var content string // check for both manifest and blob paths if manifestMatch := manifestRegexp.FindStringSubmatch(r.URL.Path); len(manifestMatch) == 3 { content = manifestMatch[2] } else if blobMatch := blobUploadRegexp.FindStringSubmatch(r.URL.Path); len(blobMatch) == 3 { content = blobMatch[2] } // if content is not found or if the path is not manifest or blob // we return 404 if u.isContentAlreadyExist(content) { w.WriteHeader(http.StatusOK) } else { w.WriteHeader(http.StatusNotFound) } return } fmt.Println(r) w.WriteHeader(http.StatusNotFound) } // checks if the content is already present in the registry func (u *uploadableMockRegistry) isContentAlreadyExist(c string) bool { for _, ct := range u.availableContents { if ct == c { return true } } return false } func Test_dockerPusher_push(t *testing.T) { p, reg, done := samplePusher(t) defer done() reg.uploadable = true manifestContent := []byte("manifest-content") manifestContentDigest := digest.FromBytes(manifestContent) layerContent := []byte("layer-content") layerContentDigest := digest.FromBytes(layerContent) // using a random object here baseObject := "latest@sha256:55d31f3af94c797b65b310569803cacc1c9f4a34bf61afcdc8138f89345c8308" type args struct { content []byte mediatype string ref string unavailableOnFail bool } tests := []struct { name string dp dockerPusher dockerBaseObject string args args checkerFunc func(writer *pushWriter) bool wantErr error }{ { name: "when a manifest is pushed", dp: p, dockerBaseObject: baseObject, args: args{ content: manifestContent, mediatype: ocispec.MediaTypeImageManifest, ref: fmt.Sprintf("manifest-%s", manifestContentDigest.String()), unavailableOnFail: false, }, checkerFunc: func(writer *pushWriter) bool { select { case resp := <-writer.respC: // 201 should be the response code when uploading a new manifest return resp.StatusCode == http.StatusCreated case <-writer.errC: return false } }, wantErr: nil, }, { name: "trying to push content that already exists", dp: p, dockerBaseObject: baseObject, args: args{ content: manifestContent, mediatype: ocispec.MediaTypeImageManifest, ref: fmt.Sprintf("manifest-%s", manifestContentDigest.String()), unavailableOnFail: false, }, wantErr: fmt.Errorf("content %v on remote: %w", digest.FromBytes(manifestContent), errdefs.ErrAlreadyExists), }, { name: "trying to push a blob layer", dp: p, // Not needed to set the base object as it is used to generate path only in case of manifests // dockerBaseObject: args: args{ content: layerContent, mediatype: ocispec.MediaTypeImageLayer, ref: fmt.Sprintf("layer-%s", layerContentDigest.String()), unavailableOnFail: false, }, checkerFunc: func(writer *pushWriter) bool { select { case resp := <-writer.respC: // 201 should be the response code when uploading a new blob return resp.StatusCode == http.StatusCreated case <-writer.errC: return false } }, wantErr: nil, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { desc := ocispec.Descriptor{ MediaType: test.args.mediatype, Digest: digest.FromBytes(test.args.content), Size: int64(len(test.args.content)), } test.dp.object = test.dockerBaseObject got, err := test.dp.push(context.Background(), desc, test.args.ref, test.args.unavailableOnFail) assert.Equal(t, test.wantErr, err) // if an error is expected, further comparisons are not required. if test.wantErr != nil { return } // write the content to the writer, this will be done when a Read() is called on the body of the request got.Write(test.args.content) pw, ok := got.(*pushWriter) if !ok { assert.Errorf(t, errors.New("unable to cast content.Writer to pushWriter"), "got %v instead of pushwriter", got) } // test whether a proper response has been received after the push operation assert.True(t, test.checkerFunc(pw)) }) } } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/referrers.go000066400000000000000000000055471453374237200246650ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "fmt" "io" "net/http" "strings" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/log" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) func (r dockerFetcher) FetchReferrers(ctx context.Context, dgst digest.Digest, artifactTypes ...string) (io.ReadCloser, ocispec.Descriptor, error) { var desc ocispec.Descriptor desc.MediaType = ocispec.MediaTypeImageIndex ctx = log.WithLogger(ctx, log.G(ctx).WithField("digest", dgst)) hosts := r.filterHosts(HostCapabilityResolve, HostCapabilityReferrers) if len(hosts) == 0 { return nil, desc, fmt.Errorf("no pull hosts: %w", errdefs.ErrNotFound) } ctx, err := ContextWithRepositoryScope(ctx, r.refspec, false) if err != nil { return nil, desc, err } for _, host := range hosts { var req *request // if host.Capabilities.Has(HostCapabilityReferrers) { req = r.request(host, http.MethodGet, "referrers", dgst.String()) for _, artifactType := range artifactTypes { if err := req.addQuery("artifactType", artifactType); err != nil { return nil, desc, err } } if err := req.addNamespace(r.refspec.Hostname()); err != nil { return nil, desc, err } rc, cl, err := r.open(ctx, req, desc.MediaType, 0) if err != nil { if !errdefs.IsNotFound(err) { return nil, desc, err } } else { desc.Size = cl // Digest is not known ahead of time and there is nothing in the distribution // specification defining an HTTP header to return the digest on referrers. return rc, desc, nil } // } if host.Capabilities.Has(HostCapabilityResolve) { req = r.request(host, http.MethodGet, "manifests", strings.Replace(dgst.String(), ":", "-", 1)) if err := req.addNamespace(r.refspec.Hostname()); err != nil { return nil, desc, err } rc, cl, err := r.open(ctx, req, desc.MediaType, 0) if err != nil { if !errdefs.IsNotFound(err) { return nil, desc, err } } else { desc.Size = cl // Digest could be resolved here the same as for any manifest, don't include the // digest for consistency with the referrers endpoint. return rc, desc, nil } } } return nil, ocispec.Descriptor{}, fmt.Errorf("could not be found at any host: %w", errdefs.ErrNotFound) } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/registry.go000066400000000000000000000157351453374237200245360ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "errors" "net" "net/http" ) // HostCapabilities represent the capabilities of the registry // host. This also represents the set of operations for which // the registry host may be trusted to perform. // // For example pushing is a capability which should only be // performed on an upstream source, not a mirror. // Resolving (the process of converting a name into a digest) // must be considered a trusted operation and only done by // a host which is trusted (or more preferably by secure process // which can prove the provenance of the mapping). A public // mirror should never be trusted to do a resolve action. // // | Registry Type | Pull | Resolve | Push | // |------------------|------|---------|------| // | Public Registry | yes | yes | yes | // | Private Registry | yes | yes | yes | // | Public Mirror | yes | no | no | // | Private Mirror | yes | yes | no | type HostCapabilities uint8 const ( // HostCapabilityPull represents the capability to fetch manifests // and blobs by digest HostCapabilityPull HostCapabilities = 1 << iota // HostCapabilityResolve represents the capability to fetch manifests // by name HostCapabilityResolve // HostCapabilityPush represents the capability to push blobs and // manifests HostCapabilityPush // HostCapabilityReferrers represents the capability to generate a // list of referrers using the OCI Distribution referrers endpoint. HostCapabilityReferrers // Reserved for future capabilities (i.e. search, catalog, remove) ) // Has checks whether the capabilities list has the provide capability func (c HostCapabilities) Has(t HostCapabilities) bool { return c&t == t } // RegistryHost represents a complete configuration for a registry // host, representing the capabilities, authorizations, connection // configuration, and location. type RegistryHost struct { Client *http.Client Authorizer Authorizer Host string Scheme string Path string Capabilities HostCapabilities Header http.Header } func (h RegistryHost) isProxy(refhost string) bool { if refhost != h.Host { if refhost != "docker.io" || h.Host != "registry-1.docker.io" { return true } } return false } // RegistryHosts fetches the registry hosts for a given namespace, // provided by the host component of an distribution image reference. type RegistryHosts func(string) ([]RegistryHost, error) // Registries joins multiple registry configuration functions, using the same // order as provided within the arguments. When an empty registry configuration // is returned with a nil error, the next function will be called. // NOTE: This function will not join configurations, as soon as a non-empty // configuration is returned from a configuration function, it will be returned // to the caller. func Registries(registries ...RegistryHosts) RegistryHosts { return func(host string) ([]RegistryHost, error) { for _, registry := range registries { config, err := registry(host) if err != nil { return config, err } if len(config) > 0 { return config, nil } } return nil, nil } } type registryOpts struct { authorizer Authorizer plainHTTP func(string) (bool, error) host func(string) (string, error) client *http.Client } // RegistryOpt defines a registry default option type RegistryOpt func(*registryOpts) // WithPlainHTTP configures registries to use plaintext http scheme // for the provided host match function. func WithPlainHTTP(f func(string) (bool, error)) RegistryOpt { return func(opts *registryOpts) { opts.plainHTTP = f } } // WithAuthorizer configures the default authorizer for a registry func WithAuthorizer(a Authorizer) RegistryOpt { return func(opts *registryOpts) { opts.authorizer = a } } // WithHostTranslator defines the default translator to use for registry hosts func WithHostTranslator(h func(string) (string, error)) RegistryOpt { return func(opts *registryOpts) { opts.host = h } } // WithClient configures the default http client for a registry func WithClient(c *http.Client) RegistryOpt { return func(opts *registryOpts) { opts.client = c } } // ConfigureDefaultRegistries is used to create a default configuration for // registries. For more advanced configurations or per-domain setups, // the RegistryHosts interface should be used directly. // NOTE: This function will always return a non-empty value or error func ConfigureDefaultRegistries(ropts ...RegistryOpt) RegistryHosts { var opts registryOpts for _, opt := range ropts { opt(&opts) } return func(host string) ([]RegistryHost, error) { config := RegistryHost{ Client: opts.client, Authorizer: opts.authorizer, Host: host, Scheme: "https", Path: "/v2", Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush, } if config.Client == nil { config.Client = http.DefaultClient } if opts.plainHTTP != nil { match, err := opts.plainHTTP(host) if err != nil { return nil, err } if match { config.Scheme = "http" } } if opts.host != nil { var err error config.Host, err = opts.host(config.Host) if err != nil { return nil, err } } else if host == "docker.io" { config.Host = "registry-1.docker.io" } return []RegistryHost{config}, nil } } // MatchAllHosts is a host match function which is always true. func MatchAllHosts(string) (bool, error) { return true, nil } // MatchLocalhost is a host match function which returns true for // localhost. // // Note: this does not handle matching of ip addresses in octal, // decimal or hex form. func MatchLocalhost(host string) (bool, error) { switch { case host == "::1": return true, nil case host == "[::1]": return true, nil } h, p, err := net.SplitHostPort(host) // addrError helps distinguish between errors of form // "no colon in address" and "too many colons in address". // The former is fine as the host string need not have a // port. Latter needs to be handled. addrError := &net.AddrError{ Err: "missing port in address", Addr: host, } if err != nil { if err.Error() != addrError.Error() { return false, err } // host string without any port specified h = host } else if len(p) == 0 { return false, errors.New("invalid host name format") } // use ipv4 dotted decimal for further checking if h == "localhost" { h = "127.0.0.1" } ip := net.ParseIP(h) return ip.IsLoopback(), nil } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/registry_test.go000066400000000000000000000037211453374237200255650ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import "testing" func TestHasCapability(t *testing.T) { var ( pull = HostCapabilityPull rslv = HostCapabilityResolve push = HostCapabilityPush all = pull | rslv | push ) for i, tc := range []struct { c HostCapabilities t HostCapabilities e bool }{ {all, pull, true}, {all, pull | rslv, true}, {all, pull | push, true}, {all, all, true}, {pull, all, false}, {pull, push, false}, {rslv, pull, false}, {pull | rslv, push, false}, {pull | rslv, rslv, true}, } { if a := tc.c.Has(tc.t); a != tc.e { t.Fatalf("%d: failed, expected %t, got %t", i, tc.e, a) } } } func TestMatchLocalhost(t *testing.T) { for _, tc := range []struct { host string match bool }{ {"", false}, {"127.1.1.1", true}, {"127.0.0.1", true}, {"127.256.0.1", false}, // test MatchLocalhost does not panic on invalid ip {"127.23.34.52", true}, {"127.0.0.1:5000", true}, {"registry.org", false}, {"126.example.com", false}, {"localhost", true}, {"localhost:5000", true}, {"[127:0:0:1]", false}, {"[::1]", true}, {"[::1]:", false}, // invalid ip {"127.0.1.1:", false}, // invalid ip {"[::1]:5000", true}, {"::1", true}, } { actual, _ := MatchLocalhost(tc.host) if actual != tc.match { if tc.match { t.Logf("Expected match for %s", tc.host) } else { t.Logf("Unexpected match for %s", tc.host) } t.Fail() } } } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/resolver.go000066400000000000000000000466101453374237200245230ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "errors" "fmt" "io" "net" "net/http" "net/url" "path" "strings" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" "github.com/containerd/containerd/reference" "github.com/containerd/containerd/tracing" "github.com/containerd/containerd/version" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes/docker/schema1" //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. remoteerrors "github.com/containerd/nydus-snapshotter/pkg/remote/remotes/errors" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) var ( // ErrInvalidAuthorization is used when credentials are passed to a server but // those credentials are rejected. ErrInvalidAuthorization = errors.New("authorization failed") // MaxManifestSize represents the largest size accepted from a registry // during resolution. Larger manifests may be accepted using a // resolution method other than the registry. // // NOTE: The max supported layers by some runtimes is 128 and individual // layers will not contribute more than 256 bytes, making a // reasonable limit for a large image manifests of 32K bytes. // 4M bytes represents a much larger upper bound for images which may // contain large annotations or be non-images. A proper manifest // design puts large metadata in subobjects, as is consistent the // intent of the manifest design. MaxManifestSize int64 = 4 * 1048 * 1048 ) // Authorizer is used to authorize HTTP requests based on 401 HTTP responses. // An Authorizer is responsible for caching tokens or credentials used by // requests. type Authorizer interface { // Authorize sets the appropriate `Authorization` header on the given // request. // // If no authorization is found for the request, the request remains // unmodified. It may also add an `Authorization` header as // "bearer " // "basic " // // It may return remotes/errors.ErrUnexpectedStatus, which for example, // can be used by the caller to find out the status code returned by the registry. Authorize(context.Context, *http.Request) error // AddResponses adds a 401 response for the authorizer to consider when // authorizing requests. The last response should be unauthorized and // the previous requests are used to consider redirects and retries // that may have led to the 401. // // If response is not handled, returns `ErrNotImplemented` AddResponses(context.Context, []*http.Response) error } // ResolverOptions are used to configured a new Docker register resolver type ResolverOptions struct { // Hosts returns registry host configurations for a namespace. Hosts RegistryHosts // Headers are the HTTP request header fields sent by the resolver Headers http.Header // Tracker is used to track uploads to the registry. This is used // since the registry does not have upload tracking and the existing // mechanism for getting blob upload status is expensive. Tracker StatusTracker // Authorizer is used to authorize registry requests // Deprecated: use Hosts Authorizer Authorizer // Credentials provides username and secret given a host. // If username is empty but a secret is given, that secret // is interpreted as a long lived token. // Deprecated: use Hosts Credentials func(string) (string, string, error) // Host provides the hostname given a namespace. // Deprecated: use Hosts Host func(string) (string, error) // PlainHTTP specifies to use plain http and not https // Deprecated: use Hosts PlainHTTP bool // Client is the http client to used when making registry requests // Deprecated: use Hosts Client *http.Client } // DefaultHost is the default host function. func DefaultHost(ns string) (string, error) { if ns == "docker.io" { return "registry-1.docker.io", nil } return ns, nil } type dockerResolver struct { hosts RegistryHosts header http.Header resolveHeader http.Header tracker StatusTracker } // NewResolver returns a new resolver to a Docker registry func NewResolver(options ResolverOptions) remotes.Resolver { if options.Tracker == nil { options.Tracker = NewInMemoryTracker() } if options.Headers == nil { options.Headers = make(http.Header) } if _, ok := options.Headers["User-Agent"]; !ok { options.Headers.Set("User-Agent", "containerd/"+version.Version) } resolveHeader := http.Header{} if _, ok := options.Headers["Accept"]; !ok { // set headers for all the types we support for resolution. resolveHeader.Set("Accept", strings.Join([]string{ images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex, "*/*", }, ", ")) } else { resolveHeader["Accept"] = options.Headers["Accept"] delete(options.Headers, "Accept") } if options.Hosts == nil { opts := []RegistryOpt{} if options.Host != nil { opts = append(opts, WithHostTranslator(options.Host)) } if options.Authorizer == nil { options.Authorizer = NewDockerAuthorizer( WithAuthClient(options.Client), WithAuthHeader(options.Headers), WithAuthCreds(options.Credentials)) } opts = append(opts, WithAuthorizer(options.Authorizer)) if options.Client != nil { opts = append(opts, WithClient(options.Client)) } if options.PlainHTTP { opts = append(opts, WithPlainHTTP(MatchAllHosts)) } else { opts = append(opts, WithPlainHTTP(MatchLocalhost)) } options.Hosts = ConfigureDefaultRegistries(opts...) } return &dockerResolver{ hosts: options.Hosts, header: options.Headers, resolveHeader: resolveHeader, tracker: options.Tracker, } } func getManifestMediaType(resp *http.Response) string { // Strip encoding data (manifests should always be ascii JSON) contentType := resp.Header.Get("Content-Type") if sp := strings.IndexByte(contentType, ';'); sp != -1 { contentType = contentType[0:sp] } // As of Apr 30 2019 the registry.access.redhat.com registry does not specify // the content type of any data but uses schema1 manifests. if contentType == "text/plain" { contentType = images.MediaTypeDockerSchema1Manifest } return contentType } type countingReader struct { reader io.Reader bytesRead int64 } func (r *countingReader) Read(p []byte) (int, error) { n, err := r.reader.Read(p) r.bytesRead += int64(n) return n, err } var _ remotes.Resolver = &dockerResolver{} func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocispec.Descriptor, error) { base, err := r.resolveDockerBase(ref) if err != nil { return "", ocispec.Descriptor{}, err } refspec := base.refspec if refspec.Object == "" { return "", ocispec.Descriptor{}, reference.ErrObjectRequired } var ( firstErr error paths [][]string dgst = refspec.Digest() caps = HostCapabilityPull ) if dgst != "" { if err := dgst.Validate(); err != nil { // need to fail here, since we can't actually resolve the invalid // digest. return "", ocispec.Descriptor{}, err } // turns out, we have a valid digest, make a url. paths = append(paths, []string{"manifests", dgst.String()}) // fallback to blobs on not found. paths = append(paths, []string{"blobs", dgst.String()}) } else { // Add paths = append(paths, []string{"manifests", refspec.Object}) caps |= HostCapabilityResolve } hosts := base.filterHosts(caps) if len(hosts) == 0 { return "", ocispec.Descriptor{}, fmt.Errorf("no resolve hosts: %w", errdefs.ErrNotFound) } ctx, err = ContextWithRepositoryScope(ctx, refspec, false) if err != nil { return "", ocispec.Descriptor{}, err } for _, u := range paths { for _, host := range hosts { ctx := log.WithLogger(ctx, log.G(ctx).WithField("host", host.Host)) req := base.request(host, http.MethodHead, u...) if err := req.addNamespace(base.refspec.Hostname()); err != nil { return "", ocispec.Descriptor{}, err } for key, value := range r.resolveHeader { req.header[key] = append(req.header[key], value...) } log.G(ctx).Debug("resolving") resp, err := req.doWithRetries(ctx, nil) if err != nil { if errors.Is(err, ErrInvalidAuthorization) { err = fmt.Errorf("pull access denied, repository does not exist or may require authorization: %w", err) } // Store the error for referencing later if firstErr == nil { firstErr = err } log.G(ctx).WithError(err).Info("trying next host") continue // try another host } resp.Body.Close() // don't care about body contents. if resp.StatusCode > 299 { if resp.StatusCode == http.StatusNotFound { log.G(ctx).Info("trying next host - response was http.StatusNotFound") continue } if resp.StatusCode > 399 { // Set firstErr when encountering the first non-404 status code. if firstErr == nil { firstErr = remoteerrors.NewUnexpectedStatusErr(resp) } continue // try another host } return "", ocispec.Descriptor{}, remoteerrors.NewUnexpectedStatusErr(resp) } size := resp.ContentLength contentType := getManifestMediaType(resp) // if no digest was provided, then only a resolve // trusted registry was contacted, in this case use // the digest header (or content from GET) if dgst == "" { // this is the only point at which we trust the registry. we use the // content headers to assemble a descriptor for the name. when this becomes // more robust, we mostly get this information from a secure trust store. dgstHeader := digest.Digest(resp.Header.Get("Docker-Content-Digest")) if dgstHeader != "" && size != -1 { if err := dgstHeader.Validate(); err != nil { return "", ocispec.Descriptor{}, fmt.Errorf("%q in header not a valid digest: %w", dgstHeader, err) } dgst = dgstHeader } } if dgst == "" || size == -1 { log.G(ctx).Debug("no Docker-Content-Digest header, fetching manifest instead") req = base.request(host, http.MethodGet, u...) if err := req.addNamespace(base.refspec.Hostname()); err != nil { return "", ocispec.Descriptor{}, err } for key, value := range r.resolveHeader { req.header[key] = append(req.header[key], value...) } resp, err := req.doWithRetries(ctx, nil) if err != nil { return "", ocispec.Descriptor{}, err } bodyReader := countingReader{reader: resp.Body} contentType = getManifestMediaType(resp) err = func() error { defer resp.Body.Close() if dgst != "" { _, err = io.Copy(io.Discard, &bodyReader) return err } if contentType == images.MediaTypeDockerSchema1Manifest { b, err := schema1.ReadStripSignature(&bodyReader) if err != nil { return err } dgst = digest.FromBytes(b) return nil } dgst, err = digest.FromReader(&bodyReader) return err }() if err != nil { return "", ocispec.Descriptor{}, err } size = bodyReader.bytesRead } // Prevent resolving to excessively large manifests if size > MaxManifestSize { if firstErr == nil { firstErr = fmt.Errorf("rejecting %d byte manifest for %s: %w", size, ref, errdefs.ErrNotFound) } continue } desc := ocispec.Descriptor{ Digest: dgst, MediaType: contentType, Size: size, } log.G(ctx).WithField("desc.digest", desc.Digest).Debug("resolved") return ref, desc, nil } } // If above loop terminates without return, then there was an error. // "firstErr" contains the first non-404 error. That is, "firstErr == nil" // means that either no registries were given or each registry returned 404. if firstErr == nil { firstErr = fmt.Errorf("%s: %w", ref, errdefs.ErrNotFound) } return "", ocispec.Descriptor{}, firstErr } func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) { base, err := r.resolveDockerBase(ref) if err != nil { return nil, err } return dockerFetcher{ dockerBase: base, }, nil } func (r *dockerResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher, error) { base, err := r.resolveDockerBase(ref) if err != nil { return nil, err } return dockerPusher{ dockerBase: base, object: base.refspec.Object, tracker: r.tracker, }, nil } func (r *dockerResolver) resolveDockerBase(ref string) (*dockerBase, error) { refspec, err := reference.Parse(ref) if err != nil { return nil, err } return r.base(refspec) } type dockerBase struct { refspec reference.Spec repository string hosts []RegistryHost header http.Header } func (r *dockerResolver) base(refspec reference.Spec) (*dockerBase, error) { host := refspec.Hostname() hosts, err := r.hosts(host) if err != nil { return nil, err } return &dockerBase{ refspec: refspec, repository: strings.TrimPrefix(refspec.Locator, host+"/"), hosts: hosts, header: r.header, }, nil } // filterHosts returns a set of hosts matching the given capabilities // Multiple arguments are treated as "OR" // Each argument may be a set of capabilities in which all must be satisfied to match func (r *dockerBase) filterHosts(capsets ...HostCapabilities) (hosts []RegistryHost) { for _, host := range r.hosts { for _, caps := range capsets { if host.Capabilities.Has(caps) { hosts = append(hosts, host) break } } } return } func (r *dockerBase) request(host RegistryHost, method string, ps ...string) *request { header := r.header.Clone() if header == nil { header = http.Header{} } for key, value := range host.Header { header[key] = append(header[key], value...) } parts := append([]string{"/", host.Path, r.repository}, ps...) p := path.Join(parts...) // Join strips trailing slash, re-add ending "/" if included if len(parts) > 0 && strings.HasSuffix(parts[len(parts)-1], "/") { p = p + "/" } return &request{ method: method, path: p, header: header, host: host, } } func (r *request) authorize(ctx context.Context, req *http.Request) error { // Check if has header for host if r.host.Authorizer != nil { if err := r.host.Authorizer.Authorize(ctx, req); err != nil { return err } } return nil } func (r *request) addQuery(key, value string) (err error) { var q url.Values // Parse query if i := strings.IndexByte(r.path, '?'); i > 0 { r.path = r.path[:i+1] q, err = url.ParseQuery(r.path[i+1:]) if err != nil { return } } else { r.path = r.path + "?" q = url.Values{} } q.Add(key, value) r.path = r.path + q.Encode() return } func (r *request) addNamespace(ns string) error { if !r.host.isProxy(ns) { return nil } return r.addQuery("ns", ns) } type request struct { method string path string header http.Header host RegistryHost body func() (io.ReadCloser, error) size int64 } func (r *request) do(ctx context.Context) (*http.Response, error) { u := r.host.Scheme + "://" + r.host.Host + r.path req, err := http.NewRequestWithContext(ctx, r.method, u, nil) if err != nil { return nil, err } req.Header = http.Header{} // headers need to be copied to avoid concurrent map access for k, v := range r.header { req.Header[k] = v } if r.body != nil { body, err := r.body() if err != nil { return nil, err } req.Body = body req.GetBody = r.body if r.size > 0 { req.ContentLength = r.size } } ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", u)) log.G(ctx).WithFields(requestFields(req)).Debug("do request") if err := r.authorize(ctx, req); err != nil { return nil, fmt.Errorf("failed to authorize: %w", err) } client := &http.Client{} if r.host.Client != nil { *client = *r.host.Client } if client.CheckRedirect == nil { client.CheckRedirect = func(req *http.Request, via []*http.Request) error { if len(via) >= 10 { return errors.New("stopped after 10 redirects") } if err := r.authorize(ctx, req); err != nil { return fmt.Errorf("failed to authorize redirect: %w", err) } return nil } } _, httpSpan := tracing.StartSpan( ctx, tracing.Name("remotes.docker.resolver", "HTTPRequest"), tracing.WithHTTPRequest(req), ) defer httpSpan.End() resp, err := client.Do(req) if err != nil { httpSpan.SetStatus(err) return nil, fmt.Errorf("failed to do request: %w", err) } httpSpan.SetAttributes(tracing.HTTPStatusCodeAttributes(resp.StatusCode)...) log.G(ctx).WithFields(responseFields(resp)).Debug("fetch response received") return resp, nil } func (r *request) doWithRetries(ctx context.Context, responses []*http.Response) (*http.Response, error) { resp, err := r.do(ctx) if err != nil { return nil, err } responses = append(responses, resp) retry, err := r.retryRequest(ctx, responses) if err != nil { resp.Body.Close() return nil, err } if retry { resp.Body.Close() return r.doWithRetries(ctx, responses) } return resp, err } func (r *request) retryRequest(ctx context.Context, responses []*http.Response) (bool, error) { if len(responses) > 5 { return false, nil } last := responses[len(responses)-1] switch last.StatusCode { case http.StatusUnauthorized: log.G(ctx).WithField("header", last.Header.Get("WWW-Authenticate")).Debug("Unauthorized") if r.host.Authorizer != nil { if err := r.host.Authorizer.AddResponses(ctx, responses); err == nil { return true, nil } else if !errdefs.IsNotImplemented(err) { return false, err } } return false, nil case http.StatusMethodNotAllowed: // Support registries which have not properly implemented the HEAD method for // manifests endpoint if r.method == http.MethodHead && strings.Contains(r.path, "/manifests/") { r.method = http.MethodGet return true, nil } case http.StatusRequestTimeout, http.StatusTooManyRequests: return true, nil } // TODO: Handle 50x errors accounting for attempt history return false, nil } func (r *request) String() string { return r.host.Scheme + "://" + r.host.Host + r.path } func requestFields(req *http.Request) log.Fields { fields := map[string]interface{}{ "request.method": req.Method, } for k, vals := range req.Header { k = strings.ToLower(k) if k == "authorization" { continue } for i, v := range vals { field := "request.header." + k if i > 0 { field = fmt.Sprintf("%s.%d", field, i) } fields[field] = v } } return log.Fields(fields) } func responseFields(resp *http.Response) log.Fields { fields := map[string]interface{}{ "response.status": resp.Status, } for k, vals := range resp.Header { k = strings.ToLower(k) for i, v := range vals { field := "response.header." + k if i > 0 { field = fmt.Sprintf("%s.%d", field, i) } fields[field] = v } } return log.Fields(fields) } // IsLocalhost checks if the registry host is local. func IsLocalhost(host string) bool { if h, _, err := net.SplitHostPort(host); err == nil { host = h } if host == "localhost" { return true } ip := net.ParseIP(host) return ip.IsLoopback() } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/resolver_test.go000066400000000000000000000555621453374237200255700ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "crypto/tls" "crypto/x509" "encoding/json" "errors" "fmt" "io" "net/http" "net/http/httptest" "strconv" "strings" "testing" "time" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes/docker/auth" digest "github.com/opencontainers/go-digest" specs "github.com/opencontainers/image-spec/specs-go" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) func TestHTTPResolver(t *testing.T) { s := func(h http.Handler) (string, ResolverOptions, func()) { s := httptest.NewServer(h) options := ResolverOptions{} base := s.URL[7:] // strip "http://" return base, options, s.Close } runBasicTest(t, "testname", s) } func TestHTTPSResolver(t *testing.T) { runBasicTest(t, "testname", tlsServer) } func TestBasicResolver(t *testing.T) { basicAuth := func(h http.Handler) (string, ResolverOptions, func()) { // Wrap with basic auth wrapped := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { username, password, ok := r.BasicAuth() if !ok || username != "user1" || password != "password1" { rw.Header().Set("WWW-Authenticate", "Basic realm=localhost") rw.WriteHeader(http.StatusUnauthorized) return } h.ServeHTTP(rw, r) }) base, options, close := tlsServer(wrapped) authorizer := NewDockerAuthorizer( WithAuthClient(options.Client), WithAuthCreds(func(host string) (string, string, error) { return "user1", "password1", nil }), ) options.Hosts = ConfigureDefaultRegistries( WithClient(options.Client), WithAuthorizer(authorizer), ) return base, options, close } runBasicTest(t, "testname", basicAuth) } func TestAnonymousTokenResolver(t *testing.T) { th := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { rw.WriteHeader(http.StatusMethodNotAllowed) return } rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(http.StatusOK) rw.Write([]byte(`{"access_token":"perfectlyvalidopaquetoken"}`)) }) runBasicTest(t, "testname", withTokenServer(th, nil)) } func TestBasicAuthTokenResolver(t *testing.T) { th := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { rw.WriteHeader(http.StatusMethodNotAllowed) return } rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(http.StatusOK) username, password, ok := r.BasicAuth() if !ok || username != "user1" || password != "password1" { rw.Write([]byte(`{"access_token":"insufficientscope"}`)) } else { rw.Write([]byte(`{"access_token":"perfectlyvalidopaquetoken"}`)) } }) creds := func(string) (string, string, error) { return "user1", "password1", nil } runBasicTest(t, "testname", withTokenServer(th, creds)) } func TestRefreshTokenResolver(t *testing.T) { th := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { rw.WriteHeader(http.StatusMethodNotAllowed) return } rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(http.StatusOK) r.ParseForm() if r.PostForm.Get("grant_type") != "refresh_token" || r.PostForm.Get("refresh_token") != "somerefreshtoken" { rw.Write([]byte(`{"access_token":"insufficientscope"}`)) } else { rw.Write([]byte(`{"access_token":"perfectlyvalidopaquetoken"}`)) } }) creds := func(string) (string, string, error) { return "", "somerefreshtoken", nil } runBasicTest(t, "testname", withTokenServer(th, creds)) } func TestFetchRefreshToken(t *testing.T) { f := func(t *testing.T, disablePOST bool) { name := "testname" if disablePOST { name += "-disable-post" } var fetchedRefreshToken string onFetchRefreshToken := func(ctx context.Context, refreshToken string, req *http.Request) { fetchedRefreshToken = refreshToken } srv := newRefreshTokenServer(t, name, disablePOST, onFetchRefreshToken) runBasicTest(t, name, srv.BasicTestFunc()) if fetchedRefreshToken != srv.RefreshToken { t.Errorf("unexpected refresh token: got %q", fetchedRefreshToken) } } t.Run("POST", func(t *testing.T) { f(t, false) }) t.Run("GET", func(t *testing.T) { f(t, true) }) } func TestPostBasicAuthTokenResolver(t *testing.T) { th := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { rw.WriteHeader(http.StatusMethodNotAllowed) return } rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(http.StatusOK) r.ParseForm() if r.PostForm.Get("grant_type") != "password" || r.PostForm.Get("username") != "user1" || r.PostForm.Get("password") != "password1" { rw.Write([]byte(`{"access_token":"insufficientscope"}`)) } else { rw.Write([]byte(`{"access_token":"perfectlyvalidopaquetoken"}`)) } }) creds := func(string) (string, string, error) { return "user1", "password1", nil } runBasicTest(t, "testname", withTokenServer(th, creds)) } func TestBadTokenResolver(t *testing.T) { th := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { rw.WriteHeader(http.StatusMethodNotAllowed) return } rw.Header().Set("Content-Type", "application/json") rw.WriteHeader(http.StatusOK) rw.Write([]byte(`{"access_token":"insufficientscope"}`)) }) creds := func(string) (string, string, error) { return "", "somerefreshtoken", nil } ctx := context.Background() h := newContent(ocispec.MediaTypeImageManifest, []byte("not anything parse-able")) base, ro, close := withTokenServer(th, creds)(logHandler{t, h}) defer close() resolver := NewResolver(ro) image := fmt.Sprintf("%s/doesntmatter:sometatg", base) _, _, err := resolver.Resolve(ctx, image) if err == nil { t.Fatal("Expected error getting token with inssufficient scope") } if !errors.Is(err, ErrInvalidAuthorization) { t.Fatal(err) } } func TestHostFailureFallbackResolver(t *testing.T) { sf := func(h http.Handler) (string, ResolverOptions, func()) { s := httptest.NewServer(h) base := s.URL[7:] // strip "http://" options := ResolverOptions{} createHost := func(host string) RegistryHost { return RegistryHost{ Client: &http.Client{ // Set the timeout so we timeout waiting for the non-responsive HTTP server Timeout: 500 * time.Millisecond, }, Host: host, Scheme: "http", Path: "/v2", Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush, } } // Create an unstarted HTTP server. We use this to generate a random port. notRunning := httptest.NewUnstartedServer(nil) notRunningBase := notRunning.Listener.Addr().String() // Override hosts with two hosts options.Hosts = func(host string) ([]RegistryHost, error) { return []RegistryHost{ createHost(notRunningBase), // This host IS running, but with a non-responsive HTTP server createHost(base), // This host IS running }, nil } return base, options, s.Close } runBasicTest(t, "testname", sf) } func TestHostTLSFailureFallbackResolver(t *testing.T) { sf := func(h http.Handler) (string, ResolverOptions, func()) { // Start up two servers server := httptest.NewServer(h) httpBase := server.URL[7:] // strip "http://" tlsServer := httptest.NewUnstartedServer(h) tlsServer.StartTLS() httpsBase := tlsServer.URL[8:] // strip "https://" capool := x509.NewCertPool() cert, _ := x509.ParseCertificate(tlsServer.TLS.Certificates[0].Certificate[0]) capool.AddCert(cert) client := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ RootCAs: capool, }, }, } options := ResolverOptions{} createHost := func(host string) RegistryHost { return RegistryHost{ Client: client, Host: host, Scheme: "https", Path: "/v2", Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush, } } // Override hosts with two hosts options.Hosts = func(host string) ([]RegistryHost, error) { return []RegistryHost{ createHost(httpBase), // This host is serving plain HTTP createHost(httpsBase), // This host is serving TLS }, nil } return httpBase, options, func() { server.Close() tlsServer.Close() } } runBasicTest(t, "testname", sf) } func TestResolveProxy(t *testing.T) { var ( ctx = context.Background() tag = "latest" r = http.NewServeMux() name = "testname" ns = "upstream.example.com" ) m := newManifest( newContent(ocispec.MediaTypeImageConfig, []byte("1")), newContent(ocispec.MediaTypeImageLayerGzip, []byte("2")), ) mc := newContent(ocispec.MediaTypeImageManifest, m.OCIManifest()) m.RegisterHandler(r, name) r.Handle(fmt.Sprintf("/v2/%s/manifests/%s", name, tag), mc) r.Handle(fmt.Sprintf("/v2/%s/manifests/%s", name, mc.Digest()), mc) nr := namespaceRouter{ "upstream.example.com": r, } base, ro, close := tlsServer(logHandler{t, nr}) defer close() ro.Hosts = func(host string) ([]RegistryHost, error) { return []RegistryHost{{ Client: ro.Client, Host: base, Scheme: "https", Path: "/v2", Capabilities: HostCapabilityPull | HostCapabilityResolve, }}, nil } resolver := NewResolver(ro) image := fmt.Sprintf("%s/%s:%s", ns, name, tag) _, d, err := resolver.Resolve(ctx, image) if err != nil { t.Fatal(err) } f, err := resolver.Fetcher(ctx, image) if err != nil { t.Fatal(err) } refs, err := testocimanifest(ctx, f, d) if err != nil { t.Fatal(err) } if len(refs) != 2 { t.Fatalf("Unexpected number of references: %d, expected 2", len(refs)) } for _, ref := range refs { if err := testFetch(ctx, f, ref); err != nil { t.Fatal(err) } } } func TestResolveProxyFallback(t *testing.T) { var ( ctx = context.Background() tag = "latest" r = http.NewServeMux() name = "testname" ) m := newManifest( newContent(ocispec.MediaTypeImageConfig, []byte("1")), newContent(ocispec.MediaTypeImageLayerGzip, []byte("2")), ) mc := newContent(ocispec.MediaTypeImageManifest, m.OCIManifest()) m.RegisterHandler(r, name) r.Handle(fmt.Sprintf("/v2/%s/manifests/%s", name, tag), mc) r.Handle(fmt.Sprintf("/v2/%s/manifests/%s", name, mc.Digest()), mc) nr := namespaceRouter{ "": r, } s := httptest.NewServer(logHandler{t, nr}) defer s.Close() base := s.URL[7:] // strip "http://" ro := ResolverOptions{ Hosts: func(host string) ([]RegistryHost, error) { return []RegistryHost{ { Host: flipLocalhost(host), Scheme: "http", Path: "/v2", Capabilities: HostCapabilityPull | HostCapabilityResolve, }, { Host: host, Scheme: "http", Path: "/v2", Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush, }, }, nil }, } resolver := NewResolver(ro) image := fmt.Sprintf("%s/%s:%s", base, name, tag) _, d, err := resolver.Resolve(ctx, image) if err != nil { t.Fatal(err) } f, err := resolver.Fetcher(ctx, image) if err != nil { t.Fatal(err) } refs, err := testocimanifest(ctx, f, d) if err != nil { t.Fatal(err) } if len(refs) != 2 { t.Fatalf("Unexpected number of references: %d, expected 2", len(refs)) } for _, ref := range refs { if err := testFetch(ctx, f, ref); err != nil { t.Fatal(err) } } } func flipLocalhost(host string) string { if strings.HasPrefix(host, "127.0.0.1") { return "localhost" + host[9:] } else if strings.HasPrefix(host, "localhost") { return "127.0.0.1" + host[9:] } return host } func withTokenServer(th http.Handler, creds func(string) (string, string, error)) func(h http.Handler) (string, ResolverOptions, func()) { return func(h http.Handler) (string, ResolverOptions, func()) { s := httptest.NewUnstartedServer(th) s.StartTLS() cert, _ := x509.ParseCertificate(s.TLS.Certificates[0].Certificate[0]) tokenBase := s.URL + "/token" // Wrap with token auth wrapped := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { auth := strings.ToLower(r.Header.Get("Authorization")) if auth != "bearer perfectlyvalidopaquetoken" { authHeader := fmt.Sprintf("Bearer realm=%q,service=registry,scope=\"repository:testname:pull,pull\"", tokenBase) if strings.HasPrefix(auth, "bearer ") { authHeader = authHeader + ",error=" + auth[7:] } rw.Header().Set("WWW-Authenticate", authHeader) rw.WriteHeader(http.StatusUnauthorized) return } h.ServeHTTP(rw, r) }) base, options, close := tlsServer(wrapped) options.Hosts = ConfigureDefaultRegistries( WithClient(options.Client), WithAuthorizer(NewDockerAuthorizer( WithAuthClient(options.Client), WithAuthCreds(creds), )), ) options.Client.Transport.(*http.Transport).TLSClientConfig.RootCAs.AddCert(cert) return base, options, func() { s.Close() close() } } } func tlsServer(h http.Handler) (string, ResolverOptions, func()) { s := httptest.NewUnstartedServer(h) s.StartTLS() capool := x509.NewCertPool() cert, _ := x509.ParseCertificate(s.TLS.Certificates[0].Certificate[0]) capool.AddCert(cert) client := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ RootCAs: capool, }, }, } options := ResolverOptions{ Hosts: ConfigureDefaultRegistries(WithClient(client)), // Set deprecated field for tests to use for configuration Client: client, } base := s.URL[8:] // strip "https://" return base, options, s.Close } type logHandler struct { t *testing.T handler http.Handler } func (h logHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) { h.handler.ServeHTTP(rw, r) } type namespaceRouter map[string]http.Handler func (nr namespaceRouter) ServeHTTP(rw http.ResponseWriter, r *http.Request) { h, ok := nr[r.URL.Query().Get("ns")] if !ok { rw.WriteHeader(http.StatusNotFound) return } h.ServeHTTP(rw, r) } func runBasicTest(t *testing.T, name string, sf func(h http.Handler) (string, ResolverOptions, func())) { var ( ctx = context.Background() tag = "latest" r = http.NewServeMux() ) m := newManifest( newContent(ocispec.MediaTypeImageConfig, []byte("1")), newContent(ocispec.MediaTypeImageLayerGzip, []byte("2")), ) mc := newContent(ocispec.MediaTypeImageManifest, m.OCIManifest()) m.RegisterHandler(r, name) r.Handle(fmt.Sprintf("/v2/%s/manifests/%s", name, tag), mc) r.Handle(fmt.Sprintf("/v2/%s/manifests/%s", name, mc.Digest()), mc) base, ro, close := sf(logHandler{t, r}) defer close() resolver := NewResolver(ro) image := fmt.Sprintf("%s/%s:%s", base, name, tag) _, d, err := resolver.Resolve(ctx, image) if err != nil { t.Fatal(err) } f, err := resolver.Fetcher(ctx, image) if err != nil { t.Fatal(err) } refs, err := testocimanifest(ctx, f, d) if err != nil { t.Fatal(err) } if len(refs) != 2 { t.Fatalf("Unexpected number of references: %d, expected 2", len(refs)) } for _, ref := range refs { if err := testFetch(ctx, f, ref); err != nil { t.Fatal(err) } } } func testFetch(ctx context.Context, f remotes.Fetcher, desc ocispec.Descriptor) error { r, err := f.Fetch(ctx, desc) if err != nil { return err } dgstr := desc.Digest.Algorithm().Digester() io.Copy(dgstr.Hash(), r) if dgstr.Digest() != desc.Digest { return fmt.Errorf("content mismatch: %s != %s", dgstr.Digest(), desc.Digest) } fByDigest, ok := f.(remotes.FetcherByDigest) if !ok { return fmt.Errorf("fetcher %T does not implement FetcherByDigest", f) } r2, desc2, err := fByDigest.FetchByDigest(ctx, desc.Digest) if err != nil { return fmt.Errorf("FetcherByDigest: faild to fetch %v: %w", desc.Digest, err) } if desc2.Size != desc.Size { r2b, err := io.ReadAll(r2) if err != nil { return fmt.Errorf("FetcherByDigest: size mismatch: %d != %d (content: %v)", desc2.Size, desc.Size, err) } return fmt.Errorf("FetcherByDigest: size mismatch: %d != %d (content: %q)", desc2.Size, desc.Size, string(r2b)) } dgstr2 := desc.Digest.Algorithm().Digester() if _, err = io.Copy(dgstr2.Hash(), r2); err != nil { return fmt.Errorf("FetcherByDigest: faild to copy: %w", err) } if dgstr2.Digest() != desc.Digest { return fmt.Errorf("FetcherByDigest: content mismatch: %s != %s", dgstr2.Digest(), desc.Digest) } return nil } func testocimanifest(ctx context.Context, f remotes.Fetcher, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { r, err := f.Fetch(ctx, desc) if err != nil { return nil, fmt.Errorf("failed to fetch %s: %w", desc.Digest, err) } p, err := io.ReadAll(r) if err != nil { return nil, err } if dgst := desc.Digest.Algorithm().FromBytes(p); dgst != desc.Digest { return nil, fmt.Errorf("digest mismatch: %s != %s", dgst, desc.Digest) } var manifest ocispec.Manifest if err := json.Unmarshal(p, &manifest); err != nil { return nil, err } var descs []ocispec.Descriptor descs = append(descs, manifest.Config) descs = append(descs, manifest.Layers...) return descs, nil } type testContent struct { mediaType string content []byte } func newContent(mediaType string, b []byte) testContent { return testContent{ mediaType: mediaType, content: b, } } func (tc testContent) Descriptor() ocispec.Descriptor { return ocispec.Descriptor{ MediaType: tc.mediaType, Digest: digest.FromBytes(tc.content), Size: int64(len(tc.content)), } } func (tc testContent) Digest() digest.Digest { return digest.FromBytes(tc.content) } func (tc testContent) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", tc.mediaType) w.Header().Add("Content-Length", strconv.Itoa(len(tc.content))) w.Header().Add("Docker-Content-Digest", tc.Digest().String()) w.WriteHeader(http.StatusOK) w.Write(tc.content) } type testManifest struct { config testContent references []testContent } func newManifest(config testContent, refs ...testContent) testManifest { return testManifest{ config: config, references: refs, } } func (m testManifest) OCIManifest() []byte { manifest := ocispec.Manifest{ Versioned: specs.Versioned{ SchemaVersion: 1, }, Config: m.config.Descriptor(), Layers: make([]ocispec.Descriptor, len(m.references)), } for i, c := range m.references { manifest.Layers[i] = c.Descriptor() } b, _ := json.Marshal(manifest) return b } func (m testManifest) RegisterHandler(r *http.ServeMux, name string) { for _, c := range append(m.references, m.config) { r.Handle(fmt.Sprintf("/v2/%s/blobs/%s", name, c.Digest()), c) } } func newRefreshTokenServer(t testing.TB, name string, disablePOST bool, onFetchRefreshToken OnFetchRefreshToken) *refreshTokenServer { return &refreshTokenServer{ T: t, Name: name, DisablePOST: disablePOST, OnFetchRefreshToken: onFetchRefreshToken, AccessToken: "testAccessToken-" + name, RefreshToken: "testRefreshToken-" + name, Username: "testUser-" + name, Password: "testPassword-" + name, } } type refreshTokenServer struct { T testing.TB Name string DisablePOST bool OnFetchRefreshToken OnFetchRefreshToken AccessToken string RefreshToken string Username string Password string } func (srv *refreshTokenServer) isValidAuthorizationHeader(s string) bool { fields := strings.Fields(s) return len(fields) == 2 && strings.ToLower(fields[0]) == "bearer" && (fields[1] == srv.RefreshToken || fields[1] == srv.AccessToken) } func (srv *refreshTokenServer) BasicTestFunc() func(h http.Handler) (string, ResolverOptions, func()) { t := srv.T return func(h http.Handler) (string, ResolverOptions, func()) { wrapped := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { if r.URL.Path != "/token" { if !srv.isValidAuthorizationHeader(r.Header.Get("Authorization")) { realm := fmt.Sprintf("https://%s/token", r.Host) wwwAuthenticateHeader := fmt.Sprintf("Bearer realm=%q,service=registry,scope=\"repository:%s:pull\"", realm, srv.Name) rw.Header().Set("WWW-Authenticate", wwwAuthenticateHeader) rw.WriteHeader(http.StatusUnauthorized) return } h.ServeHTTP(rw, r) return } switch r.Method { case http.MethodGet: // https://docs.docker.com/registry/spec/auth/token/#requesting-a-token u, p, ok := r.BasicAuth() if !ok || u != srv.Username || p != srv.Password { rw.WriteHeader(http.StatusForbidden) return } var resp auth.FetchTokenResponse resp.Token = srv.AccessToken resp.AccessToken = srv.AccessToken // alias of Token query := r.URL.Query() switch query.Get("offline_token") { case "true": resp.RefreshToken = srv.RefreshToken case "false", "": default: rw.WriteHeader(http.StatusBadRequest) return } b, err := json.Marshal(resp) if err != nil { rw.WriteHeader(http.StatusInternalServerError) return } rw.WriteHeader(http.StatusOK) rw.Header().Set("Content-Type", "application/json") t.Logf("GET mode: returning JSON %q, for query %+v", string(b), query) rw.Write(b) case http.MethodPost: // https://docs.docker.com/registry/spec/auth/oauth/#getting-a-token if srv.DisablePOST { rw.WriteHeader(http.StatusMethodNotAllowed) return } r.ParseForm() pf := r.PostForm if pf.Get("grant_type") != "password" { rw.WriteHeader(http.StatusBadRequest) return } if pf.Get("username") != srv.Username || pf.Get("password") != srv.Password { rw.WriteHeader(http.StatusForbidden) return } var resp auth.OAuthTokenResponse resp.AccessToken = srv.AccessToken switch pf.Get("access_type") { case "offline": resp.RefreshToken = srv.RefreshToken case "online", "": default: rw.WriteHeader(http.StatusBadRequest) return } b, err := json.Marshal(resp) if err != nil { rw.WriteHeader(http.StatusInternalServerError) return } rw.WriteHeader(http.StatusOK) rw.Header().Set("Content-Type", "application/json") t.Logf("POST mode: returning JSON %q, for form %+v", string(b), pf) rw.Write(b) default: rw.WriteHeader(http.StatusMethodNotAllowed) return } }) base, options, close := tlsServer(wrapped) authorizer := NewDockerAuthorizer( WithAuthClient(options.Client), WithAuthCreds(func(string) (string, string, error) { return srv.Username, srv.Password, nil }), WithFetchRefreshToken(srv.OnFetchRefreshToken), ) options.Hosts = ConfigureDefaultRegistries( WithClient(options.Client), WithAuthorizer(authorizer), ) return base, options, close } } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/schema1/000077500000000000000000000000001453374237200236455ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/schema1/converter.go000066400000000000000000000375271453374237200262210ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // Package schema1 provides a converter to fetch an image formatted in Docker Image Manifest v2, Schema 1. // // Deprecated: use images formatted in Docker Image Manifest v2, Schema 2, or OCI Image Spec v1. package schema1 import ( "bytes" "context" "encoding/base64" "encoding/json" "errors" "fmt" "io" "strconv" "strings" "sync" "time" "github.com/containerd/containerd/archive/compression" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/labels" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes" digest "github.com/opencontainers/go-digest" specs "github.com/opencontainers/image-spec/specs-go" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "golang.org/x/sync/errgroup" ) const ( manifestSizeLimit = 8e6 // 8MB labelDockerSchema1EmptyLayer = "containerd.io/docker.schema1.empty-layer" ) type blobState struct { diffID digest.Digest empty bool } // Converter converts schema1 manifests to schema2 on fetch type Converter struct { contentStore content.Store fetcher remotes.Fetcher pulledManifest *manifest mu sync.Mutex blobMap map[digest.Digest]blobState layerBlobs map[digest.Digest]ocispec.Descriptor } // NewConverter returns a new converter func NewConverter(contentStore content.Store, fetcher remotes.Fetcher) *Converter { return &Converter{ contentStore: contentStore, fetcher: fetcher, blobMap: map[digest.Digest]blobState{}, layerBlobs: map[digest.Digest]ocispec.Descriptor{}, } } // Handle fetching descriptors for a docker media type func (c *Converter) Handle(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { switch desc.MediaType { case images.MediaTypeDockerSchema1Manifest: if err := c.fetchManifest(ctx, desc); err != nil { return nil, err } m := c.pulledManifest if len(m.FSLayers) != len(m.History) { return nil, errors.New("invalid schema 1 manifest, history and layer mismatch") } descs := make([]ocispec.Descriptor, 0, len(c.pulledManifest.FSLayers)) for i := range m.FSLayers { if _, ok := c.blobMap[c.pulledManifest.FSLayers[i].BlobSum]; !ok { empty, err := isEmptyLayer([]byte(m.History[i].V1Compatibility)) if err != nil { return nil, err } // Do no attempt to download a known empty blob if !empty { descs = append([]ocispec.Descriptor{ { MediaType: images.MediaTypeDockerSchema2LayerGzip, Digest: c.pulledManifest.FSLayers[i].BlobSum, Size: -1, }, }, descs...) } c.blobMap[c.pulledManifest.FSLayers[i].BlobSum] = blobState{ empty: empty, } } } return descs, nil case images.MediaTypeDockerSchema2LayerGzip: if c.pulledManifest == nil { return nil, errors.New("manifest required for schema 1 blob pull") } return nil, c.fetchBlob(ctx, desc) default: return nil, fmt.Errorf("%v not support for schema 1 manifests", desc.MediaType) } } // ConvertOptions provides options on converting a docker schema1 manifest. type ConvertOptions struct { // ManifestMediaType specifies the media type of the manifest OCI descriptor. ManifestMediaType string // ConfigMediaType specifies the media type of the manifest config OCI // descriptor. ConfigMediaType string } // ConvertOpt allows configuring a convert operation. type ConvertOpt func(context.Context, *ConvertOptions) error // UseDockerSchema2 is used to indicate that a schema1 manifest should be // converted into the media types for a docker schema2 manifest. func UseDockerSchema2() ConvertOpt { return func(ctx context.Context, o *ConvertOptions) error { o.ManifestMediaType = images.MediaTypeDockerSchema2Manifest o.ConfigMediaType = images.MediaTypeDockerSchema2Config return nil } } // Convert a docker manifest to an OCI descriptor func (c *Converter) Convert(ctx context.Context, opts ...ConvertOpt) (ocispec.Descriptor, error) { co := ConvertOptions{ ManifestMediaType: ocispec.MediaTypeImageManifest, ConfigMediaType: ocispec.MediaTypeImageConfig, } for _, opt := range opts { if err := opt(ctx, &co); err != nil { return ocispec.Descriptor{}, err } } history, diffIDs, err := c.schema1ManifestHistory() if err != nil { return ocispec.Descriptor{}, fmt.Errorf("schema 1 conversion failed: %w", err) } var img ocispec.Image if err := json.Unmarshal([]byte(c.pulledManifest.History[0].V1Compatibility), &img); err != nil { return ocispec.Descriptor{}, fmt.Errorf("failed to unmarshal image from schema 1 history: %w", err) } img.History = history img.RootFS = ocispec.RootFS{ Type: "layers", DiffIDs: diffIDs, } b, err := json.MarshalIndent(img, "", " ") if err != nil { return ocispec.Descriptor{}, fmt.Errorf("failed to marshal image: %w", err) } config := ocispec.Descriptor{ MediaType: co.ConfigMediaType, Digest: digest.Canonical.FromBytes(b), Size: int64(len(b)), } layers := make([]ocispec.Descriptor, len(diffIDs)) for i, diffID := range diffIDs { layers[i] = c.layerBlobs[diffID] } manifest := ocispec.Manifest{ Versioned: specs.Versioned{ SchemaVersion: 2, }, Config: config, Layers: layers, } mb, err := json.MarshalIndent(manifest, "", " ") if err != nil { return ocispec.Descriptor{}, fmt.Errorf("failed to marshal image: %w", err) } desc := ocispec.Descriptor{ MediaType: co.ManifestMediaType, Digest: digest.Canonical.FromBytes(mb), Size: int64(len(mb)), } labels := map[string]string{} labels["containerd.io/gc.ref.content.0"] = manifest.Config.Digest.String() for i, ch := range manifest.Layers { labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i+1)] = ch.Digest.String() } ref := remotes.MakeRefKey(ctx, desc) if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(mb), desc, content.WithLabels(labels)); err != nil { return ocispec.Descriptor{}, fmt.Errorf("failed to write image manifest: %w", err) } ref = remotes.MakeRefKey(ctx, config) if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(b), config); err != nil { return ocispec.Descriptor{}, fmt.Errorf("failed to write image config: %w", err) } return desc, nil } // ReadStripSignature reads in a schema1 manifest and returns a byte array // with the "signatures" field stripped func ReadStripSignature(schema1Blob io.Reader) ([]byte, error) { b, err := io.ReadAll(io.LimitReader(schema1Blob, manifestSizeLimit)) // limit to 8MB if err != nil { return nil, err } return stripSignature(b) } func (c *Converter) fetchManifest(ctx context.Context, desc ocispec.Descriptor) error { log.G(ctx).Debug("fetch schema 1") rc, err := c.fetcher.Fetch(ctx, desc) if err != nil { return err } b, err := ReadStripSignature(rc) rc.Close() if err != nil { return err } var m manifest if err := json.Unmarshal(b, &m); err != nil { return err } if len(m.Manifests) != 0 || len(m.Layers) != 0 { return errors.New("converter: expected schema1 document but found extra keys") } c.pulledManifest = &m return nil } func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) error { log.G(ctx).Debug("fetch blob") var ( ref = remotes.MakeRefKey(ctx, desc) calc = newBlobStateCalculator() compressMethod = compression.Gzip ) // size may be unknown, set to zero for content ingest ingestDesc := desc if ingestDesc.Size == -1 { ingestDesc.Size = 0 } cw, err := content.OpenWriter(ctx, c.contentStore, content.WithRef(ref), content.WithDescriptor(ingestDesc)) if err != nil { if !errdefs.IsAlreadyExists(err) { return err } reuse, err := c.reuseLabelBlobState(ctx, desc) if err != nil { return err } if reuse { return nil } ra, err := c.contentStore.ReaderAt(ctx, desc) if err != nil { return err } defer ra.Close() r, err := compression.DecompressStream(content.NewReader(ra)) if err != nil { return err } compressMethod = r.GetCompression() _, err = io.Copy(calc, r) r.Close() if err != nil { return err } } else { defer cw.Close() rc, err := c.fetcher.Fetch(ctx, desc) if err != nil { return err } defer rc.Close() eg, _ := errgroup.WithContext(ctx) pr, pw := io.Pipe() eg.Go(func() error { r, err := compression.DecompressStream(pr) if err != nil { return err } compressMethod = r.GetCompression() _, err = io.Copy(calc, r) r.Close() pr.CloseWithError(err) return err }) eg.Go(func() error { defer pw.Close() return content.Copy(ctx, cw, io.TeeReader(rc, pw), ingestDesc.Size, ingestDesc.Digest) }) if err := eg.Wait(); err != nil { return err } } if desc.Size == -1 { info, err := c.contentStore.Info(ctx, desc.Digest) if err != nil { return fmt.Errorf("failed to get blob info: %w", err) } desc.Size = info.Size } if compressMethod == compression.Uncompressed { log.G(ctx).WithField("id", desc.Digest).Debugf("changed media type for uncompressed schema1 layer blob") desc.MediaType = images.MediaTypeDockerSchema2Layer } state := calc.State() cinfo := content.Info{ Digest: desc.Digest, Labels: map[string]string{ labels.LabelUncompressed: state.diffID.String(), labelDockerSchema1EmptyLayer: strconv.FormatBool(state.empty), }, } if _, err := c.contentStore.Update(ctx, cinfo, "labels."+labels.LabelUncompressed, fmt.Sprintf("labels.%s", labelDockerSchema1EmptyLayer)); err != nil { return fmt.Errorf("failed to update uncompressed label: %w", err) } c.mu.Lock() c.blobMap[desc.Digest] = state c.layerBlobs[state.diffID] = desc c.mu.Unlock() return nil } func (c *Converter) reuseLabelBlobState(ctx context.Context, desc ocispec.Descriptor) (bool, error) { cinfo, err := c.contentStore.Info(ctx, desc.Digest) if err != nil { return false, fmt.Errorf("failed to get blob info: %w", err) } desc.Size = cinfo.Size diffID, ok := cinfo.Labels[labels.LabelUncompressed] if !ok { return false, nil } emptyVal, ok := cinfo.Labels[labelDockerSchema1EmptyLayer] if !ok { return false, nil } isEmpty, err := strconv.ParseBool(emptyVal) if err != nil { log.G(ctx).WithField("id", desc.Digest).Warnf("failed to parse bool from label %s: %v", labelDockerSchema1EmptyLayer, isEmpty) return false, nil } bState := blobState{empty: isEmpty} if bState.diffID, err = digest.Parse(diffID); err != nil { log.G(ctx).WithField("id", desc.Digest).Warnf("failed to parse digest from label %s: %v", labels.LabelUncompressed, diffID) return false, nil } // NOTE: there is no need to read header to get compression method // because there are only two kinds of methods. if bState.diffID == desc.Digest { desc.MediaType = images.MediaTypeDockerSchema2Layer } else { desc.MediaType = images.MediaTypeDockerSchema2LayerGzip } c.mu.Lock() c.blobMap[desc.Digest] = bState c.layerBlobs[bState.diffID] = desc c.mu.Unlock() return true, nil } func (c *Converter) schema1ManifestHistory() ([]ocispec.History, []digest.Digest, error) { if c.pulledManifest == nil { return nil, nil, errors.New("missing schema 1 manifest for conversion") } m := *c.pulledManifest if len(m.History) == 0 { return nil, nil, errors.New("no history") } history := make([]ocispec.History, len(m.History)) diffIDs := []digest.Digest{} for i := range m.History { var h v1History if err := json.Unmarshal([]byte(m.History[i].V1Compatibility), &h); err != nil { return nil, nil, fmt.Errorf("failed to unmarshal history: %w", err) } blobSum := m.FSLayers[i].BlobSum state := c.blobMap[blobSum] history[len(history)-i-1] = ocispec.History{ Author: h.Author, Comment: h.Comment, Created: &h.Created, CreatedBy: strings.Join(h.ContainerConfig.Cmd, " "), EmptyLayer: state.empty, } if !state.empty { diffIDs = append([]digest.Digest{state.diffID}, diffIDs...) } } return history, diffIDs, nil } type fsLayer struct { BlobSum digest.Digest `json:"blobSum"` } type history struct { V1Compatibility string `json:"v1Compatibility"` } type manifest struct { FSLayers []fsLayer `json:"fsLayers"` History []history `json:"history"` Layers json.RawMessage `json:"layers,omitempty"` // OCI manifest Manifests json.RawMessage `json:"manifests,omitempty"` // OCI index } type v1History struct { Author string `json:"author,omitempty"` Created time.Time `json:"created"` Comment string `json:"comment,omitempty"` ThrowAway *bool `json:"throwaway,omitempty"` Size *int `json:"Size,omitempty"` // used before ThrowAway field ContainerConfig struct { Cmd []string `json:"Cmd,omitempty"` } `json:"container_config,omitempty"` } // isEmptyLayer returns whether the v1 compatibility history describes an // empty layer. A return value of true indicates the layer is empty, // however false does not indicate non-empty. func isEmptyLayer(compatHistory []byte) (bool, error) { var h v1History if err := json.Unmarshal(compatHistory, &h); err != nil { return false, err } if h.ThrowAway != nil { return *h.ThrowAway, nil } if h.Size != nil { return *h.Size == 0, nil } // If no `Size` or `throwaway` field is given, then // it cannot be determined whether the layer is empty // from the history, return false return false, nil } type signature struct { Signatures []jsParsedSignature `json:"signatures"` } type jsParsedSignature struct { Protected string `json:"protected"` } type protectedBlock struct { Length int `json:"formatLength"` Tail string `json:"formatTail"` } // joseBase64UrlDecode decodes the given string using the standard base64 url // decoder but first adds the appropriate number of trailing '=' characters in // accordance with the jose specification. // http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-2 func joseBase64UrlDecode(s string) ([]byte, error) { switch len(s) % 4 { case 0: case 2: s += "==" case 3: s += "=" default: return nil, errors.New("illegal base64url string") } return base64.URLEncoding.DecodeString(s) } func stripSignature(b []byte) ([]byte, error) { var sig signature if err := json.Unmarshal(b, &sig); err != nil { return nil, err } if len(sig.Signatures) == 0 { return nil, errors.New("no signatures") } pb, err := joseBase64UrlDecode(sig.Signatures[0].Protected) if err != nil { return nil, fmt.Errorf("could not decode %s: %w", sig.Signatures[0].Protected, err) } var protected protectedBlock if err := json.Unmarshal(pb, &protected); err != nil { return nil, err } if protected.Length > len(b) { return nil, errors.New("invalid protected length block") } tail, err := joseBase64UrlDecode(protected.Tail) if err != nil { return nil, fmt.Errorf("invalid tail base 64 value: %w", err) } return append(b[:protected.Length], tail...), nil } type blobStateCalculator struct { empty bool digester digest.Digester } func newBlobStateCalculator() *blobStateCalculator { return &blobStateCalculator{ empty: true, digester: digest.Canonical.Digester(), } } func (c *blobStateCalculator) Write(p []byte) (int, error) { if c.empty { for _, b := range p { if b != 0x00 { c.empty = false break } } } return c.digester.Hash().Write(p) } func (c *blobStateCalculator) State() blobState { return blobState{ empty: c.empty, diffID: c.digester.Digest(), } } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/scope.go000066400000000000000000000060151453374237200237660ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "fmt" "net/url" "sort" "strings" "github.com/containerd/containerd/reference" ) // RepositoryScope returns a repository scope string such as "repository:foo/bar:pull" // for "host/foo/bar:baz". // When push is true, both pull and push are added to the scope. func RepositoryScope(refspec reference.Spec, push bool) (string, error) { u, err := url.Parse("dummy://" + refspec.Locator) if err != nil { return "", err } s := "repository:" + strings.TrimPrefix(u.Path, "/") + ":pull" if push { s += ",push" } return s, nil } // tokenScopesKey is used for the key for context.WithValue(). // value: []string (e.g. {"registry:foo/bar:pull"}) type tokenScopesKey struct{} // ContextWithRepositoryScope returns a context with tokenScopesKey{} and the repository scope value. func ContextWithRepositoryScope(ctx context.Context, refspec reference.Spec, push bool) (context.Context, error) { s, err := RepositoryScope(refspec, push) if err != nil { return nil, err } return WithScope(ctx, s), nil } // WithScope appends a custom registry auth scope to the context. func WithScope(ctx context.Context, scope string) context.Context { var scopes []string if v := ctx.Value(tokenScopesKey{}); v != nil { scopes = v.([]string) scopes = append(scopes, scope) } else { scopes = []string{scope} } return context.WithValue(ctx, tokenScopesKey{}, scopes) } // ContextWithAppendPullRepositoryScope is used to append repository pull // scope into existing scopes indexed by the tokenScopesKey{}. func ContextWithAppendPullRepositoryScope(ctx context.Context, repo string) context.Context { return WithScope(ctx, fmt.Sprintf("repository:%s:pull", repo)) } // GetTokenScopes returns deduplicated and sorted scopes from ctx.Value(tokenScopesKey{}) and common scopes. func GetTokenScopes(ctx context.Context, common []string) []string { scopes := []string{} if x := ctx.Value(tokenScopesKey{}); x != nil { scopes = append(scopes, x.([]string)...) } scopes = append(scopes, common...) sort.Strings(scopes) if len(scopes) == 0 { return scopes } l := 0 for idx := 1; idx < len(scopes); idx++ { // Note: this comparison is unaware of the scope grammar (https://docs.docker.com/registry/spec/auth/scope/) // So, "repository:foo/bar:pull,push" != "repository:foo/bar:push,pull", although semantically they are equal. if scopes[l] == scopes[idx] { continue } l++ scopes[l] = scopes[idx] } return scopes[:l+1] } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/scope_test.go000066400000000000000000000057461453374237200250370ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "context" "testing" "github.com/containerd/containerd/reference" "github.com/stretchr/testify/assert" ) func TestRepositoryScope(t *testing.T) { testCases := []struct { refspec reference.Spec push bool expected string }{ { refspec: reference.Spec{ Locator: "host/foo/bar", Object: "ignored", }, push: false, expected: "repository:foo/bar:pull", }, { refspec: reference.Spec{ Locator: "host:4242/foo/bar", Object: "ignored", }, push: true, expected: "repository:foo/bar:pull,push", }, } for _, x := range testCases { t.Run(x.refspec.String(), func(t *testing.T) { actual, err := RepositoryScope(x.refspec, x.push) assert.NoError(t, err) assert.Equal(t, x.expected, actual) }) } } func TestGetTokenScopes(t *testing.T) { testCases := []struct { scopesInCtx []string commonScopes []string expected []string }{ { scopesInCtx: []string{}, commonScopes: []string{}, expected: []string{}, }, { scopesInCtx: []string{}, commonScopes: []string{"repository:foo/bar:pull"}, expected: []string{"repository:foo/bar:pull"}, }, { scopesInCtx: []string{"repository:foo/bar:pull,push"}, commonScopes: []string{}, expected: []string{"repository:foo/bar:pull,push"}, }, { scopesInCtx: []string{"repository:foo/bar:pull"}, commonScopes: []string{"repository:foo/bar:pull"}, expected: []string{"repository:foo/bar:pull"}, }, { scopesInCtx: []string{"repository:foo/bar:pull"}, commonScopes: []string{"repository:foo/bar:pull,push"}, expected: []string{"repository:foo/bar:pull", "repository:foo/bar:pull,push"}, }, { scopesInCtx: []string{"repository:foo/bar:pull"}, commonScopes: []string{"repository:foo/bar:pull,push", "repository:foo/bar:pull"}, expected: []string{"repository:foo/bar:pull", "repository:foo/bar:pull,push"}, }, } for _, tc := range testCases { ctx := context.WithValue(context.TODO(), tokenScopesKey{}, tc.scopesInCtx) actual := GetTokenScopes(ctx, tc.commonScopes) assert.Equal(t, tc.expected, actual) } } func TestCustomScope(t *testing.T) { scope := "whatever:foo/bar:pull" ctx := WithScope(context.Background(), scope) ctx = ContextWithAppendPullRepositoryScope(ctx, "foo/bar") scopes := GetTokenScopes(ctx, []string{}) assert.Equal(t, []string{"repository:foo/bar:pull", scope}, scopes) } nydus-snapshotter-0.13.4/pkg/remote/remotes/docker/status.go000066400000000000000000000041441453374237200242010ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package docker import ( "fmt" "sync" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/moby/locker" ) // Status of a content operation type Status struct { content.Status Committed bool // ErrClosed contains error encountered on close. ErrClosed error // UploadUUID is used by the Docker registry to reference blob uploads UploadUUID string } // StatusTracker to track status of operations type StatusTracker interface { GetStatus(string) (Status, error) SetStatus(string, Status) } // StatusTrackLocker to track status of operations with lock type StatusTrackLocker interface { StatusTracker Lock(string) Unlock(string) } type memoryStatusTracker struct { statuses map[string]Status m sync.Mutex locker *locker.Locker } // NewInMemoryTracker returns a StatusTracker that tracks content status in-memory func NewInMemoryTracker() StatusTrackLocker { return &memoryStatusTracker{ statuses: map[string]Status{}, locker: locker.New(), } } func (t *memoryStatusTracker) GetStatus(ref string) (Status, error) { t.m.Lock() defer t.m.Unlock() status, ok := t.statuses[ref] if !ok { return Status{}, fmt.Errorf("status for ref %v: %w", ref, errdefs.ErrNotFound) } return status, nil } func (t *memoryStatusTracker) SetStatus(ref string, status Status) { t.m.Lock() t.statuses[ref] = status t.m.Unlock() } func (t *memoryStatusTracker) Lock(ref string) { t.locker.Lock(ref) } func (t *memoryStatusTracker) Unlock(ref string) { t.locker.Unlock(ref) } nydus-snapshotter-0.13.4/pkg/remote/remotes/errors/000077500000000000000000000000001453374237200223715ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/remote/remotes/errors/errors.go000066400000000000000000000030701453374237200242340ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package errors import ( "fmt" "io" "net/http" ) var _ error = ErrUnexpectedStatus{} // ErrUnexpectedStatus is returned if a registry API request returned with unexpected HTTP status type ErrUnexpectedStatus struct { Status string StatusCode int Body []byte RequestURL, RequestMethod string } func (e ErrUnexpectedStatus) Error() string { return fmt.Sprintf("unexpected status from %s request to %s: %s", e.RequestMethod, e.RequestURL, e.Status) } // NewUnexpectedStatusErr creates an ErrUnexpectedStatus from HTTP response func NewUnexpectedStatusErr(resp *http.Response) error { var b []byte if resp.Body != nil { b, _ = io.ReadAll(io.LimitReader(resp.Body, 64000)) // 64KB } err := ErrUnexpectedStatus{ Body: b, Status: resp.Status, StatusCode: resp.StatusCode, RequestMethod: resp.Request.Method, } if resp.Request.URL != nil { err.RequestURL = resp.Request.URL.String() } return err } nydus-snapshotter-0.13.4/pkg/remote/remotes/handlers.go000066400000000000000000000274641453374237200232210ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package remotes import ( "bytes" "context" "errors" "fmt" "io" "strings" "sync" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/labels" "github.com/containerd/containerd/log" "github.com/containerd/containerd/platforms" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "golang.org/x/sync/semaphore" ) type refKeyPrefix struct{} // WithMediaTypeKeyPrefix adds a custom key prefix for a media type which is used when storing // data in the content store from the FetchHandler. // // Used in `MakeRefKey` to determine what the key prefix should be. func WithMediaTypeKeyPrefix(ctx context.Context, mediaType, prefix string) context.Context { var values map[string]string if v := ctx.Value(refKeyPrefix{}); v != nil { values = v.(map[string]string) } else { values = make(map[string]string) } values[mediaType] = prefix return context.WithValue(ctx, refKeyPrefix{}, values) } // MakeRefKey returns a unique reference for the descriptor. This reference can be // used to lookup ongoing processes related to the descriptor. This function // may look to the context to namespace the reference appropriately. func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string { key := desc.Digest.String() if desc.Annotations != nil { if name, ok := desc.Annotations[ocispec.AnnotationRefName]; ok { key = fmt.Sprintf("%s@%s", name, desc.Digest.String()) } } if v := ctx.Value(refKeyPrefix{}); v != nil { values := v.(map[string]string) if prefix := values[desc.MediaType]; prefix != "" { return prefix + "-" + key } } switch mt := desc.MediaType; { case mt == images.MediaTypeDockerSchema2Manifest || mt == ocispec.MediaTypeImageManifest: return "manifest-" + key case mt == images.MediaTypeDockerSchema2ManifestList || mt == ocispec.MediaTypeImageIndex: return "index-" + key case images.IsLayerType(mt): return "layer-" + key case images.IsKnownConfig(mt): return "config-" + key default: log.G(ctx).Warnf("reference for unknown type: %s", mt) return "unknown-" + key } } // FetchHandler returns a handler that will fetch all content into the ingester // discovered in a call to Dispatch. Use with ChildrenHandler to do a full // recursive fetch. func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc { return func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) { ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{ "digest": desc.Digest, "mediatype": desc.MediaType, "size": desc.Size, })) switch desc.MediaType { case images.MediaTypeDockerSchema1Manifest: return nil, fmt.Errorf("%v not supported", desc.MediaType) default: err := Fetch(ctx, ingester, fetcher, desc) if errdefs.IsAlreadyExists(err) { return nil, nil } return nil, err } } } // Fetch fetches the given digest into the provided ingester func Fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor) error { log.G(ctx).Debug("fetch") cw, err := content.OpenWriter(ctx, ingester, content.WithRef(MakeRefKey(ctx, desc)), content.WithDescriptor(desc)) if err != nil { return err } defer cw.Close() ws, err := cw.Status() if err != nil { return err } if desc.Size == 0 { // most likely a poorly configured registry/web front end which responded with no // Content-Length header; unable (not to mention useless) to commit a 0-length entry // into the content store. Error out here otherwise the error sent back is confusing return fmt.Errorf("unable to fetch descriptor (%s) which reports content size of zero: %w", desc.Digest, errdefs.ErrInvalidArgument) } if ws.Offset == desc.Size { // If writer is already complete, commit and return err := cw.Commit(ctx, desc.Size, desc.Digest) if err != nil && !errdefs.IsAlreadyExists(err) { return fmt.Errorf("failed commit on ref %q: %w", ws.Ref, err) } return err } if desc.Size == int64(len(desc.Data)) { return content.Copy(ctx, cw, bytes.NewReader(desc.Data), desc.Size, desc.Digest) } rc, err := fetcher.Fetch(ctx, desc) if err != nil { return err } defer rc.Close() return content.Copy(ctx, cw, rc, desc.Size, desc.Digest) } // PushHandler returns a handler that will push all content from the provider // using a writer from the pusher. func PushHandler(pusher Pusher, provider content.Provider) images.HandlerFunc { return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{ "digest": desc.Digest, "mediatype": desc.MediaType, "size": desc.Size, })) err := push(ctx, provider, pusher, desc) return nil, err } } func push(ctx context.Context, provider content.Provider, pusher Pusher, desc ocispec.Descriptor) error { log.G(ctx).Debug("push") var ( cw content.Writer err error ) if cs, ok := pusher.(content.Ingester); ok { cw, err = content.OpenWriter(ctx, cs, content.WithRef(MakeRefKey(ctx, desc)), content.WithDescriptor(desc)) } else { cw, err = pusher.Push(ctx, desc) } if err != nil { if !errdefs.IsAlreadyExists(err) { return err } return nil } defer cw.Close() ra, err := provider.ReaderAt(ctx, desc) if err != nil { return err } defer ra.Close() rd := io.NewSectionReader(ra, 0, desc.Size) return content.Copy(ctx, cw, rd, desc.Size, desc.Digest) } // PushContent pushes content specified by the descriptor from the provider. // // Base handlers can be provided which will be called before any push specific // handlers. // // If the passed in content.Provider is also a content.Manager then this will // also annotate the distribution sources in the manager. func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, store content.Provider, limiter *semaphore.Weighted, platform platforms.MatchComparer, wrapper func(h images.Handler) images.Handler) error { var m sync.Mutex manifests := []ocispec.Descriptor{} indexStack := []ocispec.Descriptor{} filterHandler := images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { switch desc.MediaType { case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: m.Lock() manifests = append(manifests, desc) m.Unlock() return nil, images.ErrStopHandler case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: m.Lock() indexStack = append(indexStack, desc) m.Unlock() return nil, images.ErrStopHandler default: return nil, nil } }) pushHandler := PushHandler(pusher, store) platformFilterhandler := images.FilterPlatforms(images.ChildrenHandler(store), platform) var handler images.Handler if m, ok := store.(content.Manager); ok { annotateHandler := annotateDistributionSourceHandler(platformFilterhandler, m) handler = images.Handlers(annotateHandler, filterHandler, pushHandler) } else { handler = images.Handlers(platformFilterhandler, filterHandler, pushHandler) } if wrapper != nil { handler = wrapper(handler) } if err := images.Dispatch(ctx, handler, limiter, desc); err != nil { return err } if err := images.Dispatch(ctx, pushHandler, limiter, manifests...); err != nil { return err } // Iterate in reverse order as seen, parent always uploaded after child for i := len(indexStack) - 1; i >= 0; i-- { err := images.Dispatch(ctx, pushHandler, limiter, indexStack[i]) if err != nil { // TODO(estesp): until we have a more complete method for index push, we need to report // missing dependencies in an index/manifest list by sensing the "400 Bad Request" // as a marker for this problem if errors.Unwrap(err) != nil && strings.Contains(errors.Unwrap(err).Error(), "400 Bad Request") { return fmt.Errorf("manifest list/index references to blobs and/or manifests are missing in your target registry: %w", err) } return err } } return nil } // SkipNonDistributableBlobs returns a handler that skips blobs that have a media type that is "non-distributeable". // An example of this kind of content would be a Windows base layer, which is not supposed to be redistributed. // // This is based on the media type of the content: // - application/vnd.oci.image.layer.nondistributable // - application/vnd.docker.image.rootfs.foreign func SkipNonDistributableBlobs(f images.HandlerFunc) images.HandlerFunc { return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { if images.IsNonDistributable(desc.MediaType) { log.G(ctx).WithField("digest", desc.Digest).WithField("mediatype", desc.MediaType).Debug("Skipping non-distributable blob") return nil, images.ErrSkipDesc } if images.IsLayerType(desc.MediaType) { return nil, nil } children, err := f(ctx, desc) if err != nil { return nil, err } if len(children) == 0 { return nil, nil } out := make([]ocispec.Descriptor, 0, len(children)) for _, child := range children { if !images.IsNonDistributable(child.MediaType) { out = append(out, child) } else { log.G(ctx).WithField("digest", child.Digest).WithField("mediatype", child.MediaType).Debug("Skipping non-distributable blob") } } return out, nil } } // FilterManifestByPlatformHandler allows Handler to handle non-target // platform's manifest and configuration data. func FilterManifestByPlatformHandler(f images.HandlerFunc, m platforms.Matcher) images.HandlerFunc { return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { children, err := f(ctx, desc) if err != nil { return nil, err } // no platform information if desc.Platform == nil || m == nil { return children, nil } var descs []ocispec.Descriptor switch desc.MediaType { case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: if m.Match(*desc.Platform) { descs = children } else { for _, child := range children { if child.MediaType == images.MediaTypeDockerSchema2Config || child.MediaType == ocispec.MediaTypeImageConfig { descs = append(descs, child) } } } default: descs = children } return descs, nil } } // annotateDistributionSourceHandler add distribution source label into // annotation of config or blob descriptor. func annotateDistributionSourceHandler(f images.HandlerFunc, manager content.Manager) images.HandlerFunc { return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { children, err := f(ctx, desc) if err != nil { return nil, err } // only add distribution source for the config or blob data descriptor switch desc.MediaType { case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest, images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: default: return children, nil } for i := range children { child := children[i] info, err := manager.Info(ctx, child.Digest) if err != nil { return nil, err } for k, v := range info.Labels { if !strings.HasPrefix(k, labels.LabelDistributionSource+".") { continue } if child.Annotations == nil { child.Annotations = map[string]string{} } child.Annotations[k] = v } children[i] = child } return children, nil } } nydus-snapshotter-0.13.4/pkg/remote/remotes/handlers_test.go000066400000000000000000000140431453374237200242450ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package remotes import ( "context" _ "crypto/sha256" "encoding/json" "sync" "testing" "github.com/containerd/containerd/content" "github.com/containerd/containerd/content/local" "github.com/containerd/containerd/images" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) func TestContextCustomKeyPrefix(t *testing.T) { ctx := context.Background() cmt := "testing/custom.media.type" ctx = WithMediaTypeKeyPrefix(ctx, images.MediaTypeDockerSchema2Layer, "bananas") ctx = WithMediaTypeKeyPrefix(ctx, cmt, "apples") // makes sure that even though we've supplied some custom handling, the built-in still works t.Run("normal supported case", func(t *testing.T) { desc := ocispec.Descriptor{MediaType: ocispec.MediaTypeImageLayer} expected := "layer-" actual := MakeRefKey(ctx, desc) if actual != expected { t.Fatalf("unexpected ref key, expected %s, got: %s", expected, actual) } }) t.Run("unknown media type", func(t *testing.T) { desc := ocispec.Descriptor{MediaType: "we.dont.know.what.this.is"} expected := "unknown-" actual := MakeRefKey(ctx, desc) if actual != expected { t.Fatalf("unexpected ref key, expected %s, got: %s", expected, actual) } }) t.Run("overwrite supported media type", func(t *testing.T) { desc := ocispec.Descriptor{MediaType: images.MediaTypeDockerSchema2Layer} expected := "bananas-" actual := MakeRefKey(ctx, desc) if actual != expected { t.Fatalf("unexpected ref key, expected %s, got: %s", expected, actual) } }) t.Run("custom media type", func(t *testing.T) { desc := ocispec.Descriptor{MediaType: cmt} expected := "apples-" actual := MakeRefKey(ctx, desc) if actual != expected { t.Fatalf("unexpected ref key, expected %s, got: %s", expected, actual) } }) } func TestSkipNonDistributableBlobs(t *testing.T) { ctx := context.Background() out, err := SkipNonDistributableBlobs(images.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { return []ocispec.Descriptor{ {MediaType: images.MediaTypeDockerSchema2Layer, Digest: "test:1"}, {MediaType: images.MediaTypeDockerSchema2LayerForeign, Digest: "test:2"}, {MediaType: images.MediaTypeDockerSchema2LayerForeignGzip, Digest: "test:3"}, {MediaType: ocispec.MediaTypeImageLayerNonDistributable, Digest: "test:4"}, {MediaType: ocispec.MediaTypeImageLayerNonDistributableGzip, Digest: "test:5"}, {MediaType: ocispec.MediaTypeImageLayerNonDistributableZstd, Digest: "test:6"}, }, nil }))(ctx, ocispec.Descriptor{MediaType: images.MediaTypeDockerSchema2Manifest}) if err != nil { t.Fatal(err) } if len(out) != 1 { t.Fatalf("unexpected number of descriptors returned: %d", len(out)) } if out[0].Digest != "test:1" { t.Fatalf("unexpected digest returned: %s", out[0].Digest) } dir := t.TempDir() cs, err := local.NewLabeledStore(dir, newMemoryLabelStore()) if err != nil { t.Fatal(err) } write := func(i interface{}, ref string) digest.Digest { t.Helper() data, err := json.Marshal(i) if err != nil { t.Fatal(err) } w, err := cs.Writer(ctx, content.WithRef(ref)) if err != nil { t.Fatal(err) } defer w.Close() dgst := digest.SHA256.FromBytes(data) n, err := w.Write(data) if err != nil { t.Fatal(err) } if err := w.Commit(ctx, int64(n), dgst); err != nil { t.Fatal(err) } return dgst } configDigest := write(ocispec.ImageConfig{}, "config") manifest := ocispec.Manifest{ Config: ocispec.Descriptor{Digest: configDigest, MediaType: ocispec.MediaTypeImageConfig}, MediaType: ocispec.MediaTypeImageManifest, Layers: []ocispec.Descriptor{ {MediaType: images.MediaTypeDockerSchema2Layer, Digest: "test:1"}, {MediaType: images.MediaTypeDockerSchema2LayerForeign, Digest: "test:2"}, {MediaType: images.MediaTypeDockerSchema2LayerForeignGzip, Digest: "test:3"}, {MediaType: ocispec.MediaTypeImageLayerNonDistributable, Digest: "test:4"}, {MediaType: ocispec.MediaTypeImageLayerNonDistributableGzip, Digest: "test:5"}, {MediaType: ocispec.MediaTypeImageLayerNonDistributableZstd, Digest: "test:6"}, }, } manifestDigest := write(manifest, "manifest") out, err = SkipNonDistributableBlobs(images.ChildrenHandler(cs))(ctx, ocispec.Descriptor{MediaType: manifest.MediaType, Digest: manifestDigest}) if err != nil { t.Fatal(err) } if len(out) != 2 { t.Fatalf("unexpected number of descriptors returned: %v", out) } if out[0].Digest != configDigest { t.Fatalf("unexpected digest returned: %v", out[0]) } if out[1].Digest != manifest.Layers[0].Digest { t.Fatalf("unexpected digest returned: %v", out[1]) } } type memoryLabelStore struct { l sync.Mutex labels map[digest.Digest]map[string]string } func newMemoryLabelStore() local.LabelStore { return &memoryLabelStore{ labels: map[digest.Digest]map[string]string{}, } } func (mls *memoryLabelStore) Get(d digest.Digest) (map[string]string, error) { mls.l.Lock() labels := mls.labels[d] mls.l.Unlock() return labels, nil } func (mls *memoryLabelStore) Set(d digest.Digest, labels map[string]string) error { mls.l.Lock() mls.labels[d] = labels mls.l.Unlock() return nil } func (mls *memoryLabelStore) Update(d digest.Digest, update map[string]string) (map[string]string, error) { mls.l.Lock() labels, ok := mls.labels[d] if !ok { labels = map[string]string{} } for k, v := range update { if v == "" { delete(labels, k) } else { labels[k] = v } } mls.labels[d] = labels mls.l.Unlock() return labels, nil } nydus-snapshotter-0.13.4/pkg/remote/remotes/resolver.go000066400000000000000000000072321453374237200232510ustar00rootroot00000000000000/* Copyright The containerd Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package remotes import ( "context" "io" "github.com/containerd/containerd/content" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) // Resolver provides remotes based on a locator. type Resolver interface { // Resolve attempts to resolve the reference into a name and descriptor. // // The argument `ref` should be a scheme-less URI representing the remote. // Structurally, it has a host and path. The "host" can be used to directly // reference a specific host or be matched against a specific handler. // // The returned name should be used to identify the referenced entity. // Depending on the remote namespace, this may be immutable or mutable. // While the name may differ from ref, it should itself be a valid ref. // // If the resolution fails, an error will be returned. Resolve(ctx context.Context, ref string) (name string, desc ocispec.Descriptor, err error) // Fetcher returns a new fetcher for the provided reference. // All content fetched from the returned fetcher will be // from the namespace referred to by ref. Fetcher(ctx context.Context, ref string) (Fetcher, error) // Pusher returns a new pusher for the provided reference // The returned Pusher should satisfy content.Ingester and concurrent attempts // to push the same blob using the Ingester API should result in ErrUnavailable. Pusher(ctx context.Context, ref string) (Pusher, error) } // Fetcher fetches content. // A fetcher implementation may implement the FetcherByDigest interface too. type Fetcher interface { // Fetch the resource identified by the descriptor. Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) } // FetcherByDigest fetches content by the digest. type FetcherByDigest interface { // FetchByDigest fetches the resource identified by the digest. // // FetcherByDigest usually returns an incomplete descriptor. // Typically, the media type is always set to "application/octet-stream", // and the annotations are unset. FetchByDigest(ctx context.Context, dgst digest.Digest) (io.ReadCloser, ocispec.Descriptor, error) } type ReferrersFetcher interface { FetchReferrers(ctx context.Context, dgst digest.Digest, artifactTypes ...string) (io.ReadCloser, ocispec.Descriptor, error) } // Pusher pushes content type Pusher interface { // Push returns a content writer for the given resource identified // by the descriptor. Push(ctx context.Context, d ocispec.Descriptor) (content.Writer, error) } // FetcherFunc allows package users to implement a Fetcher with just a // function. type FetcherFunc func(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) // Fetch content func (fn FetcherFunc) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) { return fn(ctx, desc) } // PusherFunc allows package users to implement a Pusher with just a // function. type PusherFunc func(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) // Push content func (fn PusherFunc) Push(ctx context.Context, desc ocispec.Descriptor) (content.Writer, error) { return fn(ctx, desc) } nydus-snapshotter-0.13.4/pkg/remote/unpack.go000066400000000000000000000016701453374237200212130ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package remote import ( "archive/tar" "fmt" "io" "os" "github.com/containerd/containerd/archive/compression" ) // Unpack unpacks the file named `source` in tar stream // and write into `target` path. func Unpack(reader io.Reader, source, target string) error { rdr, err := compression.DecompressStream(reader) if err != nil { return err } defer rdr.Close() found := false tr := tar.NewReader(rdr) for { hdr, err := tr.Next() if err != nil { if err == io.EOF { break } else { return err } } if hdr.Name == source { file, err := os.Create(target) if err != nil { return err } defer file.Close() if _, err := io.Copy(file, tr); err != nil { return err } found = true break } } if !found { return fmt.Errorf("not found file %s in tar", source) } return nil } nydus-snapshotter-0.13.4/pkg/resolve/000077500000000000000000000000001453374237200175635ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/resolve/resolver.go000066400000000000000000000037231453374237200217600ustar00rootroot00000000000000/* * Copyright (c) 2021. Alibaba Cloud. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package resolve import ( "fmt" "io" "net/http" "github.com/containerd/containerd/reference/docker" "github.com/containerd/nydus-snapshotter/pkg/auth" "github.com/containerd/nydus-snapshotter/pkg/utils/transport" "github.com/google/go-containerregistry/pkg/name" retryablehttp "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" ) type Resolver struct { res transport.Resolve } func NewResolver() *Resolver { resolver := Resolver{ res: transport.NewPool(), } return &resolver } func (r *Resolver) Resolve(ref, digest string, labels map[string]string) (io.ReadCloser, error) { named, err := docker.ParseDockerRef(ref) if err != nil { return nil, errors.Wrapf(err, "failed parse docker ref %s", ref) } host := docker.Domain(named) sref := fmt.Sprintf("%s/%s", host, docker.Path(named)) nref, err := name.ParseReference(sref) if err != nil { return nil, errors.Wrapf(err, "failed to parse ref %q (%q)", sref, digest) } keychain := auth.GetRegistryKeyChain(host, ref, labels) var tr http.RoundTripper url, tr, err := r.res.Resolve(nref, digest, keychain) if err != nil { return nil, errors.Wrapf(err, "failed to create authn transport %v", keychain) } req, err := retryablehttp.NewRequest("GET", url, nil) if err != nil { return nil, errors.Wrapf(err, "failed to new http get %s", url) } client := newRetryHTTPClient(tr) res, err := client.Do(req) if err != nil { return nil, errors.Wrapf(err, "failed to http get %s", url) } if res.StatusCode != http.StatusOK { return nil, fmt.Errorf("failed to GET request with code %d", res.StatusCode) } return res.Body, nil } func newRetryHTTPClient(tr http.RoundTripper) *retryablehttp.Client { retryClient := retryablehttp.NewClient() retryClient.HTTPClient.Transport = tr retryClient.Logger = nil return retryClient } nydus-snapshotter-0.13.4/pkg/signature/000077500000000000000000000000001453374237200201055ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/signature/signature.go000066400000000000000000000046771453374237200224530ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package signature import ( "encoding/base64" "fmt" "os" "github.com/pkg/errors" "github.com/containerd/nydus-snapshotter/pkg/label" "github.com/containerd/nydus-snapshotter/pkg/utils/signer" ) type Verifier struct { signer *signer.Signer force bool } func NewVerifier(publicKeyFile string, validateSignature bool) (*Verifier, error) { res := &Verifier{ force: validateSignature, } if !validateSignature { return res, nil } if publicKeyFile == "" { return nil, errors.New("publicKeyFile is required") } if _, err := os.Stat(publicKeyFile); err != nil { return nil, fmt.Errorf("failed to find publicKeyFile %q", publicKeyFile) } publicKeyByte, err := os.ReadFile(publicKeyFile) if err != nil { return nil, errors.Wrapf(err, "failed to read from publicKeyFile %q", publicKeyFile) } sign, err := signer.New(publicKeyByte) if err != nil { return nil, errors.Wrap(err, "failed to initialize signer") } res.signer = sign return res, nil } func (v *Verifier) Verify(label map[string]string, bootstrapFile string) error { signature, err := getFromLabel(label) if err != nil { return err } if signature == nil { if v.force { return errors.New("bootstrap signature is required when force validation") } return nil } if v.signer == nil { return nil } f, err := os.Open(bootstrapFile) if err != nil { return err } defer f.Close() return v.signer.Verify(f, signature) } func getFromLabel(labels map[string]string) ([]byte, error) { if s, ok := labels[label.NydusSignature]; ok { res, err := base64.StdEncoding.DecodeString(s) if err != nil { return nil, err } return res, nil } return nil, nil } // func Verify(label map[string]string, bootstrapFile, publicKey string, force bool) error { // signature, err := getFromLabel(label) // if err != nil { // return err // } // // if we found signature on image manifest, we should verify it // if signature == nil { // if force { // return errors.New("bootstrap signature is required when force validation") // } // return nil // } // // publicKeyByte, err := ioutil.ReadFile(publicKey) // if err != nil { // return err // } // sign, err := signer.New(publicKeyByte) // if err != nil { // return err // } // f, err := os.Open(bootstrapFile) // if err != nil { // return err // } // defer f.Close() // return sign.Verify(f, signature) // } nydus-snapshotter-0.13.4/pkg/snapshot/000077500000000000000000000000001453374237200177435ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/snapshot/storage.go000066400000000000000000000053731453374237200217460ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package snapshot import ( "context" "github.com/containerd/containerd/log" "github.com/containerd/containerd/snapshots" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/pkg/errors" ) type WalkFunc = func(id string, info snapshots.Info) bool func GetSnapshotInfo(ctx context.Context, ms *storage.MetaStore, key string) (string, snapshots.Info, snapshots.Usage, error) { ctx, t, err := ms.TransactionContext(ctx, false) if err != nil { return "", snapshots.Info{}, snapshots.Usage{}, err } defer func() { if err := t.Rollback(); err != nil { log.L.WithError(err).Errorf("Rollback traction %s", key) } }() id, info, usage, err := storage.GetInfo(ctx, key) if err != nil { return "", snapshots.Info{}, snapshots.Usage{}, err } return id, info, usage, nil } func GetSnapshot(ctx context.Context, ms *storage.MetaStore, key string) (*storage.Snapshot, error) { ctx, t, err := ms.TransactionContext(ctx, false) if err != nil { return nil, err } defer func() { if err := t.Rollback(); err != nil { log.L.WithError(err).Errorf("Rollback traction %s", key) } }() s, err := storage.GetSnapshot(ctx, key) if err != nil { return nil, errors.Wrap(err, "get snapshot") } return &s, nil } // Iterate all the parents of a snapshot specified by `key` // Stop the iteration once callback `fn` is invoked successfully and return current iterated snapshot func IterateParentSnapshots(ctx context.Context, ms *storage.MetaStore, key string, fn WalkFunc) (string, snapshots.Info, error) { ctx, t, err := ms.TransactionContext(ctx, false) if err != nil { return "", snapshots.Info{}, err } defer func() { if err := t.Rollback(); err != nil { log.L.WithError(err).Errorf("Rollback transaction %s", key) } }() for cKey := key; cKey != ""; { id, info, _, err := storage.GetInfo(ctx, cKey) if err != nil { log.L.WithError(err).Warnf("failed to get snapshot info of %q", cKey) return "", snapshots.Info{}, err } if fn(id, info) { return id, info, nil } cKey = info.Parent } return "", snapshots.Info{}, errdefs.ErrNotFound } func UpdateSnapshotInfo(ctx context.Context, ms *storage.MetaStore, info snapshots.Info, fieldPaths ...string) (snapshots.Info, error) { ctx, t, err := ms.TransactionContext(ctx, true) if err != nil { return snapshots.Info{}, err } info, err = storage.UpdateInfo(ctx, info, fieldPaths...) if err != nil { if rerr := t.Rollback(); rerr != nil { log.L.WithError(rerr).Errorf("update snapshot info") } return snapshots.Info{}, err } if err := t.Commit(); err != nil { return snapshots.Info{}, err } return info, nil } nydus-snapshotter-0.13.4/pkg/stargz/000077500000000000000000000000001453374237200174165ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/stargz/resolver.go000066400000000000000000000125171453374237200216140ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package stargz import ( "archive/tar" "bytes" "compress/gzip" "context" "fmt" "io" "net/http" "strconv" "strings" "time" "github.com/pkg/errors" "github.com/containerd/containerd/log" "github.com/containerd/containerd/reference/docker" "github.com/containerd/nydus-snapshotter/pkg/utils/transport" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" "github.com/containerd/stargz-snapshotter/estargz" ) const httpTimeout = 15 * time.Second const ( FooterSize = 47 TocFileName = "stargz.index.json" ) type Resolver struct { res transport.Resolve } func NewResolver() *Resolver { resolver := Resolver{ res: transport.NewPool(), } return &resolver } type Blob struct { ref string digest string sr *io.SectionReader } // getTocOffset get toc offset from stargz footer func (bb *Blob) GetTocOffset() (int64, error) { tocOffset, _, err := estargz.OpenFooter(bb.sr) if err != nil { return 0, errors.Wrap(err, "open stargz blob footer") } return tocOffset, nil } // ReadToc read stargz toc content from blob func (bb *Blob) ReadToc() (io.Reader, error) { start := time.Now() defer func() { duration := time.Since(start) log.L.Infof("read toc duration %d", duration.Milliseconds()) }() tocOffset, err := bb.GetTocOffset() if err != nil { return nil, err } tocBuf := make([]byte, bb.sr.Size()-tocOffset-FooterSize) _, err = bb.sr.ReadAt(tocBuf, tocOffset) if err != nil { return nil, err } zr, err := gzip.NewReader(bytes.NewReader(tocBuf)) if err != nil { return nil, err } zr.Multistream(false) tr := tar.NewReader(zr) h, err := tr.Next() if err != nil { return nil, err } if h.Name != TocFileName { return nil, fmt.Errorf("Failed to find toc from image %s blob %s", bb.ref, bb.digest) } var buf bytes.Buffer _, err = buf.ReadFrom(tr) if err != nil { return nil, err } return &buf, nil } func (bb *Blob) GetDigest() string { return bb.digest } func (bb *Blob) GetImageReference() string { return bb.ref } func (r *Resolver) GetBlob(ref, digest string, keychain authn.Keychain) (*Blob, error) { start := time.Now() defer func() { duration := time.Since(start) log.L.Infof("get blob duration %d", duration.Milliseconds()) }() sr, err := r.resolve(ref, digest, keychain) if err != nil { return nil, err } return &Blob{ ref: ref, digest: digest, sr: sr, }, nil } type readerAtFunc func([]byte, int64) (int, error) func (f readerAtFunc) ReadAt(p []byte, offset int64) (int, error) { return f(p, offset) } // parseFooter extract toc offset from footer func parseFooter(p []byte) (tocOffset int64, ok bool) { if len(p) != 47 { return 0, false } zr, err := gzip.NewReader(bytes.NewReader(p)) if err != nil { return 0, false } extra := zr.Header.Extra if len(extra) != 16+len("STARGZ") { return 0, false } if string(extra[16:]) != "STARGZ" { return 0, false } tocOffset, err = strconv.ParseInt(string(extra[:16]), 16, 64) return tocOffset, err == nil } func (r *Resolver) resolve(ref, digest string, keychain authn.Keychain) (*io.SectionReader, error) { named, err := docker.ParseDockerRef(ref) if err != nil { return nil, err } host := docker.Domain(named) sref := fmt.Sprintf("%s/%s", host, docker.Path(named)) nref, err := name.ParseReference(sref) if err != nil { return nil, errors.Wrapf(err, "failed to parse ref %q (%q)", sref, digest) } url, tr, err := r.res.Resolve(nref, digest, keychain) if err != nil { return nil, errors.Wrapf(err, "failed to resolve reference of %q, %q", nref, digest) } size, err := getSize(url, tr) if err != nil { return nil, errors.Wrapf(err, "failed to get size from url %s", url) } log.L.Infof("get size %d", size) sr := io.NewSectionReader(readerAtFunc(func(b []byte, offset int64) (int, error) { length := len(b) ctx, cancel := context.WithTimeout(context.Background(), httpTimeout) defer cancel() req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { return 0, err } req.Close = false r := fmt.Sprintf("bytes=%d-%d", offset, offset+int64(length)-1) req.Header.Set("Range", r) res, err := tr.RoundTrip(req) if err != nil { return 0, err } defer func() { if _, err := io.Copy(io.Discard, res.Body); err != nil { log.L.Errorf("failed to copy %s", err) } res.Body.Close() }() if res.StatusCode/100 != 2 { return 0, fmt.Errorf("failed to HEAD request with code %d", res.StatusCode) } return io.ReadFull(res.Body, b) }), 0, size) return sr, nil } func getSize(url string, tr http.RoundTripper) (int64, error) { ctx, cancel := context.WithTimeout(context.Background(), httpTimeout) defer cancel() req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { return 0, err } req.Close = false req.Header.Set("Range", "bytes=0-0") res, err := tr.RoundTrip(req) if err != nil { return 0, err } defer func() { if _, err := io.Copy(io.Discard, res.Body); err != nil { log.L.Errorf("failed to copy %s", err) } res.Body.Close() }() if res.StatusCode/100 != 2 { return 0, fmt.Errorf("failed to HEAD request with code %d", res.StatusCode) } contentRange := res.Header.Get("Content-Range") totalSize := strings.Split(contentRange, "/")[1] return strconv.ParseInt(totalSize, 10, 64) } nydus-snapshotter-0.13.4/pkg/stargz/resolver_test.go000066400000000000000000000060431453374237200226500ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package stargz import ( "archive/tar" "bytes" "compress/gzip" "fmt" "io" "net/http" "os" "testing" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/containerd/nydus-snapshotter/pkg/auth" ) func TestResolver_resolve(t *testing.T) { resolver := Resolver{ res: &MockResolver{}, } keychain, err := auth.FromBase64("dGVzdDp0ZXN0Cg==") require.Nil(t, err) sr, err := resolver.resolve("example.com/test/myserver:latest-stargz", "sha256:mock", keychain) require.Nil(t, err) size := sr.Size() var b [47]byte n, err := sr.ReadAt(b[:], size-47) assert.Nil(t, err) assert.Equal(t, 47, n) tocOffset, ok := parseFooter(b[:]) assert.True(t, ok) fmt.Printf("tocoffset %d", tocOffset) tocTargz := make([]byte, size-tocOffset-47) _, err = sr.ReadAt(tocTargz, tocOffset) assert.Nil(t, err) zr, err := gzip.NewReader(bytes.NewReader(tocTargz)) assert.Nil(t, err) zr.Multistream(false) tr := tar.NewReader(zr) h, err := tr.Next() assert.Nil(t, err) assert.Equal(t, "stargz.index.json", h.Name) } type MockResolver struct { } func (res *MockResolver) Resolve(ref name.Reference, digest string, keychain authn.Keychain) (string, http.RoundTripper, error) { return "http://oss.com/v2/test/myserver/blobs/sha256:mock", &mockRoundTripper{}, nil } type mockRoundTripper struct{} func (tr *mockRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { url := req.URL.String() if url == "https://example.com/v2/" { return &http.Response{ StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte{})), }, nil } if url == "https://example.com/v2/test/myserver/blobs/sha256:mock" { header := make(http.Header) header.Add("Location", "http://oss.com/v2/test/myserver/blobs/sha256:mock") return &http.Response{ StatusCode: http.StatusMovedPermanently, Header: header, Body: io.NopCloser(bytes.NewReader([]byte{})), }, nil } if url == "http://oss.com/v2/test/myserver/blobs/sha256:mock" { rangeHeader := req.Header.Get("Range") // get length if rangeHeader == "bytes=0-0" { header := make(http.Header) header.Add("Content-Range", "bytes 0-0/24613186") return &http.Response{ StatusCode: http.StatusPartialContent, Header: header, Body: io.NopCloser(bytes.NewReader([]byte{})), }, nil } // get footer if rangeHeader == "bytes=24613139-24613185" { footer, _ := os.ReadFile("testdata/stargzfooter.bin") return &http.Response{ StatusCode: http.StatusPartialContent, Body: io.NopCloser(bytes.NewReader(footer)), }, nil } if rangeHeader == "bytes=24442675-24613138" { toc, _ := os.ReadFile("testdata/stargztoc.bin") return &http.Response{ StatusCode: http.StatusPartialContent, Body: io.NopCloser(bytes.NewReader(toc)), }, nil } } return &http.Response{ StatusCode: 200, }, nil } nydus-snapshotter-0.13.4/pkg/stargz/testdata/000077500000000000000000000000001453374237200212275ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/stargz/testdata/config/000077500000000000000000000000001453374237200224745ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/stargz/testdata/config/nydus.json000066400000000000000000000007441453374237200245360ustar00rootroot00000000000000{ "device": { "backend": { "type": "registry", "config": { "auth": "", "timeout": 5, "connect_timeout": 5, "retry_limit": 0 } }, "cache": { "type": "blobcache", "config": { "work_dir": "" } } }, "mode": "direct", "digest_validate": true, "iostats_files": true, "enable_xattr": true, "fs_prefetch": { "enable": true, "threads_count": 10, "merging_size": 131072 } } nydus-snapshotter-0.13.4/pkg/stargz/testdata/db/000077500000000000000000000000001453374237200216145ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/stargz/testdata/db/nydus.db000066400000000000000000002000001453374237200232550ustar00rootroot00000000000000  JQa  @|XFo`!d% FeIux4POSpKqogd_8pi-tg{"ID":"FeIux4POSpKqogd_8pi-tg","SnapshotID":"1","ConfigDir":"testdata/snapshot/config/FeIux4POSpKqogd_8pi-tg","SocketDir":"testdata/snapshot/socket/FeIux4POSpKqogd_8pi-tg","LogDir":"FeIux4POSpKqogd_8pi-tg","LogLevel":"info","LogToStdout":false,"SnapshotDir":"testdata/snapshot/snapshots","Pid":0,"ImageID":"example.com/test/testimage:0.1","DaemonMode":"multiple","DaemonBackend":"","APISock":null,"RootMountPoint":null,"CustomMountPoint":null}L548T0o2Ttmm9lpDyzopRQ{"ID":"L548T0o2Ttmm9lpDyzopRQ","SnapshotID":"1","ConfigDir":"testdata/snapshot/config/L548T0o2Ttmm9lpDyzopRQ","SocketDir":"testdata/snapshot/socket/L548T0o2Ttmm9lpDyzopRQ","LogDir":"L548T0o2Ttmm9lpDyzopRQ","LogLevel":"info","LogToStdout":false,"SnapshotDir":"testdata/snapshot/snapshots","Pid":0,"ImageID":"example.com/test/testimage:0.1","DaemonMode":"multiple","DaemonBackend":"","APISock":null,"RootMountPoint":null,"CustomMountPoint":null}P0jlo0pZTYizd5dWJ38opw{"ID":"P0jlo0pZTYizd5dWJ38opw","SnapshotID":"1","ConfigDir":"testdata/snapshot/config/P0jlo0pZTYizd5dWJ38opw","SocketDir":"testdata/snapshot/socket/P0jlo0pZTYizd5dWJ38opw","LogDir":"P0jlo0pZTYizd5dWJ38opw","LogLevel":"info","LogToStdout":false,"SnapshotDir":"testdata/snapshot/snapshots","Pid":0,"ImageID":"example.com/test/testimage:0.1","DaemonMode":"multiple","DaemonBackend":"","APISock":null,"RootMountPoint":null,"CustomMountPoint":null}PIgD94RcTf2OAyUQ_NmB6Q{"ID":"PIgD94RcTf2OAyUQ_NmB6Q","SnapshotID":"1","ConfigDir":"testdata/snapshot/config/PIgD94RcTf2OAyUQ_NmB6Q","SocketDir":"testdata/snapshot/socket/PIgD94RcTf2OAyUQ_NmB6Q","LogDir":"PIgD94RcTf2OAyUQ_NmB6Q","LogLevel":"info","LogToStdout":false,"SnapshotDir":"testdata/snapshot/snapshots","Pid":0,"ImageID":"example.com/test/testimage:0.1","DaemonMode":"multiple","DaemonBackend":"","APISock":null,"RootMountPoint":null,"CustomMountPoint":null}js6InhB2RkSSqB4aoVZW4A{"ID":"js6InhB2RkSSqB4aoVZW4A","SnapshotID":"1","ConfigDir":"testdata/snapshot/config/js6InhB2RkSSqB4aoVZW4A","SocketDir":"testdata/snapshot/socket/js6InhB2RkSSqB4aoVZW4A","LogDir":"js6InhB2RkSSqB4aoVZW4A","LogLevel":"info","LogToStdout":false,"SnapshotDir":"testdata/snapshot/snapshots","Pid":0,"ImageID":"example.com/test/testimage:0.1","DaemonMode":"multiple","DaemonBackend":"","APISock":null,"RootMountPoint":null,"CustomMountPoint":null}v3m6VistRYmoe1BSjRkMFQ{"ID":"v3m6VistRYmoe1BSjRkMFQ","SnapshotID":"1","ConfigDir":"testdata/snapshot/config/v3m6VistRYmoe1BSjRkMFQ","SocketDir":"testdata/snapshot/socket/v3m6VistRYmoe1BSjRkMFQ","LogDir":"v3m6VistRYmoe1BSjRkMFQ","LogLevel":"info","LogToStdout":false,"SnapshotDir":"testdata/snapshot/snapshots","Pid":0,"ImageID":"example.com/test/testimage:0.1","DaemonMode":"multiple","DaemonBackend":"","APISock":null,"RootMountPoint":null,"CustomMountPoint":null}  5 blobssnapshotsPTFeIux4POSpKqogd_8pi-tg{"ID":"FeIux4POSpKqogd_8pi-tg","SnapshotID":"1","ConfigDir":"testdata/snapshot/config/FeIux4POSpKqogd_8pi-tg","SocketDir":"testdata/snapshot/socket/FeIux4POSpKqogd_8pi-tg","LogDir":"FeIux4POSpKqogd_8pi-tg","LogLevel":"info","LogToStdout":false,"SnapshotDir":"testdata/snapshot/snapshots","Pid":0,"ImageID":"example.com/test/testimage:0.1","DaemonMode":"multiple","DaemonBackend":"","APISock":null,"RootMountPoint":null,"CustomMountPoint":null}L548T0o2Ttmm9lpDyzopRQ{"ID":"L548T0o2Ttmm9lpDyzopRQ","SnapshotID":"1","ConfigDir":"testdata/snapshot/config/L548T0o2Ttmm9lpDyzopRQ","SocketDir":"testdata/snapshot/socket/L548T0o2Ttmm9lpDyzopRQ","LogDir":"L548T0o2Ttmm9lpDyzopRQ","LogLevel":"info","LogToStdout":false,"SnapshotDir":"testdata/snapshot/snapshots","Pid":0,"ImageID":"example.com/test/testimage:0.1","DaemonMode":"multiple","DaemonBackend":"","APISock":null,"RootMountPoint":null,"CustomMountPoint":null}P0jlo0pZTYizd5dWJ38opw{"ID":"P0jlo0pZTYizd5dWJ38opw","SnapshotID":"1","ConfigDir":"testdata/snapshot/config/P0jlo0pZTYizd5dWJ38opw","SocketDir":"testdata/snapshot/socket/P0jlo0pZTYizd5dWJ38opw","LogDir":"P0jlo0pZTYizd5dWJ38opw","LogLevel":"info","LogToStdout":false,"SnapshotDir":"testdata/snapshot/snapshots","Pid":0,"ImageID":"example.com/test/testimage:0.1","DaemonMode":"multiple","DaemonBackend":"","APISock":null,"RootMountPoint":null,"CustomMountPoint":null}PIgD94RcTf2OAyUQ_NmB6Q{"ID":"PIgD94RcTf2OAyUQ_NmB6Q","SnapshotID":"1","ConfigDir":"testdata/snapshot/config/PIgD94RcTf2OAyUQ_NmB6Q","SocketDir":"testdata/snapshot/socket/PIgD94RcTf2OAyUQ_NmB6Q","LogDir":"PIgD94RcTf2OAyUQ_NmB6Q","LogLevel":"info","LogToStdout":false,"SnapshotDir":"testdata/snapshot/snapshots","Pid":0,"ImageID":"example.com/test/testimage:0.1","DaemonMode":"multiple","DaemonBackend":"","APISock":null,"RootMountPoint":null,"CustomMountPoint":null}v3m6VistRYmoe1BSjRkMFQ{"ID":"v3m6VistRYmoe1BSjRkMFQ","SnapshotID":"1","ConfigDir":"testdata/snapshot/config/v3m6VistRYmoe1BSjRkMFQ","SocketDir":"testdata/snapshot/socket/v3m6VistRYmoe1BSjRkMFQ","LogDir":"v3m6VistRYmoe1BSjRkMFQ","LogLevel":"info","LogToStdout":false,"SnapshotDir":"testdata/snapshot/snapshots","Pid":0,"ImageID":"example.com/test/testimage:0.1","DaemonMode":"multiple","DaemonBackend":"","APISock":null,"RootMountPoint":null,"CustomMountPoint":null} &cachesdaemons &cachesdaemonsnydus-snapshotter-0.13.4/pkg/stargz/testdata/stargz.index.json000066400000000000000000041554571453374237200245670ustar00rootroot00000000000000{ "version": 1, "entries": [ { "name": "bin/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "bin/bash", "type": "reg", "size": 1099016, "modtime": "2017-05-15T19:45:32Z", "mode": 33261, "offset": 123, "NumLink": 0, "digest": "sha256:3f0bc167fa8ef1f7a38452a5fd16d077ed8ef657bb81cdce5af9537ca96e8345" }, { "name": "bin/cat", "type": "reg", "size": 35688, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 557313, "NumLink": 0, "digest": "sha256:f1e77796eaa4f465ff57128d4a66b3aaebc1c1c9812a015bc2726da949886f6c" }, { "name": "bin/chgrp", "type": "reg", "size": 64424, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 574029, "NumLink": 0, "digest": "sha256:48774490af3d77e3e7a03f1b0dc06676db9b06866422847d49423297a19a96fe" }, { "name": "bin/chmod", "type": "reg", "size": 60296, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 604734, "NumLink": 0, "digest": "sha256:a514b561e2007d38c8ea158ff62243db30dae741a95fc1da35165ce55b58bcad" }, { "name": "bin/chown", "type": "reg", "size": 64456, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 634251, "NumLink": 0, "digest": "sha256:066d6564f9a97370e347d2b792e2d6d4c8e2705ff2ce8b437a0c402202cd4908" }, { "name": "bin/cp", "type": "reg", "size": 130504, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 666106, "NumLink": 0, "digest": "sha256:e0ba82626269bd1f2d71761ef299508f6a85954721c921f07992ec5563e1f437" }, { "name": "bin/dash", "type": "reg", "size": 117208, "modtime": "2017-01-24T05:16:56Z", "mode": 33261, "offset": 729890, "NumLink": 0, "digest": "sha256:e803088e7938b328b0511957dcd0dd7b5600ec1940010c64dbd3814e3d75495f" }, { "name": "bin/date", "type": "reg", "size": 105448, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 788656, "NumLink": 0, "digest": "sha256:f4c8f40e23e7825a2d6c018adb06de6be4172a252f6ac0241abef92b1b5b192f" }, { "name": "bin/dd", "type": "reg", "size": 76816, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 839666, "NumLink": 0, "digest": "sha256:71dcc2044f22e9575881502576f648c8fccb1327126d067a7db0a3d83fa04ac3" }, { "name": "bin/df", "type": "reg", "size": 85688, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 876584, "NumLink": 0, "digest": "sha256:5c2810e81a1dda76573e378e3468a54594c0322a1def87951d090b084a18918d" }, { "name": "bin/dir", "type": "reg", "size": 130736, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 919547, "NumLink": 0, "digest": "sha256:a42642d5bad1f3a79817513a06646b98b129de7d1df64ef7a6a1aea5e917cc44" }, { "name": "bin/dmesg", "type": "reg", "size": 73032, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 981644, "NumLink": 0, "digest": "sha256:fc00594e32cc8c667f3695ff1db64ac7cc7c6ecdc9e007389b3e8ee2050cb7e8" }, { "name": "bin/dnsdomainname", "type": "symlink", "modtime": "2016-07-03T19:26:17Z", "linkName": "hostname", "mode": 41471, "NumLink": 0 }, { "name": "bin/domainname", "type": "symlink", "modtime": "2016-07-03T19:26:17Z", "linkName": "hostname", "mode": 41471, "NumLink": 0 }, { "name": "bin/echo", "type": "reg", "size": 31464, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1010882, "NumLink": 0, "digest": "sha256:615183f74a4f135160e2323720678396454266d17647874816f2843714bad102" }, { "name": "bin/egrep", "type": "reg", "size": 28, "modtime": "2017-01-23T18:18:59Z", "mode": 33261, "offset": 1025997, "NumLink": 0, "digest": "sha256:f7c621ae0ceb26a76802743830bc469288996f64342901ae5292950ff713e981" }, { "name": "bin/false", "type": "reg", "size": 31464, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1026120, "NumLink": 0, "digest": "sha256:127ae383b59b92a437692c9dd0095800bb40347b8a8488358c595c76d85e29ac" }, { "name": "bin/fgrep", "type": "reg", "size": 28, "modtime": "2017-01-23T18:18:59Z", "mode": 33261, "offset": 1039843, "NumLink": 0, "digest": "sha256:5c8b1486de899cdd010d3cacde94579999cb82d0be9ec8c131b1b56886cfd36b" }, { "name": "bin/findmnt", "type": "reg", "size": 62072, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 1039969, "NumLink": 0, "digest": "sha256:ecbf8f39f78385c8dfb35b5495471aa4144ab3c3169e89465419d3c5ba5aae27" }, { "name": "bin/grep", "type": "reg", "size": 215360, "modtime": "2017-01-23T18:18:59Z", "mode": 33261, "offset": 1066887, "NumLink": 0, "digest": "sha256:5772e5f9aea26318c6ab587d38988013d7127531ee185984fec45874c4379596" }, { "name": "bin/gunzip", "type": "reg", "size": 2301, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 1169811, "NumLink": 0, "digest": "sha256:091abe52520c96a75cf7d4ff38796fc878cd62c3a75a3fd8161aa3df1e26bebd" }, { "name": "bin/gzexe", "type": "reg", "size": 5927, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 1171050, "NumLink": 0, "digest": "sha256:6de8254cfd49543097ae946c303602ffd5899b2c88ec27cfcd86d786f95a1e92" }, { "name": "bin/gzip", "type": "reg", "size": 102408, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 1173484, "NumLink": 0, "digest": "sha256:3b7dea216f49346ddd68c471deefa345d5cdfb9d21da0942909d47e39d23b23d" }, { "name": "bin/hostname", "type": "reg", "size": 18992, "modtime": "2016-07-03T19:26:17Z", "mode": 33261, "offset": 1228033, "NumLink": 0, "digest": "sha256:f3187f6c1d9951dc45c8a3dd4579e9e1a24037156cc1126724c18be50a1c8348" }, { "name": "bin/ln", "type": "reg", "size": 56240, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1234279, "NumLink": 0, "digest": "sha256:2af73dbb7990bc6d3a21aaa386d400b96ccd4df2ff4c0751e786c6c1dc9c0e65" }, { "name": "bin/login", "type": "reg", "size": 52632, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 1261422, "NumLink": 0, "digest": "sha256:07369ff7775bc32fb0e4c977e132a442bf94c68454ddea08a3d02912c4ccb30f" }, { "name": "bin/ls", "type": "reg", "size": 130736, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1282844, "NumLink": 0, "digest": "sha256:a0e06b5a72fed6c106391cf0162dbee1750c047640117bfea2234857055216a0" }, { "name": "bin/lsblk", "type": "reg", "size": 81376, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 1344940, "NumLink": 0, "digest": "sha256:3f9a7fb1e45651b0b0b4609e3b4597282efeef3f777bb75a986edec97dfcf7cf" }, { "name": "bin/mkdir", "type": "reg", "size": 81032, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1381190, "NumLink": 0, "digest": "sha256:46254c850ec5d828557ef58c958e793ad96b948161c8378fd4954c3632b560f8" }, { "name": "bin/mknod", "type": "reg", "size": 68648, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1420908, "NumLink": 0, "digest": "sha256:02d68294caac9d375456f35e26c99d17abb27cce90abb31ecb346a26fc7b56e9" }, { "name": "bin/mktemp", "type": "reg", "size": 43912, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1454052, "NumLink": 0, "digest": "sha256:3ec6d01605f2a1d0518003dfc0822e9d7f75eafa337a5e4d575db0d98b8325a3" }, { "name": "bin/more", "type": "reg", "size": 39752, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 1473855, "NumLink": 0, "digest": "sha256:c8f448b9780748ae395fefb8abb09a4f94eaba1796996880979c15a2f970c3fa" }, { "name": "bin/mount", "type": "reg", "size": 44304, "modtime": "2018-03-07T18:29:09Z", "mode": 35309, "offset": 1493006, "NumLink": 0, "digest": "sha256:4df3d21877d09f670bc6c0a9021fecf0b0faa4434f8383ea048cbf1528f32910" }, { "name": "bin/mountpoint", "type": "reg", "size": 14840, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 1509324, "NumLink": 0, "digest": "sha256:a5640eba9a1104278409564b771b53276a5f0f48692052a7dcf76a70f9f80ad3" }, { "name": "bin/mv", "type": "reg", "size": 126416, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1514148, "NumLink": 0, "digest": "sha256:a9c0bbf66cff9f6870a3fa58c7182afb1020ff99282a6e48c82a75931d638b21" }, { "name": "bin/nisdomainname", "type": "symlink", "modtime": "2016-07-03T19:26:17Z", "linkName": "hostname", "mode": 41471, "NumLink": 0 }, { "name": "bin/pidof", "type": "symlink", "modtime": "2017-02-12T21:55:39Z", "linkName": "/sbin/killall5", "mode": 41471, "NumLink": 0 }, { "name": "bin/pwd", "type": "reg", "size": 35656, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1577351, "NumLink": 0, "digest": "sha256:d27a17c6a7ded3550c37d49e6fd8875a86641a01e18f76c297e43ee65d0a1297" }, { "name": "bin/rbash", "type": "symlink", "modtime": "2017-05-15T19:45:32Z", "linkName": "bash", "mode": 41471, "NumLink": 0 }, { "name": "bin/readlink", "type": "reg", "size": 43816, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1593217, "NumLink": 0, "digest": "sha256:539ab7e307835455c670f725fafb9831df823ea59e64d11967b9bc43f7dec749" }, { "name": "bin/rm", "type": "reg", "size": 64424, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1613850, "NumLink": 0, "digest": "sha256:661eba5491e486bb9308dc6fcfd65aaa790471ea5f6bf1b5f775672cd982389e" }, { "name": "bin/rmdir", "type": "reg", "size": 43816, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1645395, "NumLink": 0, "digest": "sha256:0d02f44490836b4f010e17cc2197921ebf0e58cbca0f206609b59fbd52cbca9d" }, { "name": "bin/run-parts", "type": "reg", "size": 19288, "modtime": "2017-04-02T17:10:33Z", "mode": 33261, "offset": 1665557, "NumLink": 0, "digest": "sha256:a37652fd9ee165d666902bd4e7a3967969dc6fc7ff0d7f017fab3260c93967e9" }, { "name": "bin/sed", "type": "reg", "size": 105808, "modtime": "2017-02-04T15:16:08Z", "mode": 33261, "offset": 1673379, "NumLink": 0, "digest": "sha256:ab8fbc38bf9f67c706d7d422a4ef4c051eb5c4c21579037f4d184ebf189f5e79" }, { "name": "bin/sh", "type": "symlink", "modtime": "2017-01-24T05:16:56Z", "linkName": "dash", "mode": 41471, "NumLink": 0 }, { "name": "bin/sh.distrib", "type": "symlink", "modtime": "2017-01-24T05:16:56Z", "linkName": "dash", "mode": 41471, "NumLink": 0 }, { "name": "bin/sleep", "type": "reg", "size": 35592, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1727499, "NumLink": 0, "digest": "sha256:196bce40af413a2188c4ca548db12d710334af5523a0d5e4f2e9bedeb987c39c" }, { "name": "bin/stty", "type": "reg", "size": 76680, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1742845, "NumLink": 0, "digest": "sha256:52fe1b6ffec2a667b411c5b131d86c8fa444bbbcacf3bcbaf43745141bd66321" }, { "name": "bin/su", "type": "reg", "size": 40536, "modtime": "2017-05-17T11:59:59Z", "mode": 35309, "offset": 1775410, "NumLink": 0, "digest": "sha256:0c1d3341d124b09395a959f2674da1d775703e66c285ed309031c2b8cc77f75e" }, { "name": "bin/sync", "type": "reg", "size": 31496, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 1791921, "NumLink": 0, "digest": "sha256:94e555750f59f1ddf60451ffd1902d520a786751f71894b3bce2e75a9ac4d841" }, { "name": "bin/tailf", "type": "reg", "size": 23232, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 1806686, "NumLink": 0, "digest": "sha256:fc2d8a0225c79247fb2d539a2d854210bcbd3512ccb45c526ac67c9f71995407" }, { "name": "bin/tar", "type": "reg", "size": 416896, "modtime": "2016-10-30T06:35:31Z", "mode": 33261, "offset": 1817371, "NumLink": 0, "digest": "sha256:3a216ed63dced5ea5ea949c4f11ee78a7f7aa715de76cb87498940a3433e5b3d" }, { "name": "bin/tempfile", "type": "reg", "size": 10680, "modtime": "2017-04-02T17:10:33Z", "mode": 33261, "offset": 2021609, "NumLink": 0, "digest": "sha256:6702e5b02aaa841832ddc9cfc6cbb6333b2d03ca88839d2cd8dcedaae4e07b8d" }, { "name": "bin/touch", "type": "reg", "size": 93160, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 2025161, "NumLink": 0, "digest": "sha256:952786e16e51f9ee059472abc0d8f1ec9e237af253e09fe49a975445aaaec589" }, { "name": "bin/true", "type": "reg", "size": 31464, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 2070363, "NumLink": 0, "digest": "sha256:5a2de760cb026c9749bf515dd1ad258b3c8b554fb4ba4bc2fd33f99ae834e472" }, { "name": "bin/umount", "type": "reg", "size": 31720, "modtime": "2018-03-07T18:29:09Z", "mode": 35309, "offset": 2084085, "NumLink": 0, "digest": "sha256:4c90ff10f6b7dc1c61e06166792f90954ca4071c4cb43942b991ffd5e1eeee3b" }, { "name": "bin/uname", "type": "reg", "size": 35592, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 2095736, "NumLink": 0, "digest": "sha256:6eb9b55fc05a8938ac49c78d336f8f8669195db70756b9ff3cb9d31e6107c95b" }, { "name": "bin/uncompress", "type": "hardlink", "modtime": "2016-03-14T20:41:45Z", "linkName": "bin/gunzip", "mode": 33261, "NumLink": 0 }, { "name": "bin/vdir", "type": "reg", "size": 130736, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 2110686, "NumLink": 0, "digest": "sha256:b42f70b011e4069795a55ee63719c9e6ed533ed356073eab38092ca92bb6bd9a" }, { "name": "bin/wdctl", "type": "reg", "size": 31464, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 2172779, "NumLink": 0, "digest": "sha256:657b50892f2acf5a3c1b0af2ced09a9cf7f70c1537c86fce5552a9936f55102d" }, { "name": "bin/which", "type": "reg", "size": 946, "modtime": "2017-04-02T17:10:33Z", "mode": 33261, "offset": 2186759, "NumLink": 0, "digest": "sha256:7bdde142dc5cb004ab82f55adba0c56fc78430a6f6b23afd33be491d4c7c238b" }, { "name": "bin/ypdomainname", "type": "symlink", "modtime": "2016-07-03T19:26:17Z", "linkName": "hostname", "mode": 41471, "NumLink": 0 }, { "name": "bin/zcat", "type": "reg", "size": 1937, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 2187365, "NumLink": 0, "digest": "sha256:aaf7b2c7036c2597450e109198ea7b5870c164591e2501b1891a3e767dfc0e00" }, { "name": "bin/zcmp", "type": "reg", "size": 1777, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 2188438, "NumLink": 0, "digest": "sha256:ae3c2b73273b7d953d432b10c50612011cb0bd0f245220d8ec10a5a47239d86d" }, { "name": "bin/zdiff", "type": "reg", "size": 5764, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 2189446, "NumLink": 0, "digest": "sha256:97f3993ead63a1ce0f6a48cda92d6655ffe210242fe057b8803506b57c99b7bc" }, { "name": "bin/zegrep", "type": "reg", "size": 140, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 2191473, "NumLink": 0, "digest": "sha256:da2da96324108bbe297a75e8ebfcb2400959bffcdaa4c88b797c4d0ce0c94c50" }, { "name": "bin/zfgrep", "type": "reg", "size": 140, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 2191669, "NumLink": 0, "digest": "sha256:b9711301d3ab42575597d8a1c015f49fddba9a7ea9934e11d38b9ff5248503a8" }, { "name": "bin/zforce", "type": "reg", "size": 2131, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 2191867, "NumLink": 0, "digest": "sha256:6936c9aa8e17781410f286bb1cbc35b5548ea4e7604c1379dc8e159d91a0193d" }, { "name": "bin/zgrep", "type": "reg", "size": 5938, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 2193069, "NumLink": 0, "digest": "sha256:1cab9ec4e390ceba0ddd47e7d4537527df5c1991c5b35208a29005e1494b408d" }, { "name": "bin/zless", "type": "reg", "size": 2037, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 2195544, "NumLink": 0, "digest": "sha256:14dc8106ec64c9e2a7c9430e1d0bef170aaad0f5f7f683c1c1810b466cdf5079" }, { "name": "bin/zmore", "type": "reg", "size": 1910, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 2196723, "NumLink": 0, "digest": "sha256:f66077e5cc686ee33c99149972abdfd3a36d3e125cc4b42c215a0d2701eeaf6e" }, { "name": "bin/znew", "type": "reg", "size": 5047, "modtime": "2016-03-14T20:41:45Z", "mode": 33261, "offset": 2197786, "NumLink": 0, "digest": "sha256:01764d96697b060b2a449769073b7cf2df61b5cb604937e39dd7a47017e92ee0" }, { "name": "boot/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "dev/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/.pwd.lock", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33152, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "etc/adduser.conf", "type": "reg", "size": 2981, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2200038, "NumLink": 0, "digest": "sha256:ccdc9675d7bd39c3cc79c2a5d6938f2562dd4062350dbed3058c1faee48b353e" }, { "name": "etc/alternatives/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/alternatives/README", "type": "reg", "size": 100, "modtime": "2018-06-26T10:28:08Z", "mode": 33188, "offset": 2201526, "NumLink": 0, "digest": "sha256:100fc671b65c94241e6013d3a7332a1f5d1a97e0324e37f4ff4851fec607497e" }, { "name": "etc/alternatives/awk", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/usr/bin/mawk", "mode": 41471, "NumLink": 0 }, { "name": "etc/alternatives/awk.1.gz", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/usr/share/man/man1/mawk.1.gz", "mode": 41471, "NumLink": 0 }, { "name": "etc/alternatives/builtins.7.gz", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/usr/share/man/man7/bash-builtins.7.gz", "mode": 41471, "NumLink": 0 }, { "name": "etc/alternatives/nawk", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/usr/bin/mawk", "mode": 41471, "NumLink": 0 }, { "name": "etc/alternatives/nawk.1.gz", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/usr/share/man/man1/mawk.1.gz", "mode": 41471, "NumLink": 0 }, { "name": "etc/alternatives/pager", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/bin/more", "mode": 41471, "NumLink": 0 }, { "name": "etc/alternatives/pager.1.gz", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/usr/share/man/man1/more.1.gz", "mode": 41471, "NumLink": 0 }, { "name": "etc/alternatives/rmt", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/usr/sbin/rmt-tar", "mode": 41471, "NumLink": 0 }, { "name": "etc/alternatives/rmt.8.gz", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/usr/share/man/man8/rmt-tar.8.gz", "mode": 41471, "NumLink": 0 }, { "name": "etc/apt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/apt/apt.conf.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/apt/apt.conf.d/01autoremove", "type": "reg", "size": 769, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 2201963, "NumLink": 0, "digest": "sha256:295419b57259cb583b726064b66ffcd3b625999c637905fdc63e06432afcf752" }, { "name": "etc/apt/apt.conf.d/70debconf", "type": "reg", "size": 182, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 2202387, "NumLink": 0, "digest": "sha256:db749e19baf3b72ca2c157c70c52522cae23d94bc8b2dc5793fd43d427445367" }, { "name": "etc/apt/apt.conf.d/docker-autoremove-suggests", "type": "reg", "size": 754, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2202646, "NumLink": 0, "digest": "sha256:84cb100b000873f25f677cf23ab51f841eb490264fa496361591d6071aebf0f4" }, { "name": "etc/apt/apt.conf.d/docker-clean", "type": "reg", "size": 1175, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2203183, "NumLink": 0, "digest": "sha256:484f60f8d215bf22008b5fe7dd8484350d7abd44655ea79accee79ce11976c81" }, { "name": "etc/apt/apt.conf.d/docker-gzip-indexes", "type": "reg", "size": 481, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2203874, "NumLink": 0, "digest": "sha256:9da4604fbac169caa47e787b4d85c8e06c887603878afa2a61f39fd551a41359" }, { "name": "etc/apt/apt.conf.d/docker-no-languages", "type": "reg", "size": 269, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2204295, "NumLink": 0, "digest": "sha256:a7fea31d968796bf459a439279abdf8d45f5e3f68bbaa9e09dbd9e7f3bd831f6" }, { "name": "etc/apt/preferences.d/", "type": "dir", "modtime": "2017-09-13T16:47:33Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/apt/sources.list", "type": "reg", "size": 168, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2204630, "NumLink": 0, "digest": "sha256:5c58eef9e4b1520d146082c7781f775f3fe1bd7d2749a7f7d8db21bd2a9b4ae5" }, { "name": "etc/apt/sources.list.d/", "type": "dir", "modtime": "2017-09-13T16:47:33Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/apt/trusted.gpg.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/apt/trusted.gpg.d/debian-archive-jessie-automatic.gpg", "type": "reg", "size": 5138, "modtime": "2017-05-25T18:17:13Z", "mode": 33188, "offset": 2204887, "NumLink": 0, "digest": "sha256:d03faac2548c2e653d8fbfdb4088f5ef7b7633cca6a1afa8a67c4df3f445e19f" }, { "name": "etc/apt/trusted.gpg.d/debian-archive-jessie-security-automatic.gpg", "type": "reg", "size": 5147, "modtime": "2017-05-25T18:17:13Z", "mode": 33188, "offset": 2210121, "NumLink": 0, "digest": "sha256:4691fd79441853a23cbd6fc991983cba296280159dfce0ef70508d064bd4c898" }, { "name": "etc/apt/trusted.gpg.d/debian-archive-jessie-stable.gpg", "type": "reg", "size": 2775, "modtime": "2017-05-25T18:17:13Z", "mode": 33188, "offset": 2215357, "NumLink": 0, "digest": "sha256:bcc458a220eb49df0cc61da109c815bdb2db17c5712f5734e5ebc4e28f0ce7a4" }, { "name": "etc/apt/trusted.gpg.d/debian-archive-stretch-automatic.gpg", "type": "reg", "size": 7483, "modtime": "2017-05-25T18:17:13Z", "mode": 33188, "offset": 2218333, "NumLink": 0, "digest": "sha256:1f1c4eba7c74aa485a0da3b170dd0b3d5ea4d5ada4ec9201a2616ec0a3f4130b" }, { "name": "etc/apt/trusted.gpg.d/debian-archive-stretch-security-automatic.gpg", "type": "reg", "size": 7492, "modtime": "2017-05-25T18:17:13Z", "mode": 33188, "offset": 2225734, "NumLink": 0, "digest": "sha256:1eb9ab7a15f18580d449658ff1ba432d06b0a6ac7e0937f933c831cd5ef36d62" }, { "name": "etc/apt/trusted.gpg.d/debian-archive-stretch-stable.gpg", "type": "reg", "size": 2275, "modtime": "2017-05-25T18:17:13Z", "mode": 33188, "offset": 2233132, "NumLink": 0, "digest": "sha256:4d221cb762e470f73d3200d30354b5c39f28c4a1d1d1c2bc01a81a0eac427d7f" }, { "name": "etc/apt/trusted.gpg.d/debian-archive-wheezy-automatic.gpg", "type": "reg", "size": 3780, "modtime": "2017-05-25T18:17:13Z", "mode": 33188, "offset": 2235599, "NumLink": 0, "digest": "sha256:13b45eb5716c72be9831bb1a9e18672ad23f3f41884df63fa42b09eb7d8d30ae" }, { "name": "etc/apt/trusted.gpg.d/debian-archive-wheezy-stable.gpg", "type": "reg", "size": 2851, "modtime": "2017-05-25T18:17:13Z", "mode": 33188, "offset": 2239517, "NumLink": 0, "digest": "sha256:9637cd12bf4cd1f33a24a714dbcaa76bfb1dd5de5c94ae0e9b621616e2d15e34" }, { "name": "etc/bash.bashrc", "type": "reg", "size": 1863, "modtime": "2017-05-15T19:45:32Z", "mode": 33188, "offset": 2242516, "NumLink": 0, "digest": "sha256:5638e43ea1289e856d5fbbc80f96d1e2cf249c04976870fa5481278e081a0163" }, { "name": "etc/bindresvport.blacklist", "type": "reg", "size": 367, "modtime": "2017-04-09T21:28:38Z", "mode": 33188, "offset": 2243473, "NumLink": 0, "digest": "sha256:63229551ffc257f56e3df60ca97e1f2963f3ab2128ce27a0f398b4418fa454d0" }, { "name": "etc/cron.daily/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/cron.daily/apt-compat", "type": "reg", "size": 1474, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 2243845, "NumLink": 0, "digest": "sha256:8eeae3a9df22621d51062e4dadfc5c63b49732b38a37b5d4e52c99c2237e5767" }, { "name": "etc/cron.daily/dpkg", "type": "reg", "size": 1597, "modtime": "2018-06-26T02:48:17Z", "mode": 33261, "offset": 2244691, "NumLink": 0, "digest": "sha256:c08441d2782fbde6e06a6f27cf84ae647efb67b5305919e739431b19f284ec95" }, { "name": "etc/cron.daily/passwd", "type": "reg", "size": 249, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 2245528, "NumLink": 0, "digest": "sha256:777a9112ee093d8683645b031eb6cfeb9ce77274f40575c48ff2054ea24114d1" }, { "name": "etc/debconf.conf", "type": "reg", "size": 2969, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 2245764, "NumLink": 0, "digest": "sha256:fe7e76d4162e80e0bc8c24bc638c56ae92c07a80db750cbf0a87e0904e143f4e" }, { "name": "etc/debian_version", "type": "reg", "size": 4, "modtime": "2018-06-26T12:03:08Z", "mode": 33188, "offset": 2247154, "NumLink": 0, "digest": "sha256:02da5eaddc974610c7221b297e33005e32beead4b2d6371e8625a5ed1494033f" }, { "name": "etc/default/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/default/hwclock", "type": "reg", "size": 657, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 2247299, "NumLink": 0, "digest": "sha256:827cf5c033ba11433d2b4087ec1e36e82766eab39ceed8e7f8f09d983d2d8235" }, { "name": "etc/default/nss", "type": "reg", "size": 1756, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 2247771, "NumLink": 0, "digest": "sha256:836614e9d4d501d0af43087c9c9300365a38d53f24f845efcf0b2ad8194cbaa0" }, { "name": "etc/default/useradd", "type": "reg", "size": 1118, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 2248690, "NumLink": 0, "digest": "sha256:03b603de7e8c7a8192902d827edea1891360bd094cf2c810669af13aee823c70" }, { "name": "etc/deluser.conf", "type": "reg", "size": 604, "modtime": "2016-06-26T20:00:56Z", "mode": 33188, "offset": 2249396, "NumLink": 0, "digest": "sha256:946e0f11a8997bf41dbafca1f6f5a4bedf46746c91801ca4f2e90dd0172f06b6" }, { "name": "etc/dpkg/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/dpkg/dpkg.cfg", "type": "reg", "size": 446, "modtime": "2014-11-28T01:08:21Z", "mode": 33188, "offset": 2249890, "NumLink": 0, "digest": "sha256:fead43b89af3ea5691c48f32d7fe1ba0f7ab229fb5d230f612d76fe8e6f5a015" }, { "name": "etc/dpkg/dpkg.cfg.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/dpkg/dpkg.cfg.d/docker", "type": "reg", "size": 3543, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2250297, "NumLink": 0, "digest": "sha256:5493667488dbf55f6aff36bac8c35362faa45803b4d350af959a76a5aaf2dda1" }, { "name": "etc/dpkg/dpkg.cfg.d/docker-apt-speedup", "type": "reg", "size": 259, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2251381, "NumLink": 0, "digest": "sha256:ab3af717d57cbbea36555833dc1ae031fa46750b879199ec579ee00be9aa0124" }, { "name": "etc/dpkg/origins/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/dpkg/origins/debian", "type": "reg", "size": 82, "modtime": "2009-02-02T23:06:58Z", "mode": 33188, "offset": 2251704, "NumLink": 0, "digest": "sha256:50f35af8ac4a5df3690991a4b428fa49d56580b0020fcc6e38283b3b1b2e6c74" }, { "name": "etc/dpkg/origins/default", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "debian", "mode": 41471, "NumLink": 0 }, { "name": "etc/environment", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "etc/fstab", "type": "reg", "size": 37, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2251928, "NumLink": 0, "digest": "sha256:a6b093c9916c6c54e5d634d3689f1a0132e14cce0b8e50ff445da8e85acfbd17" }, { "name": "etc/gai.conf", "type": "reg", "size": 2584, "modtime": "2016-08-02T02:01:36Z", "mode": 33188, "offset": 2252062, "NumLink": 0, "digest": "sha256:76a5771adee7b9f36c7ae66eae78d72f325557500269107f2d98a7e3560a1808" }, { "name": "etc/group", "type": "reg", "size": 446, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2253248, "NumLink": 0, "digest": "sha256:639aef8980b6ea2ea640187f4117523b4ade4b7289a5f8b3ef8ad7bb1a731fa7" }, { "name": "etc/group-", "type": "reg", "size": 446, "modtime": "2018-10-11T00:00:00Z", "mode": 33152, "offset": 2253598, "NumLink": 0, "digest": "sha256:cfde4574c857edbfbd31667000d75d07efe6bc61f22063693010dee2a912450b" }, { "name": "etc/gshadow", "type": "reg", "size": 374, "modtime": "2018-10-11T00:00:00Z", "mode": 33184, "gid": 42, "offset": 2253956, "NumLink": 0, "digest": "sha256:9f095e317e25ddd4a4bc3b58d5aaa08e20bbe8a0e42ca745b0e6ba6d17d61a34" }, { "name": "etc/host.conf", "type": "reg", "size": 9, "modtime": "2006-08-07T17:14:09Z", "mode": 33188, "offset": 2254224, "NumLink": 0, "digest": "sha256:380f5fe21d755923b44203b58ca3c8b9681c485d152bd5d7e3914f67d821d32a" }, { "name": "etc/hostname", "type": "reg", "size": 14, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2254330, "NumLink": 0, "digest": "sha256:411eb208674138b8ce7624993e678f6b1d8a39c6f2bc4156e10d9466e0c71d2b" }, { "name": "etc/init.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/init.d/hwclock.sh", "type": "reg", "size": 3809, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 2254481, "NumLink": 0, "digest": "sha256:a919f9434b681974a2f1d4120af10c0527b30e8cda6fdec1dea1eee3077b6609" }, { "name": "etc/issue", "type": "reg", "size": 26, "modtime": "2018-06-26T12:03:08Z", "mode": 33188, "offset": 2256157, "NumLink": 0, "digest": "sha256:3836ea85d67769580f775bb6c2e547b8f1167b00810f00f54bd9ff31fbb5ca12" }, { "name": "etc/issue.net", "type": "reg", "size": 19, "modtime": "2018-06-26T12:03:08Z", "mode": 33188, "offset": 2256283, "NumLink": 0, "digest": "sha256:202afaaf205a231b5cc398d1b78caf8d2d476d108d9ba47c62d3c5105acebe1d" }, { "name": "etc/kernel/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/kernel/postinst.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/kernel/postinst.d/apt-auto-removal", "type": "reg", "size": 2903, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 2256468, "NumLink": 0, "digest": "sha256:64fef575566fd0ab647200ed6849156d07432997d22c65a06694c8852bdb7255" }, { "name": "etc/ld.so.cache", "type": "reg", "size": 5912, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2257911, "NumLink": 0, "digest": "sha256:1b041de9bcd1a26dce46de0dd5b29ad0cfc11991925102bc1ac66bad20a4e372" }, { "name": "etc/ld.so.conf", "type": "reg", "size": 34, "modtime": "2017-04-09T21:28:38Z", "mode": 33188, "offset": 2259376, "NumLink": 0, "digest": "sha256:d4b198c463418b493208485def26a6f4c57279467b9dfa491b70433cedb602e8" }, { "name": "etc/ld.so.conf.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/ld.so.conf.d/libc.conf", "type": "reg", "size": 44, "modtime": "2016-03-20T23:45:12Z", "mode": 33188, "offset": 2259532, "NumLink": 0, "digest": "sha256:90d4c7e43e7661cd116010eb9f50ad5817e43162df344bd1ad10898851b15d41" }, { "name": "etc/ld.so.conf.d/x86_64-linux-gnu.conf", "type": "reg", "size": 68, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 2259690, "NumLink": 0, "digest": "sha256:54ad1c27463ba4c81f7cf9f58621e34ab679c760692ac046845940390fb4e612" }, { "name": "etc/libaudit.conf", "type": "reg", "size": 191, "modtime": "2017-04-12T16:17:21Z", "mode": 33188, "offset": 2259840, "NumLink": 0, "digest": "sha256:d48318c90620fde96cb6a8e6eb1eb64663b21200f9d1d053f9e3b4fce24a2543" }, { "name": "etc/localtime", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/usr/share/zoneinfo/Etc/UTC", "mode": 41471, "NumLink": 0 }, { "name": "etc/login.defs", "type": "reg", "size": 10477, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 2260119, "NumLink": 0, "digest": "sha256:ff7cf6759ea81d72c51ab879e751c23bb4aa73307b737743aae9f034a314e7b6" }, { "name": "etc/logrotate.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/logrotate.d/apt", "type": "reg", "size": 173, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 2264687, "NumLink": 0, "digest": "sha256:fcc2510172fd914ca22762c4b2dc43d36152e65becf8e84abec59f7652da5e3f" }, { "name": "etc/logrotate.d/dpkg", "type": "reg", "size": 232, "modtime": "2018-06-26T02:48:17Z", "mode": 33188, "offset": 2264867, "NumLink": 0, "digest": "sha256:a65183e9cf4e0d9c655514495e204b437baef0717c8207639c2d60d6d7a801c2" }, { "name": "etc/machine-id", "type": "reg", "size": 33, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2265064, "NumLink": 0, "digest": "sha256:7dcaeff856e487b63782f158ad6de51af878a00135068cecba7c9d4ba0df41a9" }, { "name": "etc/mke2fs.conf", "type": "reg", "size": 973, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 2265192, "NumLink": 0, "digest": "sha256:437ffd423945a6427ebb62de923667aea851fc05c79be7428eecea14a024f35e" }, { "name": "etc/motd", "type": "reg", "size": 286, "modtime": "2018-06-26T12:03:08Z", "mode": 33188, "offset": 2265645, "NumLink": 0, "digest": "sha256:a378977155fb42bb006496321cbe31f74cbda803c3f6ca590f30e76d1afad921" }, { "name": "etc/nsswitch.conf", "type": "reg", "size": 497, "modtime": "2017-12-31T12:12:42Z", "mode": 33188, "offset": 2265946, "NumLink": 0, "digest": "sha256:e241e67d7b5c15a5ace818d89277507b5ded8b49688b7a4431afb3b1041a3759" }, { "name": "etc/opt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/os-release", "type": "symlink", "modtime": "2018-06-26T12:03:08Z", "linkName": "../usr/lib/os-release", "mode": 41471, "NumLink": 0 }, { "name": "etc/pam.conf", "type": "reg", "size": 552, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 2266374, "NumLink": 0, "digest": "sha256:8aa7f3472ec88a24a572d6ffd9748ce3da223fba3b2545098eaaae768b6408c4" }, { "name": "etc/pam.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/pam.d/chfn", "type": "reg", "size": 384, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 2266702, "NumLink": 0, "digest": "sha256:d66a095a330d7e20d0bbb56a4cb28a4b1bfc92e8a5a5e9bfc3d0a51c5e3d7170" }, { "name": "etc/pam.d/chpasswd", "type": "reg", "size": 92, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 2267039, "NumLink": 0, "digest": "sha256:f3f96229e82bf41a7fd3ec12e697b3465235d96bb1e44c39ba91157425a36082" }, { "name": "etc/pam.d/chsh", "type": "reg", "size": 581, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 2267222, "NumLink": 0, "digest": "sha256:0101e7e589ce40435c5a8709888225400a78ab6be86dfc5fef86ee23ba5338ad" }, { "name": "etc/pam.d/common-account", "type": "reg", "size": 1208, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2267648, "NumLink": 0, "digest": "sha256:aa8a63d72e79399b6c51ebe4e9f828c954145a799eb4b8f3224724f51cbb9fac" }, { "name": "etc/pam.d/common-auth", "type": "reg", "size": 1221, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2268373, "NumLink": 0, "digest": "sha256:df3ed820b414b7163bd61b623e6b7e5896d541f9df392240606a23aa4f421d4a" }, { "name": "etc/pam.d/common-password", "type": "reg", "size": 1440, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2269107, "NumLink": 0, "digest": "sha256:ede17d3b24602a774a51fde44a5afd536f73eb3da65f948926ab7952b474d3b0" }, { "name": "etc/pam.d/common-session", "type": "reg", "size": 1156, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2269931, "NumLink": 0, "digest": "sha256:6dc1d9be5915053dec2ac18f1c0b6b3389b3f0ed74383dde4a46dec81edefe68" }, { "name": "etc/pam.d/common-session-noninteractive", "type": "reg", "size": 1154, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2270623, "NumLink": 0, "digest": "sha256:d137251095e22fca44fcc5c993699e46446673a085dab8238de6a670fb3cc7f2" }, { "name": "etc/pam.d/login", "type": "reg", "size": 4945, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 2271302, "NumLink": 0, "digest": "sha256:42e1e68613a5e0d2942ceeb8b5a4544341bde732fed47630108a163545359f6d" }, { "name": "etc/pam.d/newusers", "type": "reg", "size": 92, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 2273285, "NumLink": 0, "digest": "sha256:26e75ce7c9066801b8db380ff9d8ba58a5e8cf2de5fb38ffd1db5ba62c85acef" }, { "name": "etc/pam.d/other", "type": "reg", "size": 520, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 2273468, "NumLink": 0, "digest": "sha256:d13078e71d3351ef7f63a7265ddb50b710a2598b9febc78810fbb0130a02695a" }, { "name": "etc/pam.d/passwd", "type": "reg", "size": 92, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 2273845, "NumLink": 0, "digest": "sha256:87696fad1046d6b33b6d3407bb419980987331b4dcd8905f7a6041bced90c51d" }, { "name": "etc/pam.d/runuser", "type": "reg", "size": 143, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 2274030, "NumLink": 0, "digest": "sha256:2d430cb6628248953568010427d663f3305856f3cb055955c2239bea226c5280" }, { "name": "etc/pam.d/runuser-l", "type": "reg", "size": 138, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 2274230, "NumLink": 0, "digest": "sha256:be9329a8b26e3cfd4af879fe60900f646f8188f3fbe491688f23d4d8b491c5b1" }, { "name": "etc/pam.d/su", "type": "reg", "size": 2257, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 2274416, "NumLink": 0, "digest": "sha256:f7cac62fbcd50f9931d09a9190fc3ec390fd48fb5b8bec57e0996a7246856b12" }, { "name": "etc/passwd", "type": "reg", "size": 919, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2275504, "NumLink": 0, "digest": "sha256:f3df8ec25c77cb0e445aab589c5fef4d77868f875fa742c0d42fccb9e1a50754" }, { "name": "etc/passwd-", "type": "reg", "size": 919, "modtime": "2018-10-11T00:00:00Z", "mode": 33152, "offset": 2275953, "NumLink": 0, "digest": "sha256:f3df8ec25c77cb0e445aab589c5fef4d77868f875fa742c0d42fccb9e1a50754" }, { "name": "etc/profile", "type": "reg", "size": 767, "modtime": "2016-03-04T11:00:00Z", "mode": 33188, "offset": 2276404, "NumLink": 0, "digest": "sha256:b8ffd2c97588047e1cea84b7dfdb68bfde167e2957f667ca2b6ab2929feb4f49" }, { "name": "etc/profile.d/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/rc0.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/rc0.d/K01hwclock.sh", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "../init.d/hwclock.sh", "mode": 41471, "NumLink": 0 }, { "name": "etc/rc1.d/", "type": "dir", "modtime": "2017-05-02T10:20:21Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/rc2.d/", "type": "dir", "modtime": "2017-05-02T10:20:21Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/rc3.d/", "type": "dir", "modtime": "2017-05-02T10:20:21Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/rc4.d/", "type": "dir", "modtime": "2017-05-02T10:20:21Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/rc5.d/", "type": "dir", "modtime": "2017-05-02T10:20:21Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/rc6.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/rc6.d/K01hwclock.sh", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "../init.d/hwclock.sh", "mode": 41471, "NumLink": 0 }, { "name": "etc/rcS.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/rcS.d/S01hwclock.sh", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "../init.d/hwclock.sh", "mode": 41471, "NumLink": 0 }, { "name": "etc/resolv.conf", "type": "reg", "size": 104, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2277035, "NumLink": 0, "digest": "sha256:a535ac16b8fe54e9e1afbb474c4c19fd8faeddbac8b1e1c17f8f52191ce84f96" }, { "name": "etc/rmt", "type": "reg", "size": 268, "modtime": "2016-10-30T06:35:31Z", "mode": 33261, "offset": 2277208, "NumLink": 0, "digest": "sha256:0bdd822a1df82458bdf623d6869f9d0817f6e66f517366a67a4770dbbe714dd2" }, { "name": "etc/securetty", "type": "reg", "size": 4179, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 2277489, "NumLink": 0, "digest": "sha256:49310071ed72eb85aa785d2934051a9ca846f91a474b7fb9b76290444f6b16df" }, { "name": "etc/security/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/security/access.conf", "type": "reg", "size": 4620, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 2279287, "NumLink": 0, "digest": "sha256:cb2d5cbb78756240990da65ce40431a0ccb4f09746868c6a874234ba5fb42f2b" }, { "name": "etc/security/group.conf", "type": "reg", "size": 3635, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 2281174, "NumLink": 0, "digest": "sha256:41df4bc646811997d0390c6d37d839d2aef4a9a1a940c44ee1a798a9dc1ac864" }, { "name": "etc/security/limits.conf", "type": "reg", "size": 2150, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 2282877, "NumLink": 0, "digest": "sha256:69ff0dea1ee42bc6eda9077627610d3181e6fa82a9a3d03e36f20d35c3dbab9e" }, { "name": "etc/security/limits.d/", "type": "dir", "modtime": "2017-05-27T15:44:02Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/security/namespace.conf", "type": "reg", "size": 1440, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 2283786, "NumLink": 0, "digest": "sha256:d0c3045ba5071b8375fde6165d4e4db9b69f49af5d2525cecd2bca1cb7538552" }, { "name": "etc/security/namespace.d/", "type": "dir", "modtime": "2017-05-27T15:44:02Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/security/namespace.init", "type": "reg", "size": 1016, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 2284546, "NumLink": 0, "digest": "sha256:2d76094c06f10839c566ef64bde5624c325aeab7991e7f5d776c5310e8f41932" }, { "name": "etc/security/opasswd", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33152, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "etc/security/pam_env.conf", "type": "reg", "size": 2972, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 2285163, "NumLink": 0, "digest": "sha256:ff4956721a3f53e56e25ffffde62fe4fa0267e5dd94c3411def12de50322fb8f" }, { "name": "etc/security/sepermit.conf", "type": "reg", "size": 419, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 2286669, "NumLink": 0, "digest": "sha256:885ec2a43042ad88d7f849e5e1cbef4e34e58229764a84a927c0e09cd7d47d70" }, { "name": "etc/security/time.conf", "type": "reg", "size": 2179, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 2286990, "NumLink": 0, "digest": "sha256:6802adfc8efc6168f87e98e960fa7d15e516a295fef7a6472ef5359527e886ff" }, { "name": "etc/selinux/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/selinux/semanage.conf", "type": "reg", "size": 2041, "modtime": "2016-12-30T15:42:09Z", "mode": 33188, "offset": 2288206, "NumLink": 0, "digest": "sha256:80464fb793459392ffbf1e79e57df3247a7b2fe413854f2c155848a0b8c6004f" }, { "name": "etc/shadow", "type": "reg", "size": 501, "modtime": "2018-10-11T00:00:00Z", "mode": 33184, "gid": 42, "offset": 2289342, "NumLink": 0, "digest": "sha256:c1845e019de82ee247c38d602bd78dd32c53b156789869c53e447399f362d824" }, { "name": "etc/shadow-", "type": "reg", "size": 501, "modtime": "2018-10-11T00:00:00Z", "mode": 33152, "offset": 2289547, "NumLink": 0, "digest": "sha256:c1845e019de82ee247c38d602bd78dd32c53b156789869c53e447399f362d824" }, { "name": "etc/shells", "type": "reg", "size": 73, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2289752, "NumLink": 0, "digest": "sha256:ddbebd60d26dd772114734225c89b80ef95f3cffa69031ae2b6aaeda791c4652" }, { "name": "etc/skel/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/skel/.bash_logout", "type": "reg", "size": 220, "modtime": "2017-05-15T19:45:32Z", "mode": 33188, "offset": 2289933, "NumLink": 0, "digest": "sha256:26882b79471c25f945c970f8233d8ce29d54e9d5eedcd2884f88affa84a18f56" }, { "name": "etc/skel/.bashrc", "type": "reg", "size": 3526, "modtime": "2017-05-15T19:45:32Z", "mode": 33188, "offset": 2290189, "NumLink": 0, "digest": "sha256:afae8986f549c6403410e029f9cce7983311512d04b1f02af02e4ce0af0dd2bf" }, { "name": "etc/skel/.profile", "type": "reg", "size": 675, "modtime": "2017-05-15T19:45:32Z", "mode": 33188, "offset": 2291873, "NumLink": 0, "digest": "sha256:86512cad76131783f5dae4346ddc3fb39f6f7c0f74b3039bff70ca4015ade034" }, { "name": "etc/staff-group-for-usr-local", "type": "reg", "size": 771, "modtime": "2012-06-09T10:00:00Z", "mode": 33188, "offset": 2292362, "NumLink": 0, "digest": "sha256:64a482506f00572df1d4909a347d6f4fa8e6ce23686b7f058bfbd650ec0658ce" }, { "name": "etc/subgid", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "etc/subuid", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "etc/systemd/", "type": "dir", "modtime": "2017-05-02T10:20:21Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/systemd/system/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/systemd/system/timers.target.wants/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/systemd/system/timers.target.wants/apt-daily-upgrade.timer", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/lib/systemd/system/apt-daily-upgrade.timer", "mode": 41471, "NumLink": 0 }, { "name": "etc/systemd/system/timers.target.wants/apt-daily.timer", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/lib/systemd/system/apt-daily.timer", "mode": 41471, "NumLink": 0 }, { "name": "etc/terminfo/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/terminfo/README", "type": "reg", "size": 212, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2293065, "NumLink": 0, "digest": "sha256:cfc3399b782bb0ecb14b9727dbd5ffd82ef774d473f6c47c39e621f8f4850603" }, { "name": "etc/timezone", "type": "reg", "size": 8, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 2293303, "NumLink": 0, "digest": "sha256:f0dcac7b1d721d2f68937a71f0229b4c4f88564fd711339951528889913cd85d" }, { "name": "etc/update-motd.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "etc/update-motd.d/10-uname", "type": "reg", "size": 23, "modtime": "2017-04-04T12:00:00Z", "mode": 33261, "offset": 2293453, "NumLink": 0, "digest": "sha256:1dca09550a75048731bbd17f17e027cc71ae50a86e0d911a8b3813e88d9b5ab6" }, { "name": "home/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/init/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/init/init-d-script", "type": "reg", "size": 5643, "modtime": "2017-02-12T21:55:39Z", "mode": 33261, "offset": 2293643, "NumLink": 0, "digest": "sha256:31c2f323e3ea8d633880fd46f35954e2e91139c254c887c17cb06add05ef20e0" }, { "name": "lib/init/vars.sh", "type": "reg", "size": 1212, "modtime": "2017-02-12T21:55:39Z", "mode": 33188, "offset": 2295656, "NumLink": 0, "digest": "sha256:49d734860b46c62805fc29a67b9d61210113b6eac2409e4ffd5cf14589f4f0a3" }, { "name": "lib/lsb/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/lsb/init-functions", "type": "reg", "size": 11510, "modtime": "2016-11-25T15:00:10Z", "mode": 33188, "offset": 2296440, "NumLink": 0, "digest": "sha256:1ca0a1b8aa2acd634075589ef49172d6125e8f7cada2069b8576fc090c953eb5" }, { "name": "lib/lsb/init-functions.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/lsb/init-functions.d/20-left-info-blocks", "type": "reg", "size": 1088, "modtime": "2014-08-28T23:04:48Z", "mode": 33188, "offset": 2300293, "NumLink": 0, "digest": "sha256:10997f92734d15a0a49c153f47cbd11553a2f3d8132f7191e6676a69444f8810" }, { "name": "lib/systemd/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/systemd/system/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/systemd/system/apt-daily-upgrade.service", "type": "reg", "size": 238, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 2300807, "NumLink": 0, "digest": "sha256:c8e4b846bd3da8819c6c4101556742239234e2cb3f670418fdbfe33606b2c5ba" }, { "name": "lib/systemd/system/apt-daily-upgrade.timer", "type": "reg", "size": 184, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 2301099, "NumLink": 0, "digest": "sha256:b804d7bab8eb41202384f9270e25d5383346ace8b3d7c4f5029c150638d77bcd" }, { "name": "lib/systemd/system/apt-daily.service", "type": "reg", "size": 225, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 2301356, "NumLink": 0, "digest": "sha256:aaec2cdb7384fc2f5c75105e9daf6b3f5dae507ab6bfe1ea2fb7fbb8ff112c7f" }, { "name": "lib/systemd/system/apt-daily.timer", "type": "reg", "size": 156, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 2301626, "NumLink": 0, "digest": "sha256:0075e974af4e3a94757e219ba50ccb8348d4d1a8834d938f6cc9b1f4fd1db4e5" }, { "name": "lib/terminfo/", "type": "dir", "modtime": "2017-12-28T09:47:33Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/E/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/E/Eterm", "type": "reg", "size": 2267, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2301908, "NumLink": 0, "digest": "sha256:599e0a90f89a32e077f51ec8a86540680e4ae1faf99c539bc357a693b892cd6d" }, { "name": "lib/terminfo/E/Eterm-color", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "Eterm", "mode": 41471, "NumLink": 0 }, { "name": "lib/terminfo/a/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/a/ansi", "type": "reg", "size": 1481, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2303240, "NumLink": 0, "digest": "sha256:93ec8cb9beb0c898ebc7dda0f670de31addb605be9005735228680d592cff657" }, { "name": "lib/terminfo/c/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/c/cons25", "type": "reg", "size": 1502, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2303991, "NumLink": 0, "digest": "sha256:acd69b88fbc9045037b562dd67c876e88cc5d2616af20b9ca6c41d33ee335606" }, { "name": "lib/terminfo/c/cons25-debian", "type": "reg", "size": 1519, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2304827, "NumLink": 0, "digest": "sha256:0437ef75abb06ca00a0ca444a8aa7402276b7217a20330217c84b59fdd8e0b4f" }, { "name": "lib/terminfo/c/cygwin", "type": "reg", "size": 1518, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2305668, "NumLink": 0, "digest": "sha256:1a9b75481dba09d8f73b9b13f39d52db026bfc7ae8eb4de1d250388756445dbc" }, { "name": "lib/terminfo/d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/d/dumb", "type": "reg", "size": 308, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2306487, "NumLink": 0, "digest": "sha256:123c85a2812a517d967db5f31660db0e6aded4a0b95ed943c5ab435368e7a25c" }, { "name": "lib/terminfo/h/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/h/hurd", "type": "reg", "size": 1570, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2306686, "NumLink": 0, "digest": "sha256:d5dc00724a04eb3b030addab6914380521d40f416818943171070ec64c623607" }, { "name": "lib/terminfo/l/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/l/linux", "type": "reg", "size": 1788, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2307548, "NumLink": 0, "digest": "sha256:b864e16853fe9aa36a43abd59a3d349026a993a74bc9775880cafb1c9bb6675e" }, { "name": "lib/terminfo/m/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/m/mach", "type": "reg", "size": 617, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2308528, "NumLink": 0, "digest": "sha256:ecd31c58040e5908eb434514e67620b2e4be538655126f427155760b273c7e9b" }, { "name": "lib/terminfo/m/mach-bold", "type": "reg", "size": 652, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2308967, "NumLink": 0, "digest": "sha256:4e4400e3ad4df2dbbf90920860c540cd72552ca71a24b556a0b6ba62fa091b84" }, { "name": "lib/terminfo/m/mach-color", "type": "reg", "size": 1095, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2309431, "NumLink": 0, "digest": "sha256:5caa825bd606e26c8b6c55a3206eccfea525e788f74da5e7cb48cc713db52239" }, { "name": "lib/terminfo/m/mach-gnu", "type": "reg", "size": 1056, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2309925, "NumLink": 0, "digest": "sha256:99372cd399478be723230692595362004df345dee6c4145e4d109113a2357717" }, { "name": "lib/terminfo/m/mach-gnu-color", "type": "reg", "size": 1318, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2310545, "NumLink": 0, "digest": "sha256:e1c62541670d0e10fe46daabce8ce95d9fd77115a68106e5eb2c2a7647e40a13" }, { "name": "lib/terminfo/p/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/p/pcansi", "type": "reg", "size": 1198, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2311246, "NumLink": 0, "digest": "sha256:ecda9662049c96ee0a574f40cfb8950b0198b508b5b72a3de05774eb3cb3f34e" }, { "name": "lib/terminfo/r/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/r/rxvt", "type": "reg", "size": 2078, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2311812, "NumLink": 0, "digest": "sha256:cb5b104f26f34e48f9ca6b5626b1f2247f82548b198ae28aa0524b2bdc345557" }, { "name": "lib/terminfo/r/rxvt-basic", "type": "reg", "size": 2034, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2313001, "NumLink": 0, "digest": "sha256:43f20d35ddc7766d030e99d0b850a439e6d97a257aea86ae61bc52b76131d5c1" }, { "name": "lib/terminfo/r/rxvt-m", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "rxvt-basic", "mode": 41471, "NumLink": 0 }, { "name": "lib/terminfo/r/rxvt-unicode", "type": "reg", "size": 2508, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2314190, "NumLink": 0, "digest": "sha256:280165734528e93ec7c770524e8ce3a3d29dcf5ca5696dacd093d1eb5ce3460a" }, { "name": "lib/terminfo/s/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/s/screen", "type": "reg", "size": 1594, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2315571, "NumLink": 0, "digest": "sha256:2354bf40efa7c42d938abc9091da7dcfd80b2fc35bbeef6e16ae2e77ffa6a28c" }, { "name": "lib/terminfo/s/screen-256color", "type": "reg", "size": 1912, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2316442, "NumLink": 0, "digest": "sha256:15c3d76efa9475f696ca7f73a22dbe0e91a3cc1d2f316d347577042c6534b154" }, { "name": "lib/terminfo/s/screen-256color-bce", "type": "reg", "size": 1924, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2317434, "NumLink": 0, "digest": "sha256:3a12dcef9fcf27bb68948d692ada56b088ff9c00e902c292447e3edd4ac349a2" }, { "name": "lib/terminfo/s/screen-bce", "type": "reg", "size": 1590, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2318437, "NumLink": 0, "digest": "sha256:479d4fc2e09e17723741a8f69f79dc59f539e28be6fd1dbe9853a54675c8ac71" }, { "name": "lib/terminfo/s/screen-s", "type": "reg", "size": 1612, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2319302, "NumLink": 0, "digest": "sha256:93b4fd80b4159ee730b1881d747d7d173bfd69de3eb6b5325dec66e4f61c2dc8" }, { "name": "lib/terminfo/s/screen-w", "type": "reg", "size": 1594, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2320187, "NumLink": 0, "digest": "sha256:8a80c790b6f86666214cf9189f67581502a4cf74b8d1ce8001d3bba7ce82221e" }, { "name": "lib/terminfo/s/sun", "type": "reg", "size": 1004, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2321051, "NumLink": 0, "digest": "sha256:02e392161cb23f49a8fb1ba2f1a6583e013c0c26672f58c5eaca828db3b19914" }, { "name": "lib/terminfo/v/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/v/vt100", "type": "reg", "size": 1194, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2321583, "NumLink": 0, "digest": "sha256:c919070d5dd70856abcda7993ec63680e0a30b997693926301a2049b419d3fb9" }, { "name": "lib/terminfo/v/vt102", "type": "reg", "size": 1188, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2322290, "NumLink": 0, "digest": "sha256:5af8abfb4747049ccde158eee68a8b8138528ece70fddf31b5c85afbdc03dd67" }, { "name": "lib/terminfo/v/vt220", "type": "reg", "size": 1377, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2322998, "NumLink": 0, "digest": "sha256:75a4723bfcdcd22756366838f1d65233f386d7592b019740c8ca5b578e9a5857" }, { "name": "lib/terminfo/v/vt52", "type": "reg", "size": 470, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2323827, "NumLink": 0, "digest": "sha256:1d8e7d40be89fe71e5d2582caa5168fe53ed85d9063e0ccf42e5c53f4d17b069" }, { "name": "lib/terminfo/w/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/w/wsvt25", "type": "reg", "size": 1597, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2324150, "NumLink": 0, "digest": "sha256:28d3410e6b83a3b78a41f108098ac8772a3af3ee2b627b9f9bb4b19b363a5be3" }, { "name": "lib/terminfo/w/wsvt25m", "type": "reg", "size": 1607, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2325046, "NumLink": 0, "digest": "sha256:18c85db3b0ef0ab15b7eb8dc4ac6ea14a37d851628220c8bb61e2edfa4f81683" }, { "name": "lib/terminfo/x/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/terminfo/x/xterm", "type": "reg", "size": 3360, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2325980, "NumLink": 0, "digest": "sha256:c51120adbae844f9bb500711c753335bb3235192e54dff4f576bf56d23c51a9b" }, { "name": "lib/terminfo/x/xterm-256color", "type": "reg", "size": 3430, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2327737, "NumLink": 0, "digest": "sha256:7c820689eed8803db2741a0c0832eb9049ab38ce65670b0ce305ca286f15f921" }, { "name": "lib/terminfo/x/xterm-color", "type": "reg", "size": 1569, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2329533, "NumLink": 0, "digest": "sha256:0b270450c7498756c0e99cfb24341e68f7443344adcf1656e30a0333e48f550f" }, { "name": "lib/terminfo/x/xterm-debian", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "xterm", "mode": 41471, "NumLink": 0 }, { "name": "lib/terminfo/x/xterm-mono", "type": "reg", "size": 1515, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2330325, "NumLink": 0, "digest": "sha256:183c527a8cbec5b5fef3eb8c28473a0530317eea7d01150eec74c01a214fef59" }, { "name": "lib/terminfo/x/xterm-r5", "type": "reg", "size": 1301, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2331036, "NumLink": 0, "digest": "sha256:82098ec067be6189e91e8264278bb85fe3b7bfdeaa3754be301313be140522ca" }, { "name": "lib/terminfo/x/xterm-r6", "type": "reg", "size": 1491, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2331654, "NumLink": 0, "digest": "sha256:ee12fe6d2d8e1d0b83d1042fe8a38f1aed6fd73e2c7316e6db5ec5b061b09ef8" }, { "name": "lib/terminfo/x/xterm-vt220", "type": "reg", "size": 2316, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2332359, "NumLink": 0, "digest": "sha256:bbb3183473a03823612e1bdfa6d4ba7207b36f37b688cf45f217345064f9bb4c" }, { "name": "lib/terminfo/x/xterm-xfree86", "type": "reg", "size": 2265, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 2333528, "NumLink": 0, "digest": "sha256:2c5638bcc74b380e8d70032c88a5920b116bfd5d3ef84168e9b52a0c217c9a9a" }, { "name": "lib/udev/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/udev/hwclock-set", "type": "reg", "size": 776, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 2334755, "NumLink": 0, "digest": "sha256:bec691723c892b77efe3c718846c2f320b4218d6448c8cf71d663e3be8396564" }, { "name": "lib/udev/rules.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/udev/rules.d/85-hwclock.rules", "type": "reg", "size": 204, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 2335252, "NumLink": 0, "digest": "sha256:a65b7d818578fa91ebc00d086964c0528fa28d0ca04c54f11009c6c375f3e158" }, { "name": "lib/x86_64-linux-gnu/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/ld-2.24.so", "type": "reg", "size": 153288, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 2335549, "NumLink": 0, "digest": "sha256:1e73928ade92803c17729c193954735d3ca8d22e228cd95da4cb0c6ed8996df6" }, { "name": "lib/x86_64-linux-gnu/ld-linux-x86-64.so.2", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "ld-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libBrokenLocale-2.24.so", "type": "reg", "size": 6304, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 2415597, "NumLink": 0, "digest": "sha256:d4743e9fdefe3c995545d378713d7bd8c756d554513a74e9e6413b8941ad1b19" }, { "name": "lib/x86_64-linux-gnu/libBrokenLocale.so.1", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libBrokenLocale-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libSegFault.so", "type": "reg", "size": 18736, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 2417375, "NumLink": 0, "digest": "sha256:23d3c4e5a8cd6ebf20fb62bca2b5bacd9282dae432eb0eadafccaaf17d9e3ab0" }, { "name": "lib/x86_64-linux-gnu/libacl.so.1", "type": "symlink", "modtime": "2016-02-06T22:10:44Z", "linkName": "libacl.so.1.1.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libacl.so.1.1.0", "type": "reg", "size": 35488, "modtime": "2016-02-06T22:10:44Z", "mode": 33188, "offset": 2423409, "NumLink": 0, "digest": "sha256:b9c9311dbc806b487e098f844b06b68070b8681cbd4f71511f29647c188e9f1d" }, { "name": "lib/x86_64-linux-gnu/libanl-2.24.so", "type": "reg", "size": 15024, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 2439331, "NumLink": 0, "digest": "sha256:c7575604b8072decb9046118d5e650111428db5cece0aac60fc280a2c2f051a9" }, { "name": "lib/x86_64-linux-gnu/libanl.so.1", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libanl-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libattr.so.1", "type": "symlink", "modtime": "2014-09-08T07:27:07Z", "linkName": "libattr.so.1.1.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libattr.so.1.1.0", "type": "reg", "size": 18832, "modtime": "2014-09-08T07:27:07Z", "mode": 33188, "offset": 2445552, "NumLink": 0, "digest": "sha256:290a147cfa1c559e27bddef432a125c91f6ba8d3bad33555d125afe2748949aa" }, { "name": "lib/x86_64-linux-gnu/libaudit.so.1", "type": "symlink", "modtime": "2017-04-12T16:17:21Z", "linkName": "libaudit.so.1.0.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libaudit.so.1.0.0", "type": "reg", "size": 120752, "modtime": "2017-04-12T16:17:21Z", "mode": 33188, "offset": 2453677, "NumLink": 0, "digest": "sha256:11f89d5e0d0f069eeba5210970669602983da5a0f136a108d5011bb3f96e5119" }, { "name": "lib/x86_64-linux-gnu/libblkid.so.1", "type": "symlink", "modtime": "2018-03-07T18:29:09Z", "linkName": "libblkid.so.1.1.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libblkid.so.1.1.0", "type": "reg", "size": 283464, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 2497883, "NumLink": 0, "digest": "sha256:95780e2f163855c81b56c94c3e40266d7d1b9cfaa472b0d7d252e90d9b6c3a23" }, { "name": "lib/x86_64-linux-gnu/libbz2.so.1", "type": "symlink", "modtime": "2017-01-29T18:30:31Z", "linkName": "libbz2.so.1.0.4", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libbz2.so.1.0", "type": "symlink", "modtime": "2017-01-29T18:30:31Z", "linkName": "libbz2.so.1.0.4", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libbz2.so.1.0.4", "type": "reg", "size": 66992, "modtime": "2017-01-29T18:30:31Z", "mode": 33188, "offset": 2625921, "NumLink": 0, "digest": "sha256:9ebec8ea0b22a7e53f4b24d3e543120454eb228af53fa641eafba6f5e3824cb2" }, { "name": "lib/x86_64-linux-gnu/libc-2.24.so", "type": "reg", "size": 1689360, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 2657158, "NumLink": 0, "digest": "sha256:b2c8bf64c2cafdce5cb263cc100749b5e6b3e4783eef2fff16ae1b4bc5633e16" }, { "name": "lib/x86_64-linux-gnu/libc.so.6", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libc-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libcap-ng.so.0", "type": "symlink", "modtime": "2016-07-03T19:04:40Z", "linkName": "libcap-ng.so.0.0.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libcap-ng.so.0.0.0", "type": "reg", "size": 22944, "modtime": "2016-07-03T19:04:40Z", "mode": 33188, "offset": 3402905, "NumLink": 0, "digest": "sha256:d6f690e38dee69b10da966bfbf594345328f57993453a0e5606a950216d8e783" }, { "name": "lib/x86_64-linux-gnu/libcidn-2.24.so", "type": "reg", "size": 190888, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 3411878, "NumLink": 0, "digest": "sha256:0f04fd41040235d4aff6bca686da46d8fed6bdf78b6011496fed4f40cd6b8bb1" }, { "name": "lib/x86_64-linux-gnu/libcidn.so.1", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libcidn-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libcom_err.so.2", "type": "symlink", "modtime": "2017-02-01T00:54:55Z", "linkName": "libcom_err.so.2.1", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libcom_err.so.2.1", "type": "reg", "size": 14248, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 3472898, "NumLink": 0, "digest": "sha256:d4be0a20cba38d6c62e06ccd45b2142f8fa798227d6a0a41ce98689940b611a8" }, { "name": "lib/x86_64-linux-gnu/libcrypt-2.24.so", "type": "reg", "size": 39256, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 3478207, "NumLink": 0, "digest": "sha256:f52cec1c11e6d0023332a319ba9b7544450bd252a5b1d4853cf8095de9c13407" }, { "name": "lib/x86_64-linux-gnu/libcrypt.so.1", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libcrypt-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libdl-2.24.so", "type": "reg", "size": 14640, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 3496376, "NumLink": 0, "digest": "sha256:91a225e90a28326285fac19ea582e32bf02bbc081d6be78df6326cef8e97eee9" }, { "name": "lib/x86_64-linux-gnu/libdl.so.2", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libdl-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libe2p.so.2", "type": "symlink", "modtime": "2017-02-01T00:54:55Z", "linkName": "libe2p.so.2.3", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libe2p.so.2.3", "type": "reg", "size": 32264, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 3501377, "NumLink": 0, "digest": "sha256:dc040f0ec8112483eb1f26986ca459f15fe45d4ec12b20cfdd8877dde0aa8717" }, { "name": "lib/x86_64-linux-gnu/libext2fs.so.2", "type": "symlink", "modtime": "2017-02-01T00:54:55Z", "linkName": "libext2fs.so.2.4", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libext2fs.so.2.4", "type": "reg", "size": 331536, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 3514555, "NumLink": 0, "digest": "sha256:fb1d8fb387e6f452eafac6f1b428b38edb8c124d0302daed21bc3f111fd359c4" }, { "name": "lib/x86_64-linux-gnu/libfdisk.so.1", "type": "symlink", "modtime": "2018-03-07T18:29:09Z", "linkName": "libfdisk.so.1.1.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libfdisk.so.1.1.0", "type": "reg", "size": 381000, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 3674215, "NumLink": 0, "digest": "sha256:d1bc0b9de54b9b1400ad86ff1ec9133801ba8dfe228be0b038485d6cb6a27b77" }, { "name": "lib/x86_64-linux-gnu/libgcc_s.so.1", "type": "reg", "size": 92584, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 3845933, "NumLink": 0, "digest": "sha256:41124e5da0f8d4ee3368868846bebc6bb8953edea57b1c481cf03f72bbc81e46" }, { "name": "lib/x86_64-linux-gnu/libgcrypt.so.20", "type": "symlink", "modtime": "2018-06-15T09:58:05Z", "linkName": "libgcrypt.so.20.1.6", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libgcrypt.so.20.1.6", "type": "reg", "size": 1112184, "modtime": "2018-06-15T09:58:05Z", "mode": 33188, "offset": 3889670, "NumLink": 0, "digest": "sha256:594967450ccdcbb04408bb8904dadef96ae2c9ec2ef1594a897e84c4af5cc1b0" }, { "name": "lib/x86_64-linux-gnu/libgpg-error.so.0", "type": "symlink", "modtime": "2017-01-18T16:27:10Z", "linkName": "libgpg-error.so.0.21.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libgpg-error.so.0.21.0", "type": "reg", "size": 79936, "modtime": "2017-01-18T16:27:10Z", "mode": 33188, "offset": 4347769, "NumLink": 0, "digest": "sha256:24781f22c712ea9e073df0e72fac6d720d14f5e7bb7ae0f9729af188aadb038d" }, { "name": "lib/x86_64-linux-gnu/liblzma.so.5", "type": "symlink", "modtime": "2016-10-08T13:11:19Z", "linkName": "liblzma.so.5.2.2", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/liblzma.so.5.2.2", "type": "reg", "size": 154376, "modtime": "2016-10-08T13:11:19Z", "mode": 33188, "offset": 4383258, "NumLink": 0, "digest": "sha256:5b8415cf12090162ee1086681eb2183c509962ffafed315225780a49aa35a205" }, { "name": "lib/x86_64-linux-gnu/libm-2.24.so", "type": "reg", "size": 1063328, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 4465352, "NumLink": 0, "digest": "sha256:289922c95eeb611a45fe25aa04e445244095406837408629d4bbc8365dd85b94" }, { "name": "lib/x86_64-linux-gnu/libm.so.6", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libm-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libmemusage.so", "type": "reg", "size": 18808, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 5197320, "NumLink": 0, "digest": "sha256:0a4f0bc7c7aaeda9cd9e406f2a7711b9b58fac67a02c00add2a5cad505ce698d" }, { "name": "lib/x86_64-linux-gnu/libmount.so.1", "type": "symlink", "modtime": "2018-03-07T18:29:09Z", "linkName": "libmount.so.1.1.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libmount.so.1.1.0", "type": "reg", "size": 313096, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 5204144, "NumLink": 0, "digest": "sha256:52742396b967444df7b701ed146637800950fa7e3f144d77e850d6a0052286c1" }, { "name": "lib/x86_64-linux-gnu/libmvec-2.24.so", "type": "reg", "size": 170464, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 5345904, "NumLink": 0, "digest": "sha256:0e8f744c1124445b8d71d510288887424f2a0e681fc327babb78d9520fe8015c" }, { "name": "lib/x86_64-linux-gnu/libmvec.so.1", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libmvec-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libncursesw.so.5", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "libncursesw.so.5.9", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libncursesw.so.5.9", "type": "reg", "size": 194480, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 5442329, "NumLink": 0, "digest": "sha256:e07d728762a9d3db0a3f914241133a0273b644c980476c5cae884f6198514cc4" }, { "name": "lib/x86_64-linux-gnu/libnsl-2.24.so", "type": "reg", "size": 89064, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 5533494, "NumLink": 0, "digest": "sha256:c27427576c4c2a418b1751e1a1b0b433d44e160be90955af78f8c95ad3d99ebc" }, { "name": "lib/x86_64-linux-gnu/libnsl.so.1", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libnsl-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libnss_compat-2.24.so", "type": "reg", "size": 31616, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 5573691, "NumLink": 0, "digest": "sha256:b20464e41de918df0a4d6a3654d6d4c7126a4691d640eea68e56512f2ee50b93" }, { "name": "lib/x86_64-linux-gnu/libnss_compat.so.2", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libnss_compat-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libnss_dns-2.24.so", "type": "reg", "size": 22928, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 5587677, "NumLink": 0, "digest": "sha256:c825dd0cf1e0fa3d1c6027fe98ef37ef160ee05463a72bac5752af304e9299c8" }, { "name": "lib/x86_64-linux-gnu/libnss_dns.so.2", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libnss_dns-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libnss_files-2.24.so", "type": "reg", "size": 47632, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 5598262, "NumLink": 0, "digest": "sha256:05e233e28d802968e27b3e4524f15813052f38fac4a53dff5bccee49cc3bcf77" }, { "name": "lib/x86_64-linux-gnu/libnss_files.so.2", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libnss_files-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libnss_hesiod-2.24.so", "type": "reg", "size": 18880, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 5616060, "NumLink": 0, "digest": "sha256:96093b7999357700ccacfa9ad5b6bc17e8fba3db65fb01009eb46940b215afe5" }, { "name": "lib/x86_64-linux-gnu/libnss_hesiod.so.2", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libnss_hesiod-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libnss_nis-2.24.so", "type": "reg", "size": 47688, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 5624293, "NumLink": 0, "digest": "sha256:8ba7bbfb7eba66e468c8349e1d55e52d3156b7c0dc67c8f22b24501f56d0f915" }, { "name": "lib/x86_64-linux-gnu/libnss_nis.so.2", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libnss_nis-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libnss_nisplus-2.24.so", "type": "reg", "size": 51736, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 5644935, "NumLink": 0, "digest": "sha256:c05d785888d0a7e72d6ccc12d245ccfc72b5ffa9797d266a7d749d117d87e84d" }, { "name": "lib/x86_64-linux-gnu/libnss_nisplus.so.2", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libnss_nisplus-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libpam.so.0", "type": "symlink", "modtime": "2017-05-27T15:44:02Z", "linkName": "libpam.so.0.83.1", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libpam.so.0.83.1", "type": "reg", "size": 56016, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 5667737, "NumLink": 0, "digest": "sha256:010b0a9d601fc5f020fbcea4e94fe406d15ed687b503f58d7aee4b5f6b436dd6" }, { "name": "lib/x86_64-linux-gnu/libpam_misc.so.0", "type": "symlink", "modtime": "2017-05-27T15:44:02Z", "linkName": "libpam_misc.so.0.82.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libpam_misc.so.0.82.0", "type": "reg", "size": 14640, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 5692744, "NumLink": 0, "digest": "sha256:cfa4eb5810c55bc5b3335531f0d5d1a8aacf8829983e22a55cc03dd91cf46b91" }, { "name": "lib/x86_64-linux-gnu/libpamc.so.0", "type": "symlink", "modtime": "2017-05-27T15:44:02Z", "linkName": "libpamc.so.0.82.1", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libpamc.so.0.82.1", "type": "reg", "size": 14640, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 5698007, "NumLink": 0, "digest": "sha256:143e37de8cb78d3d42f8ce5dd077026378c58e1aabca523039df185f6b83ef10" }, { "name": "lib/x86_64-linux-gnu/libpcprofile.so", "type": "reg", "size": 6328, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 5703762, "NumLink": 0, "digest": "sha256:3bf9a695f6ae82d14513ce4d620a62210d939579f725e68c6ee57771473bf09c" }, { "name": "lib/x86_64-linux-gnu/libpcre.so.3", "type": "symlink", "modtime": "2017-03-21T22:03:19Z", "linkName": "libpcre.so.3.13.3", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libpcre.so.3.13.3", "type": "reg", "size": 468920, "modtime": "2017-03-21T22:03:19Z", "mode": 33188, "offset": 5705959, "NumLink": 0, "digest": "sha256:8e472c698a67150907281f8ef307f1b4df3f32e8a993f4943abd8182898b7b17" }, { "name": "lib/x86_64-linux-gnu/libpthread-2.24.so", "type": "reg", "size": 135440, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 5886295, "NumLink": 0, "digest": "sha256:d54f396d38b23c1111e8912fbbb518404efa0af34f66249634bbcde601e41b1c" }, { "name": "lib/x86_64-linux-gnu/libpthread.so.0", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libpthread-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libresolv-2.24.so", "type": "reg", "size": 84848, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 5940730, "NumLink": 0, "digest": "sha256:4163c78a92525c3a541fc77988452a8ed5e9c7769f6414267fd0148a3514507f" }, { "name": "lib/x86_64-linux-gnu/libresolv.so.2", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libresolv-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/librt-2.24.so", "type": "reg", "size": 31744, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 5983664, "NumLink": 0, "digest": "sha256:df94214b7c10737895d7a46236eff917ad66687551b8ba3906f134e672b22380" }, { "name": "lib/x86_64-linux-gnu/librt.so.1", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "librt-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libselinux.so.1", "type": "reg", "size": 155400, "modtime": "2017-09-24T15:30:16Z", "mode": 33188, "offset": 5997619, "NumLink": 0, "digest": "sha256:3f284c04405d5f7f8015347718f31c0e6239886a7d5c02a2a1c6a4f408e8323e" }, { "name": "lib/x86_64-linux-gnu/libsepol.so.1", "type": "reg", "size": 623320, "modtime": "2016-12-03T23:19:56Z", "mode": 33188, "offset": 6072745, "NumLink": 0, "digest": "sha256:e1c8fb50dc88214875a37f46e21e486f1e092b00e3ad830889020c14e3a297cb" }, { "name": "lib/x86_64-linux-gnu/libsmartcols.so.1", "type": "symlink", "modtime": "2018-03-07T18:29:09Z", "linkName": "libsmartcols.so.1.1.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libsmartcols.so.1.1.0", "type": "reg", "size": 168040, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 6342649, "NumLink": 0, "digest": "sha256:6e723c7a681e702b349b2cd25949313e3e6c9d3aea240d5ccf445023d6592d16" }, { "name": "lib/x86_64-linux-gnu/libss.so.2", "type": "symlink", "modtime": "2017-02-01T00:54:55Z", "linkName": "libss.so.2.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libss.so.2.0", "type": "reg", "size": 26544, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 6418718, "NumLink": 0, "digest": "sha256:225f7393cfdee69acf4ba224b9ac1686a52c2bb8473dbf588aea74d84863d7c5" }, { "name": "lib/x86_64-linux-gnu/libsystemd.so.0", "type": "symlink", "modtime": "2018-06-13T20:20:36Z", "linkName": "libsystemd.so.0.17.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libsystemd.so.0.17.0", "type": "reg", "size": 557552, "modtime": "2018-06-13T20:20:36Z", "mode": 33188, "offset": 6428928, "NumLink": 0, "digest": "sha256:99c33261698212db4bef7bf5069641f963433ab92f3e87f8d1bf1103eabc1832" }, { "name": "lib/x86_64-linux-gnu/libthread_db-1.0.so", "type": "reg", "size": 35744, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 6681851, "NumLink": 0, "digest": "sha256:004d1374cc5a50f86616fb3047f18b099ad35b2eb8d563faaa63f872c28e50e3" }, { "name": "lib/x86_64-linux-gnu/libthread_db.so.1", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libthread_db-1.0.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libtinfo.so.5", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "libtinfo.so.5.9", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libtinfo.so.5.9", "type": "reg", "size": 170776, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 6695310, "NumLink": 0, "digest": "sha256:33626a82c73c983b4bd872e80cd9d8965eb6d985ac82d53fa1d3a21ccd4a2c27" }, { "name": "lib/x86_64-linux-gnu/libudev.so.1", "type": "symlink", "modtime": "2018-06-13T20:20:36Z", "linkName": "libudev.so.1.6.5", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libudev.so.1.6.5", "type": "reg", "size": 131344, "modtime": "2018-06-13T20:20:36Z", "mode": 33188, "offset": 6759287, "NumLink": 0, "digest": "sha256:7dd6fd6e3d6bfedc594900e40f9ba638144d4ba474de8a922501f5d19ab97a98" }, { "name": "lib/x86_64-linux-gnu/libutil-2.24.so", "type": "reg", "size": 10688, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 6818192, "NumLink": 0, "digest": "sha256:05d83744f7cc822e5f0cb7053f439f04318bb017b176b132ced2b19e5833ab24" }, { "name": "lib/x86_64-linux-gnu/libutil.so.1", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "libutil-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libuuid.so.1", "type": "symlink", "modtime": "2018-03-07T18:29:09Z", "linkName": "libuuid.so.1.3.0", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libuuid.so.1.3.0", "type": "reg", "size": 19008, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 6822485, "NumLink": 0, "digest": "sha256:d7a0fbf91d6863b57af26dd5199c2a27a2d1691b189fb9bebcabfb6e573324a3" }, { "name": "lib/x86_64-linux-gnu/libz.so.1", "type": "symlink", "modtime": "2017-01-29T17:22:23Z", "linkName": "libz.so.1.2.8", "mode": 41471, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/libz.so.1.2.8", "type": "reg", "size": 105088, "modtime": "2017-01-29T17:22:23Z", "mode": 33188, "offset": 6830261, "NumLink": 0, "digest": "sha256:7fd423a008f108094d410797edabbd5e3f28ec3110b0ee98fa7dee2b2c0426e3" }, { "name": "lib/x86_64-linux-gnu/security/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib/x86_64-linux-gnu/security/pam_access.so", "type": "reg", "size": 18680, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6887318, "NumLink": 0, "digest": "sha256:741b9d0308461abade6ca1ca9a5c12f68ae6e8e60bfc2c5114eeac658040886b" }, { "name": "lib/x86_64-linux-gnu/security/pam_debug.so", "type": "reg", "size": 10376, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6894624, "NumLink": 0, "digest": "sha256:ce1931f2608dc6b14204d3a883f5f54663d53163cc465fc0be38411493672dd3" }, { "name": "lib/x86_64-linux-gnu/security/pam_deny.so", "type": "reg", "size": 6000, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6897618, "NumLink": 0, "digest": "sha256:a22d25e07a233c0a410f215a9276fcc7c1d0996ce5d6a8354220dd241759e768" }, { "name": "lib/x86_64-linux-gnu/security/pam_echo.so", "type": "reg", "size": 10336, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6899273, "NumLink": 0, "digest": "sha256:0df400110557b2acc88b3cf4f7e4e467100a79940a86304921e7658690f74915" }, { "name": "lib/x86_64-linux-gnu/security/pam_env.so", "type": "reg", "size": 14536, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6902605, "NumLink": 0, "digest": "sha256:01fd00b9dec9fc67ad9fc5f3ee2b0fb67d5578bfddc1fc6aa1d6f8108974eb75" }, { "name": "lib/x86_64-linux-gnu/security/pam_exec.so", "type": "reg", "size": 14728, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6909166, "NumLink": 0, "digest": "sha256:1faa12207908abbd20e26bc5bd660b227204126f961c65b095588f962c3bb886" }, { "name": "lib/x86_64-linux-gnu/security/pam_faildelay.so", "type": "reg", "size": 10368, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6914974, "NumLink": 0, "digest": "sha256:ce49ccfdad0e09bd00861c3d1a527e9214689a70e49791ada68273ba4ef09ccd" }, { "name": "lib/x86_64-linux-gnu/security/pam_filter.so", "type": "reg", "size": 14576, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6917932, "NumLink": 0, "digest": "sha256:a3342745265703a761e19453c77cef5576c09b010cd3eeebf04df6b871234e54" }, { "name": "lib/x86_64-linux-gnu/security/pam_ftp.so", "type": "reg", "size": 10304, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6923870, "NumLink": 0, "digest": "sha256:b6fff572ca79d68c3079de5531730ebe229244593ed012619fe557c719502945" }, { "name": "lib/x86_64-linux-gnu/security/pam_group.so", "type": "reg", "size": 14616, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6926757, "NumLink": 0, "digest": "sha256:a55044f05f249a7bdaff776f5bbf367878910a1c8bb6166241a6b99f0c86dfae" }, { "name": "lib/x86_64-linux-gnu/security/pam_issue.so", "type": "reg", "size": 10448, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6932891, "NumLink": 0, "digest": "sha256:fb5f07a6e14baf75d91f3414077a34be5bb8df4fdec1b8c825a631b0c6ffea10" }, { "name": "lib/x86_64-linux-gnu/security/pam_keyinit.so", "type": "reg", "size": 10344, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6937095, "NumLink": 0, "digest": "sha256:5a69822d86f9a9c08640479fe827cd041f0b28ad1948e3ea9d39199d5dc7c31a" }, { "name": "lib/x86_64-linux-gnu/security/pam_lastlog.so", "type": "reg", "size": 14560, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6940594, "NumLink": 0, "digest": "sha256:94bc347d76d327016475c084a06654eeb16121aec0ff126c267ddfd63fabaeeb" }, { "name": "lib/x86_64-linux-gnu/security/pam_limits.so", "type": "reg", "size": 22944, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6947032, "NumLink": 0, "digest": "sha256:3ac02e973a5c9e2e2bb5f2f2061b3629f54993ba4302f80dff6a1ccf8636893c" }, { "name": "lib/x86_64-linux-gnu/security/pam_listfile.so", "type": "reg", "size": 10384, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6956584, "NumLink": 0, "digest": "sha256:54cefeadd3e76f9ea910689356f90941894692b33166466ff6a6ba8a6768430d" }, { "name": "lib/x86_64-linux-gnu/security/pam_localuser.so", "type": "reg", "size": 10312, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6960925, "NumLink": 0, "digest": "sha256:b0d353746e2325d6adc1393fad9a40f2e99746b0d925974e46f96d2466c6c87b" }, { "name": "lib/x86_64-linux-gnu/security/pam_loginuid.so", "type": "reg", "size": 10392, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6963675, "NumLink": 0, "digest": "sha256:976ed19a2598c14d89261041083d5b79598652d5d523b9a0270cf810be71a91f" }, { "name": "lib/x86_64-linux-gnu/security/pam_mail.so", "type": "reg", "size": 10376, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6967126, "NumLink": 0, "digest": "sha256:82a5741ea520b1ebc626dc0908f2a7597ec0a2237c4d2074d119d8fcb02a063f" }, { "name": "lib/x86_64-linux-gnu/security/pam_mkhomedir.so", "type": "reg", "size": 10376, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6971797, "NumLink": 0, "digest": "sha256:73fbb80cb6b9148628fe7a4b78bb9d24958856338f7916cd5726d6b889687bf7" }, { "name": "lib/x86_64-linux-gnu/security/pam_motd.so", "type": "reg", "size": 10360, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6975182, "NumLink": 0, "digest": "sha256:311d8406f3e0ff395b92fc9fbfc87ccfcea7951b3cb96ee04d560dbd00fe1e9d" }, { "name": "lib/x86_64-linux-gnu/security/pam_namespace.so", "type": "reg", "size": 39720, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6977918, "NumLink": 0, "digest": "sha256:51921e28f0808e3f784b886bc5cfc1cb9eb5e6ef6fc01f719c9befe92807e9a1" }, { "name": "lib/x86_64-linux-gnu/security/pam_nologin.so", "type": "reg", "size": 10328, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6995679, "NumLink": 0, "digest": "sha256:7ff14b70ef4bed07e3b8418e32f3263e67fc4b97ab867a632bf5ef51d36861ce" }, { "name": "lib/x86_64-linux-gnu/security/pam_permit.so", "type": "reg", "size": 6168, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 6998548, "NumLink": 0, "digest": "sha256:125d4284c78f6afb87ecb34601b75d599125156f581a06976930c960e962c1e6" }, { "name": "lib/x86_64-linux-gnu/security/pam_pwhistory.so", "type": "reg", "size": 14664, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7000544, "NumLink": 0, "digest": "sha256:9d0433c3cf7dff5334ca9feab51c2c959bef02f328bd1a6ecac1c7f83137116c" }, { "name": "lib/x86_64-linux-gnu/security/pam_rhosts.so", "type": "reg", "size": 10296, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7006689, "NumLink": 0, "digest": "sha256:ff008965f47c629c01acdeeca39430a64ba5eeee423569e76f49af30cd938036" }, { "name": "lib/x86_64-linux-gnu/security/pam_rootok.so", "type": "reg", "size": 10368, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7009385, "NumLink": 0, "digest": "sha256:659c269828c5fedf40139f7f50edc268192deec5b18ab37640c8d02e974b3ed1" }, { "name": "lib/x86_64-linux-gnu/security/pam_securetty.so", "type": "reg", "size": 10368, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7012344, "NumLink": 0, "digest": "sha256:ada92bbe998f2c513721676dc3ad5624f4968f33c202cb137387b706b6ffb899" }, { "name": "lib/x86_64-linux-gnu/security/pam_selinux.so", "type": "reg", "size": 18800, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7016176, "NumLink": 0, "digest": "sha256:cc0e5a04e98404c89b5417f7db0d15924b37d0f24661a929860be2a302950ae0" }, { "name": "lib/x86_64-linux-gnu/security/pam_sepermit.so", "type": "reg", "size": 14624, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7024413, "NumLink": 0, "digest": "sha256:84722b688949aefcb8d5d093a7253ab794a3af787b8eed1abd6df5bb1e63c929" }, { "name": "lib/x86_64-linux-gnu/security/pam_shells.so", "type": "reg", "size": 6216, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7029970, "NumLink": 0, "digest": "sha256:e8130cb3fac5f8bb3af5fc799765591cbcd4f257c16ec36adde8e2e9afd8c269" }, { "name": "lib/x86_64-linux-gnu/security/pam_stress.so", "type": "reg", "size": 14456, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7032470, "NumLink": 0, "digest": "sha256:e5968c6d25951ad2b75857e0f7952d2e070937afe23bba64f4f9692967e46093" }, { "name": "lib/x86_64-linux-gnu/security/pam_succeed_if.so", "type": "reg", "size": 14496, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7038360, "NumLink": 0, "digest": "sha256:800bcedbc816683381ec819c0b063260afadfc20547072b6fdfa34fe59f374fb" }, { "name": "lib/x86_64-linux-gnu/security/pam_tally.so", "type": "reg", "size": 14536, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7043619, "NumLink": 0, "digest": "sha256:5e4a5d92cca63d8d48d282200d73d6c7bc2e951176799c6f5b6924d11cff28e7" }, { "name": "lib/x86_64-linux-gnu/security/pam_tally2.so", "type": "reg", "size": 14576, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7049672, "NumLink": 0, "digest": "sha256:e4022de4f38434e19c4d7df37a64009cba2dbe4937616935b8547c7d4e8056d6" }, { "name": "lib/x86_64-linux-gnu/security/pam_time.so", "type": "reg", "size": 14584, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7056004, "NumLink": 0, "digest": "sha256:db7a38c09c845b85283618f8c5569f98de10475c6bb1f32fc21eae961e9acf6f" }, { "name": "lib/x86_64-linux-gnu/security/pam_timestamp.so", "type": "reg", "size": 18816, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7061595, "NumLink": 0, "digest": "sha256:220f806a68e43085e93f1041a1c30c31f5fb5c40967ccab3e60f0d5f6006240a" }, { "name": "lib/x86_64-linux-gnu/security/pam_tty_audit.so", "type": "reg", "size": 10360, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7070244, "NumLink": 0, "digest": "sha256:2c0b59ae3374776f52ecbb8359646bc1660a9e90e00fd6a524181788af655927" }, { "name": "lib/x86_64-linux-gnu/security/pam_umask.so", "type": "reg", "size": 10432, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7074204, "NumLink": 0, "digest": "sha256:fa93ee352ded717297820567c4060a511768322790f7b227284f8d6e77478a4e" }, { "name": "lib/x86_64-linux-gnu/security/pam_unix.so", "type": "reg", "size": 60336, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7077930, "NumLink": 0, "digest": "sha256:af89f5fbafa92beaa31acb1197efa72562ec0b5f633f3ed29211dfeb4e4bfa36" }, { "name": "lib/x86_64-linux-gnu/security/pam_userdb.so", "type": "reg", "size": 14512, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7104104, "NumLink": 0, "digest": "sha256:1b52f6baa4b37fa10c83acf9dab51cdb5cadcf26016a8926159460e4d11c3a0f" }, { "name": "lib/x86_64-linux-gnu/security/pam_warn.so", "type": "reg", "size": 6168, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7109253, "NumLink": 0, "digest": "sha256:579b9dd418f75343d13c850ade1166f5de83dd97cfa99bf04e2a79c0b544c479" }, { "name": "lib/x86_64-linux-gnu/security/pam_wheel.so", "type": "reg", "size": 10320, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7111509, "NumLink": 0, "digest": "sha256:3eb1b65ad1db5dcdbca14e261651021463b40f2988dbb3a90dde4a9dc884f42b" }, { "name": "lib/x86_64-linux-gnu/security/pam_xauth.so", "type": "reg", "size": 18992, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 7114599, "NumLink": 0, "digest": "sha256:7cf30ba8872ef595352d1e0ce316d0ba78476a57bda0dc4eaed265b9432a56e5" }, { "name": "lib64/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "lib64/ld-linux-x86-64.so.2", "type": "symlink", "modtime": "2018-01-14T10:39:44Z", "linkName": "/lib/x86_64-linux-gnu/ld-2.24.so", "mode": 41471, "NumLink": 0 }, { "name": "media/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "mnt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "opt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "proc/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "root/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16832, "NumLink": 0 }, { "name": "root/.bashrc", "type": "reg", "size": 570, "modtime": "2010-01-31T11:52:26Z", "mode": 33188, "offset": 7122808, "NumLink": 0, "digest": "sha256:41f1685d04031d88891dea1cd02d5154f8aa841119001a72017b0e7158159e23" }, { "name": "root/.profile", "type": "reg", "size": 148, "modtime": "2015-08-17T15:30:33Z", "mode": 33188, "offset": 7123253, "NumLink": 0, "digest": "sha256:74bc92bcf960bfb62b22aa65370cdd1cd37739baa4eab9b240d72692c898ef1f" }, { "name": "run/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "run/lock/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17407, "NumLink": 0 }, { "name": "run/utmp", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33204, "gid": 43, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "sbin/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "sbin/agetty", "type": "reg", "size": 57680, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7123549, "NumLink": 0, "digest": "sha256:6adcf14685980ef53a00b82359ade7cb3373f620e7bbe3e9100f5cb2ed53a5a3" }, { "name": "sbin/badblocks", "type": "reg", "size": 26632, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 7148884, "NumLink": 0, "digest": "sha256:6c22b8ac432d81bf31b3f443dbb2acc284a16ce094b95a61825752dee26c4c1c" }, { "name": "sbin/blkdiscard", "type": "reg", "size": 27264, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7161409, "NumLink": 0, "digest": "sha256:7ef233f2d7a23b1676923be2e0c55310cc648096b4ce268eb92454c02856f33d" }, { "name": "sbin/blkid", "type": "reg", "size": 85408, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7172442, "NumLink": 0, "digest": "sha256:b39bc5aa694d02a547bbe02a749ceb0fc141bc2956be48ac19d9056ca320c163" }, { "name": "sbin/blockdev", "type": "reg", "size": 35624, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7211380, "NumLink": 0, "digest": "sha256:7d832c9473c9718bf6a1d40f8cc6d61ab20c00f44dfb712d05c80dac22e3461c" }, { "name": "sbin/cfdisk", "type": "reg", "size": 90472, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7227436, "NumLink": 0, "digest": "sha256:1d3202ac1ca49497e274acdd85f85857a36d2299d47465e2bf2a0d92e0ceb57c" }, { "name": "sbin/chcpu", "type": "reg", "size": 23128, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7267991, "NumLink": 0, "digest": "sha256:85f7dae37c72adafd7db37f7bcfba4d6355f2203d5b1a656ee5c347c5a14a6e8" }, { "name": "sbin/ctrlaltdel", "type": "reg", "size": 19032, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7277888, "NumLink": 0, "digest": "sha256:bf5470d36f33cfac7e6d701cf2ce612a871c395300f99d19483cd44b743914af" }, { "name": "sbin/debugfs", "type": "reg", "size": 218624, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 7285732, "NumLink": 0, "digest": "sha256:453270d361f09f1a18159e97710d81e924fdb9d7ee55326f033a861dd4d8e618" }, { "name": "sbin/dumpe2fs", "type": "reg", "size": 26704, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 7378324, "NumLink": 0, "digest": "sha256:2e0450a263144ebef2fa6682593b70c49c096a02555d93ea45f2620b6588c0db" }, { "name": "sbin/e2fsck", "type": "reg", "size": 305696, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 7389192, "NumLink": 0, "digest": "sha256:5fe40e84f2369007c7102486a087ed8fd77df64354e2977de0c9316f050df99d" }, { "name": "sbin/e2image", "type": "reg", "size": 34896, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 7527447, "NumLink": 0, "digest": "sha256:5bd6c8600fa8decb1057bf9feb055dfb93432a34161fbfcff4c06c588e91217b" }, { "name": "sbin/e2label", "type": "symlink", "modtime": "2017-02-01T00:54:55Z", "linkName": "tune2fs", "mode": 41471, "NumLink": 0 }, { "name": "sbin/e2undo", "type": "reg", "size": 18504, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 7541953, "NumLink": 0, "digest": "sha256:78cf9a8072c1bd7295ccf39004203762468a3bdab1f154245892995b386ebb7a" }, { "name": "sbin/fdisk", "type": "reg", "size": 118056, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7548613, "NumLink": 0, "digest": "sha256:3cd2d0f2b7a9507e7d85cba7b07a149ce9fdf281d245853e5ea80c88e1a37c82" }, { "name": "sbin/findfs", "type": "reg", "size": 10568, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7599475, "NumLink": 0, "digest": "sha256:6627f4b74b0834856bc7c75b3df1a572b4e521405913847c9165121f56f78b19" }, { "name": "sbin/fsck", "type": "reg", "size": 48328, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7602969, "NumLink": 0, "digest": "sha256:fe5c55b3131424db749416881d406f69a909738f82a8cfe755179e82f9f0e255" }, { "name": "sbin/fsck.cramfs", "type": "reg", "size": 35680, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7624273, "NumLink": 0, "digest": "sha256:0ce71a2e669b3d146d603e72b853d8acc736246653c0e60ac008d3653b66e604" }, { "name": "sbin/fsck.ext2", "type": "symlink", "modtime": "2017-02-01T00:54:55Z", "linkName": "e2fsck", "mode": 41471, "NumLink": 0 }, { "name": "sbin/fsck.ext3", "type": "symlink", "modtime": "2017-02-01T00:54:55Z", "linkName": "e2fsck", "mode": 41471, "NumLink": 0 }, { "name": "sbin/fsck.ext4", "type": "symlink", "modtime": "2017-02-01T00:54:55Z", "linkName": "e2fsck", "mode": 41471, "NumLink": 0 }, { "name": "sbin/fsck.minix", "type": "reg", "size": 85088, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7640929, "NumLink": 0, "digest": "sha256:11a4a0da6c5136844f52674889dcf3a346469f5c06f952a6e11b653558d4f439" }, { "name": "sbin/fsfreeze", "type": "reg", "size": 10680, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7679365, "NumLink": 0, "digest": "sha256:19c8eb6b70d539642ba85ecdeb101926bff94585c3640d206f62797f01e4b7c1" }, { "name": "sbin/fstab-decode", "type": "reg", "size": 6352, "modtime": "2017-02-12T21:55:39Z", "mode": 33261, "offset": 7683720, "NumLink": 0, "digest": "sha256:2ffad77e711447254ed284248d3ba09af3a1448a29651080c1623ed243049c34" }, { "name": "sbin/fstrim", "type": "reg", "size": 43992, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7686161, "NumLink": 0, "digest": "sha256:2069a7cd4120fd53a7105dce987ab07c2428dc85cc16eaebfc7e6ce925cc615e" }, { "name": "sbin/getty", "type": "symlink", "modtime": "2018-03-07T18:29:09Z", "linkName": "agetty", "mode": 41471, "NumLink": 0 }, { "name": "sbin/hwclock", "type": "reg", "size": 64528, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7704830, "NumLink": 0, "digest": "sha256:deb501e34bd14fd38f60af8f4409fb53655845033f77bba564edc9d7f42e3b13" }, { "name": "sbin/initctl", "type": "reg", "size": 253, "modtime": "2018-10-11T00:00:00Z", "mode": 33261, "offset": 7734039, "NumLink": 0, "digest": "sha256:62d14f76b1641895a5ae24a7ea65eb26dd46dadb5ffd9ca356856530ebb822e1" }, { "name": "sbin/installkernel", "type": "reg", "size": 2638, "modtime": "2017-04-02T17:10:33Z", "mode": 33261, "offset": 7734314, "NumLink": 0, "digest": "sha256:ab0bedb106c10aa2c2ce88ca6bb9db1a973854049b36a9961a532c4496051815" }, { "name": "sbin/isosize", "type": "reg", "size": 23160, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 7735645, "NumLink": 0, "digest": "sha256:12d7d7cdfeb659bf7f652f9b0cbb6bd24b179b390ecb9222df3cd163eab63997" }, { "name": "sbin/killall5", "type": "reg", "size": 23224, "modtime": "2017-02-12T21:55:39Z", "mode": 33261, "offset": 7745675, "NumLink": 0, "digest": "sha256:a00fc547beaadb6ecb7496a8aa9e79c05c27e45a452fa179977d722de86daa90" }, { "name": "sbin/ldconfig", "type": "reg", "size": 881912, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 7755155, "NumLink": 0, "digest": "sha256:3285f67cbc98d087914ca23f176377383a40351bd36d92f988643b9f048d19c6" }, { "name": "sbin/logsave", "type": "reg", "size": 10240, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 8145697, "NumLink": 0, "digest": "sha256:c1dbb0bc743b753ff4fd705853d6943b7b8188c46ea28aa75ca0df2e8c22247a" }, { "name": "sbin/losetup", "type": "reg", "size": 81120, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8149804, "NumLink": 0, "digest": "sha256:68fa149ce22fb59c02ab0ec40ce05b9ea80d08056bf41cc8b386e287f7102d24" }, { "name": "sbin/mke2fs", "type": "reg", "size": 125248, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 8186566, "NumLink": 0, "digest": "sha256:9ced556c67781a6b31069438b3b9d5b499077dbd566317d4485d86a5256806fe" }, { "name": "sbin/mkfs", "type": "reg", "size": 10664, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8243659, "NumLink": 0, "digest": "sha256:69dc955885b589730049a14d6caafff16f0370951bab247a491fc37497138486" }, { "name": "sbin/mkfs.bfs", "type": "reg", "size": 31400, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8248092, "NumLink": 0, "digest": "sha256:9fb75647f280ab27b35c95f021a55545d6372c8e46f4b58ca2c0c77ceeff85ce" }, { "name": "sbin/mkfs.cramfs", "type": "reg", "size": 35456, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8260743, "NumLink": 0, "digest": "sha256:0e13447f68e32306467bf895234bf673fead8e633ce30c195d6d3f1db4469b6e" }, { "name": "sbin/mkfs.ext2", "type": "symlink", "modtime": "2017-02-01T00:54:55Z", "linkName": "mke2fs", "mode": 41471, "NumLink": 0 }, { "name": "sbin/mkfs.ext3", "type": "symlink", "modtime": "2017-02-01T00:54:55Z", "linkName": "mke2fs", "mode": 41471, "NumLink": 0 }, { "name": "sbin/mkfs.ext4", "type": "symlink", "modtime": "2017-02-01T00:54:55Z", "linkName": "mke2fs", "mode": 41471, "NumLink": 0 }, { "name": "sbin/mkfs.minix", "type": "reg", "size": 81016, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8278232, "NumLink": 0, "digest": "sha256:53b162d90a37217a12257d77ec8239b956e7784603ab1a269753e96592e0e3d4" }, { "name": "sbin/mkhomedir_helper", "type": "reg", "size": 18848, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 8315583, "NumLink": 0, "digest": "sha256:83450062779f8461cec78e65ce86265d6eff1875935ea1b3b9219af3261e0a94" }, { "name": "sbin/mkswap", "type": "reg", "size": 81144, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8320055, "NumLink": 0, "digest": "sha256:cd1950bdb7206435290914fb502c1bbd67776ec4f609bbf4d840bc93954a757d" }, { "name": "sbin/pam_tally", "type": "reg", "size": 10592, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 8355762, "NumLink": 0, "digest": "sha256:0f2e66063fecae11a818631269b535d57b75c1ed6d9ae02c42455fd17291e0e1" }, { "name": "sbin/pam_tally2", "type": "reg", "size": 14776, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 8360230, "NumLink": 0, "digest": "sha256:96e3830159176453765f5cccc56c53df9869c47750ae5783ba058dfdb6e4f59d" }, { "name": "sbin/pivot_root", "type": "reg", "size": 10640, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8365639, "NumLink": 0, "digest": "sha256:857da20329f563fff5253f774fc47615a2ba9ac236aefb06178d2a6bc3cf92af" }, { "name": "sbin/raw", "type": "reg", "size": 14784, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8369059, "NumLink": 0, "digest": "sha256:802c354e5487c50f1083fd1d14342d077c220234e41219c798e9bc288e8cd8b1" }, { "name": "sbin/resize2fs", "type": "reg", "size": 59464, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 8374050, "NumLink": 0, "digest": "sha256:0e3ef18176cfb7fe20a71c285ce425603ecb9c60a828e41e71c8d00656ba2cd1" }, { "name": "sbin/runuser", "type": "reg", "size": 31816, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8400304, "NumLink": 0, "digest": "sha256:440a23508224db42e4315796a4f8cbb88c613cd4735ea634de2b4eaaf6be3b2b" }, { "name": "sbin/sfdisk", "type": "reg", "size": 106656, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8413762, "NumLink": 0, "digest": "sha256:754823d46d2538d9eeb5f9859a989a6e757eace3b2e036334b2fb05a044a846a" }, { "name": "sbin/shadowconfig", "type": "reg", "size": 885, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 8460396, "NumLink": 0, "digest": "sha256:e456ba3088c0cb498ba86d9ce496273138e9cfe523feeb1a7e7083aae349dded" }, { "name": "sbin/start-stop-daemon", "type": "reg", "size": 31848, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 8460821, "NumLink": 0, "digest": "sha256:a8b2eaf2a3a97f5bcafe7ff1b84dc2157510ca38356b54c91f037d89f286fc10" }, { "name": "sbin/sulogin", "type": "reg", "size": 44208, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8474664, "NumLink": 0, "digest": "sha256:e0855820d16f2bc3f054c7e1be69c79800a9c96e6538b7fdc286e317a2bdbec4" }, { "name": "sbin/swaplabel", "type": "reg", "size": 14848, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8495674, "NumLink": 0, "digest": "sha256:7c87ea0de1cb075f4d811137106811c53af315eb89286f99d4fec05142c671af" }, { "name": "sbin/swapoff", "type": "reg", "size": 19104, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8500908, "NumLink": 0, "digest": "sha256:dcae8e64c12b6efb0de4ddfbb96ba7133fc3a2c109dac31b272b42ba95e55961" }, { "name": "sbin/swapon", "type": "reg", "size": 48488, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8507986, "NumLink": 0, "digest": "sha256:41683c62a58c1a5a718678d8bc38f69dd19e2ed19635dd8056126aafd57bda4c" }, { "name": "sbin/switch_root", "type": "reg", "size": 14800, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8528257, "NumLink": 0, "digest": "sha256:faea48ed6d9dafed493aa055914886c4b5bc6557af5d22242c9609816e5bfec0" }, { "name": "sbin/tune2fs", "type": "reg", "size": 100608, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 8533221, "NumLink": 0, "digest": "sha256:0879be617e4b224d9a560376ff1a3897d2f989f8ddd6a6bda090496cc10ee24a" }, { "name": "sbin/unix_chkpwd", "type": "reg", "size": 35592, "modtime": "2017-05-27T15:44:02Z", "mode": 34285, "gid": 42, "offset": 8578992, "NumLink": 0, "digest": "sha256:f2a80b648171dbdc98e867fb9fd54c5f03509a4eb475ee6e3c53b6f03908edb1" }, { "name": "sbin/unix_update", "type": "reg", "size": 35528, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 8593770, "NumLink": 0, "digest": "sha256:b15b766a76d7f947906478c52e9b6144585499cc3304e2bdffbadeadea8bba7b" }, { "name": "sbin/wipefs", "type": "reg", "size": 31536, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8608004, "NumLink": 0, "digest": "sha256:bfb983f08b7ac1ba294bab99e8162600b07f73eb4a89e69214390c3b6dd349cc" }, { "name": "sbin/zramctl", "type": "reg", "size": 93512, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8622200, "NumLink": 0, "digest": "sha256:367402816b433cd360b6038d50dc849736de44f4df104295907cb319ef6f3fce" }, { "name": "srv/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "sys/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "tmp/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17407, "NumLink": 0 }, { "name": "usr/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/bin/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/bin/[", "type": "reg", "size": 52008, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 8664038, "NumLink": 0, "digest": "sha256:d204b3e80ec8a1004e4fdb3a6a4f908ec5f267c0a28449cb95af9e1b69f2e572" }, { "name": "usr/bin/addpart", "type": "reg", "size": 23072, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8688508, "NumLink": 0, "digest": "sha256:412862f7dad64eb66e614d87cecf30359bda3896be474a54aada5c5d241af679" }, { "name": "usr/bin/apt", "type": "reg", "size": 14424, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 8697489, "NumLink": 0, "digest": "sha256:bf44404ddc8b2c0a38dfb3e1a9e6425d2ab8d8760b1a267d759b6b7db1e8da91" }, { "name": "usr/bin/apt-cache", "type": "reg", "size": 80032, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 8702450, "NumLink": 0, "digest": "sha256:e181fc48fa88009dab8c35cfe8f01fdf3958ecd92281e95aedbe0dd5910214cf" }, { "name": "usr/bin/apt-cdrom", "type": "reg", "size": 22688, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 8737321, "NumLink": 0, "digest": "sha256:9c694896977ab9e2ba656267c588970547ff76ebaf636b418fac3ef934effcbb" }, { "name": "usr/bin/apt-config", "type": "reg", "size": 22616, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 8746221, "NumLink": 0, "digest": "sha256:d122c30960616a613c979f9df23776eb226613badcb6d1af69b2ee0c516051ab" }, { "name": "usr/bin/apt-get", "type": "reg", "size": 43168, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 8755464, "NumLink": 0, "digest": "sha256:61e6dc14f653378466cfbc9504b3e34eeb6911878ae93a7477a6570ec169d241" }, { "name": "usr/bin/apt-key", "type": "reg", "size": 26269, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 8772706, "NumLink": 0, "digest": "sha256:945c55192dfc8dd7d55bd4f332943d3fd7107a64878512bdc26c2ddf0b044ff0" }, { "name": "usr/bin/apt-mark", "type": "reg", "size": 43168, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 8780858, "NumLink": 0, "digest": "sha256:bd5e981cdfaa500cb9753e62369e94c599f041c96c4c2f12c25f12cee0f0b5ef" }, { "name": "usr/bin/arch", "type": "reg", "size": 35592, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 8799713, "NumLink": 0, "digest": "sha256:e5895e2f65d872985b5a0c18e5b195fa1b94a8f6cd40e91e597d711b2e17bfd1" }, { "name": "usr/bin/awk", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/etc/alternatives/awk", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/b2sum", "type": "reg", "size": 56200, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 8814671, "NumLink": 0, "digest": "sha256:2ab02e2d0f12f71322da010a896b8937b6bb18427b2899e3b2e2ce214c38b1b2" }, { "name": "usr/bin/base32", "type": "reg", "size": 39720, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 8839271, "NumLink": 0, "digest": "sha256:40513e3c1d21c68a756fd4c14bfaa6ce686e61d242981c07b3f412d488504b20" }, { "name": "usr/bin/base64", "type": "reg", "size": 39720, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 8857666, "NumLink": 0, "digest": "sha256:ec4ba544c021045e3272a4bfd195fb2f047b27f61a45fe20f1f672a24637281f" }, { "name": "usr/bin/basename", "type": "reg", "size": 31464, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 8875974, "NumLink": 0, "digest": "sha256:b79987e26f5937e8a8122541488ef2e57eb2f0f68636fddc00db04c46c888558" }, { "name": "usr/bin/bashbug", "type": "reg", "size": 7120, "modtime": "2017-05-15T19:45:32Z", "mode": 33261, "offset": 8890872, "NumLink": 0, "digest": "sha256:2bf2c1619c223b4a5041b8319c275a0fbb0798114d320a4a58eff23f0b3a445b" }, { "name": "usr/bin/captoinfo", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "tic", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/catchsegv", "type": "reg", "size": 3302, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 8894112, "NumLink": 0, "digest": "sha256:8d4b393b1004e0e15bc9d7db1c83692d5e441551c9f254d0976210c4f9d49069" }, { "name": "usr/bin/chage", "type": "reg", "size": 71856, "modtime": "2017-05-17T11:59:59Z", "mode": 34285, "gid": 42, "offset": 8895804, "NumLink": 0, "digest": "sha256:1b4cdc81efd9aba0b4d3dd5a18c34f4573b3260074c785a2ec3494b3b7c73a18" }, { "name": "usr/bin/chattr", "type": "reg", "size": 14336, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 8924236, "NumLink": 0, "digest": "sha256:503f92590d4a6a65e284f5ad70606a2c3e80680a3b5439753b99341104145807" }, { "name": "usr/bin/chcon", "type": "reg", "size": 64520, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 8928860, "NumLink": 0, "digest": "sha256:68642e97d0d27f8f136c5893c885d8b590a9b1573c0f97dee223120da5b5fe3d" }, { "name": "usr/bin/chfn", "type": "reg", "size": 50040, "modtime": "2017-05-17T11:59:59Z", "mode": 35309, "offset": 8960141, "NumLink": 0, "digest": "sha256:c25505dbc0c17abb8d1bf59e64020c3ee0ca3ad4ccefe3a90480fa95cb574843" }, { "name": "usr/bin/chrt", "type": "reg", "size": 31496, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 8981024, "NumLink": 0, "digest": "sha256:f235546564c11de25611b61a607af7811220885f16cac017d8f9607d3089e2bf" }, { "name": "usr/bin/chsh", "type": "reg", "size": 40504, "modtime": "2017-05-17T11:59:59Z", "mode": 35309, "offset": 8994743, "NumLink": 0, "digest": "sha256:7ef5f2f8a8460950fa1a37736c226cdcc435d7bcf85e15ab90830ce445423b3d" }, { "name": "usr/bin/cksum", "type": "reg", "size": 35592, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 9011530, "NumLink": 0, "digest": "sha256:42b99d097670fab6cffa6b619276c5c0912912576759d22ee6af10c7bfc12e46" }, { "name": "usr/bin/clear", "type": "reg", "size": 6136, "modtime": "2017-12-28T09:47:33Z", "mode": 33261, "offset": 9027982, "NumLink": 0, "digest": "sha256:0efd2a25ce5ded9cc58e7d1913cbd2bc61f0d7dfacf73bea2138e1fe1f7f4070" }, { "name": "usr/bin/clear_console", "type": "reg", "size": 10552, "modtime": "2017-05-15T19:45:32Z", "mode": 33261, "offset": 9030096, "NumLink": 0, "digest": "sha256:8bff03727bb906a63497467f0e2352486613fa900e26df2a4091f950d3dfa9db" }, { "name": "usr/bin/cmp", "type": "reg", "size": 43768, "modtime": "2017-01-09T22:55:10Z", "mode": 33261, "offset": 9034088, "NumLink": 0, "digest": "sha256:ab79ce775431d53706e8986609129837341a9c44b2599302e44307d02f4be312" }, { "name": "usr/bin/comm", "type": "reg", "size": 39720, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 9055725, "NumLink": 0, "digest": "sha256:590005cf6262bc933fd5f15d29616a7405a801c246c49a724a407540e81001ec" }, { "name": "usr/bin/csplit", "type": "reg", "size": 48072, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 9073796, "NumLink": 0, "digest": "sha256:a0f6057870475b80a03ee78071dfd22df815b8ef6955a26e1021e59cddbbf84d" }, { "name": "usr/bin/cut", "type": "reg", "size": 43880, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 9096748, "NumLink": 0, "digest": "sha256:b69c459f0d6a3e85e7368f594d4e0bf622250cc57a13ff6c389de90fac84611e" }, { "name": "usr/bin/deb-systemd-helper", "type": "reg", "size": 20142, "modtime": "2017-05-02T10:20:21Z", "mode": 33261, "offset": 9116708, "NumLink": 0, "digest": "sha256:10b3c17c0f82dbf2e29ca3a8b353237fd198999c541599a5b48f44a00b180020" }, { "name": "usr/bin/deb-systemd-invoke", "type": "reg", "size": 4507, "modtime": "2017-05-02T10:20:21Z", "mode": 33261, "offset": 9123064, "NumLink": 0, "digest": "sha256:e96ed9793cf4bdeb41fe5990323d76b7b33cd950c53828b395e517377f9127f4" }, { "name": "usr/bin/debconf", "type": "reg", "size": 2859, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 9125100, "NumLink": 0, "digest": "sha256:d365d13eb1dff880be7361e4043d25875075776445d4edd1eb4fb1e451a2e41a" }, { "name": "usr/bin/debconf-apt-progress", "type": "reg", "size": 11541, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 9126558, "NumLink": 0, "digest": "sha256:93fb257df4185cc6b83858bdae3c7aec0a4f759a848c743a0b0fd7c7091cf34b" }, { "name": "usr/bin/debconf-communicate", "type": "reg", "size": 608, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 9129978, "NumLink": 0, "digest": "sha256:705b8ce793f999f21bf2f20348b390738a139116c9e483fb39165a508fde4d27" }, { "name": "usr/bin/debconf-copydb", "type": "reg", "size": 1719, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 9130436, "NumLink": 0, "digest": "sha256:085ff55904c81115d8d65f8862f0a5ad393e062da3047762e4d9cd4f5ba761f4" }, { "name": "usr/bin/debconf-escape", "type": "reg", "size": 647, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 9131309, "NumLink": 0, "digest": "sha256:6c17a536ca0fcefa24a7d37f7eaebc02e774415b3160836918cff6cecdef807d" }, { "name": "usr/bin/debconf-set-selections", "type": "reg", "size": 2935, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 9131786, "NumLink": 0, "digest": "sha256:8085a988bb9850fd9a3405c8a1f8e643c197811f6edf53dfc5ad20ef85040224" }, { "name": "usr/bin/debconf-show", "type": "reg", "size": 1827, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 9133035, "NumLink": 0, "digest": "sha256:9dd0bfe9a51d92af868012a32a8190b83a6f4b0834385d12033732b24ee2ceca" }, { "name": "usr/bin/delpart", "type": "reg", "size": 23072, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 9133931, "NumLink": 0, "digest": "sha256:0e5ebb3ec95a1cfb3cfea4356e1b5b356f052270bb3f29b41ae169cfab13eefd" }, { "name": "usr/bin/diff", "type": "reg", "size": 146824, "modtime": "2017-01-09T22:55:10Z", "mode": 33261, "offset": 9142851, "NumLink": 0, "digest": "sha256:f580a4abfc32cf085085e532b9d12477cb955879a4482cc2281e201ff3749343" }, { "name": "usr/bin/diff3", "type": "reg", "size": 60360, "modtime": "2017-01-09T22:55:10Z", "mode": 33261, "offset": 9214889, "NumLink": 0, "digest": "sha256:ceb327f5400a38a7e85021dddf454ed114c61c8472d703b8e61031c5ff20cba4" }, { "name": "usr/bin/dircolors", "type": "reg", "size": 43792, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 9244499, "NumLink": 0, "digest": "sha256:f735068729c48d617ddc88845342a191f46b5306ae2e358925f0d6ea71497175" }, { "name": "usr/bin/dirname", "type": "reg", "size": 31464, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 9265069, "NumLink": 0, "digest": "sha256:4a1a02e1267047c0a568b7f97c28ea351331e9a6aa035ec84fc6c85be0d1254f" }, { "name": "usr/bin/dpkg", "type": "reg", "size": 293376, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 9279590, "NumLink": 0, "digest": "sha256:f59b2bde8f707858160374c6d2c7929bc82737af4ec27a027c0e6c7f40902d04" }, { "name": "usr/bin/dpkg-deb", "type": "reg", "size": 149856, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 9410564, "NumLink": 0, "digest": "sha256:9a66f16b41551031cbee4f129339043770ad7d4eaf32f3842d672170c8acadb1" }, { "name": "usr/bin/dpkg-divert", "type": "reg", "size": 141728, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 9476405, "NumLink": 0, "digest": "sha256:c05f47fc6dbbc5109d2ceb9833ac1d751ed6203373a2a7b04dd00972d3768c8d" }, { "name": "usr/bin/dpkg-maintscript-helper", "type": "reg", "size": 19030, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 9539989, "NumLink": 0, "digest": "sha256:7183c0a85c8b309d97d6a9713b58fa4cfbbb2287404c1741f781f56b0c829a23" }, { "name": "usr/bin/dpkg-query", "type": "reg", "size": 149912, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 9544415, "NumLink": 0, "digest": "sha256:be6a64db2186874046a857578c6927ca09c82f2b0f28d33be035c25a6177cd78" }, { "name": "usr/bin/dpkg-split", "type": "reg", "size": 117080, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 9611851, "NumLink": 0, "digest": "sha256:fdcc92761a3390f7a5cd2a9e906daf8ffb5f50eeb3eb7ba781224fcf18ef401a" }, { "name": "usr/bin/dpkg-statoverride", "type": "reg", "size": 71936, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 9665324, "NumLink": 0, "digest": "sha256:f1f690ef016f4e17b0aa8df4ebbe303dd908c24ef3475418abecc774be00c22e" }, { "name": "usr/bin/dpkg-trigger", "type": "reg", "size": 67848, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 9696355, "NumLink": 0, "digest": "sha256:d1eb6b4ef3af26b32852e8d2beda588fc1f5ad8713bbd58c63d4f20cd5853aa8" }, { "name": "usr/bin/du", "type": "reg", "size": 105640, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 9725993, "NumLink": 0, "digest": "sha256:62c8fd7bcf8cb3fe6426105f997aa5334b4a5a99bbea189506571fe305d34447" }, { "name": "usr/bin/env", "type": "reg", "size": 31496, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 9778101, "NumLink": 0, "digest": "sha256:9e41c33c216856b3f975d8442e782e78497d157b2aa099189a7c8c44ce069b03" }, { "name": "usr/bin/expand", "type": "reg", "size": 35624, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 9792776, "NumLink": 0, "digest": "sha256:2357a0c300183ddda4b593ad4ecf639c6e8e0353ba13af1b980420ecd3d0df77" }, { "name": "usr/bin/expiry", "type": "reg", "size": 22808, "modtime": "2017-05-17T11:59:59Z", "mode": 34285, "gid": 42, "offset": 9808891, "NumLink": 0, "digest": "sha256:e7e79217ef4aab5c4e1fc12ab6487333e1398572d0b62e57341ed9bac78a0f27" }, { "name": "usr/bin/expr", "type": "reg", "size": 43848, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 9818087, "NumLink": 0, "digest": "sha256:824957efaf21e1e78bee63a4da3ee2d9ad64f8ee8b0a03d6d88b2e254c65c259" }, { "name": "usr/bin/factor", "type": "reg", "size": 76680, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 9837814, "NumLink": 0, "digest": "sha256:d86bcbd395838672f0bde8b3cfb5c049028e925ffa94eb02ca684d0188f8931f" }, { "name": "usr/bin/faillog", "type": "reg", "size": 18728, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 9880668, "NumLink": 0, "digest": "sha256:4b1386c2f119271d3c3771a9b9d37975f695c44fa84fca4d7e1460a5c9a8747c" }, { "name": "usr/bin/fallocate", "type": "reg", "size": 27280, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 9887976, "NumLink": 0, "digest": "sha256:9101a2ce5c3936bde40dce3b92116b8cdc1b9adfd3553f45aff9048e1c4d4812" }, { "name": "usr/bin/find", "type": "reg", "size": 221768, "modtime": "2017-02-18T15:37:32Z", "mode": 33261, "offset": 9899287, "NumLink": 0, "digest": "sha256:97c94127488a66250e93cf93f475258910992f160e222166aa5c2a7890410b62" }, { "name": "usr/bin/flock", "type": "reg", "size": 27432, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10003466, "NumLink": 0, "digest": "sha256:a711e2146884827b952e586809a51522f4aadc27396d0e23a1f22dab91ab4843" }, { "name": "usr/bin/fmt", "type": "reg", "size": 39720, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 10015776, "NumLink": 0, "digest": "sha256:e13ee863ebaf2e03d0390430c42236c8f07a3c204fc4ae225b8a48d98a18fb1f" }, { "name": "usr/bin/fold", "type": "reg", "size": 35624, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 10035417, "NumLink": 0, "digest": "sha256:dd7b3f381567876171d71316d5dc5a56b096b5cac07d0eca22c1ba0f880744ae" }, { "name": "usr/bin/getconf", "type": "reg", "size": 22904, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 10051803, "NumLink": 0, "digest": "sha256:bb1ed5c8b5f0df1aa51624ddb6996ed0e70cfe85d07189384a4e4f6cee7032dd" }, { "name": "usr/bin/getent", "type": "reg", "size": 23872, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 10059112, "NumLink": 0, "digest": "sha256:4cb3a246795c58c1134e0b6ce2abfb4db667b6d517b687a8a782ce369f1ede7f" }, { "name": "usr/bin/getopt", "type": "reg", "size": 14840, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10068699, "NumLink": 0, "digest": "sha256:73c12040481a67e5a4be643d6fb0438383e20bf03a15bd08973150463ed7d394" }, { "name": "usr/bin/gpasswd", "type": "reg", "size": 75792, "modtime": "2017-05-17T11:59:59Z", "mode": 35309, "offset": 10075055, "NumLink": 0, "digest": "sha256:d92f083fc7a6638ee7a3203e7e55de3bf0e539e3f5849e8cb5644a12f1d65698" }, { "name": "usr/bin/gpgv", "type": "reg", "size": 420496, "modtime": "2018-06-08T18:12:24Z", "mode": 33261, "offset": 10106103, "NumLink": 0, "digest": "sha256:0948d08c3939b9060186cf5cc5337f1c4ac6752bda5b80c5bdb2fd1c4a517886" }, { "name": "usr/bin/groups", "type": "reg", "size": 35624, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 10321770, "NumLink": 0, "digest": "sha256:acc452e8dab94df9262cd81258c97fbf0f319418bd90c33ecc3a5cbdf72a20bf" }, { "name": "usr/bin/head", "type": "reg", "size": 43848, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 10337294, "NumLink": 0, "digest": "sha256:a6469ce6901c72f2d80b27e637998d0894adfa5468b812d74aca74e6f2837153" }, { "name": "usr/bin/hostid", "type": "reg", "size": 31464, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 10357448, "NumLink": 0, "digest": "sha256:d436a899df1651fa756a3dc8af940333c331315c10e55642d06f4e211798ac5b" }, { "name": "usr/bin/i386", "type": "symlink", "modtime": "2018-03-07T18:29:09Z", "linkName": "setarch", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/iconv", "type": "reg", "size": 56328, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 10371529, "NumLink": 0, "digest": "sha256:2139423a0d8c34211eee59501ac82f6420a08aeaf4d4118b87c9551fecee6aa0" }, { "name": "usr/bin/id", "type": "reg", "size": 43944, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 10397042, "NumLink": 0, "digest": "sha256:a88307cf73282e6b7aa985eccb065711323674e1484a8754103b7254d058baa6" }, { "name": "usr/bin/infocmp", "type": "reg", "size": 59464, "modtime": "2017-12-28T09:47:33Z", "mode": 33261, "offset": 10416302, "NumLink": 0, "digest": "sha256:3ebb18b167aa6b5c798174adb9b5e706ba65b37dbe3a6ac8b56f387db11c595d" }, { "name": "usr/bin/infotocap", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "tic", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/install", "type": "reg", "size": 138864, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 10444204, "NumLink": 0, "digest": "sha256:51522c627f0a50ef871c35c81b8a4f1d153e4cc7e2df8357abf3681693af72d8" }, { "name": "usr/bin/ionice", "type": "reg", "size": 27304, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10512302, "NumLink": 0, "digest": "sha256:0b23a47f4e71dc982bad25d3284e61f42b29ee2d99a413c89ee41a57c3dfccdb" }, { "name": "usr/bin/ipcmk", "type": "reg", "size": 27416, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10523063, "NumLink": 0, "digest": "sha256:734a8697d86f4689634039981c11637d69856738a5d27c3c08338b3883a2adab" }, { "name": "usr/bin/ipcrm", "type": "reg", "size": 27264, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10533925, "NumLink": 0, "digest": "sha256:ddaf50c3a72c430630693ce22f3c489feff0b9fefd0deb58eec8dab46a04f1c7" }, { "name": "usr/bin/ipcs", "type": "reg", "size": 52008, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10545492, "NumLink": 0, "digest": "sha256:b1ff7436abc1fed72b616367f7aae26632bbf2ac81591888dd987a5c7f909d00" }, { "name": "usr/bin/ischroot", "type": "reg", "size": 10552, "modtime": "2017-04-02T17:10:33Z", "mode": 33261, "offset": 10567108, "NumLink": 0, "digest": "sha256:70a15af1786a0de15ea8fc910b203d38b98790ae43df5efdd24534a51f358b47" }, { "name": "usr/bin/join", "type": "reg", "size": 47976, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 10570592, "NumLink": 0, "digest": "sha256:97469b77f991fce4f29ffaed18dac01e5d8b7559aab02d87a39580244599a03c" }, { "name": "usr/bin/last", "type": "reg", "size": 43880, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10592860, "NumLink": 0, "digest": "sha256:1dd54f2f90d9ba5d7b60c8a0e458606a6e38dbcda4c02dd7123402ff3c640358" }, { "name": "usr/bin/lastb", "type": "symlink", "modtime": "2018-03-07T18:29:09Z", "linkName": "last", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/lastlog", "type": "reg", "size": 18504, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 10612362, "NumLink": 0, "digest": "sha256:57eb32f4479e2b6c49780d6b6bb7c84bd96c1c8b28565d97d8e45eeab2138e91" }, { "name": "usr/bin/ldd", "type": "reg", "size": 5395, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 10619060, "NumLink": 0, "digest": "sha256:8fe75b6fdfdb63c4cb7710f4599a240a8e9d74b49f7b4354f00852afbb815a8d" }, { "name": "usr/bin/line", "type": "reg", "size": 10648, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10621531, "NumLink": 0, "digest": "sha256:53c72b327830b2a6a769336fff7a957976127f3be818fa13b76023eccbf5f8ba" }, { "name": "usr/bin/link", "type": "reg", "size": 31464, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 10624948, "NumLink": 0, "digest": "sha256:ad85507f80593524834b45e173e6c7d25edef521b09388890cb2237480b0972c" }, { "name": "usr/bin/linux32", "type": "symlink", "modtime": "2018-03-07T18:29:09Z", "linkName": "setarch", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/linux64", "type": "symlink", "modtime": "2018-03-07T18:29:09Z", "linkName": "setarch", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/locale", "type": "reg", "size": 38824, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 10639221, "NumLink": 0, "digest": "sha256:8014cd1cc08fe903a26756458680e5b3d5cdda67e77f35b35553ba2366b1bf8d" }, { "name": "usr/bin/localedef", "type": "reg", "size": 302784, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 10654128, "NumLink": 0, "digest": "sha256:7897c88201f7e4b01a8f37578c79375e0d013005d3729bde488b3ca12826dc40" }, { "name": "usr/bin/logger", "type": "reg", "size": 44472, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10787530, "NumLink": 0, "digest": "sha256:b39fdf305c3a2778a1c016ca4551d468707492597e5e8886cf6ecf0039f4f62c" }, { "name": "usr/bin/logname", "type": "reg", "size": 31464, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 10808065, "NumLink": 0, "digest": "sha256:a58a0693abd829aeb1da6f21723bdc9f27a23f2ee5e7b8b9e493a56144d5808e" }, { "name": "usr/bin/lsattr", "type": "reg", "size": 10240, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 10822124, "NumLink": 0, "digest": "sha256:d0098d84be8685553ffb2e2a07aebb771e1ce6fc9362a549a0b1e9c8c8e199d4" }, { "name": "usr/bin/lscpu", "type": "reg", "size": 64712, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10825931, "NumLink": 0, "digest": "sha256:a9509ab607c61d6bcba57ca47556b8cbbec51d75d1a8c9b083a9e92f79140c29" }, { "name": "usr/bin/lsipc", "type": "reg", "size": 72824, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10854951, "NumLink": 0, "digest": "sha256:e5806384fb3b1d5c58521098a382a534a909de3f892ef6f28135ecdc29826946" }, { "name": "usr/bin/lslocks", "type": "reg", "size": 36008, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10885523, "NumLink": 0, "digest": "sha256:5353616c18ffc2a8e0e60f5c02edad6e4448484d70a5c47d9621f5ed0cf00a66" }, { "name": "usr/bin/lslogins", "type": "reg", "size": 60696, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10900854, "NumLink": 0, "digest": "sha256:ffb8b19b306970bde5485c3bcee17303a7615287ce4d688b16edb9ed034827a5" }, { "name": "usr/bin/lsns", "type": "reg", "size": 39800, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 10927568, "NumLink": 0, "digest": "sha256:17501abd11ecc79d079aac38ba9ebff3bc3f152c76983f90686abe714c69d26b" }, { "name": "usr/bin/mawk", "type": "reg", "size": 121976, "modtime": "2012-03-23T20:15:00Z", "mode": 33261, "offset": 10945121, "NumLink": 0, "digest": "sha256:3f791f82e19d9723c55fe3fb70e85a19c1663e5b76936293fe75070667a42cba" }, { "name": "usr/bin/mcookie", "type": "reg", "size": 31528, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 11005973, "NumLink": 0, "digest": "sha256:3b0404268fc5504d4e9bd525a1848ccb92b6a81915f2756575531e6297864872" }, { "name": "usr/bin/md5sum", "type": "reg", "size": 43880, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 11019661, "NumLink": 0, "digest": "sha256:08c9ecb479710c1a5f548bf48b722c7ef03054a1741116ae0794df49a5fbb9d4" }, { "name": "usr/bin/md5sum.textutils", "type": "symlink", "modtime": "2017-02-22T12:23:45Z", "linkName": "md5sum", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/mesg", "type": "reg", "size": 10704, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 11041129, "NumLink": 0, "digest": "sha256:92c01c7ebdbbf0a99a01dff02ee410ba617217ae9eeabe30745f9e82b0429593" }, { "name": "usr/bin/mkfifo", "type": "reg", "size": 64552, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 11045233, "NumLink": 0, "digest": "sha256:6128655aea11b8cd2b24737829c22a3849d3ba76f2ed2c272c44989a595b43c9" }, { "name": "usr/bin/namei", "type": "reg", "size": 27296, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 11076521, "NumLink": 0, "digest": "sha256:0d687cece51a5f5dec3f16e9471fbc069601e31a922e419aa5bb6f46848d2aec" }, { "name": "usr/bin/nawk", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/etc/alternatives/nawk", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/newgrp", "type": "reg", "size": 40312, "modtime": "2017-05-17T11:59:59Z", "mode": 35309, "offset": 11088866, "NumLink": 0, "digest": "sha256:6fe1acc3cde9a01dd79aea6295ade4f77a6bb409f16a8fc0e807f7b26a9ad7f7" }, { "name": "usr/bin/nice", "type": "reg", "size": 35592, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 11104827, "NumLink": 0, "digest": "sha256:02174675c94855def605d70484e0c5a9d41b97ca4d9188ed1f2e702147122068" }, { "name": "usr/bin/nl", "type": "reg", "size": 39848, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 11120628, "NumLink": 0, "digest": "sha256:8fa1c7f0a5b967d98e52f57641b3ab7a60a2e30b6dd3e59c1ec02f7e43d536e8" }, { "name": "usr/bin/nohup", "type": "reg", "size": 35624, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 11139298, "NumLink": 0, "digest": "sha256:4a5834965b06e51bfbcb33014d6bf4710b658a4d66840f27d38508ea9b539ca4" }, { "name": "usr/bin/nproc", "type": "reg", "size": 35624, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 11155576, "NumLink": 0, "digest": "sha256:404890e77c1e568eff323f84b85705d509c87e9e9e3ce2d67fd45dbcd946abf1" }, { "name": "usr/bin/nsenter", "type": "reg", "size": 31688, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 11171258, "NumLink": 0, "digest": "sha256:d89feb89c37c671d6eea65992a70a5ef85f390f8e0e9bc3005f53a90a767ce4d" }, { "name": "usr/bin/numfmt", "type": "reg", "size": 60328, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 11183908, "NumLink": 0, "digest": "sha256:bcd656bdcb3dd092b8cd04a40491857d5b044efbb6411c372ab155519da35c39" }, { "name": "usr/bin/od", "type": "reg", "size": 68520, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 11212554, "NumLink": 0, "digest": "sha256:68d5ef1443988c44a6a9159bcf5eda795978946e659e90c281d09e4f29742e84" }, { "name": "usr/bin/pager", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/etc/alternatives/pager", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/partx", "type": "reg", "size": 85640, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 11244752, "NumLink": 0, "digest": "sha256:65f2986421a88eecdcb04485e359f3c09f48374c74f728c1a156b86a75cec20c" }, { "name": "usr/bin/passwd", "type": "reg", "size": 59680, "modtime": "2017-05-17T11:59:59Z", "mode": 35309, "offset": 11282891, "NumLink": 0, "digest": "sha256:1e22ec1a89d852c8429353ea8bb416e83f5b5eefdbceabd26df81e019bc8f1a8" }, { "name": "usr/bin/paste", "type": "reg", "size": 35624, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 11305777, "NumLink": 0, "digest": "sha256:ebfd11891eaf4bf1714e6368a543c70b49bb141ba9f42f49913ad899792b3352" }, { "name": "usr/bin/pathchk", "type": "reg", "size": 31496, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 11322087, "NumLink": 0, "digest": "sha256:2e44afffe8aeaca8c8377f5f26498f6a14d296d97a6c3c3a91c8fd6442bf54ea" }, { "name": "usr/bin/perl", "type": "reg", "size": 2021960, "modtime": "2018-06-10T17:37:28Z", "mode": 33261, "offset": 11337229, "NumLink": 0, "digest": "sha256:d1a8fc5e7ee0803534d6ac82d69293969a6ce78f20f201d7ddb175ad67b0da66" }, { "name": "usr/bin/perl5.24.1", "type": "hardlink", "modtime": "2018-06-10T17:37:28Z", "linkName": "usr/bin/perl", "mode": 33261, "NumLink": 0 }, { "name": "usr/bin/pg", "type": "reg", "size": 39824, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 12240511, "NumLink": 0, "digest": "sha256:e779778855282c0cb23bd2d23734537fe24761f7d15e2657114fadc77dc62e4a" }, { "name": "usr/bin/pinky", "type": "reg", "size": 39880, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12260132, "NumLink": 0, "digest": "sha256:bd141bf418442f9ba531d33f7cb745e0abf1f1e1e27f798a03d97b46efb85399" }, { "name": "usr/bin/pldd", "type": "reg", "size": 14920, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 12277950, "NumLink": 0, "digest": "sha256:d31f258fbf6377e98c9ffa230938692851303aed1b16763d28c04dcf2b5cc73e" }, { "name": "usr/bin/pr", "type": "reg", "size": 76808, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12284291, "NumLink": 0, "digest": "sha256:0e46076a45a96c94edc03b37b5f1e02584adb923202a403af38b214f80e05d5c" }, { "name": "usr/bin/printenv", "type": "reg", "size": 31464, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12320488, "NumLink": 0, "digest": "sha256:40b3aa6167ac603d66811e1361b6ca8504f4d0502ba33a304af23f9c5c4c3640" }, { "name": "usr/bin/printf", "type": "reg", "size": 52008, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12334770, "NumLink": 0, "digest": "sha256:8ccb2aa21eae8183c2a456c22938f8f2fad5f5a8a599091e8bd4c3e147a245de" }, { "name": "usr/bin/prlimit", "type": "reg", "size": 32136, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 12359026, "NumLink": 0, "digest": "sha256:1c2bb9d71566f9503d007356cb588347a79f4a452684f2f7e08b378206b573c9" }, { "name": "usr/bin/ptx", "type": "reg", "size": 72712, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12373085, "NumLink": 0, "digest": "sha256:2e52751b9d00810563e72af922413a61560ee26050add0289a9f3d5f705e397f" }, { "name": "usr/bin/realpath", "type": "reg", "size": 47944, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12408010, "NumLink": 0, "digest": "sha256:47bb43b6a5b8e17deb9e88f9b7969043196805aedcf4c9853ed89c67909a78ad" }, { "name": "usr/bin/rename.ul", "type": "reg", "size": 14824, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 12429787, "NumLink": 0, "digest": "sha256:cef334521baa2145e7b86d4386b7df1a65ccb83178ca215617c6e8dd0655b75e" }, { "name": "usr/bin/renice", "type": "reg", "size": 10608, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 12434769, "NumLink": 0, "digest": "sha256:b082856233958a9c9e442c33d029aec9f7c6453e3d2d748c43da904925607393" }, { "name": "usr/bin/reset", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "tset", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/resizepart", "type": "reg", "size": 39792, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 12439364, "NumLink": 0, "digest": "sha256:08a76a3919d9a3c73c8ca880d1c22176db459a43fed3eba8a6f8dd0e504dac0e" }, { "name": "usr/bin/rev", "type": "reg", "size": 10704, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 12456239, "NumLink": 0, "digest": "sha256:369b529387fb569d8547e1862849f4ddcd18ce83a106a7c4649eba53df24679c" }, { "name": "usr/bin/rgrep", "type": "reg", "size": 30, "modtime": "2016-11-28T21:59:51Z", "mode": 33261, "offset": 12460356, "NumLink": 0, "digest": "sha256:0a8dd42a068115f058ae57f9f6347e1ef0ae2ffea89bf658b132974246577748" }, { "name": "usr/bin/runcon", "type": "reg", "size": 35688, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12460484, "NumLink": 0, "digest": "sha256:596b31f310c95629556e2c5fdc8d81ab224546b58cc4813a814b91ca5e18ebd2" }, { "name": "usr/bin/savelog", "type": "reg", "size": 10469, "modtime": "2017-04-02T17:10:33Z", "mode": 33261, "offset": 12476468, "NumLink": 0, "digest": "sha256:b5a489fb4c7a5e1240384e25ac3ff8de31e0456a3439fd7ad0ae28fda777c5db" }, { "name": "usr/bin/script", "type": "reg", "size": 23272, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 12480189, "NumLink": 0, "digest": "sha256:d0159b8f03fe657f228f1a43559560332dda855e2eee2840d2c4ba48c3345d4f" }, { "name": "usr/bin/scriptreplay", "type": "reg", "size": 23168, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 12490349, "NumLink": 0, "digest": "sha256:1be86c1360ddfac0d4b01829dedf1f8b65900ed5dd279dfbec58e88ab408b235" }, { "name": "usr/bin/sdiff", "type": "reg", "size": 52072, "modtime": "2017-01-09T22:55:10Z", "mode": 33261, "offset": 12500871, "NumLink": 0, "digest": "sha256:146843c271e78b0736e78fc3ffd0bb45ca7c49c03c70c85ea57f91dad0e9a0e7" }, { "name": "usr/bin/select-editor", "type": "reg", "size": 1215, "modtime": "2017-12-20T13:39:04Z", "mode": 33261, "offset": 12524172, "NumLink": 0, "digest": "sha256:41184f27a957f4a6091f9e9959a3888323059c3a97c273ae0a6c3bc98bfc4fd2" }, { "name": "usr/bin/sensible-browser", "type": "reg", "size": 1138, "modtime": "2017-12-20T13:39:04Z", "mode": 33261, "offset": 12524817, "NumLink": 0, "digest": "sha256:535567fc55d7b0e4a893b2c0e27306848115c1a68f4e70a0730005a52df7da2d" }, { "name": "usr/bin/sensible-editor", "type": "reg", "size": 1109, "modtime": "2017-12-20T13:39:04Z", "mode": 33261, "offset": 12525289, "NumLink": 0, "digest": "sha256:e0c6affda06feb37dfe1342d7062bb9110c3e84709e461ac8632ade024d70aac" }, { "name": "usr/bin/sensible-pager", "type": "reg", "size": 288, "modtime": "2017-12-20T13:39:04Z", "mode": 33261, "offset": 12525822, "NumLink": 0, "digest": "sha256:0a691103beee994a548bf309f201a42f3756311a3fdefd93df7c633afbe7052f" }, { "name": "usr/bin/seq", "type": "reg", "size": 47944, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12526085, "NumLink": 0, "digest": "sha256:775eae051ea6ceb32f30651279aa482f780f0dcc6bd73e0fa06579d89f88e031" }, { "name": "usr/bin/setarch", "type": "reg", "size": 19184, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 12549367, "NumLink": 0, "digest": "sha256:c1e5f4eca6af935fa2458c9947ed0f727a8d04e6fcc7252acc08c040ccf40b4d" }, { "name": "usr/bin/setsid", "type": "reg", "size": 10696, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 12555490, "NumLink": 0, "digest": "sha256:fe4630dc8f7c730d74825519c9119dd8becee95e526575607be1c212938bfdde" }, { "name": "usr/bin/setterm", "type": "reg", "size": 39608, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 12559504, "NumLink": 0, "digest": "sha256:7f4270fcb6ea0734cbcfc81076c4047047d7d6a8a4ee20e9edc76e469dad658f" }, { "name": "usr/bin/sg", "type": "symlink", "modtime": "2017-05-17T11:59:59Z", "linkName": "newgrp", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/sha1sum", "type": "reg", "size": 47976, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12576304, "NumLink": 0, "digest": "sha256:bdfb66ff9f531063976ccecd408857c52cc4dbf5f7db36724877d332a331f482" }, { "name": "usr/bin/sha224sum", "type": "reg", "size": 56168, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12599391, "NumLink": 0, "digest": "sha256:bf49bc5ae0f5057a1a7d6568f34573015185c2b127ff466e5314a1a97f396164" }, { "name": "usr/bin/sha256sum", "type": "reg", "size": 56168, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12626948, "NumLink": 0, "digest": "sha256:355dc2076bf6973fdba060a8a8a98eaa8a04d6a49cdd11bc563dfcb9d650f305" }, { "name": "usr/bin/sha384sum", "type": "reg", "size": 60264, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12654510, "NumLink": 0, "digest": "sha256:c483a60f508e8bee6102250371a4f11ca9d2665e8d8c2d386ad67b1352c3492b" }, { "name": "usr/bin/sha512sum", "type": "reg", "size": 60264, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12685023, "NumLink": 0, "digest": "sha256:e7443c21507f7a316189c7af20aa4e7c358b0fcce4d183f22e7df623359ffd39" }, { "name": "usr/bin/shred", "type": "reg", "size": 60424, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12715542, "NumLink": 0, "digest": "sha256:3693d8c295f3bacd02c57cfdd0ad7b392864585ed61871d88b1fe77e7c8a2909" }, { "name": "usr/bin/shuf", "type": "reg", "size": 56232, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12744060, "NumLink": 0, "digest": "sha256:88f6ead25d1a76f00e7d328d22b9088381f04c74638638a863e12f39faa5e5ce" }, { "name": "usr/bin/sort", "type": "reg", "size": 110096, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12770058, "NumLink": 0, "digest": "sha256:bb7b7d5d1d8824b053fb59a5e95d753069231ae21a483ba4fa86a4c98559b748" }, { "name": "usr/bin/split", "type": "reg", "size": 56712, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12825908, "NumLink": 0, "digest": "sha256:e6c4f385cc62429ee05d25c137e9f631be98012bac82e21b98b9513e245cf7e8" }, { "name": "usr/bin/stat", "type": "reg", "size": 85096, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12851880, "NumLink": 0, "digest": "sha256:dfe514438c4c69953459973a11aa85d26f6cb7754f85c9bc0a86b21e7275c094" }, { "name": "usr/bin/stdbuf", "type": "reg", "size": 47944, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12893340, "NumLink": 0, "digest": "sha256:270c6288a4675c11c5b4aa488987b330a323beb33d8f220f44d41f085e0d2cbe" }, { "name": "usr/bin/sum", "type": "reg", "size": 39760, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12915966, "NumLink": 0, "digest": "sha256:27acd7e71844d21ac757361f299fcdf2271ff52086b0133c2fe48c171ab40052" }, { "name": "usr/bin/tabs", "type": "reg", "size": 14328, "modtime": "2017-12-28T09:47:33Z", "mode": 33261, "offset": 12935370, "NumLink": 0, "digest": "sha256:cbd146a258bb40422a779b98672625fd0e4324371bfeb9493ad3cbd74d40cd83" }, { "name": "usr/bin/tac", "type": "reg", "size": 39752, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12940795, "NumLink": 0, "digest": "sha256:27541a3a4f5bb50a9be46940ad7d2e5970bf164f57bed59a79cb8229a08d5f01" }, { "name": "usr/bin/tail", "type": "reg", "size": 68584, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 12958437, "NumLink": 0, "digest": "sha256:6d64e365ae41c6e0b72fdce23aef6e914dcfafcb3f8e91c018152e64a48c85f7" }, { "name": "usr/bin/taskset", "type": "reg", "size": 31488, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 12991834, "NumLink": 0, "digest": "sha256:8f1457e2b893dcc8c248afd23756e33449712ea7b955fcfcdc99e67c94ddd0e7" }, { "name": "usr/bin/tee", "type": "reg", "size": 35656, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13005738, "NumLink": 0, "digest": "sha256:d606a9ee3ec8d9f6a70eebf6d2cf69c0024f335dcd4dfd9deb45b9de869c0925" }, { "name": "usr/bin/test", "type": "reg", "size": 47912, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13022316, "NumLink": 0, "digest": "sha256:db96ecffc6850632a463c8776f2e37ecdf92d081deb9ae8148084876b8afcd38" }, { "name": "usr/bin/tic", "type": "reg", "size": 79984, "modtime": "2017-12-28T09:47:33Z", "mode": 33261, "offset": 13045523, "NumLink": 0, "digest": "sha256:f64a36b9119e7c8bf0b022d7b3dd3eb30f59b99720753122d7564a3af8496f3c" }, { "name": "usr/bin/timeout", "type": "reg", "size": 40296, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13081511, "NumLink": 0, "digest": "sha256:48e7c70ff117a19a2155175d117f5d482deecff2627c0ea1dc2a903c38a00a3f" }, { "name": "usr/bin/toe", "type": "reg", "size": 14328, "modtime": "2017-12-28T09:47:33Z", "mode": 33261, "offset": 13099764, "NumLink": 0, "digest": "sha256:5385b0117f1af117a549f38bfccbd2d665b3433800140a3049acc04d514e23da" }, { "name": "usr/bin/touch", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/bin/touch", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/tput", "type": "reg", "size": 18456, "modtime": "2017-12-28T09:47:33Z", "mode": 33261, "offset": 13105589, "NumLink": 0, "digest": "sha256:a984aac02449d9f7b8c3fb6800db7631419497c777fdfb5cdd6a81a5614cd89e" }, { "name": "usr/bin/tr", "type": "reg", "size": 47912, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13113172, "NumLink": 0, "digest": "sha256:885bc7a63fbd80c7046f923dd6d840095817bcabbef1ada0c7ed259ec3497ea4" }, { "name": "usr/bin/truncate", "type": "reg", "size": 39688, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13135745, "NumLink": 0, "digest": "sha256:94a38366047ebdf3ac56b2768c4391ac242a444d1b10a2152ff7493a0d33db3f" }, { "name": "usr/bin/tset", "type": "reg", "size": 22528, "modtime": "2017-12-28T09:47:33Z", "mode": 33261, "offset": 13153113, "NumLink": 0, "digest": "sha256:dbb3fceb4c20598113231d21d01c1c18835b1920a8678a07c375ccda52776d27" }, { "name": "usr/bin/tsort", "type": "reg", "size": 35592, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13162552, "NumLink": 0, "digest": "sha256:7ccd07efef4bc2b9383284f5d2c45ef292f3d7327ab9ad9b3e91bd7604d68b76" }, { "name": "usr/bin/tty", "type": "reg", "size": 31496, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13179745, "NumLink": 0, "digest": "sha256:8265e9a3914b6e62563cefbec2bd668d1d1cb79ca6d2c7297e63a18d8525f77d" }, { "name": "usr/bin/tzselect", "type": "reg", "size": 15183, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 13193742, "NumLink": 0, "digest": "sha256:098968d62a5ca72aa895c08f7ddd0d3fa34f94e8951279b64e09563c4a0aec2e" }, { "name": "usr/bin/unexpand", "type": "reg", "size": 35656, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13199746, "NumLink": 0, "digest": "sha256:11a5a98d238c3da9ffb5db16cf3e80fc6827989fff8dc3041a3227e175b544c8" }, { "name": "usr/bin/uniq", "type": "reg", "size": 43880, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13216131, "NumLink": 0, "digest": "sha256:7022bae3d35b33308300ad93113a65891562560cbc6f65ab1e1f1d931b67cc85" }, { "name": "usr/bin/unlink", "type": "reg", "size": 31464, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13236836, "NumLink": 0, "digest": "sha256:eceee77777b3852ed4c2e29123a97b9d7c087ee1c8d1c8793a0850578cdb7705" }, { "name": "usr/bin/unshare", "type": "reg", "size": 19272, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 13250963, "NumLink": 0, "digest": "sha256:256157e769562d513e2efbc478b1aa714964f105c401c1b10a9ed5a64fa6cab7" }, { "name": "usr/bin/update-alternatives", "type": "reg", "size": 47112, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 13258678, "NumLink": 0, "digest": "sha256:5284d89c9db30387c306ea730834c95a0f970cda37b94ed58a244abac4242dec" }, { "name": "usr/bin/users", "type": "reg", "size": 31528, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13279216, "NumLink": 0, "digest": "sha256:d342c8f899a264011068f44a8a2abbe5da7d0cb1c6153758033dea0676d849a7" }, { "name": "usr/bin/utmpdump", "type": "reg", "size": 23256, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 13294291, "NumLink": 0, "digest": "sha256:d7a8b32dad8560f1d8a29aa44d81d8279c2c7116e8bae0f3059c8f3be93a122c" }, { "name": "usr/bin/wall", "type": "reg", "size": 27448, "modtime": "2018-03-07T18:29:09Z", "mode": 34285, "gid": 5, "offset": 13304152, "NumLink": 0, "digest": "sha256:a2c7e6645b55c65905227f696f94731947a8fb2bfc128b3791816869e409c1b5" }, { "name": "usr/bin/wc", "type": "reg", "size": 43888, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13316715, "NumLink": 0, "digest": "sha256:d566e182f833e3e0365cc35dc2e4c78007a4d4409a1b931b85b5b3bed7c64ebe" }, { "name": "usr/bin/whereis", "type": "reg", "size": 27744, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 13337559, "NumLink": 0, "digest": "sha256:0ffa3486644df8ca05d5e4114a92c105e97a6e714c533516ca7770a86a59652b" }, { "name": "usr/bin/which", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/bin/which", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/who", "type": "reg", "size": 52168, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13348087, "NumLink": 0, "digest": "sha256:36312f62a0eb6d337ee41859d3a7c00e905357397c59d5813e8a48b13fb6d7ac" }, { "name": "usr/bin/whoami", "type": "reg", "size": 31496, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13372822, "NumLink": 0, "digest": "sha256:370dbe69b3aa202cbd31f1f597ff30b9bfa9023e37dafc610b3e4008e9375227" }, { "name": "usr/bin/x86_64", "type": "symlink", "modtime": "2018-03-07T18:29:09Z", "linkName": "setarch", "mode": 41471, "NumLink": 0 }, { "name": "usr/bin/xargs", "type": "reg", "size": 67800, "modtime": "2017-02-18T15:37:32Z", "mode": 33261, "offset": 13387042, "NumLink": 0, "digest": "sha256:efcdba7cbbf91d82113f64453ab11c0e64245a963e67b032b8f084ec30d22531" }, { "name": "usr/bin/yes", "type": "reg", "size": 31464, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 13419643, "NumLink": 0, "digest": "sha256:d07b3d1897e68927efcb012bba09d57e39a50e61ee5256ebe37fe919f2645313" }, { "name": "usr/bin/zdump", "type": "reg", "size": 14768, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 13434180, "NumLink": 0, "digest": "sha256:7597033749fadd103a24b3a278ffba55ea762ad2f43baea7e645380370c3a422" }, { "name": "usr/games/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/include/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/apt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/apt/apt-helper", "type": "reg", "size": 26784, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13441022, "NumLink": 0, "digest": "sha256:8ca18a42645e85626aabff7cd9320ccb9b3e09a94b4628ca76f9e99aefeb2b13" }, { "name": "usr/lib/apt/apt.systemd.daily", "type": "reg", "size": 15416, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13452294, "NumLink": 0, "digest": "sha256:100c73ca198b46cd60314fe2caa9c26fe7eb8573539c10358c85df58487db262" }, { "name": "usr/lib/apt/methods/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/apt/methods/bzip2", "type": "symlink", "modtime": "2017-09-13T16:47:33Z", "linkName": "store", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/apt/methods/cdrom", "type": "reg", "size": 34976, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13456996, "NumLink": 0, "digest": "sha256:8767d67d18e09afaf19fb0c836ef761c5fc50c709a888bb1748e47db382f7560" }, { "name": "usr/lib/apt/methods/copy", "type": "reg", "size": 18592, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13470455, "NumLink": 0, "digest": "sha256:d90b02abf40ff63071505eb84ede4cfd50c401f98748001c43a179c87eb9b669" }, { "name": "usr/lib/apt/methods/file", "type": "reg", "size": 18592, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13476895, "NumLink": 0, "digest": "sha256:4b30f5e92352e011facc307c4b13c959218c64e0cc396def475f16ac48697052" }, { "name": "usr/lib/apt/methods/ftp", "type": "reg", "size": 63744, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13483905, "NumLink": 0, "digest": "sha256:0fad9076801625d64e863ae4200e1b53b5af493c0536c19d4b7a20c21f911902" }, { "name": "usr/lib/apt/methods/gpgv", "type": "reg", "size": 55456, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13510659, "NumLink": 0, "digest": "sha256:02b85554325276116efdd59b6be7066cfcb4dd6d715d407a8ac90d6f0ddf3f0f" }, { "name": "usr/lib/apt/methods/gzip", "type": "symlink", "modtime": "2017-09-13T16:47:33Z", "linkName": "store", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/apt/methods/http", "type": "reg", "size": 112808, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13532943, "NumLink": 0, "digest": "sha256:63a27ce8eee65a0c6f91fadfd05feb7d2767181620739c042eea11e22e23b9b0" }, { "name": "usr/lib/apt/methods/lzma", "type": "symlink", "modtime": "2017-09-13T16:47:33Z", "linkName": "store", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/apt/methods/mirror", "type": "reg", "size": 137448, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13582418, "NumLink": 0, "digest": "sha256:5f5183db0600db27a2b2dab6158144529406d58987cc2f816d62e662883271ab" }, { "name": "usr/lib/apt/methods/rred", "type": "reg", "size": 47264, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13642317, "NumLink": 0, "digest": "sha256:005da2aa6d732ed000d00138eb744d6a0aeea1346440178739b106d4e0bfec85" }, { "name": "usr/lib/apt/methods/rsh", "type": "reg", "size": 30896, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13661946, "NumLink": 0, "digest": "sha256:9aa728dbcee13b6ea052300e707e95f805e1ed70ff1778da8e377eb3513ff2bf" }, { "name": "usr/lib/apt/methods/ssh", "type": "symlink", "modtime": "2017-09-13T16:47:33Z", "linkName": "rsh", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/apt/methods/store", "type": "reg", "size": 22688, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13674700, "NumLink": 0, "digest": "sha256:181be8323b9885182006036cfc7f9aaf2bd73dfa89985923b20e82d9a3b72737" }, { "name": "usr/lib/apt/methods/xz", "type": "symlink", "modtime": "2017-09-13T16:47:33Z", "linkName": "store", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/apt/planners/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/apt/planners/dump", "type": "symlink", "modtime": "2017-09-13T16:47:33Z", "linkName": "../solvers/dump", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/apt/solvers/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/apt/solvers/dump", "type": "reg", "size": 18520, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13683482, "NumLink": 0, "digest": "sha256:f79e93a0ce641b06284933c1f5c46d1b69610b9d1fc170ba4172480027324107" }, { "name": "usr/lib/dpkg/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/dpkg/methods/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/dpkg/methods/apt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/dpkg/methods/apt/desc.apt", "type": "reg", "size": 567, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 13690116, "NumLink": 0, "digest": "sha256:4035a2ca99d6d473f6e9a0af7b39d395bfe47e48b3a9993488fc2fae139145f8" }, { "name": "usr/lib/dpkg/methods/apt/install", "type": "reg", "size": 2861, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13690562, "NumLink": 0, "digest": "sha256:810da1fcf97636219401c67e891a04a7a4f01b2a0d73fd60bf3bbbdfb3775f76" }, { "name": "usr/lib/dpkg/methods/apt/names", "type": "reg", "size": 39, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 13691901, "NumLink": 0, "digest": "sha256:0a636de469385b41ea06f639a389c523946ec7f023fe2a12c0adf8300e2a82ad" }, { "name": "usr/lib/dpkg/methods/apt/setup", "type": "reg", "size": 7728, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13692053, "NumLink": 0, "digest": "sha256:c645a091943f61ff46847973d000cbf1817623a86e1ede412f97f437aa1eb56a" }, { "name": "usr/lib/dpkg/methods/apt/update", "type": "reg", "size": 1242, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 13694442, "NumLink": 0, "digest": "sha256:605ae19f87289e8d4cdb80028dd071c4b3ea0e2e46da9ad697b6bd739ba4c6b3" }, { "name": "usr/lib/gcc/", "type": "dir", "modtime": "2018-02-14T16:53:20Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/gcc/x86_64-linux-gnu/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/gcc/x86_64-linux-gnu/6/", "type": "dir", "modtime": "2018-02-14T16:53:20Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/gcc/x86_64-linux-gnu/6.3.0", "type": "symlink", "modtime": "2018-02-14T16:53:20Z", "linkName": "6", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/locale/", "type": "dir", "modtime": "2018-01-14T10:39:44Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/locale/C.UTF-8/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/locale/C.UTF-8/LC_ADDRESS", "type": "reg", "size": 131, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 13695330, "NumLink": 0, "digest": "sha256:e56fdac7f4d70bdb7517a9a3c98bbfefef52fcfb082d3a49c26eec93fd8f9d9d" }, { "name": "usr/lib/locale/C.UTF-8/LC_COLLATE", "type": "reg", "size": 1515838, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 13695537, "NumLink": 0, "digest": "sha256:821d59144c41906337b31ca68dec0e38bcc91b9a532d06050c6aedbf00587472" }, { "name": "usr/lib/locale/C.UTF-8/LC_CTYPE", "type": "reg", "size": 198372, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14383146, "NumLink": 0, "digest": "sha256:4826e6c02b3df039a8aa8fbddacdc060f7d697438e7b525483c44c4d4d7e949f" }, { "name": "usr/lib/locale/C.UTF-8/LC_IDENTIFICATION", "type": "reg", "size": 243, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14405493, "NumLink": 0, "digest": "sha256:d0a1272e17344d4e4d9ac8b783181721cd4a9faae87890793561261e47c7eedd" }, { "name": "usr/lib/locale/C.UTF-8/LC_MEASUREMENT", "type": "reg", "size": 23, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14405720, "NumLink": 0, "digest": "sha256:bb14a6f2cbd5092a755e8f272079822d3e842620dd4542a8dfa1e5e72fc6115b" }, { "name": "usr/lib/locale/C.UTF-8/LC_MESSAGES/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/locale/C.UTF-8/LC_MESSAGES/SYS_LC_MESSAGES", "type": "reg", "size": 48, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14405898, "NumLink": 0, "digest": "sha256:f9ad02f1d8eba721d4cbd50c365b5c681c39aec008f90bfc2be2dc80bfbaddcb" }, { "name": "usr/lib/locale/C.UTF-8/LC_MONETARY", "type": "reg", "size": 270, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14406061, "NumLink": 0, "digest": "sha256:2b453edb3c67a2b0f326d045ce72a5cd0ffde75fcfe31e47edd1c2d802bb18b6" }, { "name": "usr/lib/locale/C.UTF-8/LC_NAME", "type": "reg", "size": 62, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14406322, "NumLink": 0, "digest": "sha256:14507aad9f806112e464b9ca94c93b2e4d759ddc612b5f87922d7cac7170697d" }, { "name": "usr/lib/locale/C.UTF-8/LC_NUMERIC", "type": "reg", "size": 50, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14406486, "NumLink": 0, "digest": "sha256:f5976e6b3e6b24dfe03caad6a5b98d894d8110d8bd15507e690fd60fd3e04ab2" }, { "name": "usr/lib/locale/C.UTF-8/LC_PAPER", "type": "reg", "size": 34, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14406640, "NumLink": 0, "digest": "sha256:cde048b81e2a026517cc707c906aebbd50f5ee3957b6f0c1c04699dffcb7c015" }, { "name": "usr/lib/locale/C.UTF-8/LC_TELEPHONE", "type": "reg", "size": 47, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14406790, "NumLink": 0, "digest": "sha256:f4caf0d12844219b65ba42edc7ec2f5ac1b2fc36a3c88c28887457275daca1ee" }, { "name": "usr/lib/locale/C.UTF-8/LC_TIME", "type": "reg", "size": 2498, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14406947, "NumLink": 0, "digest": "sha256:a61ddf48d8afc6d3aa93effb63cc55033c4ab9e42a4dbed2be1e385b5f6f7451" }, { "name": "usr/lib/mime/", "type": "dir", "modtime": "2017-12-20T13:39:04Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/mime/packages/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/mime/packages/sensible-utils", "type": "reg", "size": 97, "modtime": "2017-12-20T13:39:04Z", "mode": 33188, "offset": 14407873, "NumLink": 0, "digest": "sha256:e9d9b4e7782deb0509bb543620c597710bda659a3045bfce55b28c632f201f2a" }, { "name": "usr/lib/mime/packages/tar", "type": "reg", "size": 327, "modtime": "2016-10-30T06:35:31Z", "mode": 33188, "offset": 14408061, "NumLink": 0, "digest": "sha256:31deef64d49013a02645bcd32e43d108d12ebb89a93034fb35947c7c576397c8" }, { "name": "usr/lib/mime/packages/util-linux", "type": "reg", "size": 90, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 14408260, "NumLink": 0, "digest": "sha256:8c2a3124292211ce117712858ad06a036675a7f7d8f578e5b84267b1196c1665" }, { "name": "usr/lib/os-release", "type": "reg", "size": 236, "modtime": "2018-06-26T12:03:08Z", "mode": 33188, "offset": 14408414, "NumLink": 0, "digest": "sha256:b4c8c0cfed0dc1f1b4f6f34fe29539d7177c343624de2ec59c86c762615597a6" }, { "name": "usr/lib/python2.7/", "type": "dir", "modtime": "2017-05-21T17:08:30Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/python2.7/dist-packages/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/python2.7/dist-packages/debconf.py", "type": "reg", "size": 5971, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 14408720, "NumLink": 0, "digest": "sha256:6d43e8fb8ce8e97cb0462912d224ee912c56e9453bd52bd6fb0cdfec0b27d575" }, { "name": "usr/lib/python3/", "type": "dir", "modtime": "2017-05-21T17:08:30Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/python3/dist-packages/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/python3/dist-packages/debconf.py", "type": "reg", "size": 5971, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 14411248, "NumLink": 0, "digest": "sha256:6d43e8fb8ce8e97cb0462912d224ee912c56e9453bd52bd6fb0cdfec0b27d575" }, { "name": "usr/lib/tar/", "type": "dir", "modtime": "2016-10-30T06:35:31Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/tmpfiles.d/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/tmpfiles.d/passwd.conf", "type": "reg", "size": 239, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 14413781, "NumLink": 0, "digest": "sha256:1a3b927102b44454eb4c47e4fe659de2f5283f364ba27408329a54d4ad47e310" }, { "name": "usr/lib/x86_64-linux-gnu/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/audit/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/audit/sotruss-lib.so", "type": "reg", "size": 10512, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14414075, "NumLink": 0, "digest": "sha256:d3b259d2cdfddf10191a34b45491fe65b62ba40ab7354baabab6a49729f8a972" }, { "name": "usr/lib/x86_64-linux-gnu/coreutils/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/coreutils/libstdbuf.so", "type": "reg", "size": 6208, "modtime": "2017-02-22T12:23:45Z", "mode": 33188, "offset": 14418024, "NumLink": 0, "digest": "sha256:c8a9a76f2bf31a771caaef396959e0499600db824c6fd10074d2b5d2f310ef3e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ANSI_X3.110.so", "type": "reg", "size": 22696, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14420506, "NumLink": 0, "digest": "sha256:52262e2d0a7f214cc2245cff3961f378543e0d39c6d4417ba30c9f2e49c1df9a" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ARMSCII-8.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14428237, "NumLink": 0, "digest": "sha256:ae82c1d28f62461266e9cda0cc26c4645b440747c5ca989d7a04051fbf3a6b73" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ASMO_449.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14432539, "NumLink": 0, "digest": "sha256:0807e5512dcf1ae8672b10d01c191bed90ec3776d984fe1e7173ca3d2a46639c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/BIG5.so", "type": "reg", "size": 88232, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14436989, "NumLink": 0, "digest": "sha256:0a81b5d9ade3c77d046913fb43921df3a07cb580e4846bea244c88cfc49242bd" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/BIG5HKSCS.so", "type": "reg", "size": 235688, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14501902, "NumLink": 0, "digest": "sha256:088d26cae29c1089532420dce6af0c0834ddbf2027e9a9afbe1b15babeab6326" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/BRF.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14599125, "NumLink": 0, "digest": "sha256:d2eb65850ad018518ea8e7ae4c50f847cdda4cdfc7420b6822898342ab3ead23" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP10007.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14603462, "NumLink": 0, "digest": "sha256:d25df0bc6be89a0422849cad6efaf8e3c3666eaf0be6efa73a0d7d1cab90df7a" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP1125.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14608398, "NumLink": 0, "digest": "sha256:a96ddfac1fd5bb74ea4a8c19a887225894890762e291196c27b3346472402b0e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP1250.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14613378, "NumLink": 0, "digest": "sha256:c761e88cad960d05daa141ab51c03fae9189d49967ee1afde72e5e2543257b3c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP1251.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14618353, "NumLink": 0, "digest": "sha256:c8470d189bf9c79a768cab14e380114e1634200bcf5c1b7cd45de0b4aa411ef4" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP1252.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14623308, "NumLink": 0, "digest": "sha256:f4742d917fafa59406fdeabe074b69a986bfc11e1af5c2337035f465b0431648" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP1253.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14628249, "NumLink": 0, "digest": "sha256:ebc48f981c92999a5e72516c02bed94d8526575bdc6bd52458cd07644acff61d" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP1254.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14633150, "NumLink": 0, "digest": "sha256:c91b07b46724dd2a2e4113a96d0111a99da10b5122d2d4158f43a5b0a80ddd83" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP1255.so", "type": "reg", "size": 14504, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14638095, "NumLink": 0, "digest": "sha256:050f26ec19bc43127b0f1d669818c6d9f0bb0b76259291bca38747d1e9b34f34" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP1256.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14645317, "NumLink": 0, "digest": "sha256:9083224cce4afa3cb1bf1b7ff1ea16b8e085e9664d46043c57063946e9c3c98a" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP1257.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14650361, "NumLink": 0, "digest": "sha256:ff6585ff708bf5e82fbc25fe25f0e7e4c32db17d04b9784c25b0b6e050e79657" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP1258.so", "type": "reg", "size": 14512, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14655334, "NumLink": 0, "digest": "sha256:c194a2a2ac90d7c9156b215e92e100d8311f5442e85e5ece08e0773b03214bf1" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP737.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14663380, "NumLink": 0, "digest": "sha256:8eac0e2ad46c543422ed7672850fac763fe58dc28a14a4a82ad0605a0850dfa4" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP770.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14668423, "NumLink": 0, "digest": "sha256:3fb2446b1b6483defec27db9793c0156498cea296d512e1a0bb799d1f175c751" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP771.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14673540, "NumLink": 0, "digest": "sha256:4281251137e534c30c61ba1a897c758ad61ee7dfe39d5863e44b96917c806ce3" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP772.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14678534, "NumLink": 0, "digest": "sha256:512ebd920245e0401557704cd7f2bea935d0471e6a41d4d95d9a7963aa6b4994" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP773.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14683587, "NumLink": 0, "digest": "sha256:cb607d2235d078938530c1939d1216db8e78c74c77ae0547de9e8cb0a2e4427e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP774.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14688605, "NumLink": 0, "digest": "sha256:70ecf1712bf970a9215527626c2d5c6276e1cb448212755038d019ddb2709be0" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP775.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14693692, "NumLink": 0, "digest": "sha256:61ae97e8aa5c5d703ed36945ecf7f0a8e591bf61dd584bfbd51ec5bed4235a73" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CP932.so", "type": "reg", "size": 96424, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14698751, "NumLink": 0, "digest": "sha256:6f626fa00093a081100e122fcebf717df97ed310c48e11f369c838a01686f7ba" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CSN_369103.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14740144, "NumLink": 0, "digest": "sha256:2bc8813d57c2b440c2917aa89b9e409c52fc46a659c14ca91fe3a7bcef7ae279" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/CWI.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14745042, "NumLink": 0, "digest": "sha256:6adb325cf1a72086f60d31d01e81243b8b40fbcad35a1e35f1a27a477b267ad0" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/DEC-MCS.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14750111, "NumLink": 0, "digest": "sha256:f0aaf44d6cafe56fb90c09c7d1a0dca359f375895de8493522e68649f1ad998e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-AT-DE-A.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14754955, "NumLink": 0, "digest": "sha256:3d44f8769af83450b7b75d3f9b69621f27833af117daf2b2bd927dce856fed8d" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-AT-DE.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14759385, "NumLink": 0, "digest": "sha256:44b682d782826047e399de9272a2cdfc3437d8221f036ecba701473827935148" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-CA-FR.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14763835, "NumLink": 0, "digest": "sha256:a9b9c635be74120334387edb3e0a0f622aa9fd7c3d58c04c5571ef29640ae54e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-DK-NO-A.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14768362, "NumLink": 0, "digest": "sha256:5a8dd91fe6988b4141191d94ef30b37e49351cac989b276cb5e9a717e9546ca8" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-DK-NO.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14772792, "NumLink": 0, "digest": "sha256:64df1cc8d7c8746ec30347c4b4800777af8c347ecfc66e3ff7b93df8c70d7d0a" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-ES-A.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14777239, "NumLink": 0, "digest": "sha256:e8e45fa922d6c98a1c515ab7e3a3a8a582c95d383ae63cd0e962e6f060625ed4" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-ES-S.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14781794, "NumLink": 0, "digest": "sha256:88f6ab75e922f12e226b9d0fe92c4a0ac4df64f63dd1d482287db69b638d13c9" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-ES.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14786227, "NumLink": 0, "digest": "sha256:b98e70cfd597501422b69559e7bc448ed6d4f5302953406e68e064ed840dfdf8" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-FI-SE-A.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14790805, "NumLink": 0, "digest": "sha256:f020cfdd4d521d4520a87299908e65f7d6b906452252900b5aa5a673789cd656" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-FI-SE.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14795234, "NumLink": 0, "digest": "sha256:ffb39c7296bdee62e96d7cd05c4a58073e66aecedd6bf70bbc9ca6d429d7dcb2" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-FR.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14799676, "NumLink": 0, "digest": "sha256:c8f03bf1c63291b5bf1d97a041025b91c22c2fc0d930ad38d4eb730f67c790ca" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-IS-FRISS.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14804118, "NumLink": 0, "digest": "sha256:ffc94a955ae58f68e83baf656c3c6b375851e301ff4b5f9fb7610e606a108705" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-IT.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14808669, "NumLink": 0, "digest": "sha256:0cb0f62f17f0bda72a19a2327de4692c8fce54eac0b5f05a875d4516d46fe65e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-PT.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14813101, "NumLink": 0, "digest": "sha256:423fa5915f65e0b3865c8e864c57d3c5c828515dc142a2985da5773f3572c1ab" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-UK.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14817543, "NumLink": 0, "digest": "sha256:3a4e3458fba6edf9a883d5dc4f909b6ed2fc0d8836bb6df2b6fd8e04e89e4077" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EBCDIC-US.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14822100, "NumLink": 0, "digest": "sha256:0f3a1b38dca122467b74a7a75af0f77f26bf13ea4c328a94d2197343acb194af" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ECMA-CYRILLIC.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14826536, "NumLink": 0, "digest": "sha256:073232e33584358d25014f6e1b8c2d502c7bed0413cdabe4f3780f66ff073269" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EUC-CN.so", "type": "reg", "size": 18600, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14831401, "NumLink": 0, "digest": "sha256:4f11c781a92eb325d435cb71767224d7e6c3cb87f948d1b73f4729ce7c3c26bc" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EUC-JISX0213.so", "type": "reg", "size": 14504, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14839196, "NumLink": 0, "digest": "sha256:7123e1baba3fa0da4b59aba823aff32464d7a9debb950bdd2f2d934f638cccd8" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EUC-JP-MS.so", "type": "reg", "size": 88232, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14846580, "NumLink": 0, "digest": "sha256:2f4418c4976ddd63cd367d60f2e0ed53624b6bee43e6d68320b8ce51c47835af" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EUC-JP.so", "type": "reg", "size": 14504, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14885819, "NumLink": 0, "digest": "sha256:9fc8079f6369e76c7ac57330cd90e636f8e9db2f1bd40b189a650409f1d84d29" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EUC-KR.so", "type": "reg", "size": 14504, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14892604, "NumLink": 0, "digest": "sha256:047e570c03fb7dc3f12a42776f3d14f3b4751aaf9cdd19feaabf67429f11c3b0" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/EUC-TW.so", "type": "reg", "size": 22696, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14898948, "NumLink": 0, "digest": "sha256:10e457260126d17f57ad318e53c35cc0138b0e1385e4c0b8c32a5bffe12e9d99" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/GB18030.so", "type": "reg", "size": 178344, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 14909184, "NumLink": 0, "digest": "sha256:facce5fb00a24c8a6c405e08a2076775fa706a665c5b17b0847e2e289649e3f6" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/GBBIG5.so", "type": "reg", "size": 55456, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15065887, "NumLink": 0, "digest": "sha256:69311d0fbb67b61a6f4da8a77559b5c649f7baf8d9377fddd5637235b7552b39" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/GBGBK.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15099011, "NumLink": 0, "digest": "sha256:490382cef8df9d193c080356fb8fbd686bdd3175f1daf0ba902ea58ef758423f" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/GBK.so", "type": "reg", "size": 112808, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15103715, "NumLink": 0, "digest": "sha256:1cad89450d971726751f89feb19d40373513de10cffe0065e20d4b354f587e4b" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/GEORGIAN-ACADEMY.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15195138, "NumLink": 0, "digest": "sha256:645d761630fc542d42c8121c84504f16d01484ffeff9dc355416b00a30e43f52" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/GEORGIAN-PS.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15200078, "NumLink": 0, "digest": "sha256:d7636579114a2eba5f995bff71ff91bd6f2f03308f271a9b356673661a47277a" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/GOST_19768-74.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15205024, "NumLink": 0, "digest": "sha256:c44a7f287143a6fb190f01ca1488485e81f7ed9fad8f8b81aaaf0c1820d72ed1" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/GREEK-CCITT.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15209845, "NumLink": 0, "digest": "sha256:e5a26ab830be4dcdebe57cc422518ed2f2c4dd5275b9441c34af4b5df0d621f4" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/GREEK7-OLD.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15214317, "NumLink": 0, "digest": "sha256:c15f04d0267a44780eddf824781d343e25f879d071532bec5feea8332d99c110" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/GREEK7.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15218842, "NumLink": 0, "digest": "sha256:4904f214e0f8bda99b02b4721f51943a068c6394c677eb26dbb4f65d94d87f71" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/HP-GREEK8.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15223317, "NumLink": 0, "digest": "sha256:8ab569cbc017a53dd32af34d62f7d88ff1d3898fadea71e62eb6ffc7889c3a3b" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/HP-ROMAN8.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15228105, "NumLink": 0, "digest": "sha256:3f5d0340f0ce36889d978675a59504e65ad70a1afe4d625a63055628650ff72c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/HP-ROMAN9.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15233029, "NumLink": 0, "digest": "sha256:54bb72b18c528c95b09a4290dd5da78c86c884865bc14590221ecc788dcf4924" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/HP-THAI8.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15237958, "NumLink": 0, "digest": "sha256:130909152ac8794e8fe8b4ec538fd608e3e6b6d13f66a4b892e25c0a9225c398" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/HP-TURKISH8.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15242829, "NumLink": 0, "digest": "sha256:c7fc4f586144a96fa7de6cc71a6a5445fe80da2cbad80aa7101421a7e1639146" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM037.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15247743, "NumLink": 0, "digest": "sha256:ffa677531c2da9a1bf845f2839cc4044aba8e1039de4a01600d4f548b7d57888" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM038.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15252485, "NumLink": 0, "digest": "sha256:a01d54b7e0eb7a8aa35d8152e92a5c44bfd3d61e31ab3a8fa9cb5cebd10a7dd1" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1004.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15256912, "NumLink": 0, "digest": "sha256:da5a574d13f503b0d81e78d414dcc1a139b04923d239fbcbfa3f097129147ae5" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1008.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15261823, "NumLink": 0, "digest": "sha256:5573b22026ba9d681b076fb7b7039cd521e1891f19a7cd5bebd9010fa767ee7b" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1008_420.so", "type": "reg", "size": 6304, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15266876, "NumLink": 0, "digest": "sha256:c77c2618443efe3604bcc2b3430d81610af1dbd3de34abffe3240b84276fb653" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1025.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15269808, "NumLink": 0, "digest": "sha256:d3f1c1d482362ddea8c36d7bbc9ed2dbf4be212155ecc654cc287efa7e2079c7" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1026.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15274665, "NumLink": 0, "digest": "sha256:db2d4454948890403012e477944c933aef8760781485b9074e15a555d0a6a315" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1046.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15279560, "NumLink": 0, "digest": "sha256:af4e25d6a109a75ea583bb16bc6f7baf836c25019cde02adecbeac0b116a0881" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1047.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15284718, "NumLink": 0, "digest": "sha256:a689bcda087e85aed9ac1b09e2b8fc7eca93f1d3be9555f8e5fb3c4e0c5ce108" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1097.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15289460, "NumLink": 0, "digest": "sha256:4fc795da190f3eb93324a9ad223481ea599ff5478d8629552e9d50a51220c78a" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1112.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15294514, "NumLink": 0, "digest": "sha256:ec977f45a23bfa21197e42502acb11c17666275b488b956e0240540e47088f74" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1122.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15299413, "NumLink": 0, "digest": "sha256:0357639fdbdde937f46feb178b768c0135a176aad0f2d2c9936fafdffd8c615a" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1123.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15304248, "NumLink": 0, "digest": "sha256:65632ea53e05173632a3d0dcae26bf0c1d2e0b8a3340a0111a9ab2e5f9d7bf7c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1124.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15309113, "NumLink": 0, "digest": "sha256:db992833af0f46a736af4a988167be258272c958225c9f5abe3ecc2bef6e0e58" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1129.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15313977, "NumLink": 0, "digest": "sha256:24f9a845bc9caf06ac136b345c8945b975d870415fb17481992d4c216140b71c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1130.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15318861, "NumLink": 0, "digest": "sha256:a8fb0798d47c5826b4eddbfb8eda589f3bed0d13c51d2c4a54634829586a8ddd" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1132.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15323742, "NumLink": 0, "digest": "sha256:d2a3fd0bee2d819027bcff4e19b989652dc064c4df22b1cba328548bf5acc47f" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1133.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15328571, "NumLink": 0, "digest": "sha256:0a813aacf57c8d5e844f57bafddd48166fb24464486d7eb8f574e109fc0393df" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1137.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15333396, "NumLink": 0, "digest": "sha256:c2ccad4af98d6fd4fd6fba34af927eb0bbacaaf0ed19873bd057f39a27256a53" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1140.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15338298, "NumLink": 0, "digest": "sha256:ba4d8304f773b6b875d3fc632b24a264b97489f76fac2d040b117e96b86a5f92" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1141.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15343128, "NumLink": 0, "digest": "sha256:783877472678337e9e9f3111e0408f0591fab7bf0879926164cb2752cecfb5df" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1142.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15347956, "NumLink": 0, "digest": "sha256:edbb8c88aab7ec11323f067da638af465b762bd6fcd48753858ab87c0fbde1d0" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1143.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15352782, "NumLink": 0, "digest": "sha256:e3d785fa4bd087becac09242fd4cbe91d19d6d992ba24e372db9f9bf5ba9a47d" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1144.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15357608, "NumLink": 0, "digest": "sha256:a44afd8f7d7509e91517da5c7bfcc00212ebcb5b021cd3f8297cc0a97850ad8d" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1145.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15362434, "NumLink": 0, "digest": "sha256:93ac0ff644b41571b707d3f78be9c22e39ebe7735a6caf9266d83f6847b86cab" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1146.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15367261, "NumLink": 0, "digest": "sha256:132c94776db1d54d57da406e50e8a02bfdb681ff3f3c9d4b716a2b9345f4b4b9" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1147.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15372088, "NumLink": 0, "digest": "sha256:cd372c049f87498c44cca93829d2e5129675b2d23b4acef1e010cbc959c5830f" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1148.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15376915, "NumLink": 0, "digest": "sha256:9a4dc2316705e8c0c49ce32c381bfc339c232fd26514bd0a5280e474e691712c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1149.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15381741, "NumLink": 0, "digest": "sha256:98155f7777984365e0ce63e51d0ab7cd19f4184fa09a10c85edd757c16a7523e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1153.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15386569, "NumLink": 0, "digest": "sha256:c9ffb0622e8512f6ecdfe1f10ba710f0c3ca47e8867886d21c2b06d3a44eb2af" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1154.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15391473, "NumLink": 0, "digest": "sha256:c8b38fa5d3035cca9e8f70da21ab5d0a09eaf02692dabe4ed5908ac74bfdc3b7" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1155.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15396332, "NumLink": 0, "digest": "sha256:8bacc4b9c6c33fe729ab68223a5bb263c6734179db8df3cc6793f34377d2588b" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1156.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15401174, "NumLink": 0, "digest": "sha256:aa551c5c91eb06f4181855e890e7b12b7063308d841894a2226d7da041a70062" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1157.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15406080, "NumLink": 0, "digest": "sha256:6d613439d5fd1cffab59037098eef8132a2ef81105a9f20cf45679dd8272006f" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1158.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15410923, "NumLink": 0, "digest": "sha256:315953061208acef9f8e36c4707723e33c1a82ee5648e743a5ebf2756a776917" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1160.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15415794, "NumLink": 0, "digest": "sha256:8aee39f57a5a2e37263bd515a2ce9dc0996d8f627a8bbedb26a4403caa5c39f6" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1161.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15420629, "NumLink": 0, "digest": "sha256:61a596be406a3ed50b3b5968388ceb1a889471fcceeeb1575408fa3ac7011e3e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1162.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15425413, "NumLink": 0, "digest": "sha256:4420dcd49007c9cd0e59ba80b90096b1652d2e2d8a8bfc7a99ba678141af583b" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1163.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15430305, "NumLink": 0, "digest": "sha256:fce604a2be8f9975a159d9601bcf8e5ccdd43460e160ecfdd03172a65fded28e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1164.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15435199, "NumLink": 0, "digest": "sha256:0dfed478ecbc38b59bd59cdf70ff4344b2088d65696901bf3bc92837bb2c7e9e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1166.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15440084, "NumLink": 0, "digest": "sha256:a0e9df4edae2676f8ec5b4f5b9f29bb3ea2202a9d2ba8f4484163b37f6aa9096" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1167.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15445006, "NumLink": 0, "digest": "sha256:13799e0bb916470fdf9a785df825ea8d8cc7fc748cab754c690080fb7943fec4" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM12712.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15450020, "NumLink": 0, "digest": "sha256:e7b96feddd55908724a0f76348bd6b790ee46aa5cf217bc4688078f2b814c11e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1364.so", "type": "reg", "size": 149664, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15454873, "NumLink": 0, "digest": "sha256:5eae3691cf2b1c728cbdeac9483db62b43359baada0f708d7118d0d7cbfd8376" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1371.so", "type": "reg", "size": 129184, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15541041, "NumLink": 0, "digest": "sha256:6fddb19ff2a399ea3734a21f091e2f75de7334ef813a00e8bdc9bf222cbdfd12" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1388.so", "type": "reg", "size": 174240, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15628179, "NumLink": 0, "digest": "sha256:c8d7e4a59d4578c6320c588f9a3965121154eb3a1401fcfc909edc3761cf2d50" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1390.so", "type": "reg", "size": 231584, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15755302, "NumLink": 0, "digest": "sha256:c45c11a5a89eccbf3bbc5da8212e38b23c43d623ec54fe9e8580c8b3825ebce2" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM1399.so", "type": "reg", "size": 231584, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15864185, "NumLink": 0, "digest": "sha256:69d1ed3af9406cd96f05b4767de1e1844aad4c016fdf3ee25ca341d96ecb1a2d" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM16804.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15973069, "NumLink": 0, "digest": "sha256:174471be37f87afb1ff2a2dc5d89ca168fac9eba1c2a7f085a88f79c23de61f6" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM256.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15978116, "NumLink": 0, "digest": "sha256:2fd6c744c678b54bea45ac4480281529a532dd6612ae16a46b3789642950cfae" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM273.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15983014, "NumLink": 0, "digest": "sha256:94d110b50d0fedefcc97863e11923467eaebfc82d0e8360d37a142b6c4a3a5d1" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM274.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15987881, "NumLink": 0, "digest": "sha256:a7a6242291c4cbb59097b0e6f032db96b84e01e20e62859da02687c1edb024e8" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM275.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15992310, "NumLink": 0, "digest": "sha256:ea6e9264226e60b9b2a7a3cf0bc36fb3c7d7268b98a6771d4bec1bbf3aebfd8c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM277.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 15996747, "NumLink": 0, "digest": "sha256:07f666cb4198dd56ef05a560686b93cecb7869ec3d937e73a63b26ec72d16356" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM278.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16001614, "NumLink": 0, "digest": "sha256:421e5ae26d0d6680f222df26e118a624da3468d5ee8ab4f594c19dffedf15eac" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM280.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16006483, "NumLink": 0, "digest": "sha256:5e82dfed5e52f1b370fe5b9b4512e5a21750178dde3cd33c72d8fe4b211a6c3e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM281.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16011351, "NumLink": 0, "digest": "sha256:b836097e81bce60b77c581eb02b22a36eab47385f982d4e681ad994e4e8a3911" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM284.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16015905, "NumLink": 0, "digest": "sha256:b5d14e21dd1a4334988c9a7d05026461243032eb28a58be8e6c593076f7b7dd6" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM285.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16020773, "NumLink": 0, "digest": "sha256:fcd0cce71970b57ea8f5b514edb87a67dff8881d5f8ebb507053eabe46e1f066" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM290.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16025642, "NumLink": 0, "digest": "sha256:8ff364f710e0fe5da17b6fb110f46c2f69bdaec817b3f5be30bd0f9fa13da1b6" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM297.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16030394, "NumLink": 0, "digest": "sha256:ac311a9b154b833e687e6da68b5852377826e6a3807108db5d5008ab8cb99a5b" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM420.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16035265, "NumLink": 0, "digest": "sha256:bdf124d4625d421740fd4a87c32b1c33c61fc510afad4d22733e90068cff00ae" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM423.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16040216, "NumLink": 0, "digest": "sha256:9c9aa740bfa804752c55e6f5e4900b607d080e87dee22db7a6d4fa1d1e21e37b" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM424.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16044984, "NumLink": 0, "digest": "sha256:f1709bc66bacb52d1ee29baadb87dfc54413500c5a2e8f2722ed7586a07471b7" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM437.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16049769, "NumLink": 0, "digest": "sha256:f5c1a7ff03ce11bfeefcb84dfcb4d076996dc92826c362390643ef61f5d1be77" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM4517.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16054811, "NumLink": 0, "digest": "sha256:637fe4b15c525d9189b7ff8327a6b36f5e85b065473d14b12bd40c7c6d3c5195" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM4899.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16059867, "NumLink": 0, "digest": "sha256:38d72ffc9cf63da58fdd2e8098d6f7107e9bc7a1ffe69ce7f15e1284032cbf7b" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM4909.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16064487, "NumLink": 0, "digest": "sha256:096bafbf84ae0a11c205c69be664d8b25d7c03b9601413c9c56709d110a9fc0b" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM4971.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16069397, "NumLink": 0, "digest": "sha256:aabed2c3014ca5ef9ba2343aded8d9b7be4b97b5c8c861ae5df478f146cec2d8" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM500.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16074305, "NumLink": 0, "digest": "sha256:5e7ea1eb91ae67e152ccaf54d91a805d79aec6dfda5440c6440204d2dd2d2f02" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM5347.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16079051, "NumLink": 0, "digest": "sha256:f7794f33f4f549cd7b900a9e0d124c8d8ee45ed5e72bffbf58b99636574c0dc3" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM803.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16083969, "NumLink": 0, "digest": "sha256:12e63f232b6d2c473e1b8e16ee34f718de0ae57753bfb78b148c4220baf5fde0" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM850.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16088531, "NumLink": 0, "digest": "sha256:bff40bb4f70daf445f86fc7badb76e7bef76e03d904209f804ce4c003b21ace9" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM851.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16093511, "NumLink": 0, "digest": "sha256:2246a0b9995ced61e360318c07f7bf3fb3de6a71ee6a3037f3455c93e9c52aa2" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM852.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16098541, "NumLink": 0, "digest": "sha256:94bd3f4c26c97659c7efdd4e5eb22c76ea74bebd4a483aa88e87eda89438f1df" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM855.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16103581, "NumLink": 0, "digest": "sha256:d69adcb0986a7b7bb42c5e8eac260ce795700f86f01058bdf6706d5786e672dc" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM856.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16108593, "NumLink": 0, "digest": "sha256:716fc1d1f5d59170ae615480b329b93fc17a3ccf65b1bff0193d36fbeb426ac4" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM857.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16113784, "NumLink": 0, "digest": "sha256:3ee104d20dce0e3d24e81386c8279bd10fbb44896749734c62cded74ad85593c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM860.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16118759, "NumLink": 0, "digest": "sha256:b90781183dc19b7bb0be4aa3a698149961c6082948d6875940ba9e4b27021ebd" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM861.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16123831, "NumLink": 0, "digest": "sha256:6a524114517e8b549bbc4e541f992394904ede309b0dea264ff0c9be51ba3317" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM862.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16128868, "NumLink": 0, "digest": "sha256:65a3cf8294db774a0b1f92e147e1f765945181fff298d1e157913ac5da9c09dd" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM863.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16133935, "NumLink": 0, "digest": "sha256:44f3abc411039df838412e683539ad909fb5bc5d1ff9684d9f24ede26fe866b8" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM864.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16138969, "NumLink": 0, "digest": "sha256:8bf8472ce956e06b5d1d7e4189b3b1b1d9460393fcacd169f9881fbe926b583b" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM865.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16144043, "NumLink": 0, "digest": "sha256:4c4d90e3d7c6d7578e31d6bb02f3b433955e2c2adf6080d7888a8ed09daef79b" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM866.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16149081, "NumLink": 0, "digest": "sha256:55ae4862b9143fe249143ba2f49cbab7bfbff2f16a04e139d5a69e1ea5fa5945" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM866NAV.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16154069, "NumLink": 0, "digest": "sha256:1ad140369291ad4b4c9ed5a99c09647ca1d7024267226f535e32aa6120e9c626" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM868.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16159042, "NumLink": 0, "digest": "sha256:37947f8351375fe599584fcab7808373f9ff9dabbd8e76889818fe7e977c7acb" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM869.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16164066, "NumLink": 0, "digest": "sha256:41d75ca56cfef68b22f0203a8dcab4ef6b94ac6884c00531e40a06e1abe7f878" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM870.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16169050, "NumLink": 0, "digest": "sha256:4171f7ad9654ee4544810afb91c29222062dd454991fbf734d8f0fd2c32206b5" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM871.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16173771, "NumLink": 0, "digest": "sha256:781755c6a791c3bbc367e1f77d68a47b911a075bcf2b6870149553900e611eaf" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM874.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16178514, "NumLink": 0, "digest": "sha256:3b47f8c7c57e01afa84d534ce3a84740bf4f6f5949f33868cc6b631a160d8708" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM875.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16183333, "NumLink": 0, "digest": "sha256:de05a012df560caa790bfbd539a6facafe236146a47aa1086c6f284985d2d4db" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM880.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16188228, "NumLink": 0, "digest": "sha256:e1bf245408a0e9c5b4080480818c4d9c03919dc9a9216744bf7fb42c8ff5aeb2" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM891.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16193103, "NumLink": 0, "digest": "sha256:8460de36522083da985248fc15b924c3dbe7cbb7608ba15bb3b0b77d228b8367" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM901.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16197397, "NumLink": 0, "digest": "sha256:945e714b987eec68188cdf64585bea4cd22ae324715c3bd17246a33c16aa7880" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM902.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16202547, "NumLink": 0, "digest": "sha256:7ac939c532a0033b92774d6b211ed90ac688f219988649549e38ac13d9bc233e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM903.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16207641, "NumLink": 0, "digest": "sha256:59c6612d1820088464c63be822e84d685e8034a01c51d0fb722e8f08dba6d789" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM9030.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16211931, "NumLink": 0, "digest": "sha256:1bcfb795581ebaeed2fc544cf8160d82e4ea773c48b21b33fc6d7c6692a777d0" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM904.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16216757, "NumLink": 0, "digest": "sha256:a1cc3d93256ed9456365a2c01a8a5cc9839b31d0590180b0cf9ccf1c1fce6669" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM905.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16221066, "NumLink": 0, "digest": "sha256:171f80601fa0f39d5fcacbb48ee8221e8a1a194910f9ad98339c873f34b1b120" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM9066.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16225815, "NumLink": 0, "digest": "sha256:98dc687de3d0354f1224275324e3b80cbfbc47ea789e9f57924efe92a35bc830" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM918.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16230592, "NumLink": 0, "digest": "sha256:5908006ffeb6461a7586c6f7be52d01a1449dde53ef874866387d7bf5edc41dc" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM921.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16235488, "NumLink": 0, "digest": "sha256:5dd97299d93e5bfd2e8171e73b4230176555cf1ac088b5f704bc628efe55d8b0" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM922.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16240389, "NumLink": 0, "digest": "sha256:ee548a7a8ff7579dcda62cb4fba3d2b88f45bc603fcad99e11719ca96928f4d5" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM930.so", "type": "reg", "size": 108792, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16245492, "NumLink": 0, "digest": "sha256:de5b3714b8c22e51c6e2f82287b0609b036da9c81e51d1f3dfc5759899f6fa25" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM932.so", "type": "reg", "size": 71848, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16326736, "NumLink": 0, "digest": "sha256:e341b0d949b294e2af29882efa2c177ebedc1061dbdd8def17448ba28e86d2f4" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM933.so", "type": "reg", "size": 125176, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16386443, "NumLink": 0, "digest": "sha256:63647654e0331c4c95ad7989ebea843bc023583c462a50139e20a9dfaf881942" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM935.so", "type": "reg", "size": 88312, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16485478, "NumLink": 0, "digest": "sha256:22c972c25479bc47fbed3c1d4d7c50446f9dba07caea37254f3b259f1b4346bf" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM937.so", "type": "reg", "size": 112808, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16554275, "NumLink": 0, "digest": "sha256:61b08c43ad98438cfda2db99a1b3c68e0e88f82b5a14433563fb8662994e519d" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM939.so", "type": "reg", "size": 108792, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16641205, "NumLink": 0, "digest": "sha256:7f131860e5285f14114020bc4cd70a42ee1e94ce7aeec5f36a395d65094fe513" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM943.so", "type": "reg", "size": 71848, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16722354, "NumLink": 0, "digest": "sha256:5a2930c6e3412a012bec7d42e4e214fa4904d1d0117496ce7a3bb480c46e6e67" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IBM9448.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16782497, "NumLink": 0, "digest": "sha256:546743fef1081d17e538c4f00759378aa7fcfe8ad3024edd6bff5f60a819f4ea" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/IEC_P27-1.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16787777, "NumLink": 0, "digest": "sha256:913aba8336287510c2330d2f7bc614563b932586d282ff17ca08588cedb8b2d5" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/INIS-8.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16792818, "NumLink": 0, "digest": "sha256:7dea555becddc9e970a514b4787407289ed4e031d046b9c7644b655bcd265976" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/INIS-CYRILLIC.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16797155, "NumLink": 0, "digest": "sha256:8bdc14dff70504bc689a02df98bee665bfb58e233a3785fe793e29e454b40f11" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/INIS.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16801663, "NumLink": 0, "digest": "sha256:816a7e39ad8aa48a8cc520d5e0339a4a5f3ac6c1d14b03c6e7456c044cf11dd5" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISIRI-3342.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16805997, "NumLink": 0, "digest": "sha256:dda2bd62ba2860068ce89d2cf20e12220a24687ec71b8bc07380ae6b7b85203c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO-2022-CN-EXT.so", "type": "reg", "size": 39088, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16810860, "NumLink": 0, "digest": "sha256:e025193c38c4a257c6bc6cbbcfc76636ca73a09c9139b0626430ad27ff795513" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO-2022-CN.so", "type": "reg", "size": 34984, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16829575, "NumLink": 0, "digest": "sha256:65f8fdb4fa806278d1c8a6e5479cf0935b38c0ac5ef9f803f413db124beed643" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO-2022-JP-3.so", "type": "reg", "size": 26792, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16844919, "NumLink": 0, "digest": "sha256:f3bcfe27bb653b69949f0d6446544cd721f998dd56917d7e563097088d381afe" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO-2022-JP.so", "type": "reg", "size": 43208, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16857314, "NumLink": 0, "digest": "sha256:1a299788585bfd0f94ef83bc91170f6e4d8deff92153ab01f269be57e6ff153d" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO-2022-KR.so", "type": "reg", "size": 14504, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16877102, "NumLink": 0, "digest": "sha256:32dd52a49870d3495a86d9594cea8fb8093f2bd4aff8648b530ccf5043b5562c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO-IR-197.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16883964, "NumLink": 0, "digest": "sha256:cbb8b3adfc2e13b87e0e8ef29c430d5fc8d2f33cbaefdf96a0a549aa4044dc60" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO-IR-209.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16888927, "NumLink": 0, "digest": "sha256:8d8b34e4aa48e0b44836ebb35206743cc6d390da28d4ddf64c4ce880213ffd34" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO646.so", "type": "reg", "size": 18704, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16893904, "NumLink": 0, "digest": "sha256:625a226500b5f6c8ce49a86987decce222f543c22253560bd09949ce22fde3c5" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-1.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16903072, "NumLink": 0, "digest": "sha256:46727b1a93dd243dfb0429fcbb477bfdbd6b415daa00acfba60434f9283faaac" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-10.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16906849, "NumLink": 0, "digest": "sha256:851f0221d15a6c0e2da791226a6612184105741aa1ef006dda3b655308d91512" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-11.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16911763, "NumLink": 0, "digest": "sha256:dba2a8a403fab6f5f12ad1fe136f3fcde328339b61a7910b1de37c837bf545d3" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-13.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16916633, "NumLink": 0, "digest": "sha256:b8f450dcf883cd8c998a8755fcbead27e8a72a80d6728d231c41d728c3893277" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-14.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16921539, "NumLink": 0, "digest": "sha256:38998a00cb4eb2dbf7b2103ac1ba1c253b6d2bf604f8c2ff90569704e2d224c2" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-15.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16926468, "NumLink": 0, "digest": "sha256:c011d6da2ccc5cc2679d32d38b7722527aca659c6c3f449d9c9e73b499bd5a01" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-16.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16931317, "NumLink": 0, "digest": "sha256:0e41455363ef0515ff562b97ea50a0bf52f833d56b8a56d9f2adb53315438155" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-2.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16936226, "NumLink": 0, "digest": "sha256:5515c694f7211d21914cb5b20c7533d712b0ab8b3509e4eeb7ef89884fec632c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-3.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16940961, "NumLink": 0, "digest": "sha256:2d0c5d71deb6725dc7b6c5b64785cfd67bfef0f29089f8e263e90968ca8c544a" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-4.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16945727, "NumLink": 0, "digest": "sha256:b495bfa75a310c1795456ba1d0599299f80fee44cc62264809e52981dcc700d7" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-5.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16950466, "NumLink": 0, "digest": "sha256:12dd7d7541d9b049169eb3047adcb274f0a4a0e66fea7206421caed761260e0f" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-6.so", "type": "reg", "size": 14504, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16955330, "NumLink": 0, "digest": "sha256:553da67d94b5f224c7e687433ded076d6732cde209d6224e76522296230665ff" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-7.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16959999, "NumLink": 0, "digest": "sha256:eb496fdaedbc8b165c45a4b9fe86a698fd423ad2b5b44503571c81b66e6f16b9" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-8.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16964920, "NumLink": 0, "digest": "sha256:ae95477c13c51f9efcb543114ce0ccac531f42588b286d84ac69778a45409681" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-9.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16969714, "NumLink": 0, "digest": "sha256:6e6628a4f0a818d3eef3f22ef8fb119e0f3cae87852997124158135d948f37b8" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO8859-9E.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16974408, "NumLink": 0, "digest": "sha256:d575123ca67fb2e29c1fb632b0e42d31fd90bea935673f782e9047b0d6ec1c4d" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO_10367-BOX.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16979336, "NumLink": 0, "digest": "sha256:9f7e623d1a813d7499f13eda918130d8b4b6865f7fb44f88eecb9e82a7d33780" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO_11548-1.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16984078, "NumLink": 0, "digest": "sha256:99a44f668b7d38c97c2792319b325963f28c47b3677db18a41e8fe4e7a4d9fa3" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO_2033.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16987856, "NumLink": 0, "digest": "sha256:26cffd10435270376d9dc677847bafd6eb1c7ea08b0534162798feed6547a1d2" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO_5427-EXT.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16992024, "NumLink": 0, "digest": "sha256:0b8cc43ca2ff904d2c67eadd907b9e235055336e4f0b31cd5c413d53ae2754bc" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO_5427.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 16996339, "NumLink": 0, "digest": "sha256:346d9e98132068c292ab331c0f1a7291df75b727b2c5c713c4470aa70a95301d" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO_5428.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17000793, "NumLink": 0, "digest": "sha256:fa3a53e36ea0e51b216cb0c128a3ec2746099f9b1799d36b3d2ffa78bbb50844" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO_6937-2.so", "type": "reg", "size": 22696, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17005266, "NumLink": 0, "digest": "sha256:917eec307f0419b0eb5626a3ce06a06c6b2cde5bfb07eee33e690351b5d2bf2c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/ISO_6937.so", "type": "reg", "size": 22696, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17013126, "NumLink": 0, "digest": "sha256:7bdf85fceef907f3f107f180ee1c8035df2a4a6f8ea081c470d8ef69d3b4104e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/JOHAB.so", "type": "reg", "size": 18600, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17021010, "NumLink": 0, "digest": "sha256:49f1473027e1f4a77cb488a480a2416c2da50817e4ce504382bffbd628020b56" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/KOI-8.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17029049, "NumLink": 0, "digest": "sha256:3e7a16200475dd0f5b4efc87d4d7b76d69d74418d3b8a5ea6a9b1103885ef543" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/KOI8-R.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17033579, "NumLink": 0, "digest": "sha256:3734f0fce1d3cea25057e64a3040067c2b4a75095a844b0014533f58eae0caab" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/KOI8-RU.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17038579, "NumLink": 0, "digest": "sha256:c4bcab695d57c38718e0e0f2bcd54ec8d0c8d5c4ab6b3bdd435b0ae47bba59e3" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/KOI8-T.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17043587, "NumLink": 0, "digest": "sha256:79c497aebaaa188ebc8e112fa86c1c52510e1ff8acf5020a413289cfde47103d" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/KOI8-U.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17048509, "NumLink": 0, "digest": "sha256:6c0fee532eef0f23262c6f5f40dd7bd0e75f3348c444600dd22974f1efbb869f" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/LATIN-GREEK-1.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17053521, "NumLink": 0, "digest": "sha256:bfbafee63147fa484f5d99d50185b8650dc654d0261e30d557caa04f086ee04e" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/LATIN-GREEK.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17057977, "NumLink": 0, "digest": "sha256:1d9886ec5ac307b7d6dcdde296d9776ff03742108fc9edde3a7edf5cfb6a4edd" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/MAC-CENTRALEUROPE.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17062446, "NumLink": 0, "digest": "sha256:7b5342684ef8b8d3b96bb77796d922eee2d86f51bd4dc3e2f6be99c94d4c89c4" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/MAC-IS.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17067418, "NumLink": 0, "digest": "sha256:1cda7799bf65f03fdce63d58f62ff3d3ee232381a936d27dd7ffb2bdd2640e12" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/MAC-SAMI.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17072464, "NumLink": 0, "digest": "sha256:7e59bc0bcef532ac1921dabe599d97cf51ac48bc96ba94cd16e3332b34010088" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/MAC-UK.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17077453, "NumLink": 0, "digest": "sha256:e1e6608ed00aa7edd17536a89b55772415b69698d74b0e7ac56bff88ddae7d0a" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/MACINTOSH.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17082395, "NumLink": 0, "digest": "sha256:bb17f05e20edcb5a297536325145fb8fb8944df8ed3e2b304fd9a3f7d70d6daa" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/MIK.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17087461, "NumLink": 0, "digest": "sha256:c1182feb2279704ac8908682559744389a8a643378d6937eb68f78b2ba213ee7" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/NATS-DANO.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17092524, "NumLink": 0, "digest": "sha256:bf1cf46fc38c6797ed76283e8d7167dc0db37e7b19988a6dd1021006bd05f371" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/NATS-SEFI.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17097005, "NumLink": 0, "digest": "sha256:05c0ce52f879990be8e84ee6fd13cd1056b3ba371769017b9d4739447342891c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/PT154.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17101473, "NumLink": 0, "digest": "sha256:bccaa42a9d9707c53b6646385a5dd19f6498bfe11048a51812d1e576dc6d2577" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/RK1048.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17106400, "NumLink": 0, "digest": "sha256:d49391cc45f31a755e61a9200df1f574bb6f2e8be75808b95c54a427f80e0c63" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/SAMI-WS2.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17111410, "NumLink": 0, "digest": "sha256:d0dafadac4c42a811741e0cd8c7e2fde3ec62ef1dbab88b93bb0d4b0b2c7c116" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/SHIFT_JISX0213.so", "type": "reg", "size": 18600, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17116379, "NumLink": 0, "digest": "sha256:ce1c56c87b70ae86f4e8740beb57bf0856842ee16aa681f7c1fab2f3c6ce055a" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/SJIS.so", "type": "reg", "size": 96424, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17124377, "NumLink": 0, "digest": "sha256:b4dd8bf37ed58cb46c1e62348e7731bcc49a3345646fa0d448e1764276a16203" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/T.61.so", "type": "reg", "size": 18600, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17163270, "NumLink": 0, "digest": "sha256:3e420f16235289e9ca17826b421ef9ec9db680fe943fbd159ff7cb48e340cd99" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/TCVN5712-1.so", "type": "reg", "size": 14512, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17170395, "NumLink": 0, "digest": "sha256:6b6c6e685c14292a607b93d809350c567e2a4e3a1548c6bb7b0b80a424163f61" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/TIS-620.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17177861, "NumLink": 0, "digest": "sha256:640a340021b4d554c98cff37bcb5b9e15346398e3af69629ff6b3366a04a1392" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/TSCII.so", "type": "reg", "size": 18600, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17182612, "NumLink": 0, "digest": "sha256:3a12de9b3f86bd3f60a14ecbd5b8736b8889da21d467eb2509a6baa47c9181a4" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/UHC.so", "type": "reg", "size": 71848, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17191613, "NumLink": 0, "digest": "sha256:87745f69d98339a80a94319c170c349e80b4d82ea2da5396f32e92f9b6baf687" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/UNICODE.so", "type": "reg", "size": 10424, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17239936, "NumLink": 0, "digest": "sha256:8a56a8d04dfc075211652c6d262025496610816f21c50f24a94dd44e3b464998" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/UTF-16.so", "type": "reg", "size": 14528, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17244247, "NumLink": 0, "digest": "sha256:968f95cc06ad1abccf4a9d085bc56c4bcb63dfa2a7d89772702ed33c8d7fdeca" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/UTF-32.so", "type": "reg", "size": 10432, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17250022, "NumLink": 0, "digest": "sha256:f1c221602b45ccc3050a416128510f555017047673d13e56af123a1435717fa0" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/UTF-7.so", "type": "reg", "size": 18608, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17254582, "NumLink": 0, "digest": "sha256:d69f39af22d64a34517529b6335756ce362daa89c9d90e36865950405ecf789c" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/VISCII.so", "type": "reg", "size": 10408, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17263074, "NumLink": 0, "digest": "sha256:441f95483f53007c5934b27a02980cb5e3c9a00f8d10600207cf66a84ced2098" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/gconv-modules", "type": "reg", "size": 56095, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17267992, "NumLink": 0, "digest": "sha256:6f90f42555e1f390e26b6090186384cf4131bba167c331b58e8d7b13f86b7b45" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache", "type": "reg", "size": 26258, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17277397, "NumLink": 0, "digest": "sha256:eef49f11d96d1ff44e461f9ef1dfbd9a70f02ab5dbaec1cc302527a775c62fe4" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/libCNS.so", "type": "reg", "size": 468984, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17288862, "NumLink": 0, "digest": "sha256:fbc708c917e17da80bbc83b4d1cbfd47d511c17085ef18e8c0241a83ce8ee5dd" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/libGB.so", "type": "reg", "size": 67576, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17580006, "NumLink": 0, "digest": "sha256:015d06af82091920aa60f2b9e06ae8b18ad45488917f270a956ebd11c7d67674" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/libISOIR165.so", "type": "reg", "size": 59384, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17614076, "NumLink": 0, "digest": "sha256:3aed87fc8c51a7f5de1921639de2c02499b1075852c98c23a95827bc40e5b667" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/libJIS.so", "type": "reg", "size": 100344, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17654497, "NumLink": 0, "digest": "sha256:a329c58c5692ae5fb1a3d900a14226def7afbeae9293a352291f963d9d167fcd" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/libJISX0213.so", "type": "reg", "size": 120824, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17721680, "NumLink": 0, "digest": "sha256:d4c0867d87e8d3b67cbaf3d16d9e0febbc4c889ea99312b06628641004027ec2" }, { "name": "usr/lib/x86_64-linux-gnu/gconv/libKSC.so", "type": "reg", "size": 47096, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 17773967, "NumLink": 0, "digest": "sha256:a162aa2fce5ab2a500d13c461d90c772dea2e3134f01c788908de538584cb626" }, { "name": "usr/lib/x86_64-linux-gnu/libapt-pkg.so.5.0", "type": "symlink", "modtime": "2017-09-13T16:47:33Z", "linkName": "libapt-pkg.so.5.0.1", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/libapt-pkg.so.5.0.1", "type": "reg", "size": 1776872, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 17813375, "NumLink": 0, "digest": "sha256:c90b5b1173c7e515a7fefee77c5d9b8d0fef4e4ca49b89e806061fb0b30f6088" }, { "name": "usr/lib/x86_64-linux-gnu/libapt-private.so.0.0", "type": "symlink", "modtime": "2017-09-13T16:47:33Z", "linkName": "libapt-private.so.0.0.0", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/libapt-private.so.0.0.0", "type": "reg", "size": 378968, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 18584843, "NumLink": 0, "digest": "sha256:5b38fedfa8f8a38929bb9fdfa5bc65a15610457b53a662f50f7ec6dca23e2fce" }, { "name": "usr/lib/x86_64-linux-gnu/libdb-5.3.so", "type": "reg", "size": 1827512, "modtime": "2017-09-24T07:14:53Z", "mode": 33188, "offset": 18743676, "NumLink": 0, "digest": "sha256:0d14b28c8e96a50f8532cc26eb8c6e9f49db92fbe9cd35389a3926599c92a12c" }, { "name": "usr/lib/x86_64-linux-gnu/libdebconfclient.so.0", "type": "symlink", "modtime": "2017-04-03T05:58:27Z", "linkName": "libdebconfclient.so.0.0.0", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/libdebconfclient.so.0.0.0", "type": "reg", "size": 10360, "modtime": "2017-04-03T05:58:27Z", "mode": 33188, "offset": 19590542, "NumLink": 0, "digest": "sha256:a2a1f22356ddcffcf35745f744dfeabdee3147653226ab168f994d832fad2638" }, { "name": "usr/lib/x86_64-linux-gnu/libformw.so.5", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "libformw.so.5.9", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/libformw.so.5.9", "type": "reg", "size": 68840, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 19593588, "NumLink": 0, "digest": "sha256:fc08c8a92dab40a2bdefe2524665db90e03cd483a173d7ca643deaf9deb45461" }, { "name": "usr/lib/x86_64-linux-gnu/liblz4.so.1", "type": "symlink", "modtime": "2016-02-17T15:27:54Z", "linkName": "liblz4.so.1.7.1", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/liblz4.so.1.7.1", "type": "reg", "size": 72024, "modtime": "2016-02-17T15:27:54Z", "mode": 33188, "offset": 19624444, "NumLink": 0, "digest": "sha256:89bfd1003b37b293626a7800b34eab1b1d665465960d6955fd151eda316d14a1" }, { "name": "usr/lib/x86_64-linux-gnu/libmenuw.so.5", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "libmenuw.so.5.9", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/libmenuw.so.5.9", "type": "reg", "size": 35088, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 19658643, "NumLink": 0, "digest": "sha256:00069d616f3a56330f24e452e3950fc374fc5f380d46a71d4eea516cdfb46933" }, { "name": "usr/lib/x86_64-linux-gnu/libpanelw.so.5", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "libpanelw.so.5.9", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/libpanelw.so.5.9", "type": "reg", "size": 14184, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 19673786, "NumLink": 0, "digest": "sha256:b59bd2358da7fbe2f4c9a3df20781c72a00dd271fc93243363d566f3b862252c" }, { "name": "usr/lib/x86_64-linux-gnu/libpcreposix.so.3", "type": "symlink", "modtime": "2017-03-21T22:03:19Z", "linkName": "libpcreposix.so.3.13.3", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/libpcreposix.so.3.13.3", "type": "reg", "size": 10128, "modtime": "2017-03-21T22:03:19Z", "mode": 33188, "offset": 19679391, "NumLink": 0, "digest": "sha256:20ab25eb5624d2f2046c5a960f9b430cd5d2d26bb6d06659d2ba5ec99c33dcd6" }, { "name": "usr/lib/x86_64-linux-gnu/libsemanage.so.1", "type": "reg", "size": 248032, "modtime": "2016-12-30T15:42:09Z", "mode": 33188, "offset": 19682805, "NumLink": 0, "digest": "sha256:a49abba01c68d4b5ee596db8bb5d1df4f7fc8eabf7650dcb87f54acd7572d824" }, { "name": "usr/lib/x86_64-linux-gnu/libstdc++.so.6", "type": "symlink", "modtime": "2018-02-14T16:53:20Z", "linkName": "libstdc++.so.6.0.22", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22", "type": "reg", "size": 1566168, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 19780945, "NumLink": 0, "digest": "sha256:4376550db3d4404d019fab791ad0795ec76ded3fc969248c11ec6d775f614860" }, { "name": "usr/lib/x86_64-linux-gnu/libtic.so.5", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "libtic.so.5.9", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/libtic.so.5.9", "type": "reg", "size": 59400, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 20271814, "NumLink": 0, "digest": "sha256:c75698c2c3fe73c1eb5cda96578cf74aebd9d9115e5094cd17d2d14fc21cac89" }, { "name": "usr/lib/x86_64-linux-gnu/libustr-1.0.so.1", "type": "symlink", "modtime": "2016-11-23T19:59:34Z", "linkName": "libustr-1.0.so.1.0.4", "mode": 41471, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/libustr-1.0.so.1.0.4", "type": "reg", "size": 215040, "modtime": "2016-11-23T19:59:34Z", "mode": 33188, "offset": 20301589, "NumLink": 0, "digest": "sha256:95f03fca5815ca2181d1323e140aa73f89842dd3792efc836dc1ca7bab1b27f8" }, { "name": "usr/lib/x86_64-linux-gnu/perl/", "type": "dir", "modtime": "2018-06-10T17:37:28Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/AutoLoader.pm", "type": "reg", "size": 5487, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20380419, "NumLink": 0, "digest": "sha256:750ee369fbf3c34f72a823ca261d33a89bba98ad1d4a967f4f89e19b122eaabf" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Carp/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Carp/Heavy.pm", "type": "reg", "size": 773, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20382632, "NumLink": 0, "digest": "sha256:d5ac9b22f0e3e5632a1ce0945adedacbcfd02f4409d60437e908604f4857fb58" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Carp.pm", "type": "reg", "size": 20138, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20383195, "NumLink": 0, "digest": "sha256:fa19d9299eb23a422f3d8220e06e434ea4e6b3154226d8ec8ba84cb3904060d4" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Config.pm", "type": "reg", "size": 3331, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20390093, "NumLink": 0, "digest": "sha256:2f1a1c4013c19ebf4260c6b6e5f0039145f54409411fd140b4f153e641d7fad2" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Config_git.pl", "type": "reg", "size": 409, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20391666, "NumLink": 0, "digest": "sha256:09c5e2ee35ee18d9043d95273f1cd37bc82e80567fd1372a1eb134c809c39504" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Config_heavy.pl", "type": "reg", "size": 50645, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20391977, "NumLink": 0, "digest": "sha256:0ecaa7f841191eed99ec3daaa84d891eb68125d1f357f337160a630dea100d12" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Cwd.pm", "type": "reg", "size": 18542, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20407426, "NumLink": 0, "digest": "sha256:0e707f6c9273736f137eed9710aa2eec7edf582f86813abc8820fb982c4bf101" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/DynaLoader.pm", "type": "reg", "size": 10453, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20414075, "NumLink": 0, "digest": "sha256:877b793ad9ae57d997c22aa505862f0a44221764b12201a2bc8634260ac7fffc" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Errno.pm", "type": "reg", "size": 4884, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20418413, "NumLink": 0, "digest": "sha256:fb0e2878b7d240e5d4a74509a19ae2fff14ffe23ab3a69494c41a916ab915443" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Exporter/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Exporter/Heavy.pm", "type": "reg", "size": 6406, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20420798, "NumLink": 0, "digest": "sha256:4a05d2fb4ade7016e108d8b8cdb25b8426b232560be0874755b198fc5be0fee1" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Exporter.pm", "type": "reg", "size": 2367, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20423386, "NumLink": 0, "digest": "sha256:b9db7ff262f5d5bcc8ac7c827b0453c7e514c3cb1dd6a30fad96a25de2a76991" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Fcntl.pm", "type": "reg", "size": 2156, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20424559, "NumLink": 0, "digest": "sha256:293ad7b0904fa32bf79bda796dd2244e799bb6b42450c910ef8f54d2edf076ee" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/File/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/File/Basename.pm", "type": "reg", "size": 5429, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20425726, "NumLink": 0, "digest": "sha256:9aeea43fda475ea4e2b75633b2e25528f45b2510c7df4809449fbf938de58bd8" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/File/Glob.pm", "type": "reg", "size": 1837, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20427698, "NumLink": 0, "digest": "sha256:ad3a5d01dbdaea75fe6a46ab66146583d71ba0fff3b7b91dce67409a2d6e5f84" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/File/Path.pm", "type": "reg", "size": 18490, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20428654, "NumLink": 0, "digest": "sha256:83defe5b5d9de11983c36de5507cefbf71822786fcd05d4549b4d3ab083f654a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/File/Spec/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/File/Spec/Unix.pm", "type": "reg", "size": 10014, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20433898, "NumLink": 0, "digest": "sha256:9be5591be0deed683c85b784c13d7706aaf156301da775975bc529fc31fb7ddd" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/File/Spec.pm", "type": "reg", "size": 622, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20437583, "NumLink": 0, "digest": "sha256:fd864e0a9be904138992c9174a9f51524d38599ad6b1d584fa8ef723c652c3dd" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/File/Temp.pm", "type": "reg", "size": 46927, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20438022, "NumLink": 0, "digest": "sha256:f83f5e969b8ba4cb9de0302624d1df4220f1ad8c5e20f83acb9967d474516fb2" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/FileHandle.pm", "type": "reg", "size": 2105, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20452671, "NumLink": 0, "digest": "sha256:54211db845a110f16d8f3630e2cd2d258f2e47078a1e5261b0eae18a0a5d6cd5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Getopt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Getopt/Long.pm", "type": "reg", "size": 43321, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20453804, "NumLink": 0, "digest": "sha256:0a9a40e9df4b4c1a5aa260ab5fc9affa4cae13a8070fc52aea6768d276434fb9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Hash/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Hash/Util.pm", "type": "reg", "size": 7580, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20466581, "NumLink": 0, "digest": "sha256:983dc4ad312e28882bc90465167f4a19e03dd4c27ecae615190cdbc26aa0fc82" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IO/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IO/File.pm", "type": "reg", "size": 1666, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20468833, "NumLink": 0, "digest": "sha256:79263664dcd2997530dd5d941fbccc1470d4c66b8ae82c02fd96290513c39d14" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IO/Handle.pm", "type": "reg", "size": 8235, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20469704, "NumLink": 0, "digest": "sha256:fb4a9ff170e5a74ded4c42c539f6d5ce8999761b394830d39e6d3f152ab73b69" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IO/Pipe.pm", "type": "reg", "size": 3425, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20472376, "NumLink": 0, "digest": "sha256:45f66014a6b374dbbbcc0325c79024b7d8bb22b41c8c7dc855e4394cebfe7c26" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IO/Seekable.pm", "type": "reg", "size": 686, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20473786, "NumLink": 0, "digest": "sha256:a8ac552be340a0b593516d44eb34ca695676e46d2492f2651efeb6ada7f22103" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IO/Select.pm", "type": "reg", "size": 4359, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20474271, "NumLink": 0, "digest": "sha256:09c61eed565460a2edee326be3eb5391ce55c0e3c53ec74c831a87646decf955" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IO/Socket/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IO/Socket/INET.pm", "type": "reg", "size": 7474, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20476044, "NumLink": 0, "digest": "sha256:4ff429519f3b93fb5e6ae2e42127b75cc5f37b6978de5885fd8251f7489057f9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IO/Socket/IP.pm", "type": "reg", "size": 20427, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20478446, "NumLink": 0, "digest": "sha256:866b9e45195fabae560e69cb445142d8e2aa902825c54b183fe5463137b7aa9a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IO/Socket/UNIX.pm", "type": "reg", "size": 1375, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20484519, "NumLink": 0, "digest": "sha256:1555039d56f24fccc3b829dcd40b87c1aa04b22e37b228e903ce12fb9bd0d58e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IO/Socket.pm", "type": "reg", "size": 9455, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20485297, "NumLink": 0, "digest": "sha256:c1074f21b6d6a5e43e8c4363cb7ca4847a32e24f373d10ada9dfd3c93bad2d9c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IO.pm", "type": "reg", "size": 472, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20488603, "NumLink": 0, "digest": "sha256:3d851a18125f4ad6f9d4d9aa8be00a33ce924b3965f0381fd8e74ac1507f68c6" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IPC/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IPC/Open2.pm", "type": "reg", "size": 816, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20489092, "NumLink": 0, "digest": "sha256:6500142ce04d79ddb58102de7bdf1427c49a9d1be04f6c908027b6240a0e6303" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/IPC/Open3.pm", "type": "reg", "size": 9053, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20489716, "NumLink": 0, "digest": "sha256:2d4aa629476d90f663ebff57af566044f9cb134f4eef1699516dc13c227cdb83" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/List/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/List/Util.pm", "type": "reg", "size": 1078, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20493539, "NumLink": 0, "digest": "sha256:0d9f7992c477f3cce159a5477927380e304cca7cb4cc99abf9e520bff652ffab" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/POSIX.pm", "type": "reg", "size": 19879, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20494294, "NumLink": 0, "digest": "sha256:9d3f00c0ad31d9bc8875d19f0703490b39bc4ff8c36de3864269fd30708165a7" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Scalar/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Scalar/Util.pm", "type": "reg", "size": 1410, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20502130, "NumLink": 0, "digest": "sha256:3b04edbbe4a7f38411c5081ab10c79f538e7c08dd7b4866d63f60492a2d09be6" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/SelectSaver.pm", "type": "reg", "size": 344, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20502957, "NumLink": 0, "digest": "sha256:f6f2b9bf40423e54466311866dc9f67a1318396d2d162cf84722e28d715a0ca9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Socket.pm", "type": "reg", "size": 13554, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20503310, "NumLink": 0, "digest": "sha256:535d67a90adfaab5f799eea70bf57859da660a0c99fd4777384d7e85123d0b8c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Symbol.pm", "type": "reg", "size": 2099, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20508323, "NumLink": 0, "digest": "sha256:b2ba240a38118df64bb369c770ae6476502a71097ba53f65fe435d82deafd94d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Text/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Text/ParseWords.pm", "type": "reg", "size": 4480, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20509533, "NumLink": 0, "digest": "sha256:aa7484ce8671e27adbb65f24d19d376882e84edab8da3ea91d144fefc6906184" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Text/Tabs.pm", "type": "reg", "size": 1702, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20511107, "NumLink": 0, "digest": "sha256:fa167b69c997b88b575b3a98013421745b41c3681b0a6a7433f17c1da19f8f25" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Text/Wrap.pm", "type": "reg", "size": 2922, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20512058, "NumLink": 0, "digest": "sha256:d63777a317a5631dcfb6b0ea4ae5f782d2e718ff31b9f091ac03962a997fc095" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Tie/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/Tie/Hash.pm", "type": "reg", "size": 2037, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20513449, "NumLink": 0, "digest": "sha256:e81ae4e495e961af321beac6695b5d43870418739901785a6b90c742f2d39d42" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/XSLoader.pm", "type": "reg", "size": 3899, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20514378, "NumLink": 0, "digest": "sha256:7d50e4be2f9f14462e63858a7e2582e3e7eb7ecef4d7f2c8e74634abf71b987d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/attributes.pm", "type": "reg", "size": 3018, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20516162, "NumLink": 0, "digest": "sha256:67b321a13ffc51ace70061b9d2a079e1775fd7b915c27a3176cc40c7fab5a9e6" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/", "type": "dir", "modtime": "2018-06-10T17:37:28Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/Cwd/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/Cwd/Cwd.so", "type": "reg", "size": 18704, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20517619, "NumLink": 0, "digest": "sha256:ec2714a435c774dba95b03f798b37f13cee4041449dfbc1c131c1234ff2bd0df" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/Fcntl/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/Fcntl/Fcntl.so", "type": "reg", "size": 18688, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20524515, "NumLink": 0, "digest": "sha256:ea8785c9591bb2c1d35e125a1b7c92fa14c01e3558004ecfd85d6ba0cf932bdf" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/File/", "type": "dir", "modtime": "2018-06-10T17:37:28Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/File/Glob/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/File/Glob/Glob.so", "type": "reg", "size": 27176, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20531138, "NumLink": 0, "digest": "sha256:9a11a966a7961d77dc8b882e35c0424f6a938a8931e6ad8994298f19292e6772" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/Hash/", "type": "dir", "modtime": "2018-06-10T17:37:28Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/Hash/Util/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/Hash/Util/Util.so", "type": "reg", "size": 14544, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20543995, "NumLink": 0, "digest": "sha256:c4f6fe1e6a3f629d31afeb9f4b27d3f83a68f7efaf9e4fa29aa143cf728d38de" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/IO/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/IO/IO.so", "type": "reg", "size": 18768, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20550050, "NumLink": 0, "digest": "sha256:11b53111335419d0c238e35d067fc2eca5d7b8c0ecf98570b0d6b5a537980870" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/List/", "type": "dir", "modtime": "2018-06-10T17:37:28Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/List/Util/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/List/Util/Util.so", "type": "reg", "size": 47696, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20557011, "NumLink": 0, "digest": "sha256:73c3c43ebc0f93b27345edfd7795f4fdeeb9004d3a30e51dd0a33046282f619e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/POSIX/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/POSIX/POSIX.so", "type": "reg", "size": 106128, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20577193, "NumLink": 0, "digest": "sha256:aeb85d4a9ea24a5350c0e68574d7b343aceea965eb733125bd2c3710bd924797" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/Socket/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/Socket/Socket.so", "type": "reg", "size": 43464, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20614367, "NumLink": 0, "digest": "sha256:503d657ab8a95d1979f74bdcce8796f06f32d49f7a8631815e07e53a0073845c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/attributes/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/attributes/attributes.so", "type": "reg", "size": 10408, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20630016, "NumLink": 0, "digest": "sha256:4031753d1e50bc3e256e64af263c0ae58f9080219869fd6b3fd0e2e383b43427" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/re/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/auto/re/re.so", "type": "reg", "size": 495120, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20634547, "NumLink": 0, "digest": "sha256:2aeebf7edb04019dcfefaa326d6d779766d3b5da6ec6633807bd569fbcf5dd85" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/base.pm", "type": "reg", "size": 8931, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20858830, "NumLink": 0, "digest": "sha256:394447d984af9973eef7ce0628625cfad98ec778f3ed81a467f0b8c6ed2fd1a1" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/bytes.pm", "type": "reg", "size": 447, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20862319, "NumLink": 0, "digest": "sha256:cb05c506666da8af731d6470f1d5824c794461e1d5a6a4fd0ec9a78d1589e574" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/bytes_heavy.pl", "type": "reg", "size": 758, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20862684, "NumLink": 0, "digest": "sha256:c7def62cbf7d031c4fe319e414117043f2a273885bff93bd18e11935d00a6677" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/constant.pm", "type": "reg", "size": 5737, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20863007, "NumLink": 0, "digest": "sha256:5decbf923c0f5f065147a7a1a89fd351a26d5d5efd8799ba4ee992a1d00cd837" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/feature.pm", "type": "reg", "size": 4313, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20865364, "NumLink": 0, "digest": "sha256:79baab039d05935885bb984532dbfeed64e4fd5b238a6c6cdce38b92524bad92" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/fields.pm", "type": "reg", "size": 5022, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20866841, "NumLink": 0, "digest": "sha256:47de715abc8377a925a04ca8e0f68f80957c075fd0cddb2400724968c22c08ef" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/integer.pm", "type": "reg", "size": 172, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20868888, "NumLink": 0, "digest": "sha256:1c387bfbc4bcb4046e7372c534372c7150315499bc5641328d5c3c1c1ad50373" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/lib.pm", "type": "reg", "size": 2284, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20869115, "NumLink": 0, "digest": "sha256:6636e89a2107d3d76574e41f6535aee9d740700c892fe1f0179f015356d9ba4e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/locale.pm", "type": "reg", "size": 3421, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20870148, "NumLink": 0, "digest": "sha256:d584f47f71a525301511965b4a245933e9a936f94406b6bcd1c78e7fe63a7b6f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/overload.pm", "type": "reg", "size": 4466, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20871537, "NumLink": 0, "digest": "sha256:6eb2a643d33cb9ad8c265e890836c4c9a7bf3be53efa9a75e6bf8a99704f927d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/overloading.pm", "type": "reg", "size": 964, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20873372, "NumLink": 0, "digest": "sha256:5387b33943963d2e47f05b3f37926f2d454f9ded33ca857e56ffb33b3adb999d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/parent.pm", "type": "reg", "size": 479, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20873905, "NumLink": 0, "digest": "sha256:3ce8f47c371967107564fdb66a00c46303213f8f6e7c933e19ed856af79af758" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/re.pm", "type": "reg", "size": 8639, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20874317, "NumLink": 0, "digest": "sha256:7aec46a23600f1c35b9037a0ffefb061bf064e4954b4e35f4eeb39d22b46c8e3" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/strict.pm", "type": "reg", "size": 1606, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20877274, "NumLink": 0, "digest": "sha256:3f100533c2abc1cd0b20060bfe71372c28443b13356fd5604133a69e844fc88b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/Heavy.pl", "type": "reg", "size": 129498, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20878088, "NumLink": 0, "digest": "sha256:cac1f06d7853a8dd1f6b8b59c3341758cbf59dd48c11c47ef1c1982a09d7fd4e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Age.pl", "type": "reg", "size": 17925, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20905776, "NumLink": 0, "digest": "sha256:799fc2db4cef7d7dda3548341210a8682ee71a2f4added92776b9991c65620b3" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Bc.pl", "type": "reg", "size": 7925, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20913050, "NumLink": 0, "digest": "sha256:172a214478d317cb35788e97fa81a574ed0ffd9ac3abe5fb42119973fad512c3" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Bmg.pl", "type": "reg", "size": 5118, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20916542, "NumLink": 0, "digest": "sha256:6d45b0fb96dc56845f3c1444b2d92fa7029f6d0f06aa807725d94708e6de1030" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Bpb.pl", "type": "reg", "size": 2125, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20919036, "NumLink": 0, "digest": "sha256:495995c6eb2b997756c2b2f91071b2f9a2e3a0cafd63a69e9f6f347af868ce05" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Bpt.pl", "type": "reg", "size": 1692, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20920165, "NumLink": 0, "digest": "sha256:bdbc4054229d801ca6824d97da7cd8b618437a3587eee430578b870c1f55d4eb" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Cf.pl", "type": "reg", "size": 15381, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20921046, "NumLink": 0, "digest": "sha256:54a8ed05ddd618f1fa3bcbb38843656be0d9665870513e0f7a2565b26f589d9f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Digit.pl", "type": "reg", "size": 5673, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20926472, "NumLink": 0, "digest": "sha256:cb144fe271026cc6d95fbc440569557c8ab031e5f20697e2024af502680b0c49" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Ea.pl", "type": "reg", "size": 2980, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20928828, "NumLink": 0, "digest": "sha256:d1c2abec486552afa3e054d3a04c051337f8a2baf2ad28af3ade507dec6f5bb2" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Fold.pl", "type": "reg", "size": 22741, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20930384, "NumLink": 0, "digest": "sha256:5ab3a81e3d6fb8c22832d335e3c621a35f084f21d045f2d9ab4ce3c13b85ca6e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/GCB.pl", "type": "reg", "size": 17439, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20938364, "NumLink": 0, "digest": "sha256:0d7c93cd1e83dc9729c54cd49fdc39b3f7aeb10e0f010bab7957a4df4510b206" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Gc.pl", "type": "reg", "size": 31753, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20944222, "NumLink": 0, "digest": "sha256:c7ac42570c6443b79837db38e7b28400def99821d69533222e13456640c0d9dd" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Hst.pl", "type": "reg", "size": 9998, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20956677, "NumLink": 0, "digest": "sha256:023125f07cd4d45f40c3970bbaae4649dd7749f2ce60afb5065446426a606a83" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/InPC.pl", "type": "reg", "size": 7712, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20960205, "NumLink": 0, "digest": "sha256:4ed0cf7f0e9344d0359c962b30fee48084b5e1554a52c85fc7f5265e7ebf71fb" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/InSC.pl", "type": "reg", "size": 13326, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20963031, "NumLink": 0, "digest": "sha256:2442f91af082912354e8047ba1f2ce6c261de8bf48591749e9405f9d242fa8d4" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Isc.pl", "type": "reg", "size": 798, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20967132, "NumLink": 0, "digest": "sha256:6a774b0bbaa651dbdb6c76d01689c0c5b45258b7cdab8d6b33e8e8e2fa07f151" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Jg.pl", "type": "reg", "size": 3112, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20967713, "NumLink": 0, "digest": "sha256:a7b09acc2d7518a722dabe81efd8fe4a3f50f633da21709d89d38a8f3ce574a4" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Jt.pl", "type": "reg", "size": 4702, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20969363, "NumLink": 0, "digest": "sha256:db6d2fdf3147500d04a81c1e3912dfaa0b90d07047f6ca54b7e29b463368029c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Lb.pl", "type": "reg", "size": 29045, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20971709, "NumLink": 0, "digest": "sha256:d85bf398ecf6f2e50e8d3e7b8dca3f6d011133b50b25e0f20fe9eda8e3511939" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Lc.pl", "type": "reg", "size": 8187, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20983312, "NumLink": 0, "digest": "sha256:07164c5cdd6a9a387080628aa79b8bee7f330937391b6245b8504a3efd7a1d3f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Lower.pl", "type": "reg", "size": 15524, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20987466, "NumLink": 0, "digest": "sha256:d0215cd96047e1d95cab34a25177d117b886b83ca778abefda7e246f84ea10df" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/NFCQC.pl", "type": "reg", "size": 1751, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20994145, "NumLink": 0, "digest": "sha256:8b3c568799d0d1b374373948f3084efd18881070e6deaac8ec3a09a2ddd10232" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/NFDQC.pl", "type": "reg", "size": 2920, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20995181, "NumLink": 0, "digest": "sha256:6763a26a0fbf79445cff82309d495738d81b6d6383617683a57f61b3812fb17b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/NFKCCF.pl", "type": "reg", "size": 398291, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 20996710, "NumLink": 0, "digest": "sha256:bfecad5f99d94c2f4a2b4963ebe2750fa9908b15cb4efe7c438eb6c80a3d200c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/NFKCQC.pl", "type": "reg", "size": 3714, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21055779, "NumLink": 0, "digest": "sha256:9b80985800cfef4f1501f705642040f7190fe032b318320a280f4ff35562891a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/NFKDQC.pl", "type": "reg", "size": 4719, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21057625, "NumLink": 0, "digest": "sha256:5f65d6e6d9e3fe8083d0ac3020a2b1a862247fa49e5ced277c7958d8255fd920" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Na1.pl", "type": "reg", "size": 63563, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21059896, "NumLink": 0, "digest": "sha256:63b774155c56a83a978a6694c58f9b57de8eb0f8fa8e06236126eef9aec97841" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/NameAlia.pl", "type": "reg", "size": 13366, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21073969, "NumLink": 0, "digest": "sha256:b03da714d8dfc017d7bd2f2677061d395d23e923e014c65385d4f19c16374b75" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Nt.pl", "type": "reg", "size": 4211, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21077590, "NumLink": 0, "digest": "sha256:fea2fae1f19a464744e165bba3bf0547d4551a54205d9e10dad4457ec19e67a8" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Nv.pl", "type": "reg", "size": 7517, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21079264, "NumLink": 0, "digest": "sha256:2a2360e18d5df4d2b10ad5217bbbb2a60e2a4bb3e7407bdc134786898c7e2c75" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/PerlDeci.pl", "type": "reg", "size": 1621, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21082547, "NumLink": 0, "digest": "sha256:97866947d1ede559eb516bf4d4460b401381fde6777562b49f1120f0d6013652" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/SB.pl", "type": "reg", "size": 31093, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21083542, "NumLink": 0, "digest": "sha256:28e91b6b63b070bc0cc7d50c32334165c63035d77c8e68077c5cbccc0c930371" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Sc.pl", "type": "reg", "size": 15111, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21092862, "NumLink": 0, "digest": "sha256:914389449d1c7e8c20e857efc1f7d130c18624671aff6f857cb0c8091a85e6e8" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Scx.pl", "type": "reg", "size": 17831, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21098657, "NumLink": 0, "digest": "sha256:fc69aa26dd8227544693047e64023804b49fbbdbb1afa52179196f086db42a5c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Tc.pl", "type": "reg", "size": 11534, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21105089, "NumLink": 0, "digest": "sha256:288caee21b8c0d7aa9fedaa79e5f09a0aaa3e507cc12aa260273b077e694c642" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Title.pl", "type": "reg", "size": 18899, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21110011, "NumLink": 0, "digest": "sha256:880c552b5da95595385f8888449619180af41fcf361d02b648f0c0acd5b59e71" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Uc.pl", "type": "reg", "size": 15206, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21117499, "NumLink": 0, "digest": "sha256:4b6fce17927c7bbfcd067efad997c748bd0419638854e7720d6646d9aa3624c2" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/Upper.pl", "type": "reg", "size": 22274, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21122931, "NumLink": 0, "digest": "sha256:60fa685cc003713e98ab17fe1ccfdf4b6ff8f4c15f530785a4bc343293a38fb9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/WB.pl", "type": "reg", "size": 15165, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21130821, "NumLink": 0, "digest": "sha256:5535f07a25badcb4ad08550577676c465be9e0a4ebb52e1de914a8ce4429a647" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/_PerlLB.pl", "type": "reg", "size": 28370, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21135917, "NumLink": 0, "digest": "sha256:09d95c10092034783830776b1632d968fe5970a2c9cf0a8ab320d1e22dca0c05" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/To/_PerlWB.pl", "type": "reg", "size": 15388, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21144183, "NumLink": 0, "digest": "sha256:b1cd7ef951a18bff13baa2e3aef1ae8772e298362fccb86829e58461a6e995f5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/", "type": "dir", "modtime": "2018-06-10T17:37:28Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/NA.pl", "type": "reg", "size": 7663, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21149388, "NumLink": 0, "digest": "sha256:895666b9e5c02a149077dd4632bad174ac718c2eb73c0ab0d4c0f0183b1a9bba" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V11.pl", "type": "reg", "size": 3447, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21152814, "NumLink": 0, "digest": "sha256:631458895694ee09d4b5e7a1658c7e8f9dcd7e20773a561e7d8de1ec8e871e42" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V20.pl", "type": "reg", "size": 841, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21154539, "NumLink": 0, "digest": "sha256:d9fb6634cb4582e18366ecacf6f6a82244f6fb3a092b1f7a9d08a21e05224f7f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V30.pl", "type": "reg", "size": 1709, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21155161, "NumLink": 0, "digest": "sha256:9fb591eb2efddaac5e714e4f932debd58f1a8abd0ed686cf37f493db1365984d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V31.pl", "type": "reg", "size": 978, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21156189, "NumLink": 0, "digest": "sha256:85654494a8650e805227daaec6d25205b0d2d89d5dc722b5a567b7449e44ba7b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V32.pl", "type": "reg", "size": 1115, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21156832, "NumLink": 0, "digest": "sha256:39ec1432799ed310f2b97a0e697d4b2f06b1a463a5de819f887e0ffb5e235a47" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V40.pl", "type": "reg", "size": 1325, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21157581, "NumLink": 0, "digest": "sha256:d3c689b3ba921e05f55cc2f701f7ba910c1d91875edf5ba61d21008477fb06f9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V41.pl", "type": "reg", "size": 1429, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21158431, "NumLink": 0, "digest": "sha256:fde400c6deaaa41ffb42a52cc4e4a99b290fd5f12392d707107b6f55f21994a9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V50.pl", "type": "reg", "size": 870, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21159315, "NumLink": 0, "digest": "sha256:e5590ee9f1837c84b6e47dd318d952ceb83d729f096df7919d6d1bd6e1030e71" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V51.pl", "type": "reg", "size": 1459, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21159960, "NumLink": 0, "digest": "sha256:a03248090f3d9dbde0be80a89cb12131035acf9381a6e11a0ba02330d382b138" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V52.pl", "type": "reg", "size": 1539, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21160860, "NumLink": 0, "digest": "sha256:46e9e09a71988fa10555ab1a452624424f0627c849c0341e1a47b8bb5452317b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V60.pl", "type": "reg", "size": 1815, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21161778, "NumLink": 0, "digest": "sha256:b4266095222ffa94a519336edb457a9c4d8a820dcbf4b3783a81d033aebdb1ff" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V61.pl", "type": "reg", "size": 1625, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21162757, "NumLink": 0, "digest": "sha256:f77c3582d514dc07e2fd26130801864a5b034145ffd22d20df0e71d902fb736b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V70.pl", "type": "reg", "size": 2213, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21163654, "NumLink": 0, "digest": "sha256:696ac2fb6561e7598f89790b1dd2559ca33d380d01a1e72039a3afc12df3a9e5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Age/V80.pl", "type": "reg", "size": 1213, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21164825, "NumLink": 0, "digest": "sha256:1d065d94198e8268c26a48c173636c6a22b97e2c615883f8f7dc48e0572bbaf0" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Alpha/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Alpha/Y.pl", "type": "reg", "size": 7378, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21165629, "NumLink": 0, "digest": "sha256:153ecfab205c8ebe3e525e9bde6913d1640c06dd7b2fa7432d8545e798ce6368" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/AL.pl", "type": "reg", "size": 708, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21169000, "NumLink": 0, "digest": "sha256:51b28b80d650595eed708e3f67154a1587d55aaa11143f6674d4678cfc5bdefc" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/AN.pl", "type": "reg", "size": 542, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21169562, "NumLink": 0, "digest": "sha256:a45e2cf93b810b43af4f6d60e642e4e88c6894ebb05580ebb016194ef5dcb6fc" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/B.pl", "type": "reg", "size": 526, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21170033, "NumLink": 0, "digest": "sha256:18b1b9e230759a28efbc814575412350931491980dc48c3c0c9e4d0bc29e67ce" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/BN.pl", "type": "reg", "size": 882, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21170494, "NumLink": 0, "digest": "sha256:94cfe9fcb8120c1054db0a9151767423f6efe1f1b77c70129c21c69ade604667" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/CS.pl", "type": "reg", "size": 618, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21171132, "NumLink": 0, "digest": "sha256:895fb05bab16084ded08df473a119fb89f207fbcaf90598d0c90ea4451880e25" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/EN.pl", "type": "reg", "size": 614, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21171641, "NumLink": 0, "digest": "sha256:4278188bd2e78e736d4d53e61dfbdc8bf1f8bb342e2efb4b4909502c6c76d098" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/ES.pl", "type": "reg", "size": 580, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21172159, "NumLink": 0, "digest": "sha256:930e8c3072267904ed75d0a2b2945018096b1d091bca696a32987812467cfccf" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/ET.pl", "type": "reg", "size": 714, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21172649, "NumLink": 0, "digest": "sha256:2257544aa2fac4acbdf791327a2fe45990f0f4d33cdc6489b2212d4dee92a39d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/L.pl", "type": "reg", "size": 4913, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21173209, "NumLink": 0, "digest": "sha256:52adbf5dc0da2d5d721eadf3282a290611eec86bda5d2eb1be7c1b11c9eed969" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/NSM.pl", "type": "reg", "size": 3351, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21175512, "NumLink": 0, "digest": "sha256:40b12bf6ab2ca1c3c1610530a9b64a2d3c40ca7b204c1c15e8bdbdc9509acc7a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/ON.pl", "type": "reg", "size": 2436, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21177135, "NumLink": 0, "digest": "sha256:394079cd6f91f9b3dbb943b526b2cf57129ea244f048b33d5a9e834daf7c84fd" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/R.pl", "type": "reg", "size": 838, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21178455, "NumLink": 0, "digest": "sha256:e4887c1576cac2abb7788747bca6ff8eba0287ba436699cc56a5808451095b89" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bc/WS.pl", "type": "reg", "size": 554, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21179069, "NumLink": 0, "digest": "sha256:e9326135605b27c28f29a3ebc70b8a6e60ce49439b65d8f022eae0840c03ad7a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/BidiC/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/BidiC/Y.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21179579, "NumLink": 0, "digest": "sha256:95b0b0cbd67c31a3c6576d5ae664956d685a9d74c3e05cee58a34ca33c673e06" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/BidiM/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/BidiM/Y.pl", "type": "reg", "size": 1717, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21180077, "NumLink": 0, "digest": "sha256:153d2c916858765de9b42d64392328010f666b7f06bf8666c1424b1e3be79769" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Blk/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Blk/NB.pl", "type": "reg", "size": 1025, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21181075, "NumLink": 0, "digest": "sha256:98710c03108d5b8ddd049c49a5c54ea46030d365b8919d6e5df441cd11683228" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bpt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bpt/C.pl", "type": "reg", "size": 1177, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21181831, "NumLink": 0, "digest": "sha256:01271a108ff293e54e3144751dfc207edf4c57e9c42ff5f72267b468908f1591" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bpt/N.pl", "type": "reg", "size": 800, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21182545, "NumLink": 0, "digest": "sha256:21dab8af5f812d52bdf968459e49c740fb4661400bb7ae449db24c7dc5d39a91" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Bpt/O.pl", "type": "reg", "size": 1177, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21183145, "NumLink": 0, "digest": "sha256:d2f892a7cd36f3f588205261a6f47471fb3f83477a90923014b2d17dd20a2f2d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CE/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CE/Y.pl", "type": "reg", "size": 846, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21183880, "NumLink": 0, "digest": "sha256:c36c6982a245f4ca4e162574511ee721fc264eb4a21742bce44a00b433ce13ac" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CI/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CI/Y.pl", "type": "reg", "size": 4241, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21184516, "NumLink": 0, "digest": "sha256:a265bd13d34abb29313b7987de58e14c44d35b35387f511593d010c3b1c5ec1d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CWCF/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CWCF/Y.pl", "type": "reg", "size": 6490, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21186542, "NumLink": 0, "digest": "sha256:9a28dd0229822f0e85a3c00462cb32e780534f2f16af181997fcfc6a3bebc1bc" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CWCM/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CWCM/Y.pl", "type": "reg", "size": 1593, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21189631, "NumLink": 0, "digest": "sha256:d50b98c979b8b22ad5bfc1feaabb4e1ec33bd8d0389ad7afe9b512d2ac32be0d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CWKCF/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CWKCF/Y.pl", "type": "reg", "size": 8994, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21190648, "NumLink": 0, "digest": "sha256:8bd002f770064e710d41cd11ea343b92d2d536e76aa9b341fe3bce7f7e58bb5d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CWL/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CWL/Y.pl", "type": "reg", "size": 6374, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21194854, "NumLink": 0, "digest": "sha256:88ad9c96eda907f2eb3a7b30373015a29be5950279d6c3927a5c571844159de7" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CWT/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CWT/Y.pl", "type": "reg", "size": 6532, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21197888, "NumLink": 0, "digest": "sha256:abe8a77955ed2930198261b9741bdb4729acd6d853b9f2d224a92c28e65def65" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CWU/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CWU/Y.pl", "type": "reg", "size": 6524, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21200982, "NumLink": 0, "digest": "sha256:13b16e9e72a8b6f7c8d102292042ba80ba3aaa13d96880f63f9b74655b5a8a05" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Cased/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Cased/Y.pl", "type": "reg", "size": 1937, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21204072, "NumLink": 0, "digest": "sha256:cd8039d00559b55e7d6984e64b62d7baf9f8cd0f756228eada0ced86b60bcc53" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ccc/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ccc/A.pl", "type": "reg", "size": 1551, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21205189, "NumLink": 0, "digest": "sha256:7767a020409dad0f6d805f1adf3c17c362da3eaea55d6961db978f446bfbca66" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ccc/AR.pl", "type": "reg", "size": 525, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21206102, "NumLink": 0, "digest": "sha256:4af81b6bbfb9cf07817d5358f6af328c6b697f2cbe4376ec6781d70d231011d7" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ccc/ATAR.pl", "type": "reg", "size": 535, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21206571, "NumLink": 0, "digest": "sha256:a68565ea04fe17f76e245a90d84d011bf45b9dd209e2234212693a6f1baf6642" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ccc/B.pl", "type": "reg", "size": 1211, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21207036, "NumLink": 0, "digest": "sha256:847b4e8706ad7ebc9bb1c438fa3fe6f0926eac8c72fb281e87c21d08e61f4391" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ccc/BR.pl", "type": "reg", "size": 531, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21207826, "NumLink": 0, "digest": "sha256:bfad8077a9404ab7c48861b119912ab5e47cb403bc67c2f358f9dd34718f7ed6" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ccc/DB.pl", "type": "reg", "size": 523, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21208289, "NumLink": 0, "digest": "sha256:9e90c185c7c234e6fee15d4967661500f12b628114818720726ca90c22b9c1ec" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ccc/NK.pl", "type": "reg", "size": 710, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21208751, "NumLink": 0, "digest": "sha256:4b48f6419b3f652d85c3b11f9ddc4936271f4db389d11b92557af6a96f6f119f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ccc/NR.pl", "type": "reg", "size": 2149, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21209304, "NumLink": 0, "digest": "sha256:f4a6ad8520f85deea7a999166e055d235f35aeb0081ff42e5376255444cf345f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ccc/OV.pl", "type": "reg", "size": 610, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21210468, "NumLink": 0, "digest": "sha256:1ebb46d59960672a29f9045e3a2046cb93e827f58fcf8abff252a1d7c563d364" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ccc/VR.pl", "type": "reg", "size": 942, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21210977, "NumLink": 0, "digest": "sha256:fa750cfd0df25a10b0967b28690de1ba5993cb2a448f2d147ffc56080c16859a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CompEx/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/CompEx/Y.pl", "type": "reg", "size": 1259, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21211670, "NumLink": 0, "digest": "sha256:362b71e73a3b072425f5889dd64e4fdc08c93b0c002d91089ab31a36754bf68a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/DI/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/DI/Y.pl", "type": "reg", "size": 678, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21212474, "NumLink": 0, "digest": "sha256:582eb22ce663ac2cb933b20f6a1f07628d86118008d611ddf44194b2d5674755" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dash/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dash/Y.pl", "type": "reg", "size": 718, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21213052, "NumLink": 0, "digest": "sha256:3a6aada6ff63c45d487a58fa5b16e5ff15feb253b5db7ae93178eaecbf101fbf" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dep/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dep/Y.pl", "type": "reg", "size": 586, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21213637, "NumLink": 0, "digest": "sha256:7ff21ef6a2e5398dcaf1f20ffef0310f0ab60cb3c28018cefdf7a1b2b83b073a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dia/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dia/Y.pl", "type": "reg", "size": 2061, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21214164, "NumLink": 0, "digest": "sha256:f0696b99052d6493f9760f1755ef8f8e137480f4fb90de1ee0b60192e6de0bc7" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Com.pl", "type": "reg", "size": 1249, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21215342, "NumLink": 0, "digest": "sha256:6517d7369068ddf4621da7a984430011d831c9cb2f4c8a0e859bb3f938060199" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Enc.pl", "type": "reg", "size": 586, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21216156, "NumLink": 0, "digest": "sha256:2d57420e36706e61b846baf1f831f0a8c265dadf3e928595641f59af61488681" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Fin.pl", "type": "reg", "size": 1847, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21216651, "NumLink": 0, "digest": "sha256:c76ba4201f2c128223c5d10779cf0b6b643fc3429d759847f12c49cfd67a745a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Font.pl", "type": "reg", "size": 1379, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21217580, "NumLink": 0, "digest": "sha256:634e71167318263a480c83e8288105d0a588b6c33d680cf82bb791f4a09eaf9c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Init.pl", "type": "reg", "size": 1391, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21218333, "NumLink": 0, "digest": "sha256:a4e9f05f11e1f2f5c8c72010d59e5eab18051769ec32d7c307e030271719671e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Iso.pl", "type": "reg", "size": 1667, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21219121, "NumLink": 0, "digest": "sha256:cd0458d5589485eca6c394f28c91636a50e587fbfc652a1348ead4dd459521e9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Med.pl", "type": "reg", "size": 1139, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21219995, "NumLink": 0, "digest": "sha256:fce9c154d14ac6bd407150ed9e99b5c5640c60026a61d8d656baa569b69da0e2" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Nar.pl", "type": "reg", "size": 562, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21220678, "NumLink": 0, "digest": "sha256:531d4f55728f8dd5b78b1738c2e7cd45bfbcefde93d1f2f22730a59c24cde560" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Nb.pl", "type": "reg", "size": 538, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21221151, "NumLink": 0, "digest": "sha256:0e429db6cf47bfa4a78882fb401e05b37edc9ac8c2fc39c533e8d5a68b7949a6" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/NonCanon.pl", "type": "reg", "size": 2657, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21221622, "NumLink": 0, "digest": "sha256:1945b1fc2a60d15018317eacde9cd20e0e1499fbc6c906a85ec682bee21dfa84" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Sqr.pl", "type": "reg", "size": 606, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21222963, "NumLink": 0, "digest": "sha256:b45c60ee1e042ed6eb2e9dd216a07e2cd361bace92b05bee522b90fecf76bdce" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Sub.pl", "type": "reg", "size": 531, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21223466, "NumLink": 0, "digest": "sha256:6ed0dd870aed3f0db2749513931412e06b161fcd6e1c75f987c557e17da9ba2e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Sup.pl", "type": "reg", "size": 738, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21223935, "NumLink": 0, "digest": "sha256:8f90ebc3abf2cf6935c377d8ad362a1b454807fb9f86eb6c3c63ebfb44a0e43b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Dt/Vert.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21224515, "NumLink": 0, "digest": "sha256:eacc5f27dc0f5299b611fa9add6d92f47ddb80dc5f8d8faa6a09c4357ad33da1" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ea/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ea/A.pl", "type": "reg", "size": 2152, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21225014, "NumLink": 0, "digest": "sha256:7dd3d1b8becf26d4673b9de63f045a21b26a30c1cff0c1e029fe41c9f949d44f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ea/H.pl", "type": "reg", "size": 572, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21226253, "NumLink": 0, "digest": "sha256:e29e29e6c6e70eed775d55bb5b62b1cbb442cf9e2b145bac5323799028764bf8" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ea/N.pl", "type": "reg", "size": 2613, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21226733, "NumLink": 0, "digest": "sha256:00c916dfbc363c8b6d78559da963bf63d891b9df6634449309b5f905f30d6825" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ea/Na.pl", "type": "reg", "size": 553, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21228158, "NumLink": 0, "digest": "sha256:9068ab08b300c75c8ceca277b1ef6e6268b2cdfa7de15176f6f8989463cf8a47" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ea/W.pl", "type": "reg", "size": 896, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21228640, "NumLink": 0, "digest": "sha256:eddb361861195dce0801db83acfce1fb7ea7c286a9d73765799e35df4a2ec3de" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ext/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ext/Y.pl", "type": "reg", "size": 776, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21229309, "NumLink": 0, "digest": "sha256:0b98dd664962ed3dba4143d1a23d85265709c2b79c50b547a28ac2afc43c153c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/GCB/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/GCB/CN.pl", "type": "reg", "size": 717, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21229924, "NumLink": 0, "digest": "sha256:46a2b8690ebfbf7ecb3b7819097259cf2d6c03953495a9e7c3d28b59192d911d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/GCB/EX.pl", "type": "reg", "size": 3581, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21230501, "NumLink": 0, "digest": "sha256:c4152337f9173e8719f9b4b257f0ba7998ddb54900e52966edbbc3632fd07c13" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/GCB/LV.pl", "type": "reg", "size": 5279, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21232206, "NumLink": 0, "digest": "sha256:c4568a86bc16057955da044c097ff34a5e8a17f7d0005324ad15284b78468ef3" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/GCB/LVT.pl", "type": "reg", "size": 5279, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21234411, "NumLink": 0, "digest": "sha256:90aea35d7a172c8b53a3fe1b10c919a9b02c7e489fe46b84ee4ffc4e3a79fc72" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/GCB/SM.pl", "type": "reg", "size": 1929, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21236616, "NumLink": 0, "digest": "sha256:cb496af4f93e7144e07e9b15755de6497d8fc0e892de6bde46ffcf4797f3a248" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/GCB/XX.pl", "type": "reg", "size": 3296, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21237652, "NumLink": 0, "digest": "sha256:9a4a41055bf7da9f924c4fbdbb58b075fd4af6afe1e96889a9971b3f1f7de010" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/C.pl", "type": "reg", "size": 7529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21239319, "NumLink": 0, "digest": "sha256:1b684544c72a4779455627f4d813423a0ca5dc6312c509b366f9dc6a03758dfd" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Cf.pl", "type": "reg", "size": 680, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21242693, "NumLink": 0, "digest": "sha256:e789aae540f2927b3db679c559591cf4e5ff8401b60df1937315d292ade44405" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Cn.pl", "type": "reg", "size": 7523, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21243241, "NumLink": 0, "digest": "sha256:38cb532eb185268bf9ce967c557a1af01b6db11398a755ca514d7aca4d4ada05" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/L.pl", "type": "reg", "size": 6716, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21246603, "NumLink": 0, "digest": "sha256:7b658b5727e3819db80c229aa3b3dcfc392751045c3b4bfb9a1b2125b06df149" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/LC.pl", "type": "reg", "size": 1849, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21249648, "NumLink": 0, "digest": "sha256:1cc2bbb0394ae80d1d686401c9ae623e34b4f8f537594e5501afa169e6828f72" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Ll.pl", "type": "reg", "size": 6928, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21250691, "NumLink": 0, "digest": "sha256:c464c9d51cf75d1a7d3123e0c81dde4f3446175a814053b1ec196a8927d6f960" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Lm.pl", "type": "reg", "size": 1091, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21253975, "NumLink": 0, "digest": "sha256:c5becb57eedfbf023e5a36a95a5a67aeac1dec28fce67729a0cd8a4b71d6fa86" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Lo.pl", "type": "reg", "size": 5375, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21254712, "NumLink": 0, "digest": "sha256:9c49eea5bc50f051fb58329f23e9675cc01887328f93d29fa0540f727b95d939" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Lu.pl", "type": "reg", "size": 6866, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21257215, "NumLink": 0, "digest": "sha256:fa0731e935c0c4ae87db490249f22768933051e24ff8fb3adfd8dc692576f949" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/M.pl", "type": "reg", "size": 3065, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21260451, "NumLink": 0, "digest": "sha256:b69ebc1803fdef3b03df749ee254f466f80d26bc3010734759312043bcc46580" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Mc.pl", "type": "reg", "size": 2085, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21261986, "NumLink": 0, "digest": "sha256:a9a2e66cc09f7e006b0294a27d9fe0b1022c6a3232cd53789f22dda89ce751d6" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Me.pl", "type": "reg", "size": 542, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21263093, "NumLink": 0, "digest": "sha256:abbdd8849b43e36186134ba648f58e9f7ccd789683837f543b7004b9c5f678b8" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Mn.pl", "type": "reg", "size": 3391, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21263563, "NumLink": 0, "digest": "sha256:d10d8ee92ceb362c2ba777eab53b6857bfbf1c02b8cd95b558d3ecfbee5e3c26" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/N.pl", "type": "reg", "size": 1731, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21265199, "NumLink": 0, "digest": "sha256:1dc44fa3a7704c2d629b43720749f90790e49127b5a5cc94b848fe76a767399b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Nd.pl", "type": "reg", "size": 1043, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21266224, "NumLink": 0, "digest": "sha256:63dac7016953581540a2538710b0c4318ec2b9fc3acfca829e69ca737f8e49af" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Nl.pl", "type": "reg", "size": 628, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21266959, "NumLink": 0, "digest": "sha256:016a472ab6cc5b30ae7cc6551f94b63b473ea4c6b73ea282db39c5d649552868" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/No.pl", "type": "reg", "size": 1149, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21267476, "NumLink": 0, "digest": "sha256:822dd7912d7229f9f14013f318e2a1ea135fd57e6be75f108ba665d313f6a8f8" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/P.pl", "type": "reg", "size": 2229, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21268244, "NumLink": 0, "digest": "sha256:371b7f97bad43659b45c06c5935c55d427df4bb8c488672fc78f1982b3391c36" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Pd.pl", "type": "reg", "size": 678, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21269455, "NumLink": 0, "digest": "sha256:ad65ae09d8cb997364c099b590b3c28ef4a8db23ec0526278051b6a3208d432b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Pe.pl", "type": "reg", "size": 1321, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21269993, "NumLink": 0, "digest": "sha256:7615e72e7e374f966d60f68243e039dea6c567b3a9be817b40c5b3d8838938aa" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Pf.pl", "type": "reg", "size": 600, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21270747, "NumLink": 0, "digest": "sha256:753f0b70a76c59d123209a9ef95ca3793b8d99a1a7b6bf59bff11fedc5bf3b14" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Pi.pl", "type": "reg", "size": 610, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21271241, "NumLink": 0, "digest": "sha256:8c45405effca58ee2d3a4fbf1a38a8236a8076a2de9aba13bb48393c8a667468" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Po.pl", "type": "reg", "size": 2197, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21271741, "NumLink": 0, "digest": "sha256:58800da8ee0bb4a638eca93796b087a9dfe35012888a45571f2cecd211356b19" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Ps.pl", "type": "reg", "size": 1353, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21272922, "NumLink": 0, "digest": "sha256:b34ec254d4e43c5752e2226811eed8c99a41073aa72e6fd8e0b7a1563da414f5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/S.pl", "type": "reg", "size": 2934, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21273684, "NumLink": 0, "digest": "sha256:d5ce890e481dff7a947a98d7d7c76f2e7907e472f81cb7c9d5f84dd71782faae" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Sc.pl", "type": "reg", "size": 666, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21275182, "NumLink": 0, "digest": "sha256:08d139cf2fd09d29efc97db42f745d90d2bc0a7601f2fb92a43f42eb356f70cd" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Sk.pl", "type": "reg", "size": 772, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21275719, "NumLink": 0, "digest": "sha256:aa1fded45460df446896a9545016c9159a610265a1e32fa9df2d8b40c1381b8f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Sm.pl", "type": "reg", "size": 1191, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21276321, "NumLink": 0, "digest": "sha256:164ceffc29dd40a6cfd9ba9332d3a4831a99987e8d2a6c2cdd441b338656d926" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/So.pl", "type": "reg", "size": 2468, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21277089, "NumLink": 0, "digest": "sha256:6d251b99654781e7e7ec057f316a0a1eb51497f3fbc3be442a1d61bc125ef346" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Z.pl", "type": "reg", "size": 566, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21278364, "NumLink": 0, "digest": "sha256:2eab52cc23eb22532a256bf16b3ce41de6ee59dc35289113be6a8d2a804d9f84" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Gc/Zs.pl", "type": "reg", "size": 556, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21278852, "NumLink": 0, "digest": "sha256:58055a6143a100243cc3e9ed7cbdf794b4a2fff5a5fea630238823f492c6eb0c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/GrBase/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/GrBase/Y.pl", "type": "reg", "size": 8947, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21279366, "NumLink": 0, "digest": "sha256:790ad94d6a1e74542fa78f2a31e760c96ab9d767018c0a1c6f64f33200f0ffb4" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Hex/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Hex/Y.pl", "type": "reg", "size": 545, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21283331, "NumLink": 0, "digest": "sha256:21cc921c64c5201357a67823af77d2b6a19acabe9cefc238ad8938adf058e05b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Hst/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Hst/NA.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21283837, "NumLink": 0, "digest": "sha256:5fc815fa3b720f3de4e4d61db293e6abb336d413aebdf60b9b4c507566c2d3ef" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Hyphen/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Hyphen/T.pl", "type": "reg", "size": 594, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21284347, "NumLink": 0, "digest": "sha256:db11dd24449811de8c6717ebf0ce58d3e68f05d280f18b8d5816ae313b072d5f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/IDC/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/IDC/Y.pl", "type": "reg", "size": 7786, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21284880, "NumLink": 0, "digest": "sha256:988886312785a308c02e30225a6f72e3109dc0acc30b89ac0169bbebe8ed7b7c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/IDS/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/IDS/Y.pl", "type": "reg", "size": 6730, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21288422, "NumLink": 0, "digest": "sha256:2b0e8a0ac8dfa48e844a0a40a043aa11198a1564895ef9df692ebc50c226ed5e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ideo/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Ideo/Y.pl", "type": "reg", "size": 644, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21291508, "NumLink": 0, "digest": "sha256:b9a3f4b14ad1df197900ccd1f6e40fdb030486c1cf11e1cfb4ae4d2c632f3bac" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/2_0.pl", "type": "reg", "size": 3746, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21292070, "NumLink": 0, "digest": "sha256:13f6d56ca5be2fcc4826008e757ea3250f99bd6135926db97001bd25d9608109" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/2_1.pl", "type": "reg", "size": 3746, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21293931, "NumLink": 0, "digest": "sha256:3e9efcf7212fe4e7a64db95b2a03d7b420f1cd07013bd3ccca2ccdc9a72f4e7d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/3_0.pl", "type": "reg", "size": 4350, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21295794, "NumLink": 0, "digest": "sha256:d0c46b7bde68599a3b1954a0eb362cf190294381a30127a7968a92c92e42be8a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/3_1.pl", "type": "reg", "size": 4802, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21297911, "NumLink": 0, "digest": "sha256:a82015a87e5674584856f531e4143deeb2ede5c72b9b106f08fd72ce6159a39b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/3_2.pl", "type": "reg", "size": 4740, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21300214, "NumLink": 0, "digest": "sha256:01217f692d41f64cf3e72eaa4efafaef4a8ffc8f3289e8d944d8dbd20dec2ce0" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/4_0.pl", "type": "reg", "size": 4924, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21302486, "NumLink": 0, "digest": "sha256:b0d564073aae2946b46181dc7f7352e2f2a18b96c7570f0e5c8d980813a7912e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/4_1.pl", "type": "reg", "size": 5170, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21304829, "NumLink": 0, "digest": "sha256:e69aa31c985304dbd9691fecc2e8eae34c2424c867e65a3d60f023fcdb5b10b9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/5_0.pl", "type": "reg", "size": 5298, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21307271, "NumLink": 0, "digest": "sha256:fd2ee1e5d66198cf658a0bbb582b37f29f13f247b299c5380f168c98a776afaf" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/5_1.pl", "type": "reg", "size": 5490, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21309760, "NumLink": 0, "digest": "sha256:f0166a4d8804a9e22594eec9c4ef7b17e4c1363f57e30dfa8cac6cd110a77ba6" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/5_2.pl", "type": "reg", "size": 6002, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21312330, "NumLink": 0, "digest": "sha256:02fe6fae9f32062930bf45f7dbd669f9f321fa6543f6c8ee93483fefacd62904" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/6_0.pl", "type": "reg", "size": 6261, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21315100, "NumLink": 0, "digest": "sha256:9dd477413e652a76542f7d038d7fdd4f7236179b61c33040b1ff78850c4361e3" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/6_1.pl", "type": "reg", "size": 6759, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21317977, "NumLink": 0, "digest": "sha256:04c5ae4eb50ebf723ac3db094a8d42b56eeba5ed8adc5d5a0833509afb9ffe2c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/6_2.pl", "type": "reg", "size": 6759, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21321037, "NumLink": 0, "digest": "sha256:ab1d7d9b60dd8903cae87e7918b121b8c9fa4ce2a60324cf3ccd174ac8ce9789" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/6_3.pl", "type": "reg", "size": 6759, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21324098, "NumLink": 0, "digest": "sha256:d6d7ed8d5392f036d48104c22ccf3fb71c9a0a5a99b49599554818ff0125e8b2" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/7_0.pl", "type": "reg", "size": 7515, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21327162, "NumLink": 0, "digest": "sha256:923bb6a9d109b0da8a3cac2d6a1b442f9fd932ef0804a3867f9e7646365e1d0a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/In/8_0.pl", "type": "reg", "size": 7665, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21330521, "NumLink": 0, "digest": "sha256:6e3ad837e82daa5f3ec302a18814ce9f6662b5de63d557e75ff8153fda240395" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/Bottom.pl", "type": "reg", "size": 1699, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21333992, "NumLink": 0, "digest": "sha256:468da8bf6dfba6e473f2972b251691aff4c6f0e3e7f2d2c08441c6e76c70566c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/Left.pl", "type": "reg", "size": 902, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21334962, "NumLink": 0, "digest": "sha256:c6dc18df59e6636c97eedeec3fd68ac87b9fe3c9949c6be0d848a69c2482fa12" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/LeftAndR.pl", "type": "reg", "size": 628, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21335602, "NumLink": 0, "digest": "sha256:4550e724c609641a8ac46c39d0ed5bd150aff8baf8300693321f92123c02b842" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/NA.pl", "type": "reg", "size": 2311, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21336118, "NumLink": 0, "digest": "sha256:b6feb9c1b0413d1da65ee9a47ace8183300edf33ecb6bb51022dbd0a001a0f73" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/Overstru.pl", "type": "reg", "size": 533, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21337345, "NumLink": 0, "digest": "sha256:8a78146108cfd6325943bfa19174f77476accd0f7a2a662f5acd052e371d92b4" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/Right.pl", "type": "reg", "size": 1981, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21337816, "NumLink": 0, "digest": "sha256:4e3b2907207137d39f00dcdfb4e9de5d6990068a0f8a2ebe32a1150e9300ae4e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/Top.pl", "type": "reg", "size": 2125, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21338873, "NumLink": 0, "digest": "sha256:630fc5fc51a6d904805f10a558983948b9a0bb3f5f785b0843897e58d278ce3d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/TopAndBo.pl", "type": "reg", "size": 552, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21340018, "NumLink": 0, "digest": "sha256:f1afb1d74d21ae82b54c28ac2c4266f33cfeab3de1e10e8b9db7e6b9716eda7c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/TopAndL2.pl", "type": "reg", "size": 531, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21340500, "NumLink": 0, "digest": "sha256:9a0f38b4d2a324af133bfdc80cba6e71a4b12504d516d698a0afefd27aa028dc" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/TopAndLe.pl", "type": "reg", "size": 554, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21340977, "NumLink": 0, "digest": "sha256:3d33132e3c015dab8fca9eeaec0779e29cab54fd50443ac1d4b613a302482b85" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/TopAndRi.pl", "type": "reg", "size": 584, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21341459, "NumLink": 0, "digest": "sha256:75f7ba0cd02d1d35e55cc1a752bda119c86525e228849f6b07d895486c2fb3a3" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InPC/VisualOr.pl", "type": "reg", "size": 566, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21341955, "NumLink": 0, "digest": "sha256:3ed0c5935a1cda0e566a66e4568d2caba1f227952c22b93e37a4cdf34c276707" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Avagraha.pl", "type": "reg", "size": 626, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21342472, "NumLink": 0, "digest": "sha256:f72d20989594d3e67120d0be23e41d7aa7c035ad751ba8c72634368e7360cac0" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Bindu.pl", "type": "reg", "size": 892, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21342993, "NumLink": 0, "digest": "sha256:d2f8b73a98b0cdee98c1bf27fc6466d7c4befa157ed16e469b2fd72030937451" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Cantilla.pl", "type": "reg", "size": 576, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21343640, "NumLink": 0, "digest": "sha256:1dd353f8f78fff54c57d1dd7e972f709ba595ae55d97f374e06f41165591fdf3" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Consona2.pl", "type": "reg", "size": 608, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21344135, "NumLink": 0, "digest": "sha256:f5384d0716886b40810a8342cb7c8437229b7b5d98ee83ea953fe7951fc5f29c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Consona3.pl", "type": "reg", "size": 586, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21344656, "NumLink": 0, "digest": "sha256:4c807a57b2b975117eb16ac10789e0de5af30f597c79957062279adab01afd2a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Consona4.pl", "type": "reg", "size": 586, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21345157, "NumLink": 0, "digest": "sha256:4c5f334957a5abf4cad68467b86087af42a926e518c4480080822a6b96fd6b1b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Consona5.pl", "type": "reg", "size": 562, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21345658, "NumLink": 0, "digest": "sha256:2efd67da131f00815609e67de866cc43760fccde62d46414855bf5399b31ac53" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Consona6.pl", "type": "reg", "size": 531, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21346150, "NumLink": 0, "digest": "sha256:7050f2f53849a374b0f2af1ec7de9ecd1d48f1d537b8c52a899dd4ca9ecf9552" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Consonan.pl", "type": "reg", "size": 2019, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21346620, "NumLink": 0, "digest": "sha256:5339e1b16056a13163fc91a699698cc9708952648ac828f1f7e5a7652a2da8b1" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Invisibl.pl", "type": "reg", "size": 566, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21347738, "NumLink": 0, "digest": "sha256:9e2be1b50e53e515a745b2c595ab7186e590f9e74917e602bd9c14b8408250da" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Nukta.pl", "type": "reg", "size": 722, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21348226, "NumLink": 0, "digest": "sha256:ad89d93922400e9011557a23689ed306877926358f8fa2e9eb79b6092f9c725b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Number.pl", "type": "reg", "size": 918, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21348791, "NumLink": 0, "digest": "sha256:f037c0204cb21032219cb0a78893a2aa2857a01e2d09d15e430564f99ffd834b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Other.pl", "type": "reg", "size": 3459, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21349466, "NumLink": 0, "digest": "sha256:5b0c6ebd2b4fa552ea5799e784af2b49d9116eb2196eaa28f41b075ebe96fee5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/PureKill.pl", "type": "reg", "size": 652, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21351189, "NumLink": 0, "digest": "sha256:75421328514596cfafcc7de3ff352d428137c2d6d8e38250625fb0f49f4696f0" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Syllable.pl", "type": "reg", "size": 618, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21351727, "NumLink": 0, "digest": "sha256:cead1ea4a4fe43635e01bce4b9fc348abef77d318e3713498e125f7548516714" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/ToneMark.pl", "type": "reg", "size": 650, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21352246, "NumLink": 0, "digest": "sha256:b75f698a239534cbab48e902e8bb88c9f1ca298de111e7c5ed2346757155e5c5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Virama.pl", "type": "reg", "size": 732, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21352779, "NumLink": 0, "digest": "sha256:0da894d458c455ba17371f79be3244c4c97b823e2943b699393857300affeaca" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Visarga.pl", "type": "reg", "size": 796, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21353352, "NumLink": 0, "digest": "sha256:8a87513f8a1d92e4f8a8ac566b700322d47f36b9ac10f70f0468f01fe23cc6a4" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/Vowel.pl", "type": "reg", "size": 548, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21353956, "NumLink": 0, "digest": "sha256:d468fa92702a4e0f60574c696863cca6561ab504fa31062ab2cf19e096b76e65" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/VowelDep.pl", "type": "reg", "size": 1625, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21354436, "NumLink": 0, "digest": "sha256:d33a82fec0243216a80c828c8032de7d45df1bd8156e936406911527c59e8f5e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/InSC/VowelInd.pl", "type": "reg", "size": 1241, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21355390, "NumLink": 0, "digest": "sha256:84a3f31938cd83f47d9383d92cae715d5d608e97e0c31f6a3477ee2bd1f9ec10" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Ain.pl", "type": "reg", "size": 540, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21356218, "NumLink": 0, "digest": "sha256:f24016b9d14d5ed0291379def4ea1de1dab8aa0daeeca3785e790377048bfb21" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Alef.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21356690, "NumLink": 0, "digest": "sha256:f4b11ee075b7873457c9899e1f7be563c4787cd0128277cd1fe80192086fcb6f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Beh.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21357162, "NumLink": 0, "digest": "sha256:3a251179bbb302b9ff9b437f1bad999c7287026cee7403079202dcf38250f7e1" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Dal.pl", "type": "reg", "size": 540, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21357638, "NumLink": 0, "digest": "sha256:56947fd737c7f13b8376e6702eb5f26e6296a5b99a04565a6880ec2025d74ea7" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/FarsiYeh.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21358114, "NumLink": 0, "digest": "sha256:5dc68c9a2b5f3544d5df69f5571d284ae453244ff58d1a64de0efbb1b8a22323" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Feh.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21358580, "NumLink": 0, "digest": "sha256:ae53d8e50eaa7b8787692e3589b38ca28db44bc5542c0cd499dd8581642f5bf5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Gaf.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21359048, "NumLink": 0, "digest": "sha256:e4e395972574b5ab0668dc6a4f210a7dfbb03f06b04a08ade566d5474a6216e5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Hah.pl", "type": "reg", "size": 570, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21359522, "NumLink": 0, "digest": "sha256:d14cced32f4055d4ac13cf8d92b6be4fdcdc1c9b1674ec2ec9f46384239dc4ac" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Kaf.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21360010, "NumLink": 0, "digest": "sha256:87bfeee9af881a4d1357a6a08cc239b7e22d0b7df7e6f543fe83bf744c3cffe9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Lam.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21360478, "NumLink": 0, "digest": "sha256:e43f4f9917b7243e1673aeb509e0c063a56718d1e1d998fbdc05da0aa33ea7e6" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/NoJoinin.pl", "type": "reg", "size": 714, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21360948, "NumLink": 0, "digest": "sha256:a12c205a59adfa5912d715e3313fbb00a35952d9a9f4c79b1463267c79d0ca69" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Qaf.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21361502, "NumLink": 0, "digest": "sha256:d5f83fc3feeb39fad902ccae85624b39d6afb82504930dd3239ef71e0095822e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Reh.pl", "type": "reg", "size": 570, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21361964, "NumLink": 0, "digest": "sha256:264d7bee09393a22317c8583efda0c39c886997c8839ed5c2beed124d1369fc8" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Sad.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21362454, "NumLink": 0, "digest": "sha256:e51b935f2bcb554b10978d7236af8a127b2760c0ce33376de6af82c9314df086" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Seen.pl", "type": "reg", "size": 560, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21362923, "NumLink": 0, "digest": "sha256:b3127bc9cd8f5b8c005e9b3235ecda61da74279beae78d560cbd7de1b4b7627d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Waw.pl", "type": "reg", "size": 560, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21363403, "NumLink": 0, "digest": "sha256:920dcab0a75a0cbb76488df491ae59bdfc7bde9641cc858d7662aec79f2a94dd" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jg/Yeh.pl", "type": "reg", "size": 560, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21363885, "NumLink": 0, "digest": "sha256:76e8ea7d2005c5a1eefac0d1b20e58f09df82db8d61c7891c780eac65446f83b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jt/C.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21364397, "NumLink": 0, "digest": "sha256:65fa3c06bb480760cf92b70a8e4472aa9768f6b25785f3fc766f3900015327f7" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jt/D.pl", "type": "reg", "size": 1047, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21364857, "NumLink": 0, "digest": "sha256:6b7ac3e4cbfdd06d82a7486db53310fc013bec3a8e075126f4f3e309985c1abe" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jt/R.pl", "type": "reg", "size": 1021, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21365548, "NumLink": 0, "digest": "sha256:a2cb7c3e73e46c497012713f475252c94893a6a1060f6349eb136a356bc2db56" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jt/T.pl", "type": "reg", "size": 3527, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21366210, "NumLink": 0, "digest": "sha256:d332613820c49cbf11b5704ed9c4540b7ec73f4b822f94f9da42aed0010c95b5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Jt/U.pl", "type": "reg", "size": 3715, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21367906, "NumLink": 0, "digest": "sha256:e4d9ca5f6e99a834259c84c9fae537399938892687b735fd24965f360280a799" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/AI.pl", "type": "reg", "size": 1581, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21369711, "NumLink": 0, "digest": "sha256:b11022673f7f67894f2decc01c1c48b7979ed84edc80ee1e260312d0c91f6367" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/AL.pl", "type": "reg", "size": 8299, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21370654, "NumLink": 0, "digest": "sha256:9844fcc9be847140cd01ffb3ea9af682a28215faa9078140cdf143f69d4bee9f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/BA.pl", "type": "reg", "size": 1436, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21374369, "NumLink": 0, "digest": "sha256:201498aad9193c088657a784984d18f4fb4375457addd1206b0871e1737a9694" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/BB.pl", "type": "reg", "size": 652, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21375228, "NumLink": 0, "digest": "sha256:bd32e12c3a73321d3ee2caf733d70c574f2443798d38a3f834d33430170aad83" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/CJ.pl", "type": "reg", "size": 790, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21375765, "NumLink": 0, "digest": "sha256:42c7825541dc6610e017372d3a8efb1ca40e9f902f7b753dc41cc795e950835b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/CL.pl", "type": "reg", "size": 1453, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21376323, "NumLink": 0, "digest": "sha256:9103ed646347e80f105a396fb40da96c67987d228006afbec4f9a8a142996888" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/CM.pl", "type": "reg", "size": 2913, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21377123, "NumLink": 0, "digest": "sha256:bff75a24686a2f41fd0584ca0591fbc5f305f51fb6d5393120240eea6e5d87e8" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/EX.pl", "type": "reg", "size": 734, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21378606, "NumLink": 0, "digest": "sha256:20a5578ef22b824b1d46f57c7975a9988de472db0923e14da1114eda5a127d9e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/GL.pl", "type": "reg", "size": 594, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21379172, "NumLink": 0, "digest": "sha256:fbfd4d27e4263cbcedd2ab51a0565064e497b26e150f1aef9da80bc5bd563d19" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/ID.pl", "type": "reg", "size": 1997, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21379674, "NumLink": 0, "digest": "sha256:d0fcbb793a7a08737f7cdc8cd292a32e5394850852e49382a281577a829c6160" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/IN.pl", "type": "reg", "size": 533, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21380723, "NumLink": 0, "digest": "sha256:05939a3120788239583c7041e285cfb294a7d86e9fa8551c36b16cc45a7289ed" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/IS.pl", "type": "reg", "size": 580, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21381187, "NumLink": 0, "digest": "sha256:6dab652d9ca506eec3a81522f0264dd939c145d3340f96a20517d45c875f8e2a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/NS.pl", "type": "reg", "size": 678, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21381678, "NumLink": 0, "digest": "sha256:316b077ed0564abd6ed7751171e36beca2e14cfac602472fbb676b8483a58f6f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/OP.pl", "type": "reg", "size": 1441, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21382208, "NumLink": 0, "digest": "sha256:15bea04086658d18d80ce78c654cc87f72eb3c9776e4ac555ee2b6aa5981107d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/PO.pl", "type": "reg", "size": 692, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21383011, "NumLink": 0, "digest": "sha256:30e78aaf87f8f2e91f79f63c244b8d77ee976000fa38f6b095119c23481a2b94" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/PR.pl", "type": "reg", "size": 702, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21383562, "NumLink": 0, "digest": "sha256:93e20a79854fe08ed2aece340eb63149e65e4c3916add2d554a2d125c43972bc" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/QU.pl", "type": "reg", "size": 620, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21384121, "NumLink": 0, "digest": "sha256:6baa2930012d73c927e385f3b9181c8ec08a8092ad5e80338ba6413fa4a928b0" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/SA.pl", "type": "reg", "size": 926, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21384637, "NumLink": 0, "digest": "sha256:fbac2fd92d95af1bd7960f50252247040c8f1da99eaad06fea8703a90d3b31a3" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lb/XX.pl", "type": "reg", "size": 7404, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21385293, "NumLink": 0, "digest": "sha256:5e4a09109f7eddad90eaddf7ec155f28c2ea3543ea9693894cf679cd66a9d93c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lower/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Lower/Y.pl", "type": "reg", "size": 6986, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21388636, "NumLink": 0, "digest": "sha256:2fd2550c8dd707f916b5608dc6adbd5a25a41ca1cb0556461f8daebec81d3732" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Math/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Math/Y.pl", "type": "reg", "size": 2093, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21391966, "NumLink": 0, "digest": "sha256:659033c57408a43fcd825c8233d423b70d51d17aa126582a99e394da31104392" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/NFCQC/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/NFCQC/M.pl", "type": "reg", "size": 894, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21393083, "NumLink": 0, "digest": "sha256:35b860728ea7e0d195e3ff942c26df489663e927b6207e9df4b210a42e7ada2d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/NFCQC/Y.pl", "type": "reg", "size": 1641, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21393741, "NumLink": 0, "digest": "sha256:310eb93664b58c215224857f99291667c99d6be09702efcfefaf972e6b7ab4db" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/NFDQC/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/NFDQC/N.pl", "type": "reg", "size": 2885, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21394726, "NumLink": 0, "digest": "sha256:abaa7ba35e14c3bad73e74789f290c325ff1625bd31d61ccda3c5042abcf56e1" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/NFDQC/Y.pl", "type": "reg", "size": 2887, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21396206, "NumLink": 0, "digest": "sha256:3c29d7fad1c6929e8b0e7e8ab6104be050eb47b24e6126b8c4afbf6cd6b3f3a7" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/NFKCQC/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/NFKCQC/N.pl", "type": "reg", "size": 3321, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21397718, "NumLink": 0, "digest": "sha256:fe77c77030f1e1e99698aefa57fb2cf5b8e8eccf23bf9565b542650b9e7e2fcd" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/NFKCQC/Y.pl", "type": "reg", "size": 3691, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21399334, "NumLink": 0, "digest": "sha256:1f5fab3008efa3c5b53190bdf969ea1f547baeabe9a41e4c9b790ca84a6fcf93" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/NFKDQC/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/NFKDQC/N.pl", "type": "reg", "size": 4791, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21401145, "NumLink": 0, "digest": "sha256:e0f895808e8339727f0b5744779e2103ab91ebc74dc77734352667e575ff0669" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/NFKDQC/Y.pl", "type": "reg", "size": 4793, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21403408, "NumLink": 0, "digest": "sha256:8bed0812bc523847488a63a7c3aae16aa5caa8f4474b11bc2fa8173d4608a544" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nt/Di.pl", "type": "reg", "size": 702, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21405695, "NumLink": 0, "digest": "sha256:3c278d93de413ca5e0210b4ed4ad791223c18ea02ac9ccc923482b9d09d38980" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nt/None.pl", "type": "reg", "size": 2629, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21406252, "NumLink": 0, "digest": "sha256:56de36761d9a9cfd088c85e561b6081759f8e2bc77ee7b175882ffeb41a33274" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nt/Nu.pl", "type": "reg", "size": 2149, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21407619, "NumLink": 0, "digest": "sha256:beca0b577b03dca5c3e976bc219c662bbe60c40f1667d0389fbdb11008c2afd5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/0.pl", "type": "reg", "size": 1257, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21408787, "NumLink": 0, "digest": "sha256:d59f895d8d9db1e3ba2f030543fc3c58f29781dfd67bdfa3894cf2c97618c1d0" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/1.pl", "type": "reg", "size": 1787, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21409578, "NumLink": 0, "digest": "sha256:ee1c6cc39b46109853103c6c93e8f19166e59d89e02b87d5977c5eee269e0900" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/10.pl", "type": "reg", "size": 1062, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21410585, "NumLink": 0, "digest": "sha256:be3afd12ad8c3b06f8e210c273fe03b12fa43e7ad71cc72c72f9e76148897c6a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/100.pl", "type": "reg", "size": 828, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21411284, "NumLink": 0, "digest": "sha256:062447e211a0753dc7b8d69aca1bb364937d1065b74768bc0338831b56ed776f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/1000.pl", "type": "reg", "size": 710, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21411886, "NumLink": 0, "digest": "sha256:7f61ec9f997bae10ad53eba48eddf2416ad833f761564e1f77aafa90ff06d748" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/10000.pl", "type": "reg", "size": 594, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21412442, "NumLink": 0, "digest": "sha256:fbe03cac66a477c30ba70339e69ad16997456727d28ae3fd1e1edd049a3e6352" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/11.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21412940, "NumLink": 0, "digest": "sha256:10c0beb58714c1a2d12a98ba86666ad288872cf1a3a28e53c986477b13d2255f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/12.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21413416, "NumLink": 0, "digest": "sha256:7e19666dbe9e7cff6581f954c1b90842312aecfd9c137e2109947e7f986bd6b2" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/13.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21413890, "NumLink": 0, "digest": "sha256:b09047105c8f53ebf6f559362f0af14470a3b21e4e7794fa441a432d7c5019d2" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/14.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21414352, "NumLink": 0, "digest": "sha256:799cef8b8010ef2aa1edc5ec0da21261031f1942917b9e9f9252efc812a8d913" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/15.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21414815, "NumLink": 0, "digest": "sha256:80e45d74c4701efe80e6305a0965114dae16bd82a7d0dfde5d4f32bdac25d81a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/16.pl", "type": "reg", "size": 540, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21415277, "NumLink": 0, "digest": "sha256:5207764dac87e97fdcf4787cad1966721e636ff768c984dfb69f1f7444463bee" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/17.pl", "type": "reg", "size": 540, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21415746, "NumLink": 0, "digest": "sha256:18c61339544aab80adf0219e8e46046c35d188766f17996993e26b3f6e617f19" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/18.pl", "type": "reg", "size": 540, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21416214, "NumLink": 0, "digest": "sha256:825518e61f5b329281357fbc566496484a3ee5b27bf65a83dcb86ba65e8a16a4" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/19.pl", "type": "reg", "size": 540, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21416685, "NumLink": 0, "digest": "sha256:fd7a996d357f74ef65d6d9e174293dd9b2b62e1fc8b0f231c761baf67d1059c7" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/1_2.pl", "type": "reg", "size": 624, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21417156, "NumLink": 0, "digest": "sha256:2aaf91c335a92bc9014f5342abd9565cf90a28610455bd4ba8471f66c27db2fa" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/1_3.pl", "type": "reg", "size": 560, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21417673, "NumLink": 0, "digest": "sha256:71cfd371216fa9290dc38b17ec5a9f810acf1a8988bbb974aeca18ae03205134" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/1_4.pl", "type": "reg", "size": 612, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21418151, "NumLink": 0, "digest": "sha256:f3aa2dc45272ea33a70f9eb387faf24f1a521db91dfecc1229a914a896584b03" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/1_8.pl", "type": "reg", "size": 544, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21418657, "NumLink": 0, "digest": "sha256:90d84e969a919182cbb641336f84927bb38827287027c0a0f0da3e8231ad1d93" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/2.pl", "type": "reg", "size": 1789, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21419132, "NumLink": 0, "digest": "sha256:400d0cf0f66474b868ef996e910c4dc33486cdff13c2dd436bde843fc7841439" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/20.pl", "type": "reg", "size": 842, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21420124, "NumLink": 0, "digest": "sha256:26cb5831d1afaf01f35e659269bd4455b124df20d7eb12a114516b2a9a4da22b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/200.pl", "type": "reg", "size": 537, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21420733, "NumLink": 0, "digest": "sha256:748a077ee40368a52770dc192fe6ddde19d7161061c621c64228f56fbf180342" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/2_3.pl", "type": "reg", "size": 572, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21421199, "NumLink": 0, "digest": "sha256:ea4dc781c6de8fd29ad1b3d3884c3a8d9a4df1a1ae458fae80915d4bb3d7a0c6" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/3.pl", "type": "reg", "size": 1771, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21421682, "NumLink": 0, "digest": "sha256:a169a6edc2d01accc73b423afe0a4cbc165a79de17f3da89dcb90619bc6c76f9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/30.pl", "type": "reg", "size": 672, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21422679, "NumLink": 0, "digest": "sha256:e82e4c2aa63e7bdfcd08eff764bb40cad93a2ff06de84a8f6df03496b79a5205" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/300.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21423214, "NumLink": 0, "digest": "sha256:c975e4a9b2cfec95d561f3fcb33018472b139e787a614a52d38b9ebdce94f7ad" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/3_4.pl", "type": "reg", "size": 564, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21423688, "NumLink": 0, "digest": "sha256:59e611a9c7d9a6113998ddc4081599b7f1b8bfca865df319c3c64c346e456b44" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/4.pl", "type": "reg", "size": 1703, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21424171, "NumLink": 0, "digest": "sha256:86f8e4e022f5063e8916dcafdf0d948f9d3e9c949d49eb15a5adddc4f11b87e7" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/40.pl", "type": "reg", "size": 674, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21425131, "NumLink": 0, "digest": "sha256:606184715fc996afb0a828ddfaed5cb76207645a780757cb1055df956f9c910c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/400.pl", "type": "reg", "size": 537, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21425669, "NumLink": 0, "digest": "sha256:1d7a72efd682759fc95fb185033e24f78039ae948aaf7a499f9939b4c8ad4b0c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/5.pl", "type": "reg", "size": 1723, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21426135, "NumLink": 0, "digest": "sha256:d91aae3728260a7bd81a57f286e6ecec5757eb92e9391e78cea83a44d6487281" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/50.pl", "type": "reg", "size": 760, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21427113, "NumLink": 0, "digest": "sha256:c8979e1564d8d627864464b1c82808503e831a9e8dafd55f6dda8d5409debd92" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/500.pl", "type": "reg", "size": 606, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21427686, "NumLink": 0, "digest": "sha256:e084754ed9e32f713f5b5e66288dd33c1c81c59680b0fe59c4b048d71d451a15" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/5000.pl", "type": "reg", "size": 560, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21428187, "NumLink": 0, "digest": "sha256:67b3570ce87591ac940ac05127d6fe4cd86bdcb3bab1f1a5a45ae8d48e645e47" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/50000.pl", "type": "reg", "size": 548, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21428665, "NumLink": 0, "digest": "sha256:43ceac5194c4b6c13063e1bacf84965db8fc070ca441ab784eeb28e8d38ed17a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/6.pl", "type": "reg", "size": 1577, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21429135, "NumLink": 0, "digest": "sha256:4f3861e2b7418ce50ea92ab959cb1cbefd9a0e4ae87a9775a4d4793dd5e4aaa1" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/60.pl", "type": "reg", "size": 610, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21430053, "NumLink": 0, "digest": "sha256:9056982a2e7a716fce6862af087423dbd076e6522b20857d5a5cbce35e303cee" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/600.pl", "type": "reg", "size": 537, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21430560, "NumLink": 0, "digest": "sha256:31ab8a3d4a609401735014ac484ab69125f20e57cc72075ba26149106d5eb957" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/7.pl", "type": "reg", "size": 1543, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21431026, "NumLink": 0, "digest": "sha256:d88d19bd34873be079c39de0e6c15a9738850d6895fc882db01610d89486b59b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/70.pl", "type": "reg", "size": 610, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21431944, "NumLink": 0, "digest": "sha256:a4eea7e7052640fd72bd5c91eb7b59b70804c89a384f53eb67d6d7abb2cf014b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/700.pl", "type": "reg", "size": 537, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21432453, "NumLink": 0, "digest": "sha256:5576ee77c26a8d03997339628698136e995b6868e6e8da37e6c2e3bdecfb1a0c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/8.pl", "type": "reg", "size": 1505, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21432919, "NumLink": 0, "digest": "sha256:d865096d0036aa6bc3b8c418bffbe31bfceff0e438ec1689be161333245d2c00" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/80.pl", "type": "reg", "size": 598, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21433806, "NumLink": 0, "digest": "sha256:c008bbe4be4c267926deb9c1f80ac6675958042db9b02f4eab7da592a52c3f50" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/800.pl", "type": "reg", "size": 537, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21434310, "NumLink": 0, "digest": "sha256:34117ef3e064aaeed5c77798891de425b93f3493454d43388222a8dd17906429" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/9.pl", "type": "reg", "size": 1531, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21434776, "NumLink": 0, "digest": "sha256:0021379b5504a82adb2eb8292ca703b5bac28d67ed2764202476ad89526db1e9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/90.pl", "type": "reg", "size": 598, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21435681, "NumLink": 0, "digest": "sha256:d107b601802e681fcc8102c0360127dfc691b3a301ea27050b1b6dfed632f906" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Nv/900.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21436183, "NumLink": 0, "digest": "sha256:2553e3e7f5fafcee581b2dd9e769b51501b4731ff721f8a4e987a4f39c3e5d58" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/PatSyn/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/PatSyn/Y.pl", "type": "reg", "size": 747, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21436691, "NumLink": 0, "digest": "sha256:7f8b03f8f1438356ca96901ffd41d91499bea0b8401eac571cb29261abaa711c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/Alnum.pl", "type": "reg", "size": 7714, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21437317, "NumLink": 0, "digest": "sha256:9952517b0c62af4389521abaf62d3f77d595f3ffa0b19a4e27390ba92610cc8c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/Assigned.pl", "type": "reg", "size": 7525, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21440807, "NumLink": 0, "digest": "sha256:8a4fc3da22c19db3eb90d62a430d70f94845ef607485015e3829da58ac88d08a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/Blank.pl", "type": "reg", "size": 561, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21444177, "NumLink": 0, "digest": "sha256:6caa50b959c6f4371ec7a8ff725912b6a9485ceab430a2a9d74e17379db8755d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/Graph.pl", "type": "reg", "size": 7574, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21444667, "NumLink": 0, "digest": "sha256:d635200d45c7c73eab08976c3a06c4ee07d4dd09f2e9d519a05c34f1b66b818b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/PerlWord.pl", "type": "reg", "size": 514, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21448060, "NumLink": 0, "digest": "sha256:b77ce2917f3475d0cbca36f6fcbe815012fef84ef399ef9cca93105f07d577d5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/PosixPun.pl", "type": "reg", "size": 515, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21448523, "NumLink": 0, "digest": "sha256:2fcf2c1b20a2cf64bf2d8ae307e88f7e73a630e092f3f53c531c0d4d2eb60483" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/Print.pl", "type": "reg", "size": 7544, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21448985, "NumLink": 0, "digest": "sha256:7050e54f3f298bddbcdfe968001ac0c47cf9970e5a7935acee6b4b7cea9e929e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/SpacePer.pl", "type": "reg", "size": 579, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21452371, "NumLink": 0, "digest": "sha256:290b77398af470f5a01ae7c5adfaf1bcb07923be2bca3714ebe75753c140c48d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/Title.pl", "type": "reg", "size": 582, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21452864, "NumLink": 0, "digest": "sha256:c253dd153be8fe8a5801253eb6481afcb77db713d8f610438ca48442f6075cb6" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/Word.pl", "type": "reg", "size": 7842, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21453369, "NumLink": 0, "digest": "sha256:1a1cc4d2d8e4ba131156d73913dfc69be0a7356248788439afb7dff8ea42280a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/XPosixPu.pl", "type": "reg", "size": 2197, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21456911, "NumLink": 0, "digest": "sha256:e26a1dd90019c5aab86075ad71a2cb5f3e8ccdd351ab1f1f587bd2e66b56b164" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/_PerlAny.pl", "type": "reg", "size": 1673, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21458109, "NumLink": 0, "digest": "sha256:fee75cd5ad55c4c63be21af06b5fb660423e00e818bfbd2ebe51fe05136605df" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/_PerlCh2.pl", "type": "reg", "size": 7896, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21459137, "NumLink": 0, "digest": "sha256:ad559d235f4ad82d1e76a7bdfe5bdd1f8fe81e6ae46a219d505945c65c4ea72d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/_PerlCha.pl", "type": "reg", "size": 6788, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21462706, "NumLink": 0, "digest": "sha256:9a8988e8ae2dd1e436489caba1a27a9656c39ca9e92a4882c009a2f6de955fba" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/_PerlFol.pl", "type": "reg", "size": 772, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21465780, "NumLink": 0, "digest": "sha256:5108f098c6e2d5784eb1f5c257db5a86c7a03dbd4e9665f4c03a8f1830f48cb1" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/_PerlIDC.pl", "type": "reg", "size": 7870, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21466365, "NumLink": 0, "digest": "sha256:5316fa69c266fa288c4822ead5fe7a992be767c5a590f4c6be7af568560d8f11" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/_PerlIDS.pl", "type": "reg", "size": 6830, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21469916, "NumLink": 0, "digest": "sha256:607494d403c1ec2bb6e3bb337779829df1cc146a816a4be29c6a9ba1f9ef19fc" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/_PerlNch.pl", "type": "reg", "size": 742, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21473011, "NumLink": 0, "digest": "sha256:5838b0621e3cb7ca2c504a6d84c340c204a109f0196e49b5753ca7b476a8802c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/_PerlPat.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21473583, "NumLink": 0, "digest": "sha256:82bb1d0597b2a672b6c7f758ea8ee3b455c0b838335a78e4c6caf928a78bf21e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/_PerlPr2.pl", "type": "reg", "size": 602, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21474050, "NumLink": 0, "digest": "sha256:1a6f866d8d1d7959aa1c516dc9e2f897fdea0979ac8a4ae72ede7cc914ebc77b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/_PerlPro.pl", "type": "reg", "size": 594, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21474567, "NumLink": 0, "digest": "sha256:7c66d8b2697b4c70f21e26079140360c36135ad4ff40f06220f71d9168202964" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Perl/_PerlQuo.pl", "type": "reg", "size": 880, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21475077, "NumLink": 0, "digest": "sha256:77ed1efcc69728561207468b1633d4eb689b5b52fe1b1c67cf580ee461384650" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/QMark/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/QMark/Y.pl", "type": "reg", "size": 622, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21475767, "NumLink": 0, "digest": "sha256:cb3ab30d546abbb3adb5bcec8f5d87e03971aa26cac99751b30131a4e522c541" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/AT.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21476317, "NumLink": 0, "digest": "sha256:8b3f0b56cc1ca8ee4c761f2f97708e8488e2bc3663030b405d221502d6b581a8" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/CL.pl", "type": "reg", "size": 962, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21476782, "NumLink": 0, "digest": "sha256:0d142d8538c03b5c1f92bd79bd0788afbcf0df2f4fc31a1f4331f268ea62e359" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/EX.pl", "type": "reg", "size": 3087, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21477450, "NumLink": 0, "digest": "sha256:cacbd9e5476b94620ad8fd69bb61c78eeafcb81025961cea5ca835abc2f27945" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/FO.pl", "type": "reg", "size": 690, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21479003, "NumLink": 0, "digest": "sha256:66981228c363ee5ded673fc92d223eaffa3f04125cddbec3697ce26a91e358cb" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/LE.pl", "type": "reg", "size": 5607, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21479555, "NumLink": 0, "digest": "sha256:695c41da6f692fd87bd7dc442d14583021a8e8d88be6a5c58afc30d7f44279b8" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/LO.pl", "type": "reg", "size": 6978, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21482153, "NumLink": 0, "digest": "sha256:7fdbc639de5654f060468fd16c3b81e28dd423130b719b927d8fe3b093ed1b50" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/NU.pl", "type": "reg", "size": 1041, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21485451, "NumLink": 0, "digest": "sha256:021d9f558b33d16cebba51f98f508b8312a7c281736a2ff87b0451e703dc51b2" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/SC.pl", "type": "reg", "size": 694, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21486184, "NumLink": 0, "digest": "sha256:552575e253a94f8201b781e7ce63ebe61297a31223d72695407a2195109e9742" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/ST.pl", "type": "reg", "size": 1173, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21486726, "NumLink": 0, "digest": "sha256:b74f0863978c79d6d0274bde0cb8ef806da132f2d707311e7530ac3f9ec96d25" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/Sp.pl", "type": "reg", "size": 567, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21487477, "NumLink": 0, "digest": "sha256:f79d66f8d7ea24ddd3799fc847bfac9a89681e0a4c2dfd5be626a680aba329c1" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/UP.pl", "type": "reg", "size": 6958, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21487969, "NumLink": 0, "digest": "sha256:0ef1d8351b9ed81b1849112bab416fb7b34e54ab0db3b894697899eb71ac83a7" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SB/XX.pl", "type": "reg", "size": 8583, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21491241, "NumLink": 0, "digest": "sha256:a612aa0ebcf3a22e857a4b6da1b787d96d154f13916c0aec1d0e5b46b9248323" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SD/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/SD/Y.pl", "type": "reg", "size": 842, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21495129, "NumLink": 0, "digest": "sha256:79830cc7a53e501897ed8ac651e1144c52ae1296c75bae0c59f3ba64b8e09725" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/STerm/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/STerm/Y.pl", "type": "reg", "size": 1203, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21495759, "NumLink": 0, "digest": "sha256:1a2401619db14c43424d2859f389995dc07c28574cc2ec9ae553adbb6480e621" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Arab.pl", "type": "reg", "size": 1183, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21496550, "NumLink": 0, "digest": "sha256:391e6e7828216774af135c7db740773bf09a654a371848fbd058c65a57e6645c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Armn.pl", "type": "reg", "size": 552, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21497272, "NumLink": 0, "digest": "sha256:dc53d34785f52f46ad7b070bbee2b5bfd29659d8c3404b45d75eea5e0a779e1c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Beng.pl", "type": "reg", "size": 630, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21497750, "NumLink": 0, "digest": "sha256:9d880049f3d8aa0de59fff5e0b00b0f2eed60c75f41d7793855d3895923edccd" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Cham.pl", "type": "reg", "size": 537, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21498267, "NumLink": 0, "digest": "sha256:5090d5f71d3ebc95537aab6d7f8a9a9718d868ed2f70d0f168daac292965f793" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Cprt.pl", "type": "reg", "size": 562, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21498730, "NumLink": 0, "digest": "sha256:677f13ec7877273622ff8452af3556fa95b6eb26ff8277e5770fed2af32f83d5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Cyrl.pl", "type": "reg", "size": 566, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21499205, "NumLink": 0, "digest": "sha256:71208af01e306dff25877689ac0c93dd1c73421060f7ea5ddbe2c456a464959a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Deva.pl", "type": "reg", "size": 531, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21499693, "NumLink": 0, "digest": "sha256:1fa5bef570ad8ca7776e6b43fb8cad5922c7a415cf79e8ff5499130c607c79e0" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Dupl.pl", "type": "reg", "size": 560, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21500158, "NumLink": 0, "digest": "sha256:5d62fbf32fa26c241f8e6fbc5886168de8ac180c62f5e099b25275efe96b0e4c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Ethi.pl", "type": "reg", "size": 838, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21500629, "NumLink": 0, "digest": "sha256:f442e3c03c2e5bf4e4cff85fea65895e3dd30b3a8d8897ccf5876d543721357b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Geor.pl", "type": "reg", "size": 576, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21501229, "NumLink": 0, "digest": "sha256:5cd28f74fa815920c263618885f86cb12a522eb5c20e752ef68e7ee07e0fecdd" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Gran.pl", "type": "reg", "size": 670, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21501716, "NumLink": 0, "digest": "sha256:627ef9311d3318708c1d1e969fbbd759012b60ae1137165ae2fa675e57a44d4a" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Grek.pl", "type": "reg", "size": 840, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21502233, "NumLink": 0, "digest": "sha256:ba3ee2c1a1243596b4c674f19c862b794cb39f437789dfd581a65fbcd740bc51" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Gujr.pl", "type": "reg", "size": 630, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21502858, "NumLink": 0, "digest": "sha256:606ab94e81f5d4fdfaa8d06df3ca7a76880b864ac9b457de14ace9ef971b58e6" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Guru.pl", "type": "reg", "size": 650, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21503373, "NumLink": 0, "digest": "sha256:81005b5c2ea47842b1c641758b7159435ab42cdfdd9b3b59f3c6446ff491614c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Han.pl", "type": "reg", "size": 692, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21503890, "NumLink": 0, "digest": "sha256:03730121b80a9be3287176180ac9af84c037bb55315e6d20dc32bef95f4c0172" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Hang.pl", "type": "reg", "size": 656, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21504442, "NumLink": 0, "digest": "sha256:e7074414982df58297d3be0ffafbf8151a392cf9685961ae390c0d748dfdbe74" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Hebr.pl", "type": "reg", "size": 592, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21504974, "NumLink": 0, "digest": "sha256:95eda2aab9fa22213c9f0670fab3ce7898bb4968fa0749aa4bafb1458fbe906d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Hira.pl", "type": "reg", "size": 541, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21505465, "NumLink": 0, "digest": "sha256:f4a6388261e150b9582ae97adde0196558ab29cf9aaffb8e6ac1419d785aa98d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Hmng.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21505937, "NumLink": 0, "digest": "sha256:025d3ed22ce8b000246b516faef397e8cbc6325d87d10e2fe46bdbd8b8aded7d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Kana.pl", "type": "reg", "size": 588, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21506407, "NumLink": 0, "digest": "sha256:370e75d471e839252b932ad9c692847e29b6e8ff6b37672aa9edf78c304d45c5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Khar.pl", "type": "reg", "size": 586, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21506904, "NumLink": 0, "digest": "sha256:abde89231e73224c436c23c41863e463b5ddc0309f984dc2c7976b7257939aaa" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Khmr.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21507389, "NumLink": 0, "digest": "sha256:557b71c15ae04706c5b2e3cf62d0f0dd117ccdf798f7f44109405f5ff30f8e99" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Knda.pl", "type": "reg", "size": 630, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21507856, "NumLink": 0, "digest": "sha256:424843eea932b69369654447ad0954df298ee8490fdab5a44d9ac8489083c51d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Lana.pl", "type": "reg", "size": 540, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21508367, "NumLink": 0, "digest": "sha256:ee52439efb562c59d288b90995590a46aa413d112a1e4a9f2718f0b47ed9b57c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Lao.pl", "type": "reg", "size": 670, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21508838, "NumLink": 0, "digest": "sha256:0061ceac406c2a7dfd5cabead0df79fd3c271de81259c35cb1cad786d1d4d98f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Latn.pl", "type": "reg", "size": 801, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21509362, "NumLink": 0, "digest": "sha256:aa65fa55c01ad33641ae16773d397266e557275150c9297b3e22a1c408563242" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Limb.pl", "type": "reg", "size": 540, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21509978, "NumLink": 0, "digest": "sha256:76f8749d6cb28af3362f19954ac816a4a62a6eb0884bac2281a2c41d9c889705" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Linb.pl", "type": "reg", "size": 574, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21510445, "NumLink": 0, "digest": "sha256:c3ce24b3f422fdbeb65a76caa35a8ef562f2d8f903c6300af8a8c024fabfec73" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Mlym.pl", "type": "reg", "size": 600, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21510927, "NumLink": 0, "digest": "sha256:38aa93ada735f156fd8c1d1344d8acba18193574987e3b3dfcb2c6b506d028a9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Mong.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21511430, "NumLink": 0, "digest": "sha256:40db11e81fd26763bae5d0c38cdba267e6234c9783bc8ae26894b9964631068b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Mult.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21511904, "NumLink": 0, "digest": "sha256:bb5e9949b1f091314c524ba997f053697da005a46973046a88890f3cfb44c1ab" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Orya.pl", "type": "reg", "size": 630, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21512374, "NumLink": 0, "digest": "sha256:b121f8cb42bb658146b2a83f51c74b42464376e9b0451b344067f35e723019b8" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Sinh.pl", "type": "reg", "size": 622, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21512885, "NumLink": 0, "digest": "sha256:1520c9231481722f778117aa4b80385ef3864d74fe8a7d2d9e5ae1eb11013e1c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Talu.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21513399, "NumLink": 0, "digest": "sha256:c9bc81c423d40136bd98ce46a2bc93e77e0a486269f5403169d9f5ab15650b83" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Taml.pl", "type": "reg", "size": 650, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21513861, "NumLink": 0, "digest": "sha256:63e80f0800761f549a1f22c9b40a44a9efba5ea36557d10afc92ad321a1af6df" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Telu.pl", "type": "reg", "size": 620, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21514382, "NumLink": 0, "digest": "sha256:a9809ee1dd684d7f274340480239376911d01438763b2dcee24635a09d95f454" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Tibt.pl", "type": "reg", "size": 560, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21514892, "NumLink": 0, "digest": "sha256:34f03fe6ebecf64c53a6337df7d1fb81555d6bd91fa7da3f09a6fd1ed047b37d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Xsux.pl", "type": "reg", "size": 537, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21515378, "NumLink": 0, "digest": "sha256:326756f86813e33faab4db12d459add1418300d5c03b888c734e1ea95fc90290" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Zinh.pl", "type": "reg", "size": 790, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21515850, "NumLink": 0, "digest": "sha256:6ffc0b229edff63e248bb867894b1841209a0bbbdb5acef54f07fc457bee6f33" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Zyyy.pl", "type": "reg", "size": 2417, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21516447, "NumLink": 0, "digest": "sha256:bf1d7c65f2be5a71a43c5b712ec5b74231f792d282936df11a75e63d46917cf3" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Sc/Zzzz.pl", "type": "reg", "size": 7492, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21517702, "NumLink": 0, "digest": "sha256:aef97d8558d5eca3edc325992d61ec229ad72c20ce142c06c182103372e4110d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Arab.pl", "type": "reg", "size": 1145, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21521084, "NumLink": 0, "digest": "sha256:6fe86c9c031605dc818bb6a9fb35aa206da84cce9befac7c5675f66def073342" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Armn.pl", "type": "reg", "size": 552, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21521792, "NumLink": 0, "digest": "sha256:8104bbaab001aaff455371ba6ba7d4ec8be75ea8bca2291e6f53bb018a3ad8c5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Beng.pl", "type": "reg", "size": 650, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21522270, "NumLink": 0, "digest": "sha256:f6b09a7f2773d738fecf42eba0ed8ecb69bf44f7a297e3e7ff03c239c9ebdbab" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Bopo.pl", "type": "reg", "size": 726, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21522795, "NumLink": 0, "digest": "sha256:4d84e492592330f3afc443c10b145d23b89ab83a4edbfa14226def74e8984243" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Cakm.pl", "type": "reg", "size": 533, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21523350, "NumLink": 0, "digest": "sha256:1024f84347f2bfaacd98b372330c72948ffa6fb37592e0386e0a83879a8f1bea" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Copt.pl", "type": "reg", "size": 534, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21523824, "NumLink": 0, "digest": "sha256:81926afb1a8b5fdeb65d82b4e5c72a57acdccc3bf5e1c90e41963f02a696b766" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Cprt.pl", "type": "reg", "size": 598, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21524298, "NumLink": 0, "digest": "sha256:b0f8205991529c307461b5624b2ed0fcd7a19138439ea33b3bd48ca203754875" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Cyrl.pl", "type": "reg", "size": 556, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21524790, "NumLink": 0, "digest": "sha256:ade9d8f1e4a8831d77d5acb967b07967e332d869a0a6d5674b4333e2f955abc3" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Deva.pl", "type": "reg", "size": 554, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21525274, "NumLink": 0, "digest": "sha256:c2a8adc4eaf7cb7e68e6ed8e65b76019b5b6d8d76cc73a39a110ef7c832786d6" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Dupl.pl", "type": "reg", "size": 560, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21525754, "NumLink": 0, "digest": "sha256:5815a61fc51923241fc94eefc15df6c75df4b9618a7aa4aa7a9eb29793a658fc" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Geor.pl", "type": "reg", "size": 586, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21526227, "NumLink": 0, "digest": "sha256:1824c8df685eeeb654bfb2b909fe1b2e2402362645c3c7e0b2023e57e5918f21" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Glag.pl", "type": "reg", "size": 535, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21526723, "NumLink": 0, "digest": "sha256:a5e9b2059e7af774f3c7fb6e745964cf4ae1d13e9aab87930c02e067448bfd96" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Gran.pl", "type": "reg", "size": 770, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21527192, "NumLink": 0, "digest": "sha256:e4863cbc11c2641691ee9feec52be7ff57419b665da9f00fc9958243097ef581" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Grek.pl", "type": "reg", "size": 856, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21527761, "NumLink": 0, "digest": "sha256:453bd840cd2d2d7707e9d46e43d4bda59547feb83c4d7a6d2a7b6dcdea4f9592" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Gujr.pl", "type": "reg", "size": 662, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21528399, "NumLink": 0, "digest": "sha256:f001bbab220d35ccb9b34c59b8dff27679875cbebd579287332dab6b0f5244e2" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Guru.pl", "type": "reg", "size": 682, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21528933, "NumLink": 0, "digest": "sha256:201226ee4d7744d62bc277f6c91605d6089279be4050b8692e9c045dd612fe79" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Han.pl", "type": "reg", "size": 862, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21529469, "NumLink": 0, "digest": "sha256:1dbb87fdab60f31731ca377da46da55bbc3c447b490d9bd525dcfc20620c311d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Hang.pl", "type": "reg", "size": 836, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21530099, "NumLink": 0, "digest": "sha256:2a883383f42b37a0aca4c031601fa4c692034f9796237e53e3efc2703e624534" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Hira.pl", "type": "reg", "size": 782, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21530703, "NumLink": 0, "digest": "sha256:b0915643b0657a726fec45094508f0187bca5c62d9f53d11e9540c67ab8ba2ae" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Kana.pl", "type": "reg", "size": 756, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21531279, "NumLink": 0, "digest": "sha256:d6bcf7da353acdd5e9a838aba68ffa73077a5cd67a8f0a2f8479cfcc9c9510aa" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Knda.pl", "type": "reg", "size": 670, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21531851, "NumLink": 0, "digest": "sha256:aab06d08de88e4e006480c31f71c74b2caa2fd40b0cd642c40550a723d05a884" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Latn.pl", "type": "reg", "size": 851, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21532386, "NumLink": 0, "digest": "sha256:ef74e04ab1fc951cd7b386640df48f54f393cb33a2b2caff3eb20b2a9f7535c8" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Limb.pl", "type": "reg", "size": 550, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21533027, "NumLink": 0, "digest": "sha256:94f401e7b8f7427cc3eb6c380151a384678cba6c3b81c51a15e0aba18281861e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Linb.pl", "type": "reg", "size": 610, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21533502, "NumLink": 0, "digest": "sha256:819681fdf147c367160322000e3a10aceab7ae0f70db24160ea56f22ceaca7f2" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Mlym.pl", "type": "reg", "size": 630, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21534001, "NumLink": 0, "digest": "sha256:4a6c2c6ad8bf6c4815eedeffefcbe97f6bfa8570ece0b155160d3193693b0a88" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Mong.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21534522, "NumLink": 0, "digest": "sha256:2173e35e7fc77ae45b7766c3e2b50abf45425d2a0cc3581983ba156b45812dfc" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Mult.pl", "type": "reg", "size": 560, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21534991, "NumLink": 0, "digest": "sha256:97324117263a39a06e1a3c1316c87f40c9dc5548ad048e3d3fe2140a0da4a90c" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Mymr.pl", "type": "reg", "size": 535, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21535466, "NumLink": 0, "digest": "sha256:27c0e0c7503416ad0f75d333d716c53a21deed0f9be28714813824c14d9a7143" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Orya.pl", "type": "reg", "size": 650, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21535940, "NumLink": 0, "digest": "sha256:b5d8725e96463b4813fae097ae1a729f33fd83b67789294fa460fe28bc4372c5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Phlp.pl", "type": "reg", "size": 535, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21536467, "NumLink": 0, "digest": "sha256:ebe6ef500aa24950d10667482969d9aef942d2d56c1f3997ecb3d01b102563ad" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Shrd.pl", "type": "reg", "size": 564, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21536932, "NumLink": 0, "digest": "sha256:6b80a96df206302d6c2fec2eef8c86b9485263011e895cb0a64150cf58fda411" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Sind.pl", "type": "reg", "size": 535, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21537413, "NumLink": 0, "digest": "sha256:d6935b15d4f1ed7c247eb259942edfecd2995d987243064580d1164f3b1e0389" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Sinh.pl", "type": "reg", "size": 632, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21537879, "NumLink": 0, "digest": "sha256:6eb5b894fb05bc0ea822513f50b086a1b6e6165853193d84ed7a5d0fc1602be5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Syrc.pl", "type": "reg", "size": 580, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21538400, "NumLink": 0, "digest": "sha256:791c57c89d6787c329cff0b2a2624f2cc8d621fde44eee3af0e081268e496c7b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Tagb.pl", "type": "reg", "size": 529, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21538892, "NumLink": 0, "digest": "sha256:b2141832862363d05881b316c18718c45e4d22521e0dcf1db2e477973415e101" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Takr.pl", "type": "reg", "size": 535, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21539358, "NumLink": 0, "digest": "sha256:271b68e19689772c67e7729a9115197c5e98a59d1183c9532320a8c8078950a4" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Taml.pl", "type": "reg", "size": 692, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21539825, "NumLink": 0, "digest": "sha256:2ebc5b5308aa6ecd879262949a3b692e2f9b0d28b73fee509d62a06e37b71461" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Telu.pl", "type": "reg", "size": 650, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21540367, "NumLink": 0, "digest": "sha256:6516bc5e07b64daee53ae3043509486cf12d3b7adef5361351f1307391df09c5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Thaa.pl", "type": "reg", "size": 564, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21540894, "NumLink": 0, "digest": "sha256:038d130ed6d6e5a837012ef3b9a9d466de9dbae8f77f099fe4848f3cdba5a63e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Tirh.pl", "type": "reg", "size": 535, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21541377, "NumLink": 0, "digest": "sha256:1d5118ade0a294e66ddca138067da39088548bbc12150d960fb2502a1ed82a62" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Yi.pl", "type": "reg", "size": 574, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21541844, "NumLink": 0, "digest": "sha256:5f568a0611b2ef374c716ae445fc62896602f0d242f2633d83efa7d498d94a9f" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Zinh.pl", "type": "reg", "size": 670, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21542334, "NumLink": 0, "digest": "sha256:9ad52bb42607c737a802884ed51a2a38899cd1e7651b2b4331bb8424308e71d4" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Scx/Zyyy.pl", "type": "reg", "size": 2151, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21542874, "NumLink": 0, "digest": "sha256:1c674c07686b646a5b4640746d9b94ab71cf955d9540dfb56d4d4e9395328bb7" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Term/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Term/Y.pl", "type": "reg", "size": 1473, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21544059, "NumLink": 0, "digest": "sha256:2cdaf79acbaf347b062afee8411fcd64b40e21b710e6f592b65d0d87b7a7e888" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/UIdeo/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/UIdeo/Y.pl", "type": "reg", "size": 654, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21544970, "NumLink": 0, "digest": "sha256:06089c8caabc43cdd90864cf04dda05623bd78a8ebacbdee14bac4d07f87d604" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Upper/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/Upper/Y.pl", "type": "reg", "size": 6928, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21545529, "NumLink": 0, "digest": "sha256:8f05c1aaeaba2805ad712abc324c676601cf1f876ba5a83df86fb0fd0ca41e9d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/WB/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/WB/EX.pl", "type": "reg", "size": 552, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21548821, "NumLink": 0, "digest": "sha256:4ea9d698b63a3cb363ed7832498a4badac62ac24a52c7d56784b886c475719b1" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/WB/FO.pl", "type": "reg", "size": 680, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21549300, "NumLink": 0, "digest": "sha256:7aa80285ec594e5c8ec72caa6b91afba3e6c8ac2d179d9ee74314db19c9cc652" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/WB/HL.pl", "type": "reg", "size": 606, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21549850, "NumLink": 0, "digest": "sha256:dc84621340949f46330e6a3a5d3a25c9493f26f5ba236225db60d1ad65552aff" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/WB/KA.pl", "type": "reg", "size": 600, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21550349, "NumLink": 0, "digest": "sha256:5e4bc630ef471f37941ac7687982495aa16ca408cd6d4040652451b14eb94e3d" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/WB/LE.pl", "type": "reg", "size": 5957, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21550853, "NumLink": 0, "digest": "sha256:04a789e6d81dde8c6dde9f7ad82819bda5dd4bb9cf8bf45ec3fc22594dc8af62" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/WB/MB.pl", "type": "reg", "size": 552, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21553584, "NumLink": 0, "digest": "sha256:a5cf1c45426be4afe0b186372b415c9be3cbfe6c47bd75aa7d2c74e83d4abaa7" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/WB/ML.pl", "type": "reg", "size": 576, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21554059, "NumLink": 0, "digest": "sha256:ce95c41d800744b08f2a236e8c8768baa35c1b355f2f1d22ea0f787054a35399" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/WB/MN.pl", "type": "reg", "size": 632, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21554553, "NumLink": 0, "digest": "sha256:adb85c1d377067046b950aef31786832b791113ce661a4272f437bdfe18f90d9" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/WB/NU.pl", "type": "reg", "size": 1041, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21555072, "NumLink": 0, "digest": "sha256:667c6073a434ac9ba291c8d74894f8d20bf230ebf24a110ce540c04002297a3e" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/WB/XX.pl", "type": "reg", "size": 7978, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21555806, "NumLink": 0, "digest": "sha256:958a3765a4043eb2b27a977d845b343ac7c8f23ea83e1c1febc12fcbb46a17ed" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/XIDC/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/XIDC/Y.pl", "type": "reg", "size": 7870, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21559416, "NumLink": 0, "digest": "sha256:f7c1bda1333c0e2c8d8ee1aff7a4cff506ec10ae2e37ea196899e3f1e50e0753" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/XIDS/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/unicore/lib/XIDS/Y.pl", "type": "reg", "size": 6814, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21562992, "NumLink": 0, "digest": "sha256:bbc41d2ee979acb3350dc9160b0a5e6ddfe135d80e35cd352fb46b30a40a65cb" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/utf8.pm", "type": "reg", "size": 342, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21566068, "NumLink": 0, "digest": "sha256:f206b889aca0a761b973cb3dc58763c2863f3b9429f47164d1dd57f3d041d088" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/utf8_heavy.pl", "type": "reg", "size": 31615, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21566393, "NumLink": 0, "digest": "sha256:dd1cea927bfb0cd3ddc6020ee822aac3745aa7723ccfbd4beb1d70a652224a4b" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/vars.pm", "type": "reg", "size": 1149, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21574998, "NumLink": 0, "digest": "sha256:665260cd8f2ce2ae717e29e87c8f5499b7154ac6f20a4bb8c222ee4456639aa5" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/warnings/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/warnings/register.pm", "type": "reg", "size": 488, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21575707, "NumLink": 0, "digest": "sha256:962110d3faf3e55749a260d97edaf8a9d31293b0f33d2e7771663a9ef364aa94" }, { "name": "usr/lib/x86_64-linux-gnu/perl-base/warnings.pm", "type": "reg", "size": 21639, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 21576114, "NumLink": 0, "digest": "sha256:6677ba2321f7c3135854ca6f6b0d8bcaaac3fcf72dd182058a03d83705f457d8" }, { "name": "usr/local/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17917, "gid": 50, "NumLink": 0 }, { "name": "usr/local/bin/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17917, "gid": 50, "NumLink": 0 }, { "name": "usr/local/etc/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17917, "gid": 50, "NumLink": 0 }, { "name": "usr/local/games/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17917, "gid": 50, "NumLink": 0 }, { "name": "usr/local/include/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17917, "gid": 50, "NumLink": 0 }, { "name": "usr/local/lib/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17917, "gid": 50, "NumLink": 0 }, { "name": "usr/local/man", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "share/man", "mode": 41471, "gid": 50, "NumLink": 0 }, { "name": "usr/local/sbin/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17917, "gid": 50, "NumLink": 0 }, { "name": "usr/local/share/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17917, "gid": 50, "NumLink": 0 }, { "name": "usr/local/share/man/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17917, "gid": 50, "NumLink": 0 }, { "name": "usr/local/src/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17917, "gid": 50, "NumLink": 0 }, { "name": "usr/sbin/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/sbin/add-shell", "type": "reg", "size": 860, "modtime": "2017-04-02T17:10:33Z", "mode": 33261, "offset": 21580564, "NumLink": 0, "digest": "sha256:959e8afe5754f4f09e70e95f3aa952d265e9344b0cb635663aeb4bbf70347bf3" }, { "name": "usr/sbin/addgroup", "type": "symlink", "modtime": "2016-06-26T22:55:17Z", "linkName": "adduser", "mode": 41471, "NumLink": 0 }, { "name": "usr/sbin/adduser", "type": "reg", "size": 34509, "modtime": "2016-06-26T22:55:16Z", "mode": 33261, "offset": 21581154, "NumLink": 0, "digest": "sha256:90bcaa8bc2e8a547ec25f521717cfe28c7c8449144622f65b24b373055d97f86" }, { "name": "usr/sbin/chgpasswd", "type": "reg", "size": 59184, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21590493, "NumLink": 0, "digest": "sha256:a6accd32550d5ef4be45cafb960928c94fc2dd4f4ceba3a1fa0dc2d6a6cec83a" }, { "name": "usr/sbin/chpasswd", "type": "reg", "size": 51096, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21614137, "NumLink": 0, "digest": "sha256:47c59f3e369c234f699786c6a248c9bbbd3e77059ec9518dfb649e7b7e12de5d" }, { "name": "usr/sbin/chroot", "type": "reg", "size": 39816, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 21634667, "NumLink": 0, "digest": "sha256:503b2a1eef247103e996f554a39cc0993874458acdea6a8a2d8a91abe266dfa5" }, { "name": "usr/sbin/cpgr", "type": "symlink", "modtime": "2017-05-17T11:59:59Z", "linkName": "cppw", "mode": 41471, "NumLink": 0 }, { "name": "usr/sbin/cppw", "type": "reg", "size": 53248, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21652809, "NumLink": 0, "digest": "sha256:ec0206f95e21c88c1df1a18c6a22de7e66df89f82f59630954e427ff521097a8" }, { "name": "usr/sbin/delgroup", "type": "symlink", "modtime": "2016-06-26T22:55:17Z", "linkName": "deluser", "mode": 41471, "NumLink": 0 }, { "name": "usr/sbin/deluser", "type": "reg", "size": 15798, "modtime": "2016-06-26T22:55:16Z", "mode": 33261, "offset": 21673966, "NumLink": 0, "digest": "sha256:74c622e5b715f007b903281046a02b42789bd5b5a23ca402141d29551b539507" }, { "name": "usr/sbin/dpkg-preconfigure", "type": "reg", "size": 3604, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 21679333, "NumLink": 0, "digest": "sha256:82fa48ad05b55af0aed8fe79455301af57d57bfe76f32902ba3f87189b04f55f" }, { "name": "usr/sbin/dpkg-reconfigure", "type": "reg", "size": 4335, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 21680816, "NumLink": 0, "digest": "sha256:bb6b8c55f0054f73f45d65918c59b1b8cc4435d60239c96f0717491b509cf69e" }, { "name": "usr/sbin/e2freefrag", "type": "reg", "size": 10312, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 21682662, "NumLink": 0, "digest": "sha256:06851e325b694d1a54e0b706cd3dacbb522791770c1e82ac9bc103df8d66dfc2" }, { "name": "usr/sbin/e4crypt", "type": "reg", "size": 22600, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 21687223, "NumLink": 0, "digest": "sha256:352d971ad3389b75059fca8a68c2bba434f5e44625c157e31148e73fd341ad60" }, { "name": "usr/sbin/e4defrag", "type": "reg", "size": 26616, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 21696070, "NumLink": 0, "digest": "sha256:9fb3b0dceaef564bf6c0c52de2398b4ae8d93f779a08b4d6d8e0fce3eef89d55" }, { "name": "usr/sbin/fdformat", "type": "reg", "size": 31400, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 21707697, "NumLink": 0, "digest": "sha256:82115367585702c576cb36c3f2a326937624394e67911d62197c54a5098535c1" }, { "name": "usr/sbin/filefrag", "type": "reg", "size": 14352, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 21720393, "NumLink": 0, "digest": "sha256:9a1e6e12e7c7bfec60296ab2d770fb407577e5a3f6954938935f0065418b5129" }, { "name": "usr/sbin/groupadd", "type": "reg", "size": 59248, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21726797, "NumLink": 0, "digest": "sha256:2c74c36be4c3f0ffb3545e0e52e76b50cb52e55a7d30dfa54b56012b285b9310" }, { "name": "usr/sbin/groupdel", "type": "reg", "size": 54936, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21750959, "NumLink": 0, "digest": "sha256:135dc18f16a06d1f950f6fc14cb52ed45fb447ce8043c360a86e8c7cf294d0e3" }, { "name": "usr/sbin/groupmems", "type": "reg", "size": 55128, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21773295, "NumLink": 0, "digest": "sha256:9450933cf5092fa7360c8656168f39c00f93a58b78772ba25b6c0166d34d589d" }, { "name": "usr/sbin/groupmod", "type": "reg", "size": 69856, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21796121, "NumLink": 0, "digest": "sha256:7a0bd57b4fa63cf06c4e2f4c274e2566301cda9345afe5de424bdd4decf2bf57" }, { "name": "usr/sbin/grpck", "type": "reg", "size": 55064, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21823831, "NumLink": 0, "digest": "sha256:d2e867ecab4765822b1d6d5a432ca7091be3e4392189c684570712dd674f2552" }, { "name": "usr/sbin/grpconv", "type": "reg", "size": 50840, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21846506, "NumLink": 0, "digest": "sha256:6833fceebf2df346b988f68587c501877df463bbba0f2254f17076af3392ed99" }, { "name": "usr/sbin/grpunconv", "type": "reg", "size": 50840, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21866740, "NumLink": 0, "digest": "sha256:90b88dc6a4ac3352dbd8a419534c8922439cbb5c85ab6c67197591802aa4b670" }, { "name": "usr/sbin/iconvconfig", "type": "reg", "size": 23208, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 21886856, "NumLink": 0, "digest": "sha256:2c27f482761dab9ce4e634c1d3a5995082292c6c9f0eea8eaefd55ad16360ac0" }, { "name": "usr/sbin/invoke-rc.d", "type": "reg", "size": 18110, "modtime": "2017-05-02T10:20:21Z", "mode": 33261, "offset": 21897773, "NumLink": 0, "digest": "sha256:b97967909c85bb209845a7568d6e179ea1859e4761eed87edd864ae71625f79a" }, { "name": "usr/sbin/ldattach", "type": "reg", "size": 31448, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 21903781, "NumLink": 0, "digest": "sha256:e2e130f7119d1991a6b611f8c29d45f4ddf58c630d5fe5cf03833e101f4e5e2d" }, { "name": "usr/sbin/mklost+found", "type": "reg", "size": 10232, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 21916527, "NumLink": 0, "digest": "sha256:aaebcc49bc9e8396188d597de70fd9efdd6bdad30400a52796afa2fd61c6cc4a" }, { "name": "usr/sbin/newusers", "type": "reg", "size": 80312, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21919174, "NumLink": 0, "digest": "sha256:ca6ec91c32fd12432ab9f79eae4d58a79b07dec65e54d5ae0e524c1d7934d76d" }, { "name": "usr/sbin/nologin", "type": "reg", "size": 6136, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21949610, "NumLink": 0, "digest": "sha256:3d9563812289692aa1cb3d0c7ba193312ecfd98a34421ffdb62ed854d018c73c" }, { "name": "usr/sbin/pam-auth-update", "type": "reg", "size": 19490, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 21951688, "NumLink": 0, "digest": "sha256:d0edc70d5d2e46f81be6b1d5647fc54508e23630f9cb139bf6722965f21d64d3" }, { "name": "usr/sbin/pam_getenv", "type": "reg", "size": 2890, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 21958701, "NumLink": 0, "digest": "sha256:982cca7d6a9afe07d7ba3fc929082ef11ed1cadb88d253f6464bfc0a19730674" }, { "name": "usr/sbin/pam_timestamp_check", "type": "reg", "size": 10616, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 21960193, "NumLink": 0, "digest": "sha256:3698a30b91c6362501b703f24664dd367b8c73a9d25a60825fcfbe29a3992577" }, { "name": "usr/sbin/policy-rc.d", "type": "reg", "size": 255, "modtime": "2018-10-11T00:00:00Z", "mode": 33261, "offset": 21964501, "NumLink": 0, "digest": "sha256:21a8dca0d6a52cbac52cb7a86178d973616ffb42ea08747e6ff311659ab095e1" }, { "name": "usr/sbin/pwck", "type": "reg", "size": 51032, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21964776, "NumLink": 0, "digest": "sha256:3db87b030c79facd0e66f3fce64416820580d9509c6bb4c822152027c8ff427d" }, { "name": "usr/sbin/pwconv", "type": "reg", "size": 46840, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 21984047, "NumLink": 0, "digest": "sha256:ad2df81e018de0becd84b6ba604135696e0ef9b55ef8b4c45fda13474674ce49" }, { "name": "usr/sbin/pwunconv", "type": "reg", "size": 42720, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 22001336, "NumLink": 0, "digest": "sha256:3927d6643798b70627213deb68041a1176aa6bc001f2c35dd64e96215c5e6a37" }, { "name": "usr/sbin/readprofile", "type": "reg", "size": 19032, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 22018269, "NumLink": 0, "digest": "sha256:53baf68d38dbc992407f89e6c4bfbfe40d70e2e322e32737c67a2d0da1c158f5" }, { "name": "usr/sbin/remove-shell", "type": "reg", "size": 904, "modtime": "2017-04-02T17:10:33Z", "mode": 33261, "offset": 22025169, "NumLink": 0, "digest": "sha256:5a15986f8fd235bccf215832a5c39070acd6c48176c73a2415a7148bed327267" }, { "name": "usr/sbin/rmt", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/etc/alternatives/rmt", "mode": 41471, "NumLink": 0 }, { "name": "usr/sbin/rmt-tar", "type": "reg", "size": 56352, "modtime": "2016-10-30T06:35:31Z", "mode": 33261, "offset": 22025793, "NumLink": 0, "digest": "sha256:3ba1fec0831eefd0ddc86525288b27c0c0780322861d95a36b6f558c237290c4" }, { "name": "usr/sbin/rtcwake", "type": "reg", "size": 43840, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 22054312, "NumLink": 0, "digest": "sha256:5bcd24a767249c4585697dcd3d37219b42a9a7fda402df5d18bfa436c01cea8c" }, { "name": "usr/sbin/service", "type": "reg", "size": 10061, "modtime": "2017-05-02T10:20:21Z", "mode": 33261, "offset": 22073569, "NumLink": 0, "digest": "sha256:2727d140345fbba81c6c842d54822f2f8ee78e4c57a9b488f5ce0ff7c572e6bb" }, { "name": "usr/sbin/tarcat", "type": "reg", "size": 936, "modtime": "2016-10-30T06:35:31Z", "mode": 33261, "offset": 22076719, "NumLink": 0, "digest": "sha256:4307aa7cc97a4db32a674ad32f893b251188903cafa6d5266c813fc5c9ea755e" }, { "name": "usr/sbin/tunelp", "type": "reg", "size": 27248, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 22077335, "NumLink": 0, "digest": "sha256:ddcafb165a85a34431f1d2989e6405f80f6df3baa9d69fceb980962e6c22fdb4" }, { "name": "usr/sbin/tzconfig", "type": "reg", "size": 106, "modtime": "2016-01-21T17:04:38Z", "mode": 33261, "offset": 22088271, "NumLink": 0, "digest": "sha256:816e1759cc6a017900439acc6c85dd2293cc78948d54bf76c1f23bf16437b1fc" }, { "name": "usr/sbin/update-passwd", "type": "reg", "size": 31136, "modtime": "2017-01-16T15:52:12Z", "mode": 33261, "offset": 22088466, "NumLink": 0, "digest": "sha256:69f054530b4a1631c477d3b1096046836ac257cd9a1f8ecbdd279229cf7dd3a3" }, { "name": "usr/sbin/update-rc.d", "type": "reg", "size": 16062, "modtime": "2017-05-02T10:20:21Z", "mode": 33261, "offset": 22101198, "NumLink": 0, "digest": "sha256:7334018b606ce73b6266b4f073638f706df24ef4f1dcbebe53bb48bbb81e322e" }, { "name": "usr/sbin/useradd", "type": "reg", "size": 122152, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 22105960, "NumLink": 0, "digest": "sha256:1dec582729d5dad31c8b797f8a5b3625a5e84a9f6c0a33149458ff9372066853" }, { "name": "usr/sbin/userdel", "type": "reg", "size": 84472, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 22155067, "NumLink": 0, "digest": "sha256:5b9097e787567d9ffac2bb5e4c5e4b151c377acea6d2718751ad52e97e652131" }, { "name": "usr/sbin/usermod", "type": "reg", "size": 121960, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 22188064, "NumLink": 0, "digest": "sha256:43260cdabc4a9286c44b87749f5537c6ee6740c9f902fcf93bfafa7b07691fab" }, { "name": "usr/sbin/vigr", "type": "symlink", "modtime": "2017-05-17T11:59:59Z", "linkName": "vipw", "mode": 41471, "NumLink": 0 }, { "name": "usr/sbin/vipw", "type": "reg", "size": 61664, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 22237251, "NumLink": 0, "digest": "sha256:4b3632017c35f6bc85a13ffa93094059e6b3919c8b0ce9e6e6083b41f6d0c2c4" }, { "name": "usr/sbin/zic", "type": "reg", "size": 43560, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 22260567, "NumLink": 0, "digest": "sha256:f0af0e819802cbc10e6855ec744a891b18e3db25c8b3ed9cfda4e5cfb77ed40e" }, { "name": "usr/share/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/adduser/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/adduser/adduser.conf", "type": "reg", "size": 2981, "modtime": "2016-06-26T20:20:46Z", "mode": 33188, "offset": 22283213, "NumLink": 0, "digest": "sha256:ccdc9675d7bd39c3cc79c2a5d6938f2562dd4062350dbed3058c1faee48b353e" }, { "name": "usr/share/base-files/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/base-files/dot.bashrc", "type": "reg", "size": 570, "modtime": "2010-01-31T11:52:26Z", "mode": 33188, "offset": 22284711, "NumLink": 0, "digest": "sha256:41f1685d04031d88891dea1cd02d5154f8aa841119001a72017b0e7158159e23" }, { "name": "usr/share/base-files/dot.profile", "type": "reg", "size": 148, "modtime": "2015-08-17T15:30:33Z", "mode": 33188, "offset": 22285167, "NumLink": 0, "digest": "sha256:74bc92bcf960bfb62b22aa65370cdd1cd37739baa4eab9b240d72692c898ef1f" }, { "name": "usr/share/base-files/dot.profile.md5sums", "type": "reg", "size": 72, "modtime": "2015-08-17T15:32:01Z", "mode": 33188, "offset": 22285395, "NumLink": 0, "digest": "sha256:8961ee041c712c735fb05287740ab62737777bd58ce631b54b07d8083efad3bf" }, { "name": "usr/share/base-files/info.dir", "type": "reg", "size": 781, "modtime": "2018-06-26T12:03:08Z", "mode": 33188, "offset": 22285559, "NumLink": 0, "digest": "sha256:c58a258cb9c410c29486aa8fa37f4e5b738bfeedc2b8e97be1cd6cff1df28459" }, { "name": "usr/share/base-files/motd", "type": "reg", "size": 286, "modtime": "2018-06-26T12:03:08Z", "mode": 33188, "offset": 22286147, "NumLink": 0, "digest": "sha256:a378977155fb42bb006496321cbe31f74cbda803c3f6ca590f30e76d1afad921" }, { "name": "usr/share/base-files/profile", "type": "reg", "size": 767, "modtime": "2016-03-04T11:00:00Z", "mode": 33188, "offset": 22286448, "NumLink": 0, "digest": "sha256:b8ffd2c97588047e1cea84b7dfdb68bfde167e2957f667ca2b6ab2929feb4f49" }, { "name": "usr/share/base-files/profile.md5sums", "type": "reg", "size": 607, "modtime": "2016-03-04T11:00:00Z", "mode": 33188, "offset": 22286904, "NumLink": 0, "digest": "sha256:7d09366be1eb6bd4fa6b3cf9837e87236bbb9ec5ebe4e2428fbec3f88b7ec762" }, { "name": "usr/share/base-files/staff-group-for-usr-local", "type": "reg", "size": 771, "modtime": "2012-06-09T10:00:00Z", "mode": 33188, "offset": 22287395, "NumLink": 0, "digest": "sha256:64a482506f00572df1d4909a347d6f4fa8e6ce23686b7f058bfbd650ec0658ce" }, { "name": "usr/share/base-passwd/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/base-passwd/group.master", "type": "reg", "size": 446, "modtime": "2017-01-16T15:52:12Z", "mode": 33188, "offset": 22287950, "NumLink": 0, "digest": "sha256:cfde4574c857edbfbd31667000d75d07efe6bc61f22063693010dee2a912450b" }, { "name": "usr/share/base-passwd/passwd.master", "type": "reg", "size": 877, "modtime": "2017-01-16T15:52:12Z", "mode": 33188, "offset": 22288319, "NumLink": 0, "digest": "sha256:5e66dea2e22fa69f64b4f92053bedbf8ea2550dffb95967994730b718f4eb930" }, { "name": "usr/share/bash-completion/", "type": "dir", "modtime": "2017-05-21T17:08:30Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/bash-completion/completions/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/bash-completion/completions/addpart", "type": "reg", "size": 447, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22288823, "NumLink": 0, "digest": "sha256:61badc8851eb6f1c153df1a07c9c2f3bffa048fbd05d1ef775384087440a08c8" }, { "name": "usr/share/bash-completion/completions/apt", "type": "reg", "size": 7034, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 22289190, "NumLink": 0, "digest": "sha256:df95a61a8b6c5e4e779919c37fb600030ea04215e4aa82e510fbd7b6b3bf55ed" }, { "name": "usr/share/bash-completion/completions/blkdiscard", "type": "reg", "size": 571, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22290932, "NumLink": 0, "digest": "sha256:42afb5f346bd7fbb967529a9fbb92f80207d9757c9e718254e0ebf6dd6e048d1" }, { "name": "usr/share/bash-completion/completions/blkid", "type": "reg", "size": 1395, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22291326, "NumLink": 0, "digest": "sha256:e2d3fa59a351e8af1582816ace0670c72b4088caf60b6dd983cc37c3439c93b1" }, { "name": "usr/share/bash-completion/completions/blockdev", "type": "reg", "size": 726, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22291897, "NumLink": 0, "digest": "sha256:0e33e84094c213cca2fc2e3ea06efc4a655ef4bb27ae4126943c574b98709767" }, { "name": "usr/share/bash-completion/completions/cfdisk", "type": "reg", "size": 546, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22292352, "NumLink": 0, "digest": "sha256:2995b77066141f0a0b67dec82d554a20909466eca6a3e8f237eb709b7f5b4c62" }, { "name": "usr/share/bash-completion/completions/chcpu", "type": "reg", "size": 1510, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22292738, "NumLink": 0, "digest": "sha256:a33736eafd741e7929ab8c13d1484f19a0874fb5a220dac8c6e4e7d3b2dc6458" }, { "name": "usr/share/bash-completion/completions/chrt", "type": "reg", "size": 920, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22293361, "NumLink": 0, "digest": "sha256:1dd13080d71c8d880e628eee89e8f493c979441692ef364e01ca8c8a761d381e" }, { "name": "usr/share/bash-completion/completions/ctrlaltdel", "type": "reg", "size": 335, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22293872, "NumLink": 0, "digest": "sha256:52021091a5554e9b6275cdabbf1820ccd18eff38d8b0094284ef7fb68c38f66f" }, { "name": "usr/share/bash-completion/completions/debconf", "type": "reg", "size": 294, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22294193, "NumLink": 0, "digest": "sha256:45a6978806b39111a579c0e7d4e85937bd6c8e20c3f6732d3ecf5fbd2344cfb0" }, { "name": "usr/share/bash-completion/completions/debconf-show", "type": "symlink", "modtime": "2017-05-21T17:08:30Z", "linkName": "debconf", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/bash-completion/completions/delpart", "type": "reg", "size": 526, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22294515, "NumLink": 0, "digest": "sha256:e337b3898cacda9485085c522d9306a043146cc52c780bbcf2c65b8d366f095a" }, { "name": "usr/share/bash-completion/completions/dmesg", "type": "reg", "size": 1056, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22294910, "NumLink": 0, "digest": "sha256:4084df6fbe19ec0f23ab8793c95a03ef7e48b22b663012bb48ca94128ef3c62b" }, { "name": "usr/share/bash-completion/completions/fallocate", "type": "reg", "size": 643, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22295482, "NumLink": 0, "digest": "sha256:7113bc40db42905fd04f5d0d2ee1cc5bbb2646bffad8c02d4499f57809339888" }, { "name": "usr/share/bash-completion/completions/fdformat", "type": "reg", "size": 414, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22295914, "NumLink": 0, "digest": "sha256:fc16d071c7e14848ac2f86c3456afec6b3231f72acc352177790b90a2ce3350d" }, { "name": "usr/share/bash-completion/completions/fdisk", "type": "reg", "size": 1231, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22296293, "NumLink": 0, "digest": "sha256:6c432ff454d3dded724a4d7cea8e0d4c772bea33ef16fe6ee4599eedde9f2d6f" }, { "name": "usr/share/bash-completion/completions/findmnt", "type": "reg", "size": 3137, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22296835, "NumLink": 0, "digest": "sha256:bf5c1444b07690929d34d98f220de25dfe58c9e4859b902b698fc7525ebccd86" }, { "name": "usr/share/bash-completion/completions/flock", "type": "reg", "size": 860, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22298159, "NumLink": 0, "digest": "sha256:34ace7c62e5f9dfff7729a2b7182f1353b7223203c86068f61da24723b758c9b" }, { "name": "usr/share/bash-completion/completions/fsck", "type": "reg", "size": 752, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22298639, "NumLink": 0, "digest": "sha256:f1a807ffd9e57c34d769a425080836eefb882a060e4c3571db2f8596d6ccdb06" }, { "name": "usr/share/bash-completion/completions/fsck.cramfs", "type": "reg", "size": 607, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22299063, "NumLink": 0, "digest": "sha256:5c79d1606f356dd70e7d82179956c29451cbfc85ce80f04b60e72ed6d2c781b7" }, { "name": "usr/share/bash-completion/completions/fsck.minix", "type": "reg", "size": 383, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22299477, "NumLink": 0, "digest": "sha256:c80e2696bcb4fb7642418d3aec96f7c2931cdcfdaf245786ee3b6cded99e22fe" }, { "name": "usr/share/bash-completion/completions/fsfreeze", "type": "reg", "size": 524, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22299829, "NumLink": 0, "digest": "sha256:7f99f914f660697f78e57850e4e70c027e73a0aa5074a28bd3a5d25c2564b371" }, { "name": "usr/share/bash-completion/completions/fstrim", "type": "reg", "size": 677, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22300235, "NumLink": 0, "digest": "sha256:9c36b670fa1b23811490e2b47b6576a4b58f38ded511ed4f3757e7b858e3700e" }, { "name": "usr/share/bash-completion/completions/getopt", "type": "reg", "size": 815, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22300690, "NumLink": 0, "digest": "sha256:0ae50ed789c556f2abdabe09362169d385f9facf1bd05c13cf57b3f8e0078a5d" }, { "name": "usr/share/bash-completion/completions/hwclock", "type": "reg", "size": 937, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22301129, "NumLink": 0, "digest": "sha256:a16d3a4bf89dac8b127a08357fa278aa6741b0949f5a163e1509985afcc2191d" }, { "name": "usr/share/bash-completion/completions/ionice", "type": "reg", "size": 837, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22301634, "NumLink": 0, "digest": "sha256:121f9bd6d08e331cd90ddf509b2821e9f025141f0ba30b16f201d304a3b10500" }, { "name": "usr/share/bash-completion/completions/ipcmk", "type": "reg", "size": 576, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22302117, "NumLink": 0, "digest": "sha256:701db74a1133159cf159c9a182a46eb77ecdab618c52e373f432b3924d8e2707" }, { "name": "usr/share/bash-completion/completions/ipcrm", "type": "reg", "size": 1423, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22302477, "NumLink": 0, "digest": "sha256:454731bfb20b7be1e41f5b0704536a549ebf7ee755d64bd9ef882b04ae84173d" }, { "name": "usr/share/bash-completion/completions/ipcs", "type": "reg", "size": 514, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22302981, "NumLink": 0, "digest": "sha256:c8d2fc0706082e013fdec16a7b7fcc3aadbc0c3e22f87d8a818d9aa95f364acf" }, { "name": "usr/share/bash-completion/completions/isosize", "type": "reg", "size": 529, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22303373, "NumLink": 0, "digest": "sha256:0afdd61db90044908eef15ef623eb9e6f4598cdfe581f20b1b812650d961f567" }, { "name": "usr/share/bash-completion/completions/last", "type": "reg", "size": 737, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22303750, "NumLink": 0, "digest": "sha256:bc8f9d4188ca658f681e93797ff614bbe0cfae2386bb860735d00b278bc28ced" }, { "name": "usr/share/bash-completion/completions/ldattach", "type": "reg", "size": 1263, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22304174, "NumLink": 0, "digest": "sha256:363c860122e61a3daa0b76cd8f949a81b8d82e81558f148468b0bb272af450ca" }, { "name": "usr/share/bash-completion/completions/logger", "type": "reg", "size": 1431, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22304860, "NumLink": 0, "digest": "sha256:5f755d0b65c08ea67c0fb32a13c36f104952fb3d52a64ec139814633672c98fd" }, { "name": "usr/share/bash-completion/completions/losetup", "type": "reg", "size": 1657, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22305543, "NumLink": 0, "digest": "sha256:6dc177c2c2677dfb5211371de83298a217f33ef6b724d0250728caa6c6842045" }, { "name": "usr/share/bash-completion/completions/lsblk", "type": "reg", "size": 1881, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22306352, "NumLink": 0, "digest": "sha256:7d8bf9fb21ea6a53a41380105d49afe964c0d00182653ecfeb2ea1044ff442cd" }, { "name": "usr/share/bash-completion/completions/lscpu", "type": "reg", "size": 985, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22307246, "NumLink": 0, "digest": "sha256:3d7d68b009e60e1a8c0e381aacd3e3e920f655742ac733fb42cac35ebd89dd58" }, { "name": "usr/share/bash-completion/completions/lsipc", "type": "reg", "size": 1301, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22307869, "NumLink": 0, "digest": "sha256:dff12d8ed515f2ad0cfbd27bb663e761fb25b3263bc02cfb0a61ddac68d38625" }, { "name": "usr/share/bash-completion/completions/lslocks", "type": "reg", "size": 1176, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22308627, "NumLink": 0, "digest": "sha256:fe9cdb7ee7e64deae4b7638f8fc53c585714430803c49f339128d98be4ee6907" }, { "name": "usr/share/bash-completion/completions/lslogins", "type": "reg", "size": 1704, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22309333, "NumLink": 0, "digest": "sha256:713c0e99482efd5139818e6f2a3383db05a6b6f9ae2356ab7f6578e95e3c8eb7" }, { "name": "usr/share/bash-completion/completions/lsns", "type": "reg", "size": 1160, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22310192, "NumLink": 0, "digest": "sha256:e82a2cee42be609becdfda8c1c94d4af59a85bac89741f09eb34fc6248ed7315" }, { "name": "usr/share/bash-completion/completions/mcookie", "type": "reg", "size": 502, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22310825, "NumLink": 0, "digest": "sha256:94c71202101d2267e421343ca9f1e70c9884a2462e1441cdc5fd186cf834dc34" }, { "name": "usr/share/bash-completion/completions/mesg", "type": "reg", "size": 412, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22311198, "NumLink": 0, "digest": "sha256:67d09288e327f405fa72009d7e85b81a70d20c5577ffb8b418b6b0de043e7fc1" }, { "name": "usr/share/bash-completion/completions/mkfs", "type": "reg", "size": 638, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22311531, "NumLink": 0, "digest": "sha256:b90a36595a7585f33e27d5028c66fecb8db2f01832240b70527aa93f9d93c486" }, { "name": "usr/share/bash-completion/completions/mkfs.bfs", "type": "reg", "size": 656, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22311974, "NumLink": 0, "digest": "sha256:fd5315672633d2cc96166fedd130416e7ec9c37a87f8afe57dc906059a4fac04" }, { "name": "usr/share/bash-completion/completions/mkfs.cramfs", "type": "reg", "size": 821, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22312383, "NumLink": 0, "digest": "sha256:a33449ad64a9c1e51ad0b82fc6afbb07febd5650842fea214231f399d7f3bf4d" }, { "name": "usr/share/bash-completion/completions/mkfs.minix", "type": "reg", "size": 714, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22312807, "NumLink": 0, "digest": "sha256:aa873021ae3d172211a649626f466efd53423970ba15d29d6f5ce4fc5d78fcc9" }, { "name": "usr/share/bash-completion/completions/mkswap", "type": "reg", "size": 765, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22313230, "NumLink": 0, "digest": "sha256:55df38a11a3a5c062176af86f5218daa930a8d5883d5c31ae2062ac8da756e68" }, { "name": "usr/share/bash-completion/completions/more", "type": "reg", "size": 528, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22313662, "NumLink": 0, "digest": "sha256:f2a14123adff1db7144fa503b2e939d9383055e7b893a7730e146dd93c328032" }, { "name": "usr/share/bash-completion/completions/mount", "type": "reg", "size": 1908, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22314034, "NumLink": 0, "digest": "sha256:ed4e4eb18ffde93e069890cf183aa5d9682a4f6253db5998267196b6375b3ac6" }, { "name": "usr/share/bash-completion/completions/mountpoint", "type": "reg", "size": 570, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22314884, "NumLink": 0, "digest": "sha256:d882adc45a617a1d4f9f68586dc2c0e91f50045b9b864fed66af94156fed8eba" }, { "name": "usr/share/bash-completion/completions/namei", "type": "reg", "size": 500, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22315289, "NumLink": 0, "digest": "sha256:1519a1b96f840f476647daa9d041a7d5db2dde0d80d3c99e973b1eccff8b259d" }, { "name": "usr/share/bash-completion/completions/nsenter", "type": "reg", "size": 955, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22315681, "NumLink": 0, "digest": "sha256:70f6b574d524a5e9c5453d43c3e0288fc82c7434b9183ae2474eb69e4b1299a3" }, { "name": "usr/share/bash-completion/completions/partx", "type": "reg", "size": 1157, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22316277, "NumLink": 0, "digest": "sha256:ad72aff002951a0534dc0eb986fe83ee4aaf2a439e34bdf14838654ed942d5b6" }, { "name": "usr/share/bash-completion/completions/pg", "type": "reg", "size": 605, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22316980, "NumLink": 0, "digest": "sha256:5dc94774a322d4d6152cf69d869cc70db29a802108675539d658580242715e09" }, { "name": "usr/share/bash-completion/completions/pivot_root", "type": "reg", "size": 387, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22317376, "NumLink": 0, "digest": "sha256:e3fd2fed08fe53b1bdf0b344633375273ce54bdb75c65a4383f2bf29aa9868dd" }, { "name": "usr/share/bash-completion/completions/prlimit", "type": "reg", "size": 1351, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22317717, "NumLink": 0, "digest": "sha256:6e552891869727f1249d3295811069d92dfb23d1cbfe25393b7684938f016018" }, { "name": "usr/share/bash-completion/completions/raw", "type": "reg", "size": 482, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22318469, "NumLink": 0, "digest": "sha256:f546700af22030dffeefaa6b13e9ebb7c24538adb0941dcb98a9d68a6426640f" }, { "name": "usr/share/bash-completion/completions/readprofile", "type": "reg", "size": 679, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22318858, "NumLink": 0, "digest": "sha256:874cf09268bc51c0dd77267ef8e3d9948ff9c8c376a1b9ce911ca135b7baf9a5" }, { "name": "usr/share/bash-completion/completions/renice", "type": "reg", "size": 812, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22319295, "NumLink": 0, "digest": "sha256:631231b93ab12774133788a62650ce3d818ba80b56dc7632e6b7940a565f02b7" }, { "name": "usr/share/bash-completion/completions/resizepart", "type": "reg", "size": 568, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22319764, "NumLink": 0, "digest": "sha256:e0692d25787a3625816b07ea00ef66cfeada23fff0016cf0a37efd95ad84b0d5" }, { "name": "usr/share/bash-completion/completions/rev", "type": "reg", "size": 432, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22320171, "NumLink": 0, "digest": "sha256:ffab4735212694543267952b527e72f3ee4ac9b0e07d49b432db219bd26a3aae" }, { "name": "usr/share/bash-completion/completions/rtcwake", "type": "reg", "size": 921, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22320527, "NumLink": 0, "digest": "sha256:c3dcadb79aa4b54a8c09721acae529ad6d264c794c64068d9f0e279039267f9c" }, { "name": "usr/share/bash-completion/completions/runuser", "type": "reg", "size": 864, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22321008, "NumLink": 0, "digest": "sha256:cfd2d8d2f8c11b25c9c9810aeb1ce2817c17e252a8d0f1e9ee0502cf24008e75" }, { "name": "usr/share/bash-completion/completions/script", "type": "reg", "size": 667, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22321475, "NumLink": 0, "digest": "sha256:4939f89fc4e6fb5577b1803562c103d8ee43648f1f87a938c6c79a67e5850492" }, { "name": "usr/share/bash-completion/completions/scriptreplay", "type": "reg", "size": 592, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22321919, "NumLink": 0, "digest": "sha256:147d35e1d56387599071cb2e27eea8c345433948a478285dac280878b41a2d9d" }, { "name": "usr/share/bash-completion/completions/setarch", "type": "reg", "size": 770, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22322327, "NumLink": 0, "digest": "sha256:9d0a6caf10559e1c1ebec9ad0a34f80711e51da451ab67deec521e46373af12f" }, { "name": "usr/share/bash-completion/completions/setsid", "type": "reg", "size": 433, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22322832, "NumLink": 0, "digest": "sha256:3bcd86d1051046fb0f9c122e0db037e0688dd2cf08f74d8b803cdb4ad2cd7d08" }, { "name": "usr/share/bash-completion/completions/setterm", "type": "reg", "size": 2580, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22323182, "NumLink": 0, "digest": "sha256:05b03c3d0766d7fb55d9b5c9bdc1dd84b837fbdd4739f1d78b4e910375e9f92d" }, { "name": "usr/share/bash-completion/completions/sfdisk", "type": "reg", "size": 1168, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22324128, "NumLink": 0, "digest": "sha256:84c05320ee42af8c98466b2a6482a05d5a393a7b89915984c88e0c311cde8451" }, { "name": "usr/share/bash-completion/completions/swaplabel", "type": "reg", "size": 635, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22324730, "NumLink": 0, "digest": "sha256:1805b9fa1953570fa4bb99339afbb25a6d701ce5a442d22b8ddabe486b46c9c9" }, { "name": "usr/share/bash-completion/completions/swapoff", "type": "reg", "size": 743, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22325132, "NumLink": 0, "digest": "sha256:e84478bfbcfb4eb0accf290e7b158085cb0db7f679afade1a270f7e1e731a691" }, { "name": "usr/share/bash-completion/completions/swapon", "type": "reg", "size": 1523, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22325552, "NumLink": 0, "digest": "sha256:9eb769c80ce8bcffeb27b1b11129ee23e1ea534892df855357ce988862d30ca8" }, { "name": "usr/share/bash-completion/completions/tailf", "type": "reg", "size": 530, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22326307, "NumLink": 0, "digest": "sha256:217ff91e243a27ff18c0ce71505c35da7429950e5df9c8bda810e3cbd54e1395" }, { "name": "usr/share/bash-completion/completions/taskset", "type": "reg", "size": 1235, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22326689, "NumLink": 0, "digest": "sha256:f5d55cf1e4460be7e1121b9a7db533591994a9cb5138124903c19be05574be16" }, { "name": "usr/share/bash-completion/completions/tunelp", "type": "reg", "size": 1040, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22327418, "NumLink": 0, "digest": "sha256:249c5bbde4c34e5345986ddbad444ec4491a55eebb31135ea739fd750e7a8c58" }, { "name": "usr/share/bash-completion/completions/umount", "type": "reg", "size": 1469, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22327943, "NumLink": 0, "digest": "sha256:49047c62c6d9536c04be599640f37b81cf658dc6849180991e757a6c849cdbec" }, { "name": "usr/share/bash-completion/completions/unshare", "type": "reg", "size": 496, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22328723, "NumLink": 0, "digest": "sha256:bfd6b74257cd2802fc0b2fa02e890145870eb2dd83a47e929fd52d7a70f8b520" }, { "name": "usr/share/bash-completion/completions/utmpdump", "type": "reg", "size": 475, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22329092, "NumLink": 0, "digest": "sha256:69a8a5a630ce32790499b7690d033c7d73c40c861a5985ca23c4f1585fd69b48" }, { "name": "usr/share/bash-completion/completions/wall", "type": "reg", "size": 543, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22329467, "NumLink": 0, "digest": "sha256:4edebafffadbeefffad804423daf697de0ff2439b903fb203a1e9570169e1100" }, { "name": "usr/share/bash-completion/completions/wdctl", "type": "reg", "size": 1365, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22329859, "NumLink": 0, "digest": "sha256:6cc49f54ef1974fad909f827694f7bdc42e4ff9aed20bbd4dad265473f9e49db" }, { "name": "usr/share/bash-completion/completions/whereis", "type": "reg", "size": 535, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22330604, "NumLink": 0, "digest": "sha256:2a040afc44337e73ffcb2b910180aacf09566b784f887e82255a09cc42689d50" }, { "name": "usr/share/bash-completion/completions/wipefs", "type": "reg", "size": 690, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22330999, "NumLink": 0, "digest": "sha256:5479d455af2977d9d5bc9dc219e21c376abc63781eaaf6c0a5336bea82648f2f" }, { "name": "usr/share/bash-completion/completions/zramctl", "type": "reg", "size": 1213, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22331432, "NumLink": 0, "digest": "sha256:a8ca02df882804e93da5cc93f24d2125637d09e49abfcc850760569a0db31768" }, { "name": "usr/share/bug/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/bug/apt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/bug/apt/script", "type": "reg", "size": 886, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 22332138, "NumLink": 0, "digest": "sha256:b2cba592c2bd6e4077dd8b732d4895c22e77f555ed51540899b9a7bc908751bb" }, { "name": "usr/share/bug/init-system-helpers/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/bug/init-system-helpers/control", "type": "reg", "size": 24, "modtime": "2017-05-02T10:20:21Z", "mode": 33188, "offset": 22332689, "NumLink": 0, "digest": "sha256:c0306308b3e8655628cca8238616b8750ab7003201bdd68937a4739fe087ce5c" }, { "name": "usr/share/common-licenses/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/common-licenses/Apache-2.0", "type": "reg", "size": 11358, "modtime": "2004-12-19T20:30:25Z", "mode": 33188, "offset": 22332862, "NumLink": 0, "digest": "sha256:cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30" }, { "name": "usr/share/common-licenses/Artistic", "type": "reg", "size": 6111, "modtime": "1996-12-16T02:58:50Z", "mode": 33188, "offset": 22336884, "NumLink": 0, "digest": "sha256:b7fd9b73ea99602016a326e0b62e6646060d18febdd065ceca8bb482208c3d88" }, { "name": "usr/share/common-licenses/BSD", "type": "reg", "size": 1499, "modtime": "1999-08-26T12:06:20Z", "mode": 33188, "offset": 22339375, "NumLink": 0, "digest": "sha256:5d588eb3b157d52112afea935c88a7ff9efddc1e2d95a42c25d3b96ad9055008" }, { "name": "usr/share/common-licenses/GFDL", "type": "symlink", "modtime": "2018-06-26T12:03:08Z", "linkName": "GFDL-1.3", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/common-licenses/GFDL-1.2", "type": "reg", "size": 20431, "modtime": "2010-03-23T23:34:05Z", "mode": 33188, "offset": 22340330, "NumLink": 0, "digest": "sha256:56976e64523fa1e68db4e6f464f5b2cb89d7d08f54b1d012e317b8db286b3faf" }, { "name": "usr/share/common-licenses/GFDL-1.3", "type": "reg", "size": 22962, "modtime": "2008-11-03T16:47:07Z", "mode": 33188, "offset": 22347574, "NumLink": 0, "digest": "sha256:4748f03ed2dbcc14cde6ebc30799899c403e356a7465dc30fcf2b80c45fc0059" }, { "name": "usr/share/common-licenses/GPL", "type": "symlink", "modtime": "2018-06-26T12:03:08Z", "linkName": "GPL-3", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/common-licenses/GPL-1", "type": "reg", "size": 12632, "modtime": "2010-03-23T23:34:05Z", "mode": 33188, "offset": 22355724, "NumLink": 0, "digest": "sha256:d77d235e41d54594865151f4751e835c5a82322b0e87ace266567c3391a4b912" }, { "name": "usr/share/common-licenses/GPL-2", "type": "reg", "size": 18092, "modtime": "2010-03-23T23:34:05Z", "mode": 33188, "offset": 22360744, "NumLink": 0, "digest": "sha256:8177f97513213526df2cf6184d8ff986c675afb514d4e68a404010521b880643" }, { "name": "usr/share/common-licenses/GPL-3", "type": "reg", "size": 35147, "modtime": "2007-07-01T22:55:35Z", "mode": 33188, "offset": 22367652, "NumLink": 0, "digest": "sha256:8ceb4b9ee5adedde47b31e975c1d90c73ad27b6b165a1dcd80c7c545eb65b903" }, { "name": "usr/share/common-licenses/LGPL", "type": "symlink", "modtime": "2018-06-26T12:03:08Z", "linkName": "LGPL-3", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/common-licenses/LGPL-2", "type": "reg", "size": 25383, "modtime": "2010-03-25T17:29:55Z", "mode": 33188, "offset": 22379891, "NumLink": 0, "digest": "sha256:b7993225104d90ddd8024fd838faf300bea5e83d91203eab98e29512acebd69c" }, { "name": "usr/share/common-licenses/LGPL-2.1", "type": "reg", "size": 26530, "modtime": "2010-03-23T23:34:05Z", "mode": 33188, "offset": 22388991, "NumLink": 0, "digest": "sha256:dc626520dcd53a22f727af3ee42c770e56c97a64fe3adb063799d8ab032fe551" }, { "name": "usr/share/common-licenses/LGPL-3", "type": "reg", "size": 7651, "modtime": "2010-03-23T23:34:01Z", "mode": 33188, "offset": 22398425, "NumLink": 0, "digest": "sha256:da7eabb7bafdf7d3ae5e9f223aa5bdc1eece45ac569dc21b3b037520b4464768" }, { "name": "usr/share/common-licenses/MPL-1.1", "type": "reg", "size": 25755, "modtime": "2017-04-03T11:00:00Z", "mode": 33188, "offset": 22401124, "NumLink": 0, "digest": "sha256:f849fc26a7a99981611a3a370e83078deb617d12a45776d6c4cada4d338be469" }, { "name": "usr/share/common-licenses/MPL-2.0", "type": "reg", "size": 16726, "modtime": "2017-04-03T20:00:00Z", "mode": 33188, "offset": 22409547, "NumLink": 0, "digest": "sha256:fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85" }, { "name": "usr/share/debconf/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/debconf/confmodule", "type": "reg", "size": 2690, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22414952, "NumLink": 0, "digest": "sha256:640ca3222686c4d336a8a0b4721c5e54b0caba1a83e1e3409b137bea478e9a8b" }, { "name": "usr/share/debconf/confmodule.sh", "type": "reg", "size": 2875, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22416201, "NumLink": 0, "digest": "sha256:9bb739cea6c1f88c3282c6743a230acba64ac1d12c40a89daf12fe5f2390cb68" }, { "name": "usr/share/debconf/debconf.conf", "type": "reg", "size": 414, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22417708, "NumLink": 0, "digest": "sha256:2ed2f1e25211c95ae120cecfff540e33a533c03bb2793504c3d692b0b034c2dd" }, { "name": "usr/share/debconf/fix_db.pl", "type": "reg", "size": 2004, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 22417986, "NumLink": 0, "digest": "sha256:3023d816728349ffe6647f852722046631f1802737753f75517ebff0461473df" }, { "name": "usr/share/debconf/frontend", "type": "reg", "size": 2452, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 22418850, "NumLink": 0, "digest": "sha256:4425ec2e272875006ca7dde26d1c11b79a0a3570ececcd11f65baddd4b474ae0" }, { "name": "usr/share/debconf/transition_db.pl", "type": "reg", "size": 2404, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 22419970, "NumLink": 0, "digest": "sha256:9dbd7e5dcf314de4f1c1f15c46c69754f9c61c6be632b7c5a6efee08df0aa798" }, { "name": "usr/share/debianutils/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/debianutils/shells", "type": "reg", "size": 42, "modtime": "2011-10-09T00:49:46Z", "mode": 33188, "offset": 22420954, "NumLink": 0, "digest": "sha256:184fd1ac95af5ad460ee875e9fddb4975e8720ee7d805d964c68d125573537be" }, { "name": "usr/share/dict/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/adduser/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/adduser/copyright", "type": "reg", "size": 1995, "modtime": "2016-06-26T20:00:56Z", "mode": 33188, "offset": 22421163, "NumLink": 0, "digest": "sha256:3e67668ed552fe3a0684e77282325d07fa8847f2575ea1e1906000de571b5c1e" }, { "name": "usr/share/doc/apt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/apt/copyright", "type": "reg", "size": 1029, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 22422270, "NumLink": 0, "digest": "sha256:307e96c4b7e8170b422d86cfb04d9ae4a404e6d46755448331cdedb23cf1c3b0" }, { "name": "usr/share/doc/base-files/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/base-files/copyright", "type": "reg", "size": 1228, "modtime": "2018-06-26T12:03:08Z", "mode": 33188, "offset": 22422986, "NumLink": 0, "digest": "sha256:cdb5461d8515002d0fe3babb764eec3877458b20f4e4bb16219f62ea953afeea" }, { "name": "usr/share/doc/base-passwd/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/base-passwd/copyright", "type": "reg", "size": 799, "modtime": "2016-02-20T02:44:33Z", "mode": 33188, "offset": 22423766, "NumLink": 0, "digest": "sha256:c33ce99cd93b1e2f5c6067be725b73099e712afe8a4d8dffeb1659642afcd22d" }, { "name": "usr/share/doc/bash/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/bash/copyright", "type": "reg", "size": 10231, "modtime": "2014-03-03T21:46:18Z", "mode": 33188, "offset": 22424330, "NumLink": 0, "digest": "sha256:da7a8d93abf1eccdeaf326642c8ce9ed760f3a973ca46f3f69b3cf755bb81ade" }, { "name": "usr/share/doc/bsdutils/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/bsdutils/copyright", "type": "reg", "size": 17975, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22427545, "NumLink": 0, "digest": "sha256:b99c6679c1def231db02b5c30e3a552be6840021271f1e5c4cf5b7a639b0c08c" }, { "name": "usr/share/doc/coreutils/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/coreutils/copyright", "type": "reg", "size": 12531, "modtime": "2016-01-15T17:31:23Z", "mode": 33188, "offset": 22432395, "NumLink": 0, "digest": "sha256:350c1a60923248396acdf5aa3d20cdd5156e82648b3411bf9dff3a16b1ce9c7e" }, { "name": "usr/share/doc/dash/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/dash/copyright", "type": "reg", "size": 3101, "modtime": "2017-01-24T05:16:56Z", "mode": 33188, "offset": 22434945, "NumLink": 0, "digest": "sha256:7c77d28679de92b8aca0b3dd400eabac91bf9f6c68171e49355888d2593a968f" }, { "name": "usr/share/doc/debconf/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/debconf/copyright", "type": "reg", "size": 2648, "modtime": "2011-02-02T00:08:31Z", "mode": 33188, "offset": 22436654, "NumLink": 0, "digest": "sha256:5210ee02334b7cadcfe497df11a9d1ebd6e8e7de8a7fa44d15ac797b591eaac5" }, { "name": "usr/share/doc/debian-archive-keyring/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/debian-archive-keyring/copyright", "type": "reg", "size": 1243, "modtime": "2006-11-21T15:36:55Z", "mode": 33188, "offset": 22437912, "NumLink": 0, "digest": "sha256:b32aecaae84643700a33bc9ee83fa9b36938d35aa7b61b5042092eca77ddb732" }, { "name": "usr/share/doc/debianutils/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/debianutils/copyright", "type": "reg", "size": 8017, "modtime": "2009-05-06T01:07:50Z", "mode": 33188, "offset": 22438695, "NumLink": 0, "digest": "sha256:a8698f078cd21fc501e66d070e12cf2f23ec1eaf5841bbc87629de76858ef7a7" }, { "name": "usr/share/doc/diffutils/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/diffutils/copyright", "type": "reg", "size": 1839, "modtime": "2017-01-09T21:00:00Z", "mode": 33188, "offset": 22442319, "NumLink": 0, "digest": "sha256:6555a03a39adb6588f85a8aac4ea9f3f1cfdf93ac921ffbbc806215f77166b07" }, { "name": "usr/share/doc/dpkg/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/dpkg/copyright", "type": "reg", "size": 7882, "modtime": "2018-03-22T04:29:34Z", "mode": 33188, "offset": 22443295, "NumLink": 0, "digest": "sha256:1a87ca75439f4e5be763913b21e9d23476b7e5c37814b9a0500c819e437f9b8f" }, { "name": "usr/share/doc/e2fslibs/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/e2fslibs/copyright", "type": "reg", "size": 3594, "modtime": "2016-09-02T04:17:32Z", "mode": 33188, "offset": 22446456, "NumLink": 0, "digest": "sha256:b7b391571e7253d4cf607e33e3b463895768fad264471e7774882974f834faa1" }, { "name": "usr/share/doc/e2fsprogs/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/e2fsprogs/copyright", "type": "reg", "size": 3594, "modtime": "2016-09-02T04:17:32Z", "mode": 33188, "offset": 22448282, "NumLink": 0, "digest": "sha256:b7b391571e7253d4cf607e33e3b463895768fad264471e7774882974f834faa1" }, { "name": "usr/share/doc/findutils/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/findutils/copyright", "type": "reg", "size": 3089, "modtime": "2016-07-04T11:21:09Z", "mode": 33188, "offset": 22450112, "NumLink": 0, "digest": "sha256:7b056c63abe117298b7b8fd193f96f0a324a87c1f70fa38f5d1c750abf0314fd" }, { "name": "usr/share/doc/gcc-6-base/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/gcc-6-base/copyright", "type": "reg", "size": 30116, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 22451638, "NumLink": 0, "digest": "sha256:360fb8c50734b43dea21842b5e32a97e4b0d247530b7250a86e8057af33c1bc6" }, { "name": "usr/share/doc/gpgv/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/gpgv/copyright", "type": "reg", "size": 9804, "modtime": "2018-06-08T18:12:24Z", "mode": 33188, "offset": 22460146, "NumLink": 0, "digest": "sha256:b6003da5877b0d74ed5b82690d2d79129985a9eda068fc8913ba7cbdc0950263" }, { "name": "usr/share/doc/grep/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/grep/copyright", "type": "reg", "size": 1806, "modtime": "2016-11-28T21:59:51Z", "mode": 33188, "offset": 22463372, "NumLink": 0, "digest": "sha256:11638f295e8713bb780508b539e094aa9e82ae3cca8545163be3e64aec65a8e5" }, { "name": "usr/share/doc/gzip/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/gzip/copyright", "type": "reg", "size": 1112, "modtime": "2016-03-14T20:41:45Z", "mode": 33188, "offset": 22464469, "NumLink": 0, "digest": "sha256:f9ac4a5d7a670e3891881a2cdba5fa2cd625c4d58eae4a7aa372ac00a06803bd" }, { "name": "usr/share/doc/hostname/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/hostname/copyright", "type": "reg", "size": 1146, "modtime": "2013-09-06T10:04:07Z", "mode": 33188, "offset": 22465241, "NumLink": 0, "digest": "sha256:272c5b1c9235edc311f202b2a6abfff24ba96a47c779b4db3b97c2e60eb3e81a" }, { "name": "usr/share/doc/init-system-helpers/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/init-system-helpers/copyright", "type": "reg", "size": 3014, "modtime": "2017-05-02T10:20:21Z", "mode": 33188, "offset": 22465990, "NumLink": 0, "digest": "sha256:a3ee9fffdc037227ad9461b61700323bb07e3e4be81d9da5c068ad09232e5fa5" }, { "name": "usr/share/doc/libacl1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libacl1/copyright", "type": "reg", "size": 761, "modtime": "2009-08-25T00:37:49Z", "mode": 33188, "offset": 22467575, "NumLink": 0, "digest": "sha256:26522b0fba5e435a1afcd0e3482d0aaab245d60f00b3d5b777c31457c740756b" }, { "name": "usr/share/doc/libapt-pkg5.0/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libapt-pkg5.0/copyright", "type": "reg", "size": 1029, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 22468117, "NumLink": 0, "digest": "sha256:307e96c4b7e8170b422d86cfb04d9ae4a404e6d46755448331cdedb23cf1c3b0" }, { "name": "usr/share/doc/libattr1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libattr1/copyright", "type": "reg", "size": 789, "modtime": "2009-08-26T01:32:06Z", "mode": 33188, "offset": 22468833, "NumLink": 0, "digest": "sha256:2c18722769cd1f0494668b8118ba8c9c785be759d34a85d0b1c9dd2d89f87328" }, { "name": "usr/share/doc/libaudit-common/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libaudit-common/copyright", "type": "reg", "size": 1588, "modtime": "2017-04-12T16:17:21Z", "mode": 33188, "offset": 22469382, "NumLink": 0, "digest": "sha256:0c90284161619a0ccd817b467be8b225d5e52ca76ed151073c4d1e8f7fe25dd7" }, { "name": "usr/share/doc/libaudit1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libaudit1/copyright", "type": "reg", "size": 1588, "modtime": "2017-04-12T16:17:21Z", "mode": 33188, "offset": 22470319, "NumLink": 0, "digest": "sha256:0c90284161619a0ccd817b467be8b225d5e52ca76ed151073c4d1e8f7fe25dd7" }, { "name": "usr/share/doc/libblkid1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libblkid1/copyright", "type": "reg", "size": 17975, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22471259, "NumLink": 0, "digest": "sha256:b99c6679c1def231db02b5c30e3a552be6840021271f1e5c4cf5b7a639b0c08c" }, { "name": "usr/share/doc/libbz2-1.0/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libbz2-1.0/copyright", "type": "reg", "size": 2499, "modtime": "2017-01-29T18:30:31Z", "mode": 33188, "offset": 22476110, "NumLink": 0, "digest": "sha256:8d2269223e3162f7253432d7790060fe0ce16b73b12700778cde19fccb776fed" }, { "name": "usr/share/doc/libc-bin/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libc-bin/copyright", "type": "reg", "size": 25465, "modtime": "2018-01-14T10:39:16Z", "mode": 33188, "offset": 22477540, "NumLink": 0, "digest": "sha256:a09cfc6ecf8fcd835ba851a1c95b256e01420982ac7acdd01fcfaa748c402f11" }, { "name": "usr/share/doc/libc6/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libc6/copyright", "type": "reg", "size": 25465, "modtime": "2018-01-14T10:39:16Z", "mode": 33188, "offset": 22483797, "NumLink": 0, "digest": "sha256:a09cfc6ecf8fcd835ba851a1c95b256e01420982ac7acdd01fcfaa748c402f11" }, { "name": "usr/share/doc/libcap-ng0/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libcap-ng0/copyright", "type": "reg", "size": 1407, "modtime": "2015-03-25T17:03:55Z", "mode": 33188, "offset": 22490056, "NumLink": 0, "digest": "sha256:8cdc2d0eeeb4ed84963c58be27389b148e830ce5ec42c2598cf194721d0430ec" }, { "name": "usr/share/doc/libcomerr2/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libcomerr2/copyright", "type": "reg", "size": 1154, "modtime": "2009-08-13T01:39:57Z", "mode": 33188, "offset": 22490926, "NumLink": 0, "digest": "sha256:9e3a4384b6d8d2358d44103f62bcd948328b3f8a63a1a6baa66abeb43302d581" }, { "name": "usr/share/doc/libdb5.3/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libdb5.3/copyright", "type": "reg", "size": 7517, "modtime": "2017-09-24T07:14:53Z", "mode": 33188, "offset": 22491689, "NumLink": 0, "digest": "sha256:b3bbc6fbb3f2a0e6a487e953eb8c3cc4bdb6f4150f7f51d20b1e9a3c8ef92d3d" }, { "name": "usr/share/doc/libdebconfclient0/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libdebconfclient0/copyright", "type": "reg", "size": 1978, "modtime": "2011-07-05T01:00:24Z", "mode": 33188, "offset": 22493616, "NumLink": 0, "digest": "sha256:1f48252e8bd71085c67fe1f5468c67da1d2d7cc34cd8a7e9d90b9ad2df080e8e" }, { "name": "usr/share/doc/libfdisk1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libfdisk1/copyright", "type": "reg", "size": 17975, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22494822, "NumLink": 0, "digest": "sha256:b99c6679c1def231db02b5c30e3a552be6840021271f1e5c4cf5b7a639b0c08c" }, { "name": "usr/share/doc/libgcc1", "type": "symlink", "modtime": "2018-02-14T16:53:20Z", "linkName": "gcc-6-base", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/doc/libgcrypt20/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libgcrypt20/copyright", "type": "reg", "size": 14374, "modtime": "2018-06-15T09:58:05Z", "mode": 33188, "offset": 22499714, "NumLink": 0, "digest": "sha256:f8f5c4ea63d81b94e29754072a6cc2fa30cc1656a9d16e0761946c9a8a594a72" }, { "name": "usr/share/doc/libgpg-error0/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libgpg-error0/copyright", "type": "reg", "size": 1154, "modtime": "2017-01-18T16:22:13Z", "mode": 33188, "offset": 22505795, "NumLink": 0, "digest": "sha256:25806fa5ca76e47d4868beb59064475397ed841f15584dd9782dbd3228ff99db" }, { "name": "usr/share/doc/liblz4-1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/liblz4-1/copyright", "type": "reg", "size": 3092, "modtime": "2016-02-17T15:27:54Z", "mode": 33188, "offset": 22506575, "NumLink": 0, "digest": "sha256:18abf872210b2e1640d078bd84dc3adc34086f964346d71b6002b80b03860730" }, { "name": "usr/share/doc/liblzma5/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/liblzma5/copyright", "type": "reg", "size": 15308, "modtime": "2016-10-08T13:01:46Z", "mode": 33188, "offset": 22508084, "NumLink": 0, "digest": "sha256:36109804b8e69c5344232598a4f064da4465683b9461662085be7d8fca29b35a" }, { "name": "usr/share/doc/libmount1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libmount1/copyright", "type": "reg", "size": 17975, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22513112, "NumLink": 0, "digest": "sha256:b99c6679c1def231db02b5c30e3a552be6840021271f1e5c4cf5b7a639b0c08c" }, { "name": "usr/share/doc/libncursesw5", "type": "symlink", "modtime": "2017-12-28T09:47:33Z", "linkName": "libtinfo5", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/doc/libpam-modules/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libpam-modules/copyright", "type": "reg", "size": 3176, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22518010, "NumLink": 0, "digest": "sha256:7c584b7b1f37b612da7fdf3b076eb2b2c1bae72865f0699d745ae2ac7d40d13e" }, { "name": "usr/share/doc/libpam-modules-bin/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libpam-modules-bin/copyright", "type": "reg", "size": 3176, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22519765, "NumLink": 0, "digest": "sha256:7c584b7b1f37b612da7fdf3b076eb2b2c1bae72865f0699d745ae2ac7d40d13e" }, { "name": "usr/share/doc/libpam-runtime/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libpam-runtime/copyright", "type": "reg", "size": 3176, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22521517, "NumLink": 0, "digest": "sha256:7c584b7b1f37b612da7fdf3b076eb2b2c1bae72865f0699d745ae2ac7d40d13e" }, { "name": "usr/share/doc/libpam0g/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libpam0g/copyright", "type": "reg", "size": 3176, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22523264, "NumLink": 0, "digest": "sha256:7c584b7b1f37b612da7fdf3b076eb2b2c1bae72865f0699d745ae2ac7d40d13e" }, { "name": "usr/share/doc/libpcre3/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libpcre3/copyright", "type": "reg", "size": 2765, "modtime": "2015-03-07T18:28:32Z", "mode": 33188, "offset": 22525011, "NumLink": 0, "digest": "sha256:ac9276490d2fa167442ae1aae33926514ad10c8886baa40046c5e367fccc5938" }, { "name": "usr/share/doc/libselinux1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libselinux1/copyright", "type": "reg", "size": 3129, "modtime": "2016-11-06T17:22:28Z", "mode": 33188, "offset": 22526540, "NumLink": 0, "digest": "sha256:514ea9dc715249906df09333d9a7583b9251fc7c3c265602b53066e564fdfcdc" }, { "name": "usr/share/doc/libsemanage-common/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libsemanage-common/copyright", "type": "reg", "size": 1828, "modtime": "2016-12-30T15:42:09Z", "mode": 33188, "offset": 22528038, "NumLink": 0, "digest": "sha256:1ca1d72a22e1f1d16c2d805c823723df6b8bc7c1407e5e1e5d2bdca7ff222ae9" }, { "name": "usr/share/doc/libsemanage1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libsemanage1/copyright", "type": "reg", "size": 1828, "modtime": "2016-12-30T15:42:09Z", "mode": 33188, "offset": 22529020, "NumLink": 0, "digest": "sha256:1ca1d72a22e1f1d16c2d805c823723df6b8bc7c1407e5e1e5d2bdca7ff222ae9" }, { "name": "usr/share/doc/libsepol1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libsepol1/copyright", "type": "reg", "size": 2071, "modtime": "2016-12-03T23:19:56Z", "mode": 33188, "offset": 22530004, "NumLink": 0, "digest": "sha256:bd7d13a1f53de96562c3240d9189705ebbca107d860e9b811780ef9472a21ce7" }, { "name": "usr/share/doc/libsmartcols1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libsmartcols1/copyright", "type": "reg", "size": 17975, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22531126, "NumLink": 0, "digest": "sha256:b99c6679c1def231db02b5c30e3a552be6840021271f1e5c4cf5b7a639b0c08c" }, { "name": "usr/share/doc/libss2/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libss2/copyright", "type": "reg", "size": 1163, "modtime": "2016-09-02T04:17:32Z", "mode": 33188, "offset": 22535973, "NumLink": 0, "digest": "sha256:6f717a1464301a641ac17e7301f1a1b221da802e8edf8cf4bc963721d487b146" }, { "name": "usr/share/doc/libstdc++6", "type": "symlink", "modtime": "2018-02-14T16:53:20Z", "linkName": "gcc-6-base", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/doc/libsystemd0/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libsystemd0/copyright", "type": "reg", "size": 7776, "modtime": "2018-06-13T20:20:36Z", "mode": 33188, "offset": 22536790, "NumLink": 0, "digest": "sha256:75f342d2dda6c3e10591b8dbccc4a1d4868f026d27a2afd5ed4565971f533b7f" }, { "name": "usr/share/doc/libtinfo5/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libtinfo5/copyright", "type": "reg", "size": 6366, "modtime": "2017-12-28T09:32:23Z", "mode": 33188, "offset": 22539591, "NumLink": 0, "digest": "sha256:b7606456c4e97c19c54c67c1887a705b4d44e5121c48c851b256aeb65e518a4c" }, { "name": "usr/share/doc/libudev1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libudev1/copyright", "type": "reg", "size": 7776, "modtime": "2018-06-13T20:20:36Z", "mode": 33188, "offset": 22541844, "NumLink": 0, "digest": "sha256:75f342d2dda6c3e10591b8dbccc4a1d4868f026d27a2afd5ed4565971f533b7f" }, { "name": "usr/share/doc/libustr-1.0-1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libustr-1.0-1/copyright", "type": "reg", "size": 5072, "modtime": "2016-11-17T13:42:55Z", "mode": 33188, "offset": 22544645, "NumLink": 0, "digest": "sha256:41c7b465fec47217af1aba6e39525ff8e4ed904f22e8a10175a314b11f8a34b8" }, { "name": "usr/share/doc/libuuid1/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/libuuid1/copyright", "type": "reg", "size": 17975, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22546818, "NumLink": 0, "digest": "sha256:b99c6679c1def231db02b5c30e3a552be6840021271f1e5c4cf5b7a639b0c08c" }, { "name": "usr/share/doc/login/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/login/copyright", "type": "reg", "size": 5153, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 22551664, "NumLink": 0, "digest": "sha256:56ca9c00cdef4d69b35d2013465c539eb9e09a80fec538d0f6dc91423dbaa1d3" }, { "name": "usr/share/doc/lsb-base/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/lsb-base/copyright", "type": "reg", "size": 2648, "modtime": "2014-05-27T14:13:24Z", "mode": 33188, "offset": 22554262, "NumLink": 0, "digest": "sha256:0e9ed2924c559a5fd2fd5e32f59885baee291b46dcff09c90fbc12c7aeb61c10" }, { "name": "usr/share/doc/mawk/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/mawk/copyright", "type": "reg", "size": 1298, "modtime": "2012-03-23T20:15:00Z", "mode": 33188, "offset": 22555721, "NumLink": 0, "digest": "sha256:80910bdabaf183ae4d3ffd72d9fe9066a9a1035be8e5d7dd541ddc6755d19abb" }, { "name": "usr/share/doc/mount/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/mount/copyright", "type": "reg", "size": 17975, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22556577, "NumLink": 0, "digest": "sha256:b99c6679c1def231db02b5c30e3a552be6840021271f1e5c4cf5b7a639b0c08c" }, { "name": "usr/share/doc/multiarch-support/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/multiarch-support/copyright", "type": "reg", "size": 25465, "modtime": "2018-01-14T10:39:16Z", "mode": 33188, "offset": 22561433, "NumLink": 0, "digest": "sha256:a09cfc6ecf8fcd835ba851a1c95b256e01420982ac7acdd01fcfaa748c402f11" }, { "name": "usr/share/doc/ncurses-base/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/ncurses-base/copyright", "type": "reg", "size": 6366, "modtime": "2017-12-28T09:32:23Z", "mode": 33188, "offset": 22567694, "NumLink": 0, "digest": "sha256:b7606456c4e97c19c54c67c1887a705b4d44e5121c48c851b256aeb65e518a4c" }, { "name": "usr/share/doc/ncurses-bin/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/ncurses-bin/copyright", "type": "reg", "size": 6366, "modtime": "2017-12-28T09:32:23Z", "mode": 33188, "offset": 22569948, "NumLink": 0, "digest": "sha256:b7606456c4e97c19c54c67c1887a705b4d44e5121c48c851b256aeb65e518a4c" }, { "name": "usr/share/doc/passwd/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/passwd/copyright", "type": "reg", "size": 5153, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 22572201, "NumLink": 0, "digest": "sha256:56ca9c00cdef4d69b35d2013465c539eb9e09a80fec538d0f6dc91423dbaa1d3" }, { "name": "usr/share/doc/perl/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/perl/copyright", "type": "reg", "size": 104049, "modtime": "2018-06-10T17:35:32Z", "mode": 33188, "offset": 22574795, "NumLink": 0, "digest": "sha256:84302bc1e1c76708a293f348a0b2b9a0eee86eac9cc065bb73b4a28318c6fd9b" }, { "name": "usr/share/doc/perl-base", "type": "symlink", "modtime": "2018-06-10T17:37:28Z", "linkName": "perl", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/doc/sed/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/sed/copyright", "type": "reg", "size": 849, "modtime": "2017-01-05T01:31:41Z", "mode": 33188, "offset": 22598004, "NumLink": 0, "digest": "sha256:60886b6264e9531565ccf1e31a63cd9b23f0bf4bbd7053b46aa9e6ae7622d31d" }, { "name": "usr/share/doc/sensible-utils/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/sensible-utils/copyright", "type": "reg", "size": 694, "modtime": "2017-12-20T13:39:04Z", "mode": 33188, "offset": 22598598, "NumLink": 0, "digest": "sha256:5c58dcf1d8debb43fcec08ae0cbf2f049aa5d48c567147046db48e42c2f706ac" }, { "name": "usr/share/doc/sysvinit-utils/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/sysvinit-utils/copyright", "type": "reg", "size": 2199, "modtime": "2017-02-12T21:55:39Z", "mode": 33188, "offset": 22599093, "NumLink": 0, "digest": "sha256:7778a27498a3909c855d6b3ccec28dc16c67ca5d5aaba6660842cd333ffe188d" }, { "name": "usr/share/doc/tar/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/tar/copyright", "type": "reg", "size": 1486, "modtime": "2016-10-30T06:35:31Z", "mode": 33188, "offset": 22600344, "NumLink": 0, "digest": "sha256:9292780f2dfd11900e92ea67c7a316cf9df740b955956f87ec099a5b4f3d9136" }, { "name": "usr/share/doc/tzdata/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/tzdata/copyright", "type": "reg", "size": 307, "modtime": "2018-05-04T18:20:29Z", "mode": 33188, "offset": 22601083, "NumLink": 0, "digest": "sha256:2b81a12912f0ea7b6c928bc57c950234a13bfeb690611bfd81b5c329b914cd8b" }, { "name": "usr/share/doc/util-linux/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/util-linux/copyright", "type": "reg", "size": 17975, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 22601449, "NumLink": 0, "digest": "sha256:b99c6679c1def231db02b5c30e3a552be6840021271f1e5c4cf5b7a639b0c08c" }, { "name": "usr/share/doc/zlib1g/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc/zlib1g/copyright", "type": "reg", "size": 1606, "modtime": "2013-05-03T15:30:15Z", "mode": 33188, "offset": 22606295, "NumLink": 0, "digest": "sha256:bcf07f8f2414e28405b35fee95fb14569e926a7d4e99cc4a5db2fe1a0d1aca56" }, { "name": "usr/share/doc-base/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/doc-base/findutils", "type": "reg", "size": 323, "modtime": "2014-04-13T14:12:32Z", "mode": 33188, "offset": 22607266, "NumLink": 0, "digest": "sha256:83026123456c2f7c1cc44196701180752a65423ade28344ef277cf577b12faa6" }, { "name": "usr/share/doc-base/users-and-groups", "type": "reg", "size": 423, "modtime": "2016-02-20T02:44:33Z", "mode": 33188, "offset": 22607568, "NumLink": 0, "digest": "sha256:159902a0284dbbcc039824ebab914948f8a803280fa2b67742b8f7fd40c50250" }, { "name": "usr/share/dpkg/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/dpkg/abitable", "type": "reg", "size": 362, "modtime": "2018-06-26T10:28:08Z", "mode": 33188, "offset": 22607923, "NumLink": 0, "digest": "sha256:c9ed655f391a2dffdfee2070e9c4bd1f502ffff17d19abff21ba492ab643c919" }, { "name": "usr/share/dpkg/cputable", "type": "reg", "size": 1971, "modtime": "2018-06-26T10:28:08Z", "mode": 33188, "offset": 22608231, "NumLink": 0, "digest": "sha256:88d770b7e95d793c6250285c4d901365487c44e460a8ebdd4895685f7613d104" }, { "name": "usr/share/dpkg/ostable", "type": "reg", "size": 2000, "modtime": "2018-06-26T10:28:08Z", "mode": 33188, "offset": 22609080, "NumLink": 0, "digest": "sha256:49b8a094236fd9f06463afab94d49956cf6fba363ec14d75da6ae3310214ca42" }, { "name": "usr/share/dpkg/tupletable", "type": "reg", "size": 1361, "modtime": "2018-06-26T10:28:08Z", "mode": 33188, "offset": 22609851, "NumLink": 0, "digest": "sha256:d8311834400bd4c74bcdc764968d13c44b5ac8745a9d06068c2209c51401b826" }, { "name": "usr/share/gcc-6/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/gcc-6/python/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/gcc-6/python/libstdcxx/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/gcc-6/python/libstdcxx/__init__.py", "type": "reg", "size": 1, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 22610429, "NumLink": 0, "digest": "sha256:01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b" }, { "name": "usr/share/gcc-6/python/libstdcxx/v6/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/gcc-6/python/libstdcxx/v6/__init__.py", "type": "reg", "size": 1161, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 22610594, "NumLink": 0, "digest": "sha256:78a3a4acc2b1b08db8f766d251b6f4d009e84663022dfee9ce2c66efd54bcb77" }, { "name": "usr/share/gcc-6/python/libstdcxx/v6/printers.py", "type": "reg", "size": 55953, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 22611282, "NumLink": 0, "digest": "sha256:8d290e0fd40318fcbaf0dae5a8e17a45a94be40b6c0285a75fdd3f30b412e65b" }, { "name": "usr/share/gcc-6/python/libstdcxx/v6/xmethods.py", "type": "reg", "size": 26822, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 22622344, "NumLink": 0, "digest": "sha256:ea30e5690abecb7808b4cb9dbe36afc3922cde4f982b5f64e1888a339880b1c9" }, { "name": "usr/share/gdb/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/gdb/auto-load/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/gdb/auto-load/usr/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/gdb/auto-load/usr/lib/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/gdb/auto-load/usr/lib/x86_64-linux-gnu/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/gdb/auto-load/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22-gdb.py", "type": "reg", "size": 2389, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 22626081, "NumLink": 0, "digest": "sha256:6957a1cadd8485b585a3821f167b8867893b5fc4ce7639c4b843901746858cdd" }, { "name": "usr/share/info/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/keyrings/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/keyrings/debian-archive-keyring.gpg", "type": "reg", "size": 36941, "modtime": "2017-05-25T18:17:13Z", "mode": 33188, "offset": 22627405, "NumLink": 0, "digest": "sha256:350902b7289c1db8ffc28749772723a195dcd5ee42bbc43d2f57e59d5b06b08f" }, { "name": "usr/share/keyrings/debian-archive-removed-keys.gpg", "type": "reg", "size": 17538, "modtime": "2017-05-25T18:17:13Z", "mode": 33188, "offset": 22662459, "NumLink": 0, "digest": "sha256:ac8b1500ec8cd69c437ff1b23a2b47f60cc740573cdae02a42abe342890faa09" }, { "name": "usr/share/libc-bin/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/libc-bin/nsswitch.conf", "type": "reg", "size": 497, "modtime": "2017-12-31T12:12:42Z", "mode": 33188, "offset": 22678696, "NumLink": 0, "digest": "sha256:e241e67d7b5c15a5ace818d89277507b5ded8b49688b7a4431afb3b1041a3759" }, { "name": "usr/share/lintian/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/lintian/overrides/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/locale/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/man/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/menu/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/menu/bash", "type": "reg", "size": 194, "modtime": "2013-10-23T12:41:22Z", "mode": 33188, "offset": 22679157, "NumLink": 0, "digest": "sha256:1e862c7883df7a31e995769e90b4e6b87399a70f2cad6b2ce95fd865975286aa" }, { "name": "usr/share/menu/dash", "type": "reg", "size": 108, "modtime": "2017-01-24T05:16:56Z", "mode": 33188, "offset": 22679353, "NumLink": 0, "digest": "sha256:c8bdff923cdb32fc55c80c70546c344e22444dfdccdea6280d9c4c6fa25c7c38" }, { "name": "usr/share/misc/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/pam/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/pam/common-account", "type": "reg", "size": 1175, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22679605, "NumLink": 0, "digest": "sha256:8657819f898333b2ff09e8bb4fcc6ffabb02acd015411d0ec89f28a70e672537" }, { "name": "usr/share/pam/common-account.md5sums", "type": "reg", "size": 107, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22680317, "NumLink": 0, "digest": "sha256:8e2e9985399c29f44638f97acc1b71f9b2b946cfedb21ead16a54cd12c25992a" }, { "name": "usr/share/pam/common-auth", "type": "reg", "size": 1194, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22680502, "NumLink": 0, "digest": "sha256:940827d13f472a45ebd38cca4c4b2f91b7fc22f08a266a9e987222e88df4cc9b" }, { "name": "usr/share/pam/common-auth.md5sums", "type": "reg", "size": 159, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22681223, "NumLink": 0, "digest": "sha256:9dfd7b4897f508b7e327e7a511c7d097551d7063145b411e266aa91f2c0c1d57" }, { "name": "usr/share/pam/common-password", "type": "reg", "size": 1416, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22681432, "NumLink": 0, "digest": "sha256:fa54ac2f7b8f18c22c1a73dc63d471bfd2694686686fd244d02cd774772dc911" }, { "name": "usr/share/pam/common-password.md5sums", "type": "reg", "size": 357, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22682250, "NumLink": 0, "digest": "sha256:5f44a9db909d4ec8cc580261a4674f9a609ad5e7a776a7896087b738e9581b38" }, { "name": "usr/share/pam/common-session", "type": "reg", "size": 1127, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22682543, "NumLink": 0, "digest": "sha256:b1413e5c9105ebdaec6be4eee00535552331a09c5f6206006e8c280374b5a2df" }, { "name": "usr/share/pam/common-session-noninteractive", "type": "reg", "size": 1139, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22683232, "NumLink": 0, "digest": "sha256:7ac763203bc998dde4c1ddbdf0c572be2afa61e3f59d82194a51f7b3a5d11f7f" }, { "name": "usr/share/pam/common-session-noninteractive.md5sums", "type": "reg", "size": 46, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22683911, "NumLink": 0, "digest": "sha256:c4e029edf22d18a793db84b3092d36b88ddfacc5e361b785364e4756755b10e1" }, { "name": "usr/share/pam/common-session.md5sums", "type": "reg", "size": 174, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22684065, "NumLink": 0, "digest": "sha256:b80d0e21fd90493886ba1dd4a4fbacf283e6ffc07815469a0ccb130f2e5d156b" }, { "name": "usr/share/pam-configs/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/pam-configs/unix", "type": "reg", "size": 682, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 22684316, "NumLink": 0, "digest": "sha256:5b434421d10875a53932e967eddc9b885ea42bd9f1360600af04248e8d42be74" }, { "name": "usr/share/perl5/", "type": "dir", "modtime": "2017-05-21T17:08:30Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/AutoSelect.pm", "type": "reg", "size": 1833, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22684716, "NumLink": 0, "digest": "sha256:05d14126837c8b32b3f6a96c204d0946521827cfe7629e6f6060f698ab6788e3" }, { "name": "usr/share/perl5/Debconf/Base.pm", "type": "reg", "size": 499, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22685564, "NumLink": 0, "digest": "sha256:66ddc0f2cb2cae1e92bce9f5ae48cc82aea652a9ade8ab86cf9a1a3093e1f3e1" }, { "name": "usr/share/perl5/Debconf/Client/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/Client/ConfModule.pm", "type": "reg", "size": 3900, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22686015, "NumLink": 0, "digest": "sha256:7d1b308c40b249d160ca49488f5ef1658db695940b53c7bf83bc89f49640b066" }, { "name": "usr/share/perl5/Debconf/ConfModule.pm", "type": "reg", "size": 15639, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22688084, "NumLink": 0, "digest": "sha256:387c6f3a403d3e4cd862b3e68450ab014be1b3b7b6c5824e09ad2f590aae2314" }, { "name": "usr/share/perl5/Debconf/Config.pm", "type": "reg", "size": 7020, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22691708, "NumLink": 0, "digest": "sha256:cd8de0d581b2ef08ff3deddd060fed52e4a914ddc0b59d46e3af617ee4961d1d" }, { "name": "usr/share/perl5/Debconf/Db.pm", "type": "reg", "size": 1202, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22694150, "NumLink": 0, "digest": "sha256:c0e7a554455e3cf9c42d937bbc8a701627b43f048cbf7a1d7590af44f218338f" }, { "name": "usr/share/perl5/Debconf/DbDriver/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/DbDriver/Backup.pm", "type": "reg", "size": 1638, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22694834, "NumLink": 0, "digest": "sha256:0dd39de90e426e2062483ea468348aef62ecbdfb76fb1292728f3679a42b9dfd" }, { "name": "usr/share/perl5/Debconf/DbDriver/Cache.pm", "type": "reg", "size": 4825, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22695517, "NumLink": 0, "digest": "sha256:7075a4f322db7e12d96e2391267073cf11a01277ed972b8fd5285c8b3b89e272" }, { "name": "usr/share/perl5/Debconf/DbDriver/Copy.pm", "type": "reg", "size": 950, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22696546, "NumLink": 0, "digest": "sha256:d79bf94498c68355489fdd90c09d7aaa62116e42f0845ae78ba2c3b45fef9859" }, { "name": "usr/share/perl5/Debconf/DbDriver/Debug.pm", "type": "reg", "size": 950, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22697054, "NumLink": 0, "digest": "sha256:feb9793dbf296b01cc866c0bb792843e711f2126a2ed4171f4a1f2561da76cb8" }, { "name": "usr/share/perl5/Debconf/DbDriver/DirTree.pm", "type": "reg", "size": 1990, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22697621, "NumLink": 0, "digest": "sha256:57aba77c08bd3c0106b9d21c1c177984e20a477c2528b85b13ef1345b20af677" }, { "name": "usr/share/perl5/Debconf/DbDriver/Directory.pm", "type": "reg", "size": 3609, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22698531, "NumLink": 0, "digest": "sha256:ecf618cb2a38996f131f775e72084062b9c942c274133f7adb50ab8c36ef598f" }, { "name": "usr/share/perl5/Debconf/DbDriver/File.pm", "type": "reg", "size": 3633, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22699802, "NumLink": 0, "digest": "sha256:18906996142065a6c897392a366934054c821d08f34acacb645724da5f6235d5" }, { "name": "usr/share/perl5/Debconf/DbDriver/LDAP.pm", "type": "reg", "size": 6226, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22701131, "NumLink": 0, "digest": "sha256:633a36005440e5101b822a293751d63e0574787fe2b13157aacc2bc00fb0ef02" }, { "name": "usr/share/perl5/Debconf/DbDriver/PackageDir.pm", "type": "reg", "size": 3671, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22703234, "NumLink": 0, "digest": "sha256:081953795cd5ffbfc2b56cdc1e24c59f76be1fd7664ceaaee6688a55f12c1a3e" }, { "name": "usr/share/perl5/Debconf/DbDriver/Pipe.pm", "type": "reg", "size": 1783, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22704553, "NumLink": 0, "digest": "sha256:b50341f54a9e86d13c0fc1b607466df39f8db062f226b22123a97d73b1d73063" }, { "name": "usr/share/perl5/Debconf/DbDriver/Stack.pm", "type": "reg", "size": 5256, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22705362, "NumLink": 0, "digest": "sha256:f55d0e3f3f4f3ad8910ca1db54838eea67ee5b4fd4efdfa668e4fb23b432f6b9" }, { "name": "usr/share/perl5/Debconf/DbDriver.pm", "type": "reg", "size": 2359, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22706941, "NumLink": 0, "digest": "sha256:7ce0f564262a8d5dcdc1027951b080af151669b1841ac88cf6db54f9f5dcacab" }, { "name": "usr/share/perl5/Debconf/Element/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/Element/Dialog/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/Element/Dialog/Boolean.pm", "type": "reg", "size": 729, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22707971, "NumLink": 0, "digest": "sha256:81d60ef5716baeedcd3ec9ed5d59d8d310d6a187d7c902133770fa201604cfa5" }, { "name": "usr/share/perl5/Debconf/Element/Dialog/Error.pm", "type": "reg", "size": 331, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22708430, "NumLink": 0, "digest": "sha256:94044eacc5f6137204dc1c805e9323d8ee370163e21e16485961c073bd244c16" }, { "name": "usr/share/perl5/Debconf/Element/Dialog/Multiselect.pm", "type": "reg", "size": 1832, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22708761, "NumLink": 0, "digest": "sha256:6731d2d9fec3870ff1bece763a60b97666dc9401a52ca5abac9a5c981b607e3b" }, { "name": "usr/share/perl5/Debconf/Element/Dialog/Note.pm", "type": "reg", "size": 330, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22709571, "NumLink": 0, "digest": "sha256:768e0c2ebfbc4e9227ce359f38b2469e070135c56adba1ec7f5b7505e8ec87e6" }, { "name": "usr/share/perl5/Debconf/Element/Dialog/Password.pm", "type": "reg", "size": 690, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22709902, "NumLink": 0, "digest": "sha256:0f795cb55435e9660233584f899e769e263d1e605e9748860b5edb02ffad3aae" }, { "name": "usr/share/perl5/Debconf/Element/Dialog/Progress.pm", "type": "reg", "size": 1846, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22710363, "NumLink": 0, "digest": "sha256:abe844eae752340e23f9f21ddcb6b24764f0eb980471c25f5158c452cfce961d" }, { "name": "usr/share/perl5/Debconf/Element/Dialog/Select.pm", "type": "reg", "size": 1350, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22711099, "NumLink": 0, "digest": "sha256:53b327be9f1f04b236b0b5baa15b3ec041f56cf9b6f6f98cad37860a495d81bb" }, { "name": "usr/share/perl5/Debconf/Element/Dialog/String.pm", "type": "reg", "size": 788, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22711762, "NumLink": 0, "digest": "sha256:6c2a414ab5362a2d25f5d080c18da7dfb6efee6d6073635b6e3f1da5793ffac8" }, { "name": "usr/share/perl5/Debconf/Element/Dialog/Text.pm", "type": "reg", "size": 330, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22712227, "NumLink": 0, "digest": "sha256:d95c589193ffc32fa5f5c7fb151a458f210ec17a8f33ef5d1644b61110c7a8b0" }, { "name": "usr/share/perl5/Debconf/Element/Editor/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/Element/Editor/Boolean.pm", "type": "reg", "size": 1009, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22712592, "NumLink": 0, "digest": "sha256:03aaf5a065ce57bce012d4ac22f19c776eb5b49daf5842f06bf50de0948b7b17" }, { "name": "usr/share/perl5/Debconf/Element/Editor/Error.pm", "type": "reg", "size": 165, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22713132, "NumLink": 0, "digest": "sha256:dea5e8e710441f23f824944d013a72167c5e5a0eb9ed31502b543e6aea6d33ba" }, { "name": "usr/share/perl5/Debconf/Element/Editor/Multiselect.pm", "type": "reg", "size": 916, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22713367, "NumLink": 0, "digest": "sha256:6a607d19aec535e157cc301eb01a49d25335000d3312f5d0a06e9701d46edfb3" }, { "name": "usr/share/perl5/Debconf/Element/Editor/Note.pm", "type": "reg", "size": 164, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22713948, "NumLink": 0, "digest": "sha256:f3922ec83c3ff8ab7f2a0c9a832628c64aeff1a92249544259df48f642df14b7" }, { "name": "usr/share/perl5/Debconf/Element/Editor/Password.pm", "type": "reg", "size": 171, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22714182, "NumLink": 0, "digest": "sha256:e0802d54649714aafd6d6ef426ed4bf4f0429bc8b5ad930e8822b4835d66c4be" }, { "name": "usr/share/perl5/Debconf/Element/Editor/Progress.pm", "type": "reg", "size": 235, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22714419, "NumLink": 0, "digest": "sha256:f5b8cf39ff9f833f719d260e27466e4e11839a488286c25dacb56a23b049f831" }, { "name": "usr/share/perl5/Debconf/Element/Editor/Select.pm", "type": "reg", "size": 834, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22714684, "NumLink": 0, "digest": "sha256:4d8a031e7a23ad208675d097d700692b04304704fca6764630ffaeaa647843d0" }, { "name": "usr/share/perl5/Debconf/Element/Editor/String.pm", "type": "reg", "size": 439, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22715194, "NumLink": 0, "digest": "sha256:f8aec4b503d26da2b87eba5acb67456aa6752ad37add8915beee15646626d4a6" }, { "name": "usr/share/perl5/Debconf/Element/Editor/Text.pm", "type": "reg", "size": 316, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22715552, "NumLink": 0, "digest": "sha256:5478c4f864725771238f7a4d42071be055fdf1781098f9a67671ce4c082d6236" }, { "name": "usr/share/perl5/Debconf/Element/Gnome/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/Element/Gnome/Boolean.pm", "type": "reg", "size": 684, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22715912, "NumLink": 0, "digest": "sha256:c318ba062e156a6aee047e374602c3706c6b411fc42a3ec7e007e72d0ed9a633" }, { "name": "usr/share/perl5/Debconf/Element/Gnome/Error.pm", "type": "reg", "size": 1166, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22716373, "NumLink": 0, "digest": "sha256:30728fd5851c519aa6d04fc389141c269b933e715c7e4f34c4b374eea08f0e6e" }, { "name": "usr/share/perl5/Debconf/Element/Gnome/Multiselect.pm", "type": "reg", "size": 2479, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22717012, "NumLink": 0, "digest": "sha256:f038ebdef7cac98c970b5a009e72c9436addd0bb43b5c3dad66cde38601b4422" }, { "name": "usr/share/perl5/Debconf/Element/Gnome/Note.pm", "type": "reg", "size": 1076, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22718096, "NumLink": 0, "digest": "sha256:ebb6c28c8d917316a985911221448d6df0b448db5ac259b8e6281e82d600762d" }, { "name": "usr/share/perl5/Debconf/Element/Gnome/Password.pm", "type": "reg", "size": 580, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22718691, "NumLink": 0, "digest": "sha256:909030e9b56deb035d804e5acf0bbb8e31d57cf6b7ded3c2bc44634ca1465a41" }, { "name": "usr/share/perl5/Debconf/Element/Gnome/Progress.pm", "type": "reg", "size": 1113, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22719113, "NumLink": 0, "digest": "sha256:88e82679aa749d40dc705ddd37bc9b39732c8d67444c2a0d1b8bba605bc53309" }, { "name": "usr/share/perl5/Debconf/Element/Gnome/Select.pm", "type": "reg", "size": 975, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22719663, "NumLink": 0, "digest": "sha256:15ae5e72faf962e197edc6da61a5a12aa660027e8ab4e4294c6571dbe2271cf9" }, { "name": "usr/share/perl5/Debconf/Element/Gnome/String.pm", "type": "reg", "size": 649, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22720228, "NumLink": 0, "digest": "sha256:cb92206c450cf81313d1c96a9905a2e5a74fadcf9eb810bd7f5ad1e54d57c207" }, { "name": "usr/share/perl5/Debconf/Element/Gnome/Text.pm", "type": "reg", "size": 300, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22720673, "NumLink": 0, "digest": "sha256:21ebacfb1853ff920ebf8ec0d948ffba52863e7acf3d95185bc0c3c213f02af3" }, { "name": "usr/share/perl5/Debconf/Element/Gnome.pm", "type": "reg", "size": 2956, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22720986, "NumLink": 0, "digest": "sha256:7a249e4a2d49d59af9d1432adda52712f607ee20c85b0748356f85e25d17d729" }, { "name": "usr/share/perl5/Debconf/Element/Kde/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/Element/Kde/Boolean.pm", "type": "reg", "size": 730, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22722086, "NumLink": 0, "digest": "sha256:00fe2541a80981c26a26f33df614e88a080c00d592088c6c065a560af16030d2" }, { "name": "usr/share/perl5/Debconf/Element/Kde/Error.pm", "type": "reg", "size": 339, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22722556, "NumLink": 0, "digest": "sha256:587b37fd9a3dbdb70116fa02a95592b6c713852df37c8bd67d10884aa9778cae" }, { "name": "usr/share/perl5/Debconf/Element/Kde/Multiselect.pm", "type": "reg", "size": 1241, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22722886, "NumLink": 0, "digest": "sha256:e76353e8dd6e224fdf11c0589a4d9fc50f2658f0a3830f4c7b154fd58f6354b3" }, { "name": "usr/share/perl5/Debconf/Element/Kde/Note.pm", "type": "reg", "size": 365, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22723575, "NumLink": 0, "digest": "sha256:e3dcea774a31296c300a5b3f3759e4280dca2b6ed4d603758102caac2a4f8b23" }, { "name": "usr/share/perl5/Debconf/Element/Kde/Password.pm", "type": "reg", "size": 605, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22723906, "NumLink": 0, "digest": "sha256:a1cf8c7a6c23c4011d59b0e5d947f76edf59d2ec2a0ad59d6b1c962c477f81ae" }, { "name": "usr/share/perl5/Debconf/Element/Kde/Progress.pm", "type": "reg", "size": 1164, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22724332, "NumLink": 0, "digest": "sha256:f72dcf155b89c7b6275f246f083d5aeefc188a66056c49bf0420f30968606b26" }, { "name": "usr/share/perl5/Debconf/Element/Kde/Select.pm", "type": "reg", "size": 1083, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22724884, "NumLink": 0, "digest": "sha256:531a4048d81c02f477ac9405a13ca1110c63dcd8bd7a28607afe670cf081fdcf" }, { "name": "usr/share/perl5/Debconf/Element/Kde/String.pm", "type": "reg", "size": 636, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22725519, "NumLink": 0, "digest": "sha256:daaaf6d66dca96cca82e9d64c563c705927d1a604a18fb352d3fa17b32f09547" }, { "name": "usr/share/perl5/Debconf/Element/Kde/Text.pm", "type": "reg", "size": 323, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22725961, "NumLink": 0, "digest": "sha256:b49c5cf58bf4ce29ed7d2789f6b8f44480d84527dd166f80fc3abd2272c0a394" }, { "name": "usr/share/perl5/Debconf/Element/Kde.pm", "type": "reg", "size": 2185, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22726278, "NumLink": 0, "digest": "sha256:46e40500a4283dc9d8a581182cc5ccbfed82c54163969a4f425568e303e323f1" }, { "name": "usr/share/perl5/Debconf/Element/Multiselect.pm", "type": "reg", "size": 916, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22727089, "NumLink": 0, "digest": "sha256:8f4919e0b67b61f650af51406b13998467a477cd04f7772bc8b5ad6cb18649c3" }, { "name": "usr/share/perl5/Debconf/Element/Noninteractive/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/Element/Noninteractive/Boolean.pm", "type": "reg", "size": 178, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22727632, "NumLink": 0, "digest": "sha256:13e3e74cafc97617862521b51e2c4ba4b87e87658363d1537452fcd5d874d261" }, { "name": "usr/share/perl5/Debconf/Element/Noninteractive/Error.pm", "type": "reg", "size": 1666, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22727869, "NumLink": 0, "digest": "sha256:799e48fc5a362d653334159305bafe67cd451420d98988d3047d515b2408120b" }, { "name": "usr/share/perl5/Debconf/Element/Noninteractive/Multiselect.pm", "type": "reg", "size": 182, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22728700, "NumLink": 0, "digest": "sha256:14bbbea9a46115ea16632083ea3ba850b13594957e5dc49b7907ec07e14a0789" }, { "name": "usr/share/perl5/Debconf/Element/Noninteractive/Note.pm", "type": "reg", "size": 175, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22728938, "NumLink": 0, "digest": "sha256:88f2b6eaca06a4b404d62cbdaad4f497aa17aca4d44e785c3a78a763b66c24d4" }, { "name": "usr/share/perl5/Debconf/Element/Noninteractive/Password.pm", "type": "reg", "size": 179, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22729174, "NumLink": 0, "digest": "sha256:5a046112c91b00436a614d93590338a04ad14710cf3af56ebdb883041e38a955" }, { "name": "usr/share/perl5/Debconf/Element/Noninteractive/Progress.pm", "type": "reg", "size": 258, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22729413, "NumLink": 0, "digest": "sha256:f21d00539d3a4b8dafa82322d0e0cb1281f0493995723dfdd9a6fc7cc28a7434" }, { "name": "usr/share/perl5/Debconf/Element/Noninteractive/Select.pm", "type": "reg", "size": 602, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22729684, "NumLink": 0, "digest": "sha256:e0b972e4af3cefd2ab4858fac0a20df5ac91feb886bb8f0003cfac187581609b" }, { "name": "usr/share/perl5/Debconf/Element/Noninteractive/String.pm", "type": "reg", "size": 177, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22730106, "NumLink": 0, "digest": "sha256:505643b340d236ba8fe6e3bb930640e79ecf6ac15b43513456cb81228c946e23" }, { "name": "usr/share/perl5/Debconf/Element/Noninteractive/Text.pm", "type": "reg", "size": 226, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22730341, "NumLink": 0, "digest": "sha256:17d40add0e5bf98fdfb6ad5f71f337a04536c57c5b4e663cb6f5308398f27349" }, { "name": "usr/share/perl5/Debconf/Element/Noninteractive.pm", "type": "reg", "size": 342, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22730614, "NumLink": 0, "digest": "sha256:e1b6db74cda4b4b43bdf2244350494ea6a53d13a1f7dfeaca90ed16b22d13791" }, { "name": "usr/share/perl5/Debconf/Element/Select.pm", "type": "reg", "size": 1982, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22730932, "NumLink": 0, "digest": "sha256:249a05d5f564db0f40e09c13d79b0a77ab128563a19a1ceee585c3431b844d1e" }, { "name": "usr/share/perl5/Debconf/Element/Teletype/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/Element/Teletype/Boolean.pm", "type": "reg", "size": 1196, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22731691, "NumLink": 0, "digest": "sha256:a97d6deb504426af124f6c1dd8d522a6abd009dbb37fbe0a3e2a284b921ea1f3" }, { "name": "usr/share/perl5/Debconf/Element/Teletype/Error.pm", "type": "reg", "size": 170, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22732309, "NumLink": 0, "digest": "sha256:a271b558a75a7617474d93cd77402c339334e84938651ea0a01f7336db09d010" }, { "name": "usr/share/perl5/Debconf/Element/Teletype/Multiselect.pm", "type": "reg", "size": 1899, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22732550, "NumLink": 0, "digest": "sha256:dccdb67e08a4053c00c2395d4178ecf37ce8e64e81c63b4807e1d763ab0d5450" }, { "name": "usr/share/perl5/Debconf/Element/Teletype/Note.pm", "type": "reg", "size": 403, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22733446, "NumLink": 0, "digest": "sha256:0ea94576f9890a0f5f9a4a59361bd1e0f6153b3ff23b883e6078b2e08063155d" }, { "name": "usr/share/perl5/Debconf/Element/Teletype/Password.pm", "type": "reg", "size": 629, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22733811, "NumLink": 0, "digest": "sha256:9c3cc0ef1ccbe6da38b3885610369edef2005a691d043023c27689621e027a39" }, { "name": "usr/share/perl5/Debconf/Element/Teletype/Progress.pm", "type": "reg", "size": 805, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22734250, "NumLink": 0, "digest": "sha256:63968f89058f1066176e80bc3a4e4ada8f4f24dcf78fc56c722edc7aa12f0f9c" }, { "name": "usr/share/perl5/Debconf/Element/Teletype/Select.pm", "type": "reg", "size": 3292, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22734710, "NumLink": 0, "digest": "sha256:a5749589dee50745a7db1e2c6743788334381461cca018552058183edae81d8c" }, { "name": "usr/share/perl5/Debconf/Element/Teletype/String.pm", "type": "reg", "size": 573, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22736001, "NumLink": 0, "digest": "sha256:9bbe2c52e9629b135b888fe81fdcaf9eb1280076df252bb86292ba904aad8a1c" }, { "name": "usr/share/perl5/Debconf/Element/Teletype/Text.pm", "type": "reg", "size": 315, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22736409, "NumLink": 0, "digest": "sha256:f61a5ec96a09bf7671dadd87281a75622df7043b2736d788af6767f6827bcbba" }, { "name": "usr/share/perl5/Debconf/Element/Web/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/Element/Web/Boolean.pm", "type": "reg", "size": 660, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22736769, "NumLink": 0, "digest": "sha256:e74c742b01709c060bd24a58f960c03cbe688a818919037295d6222f8c3165ee" }, { "name": "usr/share/perl5/Debconf/Element/Web/Error.pm", "type": "reg", "size": 160, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22737256, "NumLink": 0, "digest": "sha256:1699c8211d030d2d67fcfaafd5e30867d2661c21dad41c574dec2d88bd96ebc6" }, { "name": "usr/share/perl5/Debconf/Element/Web/Multiselect.pm", "type": "reg", "size": 958, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22737491, "NumLink": 0, "digest": "sha256:367f3dce72c5bb9e40587416570903867824a063eb04319b6d57afdce1039d01" }, { "name": "usr/share/perl5/Debconf/Element/Web/Note.pm", "type": "reg", "size": 159, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22738086, "NumLink": 0, "digest": "sha256:6654230ab4dc25692f22f7eae0798896067c2f5471ceabc4bbfdfa63258970aa" }, { "name": "usr/share/perl5/Debconf/Element/Web/Password.pm", "type": "reg", "size": 483, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22738319, "NumLink": 0, "digest": "sha256:aff9175f3d6d46cd1a98d602e670d565c66005bc1e482174ca8ca75b53a40300" }, { "name": "usr/share/perl5/Debconf/Element/Web/Progress.pm", "type": "reg", "size": 231, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22738728, "NumLink": 0, "digest": "sha256:430c8365d9c3278fc0375434cc93725f8fa75a5353b072f0f8cfdfe4c7dd4dfc" }, { "name": "usr/share/perl5/Debconf/Element/Web/Select.pm", "type": "reg", "size": 877, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22738993, "NumLink": 0, "digest": "sha256:42a7752151c302e29228a17fa3d0fa8bd65dc999025846c013ee580e06d78766" }, { "name": "usr/share/perl5/Debconf/Element/Web/String.pm", "type": "reg", "size": 467, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22739538, "NumLink": 0, "digest": "sha256:3dacc1ab78f01cd9db77d95163cc33fec708f1ba1d3ca10146f5b14c6096def7" }, { "name": "usr/share/perl5/Debconf/Element/Web/Text.pm", "type": "reg", "size": 315, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22739935, "NumLink": 0, "digest": "sha256:03e9ea3bda1040086d423f3fbe2ee6cc93f59d90d26b4bf8554ab5c6cdc73885" }, { "name": "usr/share/perl5/Debconf/Element.pm", "type": "reg", "size": 196, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22740263, "NumLink": 0, "digest": "sha256:00c10272de11fd0ddfbacf752982b22623e629b9d796533c95d586d858ce2c39" }, { "name": "usr/share/perl5/Debconf/Encoding.pm", "type": "reg", "size": 1487, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22740523, "NumLink": 0, "digest": "sha256:801fe349da27f9312f3b6c60ea38e44e34bf7fce5138a0a9235b5efd1f7ff7eb" }, { "name": "usr/share/perl5/Debconf/Format/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/Format/822.pm", "type": "reg", "size": 2139, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22741293, "NumLink": 0, "digest": "sha256:47bb2e39010d9e051b79bdae364bb5824c663441b05037babae6a634fd4c0fb4" }, { "name": "usr/share/perl5/Debconf/Format.pm", "type": "reg", "size": 133, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22742209, "NumLink": 0, "digest": "sha256:5ce727bb1a20759b641ffb8bd6c45176bae65e65f907e237c6dc1f093899b02f" }, { "name": "usr/share/perl5/Debconf/FrontEnd/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/FrontEnd/Dialog.pm", "type": "reg", "size": 7389, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22742465, "NumLink": 0, "digest": "sha256:03417133c48efa609a58085ee135db1008ac8326a6457874df9105ad5fce075e" }, { "name": "usr/share/perl5/Debconf/FrontEnd/Editor.pm", "type": "reg", "size": 2165, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22745016, "NumLink": 0, "digest": "sha256:24b3da6ed94ce2682a51501683188675dbb50d4b154496e875ef1488c391711c" }, { "name": "usr/share/perl5/Debconf/FrontEnd/Gnome.pm", "type": "reg", "size": 4956, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22746092, "NumLink": 0, "digest": "sha256:a2e09f7bbe1cbd15850b432a626a0321bba98cec860960e8fc01963c446faea0" }, { "name": "usr/share/perl5/Debconf/FrontEnd/Kde/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/FrontEnd/Kde/Ui_DebconfWizard.pm", "type": "reg", "size": 4244, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22747752, "NumLink": 0, "digest": "sha256:649442e8cccc20d0f5937021d5f5fc551f4c91d9fc30f2c6181d295824a4948e" }, { "name": "usr/share/perl5/Debconf/FrontEnd/Kde/Wizard.pm", "type": "reg", "size": 1707, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22748897, "NumLink": 0, "digest": "sha256:9ae54bf90aa55c3aaca791616079cc9c342364995f992bc1e03d374440a9dc62" }, { "name": "usr/share/perl5/Debconf/FrontEnd/Kde.pm", "type": "reg", "size": 4409, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22749664, "NumLink": 0, "digest": "sha256:457b5677b1907bf3b85fd3189efdd47a537dcbce15943f953495e9739ad82825" }, { "name": "usr/share/perl5/Debconf/FrontEnd/Noninteractive.pm", "type": "reg", "size": 734, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22751134, "NumLink": 0, "digest": "sha256:1604a04e4c2ddebc03659bef3bfe94a1f97330ca8e4ea88b036b10ca509308e5" }, { "name": "usr/share/perl5/Debconf/FrontEnd/Passthrough.pm", "type": "reg", "size": 6438, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22751635, "NumLink": 0, "digest": "sha256:6cc52e0f85ac962e7fcdf11cabf01b13a7493d02209c23e8690a0c9afa3426da" }, { "name": "usr/share/perl5/Debconf/FrontEnd/Readline.pm", "type": "reg", "size": 3486, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22753569, "NumLink": 0, "digest": "sha256:de513abc3901f8244dc3cee1f84ccbeb817f7c3594167c9d3d52c074ea586d81" }, { "name": "usr/share/perl5/Debconf/FrontEnd/ScreenSize.pm", "type": "reg", "size": 881, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22754913, "NumLink": 0, "digest": "sha256:abd4a309996b0f8798df81bd51d881fa014b66ebbd0d626220884aee2868922e" }, { "name": "usr/share/perl5/Debconf/FrontEnd/Teletype.pm", "type": "reg", "size": 1573, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22755436, "NumLink": 0, "digest": "sha256:e01ec0a98b14a8092dda1656e66248212dc4f164248f4058178e2964e5b72928" }, { "name": "usr/share/perl5/Debconf/FrontEnd/Text.pm", "type": "reg", "size": 155, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22756257, "NumLink": 0, "digest": "sha256:cf4595fb746e12a9c0a43cd6806aec7d45523aa71b2bf9d98328d8c713c8470b" }, { "name": "usr/share/perl5/Debconf/FrontEnd/Web.pm", "type": "reg", "size": 2665, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22756483, "NumLink": 0, "digest": "sha256:ca7b97f7c6ecd207e6b161a89a0d42e5e547c81206b09c430b9a4ac1f0b9f847" }, { "name": "usr/share/perl5/Debconf/FrontEnd.pm", "type": "reg", "size": 2864, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22757757, "NumLink": 0, "digest": "sha256:e7a545c137bb45bfc70dc75f6f14f2246219a4cf9a60344bff9dcf04b1e25b33" }, { "name": "usr/share/perl5/Debconf/Gettext.pm", "type": "reg", "size": 301, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22758780, "NumLink": 0, "digest": "sha256:a88fa616d014b4668aa0acddd4b62c6f16f23ca4d770f74c42a465bccd757ddf" }, { "name": "usr/share/perl5/Debconf/Iterator.pm", "type": "reg", "size": 198, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22759107, "NumLink": 0, "digest": "sha256:25e26945b7cd46f0807fc71e4aa0187668d883f9068076356ec4fc3515d58b15" }, { "name": "usr/share/perl5/Debconf/Log.pm", "type": "reg", "size": 914, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22759368, "NumLink": 0, "digest": "sha256:295705788c02bc5ecab17acab91e8bca411c88a5ec5404b64ea1bf85f408d98a" }, { "name": "usr/share/perl5/Debconf/Path.pm", "type": "reg", "size": 291, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22759962, "NumLink": 0, "digest": "sha256:028380a22abab29ad18b0f4411bb3f1a1f3bf192f139ae61121393cebf5acc6e" }, { "name": "usr/share/perl5/Debconf/Priority.pm", "type": "reg", "size": 642, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22760266, "NumLink": 0, "digest": "sha256:bf398f78a07d12eb8aee3fb782ffd002f311027279d076eaa6fffd0de11ce0d1" }, { "name": "usr/share/perl5/Debconf/Question.pm", "type": "reg", "size": 5867, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22760693, "NumLink": 0, "digest": "sha256:457f0d6a12d8dc4ab1fc109b5c54c423a703184630b50e49abfd3b2cbba2e640" }, { "name": "usr/share/perl5/Debconf/Template/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debconf/Template/Transient.pm", "type": "reg", "size": 1108, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22762474, "NumLink": 0, "digest": "sha256:3a0e780834bf3c643f32931ad4fe02b3447343b1a54def72f03e15823e6723ae" }, { "name": "usr/share/perl5/Debconf/Template.pm", "type": "reg", "size": 8201, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22763043, "NumLink": 0, "digest": "sha256:4ee3d67fccb651ed7bca60a48bd85758e3a177fdda3167a5209f1513379eb6ac" }, { "name": "usr/share/perl5/Debconf/TmpFile.pm", "type": "reg", "size": 374, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22765731, "NumLink": 0, "digest": "sha256:01a27c6a5acbf11d145efb8341e0328892a0c00db0526ad522a8c2165e4e01f6" }, { "name": "usr/share/perl5/Debian/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debian/AdduserCommon.pm", "type": "reg", "size": 6185, "modtime": "2016-06-26T22:55:16Z", "mode": 33188, "offset": 22766120, "NumLink": 0, "digest": "sha256:94551d94231a98889d4fe7559c990cd5b26abf14c53a5ed8d072287e66b637d1" }, { "name": "usr/share/perl5/Debian/DebConf/", "type": "dir", "modtime": "2017-05-21T17:08:30Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debian/DebConf/Client/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/perl5/Debian/DebConf/Client/ConfModule.pm", "type": "reg", "size": 610, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22768783, "NumLink": 0, "digest": "sha256:18613eb5076afb75cd5cd97811c465b78533ab566d482023c9f3379f4f7fe7a0" }, { "name": "usr/share/pixmaps/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/pixmaps/debian-logo.png", "type": "reg", "size": 1718, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 22769254, "NumLink": 0, "digest": "sha256:18aa40cbfcd56cd1dddb005a7b20560d5466046472c665bad8683dfa9e17d6f2" }, { "name": "usr/share/tabset/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/tabset/std", "type": "reg", "size": 135, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 22771163, "NumLink": 0, "digest": "sha256:fbadb5f608b355fe481c0c7d9c6265b2372bfa35250662f81f68d46540080770" }, { "name": "usr/share/tabset/stdcrt", "type": "reg", "size": 95, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 22771283, "NumLink": 0, "digest": "sha256:cf6c37b18ceea7c306f7e3a5e604a03b0dfb9c22ec99163e4b52f885ce063145" }, { "name": "usr/share/tabset/vt100", "type": "reg", "size": 160, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 22771399, "NumLink": 0, "digest": "sha256:075251754239d9973945d82b95c18cd90997acd2017393e70c8832e9297de056" }, { "name": "usr/share/tabset/vt300", "type": "reg", "size": 64, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 22771518, "NumLink": 0, "digest": "sha256:61f8388cad6a381feb819bc6a8d299d06a853d15e1f4bfdfd6b6f40069ad4956" }, { "name": "usr/share/terminfo/", "type": "dir", "modtime": "2017-12-28T09:47:33Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Abidjan", "type": "reg", "size": 170, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22771745, "NumLink": 0, "digest": "sha256:d5ded126df8f693ce1ff83e85aa4d44185c2bdef7da1f915b214f53deffdee47" }, { "name": "usr/share/zoneinfo/Africa/Accra", "type": "reg", "size": 842, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22771916, "NumLink": 0, "digest": "sha256:ea0a89ec3c253390f746107c3ea69392270d8df0dc2d2aed6f23f4cff852bf91" }, { "name": "usr/share/zoneinfo/Africa/Addis_Ababa", "type": "reg", "size": 285, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22772459, "NumLink": 0, "digest": "sha256:f143bcb83b80bc1ad0bbb8ad736c852e62bbeb6b3134412bfa77684663ed222a" }, { "name": "usr/share/zoneinfo/Africa/Algiers", "type": "reg", "size": 760, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22772689, "NumLink": 0, "digest": "sha256:d777e8eecb9ebe269692349daa6b45b2463e4a3c2d107ccd139b6206c4fa73cc" }, { "name": "usr/share/zoneinfo/Africa/Asmara", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Asmera", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Bamako", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Bangui", "type": "reg", "size": 171, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22773263, "NumLink": 0, "digest": "sha256:e40c3386f3a5cd88a03c811fa30ecac34f31368f960ae79e4a90de295c5b1938" }, { "name": "usr/share/zoneinfo/Africa/Banjul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Bissau", "type": "reg", "size": 208, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22773480, "NumLink": 0, "digest": "sha256:8ddad13adc33cdee8eaf55cfa31efcafd79305ae8dfcc3be06ff78299f29f1d8" }, { "name": "usr/share/zoneinfo/Africa/Blantyre", "type": "reg", "size": 171, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22773681, "NumLink": 0, "digest": "sha256:3d7e6d17cabdaa1814a56dddec02687e1087bc3334fe920ad268a892bf080511" }, { "name": "usr/share/zoneinfo/Africa/Brazzaville", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Bujumbura", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Cairo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Egypt", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Casablanca", "type": "reg", "size": 1629, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22773963, "NumLink": 0, "digest": "sha256:afb98baa9972580559410aa145c57fb8c86689a05f7f0e97815f96bdea7af5ad" }, { "name": "usr/share/zoneinfo/Africa/Ceuta", "type": "reg", "size": 2059, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22774905, "NumLink": 0, "digest": "sha256:387d2c354117fe2a22f6f3b429e4193a331d3e93d7007a55c50b3b9eedee63de" }, { "name": "usr/share/zoneinfo/Africa/Conakry", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Dakar", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Dar_es_Salaam", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Djibouti", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Douala", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/El_Aaiun", "type": "reg", "size": 1459, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22776159, "NumLink": 0, "digest": "sha256:9c3a4c95fd64c01a78dcd44ca4b16cf72f2416be4704e8c5d52ffc7c131ae015" }, { "name": "usr/share/zoneinfo/Africa/Freetown", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Gaborone", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Harare", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Johannesburg", "type": "reg", "size": 271, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22777115, "NumLink": 0, "digest": "sha256:fcec4247091905d88a0b869e8e5c7ee6bcfba7db6c310165baa95078b0be31af" }, { "name": "usr/share/zoneinfo/Africa/Juba", "type": "reg", "size": 683, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22777350, "NumLink": 0, "digest": "sha256:73d986c70173c763e9b262dbf367120bc2a4f63f006c1d412ea9adab77e09da3" }, { "name": "usr/share/zoneinfo/Africa/Kampala", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Khartoum", "type": "reg", "size": 713, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22777856, "NumLink": 0, "digest": "sha256:5256a96f78382e82db80ad8591240c3886fc58f9a83fe94506e3a192fbcf2f4e" }, { "name": "usr/share/zoneinfo/Africa/Kigali", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Kinshasa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Lagos", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Libreville", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Lome", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Luanda", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Lubumbashi", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Lusaka", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Malabo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Maputo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Maseru", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Johannesburg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Mbabane", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Johannesburg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Mogadishu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Monrovia", "type": "reg", "size": 233, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22778584, "NumLink": 0, "digest": "sha256:3f9672c98983af595b3c6274cf8135728c8815a4f9c98ffba043707609e5d122" }, { "name": "usr/share/zoneinfo/Africa/Nairobi", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Ndjamena", "type": "reg", "size": 225, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22778843, "NumLink": 0, "digest": "sha256:b1391c8edd23b3f73e0bfacf8b878801c58206ca42349c30b22fcb7e8d13de3a" }, { "name": "usr/share/zoneinfo/Africa/Niamey", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Nouakchott", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Ouagadougou", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Porto-Novo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Sao_Tome", "type": "reg", "size": 234, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22779160, "NumLink": 0, "digest": "sha256:8d9cc441a8cb7dfebbf23510dba8510ba8b7a2cac7661b0cccab368555d865bf" }, { "name": "usr/share/zoneinfo/Africa/Timbuktu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Tripoli", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Libya", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Africa/Tunis", "type": "reg", "size": 710, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22779449, "NumLink": 0, "digest": "sha256:eecc34436d1dd96c49d6b671ed61bc594548d280a967537a9653841b537a9a92" }, { "name": "usr/share/zoneinfo/Africa/Windhoek", "type": "reg", "size": 988, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22779935, "NumLink": 0, "digest": "sha256:f6d37353c3cf02bb1b950cdc1cc024e9849a374532a8f7e4ee0bb00bdd4b6ab1" }, { "name": "usr/share/zoneinfo/America/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Adak", "type": "reg", "size": 2365, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22780581, "NumLink": 0, "digest": "sha256:c45c94d316413c8f666aff65ed1f837a7e2d392262de31ce59fac2e96a1edc81" }, { "name": "usr/share/zoneinfo/America/Anchorage", "type": "reg", "size": 2380, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22781880, "NumLink": 0, "digest": "sha256:f5df0a6f7f9d43cbbd3e74d33a23fe686080eb55965f5d9246b6e859b3db9d18" }, { "name": "usr/share/zoneinfo/America/Anguilla", "type": "reg", "size": 170, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22783178, "NumLink": 0, "digest": "sha256:b2659c267f7555c0640505660234cbe0d7feead3a5e29f41272e28a1d7d18962" }, { "name": "usr/share/zoneinfo/America/Antigua", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Araguaina", "type": "reg", "size": 896, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22783403, "NumLink": 0, "digest": "sha256:272c5c90b22d2661b00ed78567b641a8e7aacd3261e19c40ef191af4c7b1c60c" }, { "name": "usr/share/zoneinfo/America/Argentina/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Argentina/Buenos_Aires", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Buenos_Aires", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Argentina/Catamarca", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Catamarca", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Argentina/ComodRivadavia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Catamarca", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Argentina/Cordoba", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Cordoba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Argentina/Jujuy", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Jujuy", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Argentina/La_Rioja", "type": "reg", "size": 1109, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22784151, "NumLink": 0, "digest": "sha256:621f1bb3113e8ef3675827b6bcd718fc09f13157639ce8986c98bde382f3c957" }, { "name": "usr/share/zoneinfo/America/Argentina/Mendoza", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Mendoza", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Argentina/Rio_Gallegos", "type": "reg", "size": 1095, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22784897, "NumLink": 0, "digest": "sha256:29a13c6e65962f48b48ba73bffd41474a98257d1212584f32b3b51e5daa092a9" }, { "name": "usr/share/zoneinfo/America/Argentina/Salta", "type": "reg", "size": 1067, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22785586, "NumLink": 0, "digest": "sha256:113093ce6d0f2189f9a34183b0a1117b028c89761740700378f64c26ca60a884" }, { "name": "usr/share/zoneinfo/America/Argentina/San_Juan", "type": "reg", "size": 1109, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22786267, "NumLink": 0, "digest": "sha256:01d61c864a3edb46fc9c0245bda0c551c6b12253e962178ad42b9fa3d2ea96a3" }, { "name": "usr/share/zoneinfo/America/Argentina/San_Luis", "type": "reg", "size": 1125, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22786966, "NumLink": 0, "digest": "sha256:954240d24edafb8de8aec83efe5f926bde08620d4564105c68b5e59afcddcaf4" }, { "name": "usr/share/zoneinfo/America/Argentina/Tucuman", "type": "reg", "size": 1123, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22787667, "NumLink": 0, "digest": "sha256:82abb66f092dc63c03be1c298b65a8266ec6a638d17c00051701138b9bf7e00e" }, { "name": "usr/share/zoneinfo/America/Argentina/Ushuaia", "type": "reg", "size": 1095, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22788378, "NumLink": 0, "digest": "sha256:1caf03ba65f9d802fd8160f103c613ba9266500ef95956af6af8636ac4f5a7e3" }, { "name": "usr/share/zoneinfo/America/Aruba", "type": "reg", "size": 212, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22789059, "NumLink": 0, "digest": "sha256:023d877932f35d889772f561f79e266c8541b984e0ce2bd257723aafc7d883c1" }, { "name": "usr/share/zoneinfo/America/Asuncion", "type": "reg", "size": 2063, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22789263, "NumLink": 0, "digest": "sha256:f84a9ad05fdbc043ec0d57f60c0d9dde2c4979ff53de5f4b09520174f908c8c1" }, { "name": "usr/share/zoneinfo/America/Atikokan", "type": "reg", "size": 345, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22790378, "NumLink": 0, "digest": "sha256:c30226b472b507b5a30b69557d56f24fcc8e9467110e4d3ec15c2c51de5d245c" }, { "name": "usr/share/zoneinfo/America/Atka", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Adak", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Bahia", "type": "reg", "size": 1036, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22790689, "NumLink": 0, "digest": "sha256:2907605adbb291db6f65ffa990fb28e2150b37896752171c664a9cff6b4a890d" }, { "name": "usr/share/zoneinfo/America/Bahia_Banderas", "type": "reg", "size": 1588, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22791336, "NumLink": 0, "digest": "sha256:9d0e0d9f6168635a5f98550a170d423854ff5b662ce0d874c3cba77199bf1cbd" }, { "name": "usr/share/zoneinfo/America/Barbados", "type": "reg", "size": 344, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22792245, "NumLink": 0, "digest": "sha256:9b1a7857a01ae2a3ae9a51e0b40cfbed91bac468579ed3c08b54466276bbb1fa" }, { "name": "usr/share/zoneinfo/America/Belem", "type": "reg", "size": 588, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22792521, "NumLink": 0, "digest": "sha256:cab597d9b0946c0542e1e7efc41de81ffb67e5ad1b982ba7512e7c3b7abf9712" }, { "name": "usr/share/zoneinfo/America/Belize", "type": "reg", "size": 978, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22792941, "NumLink": 0, "digest": "sha256:eb4e57a8c657d0c253ef4e0a5af118c928e6e5875564081a714563addfd4b31a" }, { "name": "usr/share/zoneinfo/America/Blanc-Sablon", "type": "reg", "size": 307, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22793566, "NumLink": 0, "digest": "sha256:c7d383bfb7e85331030f8091a9055a5f424e3674407ca0c76cce06b5a0316fdb" }, { "name": "usr/share/zoneinfo/America/Boa_Vista", "type": "reg", "size": 644, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22793828, "NumLink": 0, "digest": "sha256:593ec3794b5fdc2fdb6141cf37eb943ccaf64818224f4c6c9eb64e001562eecc" }, { "name": "usr/share/zoneinfo/America/Bogota", "type": "reg", "size": 257, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22794278, "NumLink": 0, "digest": "sha256:7035a44b8a40432315da50a5db760cabde6fb2ad4004e1416645a04841c72b79" }, { "name": "usr/share/zoneinfo/America/Boise", "type": "reg", "size": 2403, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22794506, "NumLink": 0, "digest": "sha256:33353ef05ccdda7debe757cf865ee7bd78031f38c6797b8fbfc11f9010f55a10" }, { "name": "usr/share/zoneinfo/America/Buenos_Aires", "type": "reg", "size": 1095, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22795805, "NumLink": 0, "digest": "sha256:734a334127e43faddb2bc722a0e508719105a4aa25897c2a280fb1dfec261113" }, { "name": "usr/share/zoneinfo/America/Cambridge_Bay", "type": "reg", "size": 2098, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22796491, "NumLink": 0, "digest": "sha256:0aeaed5b104ee99ab13a9f5b5a7aaf7f6c9a7f59bdefd15d3c9951551c7b5f6f" }, { "name": "usr/share/zoneinfo/America/Campo_Grande", "type": "reg", "size": 2016, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22797635, "NumLink": 0, "digest": "sha256:ef672b3c0637f5e677307da2759bc261afa4f07e52fe45197f85b211f8bb9364" }, { "name": "usr/share/zoneinfo/America/Cancun", "type": "reg", "size": 816, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22798770, "NumLink": 0, "digest": "sha256:d22316873f309799c6f97fefb8a0a8897d0df4eb376f84bb0b71602ec240d04f" }, { "name": "usr/share/zoneinfo/America/Caracas", "type": "reg", "size": 275, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22799294, "NumLink": 0, "digest": "sha256:2f9e7150c7461615db09d15ae2ac14d42d3fa06327f57fa7a4064a9bedba2992" }, { "name": "usr/share/zoneinfo/America/Catamarca", "type": "reg", "size": 1095, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22799541, "NumLink": 0, "digest": "sha256:81e2c01af75fe321d32147db82facd088b6c191e9ea4cc3f8dd0ca36d90c1d12" }, { "name": "usr/share/zoneinfo/America/Cayenne", "type": "reg", "size": 210, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22800223, "NumLink": 0, "digest": "sha256:0afd6f15f47edfdfdeb34d7cfd8e1c1da974259085acec6fa03ad2f2c27f138a" }, { "name": "usr/share/zoneinfo/America/Cayman", "type": "reg", "size": 203, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22800426, "NumLink": 0, "digest": "sha256:fc4fbba14653a3186f3c5b719f7b9bf7d8a5824401064cf6d508205592e55a9f" }, { "name": "usr/share/zoneinfo/America/Chicago", "type": "reg", "size": 3585, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22800632, "NumLink": 0, "digest": "sha256:143f29b957173a46008187230a38125bd3a03b3dbcba0dc1d1b8661331f71693" }, { "name": "usr/share/zoneinfo/America/Chihuahua", "type": "reg", "size": 1522, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22802506, "NumLink": 0, "digest": "sha256:a7d150e716db5b1c96bb0e50252b80306e1d9e8bcc2bf90a3ae7071906e71513" }, { "name": "usr/share/zoneinfo/America/Coral_Harbour", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Atikokan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Cordoba", "type": "reg", "size": 1095, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22803431, "NumLink": 0, "digest": "sha256:aa24a2867e3cdce8158a4abb12118fff2a65c7ead38edbb8d56a43b8345b3600" }, { "name": "usr/share/zoneinfo/America/Costa_Rica", "type": "reg", "size": 341, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22804110, "NumLink": 0, "digest": "sha256:4e6ff29a776e053226bf590ebe734896f9150d69074f22a16a1c7199a1484ec5" }, { "name": "usr/share/zoneinfo/America/Creston", "type": "reg", "size": 233, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22804393, "NumLink": 0, "digest": "sha256:97b74beec3714be518219f24533cc21edf9b53d01f4ab792a6fe0f88973449eb" }, { "name": "usr/share/zoneinfo/America/Cuiaba", "type": "reg", "size": 1988, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22804608, "NumLink": 0, "digest": "sha256:1df651a890eb83ad31e503fa10697555f735974ae4501b48735d67cddf5f4a2b" }, { "name": "usr/share/zoneinfo/America/Curacao", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Aruba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Danmarkshavn", "type": "reg", "size": 712, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22805784, "NumLink": 0, "digest": "sha256:087e39cd6f10b6944b68b1de557289ef33769467f1b29806b96a16cf8e438e6e" }, { "name": "usr/share/zoneinfo/America/Dawson", "type": "reg", "size": 2093, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22806252, "NumLink": 0, "digest": "sha256:2d01b4b6114df8b0ed8aa64654f777842f20729818f1566a5f341d73ef7093dc" }, { "name": "usr/share/zoneinfo/America/Dawson_Creek", "type": "reg", "size": 1059, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22807410, "NumLink": 0, "digest": "sha256:29d0245bc04dadcbb196a3b6a81bace1696451166a7417d5bb2a8610f37ec5ba" }, { "name": "usr/share/zoneinfo/America/Denver", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Detroit", "type": "reg", "size": 2188, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22808104, "NumLink": 0, "digest": "sha256:d9037aded390d30e2e30f2302062ad6042651b261392872ef772cad5afaed92a" }, { "name": "usr/share/zoneinfo/America/Dominica", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Edmonton", "type": "reg", "size": 2402, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22809338, "NumLink": 0, "digest": "sha256:6678c23f86573b6c95e6c748a317aa8ce90f68636bcdad18db081e70986fb54e" }, { "name": "usr/share/zoneinfo/America/Eirunepe", "type": "reg", "size": 676, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22810634, "NumLink": 0, "digest": "sha256:1cf7b8dcba3182d527e72c1307bb6fc6908e8722d7ae10ff6522608df38d70c3" }, { "name": "usr/share/zoneinfo/America/El_Salvador", "type": "reg", "size": 250, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22811100, "NumLink": 0, "digest": "sha256:63215b213a31505bfd545fd52b11214cb614f13f0f55911f414edb44286e7f8a" }, { "name": "usr/share/zoneinfo/America/Ensenada", "type": "reg", "size": 2356, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22811333, "NumLink": 0, "digest": "sha256:d827b95b4fa16b8c56d9a1636341c9112657e567ae84b37a9bfca133ae31babb" }, { "name": "usr/share/zoneinfo/America/Fort_Nelson", "type": "reg", "size": 2249, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22812593, "NumLink": 0, "digest": "sha256:e7ce9a01cdd313d20352112430341c262e1b90182de490fc95c132daac118ce7" }, { "name": "usr/share/zoneinfo/America/Fort_Wayne", "type": "reg", "size": 1675, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22813803, "NumLink": 0, "digest": "sha256:55c2f3feb241f88435e9876e76e2c69ddfd0dfd36a273b551ff480e2cfad99fe" }, { "name": "usr/share/zoneinfo/America/Fortaleza", "type": "reg", "size": 728, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22814775, "NumLink": 0, "digest": "sha256:dc020e10d5350251d78744ffa59f54a7fc47eb521e3813a4811d614067a929ba" }, { "name": "usr/share/zoneinfo/America/Glace_Bay", "type": "reg", "size": 2206, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22815275, "NumLink": 0, "digest": "sha256:e6af24e3b9f1240abb8618fac326ee3a1ecccd25d2fa4936b2a28b0b0880e550" }, { "name": "usr/share/zoneinfo/America/Godthab", "type": "reg", "size": 1878, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22816473, "NumLink": 0, "digest": "sha256:69351ff5190c3330d5910eb4d23211674dca4a120c6636bd535d6b6687f96b23" }, { "name": "usr/share/zoneinfo/America/Goose_Bay", "type": "reg", "size": 3219, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22817492, "NumLink": 0, "digest": "sha256:f0c06c6a1841cdc37bfb311c11caba1c974d0d6c27725c04b69657e7ca112a49" }, { "name": "usr/share/zoneinfo/America/Grand_Turk", "type": "reg", "size": 1881, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22819220, "NumLink": 0, "digest": "sha256:90848fabb8bcfdbb4e66f5a624c4e7fa88962f16f8b6005f527cd84abebfa574" }, { "name": "usr/share/zoneinfo/America/Grenada", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Guadeloupe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Guatemala", "type": "reg", "size": 306, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22820334, "NumLink": 0, "digest": "sha256:795cc25e5ffe825a8b3d86eed98ad5f9bb9f6d152df2b624f0e2a63b17f0ee43" }, { "name": "usr/share/zoneinfo/America/Guayaquil", "type": "reg", "size": 257, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22820599, "NumLink": 0, "digest": "sha256:b144b87141ba1c6e6e7e0da5b35ec3c50d57dda3b2be94caf3186062563ccf35" }, { "name": "usr/share/zoneinfo/America/Guyana", "type": "reg", "size": 252, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22820833, "NumLink": 0, "digest": "sha256:4b38a7f5eb21df41f8efbca839606a2b76dcb13f13aecab80956d6cb1196a76a" }, { "name": "usr/share/zoneinfo/America/Halifax", "type": "reg", "size": 3438, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22821055, "NumLink": 0, "digest": "sha256:627e18218c6f3c3f446c4970abe8164672e2a7ba94bcf841b1e06af5089b94ea" }, { "name": "usr/share/zoneinfo/America/Havana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Cuba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Hermosillo", "type": "reg", "size": 454, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22822913, "NumLink": 0, "digest": "sha256:ec6eb21d068f1ca8e80a9e825206ad1b5a04b1e8abb2dd981c6c90b7686b8820" }, { "name": "usr/share/zoneinfo/America/Indiana/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Indiana/Indianapolis", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Fort_Wayne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Indiana/Knox", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Knox_IN", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Indiana/Marengo", "type": "reg", "size": 1731, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22823353, "NumLink": 0, "digest": "sha256:64bb87669a7c161454b283e5855e28de7655450680cc403eea0572e580eb2625" }, { "name": "usr/share/zoneinfo/America/Indiana/Petersburg", "type": "reg", "size": 1913, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22824368, "NumLink": 0, "digest": "sha256:3eb5dd510d677f9118ec4bca7892db4ed181722fbaf94ef9cb1a441718400321" }, { "name": "usr/share/zoneinfo/America/Indiana/Tell_City", "type": "reg", "size": 1735, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22825472, "NumLink": 0, "digest": "sha256:268c538689f4815f86ae1d100b4b072a785d5e68b03de71b74f437135bc52843" }, { "name": "usr/share/zoneinfo/America/Indiana/Vevay", "type": "reg", "size": 1423, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22826469, "NumLink": 0, "digest": "sha256:5cf728ac267cce51bddf1875219bf0e800d5aaa17794dc2c7408293773f516e5" }, { "name": "usr/share/zoneinfo/America/Indiana/Vincennes", "type": "reg", "size": 1703, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22827322, "NumLink": 0, "digest": "sha256:8a9db38f7575f9e2a624c9466128927caef0eea7e9a3841679cd6eb129b019d3" }, { "name": "usr/share/zoneinfo/America/Indiana/Winamac", "type": "reg", "size": 1787, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22828318, "NumLink": 0, "digest": "sha256:d2dc919207b8db95bd82aff68b8a498a6d3bec2c33220ba5381ebca171dcc095" }, { "name": "usr/share/zoneinfo/America/Indianapolis", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Fort_Wayne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Inuvik", "type": "reg", "size": 1928, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22829403, "NumLink": 0, "digest": "sha256:ea64cbc0bf92cf88c8917222f11db8838f42e2d41360cd81bb93f669a2bc685b" }, { "name": "usr/share/zoneinfo/America/Iqaluit", "type": "reg", "size": 2046, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22830466, "NumLink": 0, "digest": "sha256:eb8797250b8bd8c3d09893b4f261ffb1bedd668869a051c8e2c80f6c0d63408c" }, { "name": "usr/share/zoneinfo/America/Jamaica", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Jamaica", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Jujuy", "type": "reg", "size": 1067, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22831625, "NumLink": 0, "digest": "sha256:9e5e87b452a3cdc3f010537e096150239b10ee67ec1c438b7864096a96758992" }, { "name": "usr/share/zoneinfo/America/Juneau", "type": "reg", "size": 2362, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22832294, "NumLink": 0, "digest": "sha256:8185913ee68f7ec72cd98efcee68d1b6bd0c304e303a2dc613b06cd97e6333c8" }, { "name": "usr/share/zoneinfo/America/Kentucky/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Kentucky/Louisville", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Louisville", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Kentucky/Monticello", "type": "reg", "size": 2361, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22833680, "NumLink": 0, "digest": "sha256:b87081e46bbe688816a7e03cfdc5b4efe10bd6b92cb5a780df6b0c86af4c1a37" }, { "name": "usr/share/zoneinfo/America/Knox_IN", "type": "reg", "size": 2437, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22834964, "NumLink": 0, "digest": "sha256:9e75dd6c52c5339c8e2b195ff8ac6a7212e2c5e84b2be3023cc355972c20d856" }, { "name": "usr/share/zoneinfo/America/Kralendijk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Aruba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/La_Paz", "type": "reg", "size": 243, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22836334, "NumLink": 0, "digest": "sha256:379b1f2fd14b7f6b584e9e7030f45b580a84fc7c0c96314006c76c0afd620532" }, { "name": "usr/share/zoneinfo/America/Lima", "type": "reg", "size": 417, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22836556, "NumLink": 0, "digest": "sha256:4adf338b94b1680c4e114ffa17669dba4363a08009d6e21f090610e55aaa30a1" }, { "name": "usr/share/zoneinfo/America/Los_Angeles", "type": "reg", "size": 2845, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22836893, "NumLink": 0, "digest": "sha256:fea9d66ff6522e69d22073dc4e84179b7cac2e372b398dc2fafdfdb61a9eb2e1" }, { "name": "usr/share/zoneinfo/America/Louisville", "type": "reg", "size": 2781, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22838408, "NumLink": 0, "digest": "sha256:779c6a6c566774f94f754dad8936ea7f7f6afb028ed9c76b74d8f375355439ee" }, { "name": "usr/share/zoneinfo/America/Lower_Princes", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Aruba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Maceio", "type": "reg", "size": 756, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22839952, "NumLink": 0, "digest": "sha256:c640e22f9bb0f3c376f8a3440622e7a29de3b48d71d06d900ae66e0e2ea4f392" }, { "name": "usr/share/zoneinfo/America/Managua", "type": "reg", "size": 463, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22840458, "NumLink": 0, "digest": "sha256:a3c1f00bc879ee84e623d25252f1fb8ffd8cf43cd9c8b8bf12b6b5eda8045683" }, { "name": "usr/share/zoneinfo/America/Manaus", "type": "reg", "size": 616, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22840809, "NumLink": 0, "digest": "sha256:7a411c339329e8984d50258dd3bbf44e06e4a86db28d1b34a27c056f2a00686a" }, { "name": "usr/share/zoneinfo/America/Marigot", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Martinique", "type": "reg", "size": 257, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22841288, "NumLink": 0, "digest": "sha256:e087c3e4ae20234a08667adcf6ab4cd03ab3aeee7e035278f271ddb0b65cfff2" }, { "name": "usr/share/zoneinfo/America/Matamoros", "type": "reg", "size": 1416, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22841520, "NumLink": 0, "digest": "sha256:4398d831df4bfcfd9bafa22ac35cd55dbb7dfd5f25c138452e8adf275ea11735" }, { "name": "usr/share/zoneinfo/America/Mazatlan", "type": "reg", "size": 1564, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22842351, "NumLink": 0, "digest": "sha256:9340b719b250773262cec62e771d121105aed168836723dfc305e30bb04cfbb1" }, { "name": "usr/share/zoneinfo/America/Mendoza", "type": "reg", "size": 1095, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22843245, "NumLink": 0, "digest": "sha256:38933e04d16131a11b1052c7daba2794b994030dd485142d8766f7f13d105b61" }, { "name": "usr/share/zoneinfo/America/Menominee", "type": "reg", "size": 2283, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22843927, "NumLink": 0, "digest": "sha256:46ced580e74834d2c68a80a60ae05a0b715014bb2b4dad67cf994ac20ce2ac22" }, { "name": "usr/share/zoneinfo/America/Merida", "type": "reg", "size": 1456, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22845164, "NumLink": 0, "digest": "sha256:ecdcf4b29f7b439152b9e9b559f04d7d4ba759dd942c2fd685a4ee36798fc8d1" }, { "name": "usr/share/zoneinfo/America/Metlakatla", "type": "reg", "size": 1418, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22846006, "NumLink": 0, "digest": "sha256:49ad5e4fc549d0db2e2cc6dcd2936ecb12b8591dbc3a806ffcf843df8240f6a0" }, { "name": "usr/share/zoneinfo/America/Mexico_City", "type": "reg", "size": 1618, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22846865, "NumLink": 0, "digest": "sha256:88bc3fcb1a92ef053e0af4af9053ecbf12855fdf18f859b2a54d826dbfacb655" }, { "name": "usr/share/zoneinfo/America/Miquelon", "type": "reg", "size": 1682, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22847792, "NumLink": 0, "digest": "sha256:41f2e13c925042a466b8cdcc8bd1dced7e9247cc893bcde20b91d98ce10d316f" }, { "name": "usr/share/zoneinfo/America/Moncton", "type": "reg", "size": 3163, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22848744, "NumLink": 0, "digest": "sha256:1300d5a93bb376cbf23a890a23ea05fa2b229486e7eb7d5959c7834260fbb7b7" }, { "name": "usr/share/zoneinfo/America/Monterrey", "type": "reg", "size": 1416, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22850420, "NumLink": 0, "digest": "sha256:89dadca852ebf52e4405c958132255c25fb195604d7df9b844bf50b48a0865d8" }, { "name": "usr/share/zoneinfo/America/Montevideo", "type": "reg", "size": 1550, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22851248, "NumLink": 0, "digest": "sha256:b58bb9b5a2c6f4f5c20067ff6b4a56037962fa37e5264c521d340eb7323e5b3a" }, { "name": "usr/share/zoneinfo/America/Montreal", "type": "reg", "size": 3503, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22852152, "NumLink": 0, "digest": "sha256:842f7a103dfac9c0c2c33c9cc392a113d266ac064c5c7497883ab41b797ce194" }, { "name": "usr/share/zoneinfo/America/Montserrat", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Nassau", "type": "reg", "size": 2284, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22854046, "NumLink": 0, "digest": "sha256:4c999dbcc6c6045acbedf6fd48f5b70b20eb8d8b0bd9612d2bea88dc03aa9f4d" }, { "name": "usr/share/zoneinfo/America/New_York", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../posixrules", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Nipigon", "type": "reg", "size": 2131, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22855326, "NumLink": 0, "digest": "sha256:7100ca4bf3044211ff8e770dade20b683880f3965f146ebbdd72c644aaec7c37" }, { "name": "usr/share/zoneinfo/America/Nome", "type": "reg", "size": 2376, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22856491, "NumLink": 0, "digest": "sha256:d312bc797eb1b384ccfba0c40822d50b2e0abf37d5daa43dd3e255fdc7573b00" }, { "name": "usr/share/zoneinfo/America/Noronha", "type": "reg", "size": 728, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22857800, "NumLink": 0, "digest": "sha256:4b71d8f0d772be18ab8425cff1be9d927f340511a91e248e962745ccc76ced79" }, { "name": "usr/share/zoneinfo/America/North_Dakota/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/North_Dakota/Beulah", "type": "reg", "size": 2389, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22858337, "NumLink": 0, "digest": "sha256:f604eb42f0197f5edefcd6d43051a0b64e6e1327dbd2d3cfa94d0348b23e1fa8" }, { "name": "usr/share/zoneinfo/America/North_Dakota/Center", "type": "reg", "size": 2389, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22859652, "NumLink": 0, "digest": "sha256:08efea4af9a2b6a5ab25e86116cfcf4b93c16ba9b7b22f762d9cb3481ecf3ac8" }, { "name": "usr/share/zoneinfo/America/North_Dakota/New_Salem", "type": "reg", "size": 2389, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22860971, "NumLink": 0, "digest": "sha256:c5a43eb6776c326b1250f914f00e9e00e121b9b51f63665f90f245376da2017a" }, { "name": "usr/share/zoneinfo/America/Ojinaga", "type": "reg", "size": 1522, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22862271, "NumLink": 0, "digest": "sha256:a07ff8fe3ee3531f866afca0f7937d86acec1826fb3eaa655d54300ec22dc713" }, { "name": "usr/share/zoneinfo/America/Panama", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Cayman", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Pangnirtung", "type": "reg", "size": 2108, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22863195, "NumLink": 0, "digest": "sha256:1b6a497653df9220c30a022d87ec2aa1320af9e51bb3cdc48756e72d770a6738" }, { "name": "usr/share/zoneinfo/America/Paramaribo", "type": "reg", "size": 282, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22864347, "NumLink": 0, "digest": "sha256:95afc0b1d45e18abc0fc3a8952500b443a1c49174b6a61de4fb09c8a1284131c" }, { "name": "usr/share/zoneinfo/America/Phoenix", "type": "reg", "size": 353, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22864579, "NumLink": 0, "digest": "sha256:9c013ecf82b6ed1dde235b5fc983fe9d23c8d56d610323f7c94c6ba3cd7b4564" }, { "name": "usr/share/zoneinfo/America/Port-au-Prince", "type": "reg", "size": 1455, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22864881, "NumLink": 0, "digest": "sha256:b0b60ad1c557c41596e0fcc7fc8b9b39444c78295b147cee495e29985a225da6" }, { "name": "usr/share/zoneinfo/America/Port_of_Spain", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Porto_Acre", "type": "reg", "size": 648, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22865790, "NumLink": 0, "digest": "sha256:f3461eaf7c44f1bf84193b3889dd3ff27901f8d0c4412afe77f917ce1afb2b85" }, { "name": "usr/share/zoneinfo/America/Porto_Velho", "type": "reg", "size": 588, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22866239, "NumLink": 0, "digest": "sha256:526e90a17542252332361dbaf136103513731b094788e8705f5df5d981c1fa4f" }, { "name": "usr/share/zoneinfo/America/Puerto_Rico", "type": "reg", "size": 255, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22866673, "NumLink": 0, "digest": "sha256:7eee44e1cb7ac885fdd5042815c548bcb6ca84cff8de007e52b53c0b9ad53f19" }, { "name": "usr/share/zoneinfo/America/Punta_Arenas", "type": "reg", "size": 1897, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22866911, "NumLink": 0, "digest": "sha256:12d157ad893061c7f49cb94cc6a0ec3b20a11ef71fdc150c0baf4c39d97836e6" }, { "name": "usr/share/zoneinfo/America/Rainy_River", "type": "reg", "size": 2131, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22867972, "NumLink": 0, "digest": "sha256:9a7b8dd4c968de31fe35fd9fe075fad8afc15892067119f638b5aef0d2288d83" }, { "name": "usr/share/zoneinfo/America/Rankin_Inlet", "type": "reg", "size": 1930, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22869151, "NumLink": 0, "digest": "sha256:b3ae38ccfa3091ebd8037fd5e1fd2715a72008932f94526a15fb1aa7fae722dc" }, { "name": "usr/share/zoneinfo/America/Recife", "type": "reg", "size": 728, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22870219, "NumLink": 0, "digest": "sha256:a87a7203eb4cb49346d80581463e0b8d0e8fde53f3801cc98c12d26d016708d7" }, { "name": "usr/share/zoneinfo/America/Regina", "type": "reg", "size": 994, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22870714, "NumLink": 0, "digest": "sha256:929d07457407529637626d09f5ca975b4f05801f35d0bfac4e3b0027efee6776" }, { "name": "usr/share/zoneinfo/America/Resolute", "type": "reg", "size": 1930, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22871326, "NumLink": 0, "digest": "sha256:c529141807704725b059187b9f458080f911b6dd4313e74139d2c7dac287c901" }, { "name": "usr/share/zoneinfo/America/Rio_Branco", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Porto_Acre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Rosario", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Cordoba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Santa_Isabel", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Ensenada", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Santarem", "type": "reg", "size": 618, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22872513, "NumLink": 0, "digest": "sha256:d126927c9419ef3afbb32be4fc3600d5f44c022a4e8472cf2532863ca9787d0b" }, { "name": "usr/share/zoneinfo/America/Santiago", "type": "reg", "size": 2524, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22872951, "NumLink": 0, "digest": "sha256:9250d4f8f07d8cee14e8ae9e2ece611b7ea9bf69bca4fde77788346477b14658" }, { "name": "usr/share/zoneinfo/America/Santo_Domingo", "type": "reg", "size": 491, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22874310, "NumLink": 0, "digest": "sha256:adf349e4c7314aaa699c4893c589b077f6dfa7d9a54ea9eae459658f9af41dc7" }, { "name": "usr/share/zoneinfo/America/Sao_Paulo", "type": "reg", "size": 2016, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22874684, "NumLink": 0, "digest": "sha256:e54f2d187b08effd2d1ac9c4f66d6bc0a3136704887928557a5c7f74c23af408" }, { "name": "usr/share/zoneinfo/America/Scoresbysund", "type": "reg", "size": 1916, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22875829, "NumLink": 0, "digest": "sha256:2c37c6a1f497e2c993dadbd3aab2bf04ab72b626c3abde7ac29d55d4601f967e" }, { "name": "usr/share/zoneinfo/America/Shiprock", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Sitka", "type": "reg", "size": 2350, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22876913, "NumLink": 0, "digest": "sha256:ba79b89ecd8e64dba4119f2c5af2373167557c4bc71b7b134ab252e0b7485fdb" }, { "name": "usr/share/zoneinfo/America/St_Barthelemy", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/St_Johns", "type": "reg", "size": 3664, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22878264, "NumLink": 0, "digest": "sha256:2b960a58d6d3f6a272707f941f55b15b8ba3fd0fd55f8680ea84af6b1e98bae0" }, { "name": "usr/share/zoneinfo/America/St_Kitts", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/St_Lucia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/St_Thomas", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/St_Vincent", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Swift_Current", "type": "reg", "size": 574, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22880313, "NumLink": 0, "digest": "sha256:6b6029f04ac07c382e20d315da7a72d9204d813ef83585f042562e7f6788a78f" }, { "name": "usr/share/zoneinfo/America/Tegucigalpa", "type": "reg", "size": 278, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22880722, "NumLink": 0, "digest": "sha256:fd295a9cc689a966786b6e0ec9d0f101796ac8b4f04a6f529b192937df3a2115" }, { "name": "usr/share/zoneinfo/America/Thule", "type": "reg", "size": 1528, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22880965, "NumLink": 0, "digest": "sha256:9a474a1fc764343470d310369cdbf6d7007ea611116e25bea68f60ddf5a6cd68" }, { "name": "usr/share/zoneinfo/America/Thunder_Bay", "type": "reg", "size": 2211, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22881853, "NumLink": 0, "digest": "sha256:aef45e1474369f52e1afb1cd7f312e9f035ca13686092cf2351a353133e1cee6" }, { "name": "usr/share/zoneinfo/America/Tijuana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Ensenada", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Toronto", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Montreal", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Tortola", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Vancouver", "type": "reg", "size": 2901, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22883151, "NumLink": 0, "digest": "sha256:8b414b9a20be09ad61214deeb2dbff3bb1bd1e9d351a79aceae757fa0fbe91dd" }, { "name": "usr/share/zoneinfo/America/Virgin", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/America/Whitehorse", "type": "reg", "size": 2093, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22884733, "NumLink": 0, "digest": "sha256:1864fe33d51e58780a5c8400a47e7c42e6e6655abe49a82cc11a461059058313" }, { "name": "usr/share/zoneinfo/America/Winnipeg", "type": "reg", "size": 2891, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22885882, "NumLink": 0, "digest": "sha256:77be5c08f6f8ebe5330fb86a60c4447ea2549620609f4ef6a7a7a68d1a12d9d6" }, { "name": "usr/share/zoneinfo/America/Yakutat", "type": "reg", "size": 2314, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22887419, "NumLink": 0, "digest": "sha256:07f189f49873b1392989ecbde19d19d33cd6c16953bf7e6b927ca2f1040f7106" }, { "name": "usr/share/zoneinfo/America/Yellowknife", "type": "reg", "size": 1980, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22888688, "NumLink": 0, "digest": "sha256:3140de7fe4136fb4920e8bb8ed8d707256e78c672edfce1657ae22672de68768" }, { "name": "usr/share/zoneinfo/Antarctica/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Antarctica/Casey", "type": "reg", "size": 297, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22889822, "NumLink": 0, "digest": "sha256:235e572b63f7ae91a9cd1f352fef86fb61b506465f418e0127c5ad86c88e2253" }, { "name": "usr/share/zoneinfo/Antarctica/Davis", "type": "reg", "size": 297, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22890070, "NumLink": 0, "digest": "sha256:ee123489006dfbc147e65020c9836054e7fcb494d150582464bc2060d409a16e" }, { "name": "usr/share/zoneinfo/Antarctica/DumontDUrville", "type": "reg", "size": 202, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22890326, "NumLink": 0, "digest": "sha256:26fa92c4c643cc230c34b1641355726fddba6587181ddf3c3b1f1a63149e64c7" }, { "name": "usr/share/zoneinfo/Antarctica/Macquarie", "type": "reg", "size": 1529, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22890530, "NumLink": 0, "digest": "sha256:19fe3ba56b287f6117a93b06d16402bfd5386deb06676349c1b8501d497f5a90" }, { "name": "usr/share/zoneinfo/Antarctica/Mawson", "type": "reg", "size": 211, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22891378, "NumLink": 0, "digest": "sha256:5779e99cfe950860cd5fadb21f21c8a9a3ff264a0e1f06a41de944e8d62d68b0" }, { "name": "usr/share/zoneinfo/Antarctica/McMurdo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../NZ", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Antarctica/Palmer", "type": "reg", "size": 1418, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22891618, "NumLink": 0, "digest": "sha256:59261d3bbe6da255add2fc7fb8eb711b6c4a718de8982cde36806c2a766f74eb" }, { "name": "usr/share/zoneinfo/Antarctica/Rothera", "type": "reg", "size": 172, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22892432, "NumLink": 0, "digest": "sha256:c15f59336f5a90350fb5c13cfe7e4836a54d387f7b7248eaa154ca7e21ca0fbb" }, { "name": "usr/share/zoneinfo/Antarctica/South_Pole", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../NZ", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Antarctica/Syowa", "type": "reg", "size": 173, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22892651, "NumLink": 0, "digest": "sha256:9b96709317fec4c34c541fd36cf4fe466da31a1f40e62905b1dff9217dcb85c0" }, { "name": "usr/share/zoneinfo/Antarctica/Troll", "type": "reg", "size": 1162, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22892830, "NumLink": 0, "digest": "sha256:5038d1f2d45e68bcadb7c6e3fce73f1b3ed6719c9ae9ff46225ffabe7eadd717" }, { "name": "usr/share/zoneinfo/Antarctica/Vostok", "type": "reg", "size": 173, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22893516, "NumLink": 0, "digest": "sha256:57d73835fefd936f16f953339a6f0195050e4d1499fb4e6551be1b90c25872c0" }, { "name": "usr/share/zoneinfo/Arctic/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Arctic/Longyearbyen", "type": "reg", "size": 2251, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22893736, "NumLink": 0, "digest": "sha256:0fa4e635da2b178fa3ea13ff3829c702844cf8bd69e16bca8e1d34dbd9249d01" }, { "name": "usr/share/zoneinfo/Asia/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Aden", "type": "reg", "size": 173, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22894950, "NumLink": 0, "digest": "sha256:baacbd8acbcee961f154dbbd5d4b40f82f124576b8191f08c7b1501ad7e78364" }, { "name": "usr/share/zoneinfo/Asia/Almaty", "type": "reg", "size": 1017, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22895128, "NumLink": 0, "digest": "sha256:038801e8f58d0f0166ed053af84d11fde658e6e997c100101a9f4330c8cde4e0" }, { "name": "usr/share/zoneinfo/Asia/Amman", "type": "reg", "size": 1877, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22895726, "NumLink": 0, "digest": "sha256:ba18a1f823f77e478e7030eeb82ddd71a5f3fae6efdf56325b7776304912da08" }, { "name": "usr/share/zoneinfo/Asia/Anadyr", "type": "reg", "size": 1208, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22896767, "NumLink": 0, "digest": "sha256:0bd4d0ef1c353f753b6e034aff4e004b77df3c92d1f0de648b07e03b1f90a253" }, { "name": "usr/share/zoneinfo/Asia/Aqtau", "type": "reg", "size": 1003, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22897471, "NumLink": 0, "digest": "sha256:4abd31e6c7b73775c51c2bc1c78de6a9901cd9e241627c2c8e311fd306896b0e" }, { "name": "usr/share/zoneinfo/Asia/Aqtobe", "type": "reg", "size": 1033, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22898074, "NumLink": 0, "digest": "sha256:062a98f4317d5dc621baa9a377caedb8bc5c48163930d33a6ad8747f5d2a49a9" }, { "name": "usr/share/zoneinfo/Asia/Ashgabat", "type": "reg", "size": 637, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22898687, "NumLink": 0, "digest": "sha256:205016ab50f3a20f3cdae2177d7e52df062d8fe6f9512adbece19c877575ec58" }, { "name": "usr/share/zoneinfo/Asia/Ashkhabad", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Ashgabat", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Atyrau", "type": "reg", "size": 1011, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22899160, "NumLink": 0, "digest": "sha256:b8946a7b9d150a7179177c8ad06e98f1e283a3496116f4c258e14f16d256f737" }, { "name": "usr/share/zoneinfo/Asia/Baghdad", "type": "reg", "size": 990, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22899769, "NumLink": 0, "digest": "sha256:21e1a6fad8d08e442b3f0ac5a30f8424f06207083a804d14dea2026432d0a80b" }, { "name": "usr/share/zoneinfo/Asia/Bahrain", "type": "reg", "size": 211, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22900378, "NumLink": 0, "digest": "sha256:7bced891a18abd8ea443dd4f0c9d7dd40270fca879e9a116f573b9f73152d5e1" }, { "name": "usr/share/zoneinfo/Asia/Baku", "type": "reg", "size": 1255, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22900573, "NumLink": 0, "digest": "sha256:aeb15bd0c24d68422bff995167cb959c7b060475f6b814cb25b76cd9bafc7b14" }, { "name": "usr/share/zoneinfo/Asia/Bangkok", "type": "reg", "size": 206, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22901290, "NumLink": 0, "digest": "sha256:2417678a4ccd8a6d6ee3cebc6eaadb5991cfaed89d1fee3a4c7f3166a0eb14f4" }, { "name": "usr/share/zoneinfo/Asia/Barnaul", "type": "reg", "size": 1241, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22901493, "NumLink": 0, "digest": "sha256:5d6b63755c1e59a9b18197b85b39ec174a26cbd578a76aed38f5d43483c3fac2" }, { "name": "usr/share/zoneinfo/Asia/Beirut", "type": "reg", "size": 2175, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22902219, "NumLink": 0, "digest": "sha256:abdfa509ed982455873c1035962d8642ae8b88ab75f7f1a9a4cf7eea5ce120ef" }, { "name": "usr/share/zoneinfo/Asia/Bishkek", "type": "reg", "size": 1031, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22903399, "NumLink": 0, "digest": "sha256:3ea68d645187bc48c3a502d987750306c1c45660d889e2bc641c4f562726319c" }, { "name": "usr/share/zoneinfo/Asia/Brunei", "type": "reg", "size": 215, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22904019, "NumLink": 0, "digest": "sha256:f08de1917e19626c3ff34c1cab734a420b3dd4ec3a3446df12b8960f9c7a420f" }, { "name": "usr/share/zoneinfo/Asia/Calcutta", "type": "reg", "size": 312, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22904220, "NumLink": 0, "digest": "sha256:c71d7bc10d52c64f59eae8eac701c1b156bbec3fd9fe750970bed15e9b408fa5" }, { "name": "usr/share/zoneinfo/Asia/Chita", "type": "reg", "size": 1243, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22904515, "NumLink": 0, "digest": "sha256:f01ce6d6e72d33ebd2982f99e1070a057a8a4991c60445bfe60fd0963ff4e7e5" }, { "name": "usr/share/zoneinfo/Asia/Choibalsan", "type": "reg", "size": 977, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22905226, "NumLink": 0, "digest": "sha256:f8e8eb47d086dee4559a9db7cca2add3be302c98203b2fbb356e342c5978a480" }, { "name": "usr/share/zoneinfo/Asia/Chongqing", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Chungking", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Colombo", "type": "reg", "size": 399, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22905870, "NumLink": 0, "digest": "sha256:711f68dfe65cec6d99564f98f631d093bc2285e3829aeefea3692002eb45c6e4" }, { "name": "usr/share/zoneinfo/Asia/Dacca", "type": "reg", "size": 356, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22906154, "NumLink": 0, "digest": "sha256:829ff841289d431205ea745311f94fd3c32196a23d492f9f458617e0b5800c30" }, { "name": "usr/share/zoneinfo/Asia/Damascus", "type": "reg", "size": 2320, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22906436, "NumLink": 0, "digest": "sha256:0f42d5702ee52944dde43071569de645a5d668a385c4a2e0cd8aa43d39d2ea21" }, { "name": "usr/share/zoneinfo/Asia/Dhaka", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Dacca", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Dili", "type": "reg", "size": 239, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22907724, "NumLink": 0, "digest": "sha256:8f845da70d08bcd62be5a9d0d80420b08936bfbe1e3012ed18fdcf90f152b91f" }, { "name": "usr/share/zoneinfo/Asia/Dubai", "type": "reg", "size": 173, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22907941, "NumLink": 0, "digest": "sha256:ee6d427e4bc5e3d6d97b348d4b0cf666636d2ea95bcb117490d8d8ab0641f2ed" }, { "name": "usr/share/zoneinfo/Asia/Dushanbe", "type": "reg", "size": 607, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22908121, "NumLink": 0, "digest": "sha256:68f352f8356e69f25650cb2f25bc7ece7209ef85e73796ce974807136678f175" }, { "name": "usr/share/zoneinfo/Asia/Famagusta", "type": "reg", "size": 2042, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22908539, "NumLink": 0, "digest": "sha256:4a3e66759c060ff5d9e338169781678161df5b9acd9aec6146f1d4d3cfd9030b" }, { "name": "usr/share/zoneinfo/Asia/Gaza", "type": "reg", "size": 2295, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22909640, "NumLink": 0, "digest": "sha256:3a9df8fb70a5130a724e84221e63bb18cc84cf5c6c8788778bee070eb7330ea2" }, { "name": "usr/share/zoneinfo/Asia/Harbin", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Hebron", "type": "reg", "size": 2323, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22910928, "NumLink": 0, "digest": "sha256:93e1c96bff5d265217a68939ae160e86bbee16d96394d7c2b99589063435eea4" }, { "name": "usr/share/zoneinfo/Asia/Ho_Chi_Minh", "type": "reg", "size": 375, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22912197, "NumLink": 0, "digest": "sha256:23fb827e1435ea540aedbc7725a4ae82980205befe4aff833a0ad039dd14a73c" }, { "name": "usr/share/zoneinfo/Asia/Hong_Kong", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Hongkong", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Hovd", "type": "reg", "size": 907, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22912525, "NumLink": 0, "digest": "sha256:1561b7c3cc7a943046780584b726eaba320ccab4a46120b2c77af01dea9dfdf3" }, { "name": "usr/share/zoneinfo/Asia/Irkutsk", "type": "reg", "size": 1262, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22913088, "NumLink": 0, "digest": "sha256:102019f46d5e031cbc28520b08c080de899f5b1cadf93590787c1719e5a9dc4f" }, { "name": "usr/share/zoneinfo/Asia/Istanbul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Turkey", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Jakarta", "type": "reg", "size": 392, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22913851, "NumLink": 0, "digest": "sha256:7ea1c3e53a0d3f40cb6d7724f1bacb4fca1cf0ae96d9ab42f00f2d30dc0dee3a" }, { "name": "usr/share/zoneinfo/Asia/Jayapura", "type": "reg", "size": 251, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22914145, "NumLink": 0, "digest": "sha256:c6fa24de2e83f471878b8e10ecd68828eb3aba1f49ce462dac7721661386eb0c" }, { "name": "usr/share/zoneinfo/Asia/Jerusalem", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Israel", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Kabul", "type": "reg", "size": 215, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22914400, "NumLink": 0, "digest": "sha256:2df091b8e1752a8c8d402b12037977392347626a34c8f011f179ede4079ded1b" }, { "name": "usr/share/zoneinfo/Asia/Kamchatka", "type": "reg", "size": 1184, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22914607, "NumLink": 0, "digest": "sha256:c5d9b980d12e91cfea342560702708c488aabe957c1fc2b7afc6c996518bef33" }, { "name": "usr/share/zoneinfo/Asia/Karachi", "type": "reg", "size": 417, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22915300, "NumLink": 0, "digest": "sha256:fc4b2a68ad79efadecf52f333fa19cbaa5dd084cdc9bf96ab8b65a75c559a370" }, { "name": "usr/share/zoneinfo/Asia/Kashgar", "type": "reg", "size": 173, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22915608, "NumLink": 0, "digest": "sha256:f582157ddba6cf2bf93e8cd57ecd61318e9faa7fff2abbd0e2e7897690373587" }, { "name": "usr/share/zoneinfo/Asia/Kathmandu", "type": "reg", "size": 224, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22915789, "NumLink": 0, "digest": "sha256:b7d597ba6228a77823c20d3b48f343ad78843ee888b1b17a40b05ffcc0da3913" }, { "name": "usr/share/zoneinfo/Asia/Katmandu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Kathmandu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Khandyga", "type": "reg", "size": 1297, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22916034, "NumLink": 0, "digest": "sha256:762a1f42993920d6475e1ef40b46ab6dbc65b6f48ea9537387ce418929c21a3b" }, { "name": "usr/share/zoneinfo/Asia/Kolkata", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Calcutta", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Krasnoyarsk", "type": "reg", "size": 1229, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22916824, "NumLink": 0, "digest": "sha256:ec5d6603322f8e1a0d7e5d7a1cf798b66e5def66b2ae79bbc8c961e976ad4a6b" }, { "name": "usr/share/zoneinfo/Asia/Kuala_Lumpur", "type": "reg", "size": 410, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22917526, "NumLink": 0, "digest": "sha256:521d864f401ae2eae2e9f0292aeecf38d2d6daf3e12b442795ee696e629f3700" }, { "name": "usr/share/zoneinfo/Asia/Kuching", "type": "reg", "size": 507, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22917820, "NumLink": 0, "digest": "sha256:2b4cb8160273db177c6ddb669dd648162730ef1a1b62d60abff510e37444628e" }, { "name": "usr/share/zoneinfo/Asia/Kuwait", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Aden", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Macao", "type": "reg", "size": 771, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22918221, "NumLink": 0, "digest": "sha256:c2b8cdca155a78c7ae34ca5c30185713c60b2496b01cfd31f998bb6bda16f3ce" }, { "name": "usr/share/zoneinfo/Asia/Macau", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Macao", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Magadan", "type": "reg", "size": 1244, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22918757, "NumLink": 0, "digest": "sha256:d6f81d26a42303d75910f98033f0fc147eed23c574b016995fa002f5075a3fd6" }, { "name": "usr/share/zoneinfo/Asia/Makassar", "type": "reg", "size": 288, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22919466, "NumLink": 0, "digest": "sha256:24fac901695ef43b73fa8b3cd9e4bf893ceb757c5200b6628ae6a0fc70f01956" }, { "name": "usr/share/zoneinfo/Asia/Manila", "type": "reg", "size": 353, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22919696, "NumLink": 0, "digest": "sha256:1f1bc3dd4bac8e3da2ad11709b6882359c9821caced28b545d1b738524f3419b" }, { "name": "usr/share/zoneinfo/Asia/Muscat", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Dubai", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Nicosia", "type": "reg", "size": 2016, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22920037, "NumLink": 0, "digest": "sha256:f2aa2a3f77a43b7558a7508a6cd6c50fdf7d991f9d64da5948fd9003923b1d72" }, { "name": "usr/share/zoneinfo/Asia/Novokuznetsk", "type": "reg", "size": 1183, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22921136, "NumLink": 0, "digest": "sha256:ad7f74c0ace0cee04470ceb51df7f58321e23a002f3d3ac64ca0e889b3ab698c" }, { "name": "usr/share/zoneinfo/Asia/Novosibirsk", "type": "reg", "size": 1241, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22921832, "NumLink": 0, "digest": "sha256:fc386ed4132a37957acfba6984468588a1e9ff08e24bd5c15bf27ccba8a15a0b" }, { "name": "usr/share/zoneinfo/Asia/Omsk", "type": "reg", "size": 1229, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22922553, "NumLink": 0, "digest": "sha256:abaab5e651101ef99c5425ac184efc1b5d778d4c4c3c86aa894d9059dbe951b6" }, { "name": "usr/share/zoneinfo/Asia/Oral", "type": "reg", "size": 1025, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22923251, "NumLink": 0, "digest": "sha256:eacbd3df5ab43997cf2396786dc819f12461e61de06dd829ee8c8fa76baf7886" }, { "name": "usr/share/zoneinfo/Asia/Phnom_Penh", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangkok", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Pontianak", "type": "reg", "size": 395, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22923912, "NumLink": 0, "digest": "sha256:2516ac2bc84fe6498a50bc8865ec00e3499b38f2f485403cd5028578a98d1fd8" }, { "name": "usr/share/zoneinfo/Asia/Pyongyang", "type": "reg", "size": 267, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22924204, "NumLink": 0, "digest": "sha256:40434acc1dc1ac05a9ff3d3bb12448629ca45f7a415f03eb4b13f5416061d299" }, { "name": "usr/share/zoneinfo/Asia/Qatar", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bahrain", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Qyzylorda", "type": "reg", "size": 1033, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22924470, "NumLink": 0, "digest": "sha256:4530cb2e704a356eaa4aadcbf12e5faafd411ffe3210bd83ed3370d6876e8182" }, { "name": "usr/share/zoneinfo/Asia/Rangoon", "type": "reg", "size": 283, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22925083, "NumLink": 0, "digest": "sha256:95329208ae33f6298dbecd3309e6c397f4a0a42fd3bc214a87a3cbd6278c5752" }, { "name": "usr/share/zoneinfo/Asia/Riyadh", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Aden", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Saigon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Ho_Chi_Minh", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Sakhalin", "type": "reg", "size": 1220, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22925387, "NumLink": 0, "digest": "sha256:597a4d79d7ad4b2ecae1c5dbe53a19716cf30cfccd4fa7452c9e9822ca23ca03" }, { "name": "usr/share/zoneinfo/Asia/Samarkand", "type": "reg", "size": 605, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22926102, "NumLink": 0, "digest": "sha256:716675c5cb21a2ce4a48b9ce438744a501828079b06c80ce99a7dead0eeb2dc9" }, { "name": "usr/share/zoneinfo/Asia/Seoul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../ROK", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Shanghai", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Singapore", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Singapore", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Srednekolymsk", "type": "reg", "size": 1230, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22926617, "NumLink": 0, "digest": "sha256:84c8f7ebdb10b6720a01a11198c8b1fa1d1856f1bef11473d2c9a33b97f812a6" }, { "name": "usr/share/zoneinfo/Asia/Taipei", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../ROC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Tashkent", "type": "reg", "size": 621, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22927354, "NumLink": 0, "digest": "sha256:1cce3ce8c9cb736d9163691f4b6fabd2d2e076c7a209621a57bbc207973a8ef3" }, { "name": "usr/share/zoneinfo/Asia/Tbilisi", "type": "reg", "size": 1066, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22927779, "NumLink": 0, "digest": "sha256:b3da0a88ac9d5cf61c1e42ca1a941b36d83ecff5e9f819f80876512ddb07e0f1" }, { "name": "usr/share/zoneinfo/Asia/Tehran", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Iran", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Tel_Aviv", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Israel", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Thimbu", "type": "reg", "size": 215, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22928487, "NumLink": 0, "digest": "sha256:3912ba10af951b2d81f680dee0f89507c14cd7f38bcb9e55a87db48aaed01ab4" }, { "name": "usr/share/zoneinfo/Asia/Thimphu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Thimbu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Tokyo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Japan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Tomsk", "type": "reg", "size": 1241, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22928752, "NumLink": 0, "digest": "sha256:b41e5deff2d573ef6e76cf17e0f91ab467576d584b8e5ff5eba01e10f5dee92d" }, { "name": "usr/share/zoneinfo/Asia/Ujung_Pandang", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Makassar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Ulaanbaatar", "type": "reg", "size": 907, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22929528, "NumLink": 0, "digest": "sha256:aa2c8bbf2b6133470875236c95cbea9d75d369475cdb64ec3098781ae89ffe15" }, { "name": "usr/share/zoneinfo/Asia/Ulan_Bator", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Ulaanbaatar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Urumqi", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Kashgar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Ust-Nera", "type": "reg", "size": 1276, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22930166, "NumLink": 0, "digest": "sha256:3711785086a9e0d04a87c1591be40b3a0cd944ea3907182b6b45f6fceb0e024c" }, { "name": "usr/share/zoneinfo/Asia/Vientiane", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangkok", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Vladivostok", "type": "reg", "size": 1230, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22930941, "NumLink": 0, "digest": "sha256:2b86847acf51b50e5286e87efecf44cb0f2ea26735a6c9810623a814c4f69899" }, { "name": "usr/share/zoneinfo/Asia/Yakutsk", "type": "reg", "size": 1229, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22931636, "NumLink": 0, "digest": "sha256:350cb7d4232de1e621e9363412b75a161053bcc6510401b13cdd2405ddc867ac" }, { "name": "usr/share/zoneinfo/Asia/Yangon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Rangoon", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Asia/Yekaterinburg", "type": "reg", "size": 1267, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22932381, "NumLink": 0, "digest": "sha256:d36b87b5bbe9787ec26cecca1e9c2446c4126011ea2ae570b59138468f3f2f56" }, { "name": "usr/share/zoneinfo/Asia/Yerevan", "type": "reg", "size": 1199, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22933097, "NumLink": 0, "digest": "sha256:c595907a2d221300674badfb7c157198f862936331bc44bcfd6fb22ba953d05a" }, { "name": "usr/share/zoneinfo/Atlantic/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Atlantic/Azores", "type": "reg", "size": 3479, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22933829, "NumLink": 0, "digest": "sha256:c05864219d3fde7b5d5865bd1433a09f59a08da3980eb550666fdabf99634147" }, { "name": "usr/share/zoneinfo/Atlantic/Bermuda", "type": "reg", "size": 2004, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22935633, "NumLink": 0, "digest": "sha256:462d205904f32dcb79317f83ddb4dea1548d51849217dc3e42ba17c3cc7fcf08" }, { "name": "usr/share/zoneinfo/Atlantic/Canary", "type": "reg", "size": 1911, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22936737, "NumLink": 0, "digest": "sha256:4617cb1aa75514003f181908e9ccfc1d3d062ef22bb0196867dbe530ec2e1416" }, { "name": "usr/share/zoneinfo/Atlantic/Cape_Verde", "type": "reg", "size": 270, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22937762, "NumLink": 0, "digest": "sha256:0cf879a38c3443ff0cba02040a778ec7d07971ac3b43943f1e205c77afdd05bc" }, { "name": "usr/share/zoneinfo/Atlantic/Faeroe", "type": "reg", "size": 1829, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22937992, "NumLink": 0, "digest": "sha256:6b1a5769f8ffa2ec29bf298dffd7fb324e625e36fc527c14bb66b6520e6f76a7" }, { "name": "usr/share/zoneinfo/Atlantic/Faroe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Faeroe", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Atlantic/Jan_Mayen", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Arctic/Longyearbyen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Atlantic/Madeira", "type": "reg", "size": 3484, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22939064, "NumLink": 0, "digest": "sha256:24c616780589fb6a7e22913e3402522517ba4a7460738ccd38f1a3a0e4a21f40" }, { "name": "usr/share/zoneinfo/Atlantic/Reykjavik", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Iceland", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Atlantic/South_Georgia", "type": "reg", "size": 150, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22940919, "NumLink": 0, "digest": "sha256:64868e0ba919bae24ad2bd06290aef6200296c282cbc74d2d814a07a5e9342a0" }, { "name": "usr/share/zoneinfo/Atlantic/St_Helena", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Atlantic/Stanley", "type": "reg", "size": 1237, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22941164, "NumLink": 0, "digest": "sha256:53a20741ef1ef47a19fc9c192da23e9a0cf08c3f3b1fd72673d023dce0281890" }, { "name": "usr/share/zoneinfo/Australia/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Australia/ACT", "type": "reg", "size": 2223, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22941936, "NumLink": 0, "digest": "sha256:b540f8e21ed6a6b262336e0eb020c18ab43f283e9774613dd9864239523e4233" }, { "name": "usr/share/zoneinfo/Australia/Adelaide", "type": "reg", "size": 2238, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22943116, "NumLink": 0, "digest": "sha256:735476eef81652d7189574f8b7a11c942a986aba24b6ddc644fbebd1eb49245c" }, { "name": "usr/share/zoneinfo/Australia/Brisbane", "type": "reg", "size": 452, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22944338, "NumLink": 0, "digest": "sha256:74ac9f5d1d15ef0f6bd9e69c687b9047fb1f749c59279475685721f574b427cc" }, { "name": "usr/share/zoneinfo/Australia/Broken_Hill", "type": "reg", "size": 2274, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22944684, "NumLink": 0, "digest": "sha256:d6451675d3b5afb8572e2cbb4d381730da23daa3bfcb57601fe6f815985237db" }, { "name": "usr/share/zoneinfo/Australia/Canberra", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "ACT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Australia/Currie", "type": "reg", "size": 2223, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22945977, "NumLink": 0, "digest": "sha256:543c7afaebfdd907f8d637efce48bf41c407da72658b8e9c12f7208a54d1d84a" }, { "name": "usr/share/zoneinfo/Australia/Darwin", "type": "reg", "size": 323, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22947148, "NumLink": 0, "digest": "sha256:6172d8687a78608d884b04903d36053bdfb56433541930b2a42b405cbb62dc0b" }, { "name": "usr/share/zoneinfo/Australia/Eucla", "type": "reg", "size": 489, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22947450, "NumLink": 0, "digest": "sha256:73e13a985c1612b5881e45564bdf93c8f35a30298ee563dcf50d1cc35bf76a44" }, { "name": "usr/share/zoneinfo/Australia/Hobart", "type": "reg", "size": 2335, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22947817, "NumLink": 0, "digest": "sha256:de1bb5e82f86774e70082b906462e02a062238e5c4d76149566e21b1cb31b23a" }, { "name": "usr/share/zoneinfo/Australia/LHI", "type": "reg", "size": 1875, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22949038, "NumLink": 0, "digest": "sha256:3d35779f2c81370c90f29ba92693a409a094d84d9f236cccda8438d063fb6e5f" }, { "name": "usr/share/zoneinfo/Australia/Lindeman", "type": "reg", "size": 522, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22950087, "NumLink": 0, "digest": "sha256:663df35f044a15c743b9716e183595147d0c1838e99148a9473623ac82076bf9" }, { "name": "usr/share/zoneinfo/Australia/Lord_Howe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "LHI", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Australia/Melbourne", "type": "reg", "size": 2223, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22950514, "NumLink": 0, "digest": "sha256:272c1f13d01e35e6a58855cbb53878795451928adbf0c8ca2982b79db1f450a7" }, { "name": "usr/share/zoneinfo/Australia/NSW", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "ACT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Australia/North", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Darwin", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Australia/Perth", "type": "reg", "size": 479, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22951747, "NumLink": 0, "digest": "sha256:4ecd4a085ca9ec5b7903016c2d4e311276024a2bcd0c35d40281658e48421f93" }, { "name": "usr/share/zoneinfo/Australia/Queensland", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Brisbane", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Australia/South", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Adelaide", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Australia/Sydney", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "ACT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Australia/Tasmania", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Hobart", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Australia/Victoria", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Melbourne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Australia/West", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Perth", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Australia/Yancowinna", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Broken_Hill", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Brazil/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Brazil/Acre", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Porto_Acre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Brazil/DeNoronha", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Noronha", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Brazil/East", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Sao_Paulo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Brazil/West", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Manaus", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/CET", "type": "reg", "size": 2102, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22952449, "NumLink": 0, "digest": "sha256:3c0029045f6f80bc5a84f1bb8ed36230454759c54578eb9a8c195d14f442213c" }, { "name": "usr/share/zoneinfo/CST6CDT", "type": "reg", "size": 2294, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22953547, "NumLink": 0, "digest": "sha256:44e8b569e60027647f9801a33d0b43be0106a6d3f6cd059677e0ed65c9b8b831" }, { "name": "usr/share/zoneinfo/Canada/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Canada/Atlantic", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Halifax", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Canada/Central", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Winnipeg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Canada/Eastern", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Montreal", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Canada/Mountain", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Edmonton", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Canada/Newfoundland", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/St_Johns", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Canada/Pacific", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Vancouver", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Canada/Saskatchewan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Regina", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Canada/Yukon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Whitehorse", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Chile/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Chile/Continental", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Santiago", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Chile/EasterIsland", "type": "reg", "size": 2228, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22955143, "NumLink": 0, "digest": "sha256:c0632af9cba4869ddc8dbfdd78fdc6094d751d0e1d54564e380bad0ff6cbcaf7" }, { "name": "usr/share/zoneinfo/Cuba", "type": "reg", "size": 2437, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22956340, "NumLink": 0, "digest": "sha256:7871f875a8819f415c292519db1590556a0dc1a6ce691bf4f7af55e6716fb894" }, { "name": "usr/share/zoneinfo/EET", "type": "reg", "size": 1876, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22957640, "NumLink": 0, "digest": "sha256:0bf6d2669ab45c13a1c9be47c351972feb671770b90a61d9d313fc60b721b2b4" }, { "name": "usr/share/zoneinfo/EST", "type": "reg", "size": 127, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22958639, "NumLink": 0, "digest": "sha256:c9e75f112a498ff00344551c3c5c4a62bd15d5c218ee951f4363ab218c5d88eb" }, { "name": "usr/share/zoneinfo/EST5EDT", "type": "reg", "size": 2294, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22958790, "NumLink": 0, "digest": "sha256:79ce27e03a2752091e8a49cc7e7ccc9ac202d6c52dd5d224571fe82262fbeec8" }, { "name": "usr/share/zoneinfo/Egypt", "type": "reg", "size": 1972, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22960019, "NumLink": 0, "digest": "sha256:279bbe1fa62da67387c63593b60bb655252ef5c8f189cf43469087740af2b4fc" }, { "name": "usr/share/zoneinfo/Eire", "type": "reg", "size": 3531, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22961121, "NumLink": 0, "digest": "sha256:44bdc5d63e5b1663867491cc0d30b81820fc8694ad0fd5ef500ba8ac6b7fba5f" }, { "name": "usr/share/zoneinfo/Etc/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Etc/GMT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Etc/GMT+0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Etc/GMT+1", "type": "reg", "size": 129, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22963015, "NumLink": 0, "digest": "sha256:f549f85e4a86989da1b3c592cd455d6846f8103c2c1c7c7d193b3e29de92efc9" }, { "name": "usr/share/zoneinfo/Etc/GMT+10", "type": "reg", "size": 130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22963173, "NumLink": 0, "digest": "sha256:4b331f62b7c4dd05398fe87517e824152a0faa3ffe80d73e3f1b2bab03e16c99" }, { "name": "usr/share/zoneinfo/Etc/GMT+11", "type": "reg", "size": 130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22963331, "NumLink": 0, "digest": "sha256:3be86f06310b626b26b42bee3b8ba37be7b836927e204fa7b84e35758e99dce1" }, { "name": "usr/share/zoneinfo/Etc/GMT+12", "type": "reg", "size": 130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22963489, "NumLink": 0, "digest": "sha256:bb3cf7591690fd770967c92719c1ba023f62a7e40de886f89f57178b0faaf616" }, { "name": "usr/share/zoneinfo/Etc/GMT+2", "type": "reg", "size": 129, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22963644, "NumLink": 0, "digest": "sha256:ae3b221ddd94a88c94c3a069b042c1b06d2718b5bbe6903724110103621e40c5" }, { "name": "usr/share/zoneinfo/Etc/GMT+3", "type": "reg", "size": 129, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22963799, "NumLink": 0, "digest": "sha256:6cdb1f7a18e6008da4e9a72ac9c2be59a26bc03109700b3ec64e4ed8161660db" }, { "name": "usr/share/zoneinfo/Etc/GMT+4", "type": "reg", "size": 129, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22963956, "NumLink": 0, "digest": "sha256:b4c86cac6e9f40dfdbec05b88a38eea2463fe92f1fff80a6e24ff15a9814218f" }, { "name": "usr/share/zoneinfo/Etc/GMT+5", "type": "reg", "size": 129, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22964113, "NumLink": 0, "digest": "sha256:a6653c6b0ba94d0c0bd4b8a6f4c69d001db916f93c0723b9c9fcbbaa34bba098" }, { "name": "usr/share/zoneinfo/Etc/GMT+6", "type": "reg", "size": 129, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22964270, "NumLink": 0, "digest": "sha256:c4a801cd93bdec1b9341b334868ef1ccaeb01b74a31a9f5bb1f1da90ea985789" }, { "name": "usr/share/zoneinfo/Etc/GMT+7", "type": "reg", "size": 129, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22964427, "NumLink": 0, "digest": "sha256:9456c866abdf01fde371357edb5ec59d0c5adc3c09ed9d2bbafd0be21807adad" }, { "name": "usr/share/zoneinfo/Etc/GMT+8", "type": "reg", "size": 129, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22964584, "NumLink": 0, "digest": "sha256:7084ca1e2d9a7349e0556d8c63107fdc64cb5d50778cc74b4b9ea3d2ca1eeb43" }, { "name": "usr/share/zoneinfo/Etc/GMT+9", "type": "reg", "size": 129, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22964740, "NumLink": 0, "digest": "sha256:847ded37313ae7de90d5dec700acf7d229ad88cc7462e9527ac5bb37cd2c00ac" }, { "name": "usr/share/zoneinfo/Etc/GMT-0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Etc/GMT-1", "type": "reg", "size": 130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22964928, "NumLink": 0, "digest": "sha256:355d77cdeed83884c287b29454078b89865d4e56508dd71e8597c8c038029ade" }, { "name": "usr/share/zoneinfo/Etc/GMT-10", "type": "reg", "size": 131, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22965086, "NumLink": 0, "digest": "sha256:4653c5c305ed3a46ac02c471feb310f356ed6c8d2465fd37e555132b0004899c" }, { "name": "usr/share/zoneinfo/Etc/GMT-11", "type": "reg", "size": 131, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22965245, "NumLink": 0, "digest": "sha256:b65fdb39373fa4c47b1e6a2105931e5459fdceaa74194ea737dd981527e5a1a5" }, { "name": "usr/share/zoneinfo/Etc/GMT-12", "type": "reg", "size": 131, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22965404, "NumLink": 0, "digest": "sha256:f67b770d0224c9dbf776e8bc913c0dc462af7eb90f04b88b7387af662c248545" }, { "name": "usr/share/zoneinfo/Etc/GMT-13", "type": "reg", "size": 131, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22965561, "NumLink": 0, "digest": "sha256:551aebd6c58a89bbc34283170a01c5de12d98ca658aee39f68e8ed7cf11dd872" }, { "name": "usr/share/zoneinfo/Etc/GMT-14", "type": "reg", "size": 131, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22965720, "NumLink": 0, "digest": "sha256:414d785a776406dce6ccf450aa2ae48c4d3e4db23482ac3cc285567c0624b33f" }, { "name": "usr/share/zoneinfo/Etc/GMT-2", "type": "reg", "size": 130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22965878, "NumLink": 0, "digest": "sha256:6a4f02622392c0c01ad74aacdd1d9835949b10084b6ff3494ca593871fa36279" }, { "name": "usr/share/zoneinfo/Etc/GMT-3", "type": "reg", "size": 130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22966033, "NumLink": 0, "digest": "sha256:2331d90cf59bd06209da3f57fe71f8eeff4f9987cda8f209f7d19605173c7940" }, { "name": "usr/share/zoneinfo/Etc/GMT-4", "type": "reg", "size": 130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22966190, "NumLink": 0, "digest": "sha256:3d1d2a77c8fc7121113f50455ab5ecf7a83af5d100b1665c069ad2283beedd05" }, { "name": "usr/share/zoneinfo/Etc/GMT-5", "type": "reg", "size": 130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22966347, "NumLink": 0, "digest": "sha256:a998fef5ca21deb83d7b6801cecb36f851af7d09e45b23f1a8e1cab037c94cd2" }, { "name": "usr/share/zoneinfo/Etc/GMT-6", "type": "reg", "size": 130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22966504, "NumLink": 0, "digest": "sha256:59a432b594fd6a1775aaf1798ffded3e325481040786cf56500d61194d156b1d" }, { "name": "usr/share/zoneinfo/Etc/GMT-7", "type": "reg", "size": 130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22966661, "NumLink": 0, "digest": "sha256:6b8fd7cee7b9e0ac90f11617a6e4f0c68cda81a2153a0b37a46a3516f94c3e1a" }, { "name": "usr/share/zoneinfo/Etc/GMT-8", "type": "reg", "size": 130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22966818, "NumLink": 0, "digest": "sha256:47625566b0b8e5476810ac5fe4882586ec53793d4f53ed281702a220eee7d554" }, { "name": "usr/share/zoneinfo/Etc/GMT-9", "type": "reg", "size": 130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22966975, "NumLink": 0, "digest": "sha256:2f4662e616bd94e9eb6a2ed069f01bdf316b3e2c39c3b945e5397a53e26d16c4" }, { "name": "usr/share/zoneinfo/Etc/GMT0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Etc/Greenwich", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Etc/UCT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../UCT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Etc/UTC", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Etc/Universal", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Etc/Zulu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Amsterdam", "type": "reg", "size": 2949, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22967288, "NumLink": 0, "digest": "sha256:8a813ac6b8d1b68a7960242cae5325a2269fd1c791b203f8d22f2dfa3b61ba87" }, { "name": "usr/share/zoneinfo/Europe/Andorra", "type": "reg", "size": 1751, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22968805, "NumLink": 0, "digest": "sha256:add5505c473225e33a884a02105610a9b95003f429195624b953c18f771317af" }, { "name": "usr/share/zoneinfo/Europe/Astrakhan", "type": "reg", "size": 1183, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22969765, "NumLink": 0, "digest": "sha256:08873fa11e5ab238e56d7a2fbbfb0876aa3ea0b71ee8ce95b0d5d394be923514" }, { "name": "usr/share/zoneinfo/Europe/Athens", "type": "reg", "size": 2271, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22970465, "NumLink": 0, "digest": "sha256:799090551202c0b8417f836facf75049573dd1c27b5e6adeb584fcc414051139" }, { "name": "usr/share/zoneinfo/Europe/Belfast", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Belgrade", "type": "reg", "size": 1957, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22971711, "NumLink": 0, "digest": "sha256:e957543623baaba84999b40188e7e0948471b75a8ff4f88abb267e773feb8e5c" }, { "name": "usr/share/zoneinfo/Europe/Berlin", "type": "reg", "size": 2335, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22972765, "NumLink": 0, "digest": "sha256:7eb93dcba603d528fdf536160ef6911c16f834afcf88ce23a382b97ff28319d4" }, { "name": "usr/share/zoneinfo/Europe/Bratislava", "type": "reg", "size": 2338, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22973995, "NumLink": 0, "digest": "sha256:a50be470a22de9def3e4fec7bcd95d5d7e24e5b11edf448a82b04d19da3d3e52" }, { "name": "usr/share/zoneinfo/Europe/Brussels", "type": "reg", "size": 2970, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22975270, "NumLink": 0, "digest": "sha256:f372a903a6a57da43a6f500d6aceccfc74e800d7dfe88a7eaf56ca2564557e66" }, { "name": "usr/share/zoneinfo/Europe/Bucharest", "type": "reg", "size": 2221, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22976855, "NumLink": 0, "digest": "sha256:3b3a0017333b2f466e59c8ac3dc0cf7aa4f0a4608040a3180f752b19d6a93526" }, { "name": "usr/share/zoneinfo/Europe/Budapest", "type": "reg", "size": 2405, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22978053, "NumLink": 0, "digest": "sha256:b67f2c4690a87f294ea5d35ae3967c8aa8bde227aeb36c3877285e4e94a17418" }, { "name": "usr/share/zoneinfo/Europe/Busingen", "type": "reg", "size": 1918, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22979324, "NumLink": 0, "digest": "sha256:bc45f8c6c8190477cdaae46f77059fab74fde92a02fc57b733f07cb9a55e98a3" }, { "name": "usr/share/zoneinfo/Europe/Chisinau", "type": "reg", "size": 2445, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22980397, "NumLink": 0, "digest": "sha256:5749f01c78d0c2fd50d0dc2280c1957ce0419edbfc7c4073c67e6da78153d8c8" }, { "name": "usr/share/zoneinfo/Europe/Copenhagen", "type": "reg", "size": 2160, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22981687, "NumLink": 0, "digest": "sha256:d2d9a359ef02d2afe293f429c4fd60fc04fbf8d1d8343c9b224dcfc116c011a8" }, { "name": "usr/share/zoneinfo/Europe/Dublin", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Eire", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Gibraltar", "type": "reg", "size": 3061, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22982916, "NumLink": 0, "digest": "sha256:c79088f67ba5d3fa9ad989bd573bfdef0e86c89e310ea70bc3e01e14dca1075e" }, { "name": "usr/share/zoneinfo/Europe/Guernsey", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Helsinki", "type": "reg", "size": 1909, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22984560, "NumLink": 0, "digest": "sha256:ed7d89fae1fb40a9582edd7e03ed02d7fe81ba456b9c1ed8d6ee5f0b931aad45" }, { "name": "usr/share/zoneinfo/Europe/Isle_of_Man", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Istanbul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Turkey", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Jersey", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Kaliningrad", "type": "reg", "size": 1518, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22985701, "NumLink": 0, "digest": "sha256:450a2c6ff69d262b5c5d8ef584464e9c8274b389a1c39b7abc5aa70608d29425" }, { "name": "usr/share/zoneinfo/Europe/Kiev", "type": "reg", "size": 2097, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22986542, "NumLink": 0, "digest": "sha256:242912df3212e0725ded4aab25fd869c52f13c3ce619764a883adcbbd937afc5" }, { "name": "usr/share/zoneinfo/Europe/Kirov", "type": "reg", "size": 1153, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22987671, "NumLink": 0, "digest": "sha256:d562c884fcbbde25ad884da464c7f981296c2c4e13b3b7c1d3c322b82bd4f726" }, { "name": "usr/share/zoneinfo/Europe/Lisbon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Portugal", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Ljubljana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/London", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Luxembourg", "type": "reg", "size": 2974, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22988462, "NumLink": 0, "digest": "sha256:90b76259274c78a40f34aa5b58545b5409edfbba2fd08efa1b300896cb4062ee" }, { "name": "usr/share/zoneinfo/Europe/Madrid", "type": "reg", "size": 2637, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22989991, "NumLink": 0, "digest": "sha256:74103ad1e48f71f4cd9b6d1c03dcd97b58d87bb8affb02b1d6967b204036ebd6" }, { "name": "usr/share/zoneinfo/Europe/Malta", "type": "reg", "size": 2629, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22991364, "NumLink": 0, "digest": "sha256:7c4134c8d37bd159e31fd739e8b1b8203a9f3023788bd9c83b8109e361eee5d5" }, { "name": "usr/share/zoneinfo/Europe/Mariehamn", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Helsinki", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Minsk", "type": "reg", "size": 1356, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22992812, "NumLink": 0, "digest": "sha256:0d0535cb101110d8fbb1238dde8444e980fab90bbdc8402371cc6ab5caa1a96c" }, { "name": "usr/share/zoneinfo/Europe/Monaco", "type": "reg", "size": 2953, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22993582, "NumLink": 0, "digest": "sha256:7c723359888417b86a66a609ffdd0becf81673cbb3e8b011131088b4d26f6bcd" }, { "name": "usr/share/zoneinfo/Europe/Moscow", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../W-SU", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Nicosia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Asia/Nicosia", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Oslo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Arctic/Longyearbyen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Paris", "type": "reg", "size": 2971, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22995220, "NumLink": 0, "digest": "sha256:735b08e2737de2b47e79f596f3574b5a9e9019e56d2ead0cdc17c0b29e84a585" }, { "name": "usr/share/zoneinfo/Europe/Podgorica", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Prague", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bratislava", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Riga", "type": "reg", "size": 2235, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22996819, "NumLink": 0, "digest": "sha256:79d10debbaa2743458d0dec1fb71d3c576cea80d245f84819da82a25d93c1401" }, { "name": "usr/share/zoneinfo/Europe/Rome", "type": "reg", "size": 2692, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22998013, "NumLink": 0, "digest": "sha256:3eff2ef2cdc67e2f5cfd44866cdb4d448956b89eae8b0e37f63126f2068ee889" }, { "name": "usr/share/zoneinfo/Europe/Samara", "type": "reg", "size": 1239, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 22999495, "NumLink": 0, "digest": "sha256:24506ef1ada9839602c5d6589f46c16ba427e1e310c473f0ec77f4436b973185" }, { "name": "usr/share/zoneinfo/Europe/San_Marino", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Rome", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Sarajevo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Saratov", "type": "reg", "size": 1183, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23000281, "NumLink": 0, "digest": "sha256:4ad0f06f89a5b7ef2abd7d249300cd31328bfed591f3a6a7acede6bb8c0b7977" }, { "name": "usr/share/zoneinfo/Europe/Simferopol", "type": "reg", "size": 1490, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23000978, "NumLink": 0, "digest": "sha256:b1ee6f714fd88fd61fef6df54f95abacb80dd3036c25e9a10708fec9b11c34cf" }, { "name": "usr/share/zoneinfo/Europe/Skopje", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Sofia", "type": "reg", "size": 2130, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23001878, "NumLink": 0, "digest": "sha256:16813fb30f2ebb782a806ce0664014ddfbf921890d32ec3d1398bd182bf9245c" }, { "name": "usr/share/zoneinfo/Europe/Stockholm", "type": "reg", "size": 1918, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23003096, "NumLink": 0, "digest": "sha256:07b242f9e3d8150663bfaf417fe7d209927fc299fac487789b70841956c35335" }, { "name": "usr/share/zoneinfo/Europe/Tallinn", "type": "reg", "size": 2187, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23004161, "NumLink": 0, "digest": "sha256:e3c4ba916c25500c709c56395c040abad62a834fafaf5163a89974b7f66b019a" }, { "name": "usr/share/zoneinfo/Europe/Tirane", "type": "reg", "size": 2098, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23005327, "NumLink": 0, "digest": "sha256:62dbc606a32a5f50ceca86c6f96d088ea689bced60a1623c986f045cde9c730a" }, { "name": "usr/share/zoneinfo/Europe/Tiraspol", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Chisinau", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Ulyanovsk", "type": "reg", "size": 1267, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23006502, "NumLink": 0, "digest": "sha256:0d96c23e54ab8bcae4174fe792f1c00e4158f81a5b98039121e6502ce6686716" }, { "name": "usr/share/zoneinfo/Europe/Uzhgorod", "type": "reg", "size": 2103, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23007229, "NumLink": 0, "digest": "sha256:098575b4ec6599758c85bcad8dd21d89bca213a9f890c0ead6defd14878705f3" }, { "name": "usr/share/zoneinfo/Europe/Vaduz", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Busingen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Vatican", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Rome", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Vienna", "type": "reg", "size": 2237, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23008430, "NumLink": 0, "digest": "sha256:be42c32ad7c54f15dcf5dd9425e289fd20bebe986e5e8c240a11dfeec46550f7" }, { "name": "usr/share/zoneinfo/Europe/Vilnius", "type": "reg", "size": 2199, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23009609, "NumLink": 0, "digest": "sha256:75adc0a906b39e283f5e5020984a36f34b4f58ef1d3099efbc899ff07f035f7e" }, { "name": "usr/share/zoneinfo/Europe/Volgograd", "type": "reg", "size": 1153, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23010776, "NumLink": 0, "digest": "sha256:4b826a3d9cdffa786e46da2315977f13cac9ce01e4b214415f3362505b97fdd1" }, { "name": "usr/share/zoneinfo/Europe/Warsaw", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Poland", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Zagreb", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Europe/Zaporozhye", "type": "reg", "size": 2115, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23011522, "NumLink": 0, "digest": "sha256:b6c5127b52518818e3b4211e89e5e1e9a479cca65f7763a0afb145d512c38e34" }, { "name": "usr/share/zoneinfo/Europe/Zurich", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Busingen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Factory", "type": "reg", "size": 129, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23012709, "NumLink": 0, "digest": "sha256:ce4929e887a3f9f403d15e734f7798028addf502e767e7da09b8c837e7bd9bbd" }, { "name": "usr/share/zoneinfo/GB", "type": "reg", "size": 3687, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23012854, "NumLink": 0, "digest": "sha256:b14c486019e3cb259cf8235a0d6a4bc3ff6cfa726a165f1ea2df403c8ae31b86" }, { "name": "usr/share/zoneinfo/GB-Eire", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/GMT", "type": "reg", "size": 127, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23014784, "NumLink": 0, "digest": "sha256:d7b39879094135d13efd282937690b43f48bb53597ce3e78697f48dcceaeb3ec" }, { "name": "usr/share/zoneinfo/GMT+0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/GMT-0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/GMT0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Greenwich", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/HST", "type": "reg", "size": 128, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23015004, "NumLink": 0, "digest": "sha256:44048bf7df61bdcf45972c13426b039f0d34d80947d60a2603183b3b6be4027f" }, { "name": "usr/share/zoneinfo/Hongkong", "type": "reg", "size": 1189, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23015158, "NumLink": 0, "digest": "sha256:9786fbe4ad9b820f61a5664b3b85dd601aa6e9152c93ff4e14bd54effdf8f1d5" }, { "name": "usr/share/zoneinfo/Iceland", "type": "reg", "size": 1188, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23015865, "NumLink": 0, "digest": "sha256:9cdcea6aa1eed8276d3f6620e0c0ffae9cfcc3722c443ea6ba39147975eafaa3" }, { "name": "usr/share/zoneinfo/Indian/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Indian/Antananarivo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Indian/Chagos", "type": "reg", "size": 211, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23016657, "NumLink": 0, "digest": "sha256:1b1797b71359a3a9fd49683dd9028692c20b4c9b56088c50de6ae122f075f3d1" }, { "name": "usr/share/zoneinfo/Indian/Christmas", "type": "reg", "size": 151, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23016859, "NumLink": 0, "digest": "sha256:720ed3c1a13aa4e6b4a9acb7c6f017a5e28e20507169ce1b3ec25075c98be656" }, { "name": "usr/share/zoneinfo/Indian/Cocos", "type": "reg", "size": 160, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23017045, "NumLink": 0, "digest": "sha256:b78aea130d938147f36de61341c44388915da43f467f3723c98dcc3d8b808884" }, { "name": "usr/share/zoneinfo/Indian/Comoro", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Indian/Kerguelen", "type": "reg", "size": 173, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23017295, "NumLink": 0, "digest": "sha256:29bc1cca3de7cf37433fcee5ec99d490abf20c767f284d5bb40a15feac0ad398" }, { "name": "usr/share/zoneinfo/Indian/Mahe", "type": "reg", "size": 173, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23017469, "NumLink": 0, "digest": "sha256:aed7dcefc4d7a4659ef1a62e56d1dd6f21cf0e9cea7a1089a94ac1d48113d5fe" }, { "name": "usr/share/zoneinfo/Indian/Maldives", "type": "reg", "size": 206, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23017651, "NumLink": 0, "digest": "sha256:49fa18af1a1c531f2a63bffc82e4cba7c53f4e587376f453c97084d605d4a9f1" }, { "name": "usr/share/zoneinfo/Indian/Mauritius", "type": "reg", "size": 253, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23017858, "NumLink": 0, "digest": "sha256:25c927943cddfb96e41b9bfa014791a9375f8cb77e672f42d72fc81d83607f0c" }, { "name": "usr/share/zoneinfo/Indian/Mayotte", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Indian/Reunion", "type": "reg", "size": 173, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23018144, "NumLink": 0, "digest": "sha256:263f52802a6b69445a66bb8d75a4ca3dfe717ce6512d7e2501466e7a1b6d56a3" }, { "name": "usr/share/zoneinfo/Iran", "type": "reg", "size": 1704, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23018313, "NumLink": 0, "digest": "sha256:19084f9dda0e334eb24bd8ff70daedffefd64c537cb27e5a54c5df7694c534d5" }, { "name": "usr/share/zoneinfo/Israel", "type": "reg", "size": 2265, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23019248, "NumLink": 0, "digest": "sha256:60019ee0d1deb6e6994a1a5c951861e1db9f992a5c027fbc4e3617f942c021cf" }, { "name": "usr/share/zoneinfo/Jamaica", "type": "reg", "size": 507, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23020475, "NumLink": 0, "digest": "sha256:addb98caf3459bb75d6e14ed76aa66e642bead2d067e7fe81814a4f02cf13503" }, { "name": "usr/share/zoneinfo/Japan", "type": "reg", "size": 318, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23020841, "NumLink": 0, "digest": "sha256:4d598cea3fe55b44afbd9c6f603f748960e4a9806e1ea1e87fc2f2bb98214377" }, { "name": "usr/share/zoneinfo/Kwajalein", "type": "reg", "size": 245, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23021102, "NumLink": 0, "digest": "sha256:728eed0b199aa19468fe7f1dd887fe7f0c3a659a897741aa6e2d4f5b80f75eb5" }, { "name": "usr/share/zoneinfo/Libya", "type": "reg", "size": 655, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23021318, "NumLink": 0, "digest": "sha256:8ff53f7072863fb56f1e71339392b6de7e50675efa4333b9e032b677c9c9a527" }, { "name": "usr/share/zoneinfo/MET", "type": "reg", "size": 2102, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23021774, "NumLink": 0, "digest": "sha256:1fff331a4414e98097d33bec1a9bbf2a155d991b57acd1bb4c11f8559fb4e514" }, { "name": "usr/share/zoneinfo/MST", "type": "reg", "size": 127, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23022868, "NumLink": 0, "digest": "sha256:f8fb610056087bb3ca8ecf5cdcb5305c1652b649fde512f606b9ee1b3556fb9e" }, { "name": "usr/share/zoneinfo/MST7MDT", "type": "reg", "size": 2294, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23023019, "NumLink": 0, "digest": "sha256:85452d031526621178e9b24c91af69b7ecc30df47036669378956135c4e735d0" }, { "name": "usr/share/zoneinfo/Mexico/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Mexico/BajaNorte", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Ensenada", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Mexico/BajaSur", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Mazatlan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Mexico/General", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Mexico_City", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/NZ", "type": "reg", "size": 2460, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23024405, "NumLink": 0, "digest": "sha256:d7b5175387ac78e29f7b9021e411512756be283ed3d1819942ef5d45ecf338e4" }, { "name": "usr/share/zoneinfo/NZ-CHAT", "type": "reg", "size": 2073, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23025679, "NumLink": 0, "digest": "sha256:b8f1a26d43eeecaf8302456d69fdf047b847b6973069804c5a39f8ecb886d74c" }, { "name": "usr/share/zoneinfo/Navajo", "type": "reg", "size": 2453, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23026786, "NumLink": 0, "digest": "sha256:f4df3cc74c79d070a25a7927744d3a422a05d862a9a234a12105c5c964efb22d" }, { "name": "usr/share/zoneinfo/PRC", "type": "reg", "size": 414, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23028092, "NumLink": 0, "digest": "sha256:953622bbd7eb9eba8c3b9e8cd5d5ec98cea6a085a9deb1c43e49e889a154d344" }, { "name": "usr/share/zoneinfo/PST8PDT", "type": "reg", "size": 2294, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23028413, "NumLink": 0, "digest": "sha256:4d8e69bd43e8d71f0f58e115593814d68c1a6aa441255b17b3e9a92a9d6efc46" }, { "name": "usr/share/zoneinfo/Pacific/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Pacific/Apia", "type": "reg", "size": 1120, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23029687, "NumLink": 0, "digest": "sha256:171011084ad201170e51b42435679a50bab661ff6114ca09a764e822f13f45db" }, { "name": "usr/share/zoneinfo/Pacific/Auckland", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../NZ", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Pacific/Bougainville", "type": "reg", "size": 282, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23030404, "NumLink": 0, "digest": "sha256:35e0203bf554d7ccf0b4e0176829aa342747427924ae9e9b661e484205e828e2" }, { "name": "usr/share/zoneinfo/Pacific/Chatham", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../NZ-CHAT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Pacific/Chuuk", "type": "reg", "size": 152, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23030725, "NumLink": 0, "digest": "sha256:6efbcffeaffabb8b91c03e12dd02707f3b2f12ed6c4583ede4d8d6b72721c4fc" }, { "name": "usr/share/zoneinfo/Pacific/Easter", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Chile/EasterIsland", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Pacific/Efate", "type": "reg", "size": 478, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23030964, "NumLink": 0, "digest": "sha256:adbee8a8544a400050d7dce148e2c10a785b9120c755a69a674395b04c36092e" }, { "name": "usr/share/zoneinfo/Pacific/Enderbury", "type": "reg", "size": 245, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23031328, "NumLink": 0, "digest": "sha256:dab23f777b9cb06d602bcd5de7670da9191830816d802041846132e137f7eae6" }, { "name": "usr/share/zoneinfo/Pacific/Fakaofo", "type": "reg", "size": 207, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23031556, "NumLink": 0, "digest": "sha256:0427f848089402d7105907710ec0a9096365b10d1dd3ee015edc5da527e1c3de" }, { "name": "usr/share/zoneinfo/Pacific/Fiji", "type": "reg", "size": 1076, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23031762, "NumLink": 0, "digest": "sha256:7281ebcc865b2c2712ac51b6f4654543a99ddce68ad42ea7bca0105b825e3a94" }, { "name": "usr/share/zoneinfo/Pacific/Funafuti", "type": "reg", "size": 152, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23032435, "NumLink": 0, "digest": "sha256:7fae086ba7234a7684b22e8948faec02be41bb76b3944213206d1857b049ba1a" }, { "name": "usr/share/zoneinfo/Pacific/Galapagos", "type": "reg", "size": 254, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23032625, "NumLink": 0, "digest": "sha256:c91721b38d5ee01676190b91cf5150050b3fed2ad4634816724f8207d69877be" }, { "name": "usr/share/zoneinfo/Pacific/Gambier", "type": "reg", "size": 172, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23032851, "NumLink": 0, "digest": "sha256:5008ae162414c442be54580de29eb211a9f652f8eda265f038a6a82eddd5e5d2" }, { "name": "usr/share/zoneinfo/Pacific/Guadalcanal", "type": "reg", "size": 174, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23033038, "NumLink": 0, "digest": "sha256:69ec8cb3bd0e92db41f2d7b9ffcdd1881d0f7b7ee6048d3f092ad17cc686e5a5" }, { "name": "usr/share/zoneinfo/Pacific/Guam", "type": "reg", "size": 225, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23033218, "NumLink": 0, "digest": "sha256:6613576ebdf4d9d6be5eb849539d3f74a4fb137acf6bcf8cda20d28e5c612e77" }, { "name": "usr/share/zoneinfo/Pacific/Honolulu", "type": "reg", "size": 276, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23033439, "NumLink": 0, "digest": "sha256:88885824bf915a9a6f39a7030798da825e34be79d1b35c2444696a81c159f2e8" }, { "name": "usr/share/zoneinfo/Pacific/Johnston", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Honolulu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Pacific/Kiritimati", "type": "reg", "size": 249, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23033735, "NumLink": 0, "digest": "sha256:43d21c8bf4a0547479d1512db27d5dd7d8b2db69ee232680a88863c3e446bd42" }, { "name": "usr/share/zoneinfo/Pacific/Kosrae", "type": "reg", "size": 237, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23033959, "NumLink": 0, "digest": "sha256:dd24709003b34eca2e8975694b370b5892dc8a1560892e42fa5c3a9669dc00b9" }, { "name": "usr/share/zoneinfo/Pacific/Kwajalein", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Kwajalein", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Pacific/Majuro", "type": "reg", "size": 207, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23034217, "NumLink": 0, "digest": "sha256:2784fe14ae4b06d84b54e2ef9195ee8fcd33a1151ae9d92b2b144ed80324c4ec" }, { "name": "usr/share/zoneinfo/Pacific/Marquesas", "type": "reg", "size": 181, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23034425, "NumLink": 0, "digest": "sha256:c1c151ea927de5f087bab64d962d1bf4c8af0672fb66dab9eb63e93c5c0ce906" }, { "name": "usr/share/zoneinfo/Pacific/Midway", "type": "reg", "size": 196, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23034611, "NumLink": 0, "digest": "sha256:7218a2ae386cd5e8981a940f6b56f6f9b60a65f3e3bd2ec1fe6c9d43bac4db1a" }, { "name": "usr/share/zoneinfo/Pacific/Nauru", "type": "reg", "size": 268, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23034809, "NumLink": 0, "digest": "sha256:8eabc930825033369d3dd4d85d1cab23b40c0214c91a3a2cac6547a2d549b8c2" }, { "name": "usr/share/zoneinfo/Pacific/Niue", "type": "reg", "size": 252, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23035038, "NumLink": 0, "digest": "sha256:c7247452c2c61010dfc417d172e4f4cf955feefd89b9649fa08e51832d9ed708" }, { "name": "usr/share/zoneinfo/Pacific/Norfolk", "type": "reg", "size": 309, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23035264, "NumLink": 0, "digest": "sha256:5007254c619ebc6200e235c5aaa3b66eec80e9052d00ba63d84bce6c5408c755" }, { "name": "usr/share/zoneinfo/Pacific/Noumea", "type": "reg", "size": 314, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23035517, "NumLink": 0, "digest": "sha256:47834b191dcb3a4e4f0cb3e6c375ff66c07e609382be7d2c21e0c4d854008dca" }, { "name": "usr/share/zoneinfo/Pacific/Pago_Pago", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Midway", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Pacific/Palau", "type": "reg", "size": 151, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23035811, "NumLink": 0, "digest": "sha256:d1a61b4bffd5b61eac5d9ef0a7f10a80ffc1d027a9330e7ad89278a3f3857357" }, { "name": "usr/share/zoneinfo/Pacific/Pitcairn", "type": "reg", "size": 209, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23036001, "NumLink": 0, "digest": "sha256:97a89892a57db71698c25c9ae2bb8cd6436e239988b3bbb5e028fd9b0c233224" }, { "name": "usr/share/zoneinfo/Pacific/Pohnpei", "type": "reg", "size": 152, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23036208, "NumLink": 0, "digest": "sha256:9360c42536001cdbe62e033e03b1766ac3dc7315966c31166f86a4e9aafa4567" }, { "name": "usr/share/zoneinfo/Pacific/Ponape", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Pohnpei", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Pacific/Port_Moresby", "type": "reg", "size": 174, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23036442, "NumLink": 0, "digest": "sha256:9c505d421d2cfc45dab9819b6abdf1d9c616d63feab9ec1c22db149b192cdd3f" }, { "name": "usr/share/zoneinfo/Pacific/Rarotonga", "type": "reg", "size": 588, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23036648, "NumLink": 0, "digest": "sha256:b309575c63dbf5a1a8e499105cfc7b51dbba38302571e4a51d861a3f46eadbc3" }, { "name": "usr/share/zoneinfo/Pacific/Saipan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Guam", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Pacific/Samoa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Midway", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Pacific/Tahiti", "type": "reg", "size": 173, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23037129, "NumLink": 0, "digest": "sha256:2b908353b2b5ba977afe11a11c088376c816dd4b7f71358db6b95b060f51b637" }, { "name": "usr/share/zoneinfo/Pacific/Tarawa", "type": "reg", "size": 152, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23037313, "NumLink": 0, "digest": "sha256:5c0324994691766186531137a292759ef788a558273a13c7617f3c373b4426ec" }, { "name": "usr/share/zoneinfo/Pacific/Tongatapu", "type": "reg", "size": 379, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23037503, "NumLink": 0, "digest": "sha256:3a742868cd652d1ccd0bd219406bc09db1063c057dc2fdc05b3ff96e81b314da" }, { "name": "usr/share/zoneinfo/Pacific/Truk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Chuuk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Pacific/Wake", "type": "reg", "size": 152, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23037834, "NumLink": 0, "digest": "sha256:7d63ddb8dbd42baa9bf4fd136ad3be2612db4402fd498d67ebcfcb93eb42dd6a" }, { "name": "usr/share/zoneinfo/Pacific/Wallis", "type": "reg", "size": 152, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23038022, "NumLink": 0, "digest": "sha256:25cfc2e1a664e96e86dc7e9bcf754bd5b8608ddf7673ffa407e4a762e309ecf5" }, { "name": "usr/share/zoneinfo/Pacific/Yap", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Chuuk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Poland", "type": "reg", "size": 2705, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23038247, "NumLink": 0, "digest": "sha256:68e7493c1ca050e4134062a74aa4a4fc32159c042b4c9d8d40c8bfc9d273c5fa" }, { "name": "usr/share/zoneinfo/Portugal", "type": "reg", "size": 3469, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23039667, "NumLink": 0, "digest": "sha256:4bbe65d4ff3394ffa1b4ae6fe2296e333f55bad0ae49ca6717b6076e53490ea2" }, { "name": "usr/share/zoneinfo/ROC", "type": "reg", "size": 790, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23041447, "NumLink": 0, "digest": "sha256:25cfd02bc847bdcb11e586445ba886a76315f1f9be86f7e74944a6e8e8644543" }, { "name": "usr/share/zoneinfo/ROK", "type": "reg", "size": 531, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23041946, "NumLink": 0, "digest": "sha256:22de94642a978a6af463db175e9f93a3292e8a81a74a8b92989bc2174379edd6" }, { "name": "usr/share/zoneinfo/Singapore", "type": "reg", "size": 410, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23042328, "NumLink": 0, "digest": "sha256:1b4684d9bb6ec48169abb530da58b8cb238b785bb5ffeb5e06e50f1b2b9d60e0" }, { "name": "usr/share/zoneinfo/SystemV/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/AST4", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Puerto_Rico", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/AST4ADT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Halifax", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/CST6", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Regina", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/CST6CDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Chicago", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/EST5", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Cayman", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/EST5EDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../posixrules", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/HST10", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Pacific/Honolulu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/MST7", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Phoenix", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/MST7MDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/PST8", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Pacific/Pitcairn", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/PST8PDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Los_Angeles", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/YST9", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Pacific/Gambier", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/SystemV/YST9YDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Anchorage", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/Turkey", "type": "reg", "size": 2152, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23042976, "NumLink": 0, "digest": "sha256:2a694b73d6e78b3e9d3a94e1bc44c410bc306a360d7eebfabf8fd95c753760a3" }, { "name": "usr/share/zoneinfo/UCT", "type": "reg", "size": 127, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23044141, "NumLink": 0, "digest": "sha256:b3b762863cac2569aa33f7da192584afd9965ceeb7263fed4ad87c1b35e4c7d8" }, { "name": "usr/share/zoneinfo/US/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/Alaska", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Anchorage", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/Aleutian", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Adak", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/Arizona", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Phoenix", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/Central", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Chicago", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/East-Indiana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Fort_Wayne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/Eastern", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../posixrules", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/Hawaii", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Pacific/Honolulu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/Indiana-Starke", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Knox_IN", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/Michigan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Detroit", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/Mountain", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/Pacific", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Los_Angeles", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/Pacific-New", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Los_Angeles", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/US/Samoa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Pacific/Midway", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/UTC", "type": "reg", "size": 127, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23044644, "NumLink": 0, "digest": "sha256:3c71b358be81e13b1c24e199a119fd001dbcdb90edc7d44c2c7ae175321a0215" }, { "name": "usr/share/zoneinfo/Universal", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/W-SU", "type": "reg", "size": 1544, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23044828, "NumLink": 0, "digest": "sha256:02d55516d0f9d497998260b4f129aee59867b77a920ba2ca0c58b15ec8588e7a" }, { "name": "usr/share/zoneinfo/WET", "type": "reg", "size": 1873, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23045683, "NumLink": 0, "digest": "sha256:e5e7c4631295e7f17085e3530f99fc2984cc7e4bdb9a07db7702de8c18c2aab1" }, { "name": "usr/share/zoneinfo/Zulu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/iso3166.tab", "type": "reg", "size": 4445, "modtime": "2017-02-28T16:08:12Z", "mode": 33188, "offset": 23046733, "NumLink": 0, "digest": "sha256:fe8bd1792c0e7ec6b42507c58a3ba433ebddadbf4c3031eaca6da9c41def37d2" }, { "name": "usr/share/zoneinfo/leap-seconds.list", "type": "reg", "size": 10666, "modtime": "2018-01-15T17:19:18Z", "mode": 33188, "offset": 23049504, "NumLink": 0, "digest": "sha256:6255ce742f8189384c18dceb92ecf7639d49c480c4dc83c770e95a6f3bbdef1c" }, { "name": "usr/share/zoneinfo/localtime", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "/etc/localtime", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Abidjan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Accra", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Accra", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Addis_Ababa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Algiers", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Algiers", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Asmara", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Asmera", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Bamako", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Bangui", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Banjul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Bissau", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Bissau", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Blantyre", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Brazzaville", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Bujumbura", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Cairo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Egypt", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Casablanca", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Casablanca", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Ceuta", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Ceuta", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Conakry", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Dakar", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Dar_es_Salaam", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Djibouti", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Douala", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/El_Aaiun", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/El_Aaiun", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Freetown", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Gaborone", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Harare", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Johannesburg", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Johannesburg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Juba", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Juba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Kampala", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Khartoum", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Khartoum", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Kigali", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Kinshasa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Lagos", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Libreville", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Lome", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Luanda", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Lubumbashi", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Lusaka", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Malabo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Maputo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Maseru", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Johannesburg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Mbabane", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Johannesburg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Mogadishu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Monrovia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Monrovia", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Nairobi", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Ndjamena", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Ndjamena", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Niamey", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Nouakchott", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Ouagadougou", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Porto-Novo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Sao_Tome", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Sao_Tome", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Timbuktu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Tripoli", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Libya", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Tunis", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Tunis", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Africa/Windhoek", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Windhoek", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Adak", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Adak", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Anchorage", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anchorage", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Anguilla", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Antigua", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Araguaina", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Araguaina", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/Buenos_Aires", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Buenos_Aires", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/Catamarca", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Catamarca", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/ComodRivadavia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Catamarca", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/Cordoba", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Cordoba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/Jujuy", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Jujuy", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/La_Rioja", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Argentina/La_Rioja", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/Mendoza", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Mendoza", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/Rio_Gallegos", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Argentina/Rio_Gallegos", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/Salta", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Argentina/Salta", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/San_Juan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Argentina/San_Juan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/San_Luis", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Argentina/San_Luis", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/Tucuman", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Argentina/Tucuman", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Argentina/Ushuaia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Argentina/Ushuaia", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Aruba", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Aruba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Asuncion", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Asuncion", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Atikokan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Atikokan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Atka", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Adak", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Bahia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Bahia", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Bahia_Banderas", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Bahia_Banderas", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Barbados", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Barbados", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Belem", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Belem", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Belize", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Belize", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Blanc-Sablon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Blanc-Sablon", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Boa_Vista", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Boa_Vista", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Bogota", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Bogota", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Boise", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Boise", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Buenos_Aires", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Buenos_Aires", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Cambridge_Bay", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Cambridge_Bay", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Campo_Grande", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Campo_Grande", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Cancun", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Cancun", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Caracas", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Caracas", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Catamarca", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Catamarca", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Cayenne", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Cayenne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Cayman", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Cayman", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Chicago", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Chicago", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Chihuahua", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Chihuahua", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Coral_Harbour", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Atikokan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Cordoba", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Cordoba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Costa_Rica", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Costa_Rica", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Creston", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Creston", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Cuiaba", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Cuiaba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Curacao", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Aruba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Danmarkshavn", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Danmarkshavn", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Dawson", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Dawson", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Dawson_Creek", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Dawson_Creek", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Denver", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Detroit", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Detroit", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Dominica", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Edmonton", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Edmonton", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Eirunepe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Eirunepe", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/El_Salvador", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/El_Salvador", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Ensenada", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Ensenada", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Fort_Nelson", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Fort_Nelson", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Fort_Wayne", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Fort_Wayne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Fortaleza", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Fortaleza", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Glace_Bay", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Glace_Bay", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Godthab", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Godthab", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Goose_Bay", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Goose_Bay", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Grand_Turk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Grand_Turk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Grenada", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Guadeloupe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Guatemala", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Guatemala", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Guayaquil", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Guayaquil", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Guyana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Guyana", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Halifax", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Halifax", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Havana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Cuba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Hermosillo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Hermosillo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Indiana/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Indiana/Indianapolis", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Fort_Wayne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Indiana/Knox", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Knox_IN", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Indiana/Marengo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Indiana/Marengo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Indiana/Petersburg", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Indiana/Petersburg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Indiana/Tell_City", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Indiana/Tell_City", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Indiana/Vevay", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Indiana/Vevay", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Indiana/Vincennes", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Indiana/Vincennes", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Indiana/Winamac", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Indiana/Winamac", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Indianapolis", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Fort_Wayne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Inuvik", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Inuvik", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Iqaluit", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Iqaluit", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Jamaica", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Jamaica", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Jujuy", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Jujuy", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Juneau", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Juneau", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Kentucky/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Kentucky/Louisville", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Louisville", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Kentucky/Monticello", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/Kentucky/Monticello", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Knox_IN", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Knox_IN", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Kralendijk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Aruba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/La_Paz", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/La_Paz", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Lima", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Lima", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Los_Angeles", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Los_Angeles", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Louisville", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Louisville", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Lower_Princes", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Aruba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Maceio", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Maceio", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Managua", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Managua", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Manaus", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Manaus", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Marigot", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Martinique", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Martinique", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Matamoros", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Matamoros", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Mazatlan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Mazatlan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Mendoza", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Mendoza", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Menominee", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Menominee", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Merida", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Merida", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Metlakatla", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Metlakatla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Mexico_City", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Mexico_City", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Miquelon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Miquelon", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Moncton", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Moncton", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Monterrey", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Monterrey", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Montevideo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Montevideo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Montreal", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Montreal", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Montserrat", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Nassau", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Nassau", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/New_York", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../posixrules", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Nipigon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Nipigon", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Nome", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Nome", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Noronha", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Noronha", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/North_Dakota/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/North_Dakota/Beulah", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/North_Dakota/Beulah", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/North_Dakota/Center", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/North_Dakota/Center", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/North_Dakota/New_Salem", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../../America/North_Dakota/New_Salem", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Ojinaga", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Ojinaga", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Panama", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Cayman", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Pangnirtung", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Pangnirtung", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Paramaribo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Paramaribo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Phoenix", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Phoenix", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Port-au-Prince", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Port-au-Prince", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Port_of_Spain", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Porto_Acre", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Porto_Acre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Porto_Velho", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Porto_Velho", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Puerto_Rico", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Puerto_Rico", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Punta_Arenas", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Punta_Arenas", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Rainy_River", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Rainy_River", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Rankin_Inlet", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Rankin_Inlet", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Recife", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Recife", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Regina", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Regina", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Resolute", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Resolute", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Rio_Branco", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Porto_Acre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Rosario", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Cordoba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Santa_Isabel", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Ensenada", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Santarem", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Santarem", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Santiago", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Santiago", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Santo_Domingo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Santo_Domingo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Sao_Paulo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Sao_Paulo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Scoresbysund", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Scoresbysund", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Shiprock", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Sitka", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Sitka", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/St_Barthelemy", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/St_Johns", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/St_Johns", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/St_Kitts", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/St_Lucia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/St_Thomas", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/St_Vincent", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Swift_Current", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Swift_Current", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Tegucigalpa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Tegucigalpa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Thule", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Thule", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Thunder_Bay", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Thunder_Bay", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Tijuana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Ensenada", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Toronto", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Montreal", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Tortola", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Vancouver", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Vancouver", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Virgin", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Whitehorse", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Whitehorse", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Winnipeg", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Winnipeg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Yakutat", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Yakutat", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/America/Yellowknife", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Yellowknife", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/Casey", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Antarctica/Casey", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/Davis", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Antarctica/Davis", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/DumontDUrville", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Antarctica/DumontDUrville", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/Macquarie", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Antarctica/Macquarie", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/Mawson", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Antarctica/Mawson", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/McMurdo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../NZ", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/Palmer", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Antarctica/Palmer", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/Rothera", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Antarctica/Rothera", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/South_Pole", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../NZ", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/Syowa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Antarctica/Syowa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/Troll", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Antarctica/Troll", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Antarctica/Vostok", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Antarctica/Vostok", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Arctic/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Arctic/Longyearbyen", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Arctic/Longyearbyen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Aden", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Aden", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Almaty", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Almaty", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Amman", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Amman", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Anadyr", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Anadyr", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Aqtau", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Aqtau", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Aqtobe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Aqtobe", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Ashgabat", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Ashgabat", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Ashkhabad", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Ashgabat", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Atyrau", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Atyrau", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Baghdad", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Baghdad", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Bahrain", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Bahrain", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Baku", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Baku", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Bangkok", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Bangkok", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Barnaul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Barnaul", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Beirut", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Beirut", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Bishkek", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Bishkek", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Brunei", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Brunei", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Calcutta", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Calcutta", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Chita", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Chita", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Choibalsan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Choibalsan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Chongqing", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Chungking", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Colombo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Colombo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Dacca", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Dacca", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Damascus", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Damascus", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Dhaka", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Dacca", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Dili", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Dili", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Dubai", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Dubai", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Dushanbe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Dushanbe", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Famagusta", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Famagusta", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Gaza", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Gaza", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Harbin", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Hebron", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Hebron", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Ho_Chi_Minh", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Ho_Chi_Minh", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Hong_Kong", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Hongkong", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Hovd", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Hovd", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Irkutsk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Irkutsk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Istanbul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Turkey", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Jakarta", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Jakarta", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Jayapura", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Jayapura", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Jerusalem", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Israel", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Kabul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Kabul", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Kamchatka", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Kamchatka", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Karachi", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Karachi", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Kashgar", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Kashgar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Kathmandu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Kathmandu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Katmandu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Kathmandu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Khandyga", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Khandyga", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Kolkata", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Calcutta", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Krasnoyarsk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Krasnoyarsk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Kuala_Lumpur", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Kuala_Lumpur", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Kuching", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Kuching", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Kuwait", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Aden", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Macao", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Macao", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Macau", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Macao", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Magadan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Magadan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Makassar", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Makassar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Manila", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Manila", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Muscat", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Dubai", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Nicosia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Nicosia", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Novokuznetsk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Novokuznetsk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Novosibirsk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Novosibirsk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Omsk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Omsk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Oral", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Oral", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Phnom_Penh", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Bangkok", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Pontianak", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Pontianak", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Pyongyang", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Pyongyang", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Qatar", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Bahrain", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Qyzylorda", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Qyzylorda", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Rangoon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Rangoon", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Riyadh", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Aden", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Saigon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Ho_Chi_Minh", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Sakhalin", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Sakhalin", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Samarkand", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Samarkand", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Seoul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../ROK", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Shanghai", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Singapore", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Singapore", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Srednekolymsk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Srednekolymsk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Taipei", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../ROC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Tashkent", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Tashkent", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Tbilisi", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Tbilisi", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Tehran", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Iran", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Tel_Aviv", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Israel", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Thimbu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Thimbu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Thimphu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Thimbu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Tokyo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Japan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Tomsk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Tomsk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Ujung_Pandang", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Makassar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Ulaanbaatar", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Ulaanbaatar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Ulan_Bator", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Ulaanbaatar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Urumqi", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Kashgar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Ust-Nera", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Ust-Nera", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Vientiane", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Bangkok", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Vladivostok", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Vladivostok", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Yakutsk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Yakutsk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Yangon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Rangoon", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Yekaterinburg", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Yekaterinburg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Asia/Yerevan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Yerevan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/Azores", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Atlantic/Azores", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/Bermuda", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Atlantic/Bermuda", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/Canary", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Atlantic/Canary", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/Cape_Verde", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Atlantic/Cape_Verde", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/Faeroe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Atlantic/Faeroe", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/Faroe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Atlantic/Faeroe", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/Jan_Mayen", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Arctic/Longyearbyen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/Madeira", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Atlantic/Madeira", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/Reykjavik", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Iceland", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/South_Georgia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Atlantic/South_Georgia", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/St_Helena", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Atlantic/Stanley", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Atlantic/Stanley", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/ACT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/ACT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Adelaide", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Adelaide", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Brisbane", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Brisbane", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Broken_Hill", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Broken_Hill", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Canberra", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/ACT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Currie", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Currie", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Darwin", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Darwin", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Eucla", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Eucla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Hobart", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Hobart", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/LHI", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/LHI", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Lindeman", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Lindeman", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Lord_Howe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/LHI", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Melbourne", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Melbourne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/NSW", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/ACT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/North", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Darwin", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Perth", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Perth", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Queensland", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Brisbane", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/South", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Adelaide", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Sydney", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/ACT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Tasmania", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Hobart", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Victoria", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Melbourne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/West", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Perth", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Australia/Yancowinna", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Australia/Broken_Hill", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Brazil/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Brazil/Acre", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Porto_Acre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Brazil/DeNoronha", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Noronha", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Brazil/East", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Sao_Paulo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Brazil/West", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Manaus", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/CET", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../CET", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/CST6CDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../CST6CDT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Canada/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Canada/Atlantic", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Halifax", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Canada/Central", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Winnipeg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Canada/Eastern", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Montreal", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Canada/Mountain", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Edmonton", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Canada/Newfoundland", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/St_Johns", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Canada/Pacific", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Vancouver", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Canada/Saskatchewan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Regina", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Canada/Yukon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Whitehorse", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Chile/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Chile/Continental", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Santiago", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Chile/EasterIsland", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Chile/EasterIsland", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Cuba", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Cuba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/EET", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../EET", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/EST", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../EST", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/EST5EDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../EST5EDT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Egypt", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Egypt", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Eire", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Eire", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+1", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT+1", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+10", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT+10", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+11", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT+11", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+12", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT+12", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+2", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT+2", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+3", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT+3", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+4", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT+4", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+5", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT+5", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+6", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT+6", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+7", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT+7", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+8", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT+8", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT+9", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT+9", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-1", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-1", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-10", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-10", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-11", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-11", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-12", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-12", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-13", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-13", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-14", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-14", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-2", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-2", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-3", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-3", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-4", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-4", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-5", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-5", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-6", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-6", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-7", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-7", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-8", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-8", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT-9", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Etc/GMT-9", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/GMT0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/Greenwich", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/UCT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../UCT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/UTC", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/Universal", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Etc/Zulu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Amsterdam", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Amsterdam", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Andorra", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Andorra", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Astrakhan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Astrakhan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Athens", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Athens", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Belfast", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Belgrade", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Berlin", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Berlin", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Bratislava", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Bratislava", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Brussels", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Brussels", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Bucharest", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Bucharest", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Budapest", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Budapest", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Busingen", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Busingen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Chisinau", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Chisinau", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Copenhagen", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Copenhagen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Dublin", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Eire", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Gibraltar", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Gibraltar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Guernsey", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Helsinki", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Helsinki", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Isle_of_Man", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Istanbul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Turkey", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Jersey", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Kaliningrad", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Kaliningrad", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Kiev", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Kiev", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Kirov", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Kirov", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Lisbon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Portugal", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Ljubljana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/London", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Luxembourg", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Luxembourg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Madrid", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Madrid", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Malta", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Malta", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Mariehamn", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Helsinki", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Minsk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Minsk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Monaco", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Monaco", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Moscow", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../W-SU", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Nicosia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Asia/Nicosia", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Oslo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Arctic/Longyearbyen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Paris", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Paris", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Podgorica", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Prague", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Bratislava", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Riga", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Riga", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Rome", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Rome", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Samara", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Samara", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/San_Marino", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Rome", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Sarajevo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Saratov", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Saratov", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Simferopol", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Simferopol", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Skopje", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Sofia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Sofia", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Stockholm", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Stockholm", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Tallinn", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Tallinn", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Tirane", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Tirane", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Tiraspol", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Chisinau", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Ulyanovsk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Ulyanovsk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Uzhgorod", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Uzhgorod", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Vaduz", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Busingen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Vatican", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Rome", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Vienna", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Vienna", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Vilnius", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Vilnius", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Volgograd", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Volgograd", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Warsaw", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Poland", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Zagreb", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Zaporozhye", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Zaporozhye", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Europe/Zurich", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Europe/Busingen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Factory", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Factory", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/GB", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/GB-Eire", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/GMT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/GMT+0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/GMT-0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/GMT0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Greenwich", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/HST", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../HST", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Hongkong", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Hongkong", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Iceland", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Iceland", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Indian/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Indian/Antananarivo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Indian/Chagos", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Indian/Chagos", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Indian/Christmas", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Indian/Christmas", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Indian/Cocos", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Indian/Cocos", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Indian/Comoro", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Indian/Kerguelen", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Indian/Kerguelen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Indian/Mahe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Indian/Mahe", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Indian/Maldives", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Indian/Maldives", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Indian/Mauritius", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Indian/Mauritius", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Indian/Mayotte", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Indian/Reunion", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Indian/Reunion", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Iran", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Iran", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Israel", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Israel", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Jamaica", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Jamaica", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Japan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Japan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Kwajalein", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Kwajalein", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Libya", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Libya", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/MET", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../MET", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/MST", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../MST", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/MST7MDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../MST7MDT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Mexico/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Mexico/BajaNorte", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Ensenada", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Mexico/BajaSur", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Mazatlan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Mexico/General", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Mexico_City", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/NZ", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../NZ", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/NZ-CHAT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../NZ-CHAT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Navajo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/PRC", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/PST8PDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../PST8PDT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Apia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Apia", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Auckland", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../NZ", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Bougainville", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Bougainville", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Chatham", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../NZ-CHAT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Chuuk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Chuuk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Easter", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Chile/EasterIsland", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Efate", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Efate", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Enderbury", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Enderbury", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Fakaofo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Fakaofo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Fiji", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Fiji", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Funafuti", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Funafuti", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Galapagos", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Galapagos", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Gambier", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Gambier", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Guadalcanal", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Guadalcanal", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Guam", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Guam", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Honolulu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Honolulu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Johnston", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Honolulu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Kiritimati", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Kiritimati", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Kosrae", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Kosrae", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Kwajalein", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Kwajalein", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Majuro", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Majuro", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Marquesas", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Marquesas", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Midway", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Midway", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Nauru", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Nauru", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Niue", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Niue", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Norfolk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Norfolk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Noumea", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Noumea", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Pago_Pago", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Midway", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Palau", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Palau", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Pitcairn", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Pitcairn", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Pohnpei", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Pohnpei", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Ponape", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Pohnpei", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Port_Moresby", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Port_Moresby", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Rarotonga", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Rarotonga", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Saipan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Guam", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Samoa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Midway", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Tahiti", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Tahiti", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Tarawa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Tarawa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Tongatapu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Tongatapu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Truk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Chuuk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Wake", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Wake", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Wallis", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Wallis", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Pacific/Yap", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Chuuk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Poland", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Poland", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Portugal", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Portugal", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/ROC", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../ROC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/ROK", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../ROK", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Singapore", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Singapore", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/AST4", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Puerto_Rico", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/AST4ADT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Halifax", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/CST6", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Regina", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/CST6CDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Chicago", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/EST5", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Cayman", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/EST5EDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../posixrules", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/HST10", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Honolulu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/MST7", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Phoenix", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/MST7MDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/PST8", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Pitcairn", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/PST8PDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Los_Angeles", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/YST9", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Gambier", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/SystemV/YST9YDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anchorage", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Turkey", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Turkey", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/UCT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../UCT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/Alaska", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Anchorage", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/Aleutian", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Adak", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/Arizona", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Phoenix", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/Central", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Chicago", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/East-Indiana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Fort_Wayne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/Eastern", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../posixrules", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/Hawaii", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Honolulu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/Indiana-Starke", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Knox_IN", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/Michigan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Detroit", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/Mountain", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/Pacific", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Los_Angeles", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/Pacific-New", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../America/Los_Angeles", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/US/Samoa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../../Pacific/Midway", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/UTC", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Universal", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/W-SU", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../W-SU", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/WET", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../WET", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posix/Zulu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/posixrules", "type": "reg", "size": 3545, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23065057, "NumLink": 0, "digest": "sha256:5fa6dccc303352e1195c4348b189f3085014d8a56a1976c8e8a32bd4fedb69fd" }, { "name": "usr/share/zoneinfo/right/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Abidjan", "type": "reg", "size": 710, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23066974, "NumLink": 0, "digest": "sha256:c177f3894cfb7acf27cfefcefd177aebfa1699e409e7fc4cd5a11ef116f8d236" }, { "name": "usr/share/zoneinfo/right/Africa/Accra", "type": "reg", "size": 1382, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23067446, "NumLink": 0, "digest": "sha256:fbee22da817893911690f2ee7093499893985e39c0ced1116709947f9bd206d5" }, { "name": "usr/share/zoneinfo/right/Africa/Addis_Ababa", "type": "reg", "size": 825, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23068277, "NumLink": 0, "digest": "sha256:ae39f133e4fad735bf5e099f9090b322f84efb7fe050968da196289a3c703905" }, { "name": "usr/share/zoneinfo/right/Africa/Algiers", "type": "reg", "size": 1300, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23068801, "NumLink": 0, "digest": "sha256:84081708d8029add247fd5add1ed963c2811b8b7841b65540ba7bbb02a068019" }, { "name": "usr/share/zoneinfo/right/Africa/Asmara", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Asmera", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Bamako", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Bangui", "type": "reg", "size": 711, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23069674, "NumLink": 0, "digest": "sha256:699bdf57ddb361bef922d520674b4fecd15db812c73e984727455fa7c3ada2d3" }, { "name": "usr/share/zoneinfo/right/Africa/Banjul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Bissau", "type": "reg", "size": 748, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23070186, "NumLink": 0, "digest": "sha256:197606820a95c35d6c3d2f64e5e1d9542e198732db52d3b9ca6ff7294bb0ff9b" }, { "name": "usr/share/zoneinfo/right/Africa/Blantyre", "type": "reg", "size": 711, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23070680, "NumLink": 0, "digest": "sha256:3e39755e95604e242f4218d248dafd51ffa09392975c3f86c26907e6aad60da9" }, { "name": "usr/share/zoneinfo/right/Africa/Brazzaville", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Bujumbura", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Cairo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Egypt", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Casablanca", "type": "reg", "size": 2169, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23071255, "NumLink": 0, "digest": "sha256:891b90e824430fb61b050271bf1f409a9166b28f55885e50ca63ebb24d0679ab" }, { "name": "usr/share/zoneinfo/right/Africa/Ceuta", "type": "reg", "size": 2599, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23072513, "NumLink": 0, "digest": "sha256:ca6b06411c93017e93ded83d917cac8399690d6fb2771bcc66ecf132ee2e3ef6" }, { "name": "usr/share/zoneinfo/right/Africa/Conakry", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Dakar", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Dar_es_Salaam", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Djibouti", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Douala", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/El_Aaiun", "type": "reg", "size": 1999, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23074107, "NumLink": 0, "digest": "sha256:9568caf33829340936f06819a98b4458092b9c363ab915421ea3bf46e0665e9f" }, { "name": "usr/share/zoneinfo/right/Africa/Freetown", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Gaborone", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Harare", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Johannesburg", "type": "reg", "size": 811, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23075380, "NumLink": 0, "digest": "sha256:af7338314b4255661ce9afdd064e487321d4369ce15488395bb20bb4627d1ae2" }, { "name": "usr/share/zoneinfo/right/Africa/Juba", "type": "reg", "size": 1223, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23075905, "NumLink": 0, "digest": "sha256:2837717687d9cf2982e14bc35199ebe448380678330f15de5a6a2c49ef204b3c" }, { "name": "usr/share/zoneinfo/right/Africa/Kampala", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Khartoum", "type": "reg", "size": 1253, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23076712, "NumLink": 0, "digest": "sha256:0cd1350c87bd18606418d615dd78790f8ee9458ade7acb1af82b67afbdfc27f1" }, { "name": "usr/share/zoneinfo/right/Africa/Kigali", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Kinshasa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Lagos", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Libreville", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Lome", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Luanda", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Lubumbashi", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Lusaka", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Malabo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Maputo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Blantyre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Maseru", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Johannesburg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Mbabane", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Johannesburg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Mogadishu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Monrovia", "type": "reg", "size": 773, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23077761, "NumLink": 0, "digest": "sha256:eb1deb0dd9325844227c376d1532b484511c76f79f42032806553d36a9464e55" }, { "name": "usr/share/zoneinfo/right/Africa/Nairobi", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Ndjamena", "type": "reg", "size": 765, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23078309, "NumLink": 0, "digest": "sha256:180050fab205819406f6d6b572fe6f37eb805cc3f796543185c3229108470189" }, { "name": "usr/share/zoneinfo/right/Africa/Niamey", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Nouakchott", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Ouagadougou", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Porto-Novo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangui", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Sao_Tome", "type": "reg", "size": 774, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23078918, "NumLink": 0, "digest": "sha256:29e95715ef8893f1bd3f1a1625d200fdd0fe65fe0432b659130b69cff2460dbb" }, { "name": "usr/share/zoneinfo/right/Africa/Timbuktu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Tripoli", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Libya", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Africa/Tunis", "type": "reg", "size": 1250, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23079488, "NumLink": 0, "digest": "sha256:dbc64f2ddde5756e10d2ec8156bbe83f6f9ecbeb33b5bd6d771542f623d8fc39" }, { "name": "usr/share/zoneinfo/right/Africa/Windhoek", "type": "reg", "size": 1528, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23080260, "NumLink": 0, "digest": "sha256:9232e815aee566ea37642ad831abe23161c2f1c286dcffdc72d95f71d5e40289" }, { "name": "usr/share/zoneinfo/right/America/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Adak", "type": "reg", "size": 2905, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23081220, "NumLink": 0, "digest": "sha256:6d3e31970fee36399f30950e3f68ce7a5038be38a64547241c2ac97daaccd994" }, { "name": "usr/share/zoneinfo/right/America/Anchorage", "type": "reg", "size": 2920, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23082890, "NumLink": 0, "digest": "sha256:b5b62f7337785e26117bbc34ef7976018f021e63eb3e208f8c752d4f949ef2ef" }, { "name": "usr/share/zoneinfo/right/America/Anguilla", "type": "reg", "size": 710, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23084562, "NumLink": 0, "digest": "sha256:dbe365d9a8abfd164690db1cec6c51c19f86154900595509c991401e13a16585" }, { "name": "usr/share/zoneinfo/right/America/Antigua", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Araguaina", "type": "reg", "size": 1436, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23085077, "NumLink": 0, "digest": "sha256:43bf02f6b5a9899a0f6991d0077f4d2216971d7b30b5de2fc790e327e019ee5e" }, { "name": "usr/share/zoneinfo/right/America/Argentina/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Argentina/Buenos_Aires", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Buenos_Aires", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Argentina/Catamarca", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Catamarca", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Argentina/ComodRivadavia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Catamarca", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Argentina/Cordoba", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Cordoba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Argentina/Jujuy", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Jujuy", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Argentina/La_Rioja", "type": "reg", "size": 1649, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23086135, "NumLink": 0, "digest": "sha256:c7ded9821e935c4b533f557a31ccc2e4c3e89589091854b080f633b4a914c21c" }, { "name": "usr/share/zoneinfo/right/America/Argentina/Mendoza", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Mendoza", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Argentina/Rio_Gallegos", "type": "reg", "size": 1635, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23087183, "NumLink": 0, "digest": "sha256:e94db6d4db923985621567e409b6db116b4ef5bee49c750518bd2f6be1f6863b" }, { "name": "usr/share/zoneinfo/right/America/Argentina/Salta", "type": "reg", "size": 1607, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23088175, "NumLink": 0, "digest": "sha256:6829678c15796b06de4b1da92b4eb8468d2ad8b25e2811c5faca7e6d4cf96098" }, { "name": "usr/share/zoneinfo/right/America/Argentina/San_Juan", "type": "reg", "size": 1649, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23089159, "NumLink": 0, "digest": "sha256:87e65aaeddf18f1584306b42fc929f85e875f4eb729d15e2fb872bce277dc4c4" }, { "name": "usr/share/zoneinfo/right/America/Argentina/San_Luis", "type": "reg", "size": 1665, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23090160, "NumLink": 0, "digest": "sha256:959fd4de4b39ef6c77a411d434d75fe5941da9374d58f9d40fbeef0e01f0886c" }, { "name": "usr/share/zoneinfo/right/America/Argentina/Tucuman", "type": "reg", "size": 1663, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23091165, "NumLink": 0, "digest": "sha256:daae915c9ee5454bf0caff7c0e76f34166a3f6a3f2457325f02cdfe628324d04" }, { "name": "usr/share/zoneinfo/right/America/Argentina/Ushuaia", "type": "reg", "size": 1635, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23092175, "NumLink": 0, "digest": "sha256:45587dee42013d07c5cbe4cc755f71552d24755d364f933de4f0cbd595545f42" }, { "name": "usr/share/zoneinfo/right/America/Aruba", "type": "reg", "size": 752, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23093157, "NumLink": 0, "digest": "sha256:ec9709d87bbdd0aae7be4070156e5dc05c12d822da203cb1030354342bae2df0" }, { "name": "usr/share/zoneinfo/right/America/Asuncion", "type": "reg", "size": 2603, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23093653, "NumLink": 0, "digest": "sha256:1f9c20fdeff202451fcef7540f2787175f5c494157805091e7943d736dbcd919" }, { "name": "usr/share/zoneinfo/right/America/Atikokan", "type": "reg", "size": 885, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23095126, "NumLink": 0, "digest": "sha256:2fe220cd5f52ece0e3aa468ed33c443eaad61fc9e3bfbb47b7b754e8ad1a4613" }, { "name": "usr/share/zoneinfo/right/America/Atka", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Adak", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Bahia", "type": "reg", "size": 1576, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23095721, "NumLink": 0, "digest": "sha256:9945af7dcc0f3d98b12a34a0f312f79d54ae2cbd8261d4be697e3e0cd10f1b56" }, { "name": "usr/share/zoneinfo/right/America/Bahia_Banderas", "type": "reg", "size": 2128, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23096687, "NumLink": 0, "digest": "sha256:e44343d2e96738b96a6d83d5327dda8d041b1fb8e62b281f7fac7e56642b960b" }, { "name": "usr/share/zoneinfo/right/America/Barbados", "type": "reg", "size": 884, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23097912, "NumLink": 0, "digest": "sha256:64d664790217c76976a3a1f386ac82fc0f2295247f64547385711656b9f8f13b" }, { "name": "usr/share/zoneinfo/right/America/Belem", "type": "reg", "size": 1128, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23098477, "NumLink": 0, "digest": "sha256:5c276cfcf3596de48c0e4945ac5d19041e615fe79cd9e87fdaff0e7aaa558b7d" }, { "name": "usr/share/zoneinfo/right/America/Belize", "type": "reg", "size": 1518, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23099183, "NumLink": 0, "digest": "sha256:8128f9212e7e47481a2893da5f65f2c0047bf1329e314591435d7bb18b81b136" }, { "name": "usr/share/zoneinfo/right/America/Blanc-Sablon", "type": "reg", "size": 847, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23100102, "NumLink": 0, "digest": "sha256:6e9969e343200d865e82628b88310774524c38ae9c5ede30b7e5163acb70e6a1" }, { "name": "usr/share/zoneinfo/right/America/Boa_Vista", "type": "reg", "size": 1184, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23100654, "NumLink": 0, "digest": "sha256:33c2236e501f89ef5f2a5d1afcfc1434c264b10d1e14f9def6efd4c00c3f5003" }, { "name": "usr/share/zoneinfo/right/America/Bogota", "type": "reg", "size": 797, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23101399, "NumLink": 0, "digest": "sha256:b517e5bdb8aeeede03927787dcf5529f4fb33fbcb76daa7c5bcfda5320cd4468" }, { "name": "usr/share/zoneinfo/right/America/Boise", "type": "reg", "size": 2943, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23101924, "NumLink": 0, "digest": "sha256:7189c739198e19615b75a8a336aabd3cb223a765487382eb16c783cbb91c8c95" }, { "name": "usr/share/zoneinfo/right/America/Buenos_Aires", "type": "reg", "size": 1635, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23103582, "NumLink": 0, "digest": "sha256:d47983ff5ce9a8ecb9d65fdea3f3f603ccccdd170da513266c852d25ade2a6ca" }, { "name": "usr/share/zoneinfo/right/America/Cambridge_Bay", "type": "reg", "size": 2638, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23104571, "NumLink": 0, "digest": "sha256:dfa58c30cd1217d5f8e9dcb757d64bfb901c28a5f9475a38ac7de9e03c2d80c0" }, { "name": "usr/share/zoneinfo/right/America/Campo_Grande", "type": "reg", "size": 2556, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23106050, "NumLink": 0, "digest": "sha256:dab46c4d5ef0c2ec09cbf68010b9f73c7e5082669c3b92e3be032a6af4ccb61d" }, { "name": "usr/share/zoneinfo/right/America/Cancun", "type": "reg", "size": 1356, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23107525, "NumLink": 0, "digest": "sha256:c8ce65577ce494166ad8f57f14a55ae961e27dd7aa356d8802fb5c9f2d510fb6" }, { "name": "usr/share/zoneinfo/right/America/Caracas", "type": "reg", "size": 815, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23108350, "NumLink": 0, "digest": "sha256:08c9e8707db81610f374294e7d3e8338ce329e60bc467547ef1714287271f563" }, { "name": "usr/share/zoneinfo/right/America/Catamarca", "type": "reg", "size": 1635, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23108882, "NumLink": 0, "digest": "sha256:0d0d4323f8e3489b61b4c512a2300d68672a9f92a8d7bf5ecaf6e2dd786ee449" }, { "name": "usr/share/zoneinfo/right/America/Cayenne", "type": "reg", "size": 750, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23109869, "NumLink": 0, "digest": "sha256:b11737b697bbe5e67a9fc1ab08a0dd868df4b2290225e3b15d7b677ec2009bcb" }, { "name": "usr/share/zoneinfo/right/America/Cayman", "type": "reg", "size": 743, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23110367, "NumLink": 0, "digest": "sha256:6962181adfca6314029efa4c3a2dae17c775d6031cff3bd6c63d49ed30c31cb1" }, { "name": "usr/share/zoneinfo/right/America/Chicago", "type": "reg", "size": 4125, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23110864, "NumLink": 0, "digest": "sha256:94f71253caa6bde6db52f2f5ad3b816df0c2da9af7cc7d4a4abf1b91e391821f" }, { "name": "usr/share/zoneinfo/right/America/Chihuahua", "type": "reg", "size": 2062, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23113109, "NumLink": 0, "digest": "sha256:1f0007a74669d2ede5ccea2c49ff17ced52ae2e28756ebbf5eb08aa08b3e9d45" }, { "name": "usr/share/zoneinfo/right/America/Coral_Harbour", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Atikokan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Cordoba", "type": "reg", "size": 1635, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23114349, "NumLink": 0, "digest": "sha256:3941316300e3137c4e8826d17e00a9df06aff8cec73034e6b61e9b371bb0a540" }, { "name": "usr/share/zoneinfo/right/America/Costa_Rica", "type": "reg", "size": 881, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23115335, "NumLink": 0, "digest": "sha256:a697b205589062aab7599c2e812f164df50b32f2d9c8f2ea7b42f1e53b4e3e94" }, { "name": "usr/share/zoneinfo/right/America/Creston", "type": "reg", "size": 773, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23115910, "NumLink": 0, "digest": "sha256:071acbeb9c771d5bd244b0d6bd73b7e7893aa40deb19c1074908a0094de4463f" }, { "name": "usr/share/zoneinfo/right/America/Cuiaba", "type": "reg", "size": 2528, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23116419, "NumLink": 0, "digest": "sha256:7728725c174a947f2e7c6acee48c0b40b6ef1947aa706c8b3ef1bff9a3b4a453" }, { "name": "usr/share/zoneinfo/right/America/Curacao", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Aruba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Danmarkshavn", "type": "reg", "size": 1252, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23117933, "NumLink": 0, "digest": "sha256:99b1ff4ad370c93145279b56504ccd2d0bb39f92c002aaa490bd5969285cdd1f" }, { "name": "usr/share/zoneinfo/right/America/Dawson", "type": "reg", "size": 2633, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23118705, "NumLink": 0, "digest": "sha256:93a9938a26f814adf696f2e4f537164bc8ca9e4843d8bc6cb96dc59377534437" }, { "name": "usr/share/zoneinfo/right/America/Dawson_Creek", "type": "reg", "size": 1599, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23120198, "NumLink": 0, "digest": "sha256:4f2bb35e6c4c8804409dc81ad024881457705dca4ae468184f73c04bff51ead1" }, { "name": "usr/share/zoneinfo/right/America/Denver", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Detroit", "type": "reg", "size": 2728, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23121184, "NumLink": 0, "digest": "sha256:d7c0f33030d0e2d553b385457787d9faf8ce714c0b3a17778d5d45ad1a6560b2" }, { "name": "usr/share/zoneinfo/right/America/Dominica", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Edmonton", "type": "reg", "size": 2942, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23122773, "NumLink": 0, "digest": "sha256:da80c9534c7b548bbb92e982c1ca2b15b30608ca72567d20e9881444cf58b4aa" }, { "name": "usr/share/zoneinfo/right/America/Eirunepe", "type": "reg", "size": 1216, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23124428, "NumLink": 0, "digest": "sha256:9396017faecf7a3931851bec7fc924eeb8a2a53ceda91da3d458edcb555ced62" }, { "name": "usr/share/zoneinfo/right/America/El_Salvador", "type": "reg", "size": 790, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23125181, "NumLink": 0, "digest": "sha256:04993007b8086580ac35e8fa524bbdcd45f045c965608fca3da26deaa1ede337" }, { "name": "usr/share/zoneinfo/right/America/Ensenada", "type": "reg", "size": 2896, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23125708, "NumLink": 0, "digest": "sha256:a1a5199868d6aa4c24fef5e908e99e4c6e116d16afc554d25ec431990d8f02da" }, { "name": "usr/share/zoneinfo/right/America/Fort_Nelson", "type": "reg", "size": 2789, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23127332, "NumLink": 0, "digest": "sha256:c20108fb21d7e76aef2c0bd669f1dfd6043b5269020bde6cff669f088d13abec" }, { "name": "usr/share/zoneinfo/right/America/Fort_Wayne", "type": "reg", "size": 2215, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23128915, "NumLink": 0, "digest": "sha256:7dfb7b2796f9b9d9a69d402b2e8269a2f834e1d01e2da34af490b2b24c21ace5" }, { "name": "usr/share/zoneinfo/right/America/Fortaleza", "type": "reg", "size": 1268, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23130193, "NumLink": 0, "digest": "sha256:6ab4cad81917df05f5ba0f3dc90923aa5074f740095a6439a8739249bc26df0e" }, { "name": "usr/share/zoneinfo/right/America/Glace_Bay", "type": "reg", "size": 2746, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23130981, "NumLink": 0, "digest": "sha256:799c72cab5fafdcf48dfe766d52c24e7fd7f4a61e0d554c97888023766219287" }, { "name": "usr/share/zoneinfo/right/America/Godthab", "type": "reg", "size": 2418, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23132536, "NumLink": 0, "digest": "sha256:c9d318e4f59dd5f3016f5e3981a67ab34140b767c987178738e14a80eae74976" }, { "name": "usr/share/zoneinfo/right/America/Goose_Bay", "type": "reg", "size": 3759, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23133907, "NumLink": 0, "digest": "sha256:462bef059c879d10cbcce574a128bc2d847dfc342dd77f43e6494f3aba6cf94c" }, { "name": "usr/share/zoneinfo/right/America/Grand_Turk", "type": "reg", "size": 2421, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23135999, "NumLink": 0, "digest": "sha256:50148cea43182f25effdaba081e72c55239b58f5985a2af2e1ace6d591ef2388" }, { "name": "usr/share/zoneinfo/right/America/Grenada", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Guadeloupe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Guatemala", "type": "reg", "size": 846, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23137448, "NumLink": 0, "digest": "sha256:b8d8d7b3edd1a237b4d4aee860162700cf11e25aa9102ba61bed6640ced94463" }, { "name": "usr/share/zoneinfo/right/America/Guayaquil", "type": "reg", "size": 797, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23138012, "NumLink": 0, "digest": "sha256:cd8bef091fd1f925658709c0f130381dc8b9406dd50af15dbba3ee0740761777" }, { "name": "usr/share/zoneinfo/right/America/Guyana", "type": "reg", "size": 792, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23138541, "NumLink": 0, "digest": "sha256:607345856a6751417bbfc7c185e9245fc34af1d87b2ea11c77aadc7b8f7b7799" }, { "name": "usr/share/zoneinfo/right/America/Halifax", "type": "reg", "size": 3978, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23139058, "NumLink": 0, "digest": "sha256:86c84ef0a21a387fdd0058046268c5eca94c10cb73231638724d344cc478bd10" }, { "name": "usr/share/zoneinfo/right/America/Havana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Cuba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Hermosillo", "type": "reg", "size": 994, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23141298, "NumLink": 0, "digest": "sha256:778350bbb96f05ab2e74834f35be215801da358dd7c261f1ba3bfe6f1c9b07e9" }, { "name": "usr/share/zoneinfo/right/America/Indiana/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Indiana/Indianapolis", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Fort_Wayne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Indiana/Knox", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Knox_IN", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Indiana/Marengo", "type": "reg", "size": 2271, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23142027, "NumLink": 0, "digest": "sha256:b3e8fe887a5ce407f7208f16d0b296a4594b3f93de33b70d5a260139f66cfab2" }, { "name": "usr/share/zoneinfo/right/America/Indiana/Petersburg", "type": "reg", "size": 2453, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23143358, "NumLink": 0, "digest": "sha256:285f27ebb54838060d3a33238dae6ee695af5c258d40780fc89c797a239360ba" }, { "name": "usr/share/zoneinfo/right/America/Indiana/Tell_City", "type": "reg", "size": 2275, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23144773, "NumLink": 0, "digest": "sha256:17b0f617df438b7a18a3bbb5f43d1a0fbda97ac074c429d699fc6ff2b70f9080" }, { "name": "usr/share/zoneinfo/right/America/Indiana/Vevay", "type": "reg", "size": 1963, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23146072, "NumLink": 0, "digest": "sha256:74d2b6f797d63017075f1425e695e5f61a6e1b3ef08f812bc330e22fae18333a" }, { "name": "usr/share/zoneinfo/right/America/Indiana/Vincennes", "type": "reg", "size": 2243, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23147239, "NumLink": 0, "digest": "sha256:970baaf1ed777c07d74546d61282e9df9a0488ad90084210a770c82ae78b8357" }, { "name": "usr/share/zoneinfo/right/America/Indiana/Winamac", "type": "reg", "size": 2327, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23148540, "NumLink": 0, "digest": "sha256:cade9b122bd306fd5bb1fd4ff0471861c8eaed414a166ba570554a349a7a20b6" }, { "name": "usr/share/zoneinfo/right/America/Indianapolis", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Fort_Wayne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Inuvik", "type": "reg", "size": 2468, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23149925, "NumLink": 0, "digest": "sha256:c51f2f3cef4844e5c800ed3592d85bc69e5f05dc4a53e94c76b2433be16b1a5f" }, { "name": "usr/share/zoneinfo/right/America/Iqaluit", "type": "reg", "size": 2586, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23151324, "NumLink": 0, "digest": "sha256:7179d696e8f2aac641bbe8a0b0635128246fd4669e258befaac2e91170f75d1e" }, { "name": "usr/share/zoneinfo/right/America/Jamaica", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Jamaica", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Jujuy", "type": "reg", "size": 1607, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23152819, "NumLink": 0, "digest": "sha256:29822a6d077e97673b9e892cd65c00709d43e0aa90ce6d84b0c1228083def36d" }, { "name": "usr/share/zoneinfo/right/America/Juneau", "type": "reg", "size": 2902, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23153792, "NumLink": 0, "digest": "sha256:2be628832b78514026f7932644e221fd4490d502f686f069d7ebf8ba0b220c40" }, { "name": "usr/share/zoneinfo/right/America/Kentucky/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Kentucky/Louisville", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Louisville", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Kentucky/Monticello", "type": "reg", "size": 2901, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23155552, "NumLink": 0, "digest": "sha256:ff56ff4d9ee52923c57354d5d836e87cc8acb748bbf0648c2406bcbafaa4227c" }, { "name": "usr/share/zoneinfo/right/America/Knox_IN", "type": "reg", "size": 2977, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23157195, "NumLink": 0, "digest": "sha256:ac4c928ad03acaf42f346aa81bf9d269a513adb14a955ff55a5177927832c6a8" }, { "name": "usr/share/zoneinfo/right/America/Kralendijk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Aruba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/La_Paz", "type": "reg", "size": 783, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23158926, "NumLink": 0, "digest": "sha256:beab009d797e8c2a8607eaf7192b5ff2736c220073fc5c29e45a8cd9dc6a5a1e" }, { "name": "usr/share/zoneinfo/right/America/Lima", "type": "reg", "size": 957, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23159443, "NumLink": 0, "digest": "sha256:c75b82ab26d2838d0eec739aabecbc33de43a72d3f7551e25284197563ad6fcb" }, { "name": "usr/share/zoneinfo/right/America/Los_Angeles", "type": "reg", "size": 3385, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23160074, "NumLink": 0, "digest": "sha256:5f2a6fb2744e29e2a6ac88e89843ce0c74f8934b37d1b35d67e115d5363c9e57" }, { "name": "usr/share/zoneinfo/right/America/Louisville", "type": "reg", "size": 3321, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23161959, "NumLink": 0, "digest": "sha256:2d8d4b0dbd3eda1d9c9992b42fb309f7c645a9ac0048e2dba3283e7ad9d67f1b" }, { "name": "usr/share/zoneinfo/right/America/Lower_Princes", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Aruba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Maceio", "type": "reg", "size": 1296, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23163862, "NumLink": 0, "digest": "sha256:dd3e4475c42101aaa3010513fb3dc80dcf598582c4d7aa3caa0dd1cbd55e23ac" }, { "name": "usr/share/zoneinfo/right/America/Managua", "type": "reg", "size": 1003, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23164661, "NumLink": 0, "digest": "sha256:1a2e937499925a46e4d2b93113e7b035fdc270174a8fb4b65fd61f163b430ca3" }, { "name": "usr/share/zoneinfo/right/America/Manaus", "type": "reg", "size": 1156, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23165300, "NumLink": 0, "digest": "sha256:876c087b224fcebb22e281b18dadd4283844ab83280afc8c9092ad2f8defd3a4" }, { "name": "usr/share/zoneinfo/right/America/Marigot", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Martinique", "type": "reg", "size": 797, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23166078, "NumLink": 0, "digest": "sha256:18a0f75cca7c62ff1b7c8e0463856c1fa811e796806ef23cfd53d40a860861fa" }, { "name": "usr/share/zoneinfo/right/America/Matamoros", "type": "reg", "size": 1956, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23166601, "NumLink": 0, "digest": "sha256:298a0a44d6576a9c127e048262a3f7f1b613653e0520a75bf912a65ccef50771" }, { "name": "usr/share/zoneinfo/right/America/Mazatlan", "type": "reg", "size": 2104, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23167751, "NumLink": 0, "digest": "sha256:972ebc94965c29a285412a68e853fc7729bd741b5be52edeb9f3b9a1a707ac43" }, { "name": "usr/share/zoneinfo/right/America/Mendoza", "type": "reg", "size": 1635, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23168962, "NumLink": 0, "digest": "sha256:0f4bf9977f2591788ba0b60418f7b932da1112abffe03a742ee2b770d4fcefbf" }, { "name": "usr/share/zoneinfo/right/America/Menominee", "type": "reg", "size": 2823, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23169947, "NumLink": 0, "digest": "sha256:a9f238c519f7699a3bdd001ffb5588fc5c80329a14c95309aa424c0026440108" }, { "name": "usr/share/zoneinfo/right/America/Merida", "type": "reg", "size": 1996, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23171534, "NumLink": 0, "digest": "sha256:a6352eb8ee46c326f0231e5e22ae330d465964514c21390e28aa5ddee377fb5c" }, { "name": "usr/share/zoneinfo/right/America/Metlakatla", "type": "reg", "size": 1958, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23172688, "NumLink": 0, "digest": "sha256:0e130ce578bb5bffd9871e92519541592cca5e32e28912f82883efb4348f7382" }, { "name": "usr/share/zoneinfo/right/America/Mexico_City", "type": "reg", "size": 2158, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23173867, "NumLink": 0, "digest": "sha256:2b2e4e7d462f693d46142205a03882b383f3cfbc6eaa0a4c514fe71fd5112f12" }, { "name": "usr/share/zoneinfo/right/America/Miquelon", "type": "reg", "size": 2222, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23175115, "NumLink": 0, "digest": "sha256:7da3a78f48b2870cdb2b246107ad28ad353c006f6d10e26034f8bb7ae299e837" }, { "name": "usr/share/zoneinfo/right/America/Moncton", "type": "reg", "size": 3703, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23176404, "NumLink": 0, "digest": "sha256:d587577011570e8271781f98b52f5ccb8650a7a1dc2c50789f4cb5d5d7e9c13a" }, { "name": "usr/share/zoneinfo/right/America/Monterrey", "type": "reg", "size": 1956, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23178451, "NumLink": 0, "digest": "sha256:a0334e1c8f6ebfdb959a536fea620a72031db45036d563864cdaba4e34b0c2c7" }, { "name": "usr/share/zoneinfo/right/America/Montevideo", "type": "reg", "size": 2090, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23179597, "NumLink": 0, "digest": "sha256:17c9e4bcff4188d1cb3a8bc583991d6ee81896fc64664f8d6b01c02fda66c1a3" }, { "name": "usr/share/zoneinfo/right/America/Montreal", "type": "reg", "size": 4043, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23180808, "NumLink": 0, "digest": "sha256:bd1fdaf567be65339c2fe8cadf9e690d0929548cd731edcb41ae7f322885a590" }, { "name": "usr/share/zoneinfo/right/America/Montserrat", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Nassau", "type": "reg", "size": 2824, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23183080, "NumLink": 0, "digest": "sha256:b3526d4c47155f9f9049070f75b3981b9f17b153e9482afe6e3f83e0f84adad6" }, { "name": "usr/share/zoneinfo/right/America/New_York", "type": "reg", "size": 4085, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23184683, "NumLink": 0, "digest": "sha256:9699b3dbf1b5a2fe33cc0eeb1bae542d83608786c0b1872b07b24adda81556a1" }, { "name": "usr/share/zoneinfo/right/America/Nipigon", "type": "reg", "size": 2671, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23186917, "NumLink": 0, "digest": "sha256:bedddedf42d1ecd3db1eeb61988fa1216f75b06c45a768822a16b4bf3e78542f" }, { "name": "usr/share/zoneinfo/right/America/Nome", "type": "reg", "size": 2916, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23188435, "NumLink": 0, "digest": "sha256:2f167608a9d4171d89ee0a4d68c3ee845ebbd073e3759dc663a95dc8c865e4c1" }, { "name": "usr/share/zoneinfo/right/America/Noronha", "type": "reg", "size": 1268, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23190108, "NumLink": 0, "digest": "sha256:276cc0daf61bee62a6f8ca0636b0da6a4bebf95dbdde6859c7b53434ab6e3eaa" }, { "name": "usr/share/zoneinfo/right/America/North_Dakota/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/North_Dakota/Beulah", "type": "reg", "size": 2929, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23190948, "NumLink": 0, "digest": "sha256:5a05c79be4ba9c4ed5a70aedbb8e83c2864c9ee5d974824130552d11097f654d" }, { "name": "usr/share/zoneinfo/right/America/North_Dakota/Center", "type": "reg", "size": 2929, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23192612, "NumLink": 0, "digest": "sha256:c4daf0f8f179948ca4f3edfef1c4bf6ea9926d157cbb83334d990c4f3ae76fb3" }, { "name": "usr/share/zoneinfo/right/America/North_Dakota/New_Salem", "type": "reg", "size": 2929, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23194273, "NumLink": 0, "digest": "sha256:f728e13f15039666ade97ebb9e0e7d54b575495e14aa88ccf2761d29e5a390f4" }, { "name": "usr/share/zoneinfo/right/America/Ojinaga", "type": "reg", "size": 2062, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23195927, "NumLink": 0, "digest": "sha256:e9cb05ec786e833e837b19a3d7bfe611e6d3ff3da1fc576fa5ea4f44c43f937f" }, { "name": "usr/share/zoneinfo/right/America/Panama", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Cayman", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Pangnirtung", "type": "reg", "size": 2648, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23197164, "NumLink": 0, "digest": "sha256:c71e8ae865312e517ebc4076ecb9665c2cfdc7155549d18462e01275961925b8" }, { "name": "usr/share/zoneinfo/right/America/Paramaribo", "type": "reg", "size": 822, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23198646, "NumLink": 0, "digest": "sha256:69e775220eadc309a7cfce0aabc4936f9e5631a4a64a844d157a8371d5293c5c" }, { "name": "usr/share/zoneinfo/right/America/Phoenix", "type": "reg", "size": 893, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23199171, "NumLink": 0, "digest": "sha256:8a89f0e65cd0a0b2edbbf65a7a81441aa91073b133edac17c25c6c9f809b8995" }, { "name": "usr/share/zoneinfo/right/America/Port-au-Prince", "type": "reg", "size": 1995, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23199760, "NumLink": 0, "digest": "sha256:aab1855d3200ed78c12406a44d8558a9a875dc57f94090b2c205811a92b5e066" }, { "name": "usr/share/zoneinfo/right/America/Port_of_Spain", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Porto_Acre", "type": "reg", "size": 1188, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23200987, "NumLink": 0, "digest": "sha256:fa8436992c68303c75f248539845c855269b6f3c307032f2510b43e0779efbe4" }, { "name": "usr/share/zoneinfo/right/America/Porto_Velho", "type": "reg", "size": 1128, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23201719, "NumLink": 0, "digest": "sha256:753c3bf10a58b02e6b991d48e356a4953cc1cdd3042665a1824dadf58d6ace07" }, { "name": "usr/share/zoneinfo/right/America/Puerto_Rico", "type": "reg", "size": 795, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23202435, "NumLink": 0, "digest": "sha256:a9e478dd8515a4c8086ff535afe44db1cf53b9400ec62aed7b6d122ecfb778f3" }, { "name": "usr/share/zoneinfo/right/America/Punta_Arenas", "type": "reg", "size": 2437, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23202967, "NumLink": 0, "digest": "sha256:9039a86b9fae5f31ebd11cf51e70e79d7fe7e082ef0f9f85a6dac48cb7f945eb" }, { "name": "usr/share/zoneinfo/right/America/Rainy_River", "type": "reg", "size": 2671, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23204364, "NumLink": 0, "digest": "sha256:1680a0ae7e1d154aa9672b6e2d24155987de256acd7273f23177ef258d4ffe16" }, { "name": "usr/share/zoneinfo/right/America/Rankin_Inlet", "type": "reg", "size": 2470, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23205889, "NumLink": 0, "digest": "sha256:1bb3cc33e21e5e7663a0cabcb02f9e7f74ee0619dcd0d84d4a4a31f611698b57" }, { "name": "usr/share/zoneinfo/right/America/Recife", "type": "reg", "size": 1268, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23207291, "NumLink": 0, "digest": "sha256:1e7229c4468b197480ae588656cd52e8ff11bacb3af0bdfab2f090e6d25a9e0c" }, { "name": "usr/share/zoneinfo/right/America/Regina", "type": "reg", "size": 1534, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23208080, "NumLink": 0, "digest": "sha256:7ef7b8f3a4e1baf07289907c77a4218ac0be68c7a24e980940a05cbba77e53c9" }, { "name": "usr/share/zoneinfo/right/America/Resolute", "type": "reg", "size": 2470, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23208978, "NumLink": 0, "digest": "sha256:2a208ed79da175c5081c8db0fb767d9b0e0270e4a73bb95f24ae0ffd22b6354f" }, { "name": "usr/share/zoneinfo/right/America/Rio_Branco", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Porto_Acre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Rosario", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Cordoba", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Santa_Isabel", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Ensenada", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Santarem", "type": "reg", "size": 1158, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23210497, "NumLink": 0, "digest": "sha256:1a927437ef7079f8ce9cb80607c823e609f1c9cd757282718932435dd4e8a5bf" }, { "name": "usr/share/zoneinfo/right/America/Santiago", "type": "reg", "size": 3064, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23211220, "NumLink": 0, "digest": "sha256:1f31a3a5f1e1ea4f97a2cd73d27dc28c51ca294378f1268b021e2e0be6a336c2" }, { "name": "usr/share/zoneinfo/right/America/Santo_Domingo", "type": "reg", "size": 1031, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23212957, "NumLink": 0, "digest": "sha256:24bf349defe5c3ed5d8950593acbcd57dc662784ddfae68b31cddfa02746f2ba" }, { "name": "usr/share/zoneinfo/right/America/Sao_Paulo", "type": "reg", "size": 2556, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23213625, "NumLink": 0, "digest": "sha256:11592bb442b3322b0f50685787c1ea58e5db05774a5c2cb6e133cbdd763c2bc5" }, { "name": "usr/share/zoneinfo/right/America/Scoresbysund", "type": "reg", "size": 2456, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23215107, "NumLink": 0, "digest": "sha256:42653212318e5d075e6fddd5a579507a13bbd0538623d1943cfff1569e24d0de" }, { "name": "usr/share/zoneinfo/right/America/Shiprock", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Sitka", "type": "reg", "size": 2890, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23216534, "NumLink": 0, "digest": "sha256:81ba6e3b87b7f9c9814c4f607a3c722a0bbd8355ab1647c51847882b3a3c0628" }, { "name": "usr/share/zoneinfo/right/America/St_Barthelemy", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/St_Johns", "type": "reg", "size": 4204, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23218260, "NumLink": 0, "digest": "sha256:10784794564849767481803ad10924bd7092c041b5e5859dc7cdf883abe13a7e" }, { "name": "usr/share/zoneinfo/right/America/St_Kitts", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/St_Lucia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/St_Thomas", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/St_Vincent", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Swift_Current", "type": "reg", "size": 1114, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23220672, "NumLink": 0, "digest": "sha256:7752d4a7cd93e6c9a16f89dfa148ce6ac6f491cf40359f9d6730e03b4aedf848" }, { "name": "usr/share/zoneinfo/right/America/Tegucigalpa", "type": "reg", "size": 818, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23221355, "NumLink": 0, "digest": "sha256:c37dd7463adb25b95fd20bd17473e710e03c9c5d36481b4626a82aabd7469983" }, { "name": "usr/share/zoneinfo/right/America/Thule", "type": "reg", "size": 2068, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23221893, "NumLink": 0, "digest": "sha256:67e571d61867a4ea726d7b19f5fabca2a7751219685d57eee29570ec9225f0ea" }, { "name": "usr/share/zoneinfo/right/America/Thunder_Bay", "type": "reg", "size": 2751, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23223108, "NumLink": 0, "digest": "sha256:2c04cafec84e648e5d1154986626b32ebdb0def10d7c8843d27bbee20ad82e5e" }, { "name": "usr/share/zoneinfo/right/America/Tijuana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Ensenada", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Toronto", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Montreal", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Tortola", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Vancouver", "type": "reg", "size": 3441, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23224766, "NumLink": 0, "digest": "sha256:20b9d3c10c060d827a80bb81260a5407b879a95af0e114b9a258c9214ac55f22" }, { "name": "usr/share/zoneinfo/right/America/Virgin", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Anguilla", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/America/Whitehorse", "type": "reg", "size": 2633, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23226731, "NumLink": 0, "digest": "sha256:84e26d472821fc0a5280f3bbd9b7d6d4130ccd78272d637314628cf299f203e5" }, { "name": "usr/share/zoneinfo/right/America/Winnipeg", "type": "reg", "size": 3431, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23228220, "NumLink": 0, "digest": "sha256:a91e3074914af25d44e7428f07b7e15c46a9b1c61adf146d78058bfb95128031" }, { "name": "usr/share/zoneinfo/right/America/Yakutat", "type": "reg", "size": 2854, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23230115, "NumLink": 0, "digest": "sha256:a8d6177b9fb9653500c7a5468e35508251be2a6dce9040ad9ebfbffcd4cc3ad2" }, { "name": "usr/share/zoneinfo/right/America/Yellowknife", "type": "reg", "size": 2520, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23231745, "NumLink": 0, "digest": "sha256:ffb6c39b1c757ff250651391b07dc8d3e3ea361f837472ef57c62eea144677ef" }, { "name": "usr/share/zoneinfo/right/Antarctica/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Antarctica/Casey", "type": "reg", "size": 837, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23233212, "NumLink": 0, "digest": "sha256:f2ca1ef915c00d2afcdb6d67afb8f02bd84eaa77953373a0b0744bb22814e632" }, { "name": "usr/share/zoneinfo/right/Antarctica/Davis", "type": "reg", "size": 837, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23233752, "NumLink": 0, "digest": "sha256:68203c490a421f72442b46179525552b863773b136d499e9fda7dde39a52b234" }, { "name": "usr/share/zoneinfo/right/Antarctica/DumontDUrville", "type": "reg", "size": 742, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23234302, "NumLink": 0, "digest": "sha256:3b2fc9d546516f429b2e95338925a2e52c328d0145157b311830c8f8fcbe56ea" }, { "name": "usr/share/zoneinfo/right/Antarctica/Macquarie", "type": "reg", "size": 2069, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23234801, "NumLink": 0, "digest": "sha256:05971185e4ba26201409ea2b3045b99efc9402e78cbb89bd4fcaaaaef76ec016" }, { "name": "usr/share/zoneinfo/right/Antarctica/Mawson", "type": "reg", "size": 751, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23235993, "NumLink": 0, "digest": "sha256:6d71da7e0dc64cde67ba892f72d2635aecfc6f8b5ba32d8e4bce77b6d43b7b1c" }, { "name": "usr/share/zoneinfo/right/Antarctica/McMurdo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../NZ", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Antarctica/Palmer", "type": "reg", "size": 1958, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23236524, "NumLink": 0, "digest": "sha256:890b910a9d56462b6b02cb97f94e4c6b1bc21d28e22c91856ffdb4491e5c9af1" }, { "name": "usr/share/zoneinfo/right/Antarctica/Rothera", "type": "reg", "size": 712, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23237665, "NumLink": 0, "digest": "sha256:2248bdca29d8909f713111c13c4562206c315e778dae04191e2c71be7e41d66e" }, { "name": "usr/share/zoneinfo/right/Antarctica/South_Pole", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../NZ", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Antarctica/Syowa", "type": "reg", "size": 713, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23238183, "NumLink": 0, "digest": "sha256:2ed146fb4b60eec7f3fd2a45ec5a47efe97628bc6f6d718bbadc4e7d0efd2699" }, { "name": "usr/share/zoneinfo/right/Antarctica/Troll", "type": "reg", "size": 1702, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23238657, "NumLink": 0, "digest": "sha256:0015c4226733a9e187e53587097ff75b4cb2aedf4157811e50d2aa88c658cb08" }, { "name": "usr/share/zoneinfo/right/Antarctica/Vostok", "type": "reg", "size": 713, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23239650, "NumLink": 0, "digest": "sha256:ac1aa91f07d0fe56ae6f0df158a36e86063712784e6692f95b1804815cbf1ee9" }, { "name": "usr/share/zoneinfo/right/Arctic/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Arctic/Longyearbyen", "type": "reg", "size": 2791, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23240160, "NumLink": 0, "digest": "sha256:b9f4a8a248c4b945a12640b4be549baaa438a9c3472822028e9f4988cd4e8b63" }, { "name": "usr/share/zoneinfo/right/Asia/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Aden", "type": "reg", "size": 713, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23241753, "NumLink": 0, "digest": "sha256:cc7153eb830b43242dfe8683480c44497fc209145045c93d2e75774495d2cfc8" }, { "name": "usr/share/zoneinfo/right/Asia/Almaty", "type": "reg", "size": 1557, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23242229, "NumLink": 0, "digest": "sha256:cd94dd030db0f5d766b246af2dc09f394a1e1a6abca0b84385a6b460c0a95001" }, { "name": "usr/share/zoneinfo/right/Asia/Amman", "type": "reg", "size": 2417, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23243139, "NumLink": 0, "digest": "sha256:0dfa946fc43a7d4ad00e75aba44720018d82f36411351b2e5a103dbfadaf0d8c" }, { "name": "usr/share/zoneinfo/right/Asia/Anadyr", "type": "reg", "size": 1748, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23244511, "NumLink": 0, "digest": "sha256:658b7df8bb11f46e1c785e1ecb46e54a7e4e4435da78edf0ed9f3c8920ee7e9e" }, { "name": "usr/share/zoneinfo/right/Asia/Aqtau", "type": "reg", "size": 1543, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23245534, "NumLink": 0, "digest": "sha256:e900765cb6d9b6c7d3320185701d7f70c8bfe1e462abf1ec687c2494afbe027a" }, { "name": "usr/share/zoneinfo/right/Asia/Aqtobe", "type": "reg", "size": 1573, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23246447, "NumLink": 0, "digest": "sha256:fe5ae88a2c0c1af7dab63e796db665ef7037a045ee93bb480f742b24143dc13e" }, { "name": "usr/share/zoneinfo/right/Asia/Ashgabat", "type": "reg", "size": 1177, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23247367, "NumLink": 0, "digest": "sha256:ce671b85f724114ded28698c8a0f90df2451b52b1ab02bc266067c6236b45792" }, { "name": "usr/share/zoneinfo/right/Asia/Ashkhabad", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Ashgabat", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Atyrau", "type": "reg", "size": 1551, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23248131, "NumLink": 0, "digest": "sha256:3ba6963e4536ac91a31a8c53de06b962be6f2265828c1fb7d8471ad2513a6c72" }, { "name": "usr/share/zoneinfo/right/Asia/Baghdad", "type": "reg", "size": 1530, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23249050, "NumLink": 0, "digest": "sha256:d50a00eca951cc4945a502bfc4993096fdf661213ec534bb8a7dc4774af88000" }, { "name": "usr/share/zoneinfo/right/Asia/Bahrain", "type": "reg", "size": 751, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23249965, "NumLink": 0, "digest": "sha256:c39550b6dca350b213a7bd957339b96089c9d4ce4d5dd975444af4d848afd06c" }, { "name": "usr/share/zoneinfo/right/Asia/Baku", "type": "reg", "size": 1795, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23250454, "NumLink": 0, "digest": "sha256:15d6954f582895136fe83e61ef7defe2abe84ae2670be41a46adfdf5021d152a" }, { "name": "usr/share/zoneinfo/right/Asia/Bangkok", "type": "reg", "size": 746, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23251494, "NumLink": 0, "digest": "sha256:27712ede5e3faa189b802aff8b25bb37058710ca9d62439643304bc522ba03d8" }, { "name": "usr/share/zoneinfo/right/Asia/Barnaul", "type": "reg", "size": 1781, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23251991, "NumLink": 0, "digest": "sha256:f422f78d9ea036ae9979c3ea4ec864d06930257d671613e49457160d602c2019" }, { "name": "usr/share/zoneinfo/right/Asia/Beirut", "type": "reg", "size": 2715, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23253036, "NumLink": 0, "digest": "sha256:3e24a502c1fb5fb0dd7a8c738f28074b8e785311ba73a33fb597c2172ca288a0" }, { "name": "usr/share/zoneinfo/right/Asia/Bishkek", "type": "reg", "size": 1571, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23254578, "NumLink": 0, "digest": "sha256:ea503d6f5d42be0d3b9cc97dcc71a07b570be925d94104180652bd4ad8667031" }, { "name": "usr/share/zoneinfo/right/Asia/Brunei", "type": "reg", "size": 755, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23255497, "NumLink": 0, "digest": "sha256:38e8f436a5483d23eb24c1422a098014239e51cf74ae41120f3d98662a9513d2" }, { "name": "usr/share/zoneinfo/right/Asia/Calcutta", "type": "reg", "size": 852, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23255993, "NumLink": 0, "digest": "sha256:637147fe7b40e10955c08b61ecc5639148589ce9bd6939cf7b98bc02cccd5036" }, { "name": "usr/share/zoneinfo/right/Asia/Chita", "type": "reg", "size": 1783, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23256570, "NumLink": 0, "digest": "sha256:0b4b8ac6a5125aae18dad505db9a49a269f4c61054dc0adf0bc3e19436fc809a" }, { "name": "usr/share/zoneinfo/right/Asia/Choibalsan", "type": "reg", "size": 1517, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23257605, "NumLink": 0, "digest": "sha256:edc88f73de96408868609ce2dfa5c125aededfd799ff7b3b2c2e5c216898cd31" }, { "name": "usr/share/zoneinfo/right/Asia/Chongqing", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Chungking", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Colombo", "type": "reg", "size": 939, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23258557, "NumLink": 0, "digest": "sha256:514a6511932107df30932d496a3e469a0415837679103d50ac262694b0699b61" }, { "name": "usr/share/zoneinfo/right/Asia/Dacca", "type": "reg", "size": 896, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23259131, "NumLink": 0, "digest": "sha256:bc6a481333c3867538193302c3390acc62a591d8556f378fc0fb90f30c75c66e" }, { "name": "usr/share/zoneinfo/right/Asia/Damascus", "type": "reg", "size": 2860, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23259697, "NumLink": 0, "digest": "sha256:e23e8576a6f8b5b65a356e535ba0ffc916d211a155207e486dd40b1757f3b831" }, { "name": "usr/share/zoneinfo/right/Asia/Dhaka", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Dacca", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Dili", "type": "reg", "size": 779, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23261338, "NumLink": 0, "digest": "sha256:29412d668b9a191c7ca3132f85e479f4fbba5daa8b7ddc6ea599639e96fe9299" }, { "name": "usr/share/zoneinfo/right/Asia/Dubai", "type": "reg", "size": 713, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23261846, "NumLink": 0, "digest": "sha256:8137fb36c9c9f6f273c75abeb39d415d411777289d0dc361c28d23e741933d20" }, { "name": "usr/share/zoneinfo/right/Asia/Dushanbe", "type": "reg", "size": 1147, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23262323, "NumLink": 0, "digest": "sha256:18ba97fd4f84ae2c99f6a60b651ec043bf5d464600aa68b7fdd331a15455c5e2" }, { "name": "usr/share/zoneinfo/right/Asia/Famagusta", "type": "reg", "size": 2582, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23263022, "NumLink": 0, "digest": "sha256:40438f760718c79a99e171a199690123f0cc531fef996423c2ca840d20b6bce9" }, { "name": "usr/share/zoneinfo/right/Asia/Gaza", "type": "reg", "size": 2835, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23264463, "NumLink": 0, "digest": "sha256:6ed90d85deebc9fb9292b65cbb103fea833bd5c9c3890598c587a5ff66fb01b1" }, { "name": "usr/share/zoneinfo/right/Asia/Harbin", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Hebron", "type": "reg", "size": 2863, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23266107, "NumLink": 0, "digest": "sha256:fa78ccb4bf6e2c7c212cb2ffd3d0e892ab59db2f96cba57d67e1bfc84c40096f" }, { "name": "usr/share/zoneinfo/right/Asia/Ho_Chi_Minh", "type": "reg", "size": 915, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23267728, "NumLink": 0, "digest": "sha256:18f4bc73f6e1b70aa7af8cb7f03b6191b91c4fe160cdabe7365a8c15c98fd209" }, { "name": "usr/share/zoneinfo/right/Asia/Hong_Kong", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Hongkong", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Hovd", "type": "reg", "size": 1447, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23268339, "NumLink": 0, "digest": "sha256:68a7869d2b4493ef412edda98d0c69171d9012de857f78f93bc1aa511d357753" }, { "name": "usr/share/zoneinfo/right/Asia/Irkutsk", "type": "reg", "size": 1802, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23269212, "NumLink": 0, "digest": "sha256:758dfc5e377e82cab46bde761d3678cb8136a7e3f6b7bc4f18a14ed8e2e45ade" }, { "name": "usr/share/zoneinfo/right/Asia/Istanbul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Turkey", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Jakarta", "type": "reg", "size": 932, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23270295, "NumLink": 0, "digest": "sha256:1e1d6c8a2a336137b702b0e68da98b2b2c3135a1844f9bc17d05d0eff1ef18bd" }, { "name": "usr/share/zoneinfo/right/Asia/Jayapura", "type": "reg", "size": 791, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23270873, "NumLink": 0, "digest": "sha256:ccfa8a6a43b97d5dd2e2c33f84951460b2bffcc1202919ef38c3b097a83167db" }, { "name": "usr/share/zoneinfo/right/Asia/Jerusalem", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Israel", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Kabul", "type": "reg", "size": 755, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23271421, "NumLink": 0, "digest": "sha256:05079923f0dcdb139abc702b063aec10c46f283019af08087b4d126f3317a5f9" }, { "name": "usr/share/zoneinfo/right/Asia/Kamchatka", "type": "reg", "size": 1724, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23271922, "NumLink": 0, "digest": "sha256:91922e506d3db985233b289c6c5be03d1c9a87cf18253b47ab3a77217e52a8c3" }, { "name": "usr/share/zoneinfo/right/Asia/Karachi", "type": "reg", "size": 957, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23272934, "NumLink": 0, "digest": "sha256:08c8c89e2687b19464bc067b6b368bfe3106c980538c0b3314e7301e192a295a" }, { "name": "usr/share/zoneinfo/right/Asia/Kashgar", "type": "reg", "size": 713, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23273531, "NumLink": 0, "digest": "sha256:7e9286573873c9113636fbac7e5559a35faeca0db3fb73da0a3bd4fc5f65a456" }, { "name": "usr/share/zoneinfo/right/Asia/Kathmandu", "type": "reg", "size": 764, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23274009, "NumLink": 0, "digest": "sha256:8bd14af9de4726482304666173d593a0847f2b429cada1a7fea3fa70a10696e4" }, { "name": "usr/share/zoneinfo/right/Asia/Katmandu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Kathmandu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Khandyga", "type": "reg", "size": 1837, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23274544, "NumLink": 0, "digest": "sha256:2b08289062a1307816fb246bf351b9264af434aa6a6a65551b8e6cfaa208e5f8" }, { "name": "usr/share/zoneinfo/right/Asia/Kolkata", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Calcutta", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Krasnoyarsk", "type": "reg", "size": 1769, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23275644, "NumLink": 0, "digest": "sha256:0e93c034f7647538f5a51adc8195d9cace109a45b5c5e3e6481fd0247c0ad11f" }, { "name": "usr/share/zoneinfo/right/Asia/Kuala_Lumpur", "type": "reg", "size": 950, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23276677, "NumLink": 0, "digest": "sha256:c8b289f4113407322af39192ffae6d4bd70fc07dece86db7afbf51bf51ab36ab" }, { "name": "usr/share/zoneinfo/right/Asia/Kuching", "type": "reg", "size": 1047, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23277254, "NumLink": 0, "digest": "sha256:1d16f6894cb9b51fa6426bf60bf6e28ca8953776a5d007d6f95a9a160658be40" }, { "name": "usr/share/zoneinfo/right/Asia/Kuwait", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Aden", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Macao", "type": "reg", "size": 1311, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23277938, "NumLink": 0, "digest": "sha256:1d776cf7633495715a0794e17c4cad9338ab05fb74fce498890acd45b6922082" }, { "name": "usr/share/zoneinfo/right/Asia/Macau", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Macao", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Magadan", "type": "reg", "size": 1784, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23278774, "NumLink": 0, "digest": "sha256:1e59de996c881c4e1440a0840b80ae9accef36d547f947e7d139629675a95ba5" }, { "name": "usr/share/zoneinfo/right/Asia/Makassar", "type": "reg", "size": 828, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23279806, "NumLink": 0, "digest": "sha256:6bb9b9d31d2f3c57b17a9ec143294ffaa86669e793adf98c5acd1a980d6d4125" }, { "name": "usr/share/zoneinfo/right/Asia/Manila", "type": "reg", "size": 893, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23280325, "NumLink": 0, "digest": "sha256:eef003e76600751c7e9e742f9aadee8e9a54fea94aba62815ec755d633772d32" }, { "name": "usr/share/zoneinfo/right/Asia/Muscat", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Dubai", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Nicosia", "type": "reg", "size": 2556, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23280953, "NumLink": 0, "digest": "sha256:b801d86c6b957dd1affe34a2d19a0c580be861d8ccd283d9f48e2dc991fe3696" }, { "name": "usr/share/zoneinfo/right/Asia/Novokuznetsk", "type": "reg", "size": 1723, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23282384, "NumLink": 0, "digest": "sha256:25ec788512729a0767bf726100faadc6e7d9d8c3d2f93f05a537480a1677c594" }, { "name": "usr/share/zoneinfo/right/Asia/Novosibirsk", "type": "reg", "size": 1781, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23283404, "NumLink": 0, "digest": "sha256:133caf0866411002a774c95699d4c3d655fc32451cd6622142cbfe322f2f9b0c" }, { "name": "usr/share/zoneinfo/right/Asia/Omsk", "type": "reg", "size": 1769, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23284446, "NumLink": 0, "digest": "sha256:e4e00ab7d4297379b94c840a93dec5aa02ee4675c0b0a063c6bb28ffb8a8ff96" }, { "name": "usr/share/zoneinfo/right/Asia/Oral", "type": "reg", "size": 1565, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23285470, "NumLink": 0, "digest": "sha256:8538cffe3000c7c62519075440e7efcf120610601bc38d4f74cf8c0c20fe8326" }, { "name": "usr/share/zoneinfo/right/Asia/Phnom_Penh", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangkok", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Pontianak", "type": "reg", "size": 935, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23286440, "NumLink": 0, "digest": "sha256:5387a863122580120cb3ee351bcada3b3dfbf163424291b97bac4e2cabd9845f" }, { "name": "usr/share/zoneinfo/right/Asia/Pyongyang", "type": "reg", "size": 807, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23287017, "NumLink": 0, "digest": "sha256:1ee9bd69289e2d175fc25a780f11c1c4b71ff6dd172427015e47e8b9afc7d9c0" }, { "name": "usr/share/zoneinfo/right/Asia/Qatar", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bahrain", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Qyzylorda", "type": "reg", "size": 1573, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23287578, "NumLink": 0, "digest": "sha256:d58e0f06c11ed11cbc3543944c48df4e7850c15f375b2c0784bc40181f5cbcaa" }, { "name": "usr/share/zoneinfo/right/Asia/Rangoon", "type": "reg", "size": 823, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23288499, "NumLink": 0, "digest": "sha256:e82e81e81d7becfd4796a9620afc7950e9dc8ea1cf28ce85b91f11f8e94ff2b3" }, { "name": "usr/share/zoneinfo/right/Asia/Riyadh", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Aden", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Saigon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Ho_Chi_Minh", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Sakhalin", "type": "reg", "size": 1760, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23289091, "NumLink": 0, "digest": "sha256:20e5edafd438adf3d299e2d1020f3034b18cc943e0b8e6183a4783fd68c91660" }, { "name": "usr/share/zoneinfo/right/Asia/Samarkand", "type": "reg", "size": 1145, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23290126, "NumLink": 0, "digest": "sha256:610fa9ffafe3bf07021986093d23c13be582da74f5240418538dce729e52cac7" }, { "name": "usr/share/zoneinfo/right/Asia/Seoul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../ROK", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Shanghai", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../PRC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Singapore", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Singapore", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Srednekolymsk", "type": "reg", "size": 1770, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23290931, "NumLink": 0, "digest": "sha256:a86ea1167361757c9c361e526dc5d6dc955e54127bbe26bb329c10cdaf3b910c" }, { "name": "usr/share/zoneinfo/right/Asia/Taipei", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../ROC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Tashkent", "type": "reg", "size": 1161, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23291991, "NumLink": 0, "digest": "sha256:2c547ea5d0b629d373549ae10d689305371b1b2ad50f50a9674d9dddb9d6c292" }, { "name": "usr/share/zoneinfo/right/Asia/Tbilisi", "type": "reg", "size": 1606, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23292699, "NumLink": 0, "digest": "sha256:fc510dc1e0fb0046ab25efb7e690494b8de952653c47e36e120126ae8f90090e" }, { "name": "usr/share/zoneinfo/right/Asia/Tehran", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Iran", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Tel_Aviv", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Israel", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Thimbu", "type": "reg", "size": 755, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23293713, "NumLink": 0, "digest": "sha256:3ff501701002f41f0a8104e3f6bf7e510ed880c196cf00fd5df68c05af58368c" }, { "name": "usr/share/zoneinfo/right/Asia/Thimphu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Thimbu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Tokyo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Japan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Tomsk", "type": "reg", "size": 1781, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23294266, "NumLink": 0, "digest": "sha256:f2607287c46263b4309de532febe5bef76f9608d9ff63086073d70106f1244fe" }, { "name": "usr/share/zoneinfo/right/Asia/Ujung_Pandang", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Makassar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Ulaanbaatar", "type": "reg", "size": 1447, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23295371, "NumLink": 0, "digest": "sha256:fb2a3f180a8e9876464b94f82d304af657abe650242cca5e1f213c79ad23d1fa" }, { "name": "usr/share/zoneinfo/right/Asia/Ulan_Bator", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Ulaanbaatar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Urumqi", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Kashgar", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Ust-Nera", "type": "reg", "size": 1816, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23296320, "NumLink": 0, "digest": "sha256:8d96e0257286d1a9a587ab8282502edfd46ff11f689c1781024ef1983698b483" }, { "name": "usr/share/zoneinfo/right/Asia/Vientiane", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bangkok", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Vladivostok", "type": "reg", "size": 1770, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23297410, "NumLink": 0, "digest": "sha256:baa65ed34a7bd4fb6cb2d3049bd300e8d1a4c94da531440f228eabf118cbdf1d" }, { "name": "usr/share/zoneinfo/right/Asia/Yakutsk", "type": "reg", "size": 1769, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23298432, "NumLink": 0, "digest": "sha256:198fe2c858c12f6ea9694e14082c83d7cd2b0cfad08d777e24649a32f4d4cd77" }, { "name": "usr/share/zoneinfo/right/Asia/Yangon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Rangoon", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Asia/Yekaterinburg", "type": "reg", "size": 1807, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23299500, "NumLink": 0, "digest": "sha256:b628820d8324f3f6f5158b205f2d2ad039c39f902c224069a0b1e4fe5d34d2fc" }, { "name": "usr/share/zoneinfo/right/Asia/Yerevan", "type": "reg", "size": 1739, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23300540, "NumLink": 0, "digest": "sha256:ef2995b9457cf5a134415bd2edc791e517cf105b82c996d562ff7924e96ef17a" }, { "name": "usr/share/zoneinfo/right/Atlantic/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Atlantic/Azores", "type": "reg", "size": 4019, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23301590, "NumLink": 0, "digest": "sha256:94aa009afe8600f7e4e9d2e08010d9e8e298c7db4b5d037083aae2623dd39c7e" }, { "name": "usr/share/zoneinfo/right/Atlantic/Bermuda", "type": "reg", "size": 2544, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23303763, "NumLink": 0, "digest": "sha256:d6de741b6c7895bfd687374854ea64fb2998d65436d657d27bd4c7c59b351918" }, { "name": "usr/share/zoneinfo/right/Atlantic/Canary", "type": "reg", "size": 2451, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23305215, "NumLink": 0, "digest": "sha256:f0bf9911e3c52ec1a10e1b9c0cb94d323c7425614948efc559ffe15c67fb48cd" }, { "name": "usr/share/zoneinfo/right/Atlantic/Cape_Verde", "type": "reg", "size": 810, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23306595, "NumLink": 0, "digest": "sha256:26e5af107ba390b89da815bf73393eda913c93bf59da49028d07c2de8c47a93f" }, { "name": "usr/share/zoneinfo/right/Atlantic/Faeroe", "type": "reg", "size": 2369, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23307116, "NumLink": 0, "digest": "sha256:4f5a41b4ae349e1c6466cba14b5afaf7d7b4a9623fc8395173e4d3a2b4a5f90d" }, { "name": "usr/share/zoneinfo/right/Atlantic/Faroe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Faeroe", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Atlantic/Jan_Mayen", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Arctic/Longyearbyen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Atlantic/Madeira", "type": "reg", "size": 4024, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23308535, "NumLink": 0, "digest": "sha256:35dedfac50f7e188bdf50bf3e03fd597e822d77b353461bbb60e3ffc3be1b71f" }, { "name": "usr/share/zoneinfo/right/Atlantic/Reykjavik", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Iceland", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Atlantic/South_Georgia", "type": "reg", "size": 690, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23310760, "NumLink": 0, "digest": "sha256:443c6fad70d4b18113f7c9377ee84d4449aa7fca3b0b7a215fe7ef37405210a5" }, { "name": "usr/share/zoneinfo/right/Atlantic/St_Helena", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Africa/Abidjan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Atlantic/Stanley", "type": "reg", "size": 1777, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23311300, "NumLink": 0, "digest": "sha256:fb5739968a69015fe6f3848e3139045a95883307b05b8f7d21ffb48182bf4567" }, { "name": "usr/share/zoneinfo/right/Australia/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Australia/ACT", "type": "reg", "size": 2763, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23312393, "NumLink": 0, "digest": "sha256:3cb5754502c335e80d639b47a7f36ddda899d8456ebfe72308882ee5ef92a698" }, { "name": "usr/share/zoneinfo/right/Australia/Adelaide", "type": "reg", "size": 2778, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23313946, "NumLink": 0, "digest": "sha256:02aaaee74a3e5b3d1629ae41daa5b46da01708d3bb87b3c7100c1e7b8202ab81" }, { "name": "usr/share/zoneinfo/right/Australia/Brisbane", "type": "reg", "size": 992, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23315538, "NumLink": 0, "digest": "sha256:ddda440f5a5595a004677523165714a25709a156027554a06dd427d5308d9b18" }, { "name": "usr/share/zoneinfo/right/Australia/Broken_Hill", "type": "reg", "size": 2814, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23316176, "NumLink": 0, "digest": "sha256:fd0d2135fb2fa2835646f9e83c23e040bbd8e45b949f3b181925049c7cf419d9" }, { "name": "usr/share/zoneinfo/right/Australia/Canberra", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "ACT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Australia/Currie", "type": "reg", "size": 2763, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23317839, "NumLink": 0, "digest": "sha256:f37c37574a6bbbebaf7d25eae300f4499741c50b8967335185ba7ee122c56869" }, { "name": "usr/share/zoneinfo/right/Australia/Darwin", "type": "reg", "size": 863, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23319388, "NumLink": 0, "digest": "sha256:a7223b77c9ca3ab6de014f4f9b566c79dd3f4161c5ea4223b6ff8608285535d9" }, { "name": "usr/share/zoneinfo/right/Australia/Eucla", "type": "reg", "size": 1029, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23319975, "NumLink": 0, "digest": "sha256:2b7483a966785d32052458bb16347dc254f8b94bcfab5eb914f4fb68b6b2a044" }, { "name": "usr/share/zoneinfo/right/Australia/Hobart", "type": "reg", "size": 2875, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23320635, "NumLink": 0, "digest": "sha256:b833dd205698e9e4ec4f134c910a46c2c203379594b70fb3dc15dac7d8d15a42" }, { "name": "usr/share/zoneinfo/right/Australia/LHI", "type": "reg", "size": 2415, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23322236, "NumLink": 0, "digest": "sha256:63e2d8d01b17c6ca1a6e7c7eedeb65f1fd8c2611c7354458bd44dac83e8f4c84" }, { "name": "usr/share/zoneinfo/right/Australia/Lindeman", "type": "reg", "size": 1062, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23323610, "NumLink": 0, "digest": "sha256:9134536b2b9078c1807e7529de64da0bc34f32f97aea996b769ccaa474c3aa12" }, { "name": "usr/share/zoneinfo/right/Australia/Lord_Howe", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "LHI", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Australia/Melbourne", "type": "reg", "size": 2763, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23324330, "NumLink": 0, "digest": "sha256:f11ce1fe7a552704c280c6e642ab51a416aff8ad6b9d9c987e90280ce0c6fc3f" }, { "name": "usr/share/zoneinfo/right/Australia/NSW", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "ACT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Australia/North", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Darwin", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Australia/Perth", "type": "reg", "size": 1019, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23325936, "NumLink": 0, "digest": "sha256:dd69002d8273324fcb2dff6a52a11667b34b9cdbd36858d5ccda4f2785b7ef7a" }, { "name": "usr/share/zoneinfo/right/Australia/Queensland", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Brisbane", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Australia/South", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Adelaide", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Australia/Sydney", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "ACT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Australia/Tasmania", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Hobart", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Australia/Victoria", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Melbourne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Australia/West", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Perth", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Australia/Yancowinna", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Broken_Hill", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Brazil/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Brazil/Acre", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Porto_Acre", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Brazil/DeNoronha", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Noronha", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Brazil/East", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Sao_Paulo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Brazil/West", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Manaus", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/CET", "type": "reg", "size": 2642, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23326941, "NumLink": 0, "digest": "sha256:a9ab0888ef44577631cf924205405001a436f7d97899c8989907aba1b77a61be" }, { "name": "usr/share/zoneinfo/right/CST6CDT", "type": "reg", "size": 2834, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23328412, "NumLink": 0, "digest": "sha256:fc4181f42429479b45e3b5d1e9d8775017957bca5c82fc9530769fcb81b2fe8e" }, { "name": "usr/share/zoneinfo/right/Canada/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Canada/Atlantic", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Halifax", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Canada/Central", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Winnipeg", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Canada/Eastern", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Montreal", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Canada/Mountain", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Edmonton", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Canada/Newfoundland", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/St_Johns", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Canada/Pacific", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Vancouver", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Canada/Saskatchewan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Regina", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Canada/Yukon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Whitehorse", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Chile/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Chile/Continental", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Santiago", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Chile/EasterIsland", "type": "reg", "size": 2768, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23330371, "NumLink": 0, "digest": "sha256:b8c22dce2336c2177f7f27feecaf145c40f13e16b5038abe13ce8dd764ec6673" }, { "name": "usr/share/zoneinfo/right/Cuba", "type": "reg", "size": 2977, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23331930, "NumLink": 0, "digest": "sha256:0d4bfd6b414442661f79556ac625c9f30e051af6694be67e3ad312e9e9589c50" }, { "name": "usr/share/zoneinfo/right/EET", "type": "reg", "size": 2416, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23333598, "NumLink": 0, "digest": "sha256:7a4178745768032216702f31fa03f676677d5951079d7e17856ab4be0ddc4061" }, { "name": "usr/share/zoneinfo/right/EST", "type": "reg", "size": 667, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23334948, "NumLink": 0, "digest": "sha256:e7c90a5d782d8843b78996aaf9cc7d332f29d923e8b41739fa0d523b6675a816" }, { "name": "usr/share/zoneinfo/right/EST5EDT", "type": "reg", "size": 2834, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23335393, "NumLink": 0, "digest": "sha256:0f7e22d9f44ba8c1c49034d187a3910eabea89ea5702363f55eadfcd12e01daa" }, { "name": "usr/share/zoneinfo/right/Egypt", "type": "reg", "size": 2512, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23336984, "NumLink": 0, "digest": "sha256:a3c84ceb744bbb495b49ef286308143f267da03f75931b82fdcb5c5a3aebcdd8" }, { "name": "usr/share/zoneinfo/right/Eire", "type": "reg", "size": 4071, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23338418, "NumLink": 0, "digest": "sha256:2004b00c415e097897394d0fcbe0e1b28f6db7b708f7777d51344a73de890132" }, { "name": "usr/share/zoneinfo/right/Etc/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Etc/GMT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Etc/GMT+0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Etc/GMT+1", "type": "reg", "size": 669, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23340689, "NumLink": 0, "digest": "sha256:9012b089ee5a16e2015052ea85bac9a4b506801bb4acbdc9e03b4d712ef198dd" }, { "name": "usr/share/zoneinfo/right/Etc/GMT+10", "type": "reg", "size": 670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23341141, "NumLink": 0, "digest": "sha256:76db27877af699cfe9adbc2bff16b7cef3fe3b9f74f09cf277b129e32260f736" }, { "name": "usr/share/zoneinfo/right/Etc/GMT+11", "type": "reg", "size": 670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23341593, "NumLink": 0, "digest": "sha256:704c6797421f83f7b8a2e0d2fb8dc81bdcb0d35557fac776eb3f015f86405ed6" }, { "name": "usr/share/zoneinfo/right/Etc/GMT+12", "type": "reg", "size": 670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23342046, "NumLink": 0, "digest": "sha256:cf46ced23a838bea5786cb93a1d8a6fecc8767bdf8e038d288f29716ee516393" }, { "name": "usr/share/zoneinfo/right/Etc/GMT+2", "type": "reg", "size": 669, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23342499, "NumLink": 0, "digest": "sha256:d79c8c528f6339f8db638202241705f906bfc75898e1898c163fa660e3139e69" }, { "name": "usr/share/zoneinfo/right/Etc/GMT+3", "type": "reg", "size": 669, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23342952, "NumLink": 0, "digest": "sha256:c779ce86e70bb6f078ae7eaea3eec065cf34d174193efe2c0d8269ab56a315a5" }, { "name": "usr/share/zoneinfo/right/Etc/GMT+4", "type": "reg", "size": 669, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23343405, "NumLink": 0, "digest": "sha256:c0127004db0b9e3f959a7d5a2ce85e945d9f6cbab766b84ea7ad290c205a36fa" }, { "name": "usr/share/zoneinfo/right/Etc/GMT+5", "type": "reg", "size": 669, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23343856, "NumLink": 0, "digest": "sha256:b4c34c2105cee69da93a16895a70309d6f66cbc3963e50fbc34a3323c1fb702d" }, { "name": "usr/share/zoneinfo/right/Etc/GMT+6", "type": "reg", "size": 669, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23344307, "NumLink": 0, "digest": "sha256:ee118477c847ebfb76305fb363fb15e85eb96321c4ddbf7342c66e2e96ce3dbd" }, { "name": "usr/share/zoneinfo/right/Etc/GMT+7", "type": "reg", "size": 669, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23344760, "NumLink": 0, "digest": "sha256:b27b23ce790d6fd0c471e0e3b982d8c17bf3c4eb80b5e96c4746d188d9e0befd" }, { "name": "usr/share/zoneinfo/right/Etc/GMT+8", "type": "reg", "size": 669, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23345214, "NumLink": 0, "digest": "sha256:86c26e9def2a5dcee6c2df681fab85b0bc007d9598ec04b9322f43238cb29d15" }, { "name": "usr/share/zoneinfo/right/Etc/GMT+9", "type": "reg", "size": 669, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23345668, "NumLink": 0, "digest": "sha256:a90f65d22e4d8e80308d4dc9bef7b81d8cdb0a475725df4fe8b4629afa28b9d0" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Etc/GMT-1", "type": "reg", "size": 670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23346152, "NumLink": 0, "digest": "sha256:a41423d3823b3f569397236083416aad827ce76ba59b60c3e90b7d770399c51a" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-10", "type": "reg", "size": 671, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23346603, "NumLink": 0, "digest": "sha256:4d69d3e560e906a2577bcd83ad7311ec9dbdd30eea0f7d8528a2b6e16c7a0232" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-11", "type": "reg", "size": 671, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23347056, "NumLink": 0, "digest": "sha256:1f5428fafb9651fd439f216d062ee891777ab36678e3691b0aefe33c124b59e1" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-12", "type": "reg", "size": 671, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23347507, "NumLink": 0, "digest": "sha256:50a8dc6b9660c4aca6babc6af0470463410d0196745f49824f38a03e0f6c1410" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-13", "type": "reg", "size": 671, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23347959, "NumLink": 0, "digest": "sha256:c11600b000c15510f07608a1e114b211b9cfd1503d3b2218fc6714bff20d66ba" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-14", "type": "reg", "size": 671, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23348412, "NumLink": 0, "digest": "sha256:41247eb4e0246a199f0efcec850f45bb8af4eb81a9a3370cc826b782ea741df6" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-2", "type": "reg", "size": 670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23348865, "NumLink": 0, "digest": "sha256:d12a5d3f5ce6aaa1cf0c06dbb47f0453cc50df54294775dfff2572ace625985d" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-3", "type": "reg", "size": 670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23349316, "NumLink": 0, "digest": "sha256:ecc1a893c3f29152db79772575ffabd6560594896bad41a22a891b22063b24fd" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-4", "type": "reg", "size": 670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23349768, "NumLink": 0, "digest": "sha256:8cc82f5c8d7c9c91f94e85b79bfff7f6cd20c6caf8b7e584a801453f7665d109" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-5", "type": "reg", "size": 670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23350218, "NumLink": 0, "digest": "sha256:ab8fd10e20bcc651da9a0576a54ba9a078a5c5cb5d0b3360b62cf2f89c107448" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-6", "type": "reg", "size": 670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23350669, "NumLink": 0, "digest": "sha256:c42ac9c37dd6f9693b5688d7dfd969c78dd830dd9c937c1fc1866009f4fa8c57" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-7", "type": "reg", "size": 670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23351119, "NumLink": 0, "digest": "sha256:4a5dbdf8cfcc24be96f0e4050f77cf2955d7e1c6b0b22f80acf3257b33677878" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-8", "type": "reg", "size": 670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23351571, "NumLink": 0, "digest": "sha256:5b800d1e9507634e1e900f3a9ef7389852954cec6bdac489beac822a5dfdbc1b" }, { "name": "usr/share/zoneinfo/right/Etc/GMT-9", "type": "reg", "size": 670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23352023, "NumLink": 0, "digest": "sha256:4e3d7d971253c770534e2344257199faa641ee50f914237c23a81af9b0ebcef8" }, { "name": "usr/share/zoneinfo/right/Etc/GMT0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Etc/Greenwich", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Etc/UCT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../UCT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Etc/UTC", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Etc/Universal", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Etc/Zulu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Amsterdam", "type": "reg", "size": 3489, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23352633, "NumLink": 0, "digest": "sha256:ae32e0cb5a9ea89b38213163daf4feb4840a6b72e82d5464c647d0a618531697" }, { "name": "usr/share/zoneinfo/right/Europe/Andorra", "type": "reg", "size": 2291, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23354524, "NumLink": 0, "digest": "sha256:1330f8009adea3c6e5134cdeadaedaa6fbbcd72b2753207ccbb953ccf5001d18" }, { "name": "usr/share/zoneinfo/right/Europe/Astrakhan", "type": "reg", "size": 1723, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23355815, "NumLink": 0, "digest": "sha256:d5a385bc8f28267d22d117464f6cb9a9cb179dfd192a4f04a5cc49044b6cf3bf" }, { "name": "usr/share/zoneinfo/right/Europe/Athens", "type": "reg", "size": 2811, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23356823, "NumLink": 0, "digest": "sha256:0c23a856f0e9c47bba55cb81c426eca0d190aea6043b018e2affa55f21b43664" }, { "name": "usr/share/zoneinfo/right/Europe/Belfast", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Belgrade", "type": "reg", "size": 2497, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23358438, "NumLink": 0, "digest": "sha256:3debded934cdf0c472df38375bd1a69c9135fb21890969bd68a50956e7181e7c" }, { "name": "usr/share/zoneinfo/right/Europe/Berlin", "type": "reg", "size": 2875, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23359833, "NumLink": 0, "digest": "sha256:0b4604767edbae4fc43cd24bd96ec235232471fddff9dc15328c0b74d4c3dc90" }, { "name": "usr/share/zoneinfo/right/Europe/Bratislava", "type": "reg", "size": 2878, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23361442, "NumLink": 0, "digest": "sha256:faec42cc5833011f1a0f07219bbdea30138befb2c85258c5e5a0d37961a0bae7" }, { "name": "usr/share/zoneinfo/right/Europe/Brussels", "type": "reg", "size": 3510, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23363099, "NumLink": 0, "digest": "sha256:b7389bbaad40e29c14b6286ef458854c08a820a22dabc9a9df0a9a371589da0a" }, { "name": "usr/share/zoneinfo/right/Europe/Bucharest", "type": "reg", "size": 2761, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23365064, "NumLink": 0, "digest": "sha256:4052f7958d6994e77da457cc9255749b2df0a6270841d23cb93937d58e1f4ec2" }, { "name": "usr/share/zoneinfo/right/Europe/Budapest", "type": "reg", "size": 2945, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23366618, "NumLink": 0, "digest": "sha256:865242b95f7d1177e289a4853ab538079af84710f8f09b4908db5928670e016a" }, { "name": "usr/share/zoneinfo/right/Europe/Busingen", "type": "reg", "size": 2458, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23368270, "NumLink": 0, "digest": "sha256:46a95ddb0c5047f5b03c6ebdd2c35f87f59e6719d2a2385134408f826753e60f" }, { "name": "usr/share/zoneinfo/right/Europe/Chisinau", "type": "reg", "size": 2985, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23369688, "NumLink": 0, "digest": "sha256:ea169f6577633d68990e74350d1f53c54d309ea1fb461bc235f6dc3c2bfd03c4" }, { "name": "usr/share/zoneinfo/right/Europe/Copenhagen", "type": "reg", "size": 2700, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23371326, "NumLink": 0, "digest": "sha256:cc7d0746ef3061d3de714685a821a4781abe813fdc6327f162fc70b0c22d62ac" }, { "name": "usr/share/zoneinfo/right/Europe/Dublin", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Eire", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Gibraltar", "type": "reg", "size": 3601, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23372927, "NumLink": 0, "digest": "sha256:16fa8d1cb048eb5d4defb961df736ae7db4d477b6f08b9d94572da2303681fe7" }, { "name": "usr/share/zoneinfo/right/Europe/Guernsey", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Helsinki", "type": "reg", "size": 2449, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23374929, "NumLink": 0, "digest": "sha256:a1894d50d5bc5e541f340d601cd8ababe40da90fa867cc7ed3215be1cd6282de" }, { "name": "usr/share/zoneinfo/right/Europe/Isle_of_Man", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Istanbul", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Turkey", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Jersey", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Kaliningrad", "type": "reg", "size": 2058, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23376409, "NumLink": 0, "digest": "sha256:5776b8702f94742194f5280ee49e61d1b8474b6d4808284afb2aaf62b9c4c7fb" }, { "name": "usr/share/zoneinfo/right/Europe/Kiev", "type": "reg", "size": 2637, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23377565, "NumLink": 0, "digest": "sha256:24c81f9cf9518821df795eb6c2660d1de98a29d658922bec6f70b05dc9f427e7" }, { "name": "usr/share/zoneinfo/right/Europe/Kirov", "type": "reg", "size": 1693, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23379024, "NumLink": 0, "digest": "sha256:07d63183733df20b6fd7ab0978715f8635406b229e4c8f0b6340aadd57567618" }, { "name": "usr/share/zoneinfo/right/Europe/Lisbon", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Portugal", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Ljubljana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/London", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Luxembourg", "type": "reg", "size": 3514, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23380120, "NumLink": 0, "digest": "sha256:af6eb983dfb45c9e363dafb9d26b8466179415e37ef87991b258523a36c18239" }, { "name": "usr/share/zoneinfo/right/Europe/Madrid", "type": "reg", "size": 3177, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23382026, "NumLink": 0, "digest": "sha256:01a00debc9c470fe55edfa31568135024d2450ba34c1c88ed16d620b67af5d83" }, { "name": "usr/share/zoneinfo/right/Europe/Malta", "type": "reg", "size": 3169, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23383772, "NumLink": 0, "digest": "sha256:80919f93a3dd18f905ec9ecc82797ea80f289fe05795f32bd9390dbed7ff7d05" }, { "name": "usr/share/zoneinfo/right/Europe/Mariehamn", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Helsinki", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Minsk", "type": "reg", "size": 1896, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23385589, "NumLink": 0, "digest": "sha256:c77b4d9a74af85f48b6bea8b640f6c5de557d64f3995567d4978fad4e8263f21" }, { "name": "usr/share/zoneinfo/right/Europe/Monaco", "type": "reg", "size": 3493, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23386672, "NumLink": 0, "digest": "sha256:7bac15b163365f1415bd5830c70e2433d36b70b490a393be07d0562071bdc98c" }, { "name": "usr/share/zoneinfo/right/Europe/Moscow", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../W-SU", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Nicosia", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Asia/Nicosia", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Oslo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Arctic/Longyearbyen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Paris", "type": "reg", "size": 3511, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23388684, "NumLink": 0, "digest": "sha256:6cd62d7d4c3d0be12b47e2e3c026ad0b5513f16e3dbf46d7812f0501c0522def" }, { "name": "usr/share/zoneinfo/right/Europe/Podgorica", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Prague", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Bratislava", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Riga", "type": "reg", "size": 2775, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23390657, "NumLink": 0, "digest": "sha256:543f059b0b90d203ac284c74a9eb1a43acfb6f6de2c3f618b9df24b1b53564d8" }, { "name": "usr/share/zoneinfo/right/Europe/Rome", "type": "reg", "size": 3232, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23392186, "NumLink": 0, "digest": "sha256:52028442c2ca14e1c747c8a0e0c5c152b1e0faacdabe0dec7e93374bf5d36ec8" }, { "name": "usr/share/zoneinfo/right/Europe/Samara", "type": "reg", "size": 1779, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23394045, "NumLink": 0, "digest": "sha256:e1ba77c8d804455d5fee38e828902dba23e86521f398f406523a4de117599f6b" }, { "name": "usr/share/zoneinfo/right/Europe/San_Marino", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Rome", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Sarajevo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Saratov", "type": "reg", "size": 1723, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23395140, "NumLink": 0, "digest": "sha256:38653f429ca844f5c49babb688a91384baa163800bcdd63fd80197d042b3ed86" }, { "name": "usr/share/zoneinfo/right/Europe/Simferopol", "type": "reg", "size": 2030, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23396154, "NumLink": 0, "digest": "sha256:c749271304d25a3772fec2f14e1a9fe29d66a993e88384b4fb8c35305208aa06" }, { "name": "usr/share/zoneinfo/right/Europe/Skopje", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Sofia", "type": "reg", "size": 2670, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23397362, "NumLink": 0, "digest": "sha256:2d9a0ae58e5f9d5b678d68e5874b4d4bf0481a5decd3e9a097bed5f172a16cd0" }, { "name": "usr/share/zoneinfo/right/Europe/Stockholm", "type": "reg", "size": 2458, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23398913, "NumLink": 0, "digest": "sha256:57c9a0626fe99afad4195a26bdd53a0013d465c876e4970a365196242191009a" }, { "name": "usr/share/zoneinfo/right/Europe/Tallinn", "type": "reg", "size": 2727, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23400331, "NumLink": 0, "digest": "sha256:3ce08292fa8bf8241cfc2bd85b05dec3459e3b653a0333720380ef66841e9db1" }, { "name": "usr/share/zoneinfo/right/Europe/Tirane", "type": "reg", "size": 2638, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23401829, "NumLink": 0, "digest": "sha256:aecddbe0e431c06b7d90ce8c9be834f2aafeba71716812b98797272f72d54141" }, { "name": "usr/share/zoneinfo/right/Europe/Tiraspol", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Chisinau", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Ulyanovsk", "type": "reg", "size": 1807, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23403357, "NumLink": 0, "digest": "sha256:40df4bd977a40651e76d094572dd6bdef9124ee8d9d534ed06aebbfc8c5abbc3" }, { "name": "usr/share/zoneinfo/right/Europe/Uzhgorod", "type": "reg", "size": 2643, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23404397, "NumLink": 0, "digest": "sha256:7ede029288ea2e0af7da34e57ef3414159d510db5e41db99ef2bd0becff29c72" }, { "name": "usr/share/zoneinfo/right/Europe/Vaduz", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Busingen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Vatican", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Rome", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Vienna", "type": "reg", "size": 2777, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23405928, "NumLink": 0, "digest": "sha256:0157530a51d22c4596dfb3d37153ba3b41379ddafd6ca1ec40ea288b3fe64dd5" }, { "name": "usr/share/zoneinfo/right/Europe/Vilnius", "type": "reg", "size": 2739, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23407483, "NumLink": 0, "digest": "sha256:60409d0bfd11d41ed822fbc0564645c41d63b215b8b1822c369a5af7824631fe" }, { "name": "usr/share/zoneinfo/right/Europe/Volgograd", "type": "reg", "size": 1693, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23408974, "NumLink": 0, "digest": "sha256:75aa972974961db6368d4fde9ce7d891f1b5dbac6911f636330347f5ef3e8513" }, { "name": "usr/share/zoneinfo/right/Europe/Warsaw", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Poland", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Zagreb", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Belgrade", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Europe/Zaporozhye", "type": "reg", "size": 2655, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23410037, "NumLink": 0, "digest": "sha256:67d4c4e23f865eeb4fcc7779563524189dd9852d7547ab5b9374f637f4f3faef" }, { "name": "usr/share/zoneinfo/right/Europe/Zurich", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Busingen", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Factory", "type": "reg", "size": 669, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23411552, "NumLink": 0, "digest": "sha256:10cef6c7d0457d242b17866e3e811bed8a06ab56064acebac07f0debcbe92006" }, { "name": "usr/share/zoneinfo/right/GB", "type": "reg", "size": 4227, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23411990, "NumLink": 0, "digest": "sha256:256c78cc8a67c9b7796737d6af67860246715133443319c41c5962d4d4411f6d" }, { "name": "usr/share/zoneinfo/right/GB-Eire", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "GB", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/GMT", "type": "reg", "size": 667, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23414295, "NumLink": 0, "digest": "sha256:da4f5e177e0e5138774896d0b82b59cce878cf3700734a5d6cdfac2f0f96eb28" }, { "name": "usr/share/zoneinfo/right/GMT+0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/GMT-0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/GMT0", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Greenwich", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "GMT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/HST", "type": "reg", "size": 668, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23414810, "NumLink": 0, "digest": "sha256:d6c14dcfa90060f656344c7f7078d78fd6046e38d850b78de5f066c0f3c0c655" }, { "name": "usr/share/zoneinfo/right/Hongkong", "type": "reg", "size": 1729, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23415259, "NumLink": 0, "digest": "sha256:49e939c0d7b29e67f9aa7c598b0f9b058f41ea38a34c76622346a60315c4312f" }, { "name": "usr/share/zoneinfo/right/Iceland", "type": "reg", "size": 1728, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23416264, "NumLink": 0, "digest": "sha256:4a419779c4e933cb9ba204355f1a3649c72d443a95e0a6d81ff506ab467293c0" }, { "name": "usr/share/zoneinfo/right/Indian/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Indian/Antananarivo", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Indian/Chagos", "type": "reg", "size": 751, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23417349, "NumLink": 0, "digest": "sha256:be59ae7c9d5f671c7ed258fc7096743913d78bea71902d23bb77c54b8d0175eb" }, { "name": "usr/share/zoneinfo/right/Indian/Christmas", "type": "reg", "size": 691, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23417847, "NumLink": 0, "digest": "sha256:38acf43ebd68867bedb27ae1544e6c1f25942ed76726c77e08ef523d84e57c9b" }, { "name": "usr/share/zoneinfo/right/Indian/Cocos", "type": "reg", "size": 700, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23418329, "NumLink": 0, "digest": "sha256:e0ee8a9a676f4bb453d822ceab90aea7d606f9db114a0b1f97bd8f301db00f51" }, { "name": "usr/share/zoneinfo/right/Indian/Comoro", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Indian/Kerguelen", "type": "reg", "size": 713, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23418870, "NumLink": 0, "digest": "sha256:efeb12b4af7ee8fb2896dfa04e1864e486423a653258b5bcc24b126eaca3f260" }, { "name": "usr/share/zoneinfo/right/Indian/Mahe", "type": "reg", "size": 713, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23419339, "NumLink": 0, "digest": "sha256:99669b539e7dbdd6a9a06df816e3b5b9e3596c9daf2df41605609c1a0507cd9c" }, { "name": "usr/share/zoneinfo/right/Indian/Maldives", "type": "reg", "size": 746, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23419818, "NumLink": 0, "digest": "sha256:882ac362aab99f9682e268966fed6700a7981dbbfd2d64ad9e2bd864f752d996" }, { "name": "usr/share/zoneinfo/right/Indian/Mauritius", "type": "reg", "size": 793, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23420316, "NumLink": 0, "digest": "sha256:6e54749fc42ea492dce64468fec1dd4ce09ac3270884a0e3b92a804126940b1c" }, { "name": "usr/share/zoneinfo/right/Indian/Mayotte", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Africa/Addis_Ababa", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Indian/Reunion", "type": "reg", "size": 713, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23420891, "NumLink": 0, "digest": "sha256:c271916f61f082d48ae258c12cf41ee28dd98e83d370deb4599ae69b6e8afa59" }, { "name": "usr/share/zoneinfo/right/Iran", "type": "reg", "size": 2244, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23421357, "NumLink": 0, "digest": "sha256:d3001b5add2c5861093986cd21513ff46898e42b18f10a60693dbf6c53d9f8f7" }, { "name": "usr/share/zoneinfo/right/Israel", "type": "reg", "size": 2805, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23422628, "NumLink": 0, "digest": "sha256:a8271f9608d08293b37ec6a3ce75711954ee4fbce8cc80b19e5c4249618ac3a0" }, { "name": "usr/share/zoneinfo/right/Jamaica", "type": "reg", "size": 1047, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23424200, "NumLink": 0, "digest": "sha256:47ddec901639efbe7268363dcc0d8b92a855372b0cae12720d68cce9a8974fdb" }, { "name": "usr/share/zoneinfo/right/Japan", "type": "reg", "size": 858, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23424863, "NumLink": 0, "digest": "sha256:f3fe73852e6756d6691f8c06056cde1a666f23d1f9bc940ac0e11c7fed3805dc" }, { "name": "usr/share/zoneinfo/right/Kwajalein", "type": "reg", "size": 785, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23425419, "NumLink": 0, "digest": "sha256:e6d534633a44ad56204f74ad53a6329eda2bc44a9ec9f8b9d9942431f2c8ce9d" }, { "name": "usr/share/zoneinfo/right/Libya", "type": "reg", "size": 1195, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23425926, "NumLink": 0, "digest": "sha256:72bb85f8ac4ec74b2ae92214c047c82f1f39c9c0785d0f54e152b8c1d940adda" }, { "name": "usr/share/zoneinfo/right/MET", "type": "reg", "size": 2642, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23426660, "NumLink": 0, "digest": "sha256:735b7a481c6b4024076996235dc00c88eba04788ea0d2320f52f3b6f832e2c5c" }, { "name": "usr/share/zoneinfo/right/MST", "type": "reg", "size": 667, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23428127, "NumLink": 0, "digest": "sha256:d7ed7889d7e664fa5f24d3ebca03abc5e6f4c1af886e13b6d057d0aa4009a953" }, { "name": "usr/share/zoneinfo/right/MST7MDT", "type": "reg", "size": 2834, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23428574, "NumLink": 0, "digest": "sha256:f5bff9e9551d99b333440822fd3fa74d2bf03b0303585ce0705557b869e47e83" }, { "name": "usr/share/zoneinfo/right/Mexico/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Mexico/BajaNorte", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Ensenada", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Mexico/BajaSur", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Mazatlan", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Mexico/General", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Mexico_City", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/NZ", "type": "reg", "size": 3000, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23430323, "NumLink": 0, "digest": "sha256:c6fa7d47e6fb209806155ca05d2d0721726515ad678714f3197b9daeb9da3a96" }, { "name": "usr/share/zoneinfo/right/NZ-CHAT", "type": "reg", "size": 2613, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23431982, "NumLink": 0, "digest": "sha256:26f595850d1431c8e91ec414ecd29867fe361f2e49ae0d04f44ed3b53df66240" }, { "name": "usr/share/zoneinfo/right/Navajo", "type": "reg", "size": 2993, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23433446, "NumLink": 0, "digest": "sha256:7448c66048e5489a28ecad3adc495351163e62cedff714bec6d15506a9e1f548" }, { "name": "usr/share/zoneinfo/right/PRC", "type": "reg", "size": 954, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23435124, "NumLink": 0, "digest": "sha256:ad1e89bcb5b895b4163043ba8b4806c1dd3d1886964770688532adbc0d6ffc4a" }, { "name": "usr/share/zoneinfo/right/PST8PDT", "type": "reg", "size": 2834, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23435732, "NumLink": 0, "digest": "sha256:f08ae6766d50d2008608f2e668ff34560eef0fb62b3e60df8c019e04cb914780" }, { "name": "usr/share/zoneinfo/right/Pacific/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Pacific/Apia", "type": "reg", "size": 1660, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23437373, "NumLink": 0, "digest": "sha256:d83e28595f25234e2e75a754d66606779f497f41f3e1e5a8389c62c85f8456e8" }, { "name": "usr/share/zoneinfo/right/Pacific/Auckland", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../NZ", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Pacific/Bougainville", "type": "reg", "size": 822, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23438397, "NumLink": 0, "digest": "sha256:74c033543ad47e18b82f929308eb88b742b84a4b718d0c743e87339a917730b3" }, { "name": "usr/share/zoneinfo/right/Pacific/Chatham", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../NZ-CHAT", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Pacific/Chuuk", "type": "reg", "size": 692, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23439002, "NumLink": 0, "digest": "sha256:31b6fa3e8b930a5d14cf1fe401480d9bd3acc0d2b202ee8d0e2a72aeed2e3be9" }, { "name": "usr/share/zoneinfo/right/Pacific/Easter", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Chile/EasterIsland", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Pacific/Efate", "type": "reg", "size": 1018, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23439534, "NumLink": 0, "digest": "sha256:11867f8f79968dab62432ae65be80de4c1ce8c9f4f2509c73f1239f87a389e74" }, { "name": "usr/share/zoneinfo/right/Pacific/Enderbury", "type": "reg", "size": 785, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23440190, "NumLink": 0, "digest": "sha256:4980802f3f305cbbc84449c6318262384c855d2c2b1c86cdddc64c50b6eb2f17" }, { "name": "usr/share/zoneinfo/right/Pacific/Fakaofo", "type": "reg", "size": 747, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23440705, "NumLink": 0, "digest": "sha256:ffa2f3656163dac98d7128708f767a9003fea91c6a0eab4e088c8530ad819ff7" }, { "name": "usr/share/zoneinfo/right/Pacific/Fiji", "type": "reg", "size": 1616, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23441201, "NumLink": 0, "digest": "sha256:7c48cfd35fece2a2e2d9e69bf8a6ac59c85db1414f67d322e98d21b6ad246a80" }, { "name": "usr/share/zoneinfo/right/Pacific/Funafuti", "type": "reg", "size": 692, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23442179, "NumLink": 0, "digest": "sha256:3b3a5bbce2ef074a52e8c7d0c1152b4859439e053ab54fbf8fcac3416946313f" }, { "name": "usr/share/zoneinfo/right/Pacific/Galapagos", "type": "reg", "size": 794, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23442666, "NumLink": 0, "digest": "sha256:a73b7fbb4d963a4de8a2116696fb14cc1d4fea7f4ee63a7bebf3de6d37ea3f35" }, { "name": "usr/share/zoneinfo/right/Pacific/Gambier", "type": "reg", "size": 712, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23443183, "NumLink": 0, "digest": "sha256:1467e739b00e63003ee811eb5f3a7598ec82c8e69132c9d13b05b4c972afb883" }, { "name": "usr/share/zoneinfo/right/Pacific/Guadalcanal", "type": "reg", "size": 714, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23443666, "NumLink": 0, "digest": "sha256:305ea4443760cd08775ece730d93eead1265d9c30f02f162009397a653892294" }, { "name": "usr/share/zoneinfo/right/Pacific/Guam", "type": "reg", "size": 765, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23444142, "NumLink": 0, "digest": "sha256:ee75c94a1fc4f5a363f4c6af4f386a4ba4751b6dbb43068cadaa613fa4ea2219" }, { "name": "usr/share/zoneinfo/right/Pacific/Honolulu", "type": "reg", "size": 816, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23444659, "NumLink": 0, "digest": "sha256:cb9b83b1f1adf4db95a208e851e6681f5111c25071b85e42620aae507b93ee40" }, { "name": "usr/share/zoneinfo/right/Pacific/Johnston", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Honolulu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Pacific/Kiritimati", "type": "reg", "size": 789, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23445243, "NumLink": 0, "digest": "sha256:b72c4f9c16069a15f87449a89faf1d1cea5388eef787f99f605a5c24316ae995" }, { "name": "usr/share/zoneinfo/right/Pacific/Kosrae", "type": "reg", "size": 777, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23445758, "NumLink": 0, "digest": "sha256:330b3690e2848d83b135182823d6a896338ee4512e9a3bd59b166395992d289a" }, { "name": "usr/share/zoneinfo/right/Pacific/Kwajalein", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Kwajalein", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Pacific/Majuro", "type": "reg", "size": 747, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23446307, "NumLink": 0, "digest": "sha256:896736fad3956359a0366760467b2af60178d8c6dbc439a3d004dfa02bfb3130" }, { "name": "usr/share/zoneinfo/right/Pacific/Marquesas", "type": "reg", "size": 721, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23446804, "NumLink": 0, "digest": "sha256:90d1dafd8f01d16ee5d029e9c9643275a6ce5f611a99580243a478cdd9d334c3" }, { "name": "usr/share/zoneinfo/right/Pacific/Midway", "type": "reg", "size": 736, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23447285, "NumLink": 0, "digest": "sha256:c996db6822af6b663b37e0c8750132432169950eed2c24bab4c9f843475b5cb5" }, { "name": "usr/share/zoneinfo/right/Pacific/Nauru", "type": "reg", "size": 808, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23447774, "NumLink": 0, "digest": "sha256:636be1327c578fde487fbba425de45a1b6ed7ad12921b99b74f40443ff10a28a" }, { "name": "usr/share/zoneinfo/right/Pacific/Niue", "type": "reg", "size": 792, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23448291, "NumLink": 0, "digest": "sha256:6ea86a60548452d527af1bf1437a846d35a2023295426a924060e001d9b34986" }, { "name": "usr/share/zoneinfo/right/Pacific/Norfolk", "type": "reg", "size": 849, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23448807, "NumLink": 0, "digest": "sha256:46a26c4fc3281118941c7da66a7b333ff252e5c411310a13ef974e4600e4635b" }, { "name": "usr/share/zoneinfo/right/Pacific/Noumea", "type": "reg", "size": 854, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23449346, "NumLink": 0, "digest": "sha256:4181221801b85e6905d0523c8ad5a799c5827cbe3813676d40c47ba8f2a53043" }, { "name": "usr/share/zoneinfo/right/Pacific/Pago_Pago", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Midway", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Pacific/Palau", "type": "reg", "size": 691, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23449932, "NumLink": 0, "digest": "sha256:4353921b3ff2f1d2e37cb674dbcd8ce1ed96401630d55a21bdddadd87a5af7f1" }, { "name": "usr/share/zoneinfo/right/Pacific/Pitcairn", "type": "reg", "size": 749, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23450416, "NumLink": 0, "digest": "sha256:9a483181af824f93b4626871dae31022260d27180e0f15a7dbfe076bedebcb71" }, { "name": "usr/share/zoneinfo/right/Pacific/Pohnpei", "type": "reg", "size": 692, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23450913, "NumLink": 0, "digest": "sha256:01f21467d5a56ff85427dc4cff9466eb47be79d73fa657658c111453d0653919" }, { "name": "usr/share/zoneinfo/right/Pacific/Ponape", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Pohnpei", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Pacific/Port_Moresby", "type": "reg", "size": 714, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23451438, "NumLink": 0, "digest": "sha256:dd70e9df820da5d290670f409b945186fb3e4c2597b981f6aa00618f9e9fe602" }, { "name": "usr/share/zoneinfo/right/Pacific/Rarotonga", "type": "reg", "size": 1128, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23451938, "NumLink": 0, "digest": "sha256:03017bb1fd0bc79957dbac5888563c69e0b2dace69e995e7f5dec95d15cdb78d" }, { "name": "usr/share/zoneinfo/right/Pacific/Saipan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Guam", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Pacific/Samoa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Midway", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Pacific/Tahiti", "type": "reg", "size": 713, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23452715, "NumLink": 0, "digest": "sha256:aa925368f0d1362d2c8c738f6d78e729bce16dfafb6a19111ba54c28cfcf77af" }, { "name": "usr/share/zoneinfo/right/Pacific/Tarawa", "type": "reg", "size": 692, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23453192, "NumLink": 0, "digest": "sha256:d1e0a1228e386b4a69c1d79581e8d034f919c251109e6ad18a7ba7a269cc0e1d" }, { "name": "usr/share/zoneinfo/right/Pacific/Tongatapu", "type": "reg", "size": 919, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23453679, "NumLink": 0, "digest": "sha256:9729f5d257db4cd92c0055ba6c667f6e5ee21ee7436cb5df495a887d2481cccd" }, { "name": "usr/share/zoneinfo/right/Pacific/Truk", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Chuuk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Pacific/Wake", "type": "reg", "size": 692, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23454297, "NumLink": 0, "digest": "sha256:8258c1f19702e381c4bfce3cb5b1335814a593531d3211b7a4a323d42aed7140" }, { "name": "usr/share/zoneinfo/right/Pacific/Wallis", "type": "reg", "size": 692, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23454780, "NumLink": 0, "digest": "sha256:2077f480b59aec6abf5cc989c61246f8fc4c1e8cd8a3e5738eb9ce63b543d586" }, { "name": "usr/share/zoneinfo/right/Pacific/Yap", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "Chuuk", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Poland", "type": "reg", "size": 3245, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23455299, "NumLink": 0, "digest": "sha256:2776052936d3361f49da479c0a6d522ea7ec256300cc9263d1011848ab2bb3a9" }, { "name": "usr/share/zoneinfo/right/Portugal", "type": "reg", "size": 4009, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23457078, "NumLink": 0, "digest": "sha256:f8e850961fc42ea64edb30cebaabad27fccda97bdf6cf1047e4051298bdf20d0" }, { "name": "usr/share/zoneinfo/right/ROC", "type": "reg", "size": 1330, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23459223, "NumLink": 0, "digest": "sha256:d5ff02c7a5dc9adb7a5b8de1e492f8ace92d832e8f2f6879265520c47f850078" }, { "name": "usr/share/zoneinfo/right/ROK", "type": "reg", "size": 1071, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23460015, "NumLink": 0, "digest": "sha256:8520047dc59323aa8ba91ad43e39229e36e4e0381ad14f59af4395b669845afc" }, { "name": "usr/share/zoneinfo/right/Singapore", "type": "reg", "size": 950, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23460673, "NumLink": 0, "digest": "sha256:e2140fbf66b5f7a235fca25454176d2eaab4c8b8303fea4ddfec5455c549bbac" }, { "name": "usr/share/zoneinfo/right/SystemV/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/AST4", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Puerto_Rico", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/AST4ADT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Halifax", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/CST6", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Regina", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/CST6CDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Chicago", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/EST5", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Cayman", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/EST5EDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/New_York", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/HST10", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Pacific/Honolulu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/MST7", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Phoenix", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/MST7MDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/PST8", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Pacific/Pitcairn", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/PST8PDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Los_Angeles", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/YST9", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Pacific/Gambier", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/SystemV/YST9YDT", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Anchorage", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/Turkey", "type": "reg", "size": 2692, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23461615, "NumLink": 0, "digest": "sha256:5bd39443ec8a05b4c68c2cb546d9a76b11c59a8d66823d6fd2eb6e49c50497ba" }, { "name": "usr/share/zoneinfo/right/UCT", "type": "reg", "size": 667, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23463108, "NumLink": 0, "digest": "sha256:de715c1e70331ba26ec0db477d50f3df14a4be5a552a5b40683a3aa7882b2975" }, { "name": "usr/share/zoneinfo/right/US/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/Alaska", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Anchorage", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/Aleutian", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Adak", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/Arizona", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Phoenix", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/Central", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Chicago", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/East-Indiana", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Fort_Wayne", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/Eastern", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/New_York", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/Hawaii", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Pacific/Honolulu", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/Indiana-Starke", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Knox_IN", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/Michigan", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Detroit", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/Mountain", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Navajo", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/Pacific", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Los_Angeles", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/Pacific-New", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../America/Los_Angeles", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/US/Samoa", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "../Pacific/Midway", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/UTC", "type": "reg", "size": 667, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23463934, "NumLink": 0, "digest": "sha256:d19fdd5d26a7753518ee9a09ab74a8e4efa9a4e6ed56eff85baabd8af9c0e459" }, { "name": "usr/share/zoneinfo/right/Universal", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/right/W-SU", "type": "reg", "size": 2084, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23464417, "NumLink": 0, "digest": "sha256:8e1367300579da7319742b25b9da707131b058482c77e7a707c71aeb60f067ff" }, { "name": "usr/share/zoneinfo/right/WET", "type": "reg", "size": 2413, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 23465586, "NumLink": 0, "digest": "sha256:e9826478fee66e6f8a7583d9a67d82f114f8a12856b4f4a6bfed5db540c54753" }, { "name": "usr/share/zoneinfo/right/Zulu", "type": "symlink", "modtime": "2018-05-04T18:22:35Z", "linkName": "UTC", "mode": 41471, "NumLink": 0 }, { "name": "usr/share/zoneinfo/zone.tab", "type": "reg", "size": 19165, "modtime": "2018-02-16T17:21:32Z", "mode": 33188, "offset": 23466994, "NumLink": 0, "digest": "sha256:14cdfb2c5e3f7201d82c368d3ac204a3cfb9e50d89dd106d414e302db57c141e" }, { "name": "usr/share/zoneinfo/zone1970.tab", "type": "reg", "size": 17781, "modtime": "2018-02-16T21:59:02Z", "mode": 33188, "offset": 23476414, "NumLink": 0, "digest": "sha256:3124b997b9183f7029585690ae3cb31afe1e271a4bbdbf05ef002d23d03760b2" }, { "name": "usr/src/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "var/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/backups/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "var/cache/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/cache/apt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/cache/debconf/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/cache/debconf/config.dat", "type": "reg", "size": 4454, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23485364, "NumLink": 0, "digest": "sha256:dd96d0ac5c66a80416a50f0d94b856efcb707bbc0c49d7ecf07a4dcf33bc4106" }, { "name": "var/cache/debconf/config.dat-old", "type": "reg", "size": 4294, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23486224, "NumLink": 0, "digest": "sha256:700ffa319f2c418a677fccd79546da9c099e71835817ee040fbc3720840923f2" }, { "name": "var/cache/debconf/passwords.dat", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33152, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "var/cache/debconf/templates.dat", "type": "reg", "size": 725910, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23487077, "NumLink": 0, "digest": "sha256:a5076b4345d5aafe17f85ae91c948727df60311056601540afc7c89b449929c8" }, { "name": "var/cache/debconf/templates.dat-old", "type": "reg", "size": 708570, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23673393, "NumLink": 0, "digest": "sha256:e4e46a38994fe5ce8a0198f315ddfaaa3fcf76b6d64357d066e2090330eeff90" }, { "name": "var/cache/ldconfig/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16832, "NumLink": 0 }, { "name": "var/lib/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/apt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/apt/extended_states", "type": "reg", "size": 4437, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23852673, "NumLink": 0, "digest": "sha256:54dbd6ae802c89a09e004b60fef8a1af518bf488683b270f72d0e88c842f8e6a" }, { "name": "var/lib/apt/lists/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/apt/mirrors/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/apt/mirrors/partial/", "type": "dir", "modtime": "2017-09-13T16:47:33Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/apt/periodic/", "type": "dir", "modtime": "2017-09-13T16:47:33Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/dpkg/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/dpkg/alternatives/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/dpkg/alternatives/awk", "type": "reg", "size": 207, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23853417, "NumLink": 0, "digest": "sha256:06c7cfca68d405ca5e20fd379b93fe97fd1698841a1449f9b403115cedcf8eba" }, { "name": "var/lib/dpkg/alternatives/builtins.7.gz", "type": "reg", "size": 83, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23853603, "NumLink": 0, "digest": "sha256:6cd368606c13e12657f237f25e3ddfd89c6ebc34b52b8391561ff89d0c052f62" }, { "name": "var/lib/dpkg/alternatives/pager", "type": "reg", "size": 150, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23853763, "NumLink": 0, "digest": "sha256:904b645490f378ef86609d5f40ddc2334aad824f59ee117664d9598ec0ac48f7" }, { "name": "var/lib/dpkg/alternatives/rmt", "type": "reg", "size": 113, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23853938, "NumLink": 0, "digest": "sha256:cc31c88e6e9660da820eaf68418b4e9dfd76dfdbbbcebbaed446afe397971dc9" }, { "name": "var/lib/dpkg/available", "type": "reg", "size": 60988, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23854101, "NumLink": 0, "digest": "sha256:2aa0bc06f4328dd5232529021351d42ea097dbc731a3cc1c07fbe208b0f1379f" }, { "name": "var/lib/dpkg/cmethopt", "type": "reg", "size": 8, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23872106, "NumLink": 0, "digest": "sha256:162ba45c89e2735aba3a5fcd4a0ad00efd9120edaa2215a8f541058cb895ce29" }, { "name": "var/lib/dpkg/diversions", "type": "reg", "size": 136, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23872222, "NumLink": 0, "digest": "sha256:164c982bde1284c84173ddcfac3bd28581551a51abae77ac01f278829477525a" }, { "name": "var/lib/dpkg/diversions-old", "type": "reg", "size": 98, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23872399, "NumLink": 0, "digest": "sha256:0e4c917474e8711b898165d3b464a2c47c027a28ec6d7f87f4bd2fc1deee2a2a" }, { "name": "var/lib/dpkg/info/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/dpkg/info/adduser.conffiles", "type": "reg", "size": 18, "modtime": "2016-06-26T22:55:18Z", "mode": 33188, "offset": 23872595, "NumLink": 0, "digest": "sha256:2ed8c75e30af614b19760b001063fbeb2a48ebaf469c44d921d3df787f2ca173" }, { "name": "var/lib/dpkg/info/adduser.config", "type": "reg", "size": 929, "modtime": "2016-06-26T22:55:17Z", "mode": 33261, "offset": 23872725, "NumLink": 0, "digest": "sha256:7bbbed298ee1cba145ccced3c596025d1bf420c978feef4269e9e3c0c8ef1855" }, { "name": "var/lib/dpkg/info/adduser.list", "type": "reg", "size": 6420, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23873215, "NumLink": 0, "digest": "sha256:1d2871a453ad11657eb656cc724f8fde70e8e618722a033460deb3418a80615d" }, { "name": "var/lib/dpkg/info/adduser.md5sums", "type": "reg", "size": 6061, "modtime": "2016-06-26T22:55:18Z", "mode": 33188, "offset": 23874065, "NumLink": 0, "digest": "sha256:b64ccdfd5680940021be7d9ce124fe90be65b8680bd1ce1228581d61efa5a616" }, { "name": "var/lib/dpkg/info/adduser.postinst", "type": "reg", "size": 964, "modtime": "2016-06-26T22:55:18Z", "mode": 33261, "offset": 23876178, "NumLink": 0, "digest": "sha256:725a17e3ccb6bcda57076fa51d824c1a0903c885261c34e053f9750be30a2755" }, { "name": "var/lib/dpkg/info/adduser.postrm", "type": "reg", "size": 297, "modtime": "2016-06-26T22:55:18Z", "mode": 33261, "offset": 23876695, "NumLink": 0, "digest": "sha256:873add4d34b1673f89a54e7bfa41f6d70f006f4c2576259e848063dbe216e233" }, { "name": "var/lib/dpkg/info/adduser.templates", "type": "reg", "size": 16424, "modtime": "2016-06-26T22:55:17Z", "mode": 33188, "offset": 23876976, "NumLink": 0, "digest": "sha256:c32dc4475a9743b42b46001f490733dce5bc10ee442208f4f50b406f466c1214" }, { "name": "var/lib/dpkg/info/apt.conffiles", "type": "reg", "size": 121, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 23884545, "NumLink": 0, "digest": "sha256:40d910bb31d4f4744f154ccd80bf53c3ec5574f1577f35af78e5ef77dbcaae47" }, { "name": "var/lib/dpkg/info/apt.list", "type": "reg", "size": 10104, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23884732, "NumLink": 0, "digest": "sha256:f7f8f166f78e81f6e3c62b94413224d446b3097bf1bc06553125db46d2d049f2" }, { "name": "var/lib/dpkg/info/apt.md5sums", "type": "reg", "size": 11361, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 23886194, "NumLink": 0, "digest": "sha256:fb6e26258b39c79746935376b34fb7e5393c1d4f9f599291e7772decf30c5f02" }, { "name": "var/lib/dpkg/info/apt.postinst", "type": "reg", "size": 4578, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 23890307, "NumLink": 0, "digest": "sha256:fbbdc95f0bafae4c6e30b833a24a1488415c9cecf5e3b8b77e5eff0515092d21" }, { "name": "var/lib/dpkg/info/apt.postrm", "type": "reg", "size": 1313, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 23891951, "NumLink": 0, "digest": "sha256:c98cf0eb8b2f164769d0d658eff78b558ee86604444306f2a8fa6388e53d3b10" }, { "name": "var/lib/dpkg/info/apt.preinst", "type": "reg", "size": 247, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 23892610, "NumLink": 0, "digest": "sha256:dc05f90439c5bc1efaff372a49e9fbc394de3645424b88245fc7b9f42cd0723e" }, { "name": "var/lib/dpkg/info/apt.prerm", "type": "reg", "size": 459, "modtime": "2017-09-13T16:47:33Z", "mode": 33261, "offset": 23892864, "NumLink": 0, "digest": "sha256:61c2d8f74fc8d7ccfab6bc555d4d658ef270e93aab26fd58d522518e8c225bf5" }, { "name": "var/lib/dpkg/info/apt.shlibs", "type": "reg", "size": 23, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 23893211, "NumLink": 0, "digest": "sha256:ac130374b3322f21573625a13454d60cf7b5166bcd43b931f8ec09e99d54c455" }, { "name": "var/lib/dpkg/info/apt.triggers", "type": "reg", "size": 60, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 23893346, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/base-files.conffiles", "type": "reg", "size": 114, "modtime": "2018-06-26T12:03:08Z", "mode": 33188, "offset": 23893518, "NumLink": 0, "digest": "sha256:4b3e9e5378d40d8d9e7c508b759513975ad83bf6faeaa3a1b1684c53931b8556" }, { "name": "var/lib/dpkg/info/base-files.list", "type": "reg", "size": 1749, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23893703, "NumLink": 0, "digest": "sha256:4bbc622bdfec8ff870c92223f56614cc43a22361d99e7e4f9d4b030c1cd70ba7" }, { "name": "var/lib/dpkg/info/base-files.md5sums", "type": "reg", "size": 1829, "modtime": "2018-06-26T12:03:08Z", "mode": 33188, "offset": 23894270, "NumLink": 0, "digest": "sha256:378b9d019a502f188899b209f441427839c7e49d19db0896481343133e8083a5" }, { "name": "var/lib/dpkg/info/base-files.postinst", "type": "reg", "size": 3370, "modtime": "2018-06-26T12:03:08Z", "mode": 33261, "offset": 23895147, "NumLink": 0, "digest": "sha256:5b201cc9661b9d7ec075602076165244482cb4b4afadb1a8ed8bc62f10938fd6" }, { "name": "var/lib/dpkg/info/base-passwd.list", "type": "reg", "size": 1120, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23896095, "NumLink": 0, "digest": "sha256:59e7d3f01481b921ab2fe7b7c0f4c9010c5dbd68e63fd6aa6b98144ec444129c" }, { "name": "var/lib/dpkg/info/base-passwd.md5sums", "type": "reg", "size": 1238, "modtime": "2017-01-16T15:52:12Z", "mode": 33188, "offset": 23896429, "NumLink": 0, "digest": "sha256:4e1e3bf27aa7bad2a465a62d6db8f7eb57c60ffebd9473e2d0351ad8a92ef117" }, { "name": "var/lib/dpkg/info/base-passwd.postinst", "type": "reg", "size": 2802, "modtime": "2017-01-16T15:52:12Z", "mode": 33261, "offset": 23897056, "NumLink": 0, "digest": "sha256:01ea366cf8c635d5e21ce289ab3b9998247eac1d3f33312cf002257b0abce445" }, { "name": "var/lib/dpkg/info/base-passwd.postrm", "type": "reg", "size": 206, "modtime": "2017-01-16T15:52:12Z", "mode": 33261, "offset": 23898426, "NumLink": 0, "digest": "sha256:c1c04914a45a56607aa795b52767684381625c27cb3a8f45302cbfa088f735b5" }, { "name": "var/lib/dpkg/info/base-passwd.preinst", "type": "reg", "size": 1516, "modtime": "2017-01-16T15:52:12Z", "mode": 33261, "offset": 23898677, "NumLink": 0, "digest": "sha256:6e38694265a25ef4a21a595dbcf58679b02eb3ef91a76b8ce293cfb97def209c" }, { "name": "var/lib/dpkg/info/base-passwd.templates", "type": "reg", "size": 108623, "modtime": "2017-01-16T15:52:12Z", "mode": 33188, "offset": 23899429, "NumLink": 0, "digest": "sha256:f7de1e47978fedea5a736df4f16b947218f4e65735753d97c1c8954e8312c776" }, { "name": "var/lib/dpkg/info/bash.conffiles", "type": "reg", "size": 77, "modtime": "2017-05-15T19:45:32Z", "mode": 33188, "offset": 23906721, "NumLink": 0, "digest": "sha256:547d1cf6291bce0dcc569f9caad2b7d204f42efb7a20047d86aa48e0c305a52f" }, { "name": "var/lib/dpkg/info/bash.list", "type": "reg", "size": 4636, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23906872, "NumLink": 0, "digest": "sha256:58b51db22b40ea38bb1ba60552d57ad2f97a790e218779fde6502d1bb2df8dc4" }, { "name": "var/lib/dpkg/info/bash.md5sums", "type": "reg", "size": 4281, "modtime": "2017-05-15T19:45:32Z", "mode": 33188, "offset": 23907602, "NumLink": 0, "digest": "sha256:d31124a7c119d4a35de5759395224b560bcd1f0d475877e11be7cb455c3ddb33" }, { "name": "var/lib/dpkg/info/bash.postinst", "type": "reg", "size": 596, "modtime": "2017-05-15T19:45:32Z", "mode": 33261, "offset": 23909308, "NumLink": 0, "digest": "sha256:28393012a0c44900dd8c3c0cb5a707ff1774556a5630efb2d853ab4d2564ec58" }, { "name": "var/lib/dpkg/info/bash.postrm", "type": "reg", "size": 493, "modtime": "2017-05-15T19:45:32Z", "mode": 33261, "offset": 23909725, "NumLink": 0, "digest": "sha256:614ae2549afbdf6887b92b717a380196b3da6e892df5594b37b1490a94c9d65b" }, { "name": "var/lib/dpkg/info/bash.preinst", "type": "reg", "size": 36112, "modtime": "2017-05-15T19:45:32Z", "mode": 33261, "offset": 23910111, "NumLink": 0, "digest": "sha256:41dc07e488ade0ebca895980e2be50c12111e82784e27949a0a4418c04bec114" }, { "name": "var/lib/dpkg/info/bash.prerm", "type": "reg", "size": 289, "modtime": "2017-05-15T19:45:32Z", "mode": 33261, "offset": 23923457, "NumLink": 0, "digest": "sha256:8d4c0e961f582ca7821cd5b81c8ba304a90f2ddfd6efd963f58cf6020eb2198a" }, { "name": "var/lib/dpkg/info/bsdutils.list", "type": "reg", "size": 851, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23923757, "NumLink": 0, "digest": "sha256:d4b57cd70404a8b1f20addaa2a31b0ff0539f2b9175814229e904f5f4804661a" }, { "name": "var/lib/dpkg/info/bsdutils.md5sums", "type": "reg", "size": 1262, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 23924053, "NumLink": 0, "digest": "sha256:7c9fe1c6a5c5d8bd7615a54b636fa7f952de2f9c66b3d62fd5df7e98f366b38d" }, { "name": "var/lib/dpkg/info/coreutils.list", "type": "reg", "size": 9706, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23924713, "NumLink": 0, "digest": "sha256:73887279428ab722d2e19ab01daa96efa399ff7fd71c5670f3b692d86dacf190" }, { "name": "var/lib/dpkg/info/coreutils.md5sums", "type": "reg", "size": 15674, "modtime": "2017-02-22T12:23:45Z", "mode": 33188, "offset": 23926177, "NumLink": 0, "digest": "sha256:dc2084243a4eadceb52eb0911ca26725b3537176ee922973d1c2b4e412cadc91" }, { "name": "var/lib/dpkg/info/coreutils.postinst", "type": "reg", "size": 114, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 23932568, "NumLink": 0, "digest": "sha256:b8cc23953515e77bc392d81af72f7362118a5fdf5961680620c2f832bf4c56a8" }, { "name": "var/lib/dpkg/info/coreutils.postrm", "type": "reg", "size": 95, "modtime": "2017-02-22T12:23:45Z", "mode": 33261, "offset": 23932765, "NumLink": 0, "digest": "sha256:fb04069056d6bd6aadb41350b25da0f9da66ff520185f4f16445430535e1bf18" }, { "name": "var/lib/dpkg/info/dash.config", "type": "reg", "size": 769, "modtime": "2017-01-24T05:16:56Z", "mode": 33261, "offset": 23932954, "NumLink": 0, "digest": "sha256:6ce6e1f0695bac42e20a96be49b70c79cf596e8f81047ff4ea3cf922c0a9cc57" }, { "name": "var/lib/dpkg/info/dash.list", "type": "reg", "size": 418, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23933488, "NumLink": 0, "digest": "sha256:8c70bf1decf43dd6558efc6fd6115e0a7079f2ed6b6d67cdd16b3cddd170ef83" }, { "name": "var/lib/dpkg/info/dash.md5sums", "type": "reg", "size": 569, "modtime": "2017-01-24T05:16:56Z", "mode": 33188, "offset": 23933727, "NumLink": 0, "digest": "sha256:bbb41d92377cc9909cbb9eff846728815b57b30770a7e4435570bc839f136596" }, { "name": "var/lib/dpkg/info/dash.postinst", "type": "reg", "size": 3651, "modtime": "2017-01-24T05:16:56Z", "mode": 33261, "offset": 23934134, "NumLink": 0, "digest": "sha256:0ba947daf43666c6e13f9da16a5afe0349c1bb89de4776f9fcf10f73a426e23b" }, { "name": "var/lib/dpkg/info/dash.postrm", "type": "reg", "size": 341, "modtime": "2017-01-24T05:16:56Z", "mode": 33261, "offset": 23935661, "NumLink": 0, "digest": "sha256:9f0a19bf26bba371cd2ddc8b00ef14af396d279c5838beb2a13faa9a7ea624bc" }, { "name": "var/lib/dpkg/info/dash.preinst", "type": "reg", "size": 1025, "modtime": "2017-01-24T05:16:56Z", "mode": 33261, "offset": 23935929, "NumLink": 0, "digest": "sha256:3de6d6ca5b09c610c66ec74b2e40f3d68b11c7c982639a588e5533505ee4a6b5" }, { "name": "var/lib/dpkg/info/dash.prerm", "type": "reg", "size": 563, "modtime": "2017-01-24T05:16:56Z", "mode": 33261, "offset": 23936576, "NumLink": 0, "digest": "sha256:2b6e56c709fbdf8956f50193ca6312a74f598c49269298699df88a5aa1df704a" }, { "name": "var/lib/dpkg/info/dash.templates", "type": "reg", "size": 8304, "modtime": "2017-01-24T05:16:56Z", "mode": 33188, "offset": 23937002, "NumLink": 0, "digest": "sha256:9451f0fff5c8aa0da29e1947305f9430ab0b1ee6d7eac8b23f46d73716c5c64c" }, { "name": "var/lib/dpkg/info/debconf.conffiles", "type": "reg", "size": 48, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 23940553, "NumLink": 0, "digest": "sha256:1980054721522ce9b99b3c1ea992a517b0ae93c7eebb9c502129c5f12ad928a8" }, { "name": "var/lib/dpkg/info/debconf.config", "type": "reg", "size": 478, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 23940693, "NumLink": 0, "digest": "sha256:4f6cca919cf82b607d0ec001e451566c887383c41320d796021eee66b4473db2" }, { "name": "var/lib/dpkg/info/debconf.list", "type": "reg", "size": 7673, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 23941070, "NumLink": 0, "digest": "sha256:87aabfdba6416de57218fc0c9df32a0ee7ca4135c6c27ff1ba3439538983ee79" }, { "name": "var/lib/dpkg/info/debconf.md5sums", "type": "reg", "size": 11273, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 23942199, "NumLink": 0, "digest": "sha256:4ee64bce4e28a40642b016c6600a3a750c01b04da33b2fc70efd7327483adda9" }, { "name": "var/lib/dpkg/info/debconf.postinst", "type": "reg", "size": 2771, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 23946063, "NumLink": 0, "digest": "sha256:4cbedde53a7f9b8656d360515ba3c21687202322424f3425ec94f6418befa5d6" }, { "name": "var/lib/dpkg/info/debconf.postrm", "type": "reg", "size": 173, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 23947305, "NumLink": 0, "digest": "sha256:51a4e382b6fe7c3211ff6bbe2284d0556e92c66d8204f35314687236b1d0bf36" }, { "name": "var/lib/dpkg/info/debconf.preinst", "type": "reg", "size": 304, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 23947542, "NumLink": 0, "digest": "sha256:790e4c93cdc18ccaafffb44e248525d75f467aa801915de8bf6e5b73e8e37050" }, { "name": "var/lib/dpkg/info/debconf.prerm", "type": "reg", "size": 563, "modtime": "2017-05-21T17:08:30Z", "mode": 33261, "offset": 23947827, "NumLink": 0, "digest": "sha256:70c4846220638de0c245ad9c355927c73569e9bacb8d2b0b502c60bf33112713" }, { "name": "var/lib/dpkg/info/debconf.templates", "type": "reg", "size": 143753, "modtime": "2017-05-21T17:08:30Z", "mode": 33188, "offset": 23948268, "NumLink": 0, "digest": "sha256:2dbd5c40bbf8d9c6b5f4130166e3ff9fd011bb821baa748aaa18215c00f8931d" }, { "name": "var/lib/dpkg/info/debian-archive-keyring.conffiles", "type": "reg", "size": 484, "modtime": "2017-05-25T18:17:13Z", "mode": 33188, "offset": 24004857, "NumLink": 0, "digest": "sha256:654e2a0d33fb4d1c829c44c70dafa3e5595e38d152995596e376c06642eeefea" }, { "name": "var/lib/dpkg/info/debian-archive-keyring.list", "type": "reg", "size": 856, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24005062, "NumLink": 0, "digest": "sha256:96f4f39133ba8c082c06a57b06c06aad72883f4200d0393ac33b48703a7675c9" }, { "name": "var/lib/dpkg/info/debian-archive-keyring.md5sums", "type": "reg", "size": 408, "modtime": "2017-05-25T18:17:13Z", "mode": 33188, "offset": 24005347, "NumLink": 0, "digest": "sha256:54f451ebd946b6a0d11d99c92515a5038a0f82c6b47899e1e34b644baf4c7b17" }, { "name": "var/lib/dpkg/info/debian-archive-keyring.postinst", "type": "reg", "size": 1003, "modtime": "2017-05-25T18:17:13Z", "mode": 33261, "offset": 24005655, "NumLink": 0, "digest": "sha256:2f8c9f4f5775f627d7be2a1243f276d0102cd21a538e29c09be63533f93c9938" }, { "name": "var/lib/dpkg/info/debian-archive-keyring.postrm", "type": "reg", "size": 502, "modtime": "2017-05-25T18:17:13Z", "mode": 33261, "offset": 24006260, "NumLink": 0, "digest": "sha256:b5d6c516c9658fca66891cf2d4cbefa8df3a7589ac59823648d922e8e3f2da20" }, { "name": "var/lib/dpkg/info/debian-archive-keyring.preinst", "type": "reg", "size": 386, "modtime": "2017-05-25T18:17:13Z", "mode": 33261, "offset": 24006579, "NumLink": 0, "digest": "sha256:ecd03bbc5ff5faaafb62bf6386197c83d87ef43cf40d3bb61207c36950e85e65" }, { "name": "var/lib/dpkg/info/debian-archive-keyring.prerm", "type": "reg", "size": 386, "modtime": "2017-05-25T18:17:13Z", "mode": 33261, "offset": 24006845, "NumLink": 0, "digest": "sha256:f5ce562982ff479363c27e6ee1205852f1112277e91f449e1f8c17018ed6b340" }, { "name": "var/lib/dpkg/info/debianutils.list", "type": "reg", "size": 3047, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24007107, "NumLink": 0, "digest": "sha256:ce60da81c5675bf3052f1bc84b3716607de015c561813f1420797e4a106e3efe" }, { "name": "var/lib/dpkg/info/debianutils.md5sums", "type": "reg", "size": 4707, "modtime": "2017-04-02T17:10:33Z", "mode": 33188, "offset": 24007642, "NumLink": 0, "digest": "sha256:7e90c622a29d314ec3518d506f3aaca217a8df282813351308a62ef199ae2e81" }, { "name": "var/lib/dpkg/info/debianutils.postinst", "type": "reg", "size": 467, "modtime": "2015-04-26T14:59:54Z", "mode": 33261, "offset": 24009426, "NumLink": 0, "digest": "sha256:d7aa50ccd2391e2b8c627cde1ca98128022bcc387801ef50c12fee0bca864ddc" }, { "name": "var/lib/dpkg/info/debianutils.postrm", "type": "reg", "size": 377, "modtime": "2015-04-26T15:13:56Z", "mode": 33261, "offset": 24009780, "NumLink": 0, "digest": "sha256:cb0dfa3fc27cf2dfac46a355e383fc25a920cda0622e1225cc74fc3b01a6c4b1" }, { "name": "var/lib/dpkg/info/diffutils.list", "type": "reg", "size": 3727, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24010100, "NumLink": 0, "digest": "sha256:368baf799339402c56245928477592cbb954b5da994f62c79d5b0e641b100746" }, { "name": "var/lib/dpkg/info/diffutils.md5sums", "type": "reg", "size": 3329, "modtime": "2017-01-09T22:55:10Z", "mode": 33188, "offset": 24010617, "NumLink": 0, "digest": "sha256:ca2a2ba957ccbf9b43ed420641684fe93521f7e1772f816f3d39cd8edc30e55c" }, { "name": "var/lib/dpkg/info/dpkg.conffiles", "type": "reg", "size": 87, "modtime": "2018-06-26T10:28:08Z", "mode": 33188, "offset": 24011873, "NumLink": 0, "digest": "sha256:e862d61384229595858b2123b380b187a831dacd342813efd146386e09a6d91b" }, { "name": "var/lib/dpkg/info/dpkg.list", "type": "reg", "size": 8442, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24012043, "NumLink": 0, "digest": "sha256:893380cde895568233bd6640c6e79a271f5cfc599389e056f2f5b504afbb302e" }, { "name": "var/lib/dpkg/info/dpkg.md5sums", "type": "reg", "size": 9424, "modtime": "2018-06-26T10:28:08Z", "mode": 33188, "offset": 24013171, "NumLink": 0, "digest": "sha256:87683e11f19a7ef51d7fb580d027cbd03e08e4ec18df283d24deafc688e769e5" }, { "name": "var/lib/dpkg/info/dpkg.postinst", "type": "reg", "size": 718, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 24016462, "NumLink": 0, "digest": "sha256:f8cee032bc3abd6ef824d60fd2ebedd9c676c0dad1468dcffafaeb1f44d8b2fa" }, { "name": "var/lib/dpkg/info/dpkg.postrm", "type": "reg", "size": 873, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 24016981, "NumLink": 0, "digest": "sha256:9340ee2661b36e6e22ced24f954f6e372792c9fb08808de2286592031388e507" }, { "name": "var/lib/dpkg/info/dpkg.prerm", "type": "reg", "size": 4320, "modtime": "2018-06-26T10:28:08Z", "mode": 33261, "offset": 24017569, "NumLink": 0, "digest": "sha256:90d17414a0558d9c3fa44570de414a3aca7efe58019a9dd008776c2d4fa0d4eb" }, { "name": "var/lib/dpkg/info/e2fslibs:amd64.list", "type": "reg", "size": 309, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24019268, "NumLink": 0, "digest": "sha256:dda7841fc00411ce8a30c6df76478ba03721a0624593cc3dc1f368a7bc51eb00" }, { "name": "var/lib/dpkg/info/e2fslibs:amd64.md5sums", "type": "reg", "size": 285, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24019488, "NumLink": 0, "digest": "sha256:eb214c1b1b7446602a6a9e5ee69b74795987566d6384bf9ed3ec5216e4f43b8a" }, { "name": "var/lib/dpkg/info/e2fslibs:amd64.shlibs", "type": "reg", "size": 102, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24019775, "NumLink": 0, "digest": "sha256:0a5eff72f9cdae23f1af177e666a874f6b7762fe6d059cd5f6c2a59f6687b9d3" }, { "name": "var/lib/dpkg/info/e2fslibs:amd64.symbols", "type": "reg", "size": 22220, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24019943, "NumLink": 0, "digest": "sha256:01c14a7a5cc623a23209987e9efd7f93157653e312ebba93a2860b4dcabc0bd3" }, { "name": "var/lib/dpkg/info/e2fslibs:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24023654, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/e2fsprogs.conffiles", "type": "reg", "size": 17, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24023824, "NumLink": 0, "digest": "sha256:4a21d18e62ee18b0b1afd94364e581e0b9b9881ea6e2df831fe8d4086a9672b9" }, { "name": "var/lib/dpkg/info/e2fsprogs.list", "type": "reg", "size": 3724, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24023956, "NumLink": 0, "digest": "sha256:57ef0996457e5974ef969080522b44c749a50a1eaa75213139bec8cfa323242a" }, { "name": "var/lib/dpkg/info/e2fsprogs.md5sums", "type": "reg", "size": 4105, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24024636, "NumLink": 0, "digest": "sha256:09b53240f72858bef3331cb8bd2fc2d699ce58d604fb4abb1f19347d4e9eb0f5" }, { "name": "var/lib/dpkg/info/e2fsprogs.postinst", "type": "reg", "size": 162, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 24026378, "NumLink": 0, "digest": "sha256:6cd869d76cb66fbd9e1cbeb40d7a21a060ffbef4337f5486ec167b9fa733c240" }, { "name": "var/lib/dpkg/info/e2fsprogs.preinst", "type": "reg", "size": 259, "modtime": "2017-02-01T00:54:55Z", "mode": 33261, "offset": 24026600, "NumLink": 0, "digest": "sha256:0ac4873d936cbf6ea2c958b686aa5097f82306e1bd50fa6eff1b95337664dac1" }, { "name": "var/lib/dpkg/info/findutils.list", "type": "reg", "size": 4524, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24026905, "NumLink": 0, "digest": "sha256:6cc308cb40b40db24caf9341efaf30f30cac9d69f53fa2a1316d95d49603ff4b" }, { "name": "var/lib/dpkg/info/findutils.md5sums", "type": "reg", "size": 3992, "modtime": "2017-02-18T15:37:32Z", "mode": 33188, "offset": 24027492, "NumLink": 0, "digest": "sha256:1035eade64b7d7879968133488de2363b3631c5ac2eb17a2394b5d764a588432" }, { "name": "var/lib/dpkg/info/findutils.postinst", "type": "reg", "size": 1195, "modtime": "2017-02-18T15:37:32Z", "mode": 33261, "offset": 24028958, "NumLink": 0, "digest": "sha256:c42144b0d65ed7c0e11524c73d8d8d3eb4effc7fa0f5f9625a0fcbf3a1447417" }, { "name": "var/lib/dpkg/info/findutils.preinst", "type": "reg", "size": 2426, "modtime": "2017-02-18T15:37:32Z", "mode": 33261, "offset": 24029640, "NumLink": 0, "digest": "sha256:3e3c2ec17f71c24420c30fc67e3ad2b333e57e2482397c793ed79d0824872393" }, { "name": "var/lib/dpkg/info/format", "type": "reg", "size": 2, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24030546, "NumLink": 0, "digest": "sha256:4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865" }, { "name": "var/lib/dpkg/info/gcc-6-base:amd64.list", "type": "reg", "size": 349, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24030672, "NumLink": 0, "digest": "sha256:4ae17456b60df15cf95281a880673f742c88d849f8fa894e6947001e9b773e1c" }, { "name": "var/lib/dpkg/info/gcc-6-base:amd64.md5sums", "type": "reg", "size": 301, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 24030906, "NumLink": 0, "digest": "sha256:01193a7e0f32c2ff715c52b21b473c39664a88cdc2f4d57cfffc38741aa62baa" }, { "name": "var/lib/dpkg/info/gpgv.list", "type": "reg", "size": 280, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24031184, "NumLink": 0, "digest": "sha256:fa4d4420c6b77df26e9b1b0a18411c1430ad18ef9dfbb5e833d8b5480954c598" }, { "name": "var/lib/dpkg/info/gpgv.md5sums", "type": "reg", "size": 380, "modtime": "2018-06-08T18:12:24Z", "mode": 33188, "offset": 24031387, "NumLink": 0, "digest": "sha256:3246d99396b1b6878d53e58d30c99e85f22d6b5ce05e31535894cdecd188903f" }, { "name": "var/lib/dpkg/info/grep.list", "type": "reg", "size": 4692, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24031702, "NumLink": 0, "digest": "sha256:aa6915ec381a63d8a0a642d76ca65dc13762d2148bf113aa53899a0ae8168026" }, { "name": "var/lib/dpkg/info/grep.md5sums", "type": "reg", "size": 4003, "modtime": "2017-01-23T18:18:59Z", "mode": 33188, "offset": 24032323, "NumLink": 0, "digest": "sha256:96b2aaba953973e6dfc8d42bc8cdffbcc30c66b48611b709c8bf13aaf53e13b9" }, { "name": "var/lib/dpkg/info/gzip.list", "type": "reg", "size": 1024, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24033852, "NumLink": 0, "digest": "sha256:8a2f948cb270e6e1b596c66c81badfec1a83a66c51d685cbb913e4b579db389d" }, { "name": "var/lib/dpkg/info/gzip.md5sums", "type": "reg", "size": 1664, "modtime": "2016-03-14T20:41:45Z", "mode": 33188, "offset": 24034205, "NumLink": 0, "digest": "sha256:9edef4bf71da5d06c2135332126caae7d5685da7264f3fe6da0065924a32b404" }, { "name": "var/lib/dpkg/info/hostname.list", "type": "reg", "size": 484, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24035094, "NumLink": 0, "digest": "sha256:2e13d739864a9c8648b05ddd0d95c9774a37e57684ba6bad8e0b3d2e806c4f0f" }, { "name": "var/lib/dpkg/info/hostname.md5sums", "type": "reg", "size": 327, "modtime": "2016-07-03T19:26:17Z", "mode": 33188, "offset": 24035326, "NumLink": 0, "digest": "sha256:670b5c913b6da065c03bfe8ea8c01748271833e08edd312b50cfcfd7b032625f" }, { "name": "var/lib/dpkg/info/init-system-helpers.list", "type": "reg", "size": 1012, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24035622, "NumLink": 0, "digest": "sha256:9746762ee1530db38b7065f1c13389638e238c6215ea54bec21d0fdaafdaf31f" }, { "name": "var/lib/dpkg/info/init-system-helpers.md5sums", "type": "reg", "size": 1142, "modtime": "2017-05-02T10:20:21Z", "mode": 33188, "offset": 24035978, "NumLink": 0, "digest": "sha256:666ecb63b005586a769fdfce6e438c8fac1159b6f7062f2c3808356f2135fb15" }, { "name": "var/lib/dpkg/info/init-system-helpers.postinst", "type": "reg", "size": 275, "modtime": "2017-05-02T10:20:21Z", "mode": 33261, "offset": 24036596, "NumLink": 0, "digest": "sha256:fc3b0684d7e3817cd81b736b6705541dd779e8af434558ccb9b370d0f52bfc8a" }, { "name": "var/lib/dpkg/info/libacl1:amd64.list", "type": "reg", "size": 317, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24036878, "NumLink": 0, "digest": "sha256:e2629d1d7243300ab8132dec55f14a86cd969a75cd29eedd44307cd00b14cd41" }, { "name": "var/lib/dpkg/info/libacl1:amd64.md5sums", "type": "reg", "size": 364, "modtime": "2016-02-06T22:10:44Z", "mode": 33188, "offset": 24037091, "NumLink": 0, "digest": "sha256:da8ad230618cacd1466ab9a4162a4b78bafcc18481adf556636c3bb29c9a4e5f" }, { "name": "var/lib/dpkg/info/libacl1:amd64.shlibs", "type": "reg", "size": 31, "modtime": "2016-02-06T22:10:44Z", "mode": 33188, "offset": 24037397, "NumLink": 0, "digest": "sha256:22cf70aad343f840f2ad3e2248b2afa1211b91e83ae25ccdd93c34cfcb64ed1b" }, { "name": "var/lib/dpkg/info/libacl1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2016-02-06T22:10:44Z", "mode": 33188, "offset": 24037544, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libapt-pkg5.0:amd64.list", "type": "reg", "size": 4833, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24037722, "NumLink": 0, "digest": "sha256:f8dd334e23c8030e4860575052965286e08b44db92dd22cb81669f9d9ab65966" }, { "name": "var/lib/dpkg/info/libapt-pkg5.0:amd64.md5sums", "type": "reg", "size": 3882, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 24038309, "NumLink": 0, "digest": "sha256:736c62eded3c14d921f9cc373dfbc0ae6a2b0b052c3126e123ea70b45921de98" }, { "name": "var/lib/dpkg/info/libapt-pkg5.0:amd64.shlibs", "type": "reg", "size": 29, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 24039624, "NumLink": 0, "digest": "sha256:66acf56dd792547b8f0503be6e9d104da1c208fce8864bbc2b472efc009005f6" }, { "name": "var/lib/dpkg/info/libapt-pkg5.0:amd64.symbols", "type": "reg", "size": 143029, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 24039768, "NumLink": 0, "digest": "sha256:aa71b10df877584493174076f143defdcaaf59e4771aaafe34bede8857579ea7" }, { "name": "var/lib/dpkg/info/libapt-pkg5.0:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-09-13T16:47:33Z", "mode": 33188, "offset": 24057089, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libattr1:amd64.list", "type": "reg", "size": 324, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24057261, "NumLink": 0, "digest": "sha256:0e3ea509a127c52d380f9c63b130034276a4a91ba0abe0a384a6e7bfbecd8b88" }, { "name": "var/lib/dpkg/info/libattr1:amd64.md5sums", "type": "reg", "size": 369, "modtime": "2014-09-08T07:27:07Z", "mode": 33188, "offset": 24057475, "NumLink": 0, "digest": "sha256:8c1f3dde4ab64f0f2f275a58274b92c7ac6503664e35ec68f0b684a60d12f780" }, { "name": "var/lib/dpkg/info/libattr1:amd64.shlibs", "type": "reg", "size": 81, "modtime": "2014-09-08T07:27:07Z", "mode": 33188, "offset": 24057780, "NumLink": 0, "digest": "sha256:748a3ebb90124c9caad8a81d4f484295df4f49ab91c9012b5e7cad01140c88a6" }, { "name": "var/lib/dpkg/info/libattr1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2014-09-08T07:27:07Z", "mode": 33188, "offset": 24057943, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libaudit-common.conffiles", "type": "reg", "size": 19, "modtime": "2017-04-12T16:17:21Z", "mode": 33188, "offset": 24058120, "NumLink": 0, "digest": "sha256:e59079facf60922dd9bef9974c852e6ad3315ca2639141786bb268e8e877bec3" }, { "name": "var/lib/dpkg/info/libaudit-common.list", "type": "reg", "size": 299, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24058253, "NumLink": 0, "digest": "sha256:809f79c7732df66a7252edea0a4ef3388b43e122fedd8a27bf0a90a059c5c3d8" }, { "name": "var/lib/dpkg/info/libaudit-common.md5sums", "type": "reg", "size": 307, "modtime": "2017-04-12T16:17:21Z", "mode": 33188, "offset": 24058457, "NumLink": 0, "digest": "sha256:ec9f52547dddbb491f7347c0c8869c5c77f62e0190d48bcedc5ddb31b7dec556" }, { "name": "var/lib/dpkg/info/libaudit1:amd64.list", "type": "reg", "size": 280, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24058733, "NumLink": 0, "digest": "sha256:af8c5c402019fb6f8eb0afeb14b68d25173855aab601b50c3fedeede3f1bbab5" }, { "name": "var/lib/dpkg/info/libaudit1:amd64.md5sums", "type": "reg", "size": 290, "modtime": "2017-04-12T16:17:21Z", "mode": 33188, "offset": 24058942, "NumLink": 0, "digest": "sha256:c50686eda08e1f881321c160bdd141c8372bb4ead4455878ced47463626fbc95" }, { "name": "var/lib/dpkg/info/libaudit1:amd64.shlibs", "type": "reg", "size": 21, "modtime": "2017-04-12T16:17:21Z", "mode": 33188, "offset": 24059225, "NumLink": 0, "digest": "sha256:7f372d6c7b0b7c8da4b6d8de368a525bf6ecbd2c1508e2a9e78a1b1aeb8684b7" }, { "name": "var/lib/dpkg/info/libaudit1:amd64.symbols", "type": "reg", "size": 2729, "modtime": "2017-04-12T16:17:21Z", "mode": 33188, "offset": 24059361, "NumLink": 0, "digest": "sha256:f536380e2359838d0d7b6e4f39d035fffa27cbaf0ee6c037bc8961dcd109fe35" }, { "name": "var/lib/dpkg/info/libaudit1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-04-12T16:17:21Z", "mode": 33188, "offset": 24060080, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libblkid1:amd64.list", "type": "reg", "size": 280, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24060252, "NumLink": 0, "digest": "sha256:6780ed0dca80693cadcbb6c482432ea79e940e32e4022372a0ea1a67475e0d22" }, { "name": "var/lib/dpkg/info/libblkid1:amd64.md5sums", "type": "reg", "size": 290, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24060463, "NumLink": 0, "digest": "sha256:cbdc8b7425256a16bfb81bcccaf719d5105ef7defa393995222e4a9c5562c72f" }, { "name": "var/lib/dpkg/info/libblkid1:amd64.shlibs", "type": "reg", "size": 73, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24060744, "NumLink": 0, "digest": "sha256:9c7ba7351473074d5a2f0f23a2378307bfbe271e53d689db16663870b1e7e3aa" }, { "name": "var/lib/dpkg/info/libblkid1:amd64.symbols", "type": "reg", "size": 4619, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24060904, "NumLink": 0, "digest": "sha256:b951a14c5f41e6ab1aa17a3ca0cffcf5f8d6c88de04ced37d6369cc6af34fbc5" }, { "name": "var/lib/dpkg/info/libblkid1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24061842, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libbz2-1.0:amd64.list", "type": "reg", "size": 316, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24062016, "NumLink": 0, "digest": "sha256:dcc4781ab86d80723d1cfe1f0ffe2494bbf07fb9c0f68133289d0f67816b3613" }, { "name": "var/lib/dpkg/info/libbz2-1.0:amd64.md5sums", "type": "reg", "size": 291, "modtime": "2017-01-29T18:30:31Z", "mode": 33188, "offset": 24062230, "NumLink": 0, "digest": "sha256:ca7005e5434d78e7e4eb43e5cb453f72563f1c39cd3a5f63e6fbbd43c29574c5" }, { "name": "var/lib/dpkg/info/libbz2-1.0:amd64.shlibs", "type": "reg", "size": 22, "modtime": "2017-01-29T17:57:57Z", "mode": 33188, "offset": 24062515, "NumLink": 0, "digest": "sha256:a48a7878642bc8269876a391a88dd3be02eeff425924be9462c4306ecccbcb20" }, { "name": "var/lib/dpkg/info/libbz2-1.0:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-01-29T18:30:31Z", "mode": 33188, "offset": 24062655, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libc-bin.conffiles", "type": "reg", "size": 103, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 24062826, "NumLink": 0, "digest": "sha256:ed1819b3573af7f7dfa94bc34567884dce8f5fabd0ae065a646d4f23d28ade32" }, { "name": "var/lib/dpkg/info/libc-bin.list", "type": "reg", "size": 1353, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24062997, "NumLink": 0, "digest": "sha256:5f95bcc50c60a7da16e8712cf72a7e7eae8a4f89640a790b0f86414ae5498a90" }, { "name": "var/lib/dpkg/info/libc-bin.md5sums", "type": "reg", "size": 2032, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 24063486, "NumLink": 0, "digest": "sha256:39a13558bc6e5e62157aea5f1874eb4b3d4199960efe0556fbc839ab39a67827" }, { "name": "var/lib/dpkg/info/libc-bin.postinst", "type": "reg", "size": 1222, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 24064565, "NumLink": 0, "digest": "sha256:47fc92ea75c72d16a695f78d1fc35671020810e4bef594266a269b34d6e9ac9a" }, { "name": "var/lib/dpkg/info/libc-bin.triggers", "type": "reg", "size": 18, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 24065205, "NumLink": 0, "digest": "sha256:3766ef03d6f8c75bc29b5131021ba41e1787667878a97b81264c5fac6ec07ae4" }, { "name": "var/lib/dpkg/info/libc6:amd64.conffiles", "type": "reg", "size": 40, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 24065345, "NumLink": 0, "digest": "sha256:a59a14914231cc9a833ba49b14308e57b755236ff70bc3b0c4ee77b2bd34eed8" }, { "name": "var/lib/dpkg/info/libc6:amd64.list", "type": "reg", "size": 13478, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24065499, "NumLink": 0, "digest": "sha256:510f950eefd185e3b1e8ca219c366602149dccfc13ccd0c1b2bc8b3497b19b29" }, { "name": "var/lib/dpkg/info/libc6:amd64.md5sums", "type": "reg", "size": 21875, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 24067091, "NumLink": 0, "digest": "sha256:7b72ebbbdbef6e0b3516a86fb65d6b7384367b943ee17d8499336efa424bbb71" }, { "name": "var/lib/dpkg/info/libc6:amd64.postinst", "type": "reg", "size": 10697, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 24074198, "NumLink": 0, "digest": "sha256:985a06a1f9156657c6a0db76cb2eeae6ceb2878668067c7b05a54e8f44f1ac73" }, { "name": "var/lib/dpkg/info/libc6:amd64.postrm", "type": "reg", "size": 2186, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 24078145, "NumLink": 0, "digest": "sha256:19000428e9404e06ed796d7dce5be523f175a88691e101df1fe0b5b3cb3cfe68" }, { "name": "var/lib/dpkg/info/libc6:amd64.preinst", "type": "reg", "size": 17153, "modtime": "2018-01-14T10:39:44Z", "mode": 33261, "offset": 24079117, "NumLink": 0, "digest": "sha256:792222823d198c8bcadfe6753386216da79458f15b78675634fced792929f91e" }, { "name": "var/lib/dpkg/info/libc6:amd64.shlibs", "type": "reg", "size": 1047, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 24084363, "NumLink": 0, "digest": "sha256:005d577db433aef01db36bf3cdd005b18e1f432f594e3399179f27165bcde2b8" }, { "name": "var/lib/dpkg/info/libc6:amd64.symbols", "type": "reg", "size": 114353, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 24084689, "NumLink": 0, "digest": "sha256:aaad67bd69138c3eb8deacd4e39786f2ce2a32fc1a656965f11bcc617587d0e9" }, { "name": "var/lib/dpkg/info/libc6:amd64.templates", "type": "reg", "size": 77955, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 24100943, "NumLink": 0, "digest": "sha256:da65f855fe06ff7bca68e544a08fb5191abd6f68450b6d7e6201d26bc2f2e03e" }, { "name": "var/lib/dpkg/info/libc6:amd64.triggers", "type": "reg", "size": 60, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 24128786, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libcap-ng0:amd64.list", "type": "reg", "size": 347, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24128960, "NumLink": 0, "digest": "sha256:7693823b3ad20f192c8094c97d956b9c74db6589b7bddf8949e8fa74ae377bf9" }, { "name": "var/lib/dpkg/info/libcap-ng0:amd64.md5sums", "type": "reg", "size": 379, "modtime": "2016-07-03T19:04:40Z", "mode": 33188, "offset": 24129179, "NumLink": 0, "digest": "sha256:06038ad6ef856d76ac52a74735cbb48b6aa3b0ab85a0cd1aaf330bcb73895201" }, { "name": "var/lib/dpkg/info/libcap-ng0:amd64.shlibs", "type": "reg", "size": 23, "modtime": "2016-07-03T19:04:40Z", "mode": 33188, "offset": 24129487, "NumLink": 0, "digest": "sha256:a6ed952c5c08c8997ec9e95b301fe30a0f32e984ed47ba51b542e208ee63143f" }, { "name": "var/lib/dpkg/info/libcap-ng0:amd64.triggers", "type": "reg", "size": 60, "modtime": "2016-07-03T19:04:40Z", "mode": 33188, "offset": 24129625, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libcomerr2:amd64.list", "type": "reg", "size": 247, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24129800, "NumLink": 0, "digest": "sha256:9f75eec6de039a666ceb3b8c0e090728947957d50e3dd48336266c4bd24d32b3" }, { "name": "var/lib/dpkg/info/libcomerr2:amd64.md5sums", "type": "reg", "size": 221, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24130013, "NumLink": 0, "digest": "sha256:f76f1ed9c07f3abc32de857fcaf7e3c13b77e27e886a6c72f63c5b571a32654c" }, { "name": "var/lib/dpkg/info/libcomerr2:amd64.shlibs", "type": "reg", "size": 58, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24130273, "NumLink": 0, "digest": "sha256:4b4d72efc9babddd5618d2fbd2b3bb3ba97f06b4e82c8660bf2df6391b137f54" }, { "name": "var/lib/dpkg/info/libcomerr2:amd64.symbols", "type": "reg", "size": 574, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24130433, "NumLink": 0, "digest": "sha256:55c2170f11bf72c7ea81ecf80cd619f1ead728f739bc048ec7989abea0b627dd" }, { "name": "var/lib/dpkg/info/libcomerr2:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24130750, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libdb5.3:amd64.list", "type": "reg", "size": 346, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24130923, "NumLink": 0, "digest": "sha256:3d4faca15ced03057f8bc69053d5e2e67c00703abfcf93632139571546ad916f" }, { "name": "var/lib/dpkg/info/libdb5.3:amd64.md5sums", "type": "reg", "size": 370, "modtime": "2017-09-24T07:14:53Z", "mode": 33188, "offset": 24131161, "NumLink": 0, "digest": "sha256:d1729499e5e3880d6c9fa118f119c908c0591aa46bdb93e734ec9e887a786a65" }, { "name": "var/lib/dpkg/info/libdb5.3:amd64.shlibs", "type": "reg", "size": 19, "modtime": "2017-09-24T07:14:53Z", "mode": 33188, "offset": 24131487, "NumLink": 0, "digest": "sha256:43a64578438bcbe0fa74ce2478b2f913223f79a3f76d18a41a389ec6d7e509d3" }, { "name": "var/lib/dpkg/info/libdb5.3:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-09-24T07:14:53Z", "mode": 33188, "offset": 24131622, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libdebconfclient0:amd64.list", "type": "reg", "size": 291, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24131801, "NumLink": 0, "digest": "sha256:91c1e72cb0d152067397a31ea09d54b6593c93164a399b8f6be9a0bcddb9e5d0" }, { "name": "var/lib/dpkg/info/libdebconfclient0:amd64.md5sums", "type": "reg", "size": 240, "modtime": "2017-04-03T05:58:27Z", "mode": 33188, "offset": 24132007, "NumLink": 0, "digest": "sha256:17d7b1886ddb3fcdb0bdc192d6bd6c3bfe13425f06119042a0325acdf40da30f" }, { "name": "var/lib/dpkg/info/libdebconfclient0:amd64.shlibs", "type": "reg", "size": 85, "modtime": "2017-04-03T05:58:27Z", "mode": 33188, "offset": 24132262, "NumLink": 0, "digest": "sha256:31978d3a0c5700466d753a9b79e77e61a871511da1b0dbb2b70f696378c94217" }, { "name": "var/lib/dpkg/info/libdebconfclient0:amd64.symbols", "type": "reg", "size": 143, "modtime": "2017-04-03T05:58:27Z", "mode": 33188, "offset": 24132419, "NumLink": 0, "digest": "sha256:e237639741b96561a9a2b619cf681517370df3a03896fa12b247be2b529827a0" }, { "name": "var/lib/dpkg/info/libdebconfclient0:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-04-03T05:58:27Z", "mode": 33188, "offset": 24132610, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libfdisk1:amd64.list", "type": "reg", "size": 280, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24132781, "NumLink": 0, "digest": "sha256:cf7d82e71a043affb869d05ea4b7eed4f8f56c2f3ffeb4c924fcbf8fb7f9d36e" }, { "name": "var/lib/dpkg/info/libfdisk1:amd64.md5sums", "type": "reg", "size": 290, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24132991, "NumLink": 0, "digest": "sha256:058eb37fa093aa54b1c4d8de8b22a469debcf5dc9ef179e741819d409ce3ab73" }, { "name": "var/lib/dpkg/info/libfdisk1:amd64.shlibs", "type": "reg", "size": 75, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24133272, "NumLink": 0, "digest": "sha256:162982062d89eaa9d5eac8ff1977aa687f1eb0640d3ff21ecca969a62bb8a605" }, { "name": "var/lib/dpkg/info/libfdisk1:amd64.symbols", "type": "reg", "size": 11005, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24133433, "NumLink": 0, "digest": "sha256:4a53c2e609f5a5860dd0485715f6362a0a88fd77628db72cc5e2bf3404385db9" }, { "name": "var/lib/dpkg/info/libfdisk1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24135118, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libgcc1:amd64.list", "type": "reg", "size": 205, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24135289, "NumLink": 0, "digest": "sha256:bfd58c1e14511b97df3f8e414924c7759e0da246e1ea62500e9240007c1060dd" }, { "name": "var/lib/dpkg/info/libgcc1:amd64.md5sums", "type": "reg", "size": 139, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 24135485, "NumLink": 0, "digest": "sha256:cd76e81c89511ba018765a2b3e6da8de7ee448c6aab0abb110cb0ba9e290c995" }, { "name": "var/lib/dpkg/info/libgcc1:amd64.postinst", "type": "reg", "size": 180, "modtime": "2018-02-14T16:53:20Z", "mode": 33261, "offset": 24135707, "NumLink": 0, "digest": "sha256:91466095137000731e5aaa4c2e0a84b5c5817ef0c3e4152901d2c0dd753d2b90" }, { "name": "var/lib/dpkg/info/libgcc1:amd64.shlibs", "type": "reg", "size": 19, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 24135944, "NumLink": 0, "digest": "sha256:bd9a2ed68fc98f63e44063dc4f3f7baaa2a26699e91e00f864d8ae1ae459beee" }, { "name": "var/lib/dpkg/info/libgcc1:amd64.symbols", "type": "reg", "size": 4360, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 24136079, "NumLink": 0, "digest": "sha256:1ea41fd012f575401b19ea387b90bed877f20087b3720253828f5a451a0ead8a" }, { "name": "var/lib/dpkg/info/libgcc1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 24137047, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libgcrypt20:amd64.list", "type": "reg", "size": 439, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24137221, "NumLink": 0, "digest": "sha256:91683fea355adec504710db635979e8817691c8cbf8c83cff1b988cbb0092783" }, { "name": "var/lib/dpkg/info/libgcrypt20:amd64.md5sums", "type": "reg", "size": 577, "modtime": "2018-06-15T09:58:05Z", "mode": 33188, "offset": 24137470, "NumLink": 0, "digest": "sha256:69a2e988b1b547f1219f24a0de4f02388f52202474bd125b92d599ebc8d5b7be" }, { "name": "var/lib/dpkg/info/libgcrypt20:amd64.shlibs", "type": "reg", "size": 85, "modtime": "2018-06-15T09:58:05Z", "mode": 33188, "offset": 24137879, "NumLink": 0, "digest": "sha256:9f43b99b16c2a39b2f53ff68fc28c1aec77d7daa459c4ccee2fb319138e3dc84" }, { "name": "var/lib/dpkg/info/libgcrypt20:amd64.symbols", "type": "reg", "size": 7364, "modtime": "2018-06-15T09:58:05Z", "mode": 33188, "offset": 24138044, "NumLink": 0, "digest": "sha256:0c0a991c6f2cc653d05fd1322535590fd83ac863f1bdd9f45bbda58d0c4faa1a" }, { "name": "var/lib/dpkg/info/libgcrypt20:amd64.triggers", "type": "reg", "size": 60, "modtime": "2018-06-15T09:58:05Z", "mode": 33188, "offset": 24139220, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libgpg-error0:amd64.list", "type": "reg", "size": 2337, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24139397, "NumLink": 0, "digest": "sha256:36afe0dc7ee8330b2dc1b1df8b9ea152ec4ad1445ea8862e2d1771ab1725f623" }, { "name": "var/lib/dpkg/info/libgpg-error0:amd64.md5sums", "type": "reg", "size": 1943, "modtime": "2017-01-18T16:27:10Z", "mode": 33188, "offset": 24139809, "NumLink": 0, "digest": "sha256:10d0827517555904cceb0b464dc4a4730aea28f269d7cbce3138268b5b6da215" }, { "name": "var/lib/dpkg/info/libgpg-error0:amd64.shlibs", "type": "reg", "size": 89, "modtime": "2017-01-18T16:27:10Z", "mode": 33188, "offset": 24140600, "NumLink": 0, "digest": "sha256:6369bf8001d9f8e107f7c57e0fa983c27c234db6f67ce6a38e4dc2f9076bfcda" }, { "name": "var/lib/dpkg/info/libgpg-error0:amd64.symbols", "type": "reg", "size": 3652, "modtime": "2017-01-18T16:27:10Z", "mode": 33188, "offset": 24140763, "NumLink": 0, "digest": "sha256:9be5deaeebda64772fdca2136bf03412dd183c255a2d2c8c8dbf97df6ff17817" }, { "name": "var/lib/dpkg/info/libgpg-error0:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-01-18T16:27:10Z", "mode": 33188, "offset": 24141435, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/liblz4-1:amd64.list", "type": "reg", "size": 301, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24141607, "NumLink": 0, "digest": "sha256:1b8651c732da43e7bbedfb35730a94b753486eea886a6004b3f3aea93a23e13f" }, { "name": "var/lib/dpkg/info/liblz4-1:amd64.md5sums", "type": "reg", "size": 302, "modtime": "2016-02-17T15:27:54Z", "mode": 33188, "offset": 24141819, "NumLink": 0, "digest": "sha256:f490e2a1b302cc5342c931e0aac525fad2e2dd2743d99835ba672c500f55cf43" }, { "name": "var/lib/dpkg/info/liblz4-1:amd64.shlibs", "type": "reg", "size": 18, "modtime": "2016-02-17T15:27:54Z", "mode": 33188, "offset": 24142101, "NumLink": 0, "digest": "sha256:88f3b33028e4581770c7c23cdf757398b80bc672210d8ff5dc9b78aadaf40722" }, { "name": "var/lib/dpkg/info/liblz4-1:amd64.symbols", "type": "reg", "size": 3436, "modtime": "2016-02-17T15:27:54Z", "mode": 33188, "offset": 24142236, "NumLink": 0, "digest": "sha256:60d87d63ced63b4cc5e06660925c131ac795036909f9ea3a35e9e82ce1dbc5aa" }, { "name": "var/lib/dpkg/info/liblz4-1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2016-02-17T15:27:54Z", "mode": 33188, "offset": 24142920, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/liblzma5:amd64.list", "type": "reg", "size": 419, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24143094, "NumLink": 0, "digest": "sha256:3a391825d566d675fddca15f6e4086f4369271bf056ee9d94294146b835c235c" }, { "name": "var/lib/dpkg/info/liblzma5:amd64.md5sums", "type": "reg", "size": 563, "modtime": "2016-10-08T13:11:19Z", "mode": 33188, "offset": 24143341, "NumLink": 0, "digest": "sha256:4cf1bd29dd0f2be41754f6984bce0563d48dddabd94af2cc61c1af496fc99290" }, { "name": "var/lib/dpkg/info/liblzma5:amd64.shlibs", "type": "reg", "size": 19, "modtime": "2016-10-08T13:11:19Z", "mode": 33188, "offset": 24143746, "NumLink": 0, "digest": "sha256:8a99812b1ff7964dc1406e712978d1ebc4e7ef9d74bc1b271c28a2a48446769d" }, { "name": "var/lib/dpkg/info/liblzma5:amd64.symbols", "type": "reg", "size": 4880, "modtime": "2016-10-08T13:11:19Z", "mode": 33188, "offset": 24143882, "NumLink": 0, "digest": "sha256:682a57db44010fb9eeb18ce1a2e7792b2aaf77f0ffd39d95f8a444d43e97c86c" }, { "name": "var/lib/dpkg/info/liblzma5:amd64.triggers", "type": "reg", "size": 60, "modtime": "2016-10-08T13:11:19Z", "mode": 33188, "offset": 24144639, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libmount1:amd64.list", "type": "reg", "size": 280, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24144813, "NumLink": 0, "digest": "sha256:d0f8689fb2b0b1547e30af3725a7be7fcafb94c85206a373d1c14f934f1d458a" }, { "name": "var/lib/dpkg/info/libmount1:amd64.md5sums", "type": "reg", "size": 290, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24145023, "NumLink": 0, "digest": "sha256:71d40c703c53148c3cb8f6d818da8b5f9b297f3cbcf4f832bcc731bf99fc5d5c" }, { "name": "var/lib/dpkg/info/libmount1:amd64.shlibs", "type": "reg", "size": 75, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24145305, "NumLink": 0, "digest": "sha256:a524d83582803e9f8c30a1731b71f3a538c74a8dbdce4506922d2ff257674970" }, { "name": "var/lib/dpkg/info/libmount1:amd64.symbols", "type": "reg", "size": 11419, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24145470, "NumLink": 0, "digest": "sha256:cec9fd5edad1e27fda3d91132929d1559b9ae6bb7df61ad71bb8928e97ee8bc1" }, { "name": "var/lib/dpkg/info/libmount1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24147308, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libncursesw5:amd64.list", "type": "reg", "size": 452, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24147483, "NumLink": 0, "digest": "sha256:14d7e39ef1e7a0aa1ebfb268d7e55e8317ef7dd893410351ac024bae982d7ea9" }, { "name": "var/lib/dpkg/info/libncursesw5:amd64.md5sums", "type": "reg", "size": 300, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 24147698, "NumLink": 0, "digest": "sha256:394c6d75586d60423595b6d5cec4e9e822e4d36ca23dbdbb5b602ba3a84baab1" }, { "name": "var/lib/dpkg/info/libncursesw5:amd64.shlibs", "type": "reg", "size": 128, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 24147961, "NumLink": 0, "digest": "sha256:37120c652701ac2173dafe1cde3a1243897f02a48ccb6025dbb1c198afc62445" }, { "name": "var/lib/dpkg/info/libncursesw5:amd64.symbols", "type": "reg", "size": 25048, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 24148130, "NumLink": 0, "digest": "sha256:80047a5dfe0a4aa69614140fd9d270d20a3cfa971b34c3da53fbef887afa585a" }, { "name": "var/lib/dpkg/info/libncursesw5:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 24151006, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libpam-modules-bin.list", "type": "reg", "size": 692, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24151180, "NumLink": 0, "digest": "sha256:df966cbf9d317eac8664ace185fcc8719052f35021d521c74d83c79054fd58a6" }, { "name": "var/lib/dpkg/info/libpam-modules-bin.md5sums", "type": "reg", "size": 1020, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 24151487, "NumLink": 0, "digest": "sha256:0678312e97ff9641033dd232de0c4275f4fb33c976f95a791127ab3ebe35225e" }, { "name": "var/lib/dpkg/info/libpam-modules:amd64.conffiles", "type": "reg", "size": 214, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 24152083, "NumLink": 0, "digest": "sha256:d55c2f2fa42a5a8d21bb599e010aa7053a91156c8523bc54fe6907ddfbf665dd" }, { "name": "var/lib/dpkg/info/libpam-modules:amd64.list", "type": "reg", "size": 4547, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24152279, "NumLink": 0, "digest": "sha256:76d7cfa38780402b874c7125a4597155f4eb73df587b929630963eda56ac9f8c" }, { "name": "var/lib/dpkg/info/libpam-modules:amd64.md5sums", "type": "reg", "size": 7235, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 24153050, "NumLink": 0, "digest": "sha256:e6249c0bb8c62d8fb7508eae5768d38d0c7620f2cc297e9d419ba66266a2a3ee" }, { "name": "var/lib/dpkg/info/libpam-modules:amd64.postinst", "type": "reg", "size": 706, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 24155725, "NumLink": 0, "digest": "sha256:a7cc62a56ddb6c83ffa89bc07acc3a39173336c24e030f94359ee202e3c04581" }, { "name": "var/lib/dpkg/info/libpam-modules:amd64.postrm", "type": "reg", "size": 206, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 24156207, "NumLink": 0, "digest": "sha256:c1c04914a45a56607aa795b52767684381625c27cb3a8f45302cbfa088f735b5" }, { "name": "var/lib/dpkg/info/libpam-modules:amd64.preinst", "type": "reg", "size": 259, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 24156462, "NumLink": 0, "digest": "sha256:bb1e2ecebc040efddf6cd8a31d090bd0f7dd7f7aa897e55b0176c52f2f186c9a" }, { "name": "var/lib/dpkg/info/libpam-modules:amd64.templates", "type": "reg", "size": 13331, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 24156752, "NumLink": 0, "digest": "sha256:492118f3907959065d04da4f35ebcf39f0c80bf68e0c2e3314967f390cd53714" }, { "name": "var/lib/dpkg/info/libpam-runtime.conffiles", "type": "reg", "size": 31, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 24162918, "NumLink": 0, "digest": "sha256:0e5df5e3149674007ef3a300996163a4d8692d21dabe9df527cf6a07e3abd65d" }, { "name": "var/lib/dpkg/info/libpam-runtime.list", "type": "reg", "size": 8374, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24163062, "NumLink": 0, "digest": "sha256:d4f0f038515bd00292f58941c66c08f36505f1d3b8a646644af7169f3670586a" }, { "name": "var/lib/dpkg/info/libpam-runtime.md5sums", "type": "reg", "size": 7166, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 24164016, "NumLink": 0, "digest": "sha256:40df1963a92dd2d90b50962e8b268178e071b61bd7049cc9a2e0135109a747fe" }, { "name": "var/lib/dpkg/info/libpam-runtime.postinst", "type": "reg", "size": 1282, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 24166482, "NumLink": 0, "digest": "sha256:d6db2d0dd0999f840faaacc10a2cdc4e6b9227022b2d72da42ee67fe7c5968ec" }, { "name": "var/lib/dpkg/info/libpam-runtime.postrm", "type": "reg", "size": 517, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 24167161, "NumLink": 0, "digest": "sha256:dda72491512e6f9757bec477428df23d17cd1f20c9c6c6b72599db270a0e62ea" }, { "name": "var/lib/dpkg/info/libpam-runtime.prerm", "type": "reg", "size": 92, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 24167516, "NumLink": 0, "digest": "sha256:b3e3b7ea23ac1d1c74ebc6aa3efee132675f5e69d9e2caba6c23e64a7b94b7f8" }, { "name": "var/lib/dpkg/info/libpam-runtime.templates", "type": "reg", "size": 34973, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 24167717, "NumLink": 0, "digest": "sha256:96fc978c5f7ce82b7aa2ab6a57a91228f44836db4288d95a50f42056c7581b14" }, { "name": "var/lib/dpkg/info/libpam0g:amd64.list", "type": "reg", "size": 710, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24181173, "NumLink": 0, "digest": "sha256:14c598b8be0d1f112802deb1b52843e3d9d9bdcc78f187c7093111c7b33391f8" }, { "name": "var/lib/dpkg/info/libpam0g:amd64.md5sums", "type": "reg", "size": 865, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 24181476, "NumLink": 0, "digest": "sha256:b8bc98dbb552c8df8ef92a791d1d5bc2cf227706e21c5b5bb9738ea1b5654d4b" }, { "name": "var/lib/dpkg/info/libpam0g:amd64.postinst", "type": "reg", "size": 5194, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 24182005, "NumLink": 0, "digest": "sha256:b1ea7619ae35ddbee9f58c0f71db9124ea5fab366e61309077dee4ef09ee0174" }, { "name": "var/lib/dpkg/info/libpam0g:amd64.postrm", "type": "reg", "size": 206, "modtime": "2017-05-27T15:44:02Z", "mode": 33261, "offset": 24184093, "NumLink": 0, "digest": "sha256:c1c04914a45a56607aa795b52767684381625c27cb3a8f45302cbfa088f735b5" }, { "name": "var/lib/dpkg/info/libpam0g:amd64.shlibs", "type": "reg", "size": 60, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 24184344, "NumLink": 0, "digest": "sha256:a9c316ab6c53dfa6f54c6eaa85530094f69c5da701e5edba5fad35ba336c2704" }, { "name": "var/lib/dpkg/info/libpam0g:amd64.symbols", "type": "reg", "size": 2959, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 24184490, "NumLink": 0, "digest": "sha256:d031a2a300bdc8769b22fe280cbb8d05fdb812b92a73b8454fe3ded9fe1f021d" }, { "name": "var/lib/dpkg/info/libpam0g:amd64.templates", "type": "reg", "size": 35685, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 24185131, "NumLink": 0, "digest": "sha256:d27358a3c3a7cddd4ba50ab21b8dcf903b0bb32f25c51703bda07d450a3f4b7f" }, { "name": "var/lib/dpkg/info/libpam0g:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-05-27T15:44:02Z", "mode": 33188, "offset": 24199156, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libpcre3:amd64.list", "type": "reg", "size": 630, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24199329, "NumLink": 0, "digest": "sha256:4a2e555c79ca4430e5833b31e4e8fadb8282bd948756095acd44081a976dfcc0" }, { "name": "var/lib/dpkg/info/libpcre3:amd64.md5sums", "type": "reg", "size": 707, "modtime": "2017-03-21T22:03:19Z", "mode": 33188, "offset": 24199625, "NumLink": 0, "digest": "sha256:b267cc3b7967e3d2776b1e83a22dd8699cc3099874aa6cd7b47998211c41a7c4" }, { "name": "var/lib/dpkg/info/libpcre3:amd64.shlibs", "type": "reg", "size": 156, "modtime": "2017-03-21T22:03:19Z", "mode": 33188, "offset": 24200093, "NumLink": 0, "digest": "sha256:0777f0af691ada09d50ad2634d2eb2a2f29faa1ef79b9be0f5688e568b90dc75" }, { "name": "var/lib/dpkg/info/libpcre3:amd64.symbols", "type": "reg", "size": 1125, "modtime": "2017-03-21T22:03:19Z", "mode": 33188, "offset": 24200266, "NumLink": 0, "digest": "sha256:b6c27cab7115a1677a8bfcd33ad4b5e644aa729086c14e20fba7d8bf44d8a659" }, { "name": "var/lib/dpkg/info/libpcre3:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-03-21T22:03:19Z", "mode": 33188, "offset": 24200667, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libselinux1:amd64.list", "type": "reg", "size": 303, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24200842, "NumLink": 0, "digest": "sha256:243992305f3d7120e42236255f9ec91df9cfd525ffcb6d1d5098d7e7dbcc7213" }, { "name": "var/lib/dpkg/info/libselinux1:amd64.md5sums", "type": "reg", "size": 380, "modtime": "2017-09-24T15:30:16Z", "mode": 33188, "offset": 24201052, "NumLink": 0, "digest": "sha256:5b4a608204edd53909754f87f898ee8758f058548f2af020d7a77295563de5e9" }, { "name": "var/lib/dpkg/info/libselinux1:amd64.shlibs", "type": "reg", "size": 61, "modtime": "2017-09-24T15:30:16Z", "mode": 33188, "offset": 24201358, "NumLink": 0, "digest": "sha256:f2b70f61e92067b391c00c2c7f7b2f9322c979cf0b8073969f12dda8130c1209" }, { "name": "var/lib/dpkg/info/libselinux1:amd64.symbols", "type": "reg", "size": 7774, "modtime": "2017-09-24T15:30:16Z", "mode": 33188, "offset": 24201509, "NumLink": 0, "digest": "sha256:45c42758b028297f26de8ff6726c232a701c1a337149f6e10d08f50fcb7d67ab" }, { "name": "var/lib/dpkg/info/libselinux1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-09-24T15:30:16Z", "mode": 33188, "offset": 24203194, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libsemanage-common.conffiles", "type": "reg", "size": 27, "modtime": "2016-12-30T15:42:09Z", "mode": 33188, "offset": 24203372, "NumLink": 0, "digest": "sha256:e0b0a931b5ae99c4bc030b6ecb183385a46fbd5e55e0e10cce9d5ed1eae556e2" }, { "name": "var/lib/dpkg/info/libsemanage-common.list", "type": "reg", "size": 332, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24203517, "NumLink": 0, "digest": "sha256:efcc339a072893927b9f958a2c0bc7a572c06e8ded38a584aeac11042daa35c4" }, { "name": "var/lib/dpkg/info/libsemanage-common.md5sums", "type": "reg", "size": 316, "modtime": "2016-12-30T15:42:09Z", "mode": 33188, "offset": 24203732, "NumLink": 0, "digest": "sha256:f4273b00cf42096e4fae6cc517c36887f62ba0cb157994d6bf834d3fdf8f0d10" }, { "name": "var/lib/dpkg/info/libsemanage1:amd64.list", "type": "reg", "size": 267, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24204007, "NumLink": 0, "digest": "sha256:61cec03dea647551fb6f821e1943cb5e12d98ab7083369b3637e273bc206f142" }, { "name": "var/lib/dpkg/info/libsemanage1:amd64.md5sums", "type": "reg", "size": 302, "modtime": "2016-12-30T15:42:09Z", "mode": 33188, "offset": 24204214, "NumLink": 0, "digest": "sha256:9e3daa074a4802ec23550997202c21727b53421b347d2d1f21594b5fd48062ad" }, { "name": "var/lib/dpkg/info/libsemanage1:amd64.shlibs", "type": "reg", "size": 27, "modtime": "2016-12-30T15:42:09Z", "mode": 33188, "offset": 24204494, "NumLink": 0, "digest": "sha256:efe84e47b7324e371a1b1263461f16814e0c9e6946e1351c507d025d34acf475" }, { "name": "var/lib/dpkg/info/libsemanage1:amd64.symbols", "type": "reg", "size": 14021, "modtime": "2016-12-30T15:42:09Z", "mode": 33188, "offset": 24204634, "NumLink": 0, "digest": "sha256:b3961b9b87663a5ec73130821a6f55c1eb9f8741c809805dc893d6363253bd58" }, { "name": "var/lib/dpkg/info/libsemanage1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2016-12-30T15:42:09Z", "mode": 33188, "offset": 24206155, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libsepol1:amd64.list", "type": "reg", "size": 240, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24206328, "NumLink": 0, "digest": "sha256:520817a40e203c8c1229c95fd28404339755cf77be8104fa74c10ce6cb3f17c5" }, { "name": "var/lib/dpkg/info/libsepol1:amd64.md5sums", "type": "reg", "size": 286, "modtime": "2016-12-03T23:19:56Z", "mode": 33188, "offset": 24206535, "NumLink": 0, "digest": "sha256:1ac559eb4577215f3e7a264c2f76c440dcc8b5db0fcd4ebd230febe0b8d0c586" }, { "name": "var/lib/dpkg/info/libsepol1:amd64.shlibs", "type": "reg", "size": 21, "modtime": "2016-12-03T23:19:56Z", "mode": 33188, "offset": 24206814, "NumLink": 0, "digest": "sha256:cc698287eb9ae72e133e0c0626577b90bea3ce48a97d3e66f5b64930faed553f" }, { "name": "var/lib/dpkg/info/libsepol1:amd64.symbols", "type": "reg", "size": 8778, "modtime": "2016-12-03T23:19:56Z", "mode": 33188, "offset": 24206951, "NumLink": 0, "digest": "sha256:36f5937b5da6e3caa3656b4b21ef446363313fa285587827f20855714ab3f1cd" }, { "name": "var/lib/dpkg/info/libsepol1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2016-12-03T23:19:56Z", "mode": 33188, "offset": 24208263, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libsmartcols1:amd64.list", "type": "reg", "size": 304, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24208440, "NumLink": 0, "digest": "sha256:0cd160716b9177e16605a23da8290f36f84c720bab0d86f9f927af83e795ef2a" }, { "name": "var/lib/dpkg/info/libsmartcols1:amd64.md5sums", "type": "reg", "size": 306, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24208654, "NumLink": 0, "digest": "sha256:24eaa7f521a0bb356fab52ee49aa1c449d51246e7a2f28c24e170af01144db6f" }, { "name": "var/lib/dpkg/info/libsmartcols1:amd64.shlibs", "type": "reg", "size": 91, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24208939, "NumLink": 0, "digest": "sha256:ec414a341698598b15f989a8b16843af57299e1cb21fda64bbf5f35c569202a8" }, { "name": "var/lib/dpkg/info/libsmartcols1:amd64.symbols", "type": "reg", "size": 6360, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24209104, "NumLink": 0, "digest": "sha256:722622113db03ecb577f0d6b5a5157f2b1c4f5d774da1e3d1134a1f18e48b368" }, { "name": "var/lib/dpkg/info/libsmartcols1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24210116, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libss2:amd64.list", "type": "reg", "size": 225, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24210288, "NumLink": 0, "digest": "sha256:bd2cbff7ebeb04d501ae90b49ff4df1c1aa732ef53f42440a141901bf2678292" }, { "name": "var/lib/dpkg/info/libss2:amd64.md5sums", "type": "reg", "size": 208, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24210495, "NumLink": 0, "digest": "sha256:a8d87407d1ae7edf18cdc4ffe8d4c4639585f560af6482e1c02ed4dc99e61fbf" }, { "name": "var/lib/dpkg/info/libss2:amd64.shlibs", "type": "reg", "size": 44, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24210751, "NumLink": 0, "digest": "sha256:fe74b5099d94fe674169a287bcaf1faf7b1c47bd4e0942912045bbf2f07f7d7e" }, { "name": "var/lib/dpkg/info/libss2:amd64.symbols", "type": "reg", "size": 948, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24210903, "NumLink": 0, "digest": "sha256:95b3f9a1df92569d95521970b6cb9bc2bdce224c6e110d4f29257438e83cc952" }, { "name": "var/lib/dpkg/info/libss2:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-02-01T00:54:55Z", "mode": 33188, "offset": 24211308, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libstdc++6:amd64.list", "type": "reg", "size": 716, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24211483, "NumLink": 0, "digest": "sha256:0e69f4b8a0543c85ca3630f04e065aacd94d2e685c8e087fae406f05292fe565" }, { "name": "var/lib/dpkg/info/libstdc++6:amd64.md5sums", "type": "reg", "size": 514, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 24211754, "NumLink": 0, "digest": "sha256:a2507120023b89d1313adc62772d3c33383b0fe687522d701acf92a84aae9352" }, { "name": "var/lib/dpkg/info/libstdc++6:amd64.postinst", "type": "reg", "size": 523, "modtime": "2018-02-14T16:53:20Z", "mode": 33261, "offset": 24212112, "NumLink": 0, "digest": "sha256:d58ab32524b4b72f16d6d6a55c792491bef47487e605b655cf92bd19d1363002" }, { "name": "var/lib/dpkg/info/libstdc++6:amd64.prerm", "type": "reg", "size": 402, "modtime": "2018-02-14T16:53:20Z", "mode": 33261, "offset": 24212494, "NumLink": 0, "digest": "sha256:be4d3d37ee6abd9f99c8eddd0c20e012aaffbdd984fbbc3ed6322adbd32a93f2" }, { "name": "var/lib/dpkg/info/libstdc++6:amd64.shlibs", "type": "reg", "size": 23, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 24212857, "NumLink": 0, "digest": "sha256:610aef7f93b6381fbcd118f65502ff420c29f00846ea92e308f1a66b1e34a98d" }, { "name": "var/lib/dpkg/info/libstdc++6:amd64.symbols", "type": "reg", "size": 369490, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 24212995, "NumLink": 0, "digest": "sha256:7baf601dddcf028a6542863262791417cf2ba4b2646f823022988ffc65146f0e" }, { "name": "var/lib/dpkg/info/libstdc++6:amd64.triggers", "type": "reg", "size": 60, "modtime": "2018-02-14T16:53:20Z", "mode": 33188, "offset": 24241707, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libsystemd0:amd64.list", "type": "reg", "size": 253, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24241880, "NumLink": 0, "digest": "sha256:cc07699f8e6948f95a506e8bd0eeee0a7a2a4dc0934110a0b2f7ce8dc22c0914" }, { "name": "var/lib/dpkg/info/libsystemd0:amd64.md5sums", "type": "reg", "size": 226, "modtime": "2018-06-13T20:20:36Z", "mode": 33188, "offset": 24242091, "NumLink": 0, "digest": "sha256:fbbd82eb187521829fac79a610e0821ebb14a26e775b70fbe170c03126b0a35b" }, { "name": "var/lib/dpkg/info/libsystemd0:amd64.shlibs", "type": "reg", "size": 25, "modtime": "2018-06-13T20:20:36Z", "mode": 33188, "offset": 24242353, "NumLink": 0, "digest": "sha256:7305604403b49cd3046a4557ea2e0fd922a284501901c382934a6930c6d34175" }, { "name": "var/lib/dpkg/info/libsystemd0:amd64.symbols", "type": "reg", "size": 19018, "modtime": "2018-06-13T20:20:36Z", "mode": 33188, "offset": 24242492, "NumLink": 0, "digest": "sha256:49364dbae4b83985980134598def25260a777915a93f1843eefe640689c4eeae" }, { "name": "var/lib/dpkg/info/libsystemd0:amd64.triggers", "type": "reg", "size": 60, "modtime": "2018-06-13T20:20:36Z", "mode": 33188, "offset": 24245204, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libtinfo5:amd64.list", "type": "reg", "size": 457, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24245376, "NumLink": 0, "digest": "sha256:a0f01eff00a4161b5ad6557223b01fd261da27a523a70a13189a72a308c2d1b1" }, { "name": "var/lib/dpkg/info/libtinfo5:amd64.md5sums", "type": "reg", "size": 493, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 24245618, "NumLink": 0, "digest": "sha256:4d3d4430b4f7545a3adc282e107efa016a1aa9a9959b424e00e2e19706918945" }, { "name": "var/lib/dpkg/info/libtinfo5:amd64.shlibs", "type": "reg", "size": 93, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 24245979, "NumLink": 0, "digest": "sha256:1d1e509ac4df064ec070dae7db743cbbdf4f0e89293c9e36dad136b01c7acae8" }, { "name": "var/lib/dpkg/info/libtinfo5:amd64.symbols", "type": "reg", "size": 10583, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 24246139, "NumLink": 0, "digest": "sha256:31a47ec102f3e749acb433cc824795306a932dfdddc8b07df81260f82be0ad3c" }, { "name": "var/lib/dpkg/info/libtinfo5:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 24247745, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libudev1:amd64.list", "type": "reg", "size": 237, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24247918, "NumLink": 0, "digest": "sha256:6304d6cc70c1fbac022db9e86253dccac0d732dc65dba5d9a3d5180bbcc768f0" }, { "name": "var/lib/dpkg/info/libudev1:amd64.md5sums", "type": "reg", "size": 216, "modtime": "2018-06-13T20:20:36Z", "mode": 33188, "offset": 24248128, "NumLink": 0, "digest": "sha256:808b5d81ac9664efe9106b1a0fe73fdb3cfe5b93abb0ff2b8c552d41e40fe160" }, { "name": "var/lib/dpkg/info/libudev1:amd64.shlibs", "type": "reg", "size": 49, "modtime": "2018-06-13T20:20:36Z", "mode": 33188, "offset": 24248387, "NumLink": 0, "digest": "sha256:1ec36f721c65c10a314a26f2c2eab2e8646738f213c1ea46b3ab5b7032be656e" }, { "name": "var/lib/dpkg/info/libudev1:amd64.symbols", "type": "reg", "size": 4117, "modtime": "2018-06-13T20:20:36Z", "mode": 33188, "offset": 24248535, "NumLink": 0, "digest": "sha256:58bbd25ce4937cdf92003159e262eb853b16d6e2a0dfd203f3e2cc780260ec2f" }, { "name": "var/lib/dpkg/info/libudev1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2018-06-13T20:20:36Z", "mode": 33188, "offset": 24249349, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libustr-1.0-1:amd64.list", "type": "reg", "size": 361, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24249526, "NumLink": 0, "digest": "sha256:ce9393596d841f4e0e573108c148bc013c3707c7847bc11236d834e3fcbfda27" }, { "name": "var/lib/dpkg/info/libustr-1.0-1:amd64.md5sums", "type": "reg", "size": 385, "modtime": "2016-11-23T19:59:34Z", "mode": 33188, "offset": 24249753, "NumLink": 0, "digest": "sha256:4dfa449478b952b012c7c93a19af0f27ee539ee745c1d5f6947b01fed7297379" }, { "name": "var/lib/dpkg/info/libustr-1.0-1:amd64.shlibs", "type": "reg", "size": 28, "modtime": "2016-11-23T19:59:34Z", "mode": 33188, "offset": 24250069, "NumLink": 0, "digest": "sha256:1afc929d34afd105bd39adb703aec7c834edac65652ca6921ef065320811a1da" }, { "name": "var/lib/dpkg/info/libustr-1.0-1:amd64.symbols", "type": "reg", "size": 18424, "modtime": "2016-11-23T19:59:34Z", "mode": 33188, "offset": 24250210, "NumLink": 0, "digest": "sha256:9d5b87acbd80cd5b9e2c496f184353ee33a28425121131dd963cf3625874fcde" }, { "name": "var/lib/dpkg/info/libustr-1.0-1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2016-11-23T19:59:34Z", "mode": 33188, "offset": 24252282, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/libuuid1:amd64.list", "type": "reg", "size": 274, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24252455, "NumLink": 0, "digest": "sha256:2409d77e3d353fc085b09905265dbc76ab7ca8455834f058f2f8c883408a4a14" }, { "name": "var/lib/dpkg/info/libuuid1:amd64.md5sums", "type": "reg", "size": 286, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24252664, "NumLink": 0, "digest": "sha256:cc145fbd4b2f26de67cfff818b6f793213812e790154502120071910d35099fd" }, { "name": "var/lib/dpkg/info/libuuid1:amd64.postinst", "type": "reg", "size": 1223, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 24252949, "NumLink": 0, "digest": "sha256:7575000f027ad8adff7f6512d37f7c9fa1ccdf9b7703076fe605a1cf70e84d0e" }, { "name": "var/lib/dpkg/info/libuuid1:amd64.shlibs", "type": "reg", "size": 73, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24253621, "NumLink": 0, "digest": "sha256:fa73b85ed0ceadffbcb5b0449a3c3c506e99fe78a4da2a6e5fec839711ffc06c" }, { "name": "var/lib/dpkg/info/libuuid1:amd64.symbols", "type": "reg", "size": 655, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24253781, "NumLink": 0, "digest": "sha256:ba5466eb5b879be271cc4783c6d5a549e862799db4064cd4e37a841ccee9dad6" }, { "name": "var/lib/dpkg/info/libuuid1:amd64.triggers", "type": "reg", "size": 60, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24254085, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/info/login.conffiles", "type": "reg", "size": 62, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 24254252, "NumLink": 0, "digest": "sha256:3f7efa04144f955d2ff173cfc54734d007eeefb9b474237040f5a3e74d43be91" }, { "name": "var/lib/dpkg/info/login.list", "type": "reg", "size": 8764, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24254402, "NumLink": 0, "digest": "sha256:d3e2e91cc4337468ae7420115b52a0779e752c059b487af8b2d18573b1b3bf34" }, { "name": "var/lib/dpkg/info/login.md5sums", "type": "reg", "size": 10068, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 24255528, "NumLink": 0, "digest": "sha256:74cf33cb4937f5502456d8c4456ed6fc2ed3d432fcc2b7ed6debc819a3da144c" }, { "name": "var/lib/dpkg/info/login.postinst", "type": "reg", "size": 1214, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 24259071, "NumLink": 0, "digest": "sha256:13780f74190f9e9564d2eaf2d4f9d26e09c67b15a61ebae713b070854e263f58" }, { "name": "var/lib/dpkg/info/login.preinst", "type": "reg", "size": 1048, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 24259587, "NumLink": 0, "digest": "sha256:60940bcd58ac8bc2308601c284183358fa5814064ac33e90345f706dc35f473b" }, { "name": "var/lib/dpkg/info/lsb-base.list", "type": "reg", "size": 319, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24260256, "NumLink": 0, "digest": "sha256:cdb270a80c74a84629d08e14fe0e6cefadb23bfe782bcbc828e7c119d5cffc18" }, { "name": "var/lib/dpkg/info/lsb-base.md5sums", "type": "reg", "size": 419, "modtime": "2016-11-25T15:15:24Z", "mode": 33188, "offset": 24260485, "NumLink": 0, "digest": "sha256:e1742e14feb7ee32fe0d7d8b7296b9d68f713dc006ca49aba1a5325598f5ae6b" }, { "name": "var/lib/dpkg/info/mawk.list", "type": "reg", "size": 772, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24260826, "NumLink": 0, "digest": "sha256:362378374a77852a70e0e0131ef2241675623e663817a1167f8db4497ae9e80a" }, { "name": "var/lib/dpkg/info/mawk.md5sums", "type": "reg", "size": 1239, "modtime": "2012-03-23T20:15:00Z", "mode": 33188, "offset": 24261125, "NumLink": 0, "digest": "sha256:66921a131a48fd13c2ea73b30af7873a74b632d845164aefee1f4dae60a0a55e" }, { "name": "var/lib/dpkg/info/mawk.postinst", "type": "reg", "size": 299, "modtime": "2012-03-23T20:15:00Z", "mode": 33261, "offset": 24261785, "NumLink": 0, "digest": "sha256:6374f7996297a6933c9ccae7eecc506a14c85112bf1984c12da1f975dab573b2" }, { "name": "var/lib/dpkg/info/mawk.prerm", "type": "reg", "size": 104, "modtime": "2012-03-23T20:15:00Z", "mode": 33261, "offset": 24262010, "NumLink": 0, "digest": "sha256:7f5bf8abeb16efa0dea7513462bf1a1dbfee6a7945dc39424d87547128d52aca" }, { "name": "var/lib/dpkg/info/mount.list", "type": "reg", "size": 1131, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24262209, "NumLink": 0, "digest": "sha256:0e92f2cd59071401cf442f4425247ec2a370687d275b7a708be3e868fab9cad5" }, { "name": "var/lib/dpkg/info/mount.md5sums", "type": "reg", "size": 1691, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24262559, "NumLink": 0, "digest": "sha256:891211cc70fcbc9a6acfbe22962959861d83f5d7b75934075a3c3b3c09b7297e" }, { "name": "var/lib/dpkg/info/multiarch-support.list", "type": "reg", "size": 209, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24263409, "NumLink": 0, "digest": "sha256:a07b2062b40da61f3acde302fe39f3702ce54c8cabd2052a550065579d897ea0" }, { "name": "var/lib/dpkg/info/multiarch-support.md5sums", "type": "reg", "size": 241, "modtime": "2018-01-14T10:39:44Z", "mode": 33188, "offset": 24263593, "NumLink": 0, "digest": "sha256:215fc7a9a5de62426e894e146f56220eeed171590d1b01f97bf9535d224bc521" }, { "name": "var/lib/dpkg/info/ncurses-base.conffiles", "type": "reg", "size": 21, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 24263839, "NumLink": 0, "digest": "sha256:b97a47660009db296563cccb2fdce8826e134e3b1bf90248d9c7cf825f06e50a" }, { "name": "var/lib/dpkg/info/ncurses-base.list", "type": "reg", "size": 1710, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24263977, "NumLink": 0, "digest": "sha256:f6c127275c38e828d43d2b3d539e01d38521f5f88b8a4619180d826fda4d9121" }, { "name": "var/lib/dpkg/info/ncurses-base.md5sums", "type": "reg", "size": 2733, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 24264443, "NumLink": 0, "digest": "sha256:0f31ffcd76b076fab4bff5ef9f7a9b8ff672fcdc07b68c5f5760fdaccc456006" }, { "name": "var/lib/dpkg/info/ncurses-bin.list", "type": "reg", "size": 829, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24265733, "NumLink": 0, "digest": "sha256:eba367c1ae9cf3bb8c3a404926611d885a84edef9dce4a7b03f87b7eb6ff3a4e" }, { "name": "var/lib/dpkg/info/ncurses-bin.md5sums", "type": "reg", "size": 1326, "modtime": "2017-12-28T09:47:33Z", "mode": 33188, "offset": 24266036, "NumLink": 0, "digest": "sha256:f75af139f1b948c4d15cc7d94672d15900cef875cbc38b2a05944f8c3800f755" }, { "name": "var/lib/dpkg/info/passwd.conffiles", "type": "reg", "size": 134, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 24266742, "NumLink": 0, "digest": "sha256:05cfff1ddfa6cf7fc524250fe96fba6e443e070b15a4014b74c7a4a5d07a12a2" }, { "name": "var/lib/dpkg/info/passwd.list", "type": "reg", "size": 12326, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24266917, "NumLink": 0, "digest": "sha256:3054328771c1a422e3af1132091b55842b27ef0c50de8d95faad643a4a12e895" }, { "name": "var/lib/dpkg/info/passwd.md5sums", "type": "reg", "size": 20584, "modtime": "2017-05-17T11:59:59Z", "mode": 33188, "offset": 24268517, "NumLink": 0, "digest": "sha256:753f53b1dfa3d2dca894c5f6f1a6de36ec7730e48a8fa8cc66c920c99cd38967" }, { "name": "var/lib/dpkg/info/passwd.postinst", "type": "reg", "size": 1574, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 24275157, "NumLink": 0, "digest": "sha256:59054ead4042a38538dde7f4921de2afc56f2c694cf0ed439b3a872c9185c325" }, { "name": "var/lib/dpkg/info/passwd.preinst", "type": "reg", "size": 1044, "modtime": "2017-05-17T11:59:59Z", "mode": 33261, "offset": 24276104, "NumLink": 0, "digest": "sha256:cf6e8844db16f76a96c215d16d674c35d3ff7128fef855c6c690f04f3aa38a64" }, { "name": "var/lib/dpkg/info/perl-base.list", "type": "reg", "size": 35267, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24276772, "NumLink": 0, "digest": "sha256:f5958bd11445205585820d8e92386d6d3388798f23db3dd33f3da11014d2d7fc" }, { "name": "var/lib/dpkg/info/perl-base.md5sums", "type": "reg", "size": 47930, "modtime": "2018-06-10T17:37:28Z", "mode": 33188, "offset": 24279426, "NumLink": 0, "digest": "sha256:ddbed287c72567e570a07ccda9e4caba252e0276241ce0a819d0fc1d623b3395" }, { "name": "var/lib/dpkg/info/sed.list", "type": "reg", "size": 4224, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24292597, "NumLink": 0, "digest": "sha256:5ade75cbe445776676e0d7b189262df16f41b85cc3277075a969540b1d30d2f0" }, { "name": "var/lib/dpkg/info/sed.md5sums", "type": "reg", "size": 3659, "modtime": "2017-02-04T15:16:08Z", "mode": 33188, "offset": 24293194, "NumLink": 0, "digest": "sha256:fe65ce9bfe5ece14806214a7744ef962f38cc54c18da0342a47caf2a58bdbdf8" }, { "name": "var/lib/dpkg/info/sensible-utils.list", "type": "reg", "size": 1573, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24294631, "NumLink": 0, "digest": "sha256:2188612130b563d8c56994d94dee0071b9ce86fa383cba21b0cf281f1d77b031" }, { "name": "var/lib/dpkg/info/sensible-utils.md5sums", "type": "reg", "size": 1058, "modtime": "2017-12-20T13:39:04Z", "mode": 33188, "offset": 24294982, "NumLink": 0, "digest": "sha256:b5edfd558e93ead2a8dce4cbf7977b3a6a252f755293ba1609f71b1768abc302" }, { "name": "var/lib/dpkg/info/sensible-utils.postinst", "type": "reg", "size": 283, "modtime": "2017-12-20T13:39:04Z", "mode": 33261, "offset": 24295533, "NumLink": 0, "digest": "sha256:f679fc646210850d00acf80323dd891df6c1e5dbc73741a5078c1322f609df11" }, { "name": "var/lib/dpkg/info/sensible-utils.postrm", "type": "reg", "size": 313, "modtime": "2017-12-20T13:39:04Z", "mode": 33261, "offset": 24295822, "NumLink": 0, "digest": "sha256:338cfffb71842952258014189d1fad44046418b6fb2d0799cab294bb1619d223" }, { "name": "var/lib/dpkg/info/sysvinit-utils.list", "type": "reg", "size": 552, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24296120, "NumLink": 0, "digest": "sha256:201c4dc0cc171838e01e801bfdf022ac760fef040ffe2a8997d66033430f41ca" }, { "name": "var/lib/dpkg/info/sysvinit-utils.md5sums", "type": "reg", "size": 792, "modtime": "2017-02-12T21:55:39Z", "mode": 33188, "offset": 24296402, "NumLink": 0, "digest": "sha256:7371e60db15baaa34dbc98c231754b058da015e9791e89cf71ceae366b30bcf9" }, { "name": "var/lib/dpkg/info/tar.conffiles", "type": "reg", "size": 9, "modtime": "2016-10-30T06:35:31Z", "mode": 33188, "offset": 24296908, "NumLink": 0, "digest": "sha256:a1edc2c1b98b0d285ada5f8075b6d1dcfe08be7a7c177462542023d293f667e9" }, { "name": "var/lib/dpkg/info/tar.list", "type": "reg", "size": 4262, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24297029, "NumLink": 0, "digest": "sha256:f1d513203e8b5b15753ef78caf5ca6a0db6268a4d4ba27eb6c0797a59a5f3161" }, { "name": "var/lib/dpkg/info/tar.md5sums", "type": "reg", "size": 3760, "modtime": "2016-10-30T06:35:31Z", "mode": 33188, "offset": 24297652, "NumLink": 0, "digest": "sha256:6d445fa9a5cc958326e9d95ecdcd4b7c0a9f9d411852e9cfe35bde24462da261" }, { "name": "var/lib/dpkg/info/tar.postinst", "type": "reg", "size": 270, "modtime": "2016-10-30T06:35:31Z", "mode": 33261, "offset": 24299129, "NumLink": 0, "digest": "sha256:4eed7466e8f44c6b480002d80becc0d998c462b759c0118e285170a93f4b3dca" }, { "name": "var/lib/dpkg/info/tar.prerm", "type": "reg", "size": 317, "modtime": "2016-10-30T06:35:31Z", "mode": 33261, "offset": 24299393, "NumLink": 0, "digest": "sha256:4d2e0a20637a93acbba993f09ed56659869ed3b5749243c2441f8443fa0bdc83" }, { "name": "var/lib/dpkg/info/tzdata.config", "type": "reg", "size": 10137, "modtime": "2018-05-04T18:22:35Z", "mode": 33261, "offset": 24299704, "NumLink": 0, "digest": "sha256:06b375f4c33ed60b3a5c0509e77d6e1268afcdafee18f7a93ac7cb60ffe1fd67" }, { "name": "var/lib/dpkg/info/tzdata.list", "type": "reg", "size": 73851, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24302050, "NumLink": 0, "digest": "sha256:f493aa8eb818ba2b93305d8bdb78380398a02bed5159e1af89b10b99155f4e52" }, { "name": "var/lib/dpkg/info/tzdata.md5sums", "type": "reg", "size": 55759, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 24311261, "NumLink": 0, "digest": "sha256:6a93492f5bf955082bec9f1b49cf3940c9fcb36291de452c1729614ddab0fd56" }, { "name": "var/lib/dpkg/info/tzdata.postinst", "type": "reg", "size": 1330, "modtime": "2018-05-04T18:22:35Z", "mode": 33261, "offset": 24330605, "NumLink": 0, "digest": "sha256:d0b65a6ef298850b186a12b84cdeff63f79b272a259b2f4495aca6f3e14eed86" }, { "name": "var/lib/dpkg/info/tzdata.postrm", "type": "reg", "size": 298, "modtime": "2018-05-04T18:22:35Z", "mode": 33261, "offset": 24331329, "NumLink": 0, "digest": "sha256:e64bf8cc4b58a0536bb10676fc0b9e59a00b8451b76be07cedb2f7a660e49443" }, { "name": "var/lib/dpkg/info/tzdata.templates", "type": "reg", "size": 267379, "modtime": "2018-05-04T18:22:35Z", "mode": 33188, "offset": 24331619, "NumLink": 0, "digest": "sha256:3bd45d8ada7d2659c953df98d4f8c5ebf0988fe1597675614610c6be9e3bc768" }, { "name": "var/lib/dpkg/info/util-linux.conffiles", "type": "reg", "size": 84, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24387384, "NumLink": 0, "digest": "sha256:ab71f6f05a3f0a7cb78fe1ec8c90af9cd821e9f66bcbde54cd6769696300317f" }, { "name": "var/lib/dpkg/info/util-linux.list", "type": "reg", "size": 10638, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24387550, "NumLink": 0, "digest": "sha256:1151138a9f9dd100ca903a2eedd17d89a8f1dc0cf3e7c1fb28b8efa928b2101d" }, { "name": "var/lib/dpkg/info/util-linux.md5sums", "type": "reg", "size": 19143, "modtime": "2018-03-07T18:29:09Z", "mode": 33188, "offset": 24389331, "NumLink": 0, "digest": "sha256:8e3d967d38b96c3898bab4656a4aa000c44d3b16184d2498b29f92b6aed3310e" }, { "name": "var/lib/dpkg/info/util-linux.postinst", "type": "reg", "size": 1500, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 24396523, "NumLink": 0, "digest": "sha256:f694e5496272871d77a31cbb471c96c8a4de630b62d90b1c1a03cceeda2513a7" }, { "name": "var/lib/dpkg/info/util-linux.postrm", "type": "reg", "size": 148, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 24397317, "NumLink": 0, "digest": "sha256:e6a730615e91fb9c7a3729817fc8208e889cd52aa80d31dbb3adf993711a9a8b" }, { "name": "var/lib/dpkg/info/util-linux.preinst", "type": "reg", "size": 205, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 24397547, "NumLink": 0, "digest": "sha256:5cc1c06e4e2aee2896e0fc0e6aae4a18070677a42fe98cb84e02007e83cbd6f0" }, { "name": "var/lib/dpkg/info/util-linux.prerm", "type": "reg", "size": 192, "modtime": "2018-03-07T18:29:09Z", "mode": 33261, "offset": 24397815, "NumLink": 0, "digest": "sha256:75c29194452a7242c7363da15ce655cca80fdf31d31a1836e820d74e5fc5381d" }, { "name": "var/lib/dpkg/info/zlib1g:amd64.list", "type": "reg", "size": 260, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24398048, "NumLink": 0, "digest": "sha256:e60913bb8b589fb1d44cd9b89f1bb69096dd12c93041242ecc30f1093d2e1266" }, { "name": "var/lib/dpkg/info/zlib1g:amd64.md5sums", "type": "reg", "size": 277, "modtime": "2017-01-29T17:22:23Z", "mode": 33188, "offset": 24398257, "NumLink": 0, "digest": "sha256:b66744b6adc964b7ef438a144ed211fa482a3183352a3aef4036fccf95df05d1" }, { "name": "var/lib/dpkg/info/zlib1g:amd64.shlibs", "type": "reg", "size": 83, "modtime": "2017-01-29T17:22:23Z", "mode": 33188, "offset": 24398539, "NumLink": 0, "digest": "sha256:b83364c157bf331505e018105935763d36db4e070e26d1f7d6c08ea576fc7d5c" }, { "name": "var/lib/dpkg/info/zlib1g:amd64.symbols", "type": "reg", "size": 2752, "modtime": "2017-01-29T17:22:23Z", "mode": 33188, "offset": 24398706, "NumLink": 0, "digest": "sha256:01394311eb033a90295b3de0e879a126e5f0d65250cb06dec4c239e57fbedff0" }, { "name": "var/lib/dpkg/info/zlib1g:amd64.triggers", "type": "reg", "size": 60, "modtime": "2017-01-29T17:22:23Z", "mode": 33188, "offset": 24399426, "NumLink": 0, "digest": "sha256:f2bec0f57ef529571abb4370d4e3cfa911ae3606a0d31559bca5980c0a1de91e" }, { "name": "var/lib/dpkg/lock", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33184, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "var/lib/dpkg/parts/", "type": "dir", "modtime": "2018-06-26T10:28:08Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/dpkg/statoverride", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "var/lib/dpkg/status", "type": "reg", "size": 68838, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24399656, "NumLink": 0, "digest": "sha256:c09e66b2e4369263618d407aaa41a5cd56b41edfc6f9a52036f41d6e20c7e44a" }, { "name": "var/lib/dpkg/status-old", "type": "reg", "size": 68559, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24420214, "NumLink": 0, "digest": "sha256:f9aab52daeabfffab21c128e899a2ad3dfaa28de29eaf97a1d0df2ac7a59c18d" }, { "name": "var/lib/dpkg/triggers/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/dpkg/triggers/Lock", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33152, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "var/lib/dpkg/triggers/Unincorp", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "var/lib/dpkg/triggers/ldconfig", "type": "reg", "size": 9, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24440548, "NumLink": 0, "digest": "sha256:e1919c8b2afb858bd2aadc7ccb27c847b3b687ed9dffe00219d645d0c30b8b83" }, { "name": "var/lib/dpkg/updates/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/misc/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/pam/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/pam/account", "type": "reg", "size": 76, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24440733, "NumLink": 0, "digest": "sha256:9f0f66ec5d201dd496bda06760e5871fa68e349fb9d423eac447d332652f6f13" }, { "name": "var/lib/pam/auth", "type": "reg", "size": 68, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24440906, "NumLink": 0, "digest": "sha256:6f405869d7e61b56e8b4c6eab08c60c538dc24853867655e208b09778d656aab" }, { "name": "var/lib/pam/password", "type": "reg", "size": 69, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24441075, "NumLink": 0, "digest": "sha256:78f7673a76134223418cd0b3479b892bb260a7d6b734bfc9caca62edcfb22d7a" }, { "name": "var/lib/pam/seen", "type": "reg", "size": 5, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24441240, "NumLink": 0, "digest": "sha256:d66f691617a7b447171b7586b8f16741a023a810f1307542c254053318f19ca0" }, { "name": "var/lib/pam/session", "type": "reg", "size": 75, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24441349, "NumLink": 0, "digest": "sha256:4a0e1452e4462ee2c1337989554acb3fe7a2473086870ec5b16e46aceb48e0e1" }, { "name": "var/lib/pam/session-noninteractive", "type": "reg", "size": 75, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24441526, "NumLink": 0, "digest": "sha256:4a0e1452e4462ee2c1337989554acb3fe7a2473086870ec5b16e46aceb48e0e1" }, { "name": "var/lib/systemd/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/systemd/deb-systemd-helper-enabled/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/systemd/deb-systemd-helper-enabled/apt-daily-upgrade.timer.dsh-also", "type": "reg", "size": 64, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24441766, "NumLink": 0, "digest": "sha256:05e0a72e601e00feaeff5d237f892b5f891cbb9c156fc5da667ac56c25f20fdf" }, { "name": "var/lib/systemd/deb-systemd-helper-enabled/apt-daily.timer.dsh-also", "type": "reg", "size": 56, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24441940, "NumLink": 0, "digest": "sha256:71649d5e78c0ba864daf3778e8d90a3707b88c587a4634cba67aa9094def7750" }, { "name": "var/lib/systemd/deb-systemd-helper-enabled/timers.target.wants/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/lib/systemd/deb-systemd-helper-enabled/timers.target.wants/apt-daily-upgrade.timer", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "var/lib/systemd/deb-systemd-helper-enabled/timers.target.wants/apt-daily.timer", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "var/local/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 17917, "gid": 50, "NumLink": 0 }, { "name": "var/lock", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/run/lock", "mode": 41471, "NumLink": 0 }, { "name": "var/log/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/log/apt/", "type": "dir", "modtime": "2017-09-13T16:47:33Z", "mode": 16877, "NumLink": 0 }, { "name": "var/log/btmp", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33200, "gid": 43, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "var/log/faillog", "type": "reg", "size": 3232, "modtime": "2018-10-11T00:00:00Z", "mode": 33188, "offset": 24442276, "NumLink": 0, "digest": "sha256:df66d6e43afb0468eda3149e5eaaffda44271cf157a9d9ea4ff6b6dafccb030c" }, { "name": "var/log/lastlog", "type": "reg", "size": 29492, "modtime": "2018-10-11T00:00:00Z", "mode": 33204, "gid": 43, "offset": 24442396, "NumLink": 0, "digest": "sha256:a04ece22923d2adaafa89580dbe2851cc93eee9f1c8f43264638d002229f2cfe" }, { "name": "var/log/wtmp", "type": "reg", "modtime": "2018-10-11T00:00:00Z", "mode": 33204, "gid": 43, "NumLink": 0, "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, { "name": "var/mail/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 17917, "gid": 8, "NumLink": 0 }, { "name": "var/opt/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/run", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "/run", "mode": 41471, "NumLink": 0 }, { "name": "var/spool/", "type": "dir", "modtime": "2018-10-11T00:00:00Z", "mode": 16877, "NumLink": 0 }, { "name": "var/spool/mail", "type": "symlink", "modtime": "2018-10-11T00:00:00Z", "linkName": "../mail", "mode": 41471, "NumLink": 0 }, { "name": "var/tmp/", "type": "dir", "modtime": "2018-06-26T12:03:08Z", "mode": 17407, "NumLink": 0 } ] }nydus-snapshotter-0.13.4/pkg/stargz/testdata/stargzfooter.bin000066400000000000000000000000571453374237200244540ustar00rootroot00000000000000000000000174f733STARGZnydus-snapshotter-0.13.4/pkg/stargz/testdata/stargztoc.bin000066400000000000000000005147401453374237200237540ustar00rootroot00000000000000 stargz.tocMwǑ' )hݠgt[Yԉ̌&l>BK{omʺnf"33n_UEϟ9ӿ??NOww߼/oy/?w>7oq{7?~|h>#AA?[_A ?>ۻ_yqQO< h/o@oP|+ovL?rc?WuOEjoyØh+zҽަ>F\v*tzD6E|h!-[D:a7ul1[)' 1VdmKɵ(wʣK$^ fnk 3! %)Ĕ^,EʁҮD8QKQ6х{ +uO\ŊUƘR~(g!ţ25Y,hxRӲ%3toC \(xԑAZg(  7-G7M BS gnLjܸ TG'|@ߢU;@SFa"ړc0EL5C ' L5Jr}򧾬TZ#L|ˌ-AZlFF :)m $XwR~Q^aל"S]#PmČ=@&Gk@ Rϑ/WqX@µM=ŢT4e᩸ a@Ha$99|-~'Dae&dBKG-\fb#c j_Io/+.DSœ |[ʷG(49=4i-uo\äz 9@asl=u{_#O{f>doL_~CP_Lo~9AGbv)x2Nj OVTlxڦv5:stC_41Vݤi0{[p0)y,JI#w{mYNtBj#ݒfc `m6esor>c̹ ,5Wgf`t' "l6}{>]t!Nħq{s{p茵8X%(R'eG`.:JxWY᫮ԺcZ ɕC3d )iHte3JoP#x+xeq/7O̴rۗi{\F˵x@*^l8g pQi_rGBtIeu: )6؀^fDO [S ;,Y@ewx"-bk-){.k\ O-xs.A|c}Ȥ]gCØ&<6StFZ'X$js"9P8-bvK*%| ۵IY,[ bC4zwo>1\+zL_{nxjs d[([c>7k|igr[̇7U=e7M%X^v՞ρ 7L3O@E|<S#㤸}:%D%eb2 ط, 1rkY_)|_]}ͺ}|zx[{ߗ3W\A1[ aĔY*rfJ\eS#'D/WX\-XB!enwO*38u KD1Gma=n?] l_|ɝsW&.f$S+57*\m6)Cs{?I'&6JS=Ƶ(0vc6keMY!8T]8xݤD:=I|Z'{V˜c"9D43Uϒ~Bn77 ߁e}xrtL? 5ef/Ү=ʷW9j9%#uD= Z@Ż9P f=majZSA[(j{zCٶA\'):~:Te//D*Z$1FSzvs{*ӧ, 3eþ{xHGd5UWN@ݒ{QY'm#8NWac+v8m6*aS8d=%'/A&Ѩ 0Ϻ?&(g8t54'k-%ʮkL:X (QRYsVKx(k493qU`m'٠OGs0xmsZX7D7m8tI~^^IݟOrݐ|'_'^ӗc_H?ͯꛏ?7^<3/k0E(c$de>?9IB^-b#YfIj&ZY֧~x3.3HsR߯qSx5\9yNI˒c%` kbИ[brS?_mR~tX!8Lg rf*ܺٷ-{DWʟc_t}z|߿ v߼?bCNrkl|}t{ K^޼PEc 99P^cjg91g|w?~y1O\\%GMUCVnEe9RdWrw}wQ엡"t$|w1E=>z㻯j>Vۺ}zߺxFA[I^fI*1My{ }1nWyhco~{~z}k!{9VE!cĽ=w 's H@`J=8}.e.ERƬr{ZZgJ5t#<+Zߜx*_4% 8Z )Cmc촅MsIpإH k追[7}q;u[|,'4cTŽ'o f7nJ5)fl'i,8|{ ǧyBXq #$G]͕kR_i<$ip%43'{ j3[cdk.EjkM>wHC419qI*=z|ܲ$ԿHTp5W"R̞l{=r;lu{t :S`9Jm u@Ø1I4V4+` WcCDiXK/( *hkVڵLCNқ@itגAرHK{>KOV:ϫ<[jF%_Leq32NG'0BEC '6[Y+wlȕV]^EuSr9Hlҹd)>s&iq,MC0V`UpOPDž b|~mpl0Mϥ;<=xB|1_"yXFר= m-܍t`\rd|- tZǛ]nO MOҝGdmRK]'*rF\їMUyM]b03{g7$ۻǯyFƋ]_ B>߂83`֎R6[B& KMӚ60#\W~aWpptDU S+ < >6m.cYl Ql {К{,<xWǼԿBK-3GOku6rL?w8DM+Y =_NL{g E]&[]jN;Z>t_"???+5S٫E]f{,F3{iؒauS%$߻kxiݟwK@!IZR2&Uct,62 s' 9P-9`ny:Bp}iq2uX9Q TH?4Nz*|FI{ Ljn$m✶iLAFX)f qѹ{wռ?-ԛck9 T&wbaRq F䃡czfpfpr+-Dx% [W2wK :Mj@ l2V͸YH~sz\v:^K@O$h99cY;-q[r4Z<Akh\gh}?tǧۻǯw]oT Ւjbm1ٽU&N,$Qm S/iZ`2vtx<޿5?0 z*D; :\XdkjXKe-{"fb"ИXl"(ivLKj{ͿP:P)3 Ɛd8ʶLukNkP!ڵ-/={( /xV’<9p.Dji韡,2I`g@]Gy3y{7>K"HȡI.ƣdn;6K n`I5A,DSZOH'~4ǒ- Ƙ FWam=Bعp~Xg6?=o4Btc߬ޗ W  5 \NSFx+N1ʙpUbYꩿDe{j?O6as5:(hʠ5*蹣Cjn\7q)|P/caesKi"M CGGA9i,[^8ω5Sn3@fޡ>=hF-[X;< Yb3뜗MXn|<^;-huy`tzv]($\Ӈ˅oq='ԎW@{;!4IьeUx4?fCg B㏙/:QƊ$wz }^"b?L@y]T^>lT޼yUߎ_6p脨y2ߡy OQũgD:-{KUDG va1O-rUga R71Z%ǞIcO^PSz?S.9z8qӘwQv8iYߋ{"Sb]ic`LQ.Ay+RO*ujCF @y԰akOݽúG)sԺLw75瑱HpIeړ3M-;(fhyfV#w@|z2 tFΛ{h<0|Jlε9 d :³H\'+%H$aGW/$TR{Hil۹2)d5<,p~ɤ5<۷.w[0[/DS uÿ;ʗBX%՜x+ZOwv. ֵR& ꍴZCc_WCОT T+b9zKQITOhȹ|DADAׄ!g!4 (u2q꭬ax~$lןWuW33N.ԉt4CAp|,؞6x8PP4Q5$ FL|8@DCsuP7Oe@cy4ydXNqllKqB_"]!H/ϐkH?="[˝YtFީe 4Wy;o~^wrnܑy|tY Oq;Eg: )J5EȎOjc}sYɮ@Ԯ>]X(wٞH d 2jZ4E ̀Wq2Lf-7d୫ZXl{pn>a α,Z g<>7?7nN^F5(2) R Nk㒄,_eW&4zi̳aO?A8V&ϫׯz<û~zc==n>>Oﲓxɜ9pH:Ϸ璫R8Y 8B s:V+TXJĊ+g{4|B]I\?z{w5>qnfjHU}yIbs%YSsʌ>Xڛ? ?ぞYfY`MݓJ"$-{/E#l(>ǯuO+?n>=xA,>k19FgA*\5$:g"n{BLkp*Z[!yd݌E<d y+X0qeD->BT+i;&[Y <'*^^5_%<<kq쌖bciSP\8i {6hol^^(CtY>jDA=&],Vc)[N cçq[Փ~b銠c ^n=|{#þvED#R[+՛0G)9%,́[_JS\p_+~% _ B0`/̆Jؑ{FT㮝9sLV/K4op3߿&9%_}>-m=^.\ז/9,L 1G0# N v5c5 tt,M{26"XדӒ#b C2s"CM0r.Zj`߼cP?W%`Ha+k6 `TTpB/f 24Z0d~=B\]rJb;țs)dcO>YqG1\߮O.Oo+$ET| ݌f%#W O!l^x~@$u"&HPkհD%\[#zL#68m&rU8Ib+Kx$U&˘/g30϶\+>|m.|xn{ h+\SZNEQVSE-woCp3߯ӧh-Eo,-\K֦5NH0*0*r,jF ^rp^^ ;ͪ lưZL`=RJ琘ӑP"W e>"'3i.N|R2<@f}E[B"r;p8x*#(8TA#[UcvN];I&|_[V<[c^ HhV=WLR-0TC!ՠ'g,Tf÷r45xЁ >9'n"3)@I5YT8~f!}  Ǜzvn3P(l[yZ[JxW !_OwMG^E㯿(ME):O =Ir.^knj.H^Cg=~m|>+^U?|uU]>VrԘ |ͽ:FFv߻(7@Ԏy2GFoP'/)mi|; X<'.ڌX\Ah T"8nT$&]񡷅fsa˒jڀstMJ^Kjdѫ 95ǝ3%{RC6`Ŷܞkjnlu R15_R%Wt5N,5a`._ye{P&]=Z5U8Γ.9' afF(s'Fns T]F,xADqtY}\=>p-Ye܀S j95p|mX1U޲mlE<XzO vrYhcZd^N L 58fÀ :68] RA0]2\mBg=HX-0ԚM %*@bq?K wd 1 J^1GO{s\ ]Q{̓ŋ{ke,m" #;Lc<|U*Gzv3T7n[q^BNvo3Zz:7`8 {kp8dr't)ؐeKF9>,bnM, e?WjcNfDi D{!h9 &ϬZAV6Es^x:,z|ϴD'4{7O700Č7NSK?|z__m!ϝ?:ZN7x2C=v% dRX0 dlD6us7Rww_~ސy<`0d wo9ߊ,rXpc;'EN SYϊED1W*L[۾y"?nztQ+п2o}_g5;?uoK=n.6aJԐ}~Pt[d}Egۀ#_dƾ<[L@p^O/SUt#/+/Kg Hpbf_wGm8Ƿ[&h֠sJ zfG=jyLn/e}=Gwp}f>s+%J^&q9+q ) ;D&شXsvTMiץ|{\5]Oq2ru5ഺfb,mS@DXSa2E Ay'p_?>_?wv;gE%zEJ k,lVoaHZs Inr{u<^ѧWHߣ}DYogeKϓ*Sa9, (BęwZ+^l۟n˳^ٿ1>{f՜LIд8T+pUJq 3k!N/RꄕӊLz;' i+ٿ';0N|qv4=L᭼e,nFQIc+a=9Hj҅sB"-SG=HsثZkqԶ-ܽi6RcnKA9]1Wg Y{̧b|\B+ϓ(l[BsnˉQ4ܚ¢Li:V@h+R5Q7o> b}d/A %co5,l ͵=^OWf̉ogE׾4z41*U_t7lVIj^Nqpl5Dz2j%: vDlΰ8x˗ǣϔԮJ=4T]Xm c_'(̓];tP: Y^",L7}r \iK)v `2 ݣ0{hP3 4gAkU]ty+2; NW;eiBdr-!{ ![ +I{&˰Qw.B׊p_axYLH὘{>w+lW)/Wm[zQq 5dыpoD܋5K.^7?Sh'/35bs!<,ZeD+loJd9b&0CBմA>҇C_cR}TH`dVcI7EXY6grKko?)l!ˮ}@GxIz/ _x _4H-U)i. UCAXFSeFM!%ck^S0ti s_Ek2_TS *bDH=ymhZNPaScx4}? ({䏈%-]sE>w+z._"UHFaؓJ!h{1*zutؽckEDLqdUjS\Bt7 -$4@] rI=Z3/>SwׇC* ә+$a?mZi#Μ'N٢5V[^,>}NVgU/[Ȑv%Z p q<"kt^(f {xFޡlhsSJ&'o2(m>y2:%x־8> ws_?6VV FP5jKBs{dO:v_ފ;Y7<ޫU>\@39ìŢ%j+-F+6$Q`'o'ۯyxF95AFĂVrHO_d6|B!/o} W @=G@/N.=۞;ҼiyZ%aetC:e-^>xk,2u.]~ޏ]{D_e]obo,STgdfU Kve7PQf}G<m, /?8\I#x1 #S1YI˜[pb KA;yܯxat Kg8^Gf\#II rQK;r^.^]y2.< 5zAjy 6;l}B( #u#;2pU1'F6Iqw ?x}dv1|D;tڈ7.ݾPY16cAqFv-Aˆl`˥|=*> }N/E{* p[ [66$_9CDA4Jy)(c>SAʿ>E)/~nik{ lN\>,hZ)mGXZEiҺYz2q0ߎ~9g*j1p<>t;'~j5e"9 -l(ֈe4czh'H%^ߡ O_ Z74\-}ԡ`^Dj:(o 1'OtThbIWw~k};;~_'b.LI=w0cY4OIgΞ5$R#r$ p[no Z >`&ԑ䶫pAUBkk[]IkDPI*brmb3F$aiXv6_Ez=dȎ fRT2+w鯋aO1Zl \!ҥd/v4v|$ le vTiT(HbɪƂ %$-c rCzCVssT'_,d S˽zZsm3Uc楕o@8Vˢ<{UrWǫtX 9 L@ ]ZBNcԙ.6a%iżH*n>G=O^;ҭ (I Kfҥ3Cَ#qO)r C]LYF bpMA^\b5h~S?G?yPfQ!c\$j̱=j-is{<]1,aoNIr]Uzx*N `|v|?CƝXb6ņh2#l.=܎Y9{?m΁oI,=W줚dFeo!ʹ|1|[qayWd9HBc3kt]5p[2Ttۣ^_/\t9Ǜs02K=bQQ̅úFaFvD{|!WҮY~X{Dn2kp 0CX-O ?9^sYtңtȹ}+*V:1d7^oO_t|k$ٙ mF%-6sPMd`J:wLTA ȩ}MXI2_#)`6 J9D!<>ChZ#ai&bzlԧys/JB\={:)rT68yR{ T)Xm<%q4Š9xL۸!IV9s-خ,+jDJ=2i~2U?9O6t,\SWYPX'+a"d :!-yy<^aޚzPh >׀UңڼUNo]>||u3 }_ݗWς} A]g^wsӗ}ї4?ܬ5m*Z$gԐLJ3%0o}9/?,6?^0dXhV35j켍}NZz)}9<3pE8/Nj f87-k>SQ@: OxԋCuP~-=_C9n{ob޴|O4$M U&iSɢOQBm33ܜ=TN"sa) h.9p PplQ+AtW|~ ŷOp|FE0Uscm*[cY{:5Y_O˫ϮgqǛ(<IorV 26MVEO׉|=jxI5{g9dn"ukx@*q|=GVqX|`GyrTmH#S`g>p-‰2k<:嚂Q'qCn; $knU&κ,q=\ďo^Va{s k {[ 4 oGT>~O ׁ^Q`^GNs9VmNb1x1q FRN9}ƘCbڵJ"/E 6M+ >d^׉n8+Uo>AjֈfF"3}ҭ%ԞXqӔVBMDS$jcbJa,3 (xYqkNFF!Y%-d۶ ;hDvU젝^xHǧgbH.`R8rBe4CyŨr>}S.hQؔYYמ/:qn>|hz/[ oF2` +EJ6˭SiX#NSV%[PG=^Y{=m:,49BVOLwTY ,: ; O^'qkҗH~Tv{,vD'^BĠ4E(4^$ gͧz_Hax|(Z{)GUc Ū*=N*C׈.GbKrǿysDgn8H/Z=YBًc[rOeS Q`s5U| 5O|5y}.M*=C; Dhvh:t4=[cM{eI =g5N㸽?{KN{ly!M&TTQ5qLMl#p(Sb}烞v5v|+ vOӜ۷)Ps\$=''t$ƙ?ގ[=O>P.=ƚur6lٞZ-:DiLD =HWڎ'oHkVƂDAэ9x\l+ig 0^{^\yit%PԎO\(\s,''w30zPZ֦""y=r{Џ_e>"]J XkhOAgX6`U<(|;-zӑh7ҋ.}KMF8<&\:%\jK$t=-Q ݯS$dWKn eWHgɁ{mxFs5]쒎v m瞮&)`LZ.c25jP;rpxIX 2%E"-|H%yX\Pl5E,GK"Q?Xx _X{A3V`'D˽+sZ8ҕ;M!Rov7|F8ϢFC ˣMtYᚬ=sӇFoU#WSnL-Z sM'0aDS \% ܲB`Vr W5@]ѯzvof`F#]HSYt-e+GN {">0᜴`@Mte7ZUVkgX+V4>yL0j NA[J]v9r = ŵ^/;۷ Jx)lp"biA,EbzDFSZ.pܮV{nXt2ZԀflNJ`jsPy-?P%0HjaTO(C%~R{ƲfWXKlzA@J/Eʱ{9]Gm`cI{!j,DZv4/}0'Nט!dZ9:k!xfɵU8?<<}F|0H-`/t84bRMGYc3d"`R'oEn ۅ4>{]-~fmNR꜆"*U Ms=?1xo7_HimoqԭgopJcfvLSFd[ 'O[%Uy?ӁdEDǗg PMaӀc) Ig[-emɘm~9qkŒO_ _  +rrH q@&w@W &Oʢtyɚcg/u"FX˸<_'~=iԠ0ھ2*s^]5:6[\kh"řPrhŏU1sZ ړG 1c<%|kbP~f6ajW{ئ`Q;Yz"lD//, +zK~ig`=|"0bN) Xi%EHO S(}%~'5R :0Z'3eĶZؚqRϽ>tQVL??Ǜ៾b~複g\Ob~dLi;20N6Z$91|Rd>9&sG6b]N?'_@ aY WK e1d.:e[b7sW]2h39 9=i$߆Ct7mN)pΗy  O o1TP"+ Z&HUDy~_kEG>8>B,"2gϮ`轉7L"zV󾻨ZeMq\~|ϙbVED aĒ):+g`KZ"T!\`<xe+HKqK rSXd2A],)8MyyRř$cx'i’aô)dX6,`Tᓽ93YAP4_3&z=eq|猅 uEc#[i$W0r:MHNⴽgW<ߦ (M"U5 } l (>σǒ#AH.!|E %p|&>yjRI q"t(@_Cdg8N sqLjwƥ`fOW?YpdLLj_@[f3ӧ?KMPu:ܬ ZhV2uQpX$VI@`9ޜ' i7ǯm:p8-UY#f59+G\i~|,ܰlp֔% s)T佭8rub}/i}8ֲE z*څG@4?_E\;hMMy2b2Y*Cl꟱Ogo Wp*Wzrmn&^n'sT(堘ڊ;|y("V ͗k{ѯxpgBkw- H\MDZSA-8a|y~8_Ԉ;s 4Lg[$Cl\|t#$ʅL!6:ZƧ= ^0bN/Ȍ֮]Va!&/?p@ ەz?<5Isul 4`EI9+ǖ.m[ ?>oJ^ Ac6=e+ 0/鱙62't5^nWn~WCM-֜zf0劽W?hY E:§qo< `õQ< Fhdȕl#O=(\@ ]p{VPA9~_=^a&a6B]=ʒdm)l`-a^Bq`XI* I"lZ;'9? 'F-iDd):^C#vֱ$+(%'qi(qU|=eDL sMmB;Pf2td#Lw3b9T?M{ ohb.B ;]WP{ƀL^Q"`9RכWob ^k 3Q8b+F.&紆!.LƬ[?R$$~ցØ:a3\Wݍ;|;2D`vbX&{,ӡXc R}JbR.Cz囷/CX]7UdASRav"A47e9Gio̱8_!{hϸy}rr,A^D9z̾brpy2GӖ/*v7im;;Jf<88EjP]ܺ|bUUf ׹o<[cw =]<>+?tz@26;ꑈŻ]H?_mԲ8O\v*X8$iDcco>d B@]Jn]ʚ]vxC^ćft|ʑRCրW %gG"-&,nEC^n;;٨T`-wد~0owӅ Yaګwڊlvmع r' lʻj߭һ'_%7Ώ [BFqP[?|"i dݛ2.Ywo{t8hϙP%H*8gS@6"[N]AǬ ,/Ǘ7gY0Q ݼJrC=ЦWNKޅ9O` !z$j۳jsY|PieIZ(۲8)Owdx~ ~SQw_;|f'h0;x&07EXFɷ̼P^\p_"],)-+;c .eP4 q6ne폯>h%"'`I6묽mqe%m9b*r-?zr q8j10 Y ''P;j{o-ϣFGNבgVf6ST8zNssmУ\ fC/L0= ~jmjnH+ % ޺@dZ&jf{˻IG$$Ph"[5>:])69 &W;*[SyU]w<骒* ŠٽoG3tX<]Sl,T[ag컛ue>DC(38D";v%+?e ]:szd}0׎w"^՛+zZ1eWmiH::[ o% #t$:2=i1+]oL9y:LԮGd+N/ۼw6ZGee^T>k߰t=xAt|XYj%%eCp{k| ouRgfg ),m7 (>a/΢gHx=ȩF?_/D{Qf`Urс|ppȏgp/9+KBJ5.pZَjvRYm/`3#yBG]n] 4xF7H(0-,k}L^豋P }D7r\H#uu>AF̩QsDh37Phv.N\z{,P0 #ݻ1o1ɹy}HZ9jy=K?'sJ$^1*fz@F10j蜩uLc!?<^&?\|e}Giqxa m=k-%+PV.Y}/\I|i[P-כɖD%o"|N0Zpۑ[ >3N݀+S?DqUS Buhf(طG껺BhH'u ݧ6,'iLk7yY5&@,{=o([H ~=.›vm<4%o?7vءS7;] s/EL@nF oZFI` B#e2YL +}s m^;c-A޼X'?@֏ωD\SV5?[}HE C`!scYgR]Wx$Pn 9]`g{AjEyBrİvS=׾ UIF9σ]'(dJ=42!:jX|zN'-aA;1χ  wP`Y%A޶yzv`e TzGfIS$;S|W4I Xr}s sTU3b v[N;;Q2[7-Z3۷Ps&2nNur!?Bg/فAd`rzXvi5ɽwlĮ6"HSR{gNse8@cu>e`3<;::ִ 9ڻOg]Lһ@|e+m9.S1g'!geMۊ:<ˌgcggpb[HfX@t xy\NxuB]b^x#z%Ʒ9^EG[znǃAv7Uo(|r>ϐ[C֊Ju^Mm9P$koV!Rx9#OÉ!Oʐ $Wl>`Jvg |y+\QYе v: 5׮`uiҜ͒>wg߾+ʖmr5M)6Y}"‰IDq!,7}t1#gNCpm^|, M؀7F.Lu.%wھodbH >gM+9B6m9tkeu.n m۷Ag6=qL'efjhlsUuJP~~bt+?Dc_OJCFZQ.HoG)2d o0IA;+Ο1_f)~q}9bً7MfN-8鰻WʴFHBB}!7͓,v< q"T\ap*0߼欻rĤ|"3*^:`GQVt`ߞMmb<4)k ./HS>nBB͋Oa]Ģc&Ti)^qb'ZX@n\9^Rl7ko^"$.]}ݢ՟l=쪗pn>`]#RIA'Xm4۹o_?3V1K&\ qØBf34mQya 4\_cs ՇpFImְIC&xoW(gefa-/쒧HyJuʍ-;6/<|Sϛ-_3o3wacG߽XϿۏO^]K2gC~5#"ן؅QrjdUߝLY)KbH_͙E_}vO^|ӌ~Jwam(ghW&;Bs#!o_|<+ֿxE=/~ۗGz?sC$O98y9nq/Ymn=[a;dEZ#ދ#~_/HV(DǢ 8tV>dnB`^P u72I4xjo߲wj-9A-aM(] Nyu[iL .u$ym̖E O"&<o^}s6F OB Z¤hs5q0g/v m8^o?nF'S^ 쉙1-vOi3˛97>P-\1߱_~}xߕ~ڞ ^^`ȋu-C QJk ߛNјQcG ]h{<&(i9fH[A+z8Bu+?ͷ"a^/gS?b+18~tvŊ|ǘ7o}{>-k ]Onzv8\N`P 0 'vSysxLPgrrGl׿ۯ~a^?>gy֧o^~OO'~\~f]S -Xr*xNr\bȼk\ltX%t șeW#ï7IOy?WWstDߑ> Кb-ڕ|l/uF|$WfDM9Qx$"/~xJ D{Kv=Ѕgtc#LR^riuxg_YDng<bK]S`8#l?@| iCH?ƛy{_ΝJn-HLcx1=o!^݈+ #U8K_S =# "Zy)re=a [OЈueV\%ֽr7{?FeMo9 ^|?~g?~mا)?~?~WO~r:jkvX\+wZgςd3;t _\xNTt}&lcŸˢgpW25(lu4\1w?` @gEU]7=A1T IhH˿Ͼ ?0*Brti˃o> na^:1 N J "]W}yyiW޼sz;ߛ|,ʝוW#YGΘf&)KZ|5?_}Лo_'߽Xyy_CID(jxf}0X$2Z%PYeUZVNyn'엯!5m~w/_/l~貇XpZjHC{zl;.MK#y}_~M;_}7ReOf vUM:G=Tx9*FrcmgW'q yQܖMk(7B2 A:!X! 5ɞ'D,P Ř 'ww]QdP-jzccrIڶ&@BrWۜ:1̦sA{㮕 G&zt2%"H#%31m/f1qdhHC)#NĮN*OMbdߜR:=NCʾx4 ~DtCc:Ǯ2(Bkݸ|h<4|] u:)`ր˲ [g#Nnbv`=b@M=M\8_[dNqR|hNmAM9ȇzB_bNME#|3΀مZP._ҺͥJCY N  l6H`e`l<,7Ҥĵ'5O#fd:{:B[1:i&-[a'7zh>˧ܜsb6#ޢI,POShڅzܨuݲ)EEL)N @# = e|*4unØ0T-UXݜBv3) 'S=4?P' [u/>Dl2 9{'o@5S֊4Xg6tݮO?3\agp(7GY66\5 gp񈬴DG=I@dmDZl4%q># 2&!ʰ19 Wv5=9B!#|0#Fu %рٽ!ӑdӸX>Q[ہRt%Zqi!'ۙ+v&OD&\/zv<  =8ziFxrGZT/3["|xc(r}~dG %*rEAl2͍+ =k__~\4Vt,';؀H+YpXy"'~'Teyfl遪#ҶY r{cAbîDca3~'}o䳏uVnnY'X/y0?vZtڙ~>@7Wc,˂ڃ(9'ɩh,Dxm* OV|j"g?<@zr$`^wp ,eI{,>ls|%P_}N׻L&FT­|4h6IF:-Gx:ıZDileÙ5-}Lq7Qx/e=8}e>yhY"1m-G(l,LCO3?'_}7(!PK+aT8e&Ęo[ &JK#wCR;gqn3F־tKiuB{|LsHpmLKN/ҕ6 -oO~}'/V(@:99;RFXLcj[8 x,=yX!/K^돀N]o,˩0ڐv}skZڢh-v uG!>zL ޼uF Rw>N>/q.U%âqVɊrr`[в1 9G;DxP.ޅDb\˵Cl&Lg S<'󏀐uqp&ah9WljھAw9iOO>hhiQaxJŤ-{99Z'%7OW7ok NHW|"z'-ݷМ,[3cm+(n`}y@Oy-m{muf؝0vb\-0LA vH{㇇&r,p^U'w7晪u̅fxӡzFW3(oֽ9 rȾ]&u Mv>|&!1YEl @r2ӭ }A E𱧂sqkOF4X2bY|rWͥ$:؉u*-~L^#sO6&o`⬶zҘ\pO/qWGB<0[a3CвXhcο/?'}o?}ӃND ljH|tΜYUna{#^ ,p`[DvzT1]pe Fa 8aPr*; PBaLkhξmGt>guS 7Ui3Q2[9NXY#%ICa%nx9||~G0Yigyl EV(^Gh,q~u2we+ CȪ# ZJzD܁FI.V)kv$-"upWrFX/5?"\}Q.u.hAq!g$q]gtD5zø^\D@V+ Ny9pVHu ] ^],o@ExΰT,|Ev5:g*nM%٨{VluPu6)|!~{{6.fTJJD҈{d^s M}#g{j/L8<$+WsT<:RoO+,E"6 76lRЂ~DqE#@kF73r-T q8.wGI&Ӵ=~z[l@օnk5jڙlg>c=޼jV9՘f)(:kƦ,Уil66MW&=U7[ζ@ Dsl`4a.FN%9B)lŢ;RҵAPOK`&lBCrg0;Z'D @?4' k7l例~H7Zh;- :0ՠ~89{p۶t0q粊mLEȤ%򸝵AnOZ-=Ig#t8ONFĹ}M<g.r=uXnebGU>A{Jwy(2)Au,o>5sjY2c!^a{=llȴSܭ [{ (L,:]xRET&N$OdlẀQ4ע&.Y{ ک5S6msIob4ذ%0msi2ś^J#.ct)]. T=¦{Gaք yLѺLtx3&Y 7Q3qz҆9YSE&.uzs=lӘ/~Qkoܶ8z$KxgW͓ 7i=:[_oRŭ;q &[0T' C0RY{/\`oߋ] c Y8[O>g&C dZtAW}Dͳ; 7o!X5nbdN-üqͨI /:jo=l9ͩ Q_KW+=2"["{-ݜa!ɐKjlBqiZpĞxBuxmĹ˾1z}ƽ< kI߹FV@%@Z)5 u}e2\GS03u1E5q2]jv`{w N4]FF13-ksfpH׾YږuvRWɻ<% &2h塬YD@+j Ab?VB%`߈)Ȟ9Php>A:+:]brm pS̾#DŽ 876t3ݭ7WI7>^[,<Ul;_8fp${:kzN 2*a7fоtq`SWs} Z9eH:=,OYviå6Z%5 1hY-걍 F\H*SP>;!7ZwT3+W3F\"gpl39Oҩ=̷&x ƲqI۝v@KܼCd hϐł6pTIgEqa?ޤ֎ -9p+xn;\ @-ڶl(%H*Rn35hK#M(Y/W4zqJ#B)49{ &Ϛ:;a }PٖK1t9(qˮ҄L]i2C0F 7NL܁x2^6I&D6ENveRm7u;И_oyl`FХV{vyXNq^E6۩Xc@.kp7YC6q;jX,ZgbLYw욀1gxSA}u;E]ûo%H}GL "_V7>o}kP-Y%Ρ'ZiL,NCC<hi a7.aعAL I(FMmMwȚзGCg7=Ph)t/>'"T)8(Ϫ<`wRqI^em:kvag!º=~m6#,T` eQJ7gq#DĪؕ/׊_$-FBeoͼ VuVK9$>J޾@s-ĕёx 3D],lag<@C3ӢC6Kqgl]4qȟƖk;r k$zA3sv% n;)6q 1qPlϦ~y8K32Kt|N%1T{N\ڞk"MEY =}S󑣒`@#Ɏi:Fe>5@ _^/8qBc|i`ŠͽXuʣPb :zz^~|=hs@<%=ag{.6 ydl.µ'@9m"}clur Eu'On44Ϩ|j>vin-SDmKM, ^+b§Wp7޾X_F]a˫NdSvAzؘS;Є&_Gegc#MtXcPLYg/9vjJ9l ~*{`I&vg5©4tm{eu&߱k>C5Hx~ jd-^i R\Z9R@8wy{ q]yRDQRɪ-'8%A! z;kk1QooHZm.wYPxMeb92ym5oo #s^/]8j >5k>!79X9W')礅tm#3aVqyxuB<,.,-OFI#v\o-[:oɷ0U.aNաMA@{D54k$ɧF¨ϐEGrS:l] '?oOG9鎫Q-)q֕79k{a;9e &A'(_@$#\5!=lJ2$F$5 jVqA7QTNx fTl }L4fn5L⨛Il1o<@q YvrneZ̕.mE O&!̌0I;kߑ?#p~͐"dфN4-oq Gރ0M\vjԧ5O,tϮy@ІH p$re ujɣ$s&i }X4 sL 5J P$GyN-xf>VڝNy @ hˇsu%bo%hYdmcqQ bT}~h^݋n=/Od>Dg;V5V^/NwD~ɻ_qqk0BS{H1yߔ"mmW݌m/i js<Ο]2Cϰ钳<w,S$kqlX[ABi{]1 ^^\ y)eJh1Lx}!9p>RHUL: 'eNpDt868I e9wg* sm2d84K ԛT@jYI2}K)w>&vy(^}6 rߜ9[Zώük银`Z" C(:>:ef HM+ۚzQt-{"ik_`%'\9FLJ#2g!›ՠnO#4&0e#+U^X2|ZN:<rA6 C<Ȗ s{+eNv3/Zi5Ag0s `w1/YqDݱ3c]s& hs&-N9 q )O[^rKxO=oftS9t&}1^usLQDJ2}wDszf.;}^J22^3s@QQJ VXjV2 z@Ljz궔؄K`2#I#3s"#6;@^K [۱I{{2}ڼ8ybxb*,ם:u1FOZOI'̈}ۑjbYA+Hޮh9 zX`,'0!k `^<؛1Re)禥},\{ڜidQ1鹓?`d^j6%it(4ݢK*τ-8-īDXw`7:o&y}:՚Tq[]*({`ﵕZ 됵-cބi_ژQ| ÇhNB́{Mx(e:vJw#/wUW$ ST0Bx:f%9ٸ">P<>Fܸ]2J d() ӧ493r7AU)DY7NIYLƇb{8#K:zy0&*}N#+9[gosZm ς(P43Ӧ oU/ 2$*)P!M|VwW͎Ÿ[ rzgDz:'bS*fpp9%q-'/ںy8Rf_v/aX 6R,M.' =يYUZ_dY+Qo%fY0FxV7B0%biS;"Ox2^x ={$fp%ND3nqc\ /:OtgG<(@>xd%mS/@٣ O~(^:WyC x|vђ9;n.z\le!G}i.ϯ>}>{{4z}+;ˁ,RP J+)e>Zu=aޤsKZkaԎA6n%E<'> K)rq6=yPklÙQy 3m;z0Kl1nt98*,_}xɻۻJh,^Yr3[C+L40@ͼX;Byf;#lXֻ{(v!8;{x}ʖK~g?_Od$ CPYBDTwZ( uQ}{:Iz=JZ;cOQD;.z뵬o^?X5a;|}0N5נ(̄;AobGq~SR{-uSJ[8ti71ɨ3 qԭ5K3)?y@c]-ɉ{cQ*;4QUm/oͻpzYl.8;S~l9ص*hF|a_OkIʯ(E4~F\gprXvdjJZ6Muw19\ yF{Y ᜜]p&O5j}؝/b:ҵuqtxeleB7 %-HVj>dxJ웗^PKH m?go?s=[&XKZUv>vi堲g ciX1-/?|P^\H=Y|ª,Zlً|rY% 8ߺَc7X X)at,꥜v&dYcB7b5qXj+WB4^ihp+-2\bo>QzmC"t}tZԽV㪽l#˸ϢN4ͼr4|&OD'o"4{3(,yGU͹Gm$^(~_iT4#):DmX])˘Qi“i*/U7YhxR%(O"_@Kw.` /5Ow_|9Kx{#Ux^[j'!+ }of,'eVG{"?g̑vpI⭈7't\{bF_zwWz\6r $XP倭X-*~)cԦq{|׼y;P0~vlG{0 n$\Cl -0Zn_~QX^3Q.[-iŝps:5k+QIF6cZ<#x!;|wÍ9pjˎYT`Fa/_}~WL)+{Ƹ UvvErG$DrhȮcZ|O#Op~?ACO&(?0@_Ƿppz|N(-DϜ g%Y``x  {}77H-xS,[zkfZg88*OM!z)/3: g[E<7qz]"|ȸ]7%QbǤ-ʴ7Tl<]I&wr$̝72S껧 ?~14w# ܢ&ٺ"VE̪a7e"['S:j2~<_H(>@Yg?~qxί z};VRXT=gHI̴+awKBLg)Qy=ԗ_ԗ3C1*??#̖xÏ_2گj$"#quU{Q-b4{L4 R4*N/Fke|/?yӳoqDΫiu,/5f8$#Jép6Zl9,E}J,_߬˟jeW( eUБxvZO/g'00"}ev_~U?} 1-xG|k/SH:9UOUtĶ48Y°[4jܻ_7n}i~H G. KrU-mR:i]Q}1?>UQY]:H^3A<)r!w>"iNǷs~ן]cHn-ҀyVyjn=g%Ilě{PbDJ'T<1+A@qvM8o+M=qYS: OUB(g?q/_~ݷ#x?ǚG,ǥ3*c?.3ɤT^L<( n9;z^^7<;|?/1l>1O]Q?|~/}_o?wQ\#(@BqgCFG[kXwM*=]mN[=2ᄐ57^v& AbY{Rvu y?ݸ[7_pT =AFpem'^KBɰs#TW4UM}q%` ):@ґjl鬊uy$Yo'F>|>O~7te1R$> ٽ4-YٸN _FW͓'G$"/yTu˜Y35j/7=3hs#o"߽=>. #I'Dg4s<}PTܓ]Yk(1w?O_}/|}?P^Ǎ<;׎pmŹ[NjÄ,MrǷ*OY鵎 nZs%ac IE {xܟ2/߮[٬JƆV"fb255 qCюZ=PYIx+zL9F=4̠`gNsH E~u}{5L4h+@rC7*GH_`y~~yHEnRO/=g2ݬyimrh.w3RcFhCwd:38=OhzRJ"6ˆ{n3q6ql )bxwGFuyOlI\I,ށ|5ecAAt*r5@1b#(3Ӹ뛛u~RgI (^^XӬXdg:΢K{eul2=l[^^GLe[ > WW `t?S8.$jQ췛Gmf1/^}WߟGu?ĈovLsWeV[ yb~6ӡVYC|:[ `p3 ׀MRɒ:rl%㼇ڏF'͎PM6EkˣSBfi5d."#c|P,qRtc]=+ql̂hvVgpcd ӟo:7r|"A3gS/gX%X*,Ǣ>n/?"ǣ !KשEXa6::K1yi?ҿ i:>8ܙhpZtj!:QDuҔXÀUvC J߭ ե0f~E+]mӢIϢذxMXJ77 ? Ю#k e. Nݱ C؋5# a㨶J HʁpϾRq cp^#Mm4pP㯿l4sA_]P{L}9֩GIY-N֍a"Vpl S*_>Qj6އ/@oG}xmVl`jf=XBAt^o˞ |\`P~N*%7: ª^#tО&|?n-^)g8(da[*3dQ3 C(`jxtwKtXIvKcPLEL*ܤ)Mt_{!{|$4N0H@҃RJ;tqC0}y2=ߟFy5HrW m2k$4%O dT釻7g'e1S˶[Z䆭K4Uo['NT|OW~ʨ|AԮD]#ţ0EK=Iܓ iv R/kFqh x8z`%48RY~(H]85Jk8챡pzxKa9y"&?|vc_UA\<64?ةK{#=jCbr k/>]&s)x$>ŏ./3pOՎ.t#C8 'j3͍`x bȖTx|e\c8fpO> _݃P?9Z'S6-IT&BKq&TW: U3+ C`TqPqLL1(`dU"c>])Ӷc7fxaˆħ$=5:Hu:(0e3^[_IGlɥ'΂8`ĆdL!Lz~Wu?7vptl@o_MCͩM|6Жh.W !>k^[9ESEUTEK@;BWy+߮)KoCNGBZkQ*Y ,4׿=&=OAﰛ/{䍧jhkE 1xswW0mlLoJ*?_%~1ޖaoo,hw pߺv2?cƿW >iI+Q8R$'lodFb5c{Hc'B߯һ'a {mYED"JM8@^l^ kez >JPHA!2G:pņUG(Ho_+2y0ށ!.iW+.4L =l@$6n]!wwEDV'Y6'f7A0#T;AuVgJGD#F /'{z^0NlQ-Y)88_suϡtUYHW^R 6t+'iiew1Tsss@',H=\yA> l6v f MVm[+"= 5'{KPj!#})闩;糧8Qғ%ru)==?|qfןeE4vc*ުUcb{>?z'f(Cs68&tDrG9kj'k`coob,\y5ځ (7<Ұ619n)I99{l^Pn.cg.퀔p[V1p˛Y|<9Î_]^ iq.Ĝ9>k$hFN8%1> 'y'{vVt<1Yc NB,Y ژ\7`9 ~fp"9P(E6$])I=Q}"?J2RES[j̈́f޽M"RKTN7ѓɍ3D*U.jm'<T`եMg:q!<1>7-Sz)X-څ72T.-lܨ'Vީo^!KNOPp¹L;NW ՏO>|3UO Ta)Q,ث7c6ukc&Z.>GXv1os>O'R8+?pOM;BMjNb @3[>`k6 xcAWd%3e8'Bnܒ[04 a݈LT.ݏ8WW O>NQ@r,rE\g鑭~r %K,bPUE ̬kEN I <f Z^G${lYO_^=&w F(8 JHb@YEC|[O>!(#'m[R}ё]rH];l29KЅ>"yz)?QJBO*kn"RkQ2]zEurX[Ƨ?|W4__y#O| {E7e F{1PAL=ۊY~L(y$KiqX+o7/42L%X @`rʂNJjje;nUXp}|hIA[~rS8%'"s:;jQ@m;jA pϲ։rOӔ A+]p֡r613OI>iݥ4DȸTl|G+2"Z "`'.(xJ@oy s@t*\2,Ua\(Nu> It3.>(M}}FwdWX`FlŧNa[v='_UKj5+z+k0ŶeC{aۡOwPP_Ke@栏!J5+ % V_Pn?p,ėpj?kZc@ڱfQ ߄ q GPw(PAvO\^) |KBDG|/^|Ӽev8oAy7sP[ `Q J`8JD+7PՔ!< T74\cxLC7/ėlI6rőT*mlson2J>T2\g#eաWf&ag}? * vYKͩ('Ap||4fOԚ!&7*.BLžBX*佨DbQ|fAF ͇>_?$ zB4Gr< t4"MLo`P'Bd-bs5A?wH{pǒEצE0V8Faocfцo#D)ZoʫY|R zOSVe3[%4tAHyi/^߿=}H[rOsH}͏Wzs4㯔1ȸ$`+@І҈e-`OZ8R&cP'N=SBăCof@hͣ(L0cy'_=nVг6 N4R8>k)ĩnTIr~e9QQjjGy2n5mdeѦrYvǐnLPvO -ݺ<:ǦE׬W~847Z>xڲ=kJ#f ]w֎M92h-)YN~I}M@?y.9]8ʠQO>Aɜm'Xs{*1߼?{ % B,:Mh~h7'ish%z?{p%NCw8iE.(Hl춃u2|AU$P]=i8Yb\kh%fj6*\r+g)81|!2}F[7R2ĩn^uc z5sCߧAӺ#';͍+Cb+"+{6#sRE1YFI8ڪk2Z=yh読L@&k1gA6#"R;jvĕ=f,"ɐK'A-b[{TW&I:}H`+u?};FvOy7F=QOWpd&ՠӽ0 1\{Y~7Uza푢 ^>ȫ?) +L4*A"WiynEQjFJ{o>|a>ϯOf$V+f5~ 餹6p*KjM41v~?| J>'sr"UWT(>i|#?g5d7HE"gXJOx2I5*,8(RқPX v,9e~$^ậsdfTW$Rf {IZLq9'1I '#6G<}H9Pѓ+(z)AP]]9IeVuZjIt\<8_aH\d,DES{t q.mrdo+`8@_8MA:gO=P/eTSљeЃΨMIGDZl}͝B= =?8^tbX k^Br]^곫[|Ј\+/XW&*^{ވ At5+ !Apn(A %7S4 :F|XLkQ)<X7`cBǵ#"(lLHI{-v5O(=muR?g -J--:Ϧ}̝`w,Ƕ%n=znsJVPC27`3$7N~F*8:wOn/3$$-LmI61{P ~cY1񗎑ʈ4 ⚌ko1Lըx< fsf1rJ)9neuW>ϙ?_X}X^kuGH.SeI#-8Gʭc+雫O{9zxs Cc0po).wMmR-'pI#KKNY!1ǭܜ3s8]M<}]߸k;@r8‚-q6փ<}H<UXdTnwĩm8)x)ٶ^?)6IU {B}~5|(=;˃y"4 O!u\!Vi3X<WY\?Z4 >U[{dx#Mq1A}6?gɿ_zTց+dC҄}3RыlP2 Z_zePnaI6J>e[WKe:#9rp_UXHLgRw'ek4 ޺s8}K8C8]Ps+, b>Yגe۫'{4+΁J="Dqh݄j |Õzr )٤r!" s:vf sӱ8P_!s=l 3 %gR2۷?4{ v:tS^'uxR ȹ!N%4. Mk<ЬXmsM/jU8}ZT zD,*Uvfy,xȁ+(7_Ewe{:W% Mev.0+_^YឰКWxۇ RY6\Iϰ<}@3Щ7YDs4{R$"cҭx.?\?SO"ij |tFZ͌)c Iv<5*o^~λcO`x"'T*;VƆmc200ߝ+WV`+od+zq{Ӳ¬]>"~3^ηصS`i^|b:`咭j<|盏@?}Հ(ZID26G?k`ŀ6 Ɗ@FOGmN=Ig"3"Ei1: DZ6N7 +6Zg8Sc旗Ĭ /{т$N@p"fIK:k+l";s~ۏ@;MTd]YNJ̎a<)ѫ lCJ^_>x~vA[P-1 th0Vvu83 bzC):%AUcYŸ3AzuZ✽ĩòIHv6 KzN)eFbF hM&0J5,k2qNϙm !eWA}FE/t S*7ohn'6\x6< RxUjxÍ&u,^^RBKUz:B֬9D~q^ ;Aw$~<19%P0­WR;I|)zG[h@M,ǝ$5SUcĢǐ+;?3[>Ye xצ%Bt^|򸉱C\ d~Jfx偲O>ƭu&PyHSBꋏ_|wT,4̙-b#CHkF >>Դ!Dpqjggn8u%MŶ=njmlrLm@DYn)7;V$ Ml8QfbX+vNB]Hy>穙 ?asVn\ ȍ]d> pz^"j(,㿝?_#x9=xyBiWk ]]j2 J;iɃxWWWh2.{z59( ٛsz,9G2, &͏>M +$`vRn ``'ub7U;xgUS|~-jBTdWfr֯ãD8?:[$HBFʂxtԼԊٕܳ)w-9 "\,CZy׏6|u|tXN!S&['R%l,Ŀ~,G pSjVf-jqh*"OMdax}jg?m=+?_$8Cr͑j<^XNlkůo^ C&se,ا;c&fǷB>h-8CEX?}7Cşa~t\ժ'}إFM5qM^~٫:>4!-–@ T^C؉rғܕӞ@rTE^^V"z/pZkFӷg.:k}^՟aT/5X JV-ATu^Lm瘟BTlaާX[{fЛbC5OgGb(TyҔ=Jy=ڐ 7ū ^xvbYeJ&Q;([MT?|s5ոZ\t~E15a] h(+MIt{syyH:QՋ"0$c) &~Izx3 .L=@"& #( @5̙,7iw}fۄ',bzZ2J]ol+_8 NmuG!\k$*iuٖ{a-bZo3S i˭MoIQcwd+hz Ztڏ\}w X"*kZUk 0|4cr<'9$jG=z 6XRnZ'{l?7͋HmA9(=Oti< NubmO`wX}}κ.fϏB,;#q|o})}$l>Qs@+g޶ :>v 0xw#my5I-8A^؁z鐵QZ,5-ǥ˯ǯX]tg |>g[,Z:Qu<R-g4iY WߣJT+hnI8vQ%І}$@]~Z/kiNM'uYZ !3k):fGťG'ʯ;e>L#z68IV˜}6\h.wrKgNM3|Κ,9+syX~F׸=y % #͹z)dRs'3f z /ٷ_x;MZQ&Ҭ3o_P壠d\(d={ ӽ8N]j$Xzř 0q86@j-uw &W7$'#s 6现L}t>H/f9;λ(} WTe!qbBEna73~Q@sT_u?$#EI|ċ}bt)\]q`qr[ V?gA<_jgׂr-kII\gieͨz{UʹawT>߹tkaԆ5LYq Gm*b|Ig?Y}ُݍ T)`kIaNrhtEól8ǯ}ʟ<[79I[^[sNPyW$nЍ~:66Oz[lK: 9+)H.+1ljkYj8=fyBzɐ`K5KO[ydѤL>w._o1O]:֙o-;dT+;g&G$Yr9$i:l@y)b_5_~Oޜ纗 y|#eހgtc#؉cl~c'DtSS'7"wqpfqWXPQT%xANB9Qu(6u w%GǬ$2o?o?ѮaGhŽs|m[YGw^jb8qWΗ*~Qo_?ȋ9Nb>J7M`Q³O #(*$ӠOSy{~w?F_~/YAe]a]p0y&64NeyF!P{s4#y+LƦW*>h;jHSNmkYPq_?I/u勊~˪UDWvȡͤ3h0ýOVG_PE4z^UMy|ඤXQd5(_$mHbKߚ~ogb0MzJ}I5]*d +ۛfg˛qGD ,eLXgҲ GWulٹ洚kRؼ^>a4Bn㸷vzl.GqR$f X 'Ҁ l|{үUafV"iE+ |T/;'+1=c8q%#U9_ 2'ֱu<;O r3țu:g{{=*E#@4k&Y#/$gB*DQE%ENP7A9?wlQxƤi;4q4mۄ(Fm`˽dy~D!ㇴ.99upJxK`ahLu@Yly(Ǜ,beYMKkJhZчOE smnsC1<"yȞo頖MU>~e-]'*!cg%myENeMOHvT.; ⴐ= ^gwx{jrsQlC~ 3-Wgs6,o܋呇-SJ lh;3pRbpNަu^q|XyI uv,8gF&Z{!IG/rzJF/ۘ䚳Sga(07xguJTdN&ud] n}’XdPN`+cw1 {,#>wg8F&bpUceǩ9cT$]Ceϛ B\O686s7i 5,8G &(xŧh{buS6(}ًW-,-8m-~COPHݵS,ȯW Iӳb68w!݋pAWGZ~O2Mc-I{^=' Z+ݵ'ys{nvD1> *j/GF5.gx~IBh^YgO{0.g(>R) (%%APJ0OGK8y6js±HAg‰yoxpP]J&0i݉!@vdq[H{(UnMVq3923uYXBNMu1GzS>8a i[0j5g7Zj4d~}Cb_y=#O JdQ9ODTqz ݫ#cx\ TgQ]tզ8}MHD*Y9>ߖ 0g@ lf[b.rPXLc rsn \tN[.E\3N8Q^2[^Re}՟?O#+d$Ġ JK#x%su y{Q }}':Iag|J`fG}1:t1Bx ,Jf)yJ8F% aRB%PFQ}M}ݣŨBۮRx+X;DZV)k CQqy۫g~GGkcc%#};w-t\`[9y@72[.zh}M%ϫY}7%k0hzBz8'd/v׷OOB졍h:Q1e IãqÑC Y\=] *AU29kڰd:'kn[|we'Z&F?_G{fy%,wΨu^I^V(Օ7 lW_M?Z@7a͛A1HoR ,G>1 $DX^vC7W;?aA-NBFT;ΉorV# Κg&(fo)\\["j\ I̭Uo:ZDZh/V|{ _l-4_ß |.خh-^n k2!n~Y"Zq m`?-=2ɼu_HVδsp^N ۪Ŋ06tg M. y>f:la]+MmsС$6@NYu}ͣEo8WtCz&¶YG:tdW H셷yO~"bՌ(MYn2-Aut+V1MٶkB N {b(&Z.)G7y-!37UV '{0g~TX`{. RvB6 l)\o}{kV8/*sZ}\+yZ-vMR¾Ҝ.5&N"y/{%:ʀXAۼ!F+OL>nY_}ٗHR- E@xrTc1Z8+|S̈́/vo~g_щsehUR&J {!#'K"LENP7_1>ar؞: {EOBخ ywڡ{wWx/py M"9g5"-MK]mde)_~+| =xW \j ,_,R )['cϟmnJː.' 'چZJ`YO~OU6"sI`K0DmSlDT]W5lU&+ү9_|nѤ~B aP[d 0K]Yu2 h[~>Gk=rZ='K n?y dJcH:MKD?ԛV>,:J#V8MKJWjaqy[IGjل]$C1.S #B'l/R^ ڕz,ڻ%c}xz?'6xr: HˠMi\[DERG军nXHšd`0ZG9Xq^r9FWx VJ3Uq^r&siڝ=4.d&)C冺Ch6AXZKh9'/m"6#﾿榒n5u΀+r5S8a@ *VOMPdy',lyhP0S&P8iOZhVs†g[_z= )IZڧj!0Ż=2֒UP4fu 돏 *'F8 DLSZ{jfE[mUIU| H! Hl)Tw쵍IOAh[gXQ#Ld:+>IJ+䶤oe9Ue rD[T\q$v&-lx qs60dٴ=ݖzrVERν Αݸ7j5m]y {AHa{>zv?! Jeɖ"u UPFwHœZJvH$o{~ꋇ~jޭ$=K案PbU|r1x\"o߽-v=%|kZ]^779$ͺ:vɘ{ V2R݀uM͝Y:NJ_D[ Ԙ^2׿_n|׆ 6a6T6YFe BVm-xrG^$T 8D߼d+[嶫X+zh$6 $Skz׾_|?^Q\uPm[͓EN^͋Eۖ{A/}dQ ؁sxUͱ*2o#vTE41FI}BvDFJ*-X:XED%Ǐ~]N%iآ Ą::؟}߾Ф"sU3TzD^%+C{8Lt:ZfOЯ;CHw :Mfvo( #QF˓PMa_$o9;pQ!ڹJ^YNiT k܋ՏΔMRŸ5ϱC., nxE:X 2^߽wJ$=i{LrUL5}> b޹#OQy6d6aS,#u +"4vN}7ϔ.OٰόqZa 01 `uQ٢mGA<yLq:oӡZ%u9RGqb"z$tOI?G{LIǰ7QqQhm B`vjAkO??=0{2JMm:l~tgZV9NݹzjVs| %t ZU fDW*?;VvE6kFq#7d"Ǘ؂W|czP>{Y/Jۛ28w:^2>Oj<ҒI0\Ex#,=+VpI5B2> !{~\{6Q1hL'cm)ŮI PY1.2 乯JK2=AKZS>{o^;xҖ]Dpt+%|R, LTbH 9y:U/+7Hy a-x܏^iӼeAQsYME_txEo}E-]{ym<Ѧ 0.;qv.BaoL>< 2$8;{6ۮgdaWIW2P=ʸDF0HvS5VBN&b#ݼazkb̽?}oLl̟)\/^.gYhj<ȝU+<6PH9yͶr|ش^q ZbwNVZ\]0AޣqT=`z?:!:GS*>/;T%#,v3]OxR\ֽW.̐g'bZ`D*g3,qU>"@".r&oEH\-’:7cHӞP=b*㜵uP`q;-KNg&0͈*<u+FZKR)ٖ,Fv69p\Dl8o?]&ɦ((]NATm^+VQ=TgH|g=~kbt󊁢 ܳwTXy ~3b璗U @hixyFU4G`>&TVE|Ϋy8ҿ4Ajr?}|q 佘^fqeq~ޛufx򽹗mxK 1/[PjaD**OxI 3(  vjHРKmv.ӎޛ=,Mݧgz5лa*dK^PqlcQz|}{r7ܴj*؛50W s\׮|C?I Xv<[UH4&(8%p՟,W=74lW`Az8V.}`r5rlxiPSoNo]Eb!)yN2HJiH.Jk쮱mc 32,dU_xOwkR-P,"<,a[2ylcB0s J˕w -Zj3k?=_P%VvŰ .Qa3%#& Ta?V u.ˋ{f ]2ue8 ,D8P@[f<·Sg : z"o aiL^>t.47U:UۺZ8E^<><2MUpnɢ%=CǛ~IFg #6^8 1Je)aêkR{: j#-i#Lw*v^Cs!W*TrKMܲ3t',cX O2JӒvNXyw+2:|z(v[ur.3 LfiO5G3+FZ<}zYM׆ _%)ib!C/[:z̑KV皣co-!:oz}U|~U .EZ5Pa@{ aޓ!;Z 0y\%r"( h"MƼ{_RFur E! mc))taEf8h^GvS4C㺡;;B=,s)p &6t ʙ2cT]kO%K:pbm .0P؞,>h]d 4tIt >VI_V?|1O-AeSH+Ȋcp&AF<LjFdep#e?~ 9n|/Ycc бib27;o0x=a/!yw\C|85,cƽ<$ck(T'˚p PEn1`-i"Aer];8k.vs0z3zX0MODj3BN[ڍp*ahe=rC᷐&z Kfm%_}߈Di3o%T̢][ vSW$6$Auk2o>|kW4ρ aj12[ƞi֒-s=`-V]:'1@Hwnf"mV6HrιA+cii<><|2kkWįD!b;xMܙUepVA&hZ=lĠ#q&3 <>CU}MVU7S6MJl]@`; +pm;hkCCAkY~w#C'Կ̡MĜKQt 3)ȹt !@((Uq*_}|z|~쫪p| ^1""M) Oa?]o4DEp/RBvИ4aC l,\@xXG )my0P0 VҴȥIHu̵dum[:vv L`QyטA4q!L5gs 'adY:8ZI᧫@1=f{nZfFl / x9`9W0 ?@0N 3b Ň8W T58 ӏ`h W_⦫"|9P^#|%r_H% טY-m,f*QRY?TB;D]O?cpU-b ~60"<CyR4O CtZ,k쁡+ юF=e߭Ө'e qZ3652lG̅8l⎢<Ykk1,ݭpKkUwOķMϓѳJrVvpF,M_W^A=h/ò*z>ϟFxvLL|Fa]Ŵ0x}Bs.VY:.5dMa.c1H \c[JfȻ^mCxՋu]N33p5Dzatl[PiVD{ͫz?K"|yD^qC ooF׬ k%WyRۭpύ3q_U 5g2~=whG\ ,X aAE 4! Ămʁ;ZI}-|S`D,1 yMl&-W͞<Ĝ3]O1̯GдW95cC퐑 3JN`g08Q6!Fݙ+Esa [&*aR6%d<1^3 V_f,Ia%2]rQL@N];yOpK{͛Iodvl:;du۬ЁHl E>=tId熱3jB[vȈĉѼ&i^YZ{M}\]~_z3wՍ l3cDt~SLժ4sqeeɱI0b5{1h-1Y}~CcO?}L/Z^Yy--t㊈k-Ec bCMhG l{&gS_⢶1Ee@-YIv=&Pka-vcH%Ud~z_v~ < oϋ4rr=Ap5`L#gw4qLp_?=]*Asg(V!A im\ŗm#ڪ-l2.C۞/?39.xt}Qm_MZԥBׁ;r]fn"0d@X4ID/'1`Ϡ6[=&Sv(q{y8t-= &ow4ƕoYxs>O_S=+7(Oα*B{PymE$\ {_G 'й>_kW烏mܪIf{uTN3V =2|ϙJ9#_sZ _bo2{hV5(F5C9M`Z\^,<_ C8?i!R\5h5]2L//| Y n~ Out]Pn һr S;|u-U )f]wlbӷNsNy[?_'@%8q>eg뱗 'Q %dc^HAkT{U&/1O%4̆ː cŊ6ؒ\)ta,mQ1pq` OƻO'ʔ̷TJ4r5U X1R(a8~@繲1|yFz/d*x3-ں"==}5/So-szS+#F D+l0U)Ytb e}O'!&mMC^vwŃ@%8vvzydڦ1ט Fh8tq.B>yGx };:cԓoyuϿxܑkTL$ya.8/ۅuqBfU/CÉ)-8Ƨ# $9-C&rRvn `h  /?~fo2Q[ b=ݻ֘QJ[&'Ɋ&)6W -y1g{L-u(Pɞۻ]u̕#hARp0:g3~΢]`ԀW黊XiWX9FeW,zp| ^pIۈ{fͨK` $SXiwzM1Ys F0m{ʜ Gκ&y̢eBC[y%F6ƀV+vJ+UcXLzYJÛ7'y/ce Ӵ z4m#H*Kit!g9U~yxO?^[>.U9\EETBd1}3$ H)j + !}]_{"Ul]kdl:GEgO]FeO}=@Qfkƚs%y@< R1X{)1/JKwe 4Q /\//%S"9V f.{Ns)A(ĸ9seSE>e )$ y!4-fg!N9P岭ղKǮx}H2]a[ cF,8hTjm/ %?#y34C-30{v0{Nn<CTj5ۦ,%Y*K"v 5KO˖9E|9S4gh;(:A -cl,sm0^)tL||s떷2U)2h2Tm²aMGp檜44e^>]q˛|y/ڽ v+OkdcfWrVk47eJ :-zp K'H)5r%=M-$96|W~iտ 2![`l"`X{w1l"w^$1ք\53F.aBf/+?M﹖8uB?\Uo9oDH^6].(v=:P4zZCr/aTzټO?ﯾ_bpra ǵ<,`._%Pa84Cklн,i./>|z|vIiU_.=#+`0aFQ58 m+Ls-d$dCx^ww?L͋9qLo]'!". t銇CdkSmÐ{gXSQ@PyY߄Ί_\~wDT_YDןznjZy,iMZ奢=Mg_͞NhүХFk#דA_|Aj0YXF ℥28r"!#=^'zC@r9zX(20jQJ`DKsg&NyB ~̆lF87S/ؤX*C xNd)^4aKщ?ToKoA8+,wPr"3ƍeU{ b(kçp}|y7bq'TxVj8= VZtLq 8><p~MGufղpXY2,mLKX<;LJϟ=&s׳g~EkW"sufM[|Ngl.cȊwO4Mr+&o}FrQ.[I3k<ﱙ̄*l\Cl\G2gXl|Z߁K냜 \2,\qM'y/KfL|ă AZ[EPk)s ˪FhY߃6[f_yC$$A_vYr_:iƨsTbVؒ4y>'!sqc]NO | ,k-k#\sYGBS{ҳc~??x=Kz4 %]w=t21:Ą`0=r%bçTta~} /vO{^?)v w)`-phڴr[htw"_NrWZ?)RLUkFck<* >F&w|GYNA#pniƉ< ;Mo-@9@*0[wΓB~zw?Anw:/.:ad  ]Vkgp\@Dxx e-vĚqx˚dImJp9=@!r64F6]#\?"9q^$eb;e_9,9J.8FZ4z Fx3,o>/yh䋯/Fxrv.JLIN7!SJbU hҰ1$s r)kL/j܁Jی/vsb Wru{Oݿ5}ww[c';qc=KUO X88?[ :DeC^Fv4|9O|z\wɳ Kw3oof[J^!DI@ y;gɔhžKXsWbqjIm&1F1CmWy_Hn"_˸=Q_4kqO̢7HO5\͒ 'c`ÚyW6XWH?XtB8?gLrACHj1\>u)U[0q{v/FE3L/~NOU3EpN^ߋr@i6z C<̬,x1Ac^P mH` ^ja{Qԫy"ޞo9N\'x*ǽejg銉:Im A8en];smúdZq1^V7/ }/Gg7T>\u3^]԰֚%K}.1Q|9C-]8)6 aXߛynoE;Q|A~tyⵎ 9]7z 6!䓷qb4˹0So9ϖC}' kz0Nx0s9yS²+*=m *`򵃚SJ/պ$:m|&t}]9`8)-=\^UF'6b+:`F6먲ۼ;I>D/ySct1O}%F2 Ӌ?r\;ՏCgZҸgȢ8Ҫh'CZF-!V#Crͫu{{s2t?<|D=k5K4^TBϹ}!LZh gtqvh:L`7 U.e$q[@ <k#!fC,JY䑥l015bhF iߕ5qϋ7I8"QKqz[wg IDռ7zA>߽vK8N?ahE^x}/&xBo>jL^jvh緂㌟OmQR5YA$i'\LQmf Xb4pz{uA?医Cv짢J;r+ ]Nܔl]].zAQ-!g^1<::.>D 76ZQ;h9 mgBtҦٕco" _(GIG0ʁG(_ 9{4rVF$ЁtY0 VLGkWݽy{2?|#O_RAQYp:5BjG0``5pc$NZz{mƃDjRnvH 21% !qhfⅠ{V$>v65ܭEMc,7ϱo/A=IrX9f2z0JlSZd)x$\t)za/VOtov_<߾/edB$a%) SK p:R^+5U2Gn̙8to_:@6D(q{Q* [97o^BBQ?=]o+TUFT-m1YYLK9֌{7l ➙f]/c8<{,|\GK Uov)HJ5RwUa:s- b]{CTTXiǻo>Z8ceJEu>Ut9윹94݃: 0Hֹ|in.X!cŧɣaQ1^Uׯ޿}>Q_転DOڰ k?S)(BE)腬19we3?"d}r0&=;rF …5l'oO4#a嶲 L<%lwJqQCϽTn}|t_s?v1cS4dM#ʨUcW$0Xf,5 ޭ뻫vzcmJ`ȇ_A$AjI+޵ל»V炚6Hdj@ S| ^?q O9#8N}_ÄIC“\mr*.uIm͜ifB̼Bc>?ȓ g4ݹ}/Ku3> z7b6j$ՎC`jm "uctɷb5>VnLJMD +Ǵ Y:*%^ qvZL1ڏxX$5#Q>QE^֠п^ >4V_?n!רbg,혵al$(\@'^+tOXAeEI{aBcV!c"H 2-qF:p :ȐXNLJ : 4E"ku3ݺ{[bM er9I̓䰓!4}@z 7yu4_k[ FWbnL{E0`El 86{Δ&\qL?_D Mn0 \F ZȦD-j{r#1 n@pAp9bLs iPm{&B顝P*p:v$.y$hgēI-5dV0 F.Y>D3 ̋p:}p?~R+|' UO/Q/gb;t Aܓ0m@@djɂ(P_w8hhh/QatvQ4䔬OǬIqږb@tzڭ2k _wRO(=!$ƠAպМ%ܴu, 6sq # Pˁd$wdDX%{ LTˡX"]+:Jv֨]'5M'WYup}`bg˟4Fq13!)9POL#6yX6H㱝Eww>~G@q|ъp刢"ƾcd΁;&zlTEAy(rI(GBi4A)fWLځs"If+|r-Ur ÇCよ LFS|@vd7z.㖁s7Yni1d mB?CzI BLJmrrJ0ņH5r ac8?Bn]\܈EP9|e& U6U1!J-/r!Sz?W7׏?~<|I{taL"{Ia ixkSq s:%m % (VoFe25tYs1qW6Y2ԆDXC/ӡa-){fmr^wpTDž6-m<}{U7G2,՟>tIeH:Er0+Nv.7/okuޯ۷G5}qɝ )Q|H߯x/8~D@OoO2!Ĕi^(9ӆ8̻u}} 皘ulI WЬ[sW9JS^ӭv$&CGLOjtn7W=Q]x|d$hP)![FSi!0k|WE`$+ŜsmU'R l#N/zS묯NzAh=04e3Qϱ:l \1i1hn%ٙ47|KZLGgsh1eQu",: rہȥb Rp=jzMJȸ5\hFPd#{(O8K~<7`B`V͂T |deM$X[o8Őxs,ǶJ m@ {DFX^{'?77WN tq Z{]4ժ Iiasa&22sOՍTA}p 2# np 1ͱ'm"DH1z OEYFI/y9ݪ 7oٜP=U}N-kN3_'m(^lV[Մ[tF(Npȍf1k [r ?]^V{~soo޼\#1a1bmZ]ͫbF{3B[@<$@Bnoo[|g˅bU yH`x/…&aX0x6Wwg0 ;~c?:.{\i0cYW`*UjάHgn|L?ě.O[6g Q56$X0YK-{&[P|gB= 'n8UulXbqn0u;33!ys2 B`;>y.?Y5X`؄5m k ,ҭ^TVx/S'Ә+6nIlLɫijvL۶+|cӁڊRPrhxRNICw^`N[SGY<\ 5@szNZcOTLQ߄ Gf^[Md"B O2;d.H_ܚ`ZKǬH-YDư5uJtnu 6B/9&(E xW@M$Ds(]d5M^+g>l%Xf;l, 'De=ҞFg m& ]iΕi2\CXK>mU2:iX35kLJ'vsjbF֒<؋bz /n2H@b#`\{p348?y^ V,zV\1L0:ִ\ d,b@l .Uc5au1?Kq9,%u |b)F  Y`^ƒR2yZ az>qXqI8)f=*+b5BزaNŝ'ыѳP:aa\91.cN+D(ma~Eӗ:Faς ~8e +Z K69}16GY"RbC`,?|ܑ)FdcVLT6D(qiY1.ÎQss9052h,)K(L\?Te&DNjg(vd Ф9dg׎5aؚKtƳ9J`/1;Of֞{WA3xy~:%kbx.I,Ij”ݩ4X\' qVۮqޫHORQfqɼñi؋T0O<56soCY eрJ;^cqIKH{X}L#g(C5hZ dW6]2c '~OY`Aȏ5w"ұKaoHv-5&m Ll8!kV :yXB]IVKPG,J>9؜SZ'I5Ҋ[c{ѴN,5[mu΢LjeumT5Mb]~j%17fsdxQ\@ď1۱ȕo# Fejρ0K1㹌mm֕aU鴢MJO.ahLI=Yy'ɴ!T39'GxY(>ԢX=Ƕ[DEitv9W C~Il4~bK@Rȹ+SѩJ^T*h)[Nt/&O |< WʷƂicnSȭ(`9cwZ1}K&QO}E/+Ϩ~IUyR+p#%Jf|:7*Q>2<^c=nX4٨MYPAsZ-B 2ZQ' 8un.GsCԕh+y+Ld KDFXc$ ˠu4q,yQ㓕`)S@ڨfgl#+Ep-9Y\v.F D8- 5$e jktg\M9؄ '޹ӉDr :{wGڮQECBdpI+gT,1hInr,Hޚt9}Bh}(r@1d&-3L`X- u +>D^!B;us>{O=p3QQ:eqMi\;p ]!7R}zM$ R}zVMFTy<~Qh8'mj(1!ȓVH0Ni|jvxHa\%T!ˍ$ (-gDcɋ\f'gD5.dcb8NUϡy5eobfY.n+!` E\0 U=m,P."m6ZLcO8'>~r| a;< a뎔`ٸ`*Oޛ,8j?sJGdGqUsY'dw5X6hZ`0 04 73`Ö,NYetjcNvsA:L*:$ԣR9z⢲!<ܙŰ*]@Wrl>FG$4Hp͹VD{=r:q7aIiN7  φp% K A9ԈzۆmNc|rsI3쒄RCh$àOϊ{:z` m#h3v<#pIpB('~kvn] n N\tHvf393Ox@$9]kP霱ԇvN`&cLk3 :03*T!tZ&ca`h d jL1 c`rɢv>^{b՘m@%N8+N}|iK3 C9vӉ8;(O'{/-Ͻh#@r %T,ZD8vrNm@bkÂ|9.N#wVa:zѡh\żW 3ŶN23$D5+yv"[ =e۵5:ɦS˪kas(4}Ȧx`IwC6NȈa\n굨$\M̈Kw>:^,Ic#mV+ٗb{Z :u=?ܾ˗4;P)%錗`I:(sɜ$e"8A̙XvK$=vAf%D]q=1'&И&<%N2c.x[.Ϸ7t/~/ҷcu&%0 d.Z<˙,MtށٺkTu};Jdg(_F2V"sJmhϩ2QE–]Ž8pa9چ(mC֒s.٨0), Z'R@`\ Oe!D{w_Wc/^H*[R-رaS:6E{\K08<.rZY9 FTED莠Y@F39rps%D1Ƙ0麛cnː%w)eh {66ϽBw f%+'MJ`d#yxu6NC[J kV뱣59$D;x<BTse>V|[x^O^]:yIk-.UsMDZGV*/Ƨ]W9C*gnI Gxoي;e9Ȉ"7'\gC/*V>) 2|CPw-3'.hB[@/ sP?C7 y5zm=B(Hjs\5ZT3N;:k 8`kJf`r8Y[cDHhKe#M)ygl?{` 15RE y):w ml"1Hi"s <{߿3y.iw}:'+f Y-ӨlmJ1`)YCG `\cBBtlj0v \ ۝w9 cU'~{(x[l3?:@{U9;fY)垺JdĹ]w?CӚ.ye"[rvH9)'l9yc% kͭYu!r?enF#9nڌ VB}.?C/253:-j ! )Fc K"nTs&-si_wK җy}wu0ipAo$F9a g˄7S0f^@E OL^{^Nl=U{xxftI` rŏj5Mq)>u/Ncw'Tب~dEhd3JEe ~[yLcW`Ⱦ$z !ĘqC5*u(e69 ߬= h{~N?M?,5ǝitC^SaX9Zc8bʜSZbߖ=GbWz>5͛/_9咯u{@]V=4$PV11Tf:ݜ{g,mٜwޞD~^Hȿx-51= ^{fO>Yu/q,QFxJ fyɵA_:#䶭xLZ+G1<&xBE*LE{xr`a()!N3Ы"FV5ܙVP^v8  5> A^ٖA0fYzSD+7-sn"[ 994uڷW/J_ͫC^?Oo(ȗ诉^=C'm[{5mpo嚏еqH'@{k "UQoYO#WXE(^iA47tQS-+}`}uկfxD/ DYy:Ǎ!ك\i͹MFk?j"Qyj}.yoȎ1jƚ,,豲;mN\ԧSWC\u>"wo.ݟ߽=y_wow lBs]~ssi \X7WOܜċg4,bvۜZ;VelF\#d@/ -@3R]>||L bF.|VkWwp |]6?ޣcY㨜jݽ |,Y l2O' xKuqswEeu^^7~.ۼx#>ۼכz͇ۏf ~wNXZ6k=MOGas}YA;OCVpp znq)sgonxQ=;I-pvZN=]IvHBlqbОi߮۫(ooޭχ!3:̻?'ۇs z{y7w Q'tq_.͛쫻>/j7׷7x̒/I ]o=69N.!YyxA,m$:.nog]!߭.Y~c"n{ON`B,Q h_|<.yoχMÛGy?~>y՗KJowP{$UU"^s^snbE虮3}f8rR_^F۫79|wQpxB9>U[cwXIMpxC a.88u}h_bqۚ+g(TV HL{,Y CrSnU7vA NjwJB|Ymȱ9z1YW?A;oń/xxސǎ9אfN T ӭ$6mOA۷;LZ` jRsAV6.-HybF`r≍"}{oC^}ET=HA'gqX=\mL;52 F 2'ͺ~ia]}uwy.3~Cu综}w7Wο}Vo ^|y/_d f]FqNFk uf@Qqpً6Wx u7;̟~Kyuտ۷oSaKj9c2E"-0S|w '.iT\ڙ >~'A=㋻kY&ؑ,nXX.xsθ9@dSM15hM/u,iqeRR^=>cޛR]UZxڟZ1=U~; JL.jP2[R6&I'kvxA_ƛ-zuۻa>:B9uCwX 6j0U%zC;u"~YN=y;|P0RTWnV ` 7Y Uʂ&9 { syļX9DiP0oQգa5jvެMDLL6)$h{$F6.Є j,ǵZ[I#!%!壯UlWDlFTf,) ѳVskMPr̹ {D!o_x<0vnۣc +o ˡcth"$j"`:Z9px}ֹhk&9s™THfRؔ2isSLSBdxc 1fSPPUZ` rx^r" 6?fhser*{uJaw |7>o,,HV+4҈쪔IAk\xGQ|]~i}OҷNGE6W-,ba1kMlahK]|uz[{ݷvR ʶZ k}\"VFam1:1Ot憎IĨnZ½ۄ.1`*P% LDy=!S\\1e M'ß(Sh P&[VX\QsN@ϫZݯu,JXV1dB9VWH&/2XgĉwdǞF{!ԅm\s,rM/LMuY+cҢ$[wA!N;* 'e(8]g}K"}z4'@Pɥ֩Z~6ysx}I1.sj]xQ(1;Rx9 WEf\.L<Ǜ ՆMlP:G]Ǹmh80h#^ra滜9^:;iPẏ ,DZq,!1(ULclY`2&wDEaB]ziAc"uo,uul0" 4=P\*iCW]u&*PF5t¾Hs&aG $u ]↲H;@=6P&S:6 sLj+[kmn% ps$.H.ܵߩ>8}|_iКm}v>pVkFk1vQ[8;/[}׮6{>4/;Q5=BE,3sE`}aSXp2<^H^}t?'v@}-%Ȍc`8" 4D0Am WVu6~_ǟNtxab1(Kp"wrZf1[k<;|w:nJݝy5Oڌfoiha+}p,F;tc}u5_boegKOQ"+Ѵ()\ ~x:|>caV& XI[@$:C\=9_sGSVy[?l6dl:{`vDfԢ\[29qĸÇ?ӫOaDGjÝ9'#OnHp G*鰲Dewx=mcݑ}]kIW \­iQjsMkp-q(U׫hGglBPin"kEIJؑCq* E~O*{jFQ)ER`;Tkwd4ĸ||I4 u2 QMf^\@Mn &Ia=uIl.H@̙lc FLČd$3j 2_e R#/W_>;&! ݌\s )BIRVw|(@[,K+=3w'sz8=U?S?ջN{oDXoԪUN-|tcK'6,( 偶JQU>|x1[ܜm|:PdE/iiY6Ur6 4Kbt@7hOD|{ =ls]Z#ù+h09rTpM@w>Ê^<g%lmd#:G(ܨf2HRˬc΅nEuIiNx5Ǭq$ٶHƴYn<˚/!IvQENQp$z Z>"c{F+gv6|tԇt<*)`Dch83/9Gׇ٠g w*9=_-9ٗPdct^cL#97TAvQ0nݨ1=yBC)5pԜ҄,wt6CP}{aQihvr(8gVPV)\ ]S}>ֆܬ;Undq֑ԗU^+/`1!8hVyYooOC,>9YĺcǬi8Vf! aLr0t@ƒ; ߏ?xO%]e6flbHGj!e+A3nӛށ98z},wD.Ze\Ò6C(2(F+û{=Z]s12PR Q 4>G+8@Z :(BKw#~z|zQ 嬾gUM[\iD`H*AݑZasB32P9y%R%:] Kh(~ϩ8???׏ڰ HY ܒK%U-f.!9cpTodpC[zOt@d-7Ur8k+"lmasͶ%K򘋬U =m_anB01)eRDB5QYxdh0HqNo d2Q1B#Ⱥo(4T-ІއXu ;mc͚͡LeRC(DA5@ATջDdQ$ݣT|>FW% g*g.ԗ ᎍF>Z dڔ](iMRjWKPElP;-Da;Ude>a*ԙ.QCkrṜڭYS-h\Kb͋魭З>(L'cEmewy6pEϙc̚V2Y입0>t ㍌&n}_`8CW@[AkY ,ưawaTsq˕o߂g oTc5*hٛ#E>\dCwacC욏G J]Z7M+`F*' 0&68\piF=B /3S $H&9nY>P|U4i<>n(4w`y "Gͥk6 A >`̮HFLRO/t~hyާ7➽v9C A2/v]aq׶PƘ(U$*㧛z9n}4Һ.k b,f\tqӚ񸇇t|62 /f4 = \ G 4X$^]ɤe]{?=޼8ޞ~bM;/!lX5@gsf۾ZZ9u CÀRZdsL+L`A\ś..쏌O> xK44Z j动r蜨#ALi,#U|.vذb_mNBi2@j:^_j[^Lgǟx#o*vLl-_UʀemFV& PI4!,nn1|zM 馍D Dӭ" bj8LqkZF B{<ǻ8γ=?*,}bSڋOXQ"dh(Β5 2ٛS'I Ie؞\9;8}6˲KiC=OMņ{o6:`(lRu-XGE$ͩbY%- Wꋯp9E^")dOجobŲY8 v: )^&, c םޜ~]J}:ZFĊsBl{A[m2+Ys]pMŮ_u;UHatokB-ȡ.ς q1/r|W8qoWjLZib5ʦetkC4\&)V%~Sv6(`bn/i#SL|Jrw4||~897}Oq>}o_1F=|`>_ObԶSL$tSXc0-r1Eɕ/zmCL Q=+/ lzVGRa},#C,3sgQ1(>PN^ɯ#mk`s\,$Q"B{Oټ0[:WѤWW%8x0"D7*ɢy5֤=eN j [hi$c #.y:x|v9m_lKe[1śWSY-gv #@6^9Td-1F owm/SfW=9^ߺ{Nh]!O4V\ lGfkա%# f<_9߰Zza=|ߺo:_,m%;|Yoa4;LGܼ-jJeK=VY: {b)֤ޢg:OXh]#}8]Nm.BhWDbTXX"&sB 0j9B8me8vͨ%PLXjRœn s\uOßgY/Oi|?t~ʺ!yzRs>e ="̪AscX}^Ȋf+`8US96bIUV1φ @PiS&b"ƶ?WuK~ys+Z/]^3 )"VAM(%d@}a +>?uG==L9ޗt7ȝ1 >sjcYxa L 5Kc]<0 ̲UkH'(k40jZF5Wj("5n79Tǧ8FQ<^Z={30U3ˢ:FωZk(*ږ Y^Dﺣ㏊I*$sDٝeb$*#/o 6/wyFj7IWtJI$dܚ9GhsC9'\(Tn*O"Ö LR}h:m)E:QhuUS8NZtM+;m6ͬW﹪7pm0=zZP@CpV)JS} J~|P ȟûQ;T.1JgPk1'5!M Cu>9AzFju Ix;m:`nFK\e%M&-FM2݇7>;}'_?eM77;V$K65Ys*QJC86sx՗UDU}Ik>qє%'sXj2^8Q}-QV9 8=> uIm՚uޘ.ޠAD} )m VF7I "?曳t|<׆=mO7Rn3h @^z12$}xĜb^}="ȑU]qa9lSrZHLc6ƴ2&^xx`Oސ6;UZrk6/-/a%7!op8l{h9=p92+1ANbO-^QZkLm2HGqS ǘܴDnWͳ0Lɍ5ZkI0؝&.pwr3/x:žIdĘiجeä4zً,)Ի8 =pMLݗ0l3p%6˨9|dKqT 94jBz[x|:DB5FA8gٴj4(M_uאbžn֬U6obܻ}w^N.7yaOl,=&hu_X,]uţ.:鲛.x2^19x-+O "[0,Hs8\bYA@*LoL7tb!h#kzNj0W 9`eqf<2FތeρƜmLH.Dcx šIWYh_x m'ASS8kVw8$m1@Yq> ɞeҘ6u([kz݆M4la5W✼"V@p~^G-Schkv'i͍[8*=e 䲪hYHPV<o .ϡ>UO4'MLi0{HLYMH{ X|l> ;ZaY%1cKXʋ":z*C>?=ugNiF"FZ(HLtJ~!-`V}v+ o=um|`ŮM \̌Hք|حntx=iwth=gY%bg̠_6fwBP;? Rۡq}輧ӻ|lߚ}ͷReޛ꾔qBDފzT NTCZj}sUlR_eRH*L#.kr2a i@(Zh 7.0b=[*?BPU.2g a>KE-%)>n?~o?><\wxwmF%y|TբO 5 &:6xÏY(`]p{N!+يnŧ ȥzFDӧ}YW2oFM't3i3 /=~q/j -j#V58B?.^??^wF dOv> .Uk=Aa6{1;j7G葳G)s|snN4gU6}._ 2 .Zj{3Pqkq|(5DvTw}{sav)&m{*_B]˴{­*nu~}zћëOǫtg bdo&5GQ rm*9 &p%fL_!O/)اoYHj7aə]D͡ #1$D`PuQesZl#Nؑa<%:[c$o/],}sun-Ѱx)xy|x~_|>vgGym|`}{U`r5rx G䐕 jM0n  {6vܾ5u,*%n>*/OY4Qٵܪ[#c9a]5]S(}/wfӧ $`f܉Ŕ4X .^Ϛxxob+:ʷGwH1W 52QYJ+5{׆>j1 9`\pO;xAzbsD9%g-ek=f<߼󏚜ٌ^rXs6(=d+ZcL(*nځx#$2~ ^ViQ,-Л! :sMջc.hmc:=]$9'i1Vw`^^(6jg3{[@uo7^4DcΣ!+_+|p^2w, U( Xi2ez; CK:v#yN^b~1w߄ݢC񣒿wa.EP2$a 3lOvkק=֖t7"M[QbCdAVAh8LX/Z'Gd@1{ށa6y{vƌZS)z5B7kɘ-E9[\w?vBnV6DZgjR+qiSR5»Q9+혋%Յj1{\]uc_HX@tUt2[g*j?(%t|:1^z5HJ{4鮭Xz싖x ^Gk:ذXYw 7I6$%2q&FB. 7J=Cڲle@^MPAqRuL];@}p:QǬ;]Lk 9 $iEH̱5qbBӹ&T7-GչߺLbʠ(6G5솚!W&Ww E۸RJaO)QZAYg Dtr>@!Y1ᅃBNgĀKl \LpKlG E*!mP@rkzIϥlj10L"WѠ[%U쎠()Kߜ'Y+cl9l 1R,HZ"4p $LWgwTq<_oy"2o:FUfeVO$ judŋm>UzC#I :X$BPs6\"#EFk'[FȞ!i~ӹ/G6'k6k9|wc~QNbw/ynhqe4 ZYL3 qsȬ&>|K.7ÿ+M8:}}ߓն}k :v+qZDcvu TRޅWu7ٞng![d^ rW놑<"h/sBy,'|U2;m_ŽL*EZ`Rjź%CA2 B3y'oom_}?ܫC^eo$fNJ,{rmש C_CeXQC!a`왓}ap@I.;zOHNg=Ve~gt~}ێVo'mUq"Iby:D-%#M&MG hY(/^j ^b/p})-Ҏ nka-'vA\=R%/O Y@~.ǧs<f#8vda޾A"j'Zt^SF5pl5f !;Q9_/X$2u>' bw2.nFX9)*]{#9A8:]W;Yaʰuޢ(+j9;lLa%8FZFdt{n8z殔~b(߼tu s2@:dcT-P wIxپи{KTܱ51W-{USL6.!=4|}%sޤ7 h\ͤ i\": Ћ92MQzS-9]o͆-{"aͬ/JG6N9z@2"̜>Ay Bpa9d}I@$ nέ7zGbđN`:V y/{g.{OaZ6h=c'`q+.[oҰ 3; s7/qw>=N)oaV?<嬆&۫Se6jҔbD2K%.H{{_KoY< }_8b)y{|:w??NjUu{☧g <_?!f~^OW;vt>ćWcӫ!wIۍI_]/ |;OE"wJ&^ad cxKHZ&ͼFOm,"eqG_|}Lw6n7R>R2[y:yiNh] jj>|80QcDXs?u<VTǧx?WC|Jt|:W<|rz>>WsW:=k^!G:o)_Jpqz~{S9uaܽ[s7-WN|;˼IƲ%jELtجTWI~u&jJx=Z HGf?sMkvO6,:S=rWXN*K!aRbAeGkR;ۤ 5`A{rrp7%s1E]Si&3>"C֥z!PK{=iΧx>QOȄ8ڂ\E^h*udAS&mŠJ4}^??9$qF306#fjmTR95Z BړGs:,zJ^f}biddYY05'p1rD hy2+'cx9|qu9^"θ3JMjb.u`u `}%RS)cuօRNA5=vϛ'zH{Tsuz }!QU%dT,z $Pb-y!ȷF?>_p eefVi?V5yvBN@>$=BMZY41b$ml2q6\^k;د&|Z])6)z9UlE˶n(ʲb ְv,h PUZ`B18SmIl,K!F $G8gBydk=jh5CVbT9D&ꌺ2"N)Ԕ:155#OM#l10;B.E2QWeՌZiea1OTt f4} *UJ;AsI1##/su*FKJ`3ll&U{I;Sqᴞ>?o1U ;R T!RJ֡f*[2报XW 7FxdcyAR)Bdtu\ՈEX RtY1czL>xL!@t%Q[gz 2S&S TRN*o_DfCunxsĄ&R޿ߦ挠xޢG<Aub K9?`OIj 3 {و,6h+8th`jJD9io"{` p K13cT0k5rɪ*WR*Ѧ5%b a.{ \(Or)hIVGJ'ֆrB>5$NLDid_qzS!T x KȲbK"}qO9SF\U&cAJEDr>\RɕPu!lSl0q}\c5=VSVX}Ξ2>V&Z]9E$Hը\#b$Fb Ϭ,i2#Q^9aI+UtU@$[Pư/1BΩrFd)j2jj$blՐX#e#f4<1gp]:FPu̩Ͷ.iqJ֍;(hic$>15T)"s,`VU#vUaHBނ*6nUu١e #=1!U{C Wv)1[r[&tTQ{1##.ABq0҅աX6h3ڒgoso7ơl{càHݑ#Gmܯ%%Js\tg.O/nPhZ~B($%$9( {k<r%1b*t/Fi'~qJOM+.Zc<[ )9PF+\WVg~'ޢN5FmuIC))r R\gc RjQ)ˠJ 9ȓͮp6kQ% yf&Q9FT%\С>Z"&O":-WU$fgZp>Wtzzw6[ $s.N8.Kju5%(ń1ЅJbfrda[9ׄ~ςR:Zk}h TRNIMљdCBp9&nR1)ojЅ jcd=!bHؘ\l@b4ɳ@Gln&9dk&G :_L:+#PcT>W(Ul@>hmUK9'{h٬5܌$);(.W1&Rh*yEИp" +3Sѩh1D1io)䨻v Fai6mvs#`} l]**WKM)Yg1caE*a4(?7ՄVdJX6S_ S.-*NSfCT-+Vޝ}=%^M{~f $d)RXd EVI.|(5S*jF6eⳮK9gL&bS6=@TA%2ٙ pX1ΐwfzj6RM-r9)Y ,P!GC^)\pkNZ :ֶQEkLIWͺHxø9 Dzz ˹k;_nBP^J.D1S:_|TfW*rT0x 7g s&H9g=VHK5r QYBʱD)֢Lr(lBY 'ÜK%Et:Ldc!7JfNEd\26T(c%i̞ 7Y?㦝PӦdXZ+Jml"TU)m:S#(4aqv|sz dh9t,)@THƚtKjV#j(H^?9y'1_7حdn>+WᕸL ͔MG_Tbm$6Eҙ} @ uDULW7-CrTy,73gYw3sH3LZ`'RĨk"|M.L O٢vJ=v8 yLO9-j$ MXɹRq?eJ ŋmjQ!1 Mn1q^r9(O:p&fhb:gCLL'{z~'{D{Z{3Ⳇ%, = O7c%j3Xȕ\eeR*sA^`mLUWAf=\z#9m QL5h 8D UMb:ddqWcNۤȌ=Q푿8&`VQIXm :uRlׇh)RJ_ry5w3]rA8bY[3L.+((!VR+* Oe69%?9\P$䊎"3W B5 J֖|cE]PaN?fJT @VLmuS1T-樒<9U?$c SƉc,Ւ;]rمg F_9DSh*&M>ԉ-m=4:V&MRB 9!(zpɱr9xm(J8.|˻'Pi;B*@qRQ0ʕCo#ޡCr{aΘ|6nzutfVK )hTrـƻctTub)~ }3-1^hd,9!T|.%z S !pp0!"_'H]ǪWvS\}9onŐ|N`+{_Z(cA]AT`͠9ŊRr2}ia?-$fRE r(B gH9Fw1/1WjսGNϨjFM 樭6#{ Z[2+kJ3ffQq|QuCWQ]kVs-`dmaԐK.>.š5ykqW=]1&áZVb)!1V[QoJp{mjPdf]{!?nQuɟwސڛ1q.aPC.ꢲ!lc>hqq5a\{x"~_;5@z[O^1|a^"{W8gG0oʟ޿4MO;MxM0&6ƒD d,sv'_65NU ,3#Դr\,r*z&ƒRiWEc&1# PR0Xhck1f+0og\ӳx)"n3^o!β˜RY4y?GC.#QUUXkO($`*rl Sn7MmXyzy,͜x#cZi2J⌳ *PBеdLն:O#κ~!дi-U{дQTEĪccH&XglpUv9fV.A &_6 2lE9Aeϖ/g ^Kwbl1E ʔk1DEuɪ%em kkdxsj7a1IؙXK*e E|V1jOsrHYf=zo"kq U s$}Bʚ b 4Q@K.x睅Cr!/x 2PǡyaiMIV)S c8e*0*SRb(6;g5*N>r}W~ϰIռ(aYGM7FAgY7~3[ %q5)c4v;8I/jxiΙMb\751 * up#Z?HsXefƄR XrHSҤj,9(V !2̜˰5BL\6сEXC(2=mx#/xѵv}6uٱN?H)d\Y{7>|N׋+3b=\Fs5ɯݲ]g!ayM ܿX8}tT]t>P1 ;SB&TX;Wf^lz~ Q;l+ޱu̩"Y Z{ )bv)mMt01y=~s nfa͐M$UXG9ҥ:LPUJ,grVV7\\^12<4dj(>Ps m!è+ltTax c Ǹ4vb(J+kmd%O[Be w yK, %a%h\tޠVTH:vaWJ)\{ܝ]_JE`0J=3&YyCJv3"N%?$W7y?}q1YWtքłcWm*rP&S8AYrJ%"o`ѝm3߰3_1 g}f}+/A3UAZAR&e"dkGML`M>Zޛf@hvBbmO9B)J!'43)%!gsJŖR<+*XkBoe{ɏa FMgmBg ZVuih!:8&] s_۵zg]r'g4M:A FP. ٺG~Η68UGR4$v9kb,^S)`UG4ٓmE'p,l&y-F==)Y%m11BeAkT)0@JQ[}QAUKLOKMGeمYNt jm#l\cJ}2тբ8gCi{]3tCW+/@t& iDRN*S*XT>J|I=>o]Zͼ_pΏ<^ˌ%* 9Sr6A*)SD!r%[.tZ5ǵHRjjXC74Fk/)DTcVp* [?)YLTs&'O]Wu*h3aDNa*3h}n_5bG)&62)S0XSpH)@ Vk.BN| /6X=|73cm6:z5[&NcI%rA13Sip_hs =]\Hr)%2"$,Ʀ/ų UŔLAN_cBɩ{If~6_ ]γlzȌ^ -/ĈIZh`䟟zApu1m%~٭q5UӼ_j%+Xr?>9Khy9/7'In8)U>{.X+4~4]yk89eָ3yz!-Xd!;CUAؠ(2 Jc6OwG9==/R%E@CFO*<2hL(Ezvi%N~<]퓺&@+H|v}kp݃fy''?vnKӏ0!j&cU\&)#d >OGߟS9'9'9 V9VUlU5&'*T2 uBP7?ژm֝!ʽo2OL:*S]eS!Aő1gZ.D@:j@ij>/W O֌]Kj"B;'DS?uh> {LM:eD%|BG,ƨ8{ՖB\VZܼ<כ#T7ϕ~_\]PVТhBP +b @ܛ8g'ď)Ĕ(a=_=f Py>vg(]ߵ݉[BBR8jFV_ť(K%C7.70$T4 X5ull#a hJ&x]AFh鰿^k8?p1tۅ~Պ-;PeejxQ '-=uzIm;^qm!;qxnyįnPFؕ;D "chλsֱ "9 m1gϠ%a-/&ujv@Dt/dEl!)h>o"V(+u =֬yE'.c BFC@DHI9HzohgJT]HB.+-&VXPŐQ!yq#ⶕ<1T\q%Bͭ,$B -7QDt=^@_?!㝠u6M-=.a !a.t K ;qI+قpv3? =~`P MYA EJ~p9]twDDGӏ-_nXP'QӮJnH踮WW m15w_X'"|&3Qѭ?n(顥ӱ}oh_PyU7^/@M!%WYI+AQrtlAHh-//#BMzH6nݬVѸ[0Z>W*{}/]Gq̿{vI yc:t77

[Ӯڡ;[^]?t_A7hC7QD4~_6/^p--M6,{,DBp>·9w1DTj}:MH1FqQ7<{qq_) .)y KAZ.ngo:LzP\u;bDHi߭V:At֭\ZʬJ~(oFvqЗ+ZȾ3}͏^o<%)h}vK>]]+[B]۟ח7%ٯ (R!;$/,$i]^qm$s.Υƕ$msӏSNos=;ǖAV80e#Jy]S`ܯP.=g~H.x.^\O(n7/(,`߬ڭg>ռZ  .`1%=k> j}v//B[sUvڟ}wvlΎv)(vqr6w2rf$A,K>k}.E(s:,v+C/T˱0ǵX_=X8%`v/p &pH*^. X^@K] /a -]-$]ts8mwwd~#xq9JNKQR*| yC͋pHk@9ג mI[~\6u#h]wSˢ;PDBvAf I[ϼV3l7,JkZ;7!pյ+oB̮ J_R?WV]O M5vIϿZ*C=y /a%y ϡ%I kN_^BX qҴ Ul}~=SJu fv-\ 6#9X;WPU<?/{/\WgO?4t\N"/K; ý]c8{-nХcVm]m 3яi.ʻ5Kބ0F>[5 2댛.vqa?v?HXA%駮gwbXTnGB%+cCH%=8"jwJv0Tڳc8_q Y ":{ȸy e;F;4K2j( uNhW,"̪c\=~T_I==:2f}JFg}.baHiι={Hr@Qtm^j~h "'?JhDFWcjCFŋ@?/"!)hZbl߃t'Ǽ*؋7qdԼ>]?,x21dT]v>{o،\Q+~6po ]/qVy=}lzOG O}f{"o~ζ`]0;{㪓 7|) -d=z.TONOtw2@?T|3/ A|}*6  ?D.}?nlIneU~ZN mH)2N`}.#hZx*} ylVC-eׄvhZnud^¢/rѪ̪e,V$\}.>?z"D?IVóR^\] lඛn#juVu9}CcIڝۀ?/u盭0Wԕ$war7eK2̭ s' 2̽ <2̣ $< 2Ϣ̳'q=]hIJ.lvQYFn%;Y!#9bdx.E}">tzOD='QOD}"3\wBob1>=a|z$Ÿm>p:w?}ό^ dj~DO[ꤞ !a=p Ò۵mxU.ZL wcJ$܅ Yt EDɸ^j-cCBňWKq;"*M`/|C@ѲY7Paͻ1$Tt.A7n(i,b]ܔVR)ÿ"c] T^jݴ獤o`eⳮ ${mt:")>C/aմM%m - }}'LWͺyøyC g~յj/J'{(JFt&AQ@V7}Khۏ;nZ:wHZNT65vErw{8gooD#;Zt}a1G6 ~j_}w![ D-j1jCgAv !wJTM %?'?j#;9mH:<_v+ѻG7Atjմ] M/U.!kI< l&OEw*~?5`hPJ[ílt~ADmƵm jI;k(tV%%3?as9lOJո"d^ȯ :궻 I)lEN6~D& [^2O„z}rHdcF/$rQEk]+pFs-K<#gzǿ@#i;@ -PKbf}Hbdv]w!(p"vA$tt(["/?/F^ =cXEدkY;"*ƾZq ǶD]Y5Vg%Nvڝp"wvĈnvN/?{XÛMIUSvs=?q,RXb|"D5$CwY)_ v?3g^w [-y,q25??[w7Q3Hys~!S J>{=Ns~V ܷFgzrH) J?ҢK[wHbeD/̟uCZh$h R(՟L8v6 n¯:* 6/c%9tձ!yJ l] ? .ŎM"4B"*F X!Bq!Ev+q]J}Jx:^6}34 <ނҭ{uv D4ȝ|Qp ^֙ځg5e좈(i#Ⱥ;^." Qv^[Fv1dT " $4Ewao`6f@hzYn^!K>xpv.WRnIy }7tBvʽ"Khy}q Fx! a BDcRv"?Ӱ\vZ5ka[C̍7JY,E \9T_JP})@ipI_#ݐBɩf~6"ie xW BSzNq PΛwr}9d_]?W- aCgQ?^GhCߝ|NONe(l~y-eNAHA7]ێ;2P؋&kxBPݩ·Fg6_K2* Un)]~IȻ1}ܫ߇g~u1V?Ppm%+BDu蔫U+(s 85\e*!Wr1vSc4WukDf4!G7uРڔX"W1 :Nejj"c<. ޲h\jZ!H:l!j-y2iCT9Xs!VN'9dy檭eWzV9׬*֘++rH:2Xf`۬ [JI驆IN%UL"b%D)&i]Rw@,(*$C )]&s>L~oXncsbgr U pƐ7HSI`&:+D@`σ~\\g62;ӥ:3*&/'s(L =k9EkxCdPk4ٕj塝vu Lv>0msA96Tgt"_I{@x)^Y\cߛ d&r4=Utu7OF֒(Үgj1 ~g)VB0m+͜ 3o5>/1t'j%$OoDNY^_%O>J+Blrbnb2 Cdj'_"R#U"oU/uX$x.2hm6mSW'3cXبպ5t7}zqywzx]s_>TsS'f@կt5 bI5h t:Fwfq1„/UX7uzT9-`yUxβs9u\}AK='8S[|/~C?קe>57˧'C>8ū=Hg?yx{ͯN lOwL7sF#qf"t4,tY,&h"m6`[9_|d|[w;X tjUUw1ڲP.uv>6F_͸;=>~j.>뜧קOߜΏ|W<}{@ߜ 1Z&*$5'RYܨ6c-bo~x۟<~r),5鹟 YphYb0hmzk]i´5ڭ&yw7Wڑ=@9Ԩ%D2ً*Z8u0!pJ1 #Qބ_3妐hMl0 VU@>Ry,l8(GcF7 6v،M53"EGZUoEˇ M^\}u;6QEi櫦2#=㨡Cp`,W  XU\nGiOՒ)*;^n}- K#p-Da872ְjdUR7_uLW:_F|6e/CNoOÏ9~yK|e/WNw\b̋6kV4ܥ%bpAţx@ wpXZ A8>\[Uy O?77y_?Um=tCL uA-\PԊ!ΎkI& }^LyR? ?9 h߃: ̠՝%$E8dH+ӆYYH^HiQKY2d_Oa]wЬ?[Iwn~m3e\ Fet5FlX,1W)y# SH,62z& Ehl+Z Fe1ݎFɎpaӭ9!2$h#4hg\p3,Oq8]}Uj*<kZĂk2aXdnhdp09iMg3oNo+=ߒ mnGUD0,2YfkUT\#;[n91Yݎ̛9;OwyF,lVCZS8FN{iX1v!ugzk䞵PqTּNoSٜ;qa%L={Qe߰Wl6L4[j9րEBlX\h o~]uM8oO ӱj_ِ(,ƌr[3ׂnp&#jv$_AHeƎIm,E/lՐ%L;vl<.uwy?Шƍw`B]bO$VgYЂX"WomMg c͔vݘoTmO\6ˋǰ^Mҳ5쳍NTح9UGm8|(0B^/f okɨHcYV[ m1DT_cY:Vx>˷|կ2;bR|KhSWMl*p`lfEA4|>?^|񊯏٦:xJ-Tb= N1Z 1wvƄ|Ç9}- źD D;2bv`9GQ{*o%|\\]a5c .5u`5aLndDrUve &7j˫GW<)Lu5XAhNsb۱yWuZ|Np ZaZeTQ7>?=tP/іi< {=iH(4IPqycwΛ|8?5WSL]Ç˲EC5l ꞔF &]DFMYwyczl  ~_C{&7;6WNnjԘ ԩ47.E3ԉa'OƧG͖Jhs, 21@H*H\psSoslvmlhdk>WekT,"<*a߬swٯ"øԐt_²SV%1ղ7Fnj#ܚr:Tqގa4Uqk}9+Z 1b">Fq"y4mј4[J9xc߬:_'cIl N֚hP.$\rQ]N Evp~ɿ<IA7^ez91YY dc!If PO^Sa yywOJkcE+HT ,l :@.{*0S4= ExW`ESMz_TE֩qeaݗu/yXZ=\s-HlnkNq`%!52x\5j͍x61ؼOۑHUKߞW ;i{̛@=td2ƫI/BqM|NgtV7 o_h?/0gKH/O|o*uN"^&AAo-e-#:ShjLIRKu=}Su޴߆xǭȭmȪw-[3K4$  氆ǰM燂}߿n b~Zhsqn.ĄgS#еC!O,lj40Y$)Y_GkPD+ 2qxۂhO&Ax̅5lMcaT1W${p&4e޽}(F~8Wjc. lΊD}65w\6t59Qp6$7>Gr(~FmHPfY\Kt-Q%ԆX2i9@1h=W󞚛e' c;W~rbZ5ӱ-gGYK$͂ ͛kE_7|Mjw;c^bZXt\A]"k:!Xnj94%ow1yøUU#S4c Y;)e[˦TZI_*c0۱S>_@;VL4>C/.t _~K[ÌOcKfXGbX]IKWaH͟: GH*hiLU`^9=:EiOXVqc"GHd@ ~;6=1Cia U*HPÒ"j &:MVZm"$4wjcc6yᚂH oGl,JD;&M}:rbc>($٤ x،PxyE}u: qL9.d*8 XZTU39T[Us:w=:.fdLǀKW). ڴLMWsİ.gju OǻW?dOzϻ c[]~ â5% f^]\ŨN Dh"BR-~V#D Wjྴ2t[k<#`jY]Pr>b_F^ P՜VGAb!>"S%ᘯ?LאR1:H s-owl*E,m6ӕRɋyp[fMҟ]~ <>ΏO]9{@3ay4FU4'\8Q$P 9ЯFݾg+\YO.3!9DX +Jar*3_gz3BoNu<\1 +<=ʘbkJZ:2s?́6HX=nwOOl+Ȟ%]d6i>4xFb+: q R!:W㧗W\C1 o[4z6LK g.B]W -έ,jANu{ 46Z_)ށJ{Nj!m s6`RD'97gqy <:Cv#(6%y8%Mr8 PC)kZ׉D5V7n~uݗlOxb{I-EXYVxˠ,Zb_̈́op|Ï=[ܶ{j YV8Q83Ԩk$FpE9E j=SUs|s8w1Z+’2Ֆ0lWb1a:?hQTokV}$QlU`VY⮢c s \iA@$(pܰ{u_-#{O9$pYIq;0ȏc;;kZD!8|vXft( {\,Xkum7GN~}{3<˗p_==%]^܃>dw_-+w G>EQ1 V pĘ&FNV)s/6j;*aD"ؾ'a’ƴ6 #) @XT͜yLu|ڎ^_6hbqZ%Ք! r1P%ssevVۧ|Wӆ=6>QzgQ%.6Rdv3N46mP7s=wOǹaҞǨZRH[ `R朒b!` \M ncQ ~8ƛOpw7[藡_ٱVnw#^ mQBӛHvT!lllny~z+~wigقE9LZN hc\-{aK/~4I4A OgOϏ  =ܙ1H1W>W8p,&b5(hrY_up} _4֖5 DckexbĐٔ;+i:e7п{>,@wcӇNEWK4ic>L0eU%A$ *?]c|s5GΥ|qUI{ì0m%콊 S^*ߟΧީ&x??Ay %Ƽ3b̈́  ҡwG"CrA!r$Cdɚί?E>ÿt~Hm'pN6r5 V}FӜ6kJ>E,v?uy3F Ɓd21V(5P̹ux_=ɡ̜?1W[]vQGgT4z4DIQ 9kc7kS?9n(ЎiƲ}_.abk 6V).oFĆRU"y zzI a.=I !*7`F0P=523kրhK ϖ}FM=bi8 Pzz2MKFӋ([C_=J4zoiש)TOZSvVpЎ}N".́%#r\귧ǻ:__{JSމJ}˰!6Xt42EðTݫoN/1ew?n渽!j"L鶫IRCV)y. {9lBIzʼ"tu6)(9on%yӢeytʚQK.g[ӛ+5=}B l*,]0grmdΥB::n=?T|}y:~WyjYaӓ`I$eK8zfrўI}L.7R}8cEj^]YPZuoй\w}0s,2M*3Ic ~u6jCq;1MsBa4NhՂ S\R;+  o7eۗ\kpKL'tZM v*I6ʙ @9|wwYp_nsypKaZidy5cAPeu*x} U=8g2:lvN[*,Vʋe6sSU#'*G,s̮,tvUe,*Z찌#9(*wXme1"Ϛ>fEXV5\yFjw  `:p'Ԡm&"׋aNK|q2Z B7*ݛzSXXV K&S/as r(A2T_"=W[)ϰunyF勛I:@&JdjQcg1"jzm|:iZhOXާ VYg(]m1*h1>Smc{+$QNtCS$) I"9 y#(C!=Cb }Yமhqf5-b-ӠA>捪峻~6,o7~RgwOo>SOoOދ#iD\9U MV(L-%4myq]ǞNsG,އ%xom4Wr "zj0L-?c6x {m~Q+3UF%hII"V:'CG[|wOuv|m F#1pȆK{nsmQ󧞇ZSGtĈ [LFhf1a8/E-L1y;މR}sbϰ5y=gNFT*XKH֜]? |ouwm&2pe >,201Bڂ1LmHg]oO&YG>5ˬ#V *w*>eh CRR]f%}vyn=0cQ4llʃKN+t|Α5.곻ëǫb^v}kK Az +PaeM%}5 Fd_}qz7~zmw5o޶33\cRgVj 04p^|E3q61xV=yz|=Ѣcs fVN#;keMӪ-/DEŒyO O7]o|WmPlU8uxRجPRzNaDg^Pka->m6Xo&6eNKxC:@ ZGPm`/dApκ))"rޮCh|s̎-g1ז5"o :O$].o]nbn?2qJ\fj!MncΖPh7sqw5܏=iFf>|x[`>@ko}UC|@o %䍨<ܽGMXIO WF 6mz+lFmuk3!s ,dQy{yXb{MK99'rFN XUڔh ζ3ș*JDP?\~ 5.ZkvFL'PJl`:{r.nDseƈt&_ry·]7+g۳nPh/S6i$sǐ#G!Dt5&ۀ+x|-ݎSaňQv `Fa7ڊvn-9y7׫X{ާ2oOinڐH`VșBmLL=࢑}t|.;Fn]՟[ ȣh$i qnΉFL(V#װHm]??g~>wh3 t D}4̃}..sI:.}meot:Cα9^NXz5B3"!P1WX\zB\^ m%or}B7眬8?lHOIz%5sMnsIk`5hnK[y[S}ަb˷y~ח!69i{aeZ_`@mRzL%xq((nN/A_x1뻟IF8?ޜm ZMlh%s9By? ib cC^,~wo6>h[LJ15B@aN9@Ϙs:Q<*vLvm A V`NR[iwB*mUB؟,_p; __կ~<;O/ C @Ÿ Jjб֔H.7޻EŸ@E޼{^ќ~\u0m_Hm b4ZKz- >c-m ETu!1۴߿7y{LwSwM78] [*%,k^y< L)gt] Ɵ ~]TʼR.D܎ҕFh7aUT2J(m@BsF+\R9dĐE`YX6G.K닸v<^nh0\Ɍ I/] ()'rI$0dUKuW:ԗ[.mg#åZ `I;V>BF])՝\k7qK>P'p𒧅7K*SKʓ ˊf!%p"%d>_Cn 4ܷ3AfuRskR[j֓n|pCG;gqñ傼 \0;blTp9\gjbfkVa3ySYѶSZ,>ya3;W#O籚gYBeSz8`?KꚎ9 (/*shbC•xMcoع$9hH?s@>зጟ $~zUvqdNGtI]o7_ZnYb DX\+2}pcQc(5y__9}q?_`6#׵?<]~AзO+C@CէsU&)" 0zUw9ZE85;|?n6px.W0f!ˆ=[uvW u8.6bdih1X= AC뇻Cƍ}8~A^.F.cZE1qcL UH48|u.mщx>},@Y|4=lr)Yk~0Ow"_qjLHsReeG؆A"#~\+a c$hV^RSLGI{s2fOKl!t>4o6$.D(%>uV*kh[&)(L)1˖L"۬ sO^ntdiCz#Rɀ1Y:er_]:swaYnp-+ quISKb4 A,RO^R0u3ߡ?cn'O.qeZ?\(KQZ7SҨwAF@Tȇ,ۜ[!a[.:s|O3WZy4/򿈻q}WW:QW\vׇYv^<%7CuwKJ~5>x]/ϿWa*+øUOf \A|om|7뒫W K경ci+\NB};POz>\0L&-)hKV?{0_oR>6m~ߊ?Wwǧ1wwG:\o꫸L^nz+.vj[~Q&qAۺ~4r5XcK=_ă &Q"f M\[Be]jr۳q/Y32VRս5Ԧ/T]Fi/df>ۓy>V!wݺLځ ॏټ!t^حi Sc?|~ Klt(̈́1҈sdEN\6; Fk"%1QH'WS( jƑkzLYB=01k+%V~j7_K?{vxvxv5J2?=<3}8qYNg1RWެԣ h惍Q9cɪ!&::Q6Q*=!1?N3&2xdO,3+2*#t1Ӡޘ90R-0wf l;mt`kc"#I]Ts`\N! $ڜ 2t.\h_Kv ]vt}J#Zp ìDPVkEkpʙnUz[i_Clp`r3SY#+xL锋{>o}h>R-xhX}} /Kܶ  ]{划5gtI܈I:̵<'6&0Lp..ė 6(loBs6cą :q4#l֠iV- bgcpwW7'#K+q LjH"(Cɴ4&, 2\ܱg@<߻ D@7VfRgHs:P`It O)X Ưp{wq+i.Ltq%K663-FpXaLFL%37w7~}5ypꋇ V?ux.ofw='\5*-\FU⥘8L M1025(b) 2gޡDW|lFm{ 4\>74VC'Bb[6sQS𷜾ٖⷻ$,~\fw؞慞hܙs ]cwmbtyɴCY "]Nn\UȌ]͟ܐ>^.958א6hxU.؊{-8Y#։Fgޡ#(F= 1}JUU`lj HӬ5zO.7qK9Gj98m9^suWAHg}Ά尫W+(w&_Zެ?{]bY[bCG X:[Vk=U=ŻH)#ExocO_ҷ0GLlYf"aNaC(8Jt9ٸWsxgOvs.ӯ{wW~Ot\n' ҙJaҐ^T<4Fk 8nH Fun}vsx?=ˇ8?=^a۽ /m{#CpL2]k`\Cfhs J3nd_ mDh ٥O (mb+bf˙Ւ湨ᯗv ͋W\7~8ǒ ɶ?aMi'wl< wό:k TU*美~ws{8]/L(xXFƄҦ`*6lMV2sK~yRr"9z-;yW̡|VOs\8ZKYVE qxyE]7.Fx՞2i{Sn$h({ .K/Y$ooQv?YKgO֓vS-.C1J1ZQNwE4?=."oΜQmN Gﮝ{j,@>2͕RRp`#*~8_Ns:xFPȷ7*V{A5d]5asu;@g:sŤ˵=IS Cq ^ԫY蕨_ڏ K[6u\ KCRAnYm'@o_~}vLr yi_gs|@%X,h(0)d7N't͆Sʙ­- V)E8Z賈vrON6wqKfEma5J2ww0b\㛝<{/'sElaQ}zgfkvpŽFEGJ1zM%`o5\Xq"cҷ-\5RʹA= HEͅ*vyǬV#NjG\ds\VxIAv]24N#.ρ(0jx6*w\/t7uGZ5Uc Rb*ġhZI+f"=}^=Gh.C-mxqs(BS Lgr/.$0* 1ܗQJ0XIE#MeFgpoKf dդ)T!N9KEVM̔Y1:I}B661Ə?|.a|!S tuW`nVIL-h'_ 2ΏyRm$טc%ci!Mh=!B<`x_Vd>V.Ic`fmtha%ޔqe77+U9>ۻM<8\o _&n_mgk9}=yp$og5@В:a'm"[GYއgӓg}:^2ety8k J$7XqQGA,Js<9$?Oe^2rT۝' VM̃f$GN QfZe@ W{O.hv6H,1Gm*b39L]wP9&5ɞ_اo]y;5Xvl` Tm-P` @pnO/ܭ% .7;G"'չoi\dۢF,E[&y w_} ..Si'iZvI}0R Ot{x/w77'S.̱=E&078Zqaj.4LBFGK]3{80C}*_`pE5٫/N_D`Beˆ3DKpAH9!iP%EJ*qw_W7+u:wvm}h]H[]-c( SQY2urɢ>;/$e=ؼ}YpIK^C-n`@CcLh&ZK4p̜* _t\Vbm8ukeGp^S*Mk ; 6?)6Wr[5K}, |Zˁ'[$8XjAoNhc̢Z%͞0 ^8$CXfLTeu.2x@Шnfk IG BTu]eNLY}IrQcq& ^·3%eq{$kћ[MiLy@2Savȸq7Uw`ҹ*I[dX@ 66'r zI-}UUo%pMY-XyX4dq?ڌPRAg;o7??à좦It{->.\[XYR5\ '58DT>$gٿ8?~ ~:N~I"()'*e]|Yجju})hQ϶tE% } "`u(2<=7420WfT<@UNItƠpB Ĭv(̒vɏ]AҦ+|8N73tKBc9wHXi 0QZytBg H8dy.!<_u͑tjtXzd&TU0^Fehs!?iw쒰: lV1 %-phe?zN8G% k! iq(h{VBF٨±P&&b&$P>Xlߡ?% W4Hdh.8{jkQjS!ky(Qn|`^W.d!ZА fuh xZd>Qؐk L#lQ49[~/\m~ Ӹ9=-XQ%zaRqCiU![ ‘ii繻;߽h ^< cr1:,lsU_ݾlrRE(ڳEӵ 2rQ!}TB[fq6Soͥ(_Z'P2ZvX>\%K#my*:PKr41p%[YS2f{Zfny.6cčKg^Cڟ}k6EmHz]Q!]Sc4mv٭:+@GM&\sg%C|o1f% ȊM XOj॑hG 9⨰I G%utЩڗV":G%¬'|h?(l/C|QoWƅזc#B@ǨjXx6J4ƘLPTv<qs{˸t/1ͣXmN7$lMX6ӂu>Ky4lg.oob ]FYGQ 5xtפ 0r" X ?iKK}+gAr0#3ȥs!H/6r<}&: {洽1&Z@G鑣G%NbSS٢֝5)}Yt4~{l_0U۽@k =gs&NZR(y,aoCMZ'>ݾ7CKB۫P`:A j&UĐiF<I}./zy>~vߍr>AQV[x^o۸]Ϳg񯱅hW\|*}_\MٳK_:ՁGք{6X %dT(PnF?翤烛"ͫz7ŕ~un*spoz;p||_nN= 6{~/q_>'ǻj_iFՂϞ+jI}/S?W}ųQvD_-I 'VR+|ԟ=|ɣ{?;]PEp{B!kg=3z#fb4{~5h_OVWd햶fˈˍT*eћqzhO(ɚY:Veftn?)&_>ɷVǟ쫦P_`}Ǧ9bd4[FՒcH\ëAg"h J1P' >a_!B~a#"]e;%pxu o!`UX1d Z-x]a @#}>`?#e y㷎_<7y|U߮_?v/3dYT׿\O}k}_kB6Uh4X.Îx zHDɧɖ Z,ڙ}{1h˪6m1:4U"p`NrS?'Ӌٍ8~f~2y\q$Z'6ɑe@< @ecX m,1SAV2&447/eop}3_h5ovj+,#|x&_7uݗuZK|%?!s:\3RhEѳY}% !G;f\V!aws/z/ fu3YMA'r!i닸/jř+ͧ֘,cS\?ݜ~_h[ N[1R5(,Q"ȪI3I1%H ct HcT[(mYɳı`SR//0D׏r !O3 z9i{/&YǐƑz m:g'Y:Q/0B`Afd<^g{x}/xgt3$Ce\pTO$Fi#GE>7cxpRL\,H~(noX{Chhx'84k8Y / QP?!9>=_ݮWsdJ =&BHR?~sfp2- ġ36&Bؒ`'Չ7O0?N^{"'x4,%c0," Qxr/nUՏCDI[ )].-JE/c1jZѤEOcAdp(n=YC ٽ:7:XugdjXwʚaOc,<~T:<{ۂ+J0 36}\xxW4lO}A|˙h7lsA P'6֬TADAP6ihjpЏ)n m9 ,v6.rh?5[q`n`>{GlokZd#~}$QJ &B8H|+(M"TߊNmsX >Rhg}˭c6Ǟ}^4-Ejy'YHά]ZζNq8MՕWDx|SOymki~-󭭛 H_8(gÚQ˓S}ڧ[S2Jb0h)xܸd76,ъZ`G7vRE'5[/_D/3kB>Z[i7$6+;Dpe Ԛ#_IC(i`ԮTVÏubu4 -N0Qx?9$SWAԖՂФ*s%G' =r<_tIEF}om<`]# *d;<^Ǝ.D3Ѹ},q8eY{cg-Yk>ϱ k{݂L&t>'Ĝ"P[ܡ|COpdӴp\'Lߊཌt#lfca.Jl`ȵN9ǹl@ey' 5c@a!.vEkM4>(u8mhp| #,e$=OҸ,;y}͐׶eSڐccǥi ^8>d[YA':S70Ф6#Վ&O#ь$Kʰu"Jp`\AhMd)9:Q(78jhۖh#mtL\[ᾪ,[/_ }b*ND3weR)zCs)GRx"6K$8 o~5P~ZL%朠6{pMs24 {jzM<VJxG@&sU}V x\`ozcC~v-*,!g0!cݛ(d1[A Q\ݿ~_"r~=?Gy`TsZd.#UkG;6;(B3K<>s 1"0aHV&8ήX 4x0~Oo Ӻݗh>r2s,GGU.QU:'q=7w??</I@Ea* iY8A9"oͱP)S5mۀ,J`a9AV U)Nan .7ҹxQ~bS(~ Y[B\QpZ<27n6#W]%DaLwOL9ȗB>frlʁm'y29ށw]F&MLEZ8T#k4$V=(l>%&k #Dtz`'҆0FTQb,;\5EsCÅ QF`fmځ/aޡB-/*_P>1QJaf'n#q*)g8<j:{COZ2 ~Ay?x\iX b}DÏj%#H3.gF9O?aT,g2&ktJL9F㹴a`#@Ҥ0۪GݫBNQQWKLBNV9+ķӿ?Pݭ/Bq 'Oe!Dфf<> lȲE_ \Èd#U-,r<:gCG[At3~ǒ_zyq0:w,x#}ր xClك^u"[n}ǭc侼pb^O,{sXHb9uj#]tyCȸA` m&HNǗ4y" & $`Яƕ\yFGv Jj>%k?~5/hkfZnCKN}oH7_R?,&hQZ!x@gG1&]NDgx (Q *KJ9HEn e] rޖf8O{ж~bo)}WK/qq@>6 cnt-МdžJw.~?~ ;}t8(3F\;Y~Qݔ7#J. 5:O hi(0?CwBFR cXg 6g4\>_D&[e%jqR(U'P@ĆF?Dw;¨d+qz~C`:>diYle /ٹP{@XuPmVX.i+7NX^ =hyʙ^rU=}5܁JchR-J!1^ lq1澾v˂o'c>6$S'Y>d<ʧV4s_ r[_-utr{|`ݵIL YظGkh7z.7)ܯG?H?!" t/؈J2+V,-SpÅ".Oʭ#}}z8$B0 g7עf歾I8}=??BƢ# Xc.XCG}@>Kcw';U\ ֊'ƾe?S:|'Is>.4+$Om);۝7\n,-/t& )L.pqQj4[>p*H??  }W>l:d; C03# :N`^*2ۧ_/CB|LW[-&im᱔\-9wqKt̚R93zb9gǬ% r`(o'j~Tg49Gic6] .Q\:݉s5G`Wé|p`t&G86̄dS}r29|0Mbj{e_z;߇½p?maR9a ւ:.ž-˺Vlh^lyǭsCoBvyい̡uMώ]1.AMYdHw~;}t1(*BAH1FTzႳΪ96כsa(|!œOq[ufSv :)7?FƝZY60l u4 ""4˓+>準K#Q1k/8zrVР4dw9hħ\ޤ7Iﯛ g#G:qҺ}jDsU0O S˟w~3?Ï|b0.Tו?*5$Z+{L mQ8Qúb/ۭt/sܙ1+'}D~%0GF׊"P9:e,VyB%}O}xknI< ݏLX={Ռ {3W S'FG uv"EPjlkzBqo'(X^D Z(8Nݲk%.Fvzu2)K1 ?l}bX-JI؞^4*Gac ip;R}{6fp,X޶p.`=t{" ,<_2N^ c!?3/t߽6 T%O鶑 aS`3m"v*؅ec"z++d^pzM )Z왩Kt_w8ShKS8Y߯k9(಴Hr{0|d丕EF3phܾu.wW ht*VUS0&bmً}[Xӣ/} }(OES7 K̈V'^8gHLo~:;E.8lȯsG>O :l"b)Э²xDyxY[qbEŽ>GHwi|:{<43ML cp^7n~j/ fuש55;Ll!^6PFXF7;zR{Fa Wp9Nw(9&PpJF%< K\?BVۺPvm^iU;7b9<ȟgrnEߜ2#Sg8- 9A l}4̊,eΚZدJ׼N^v}Vd.npOށdpזwX^4 %Qq&+$!z* #{7bܙٯxΪ9P {wL氙9<`L7fSb拏噹;oݫ ͊VaMsw B2mv|˽b޺`^zdhD5SGnӴwm|-|AKe9X2F*blVg?3鷚{<{ ec`CSx/kI0"YLͯs :2e+p0gAnM#lh?GH;3N0t/B.-c9"znJ?`-;h :Ɖ ls;:<4+p eQ= 3z:'2.'V¼u!5>xɩ) OXM|I6&;hU*A7nHE B̭#`)89 1Ub:y;#؉=W\VXD=7 -/䗄z/oϬ^Izp, 1AIkXp>MryKɇi0Qʕݷa"†Mp,=&?z/ q`aeQ T5:\v I7Ry}{t 1Ypd,s|m:r8jC-$gi?^/GnS\8bhgptMC$K gssʿ"s9ot9hE\kL* ?L`9{Ҳ u.-(y"Ry4 ٍz *,wX4p|Ϳ`<Yh~0sy*7,,؂$㮹ame;I^r6bdrہREVھHU5T7"LCWnJ|n-/\|UdD!Q πqkUІ i }`x *%ࢁss3WK+ʢ,d-k**2|]QkfmVb71V.騫6.+7;)ł]9ig @?JOɜq!X7ł.VGAa@ĉG0q%b<`.ߢ~ H ᶉ =LF4$CR 8J$.fXޟy4)ϼJ&Lll:<1`q_Dsdfo:͘ȱyMg`pjdءS^g!)&\{<ݫ4*O~M.k2秊o|BΆ5w0Cl\':w"+hBD'=F)6B`<\8uv{IAfd8C8d|z6#Y"OṴ>6Rמ-<o8C>IJڎl+-k$Ucsgٔމ秳]{*w:k JE&&VGnns݄ A%<%7 oa SgZ%{p Ү,aHuysIZ򌾪-㹨܂ӑM@3BFIOgZ+3Xi~eI"ވqb<=H`h#Gժ#ωK+l$Cgd V2[ftA2x*%]\;wl\=_y ` _?>S7V$ʼnA>NܻPm#lI}@m\)bC*r}e|Ay <2Fʵr]XlP%֪^)z`I;IϕgjbQx#xۑcr&ǡ(* s2bp̟/ oPӹwcƢTu8W%'/鳆%0bX?_ڊ"qEF uI{"t~H!;/,s̓ i%0<(1<V`֓M釧 q>gt=?2D A0>tåRzKE琺\(OtfO{M~VJD\V%k[cX˱;b=2d8r2ٿ?OžJo.qmg[ piXUw0>V$ +IΠ3d _S!}C-gQPD8elj2bMm[:{#c-mx6.j l~ Ɣy8ks! GG;󠢫3ꌑ~ͥOdPP\86*Dx _E~ן߿\ F8*⽾:i6}r=,oMI3 J?b2K!_KJ+/@t`~N!ZĴ6̓n'<ɫyf%WͳqF@|:%TZ5sBR{$Tܣr%Z>7?E:PseIK4Uv^G;)!*G98_61ZqbUű`P%]f_`7cU^c|ƨjs*f>J6$N kM@D?B`t(%Zj^婭F:\q9?M :wBsNl9=)?\ !3IB `@Va=0Q볔YD?鏏?ޯQ/ut_,dEws7W/*ωpM-9pCQ{PH1æwHGa*[Wfo|0Au0TJh4d۰Lm@V,?U2j_"!6ղմ`-̏U5P4kd['QrZ%>{>oE#Fd$*Ҷ{](!^Lf&m_~yc,z!5onE\p}F&s=-Wn!&~U*%hes?gWQz% B+k`?O䙎oi?QQ "ڍ›W5q0|q9'g*^)e=[&։}.9D`p;cʒ~̭SRLy f.7ڬky4D]zl2$eȽ]>柜T@43拽>h6]@*ܺW?b(O8\n.b2s`,zF&ܲΦ鎏~y׫dZ+}G֒.jŽ5'(:p_P|p>Lg?j~h71d{ڪ:S" [8:(WJ,t[g^r^;C-a|Fl||"wkEVX CfT,o ,yH۸@KXCypp"Ztח܎f }SZ$,ZҺM)!lP6}DViJӖ%0fK_Os`.HO%Lbˑ`,=䜥L#W8=wo܎eBE }@[ drOdq@C%Nj>wo\&N29:Ý͉04~$Mz΁pN˃V2 |̥JU%8z-1$ ~֎sɆ`1;JGL2 ?Ɇ~k?7?[lo7 ݎ0nhdl9 m{9N/ݪ6Υ{ᮭj>CM1MޗaIyRhKlڋ4v "*B%sl5`m9mE1iTϔe}eY',W7IWߋrvvqF ,; N@H^ƤK3x> U_O?~)x)6A 6O 夞E! s{|@m|G_r_w1J ֨nQwB=d踍h] g^pvoX02K#i2(|wvȼa[xD/fG$NN_sDzeGum*6&GaijxPuz|M^F<{A~u~J}F "p޸:}h J8l'daTBs Vw T ʏtکV[ G$"=luQ>>Ekl^Ub Zf4ȊF :ꔹq2>zXG- sl 8!j=Ƒ]VRx0D}Ͽ`'M_~y\,X!PĽ;Mw,В:8XL(!(L>dHw$7b ھ5rΎ%#ƩG mdM6<}^rg|E c]Z!smE=uy^! D_~.n[J½6,\'I-WCtPD2aɡ$u3/~BT 5SFO\?x!lݍRd]FFbON2– j ܒJT}m8+BypP%b'[C沃ۚґ|BMVז(hڇ 1>,rdy%(rFǿQF} 25[H6`I˶['nud8ھڅ{9#)yrzM 8^S;^riAl [*%oia OeJur4:dpzC- DIw9?~'yA8 չHyr5KW/ŀ8*D I3g'5|V󜭝\pu*--p6`.N,|/a{؎ v50wٍ;9wَ{d,g&[Dʆ0>(v[mK,n.@6d?F-<6!vMy fګOD%+ʭt̹H%k F&Cy-kJX{*@]_K7{w;;[fxCJv>>8X0 eb/m ]s_oBs'_;7,t<ԖS$ Haw+G.◐S8{|4ĸs8wbɽt.\E]^)YYTiAL` &^CHnɇ8KM%a/In!Hkqm6k}j!:"OUU 1Wؓ@,ʻ`P8+ :6QcH?m+R2bE\2ԼǴ<PrJ 1+DZ0x-h>{_΍+l 5rio؉u;06=dO#İ|"(NR#e%{\HX:Uo 1*f=/)fcಥy{Ě&uǞC;V.{-ߢS0=+ˣ; ^l)_";TεKYw1ŅA`kr,فW9vK,L frX]ld TJpv)sI :O<7˕4wʇyʥ6sM $jkZ/Ex ӮlEJ"W?֭>``5YԹiɎEe>QӰg#Op*M/.qz=O#k"aECp0ة/&Xt;*-W?ͻOgɀՏXX0e7U\x^5kh/XZ{y1~q0ޑAG'9E"fх^Lf טNa3ȫR"gb*jv."?묖1γql>%݇R:44 coqD4cMySCY٠f/[so܁ LdL{!ŭg9]1!&2Q|6HHb] SC:U~~V]GsEUw%IHsc )ux"t%B]|+a'|#gO:].]!$k#uay@&|6tЦZ/?%.Jv\Ø=lQJni|}HUfEZ֞Mt9<p ޺| &O.鹢臏xwDӟ&r.) > JYh7fVQ9R `N%Re縗Sg|+v!b[/:j :w("YJ!OGѮ؋xq^3S bM S㪚Wd,}uwXQ^{n+_p9RSAuVHNţ%hR\Aica QsnD&ChRX=V\&H=j9%"2[yɋV)ݶ1m5[;CȱsTUTD-a~-ī xޛ*K@(y(ڷj]jBjC/ᘜéRry%btKm1DDnVЖ/=T6LiWT7?B5t̅(CÖ-1<&^b޼P- $WHx~~OJyqً:$xhIJ FՐc.\F*VZšF6R$i*5v^gKDwFjU`ڵjKRGfIh%]p|^{"eS0 V(1Q8CoP/8N,8hj$0 Κ3#xCR3aы "e%}F׊_jA}s==)?ϕMvR̽ &(D/k]+w7#4i{]PQ]-ڝsI3A%8F^GL[y?8$*,OsO3X0hv)QCbdբTO {]8_L]jW/i)P8,Z䔤1ifmnh*$cܐ^MU2u$(ۜ fF!m6x=͠%D֫ɜ.Kt\LByK(!؍nbey_1Bܽ @ 9HO [ Aa#/D:&|+QAoħX輰bȴ\&{ D^S%rQr`U;tmЅr[˜A+aĮ 84Xx) MpѩX+u+ݒq) % @WCD ˔j.)h={+T/|`XVdy^P %r-5"l !l1,ӇgÇb {_6>S}OOq'ΗWS4-#{&%)ZKm e;Rb5Ay9w$ToWO.Wlޑ9VvνwNB="rڙ4VStkSF.9-uU?}zm_T|zuv-t&W5&C\ʫ&y ӆw20<$~s뇇ڲ=m,7|˷gջo~g+b6EkI\ qf=c qgb&SڶkbnnqQa Z)eFX2$wj >e΃ϳ5c9c9_Z,2wEeQړhy0x~[>/w^f =}8:Nasl4L ΁UHڮ?==*)+KB(Q72{Pɻ=Iap҉bY=e44#{bl?O]~C'X=~}9wpn_>CH[Oǧw_նrKr;aiC:6uZ#B]̳ԊtvDtR05I,m3 Hv9Fc!·#{s~s}~}=̿^$|%|U(XHgY{ӯÇo{zNAh_{S~A!A||f9!kƏq>*a㻯nh7ŭmsOQ3^)BQ=cEmV |B^ɃyDA(W:`͗ 50@Dvǟo*VouB;Wm7V>ؚo33O߽{x1o}%E<ߟ_nydus-snapshotter-0.13.4/pkg/store/000077500000000000000000000000001453374237200172405ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/store/daemonstore.go000066400000000000000000000033411453374237200221100ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package store import ( "context" "github.com/containerd/nydus-snapshotter/pkg/daemon" "github.com/containerd/nydus-snapshotter/pkg/rafs" ) type DaemonRafsStore struct { db *Database // save daemons in database } func NewDaemonRafsStore(db *Database) (*DaemonRafsStore, error) { return &DaemonRafsStore{ db: db, }, nil } // If the daemon is inserted to DB before, return error ErrAlreadyExisted. func (s *DaemonRafsStore) AddDaemon(d *daemon.Daemon) error { // Save daemon info in case snapshotter restarts so that we can restore the // daemon states and reconnect the daemons. return s.db.SaveDaemon(context.TODO(), d) } func (s *DaemonRafsStore) UpdateDaemon(d *daemon.Daemon) error { return s.db.UpdateDaemon(context.TODO(), d) } func (s *DaemonRafsStore) DeleteDaemon(id string) error { return s.db.DeleteDaemon(context.TODO(), id) } func (s *DaemonRafsStore) WalkDaemons(ctx context.Context, cb func(d *daemon.ConfigState) error) error { return s.db.WalkDaemons(ctx, cb) } func (s *DaemonRafsStore) CleanupDaemons(ctx context.Context) error { return s.db.CleanupDaemons(ctx) } func (s *DaemonRafsStore) AddRafsInstance(r *rafs.Rafs) error { return s.db.AddRafsInstance(context.TODO(), r) } func (s *DaemonRafsStore) DeleteRafsInstance(snapshotID string) error { return s.db.DeleteRafsInstance(context.TODO(), snapshotID) } func (s *DaemonRafsStore) WalkRafsInstances(ctx context.Context, cb func(*rafs.Rafs) error) error { return s.db.WalkRafsInstances(ctx, cb) } func (s *DaemonRafsStore) NextInstanceSeq() (uint64, error) { return s.db.NextInstanceSeq() } nydus-snapshotter-0.13.4/pkg/store/database.go000066400000000000000000000167251453374237200213460ustar00rootroot00000000000000/* * Copyright (c) 2021. Ant Financial. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package store import ( "context" "encoding/json" "os" "path/filepath" "time" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/daemon" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/pkg/rafs" "github.com/pkg/errors" bolt "go.etcd.io/bbolt" ) const ( databaseFileName = "nydus.db" ) // Bucket names: // Buckets hierarchy: // - v1: // - daemons // - instances var ( v1RootBucket = []byte("v1") // Nydusd daemon instances. // A daemon may host one (dedicated mode) or more (shared mode) RAFS filesystem instances. versionKey = []byte("version") daemonsBucket = []byte("daemons") // RAFS filesystem instances. // A RAFS filesystem may have associated daemon or not. instancesBucket = []byte("instances") ) // Database keeps infos that need to survive among snapshotter restart type Database struct { db *bolt.DB } // NewDatabase creates a new or open existing database file func NewDatabase(rootDir string) (*Database, error) { f := filepath.Join(rootDir, databaseFileName) if err := ensureDirectory(filepath.Dir(f)); err != nil { return nil, err } opts := bolt.Options{Timeout: time.Second * 4} db, err := bolt.Open(f, 0600, &opts) if err != nil { return nil, err } d := &Database{db: db} if err := d.initDatabase(); err != nil { return nil, errors.Wrap(err, "failed to initialize database") } return d, nil } func ensureDirectory(dir string) error { if _, err := os.Stat(dir); os.IsNotExist(err) { return os.MkdirAll(dir, 0700) } return nil } func getDaemonsBucket(tx *bolt.Tx) *bolt.Bucket { bucket := tx.Bucket(v1RootBucket) return bucket.Bucket(daemonsBucket) } func getInstancesBucket(tx *bolt.Tx) *bolt.Bucket { bucket := tx.Bucket(v1RootBucket) return bucket.Bucket(instancesBucket) } func updateObject(bucket *bolt.Bucket, key string, obj interface{}) error { keyBytes := []byte(key) value, err := json.Marshal(obj) if err != nil { return errors.Wrapf(err, "marshall key %s", key) } if err := bucket.Put(keyBytes, value); err != nil { return errors.Wrapf(err, "put key %s", key) } return nil } func putObject(bucket *bolt.Bucket, key string, obj interface{}) error { keyBytes := []byte(key) if bucket.Get(keyBytes) != nil { return errors.Errorf("object with key %q already exists", key) } value, err := json.Marshal(obj) if err != nil { return errors.Wrapf(err, "marshall %s", key) } if err := bucket.Put(keyBytes, value); err != nil { return errors.Wrapf(err, "put key %s", key) } return nil } // A basic wrapper to retrieve a object from bucket. func getObject(bucket *bolt.Bucket, key string, obj interface{}) error { if obj == nil { return errdefs.ErrInvalidArgument } value := bucket.Get([]byte(key)) if value == nil { return errdefs.ErrNotFound } if err := json.Unmarshal(value, obj); err != nil { return errors.Wrapf(err, "unmarshall %s", key) } return nil } func (db *Database) initDatabase() error { var notV1 = false var version string err := db.db.Update(func(tx *bolt.Tx) error { bk := tx.Bucket(v1RootBucket) if bk == nil { notV1 = true } // Must create v1 bucket bk, err := tx.CreateBucketIfNotExists(v1RootBucket) if err != nil { return err } if _, err := bk.CreateBucketIfNotExists(daemonsBucket); err != nil { return errors.Wrapf(err, "bucket %s", daemonsBucket) } if _, err := bk.CreateBucketIfNotExists(instancesBucket); err != nil { return errors.Wrapf(err, "bucket %s", instancesBucket) } if val := bk.Get(versionKey); val == nil { version = "v1.0" } else { version = string(val) } return nil }) if err != nil { return err } if notV1 { if err := db.tryTranslateRecords(); err != nil && !errors.Is(err, errdefs.ErrNotFound) { return errors.Wrapf(err, "convert old database") } } if version == "v1.0" { if err := db.tryUpgradeRecords(version); err != nil && !errors.Is(err, errdefs.ErrNotFound) { return errors.Wrapf(err, "convert old database") } } return nil } func (db *Database) Close() error { err := db.db.Close() if err != nil { return errors.Wrapf(err, "failed to close boltdb") } return nil } func (db *Database) SaveDaemon(ctx context.Context, d *daemon.Daemon) error { return db.db.Update(func(tx *bolt.Tx) error { bucket := getDaemonsBucket(tx) var existing daemon.ConfigState if err := getObject(bucket, d.ID(), &existing); err == nil { return errdefs.ErrAlreadyExists } return putObject(bucket, d.ID(), d.States) }) } func (db *Database) UpdateDaemon(ctx context.Context, d *daemon.Daemon) error { return db.db.Update(func(tx *bolt.Tx) error { bucket := getDaemonsBucket(tx) var existing daemon.ConfigState if err := getObject(bucket, d.ID(), &existing); err != nil { return err } return updateObject(bucket, d.ID(), d.States) }) } func (db *Database) DeleteDaemon(ctx context.Context, id string) error { return db.db.Update(func(tx *bolt.Tx) error { bucket := getDaemonsBucket(tx) if err := bucket.Delete([]byte(id)); err != nil { return errors.Wrapf(err, "delete daemon %s", id) } return nil }) } // Cleanup deletes all daemon records func (db *Database) CleanupDaemons(ctx context.Context) error { return db.db.Update(func(tx *bolt.Tx) error { bucket := getDaemonsBucket(tx) return bucket.ForEach(func(k, _ []byte) error { return bucket.Delete(k) }) }) } func (db *Database) WalkDaemons(ctx context.Context, cb func(info *daemon.ConfigState) error) error { return db.db.View(func(tx *bolt.Tx) error { bucket := getDaemonsBucket(tx) return bucket.ForEach(func(key, value []byte) error { states := &daemon.ConfigState{} if err := json.Unmarshal(value, states); err != nil { return errors.Wrapf(err, "unmarshal %s", key) } return cb(states) }) }) } // WalkDaemons iterates all daemon records and invoke callback on each func (db *Database) WalkRafsInstances(ctx context.Context, cb func(r *rafs.Rafs) error) error { return db.db.View(func(tx *bolt.Tx) error { bucket := getInstancesBucket(tx) return bucket.ForEach(func(key, value []byte) error { instance := &rafs.Rafs{} if err := json.Unmarshal(value, instance); err != nil { return errors.Wrapf(err, "unmarshal %s", key) } return cb(instance) }) }) } func (db *Database) AddRafsInstance(ctx context.Context, instance *rafs.Rafs) error { return db.db.Update(func(tx *bolt.Tx) error { bucket := getInstancesBucket(tx) return putObject(bucket, instance.SnapshotID, instance) }) } func (db *Database) DeleteRafsInstance(ctx context.Context, snapshotID string) error { return db.db.Update(func(tx *bolt.Tx) error { bucket := getInstancesBucket(tx) if err := bucket.Delete([]byte(snapshotID)); err != nil { return errors.Wrapf(err, "instance snapshot ID %s", snapshotID) } return nil }) } func (db *Database) NextInstanceSeq() (uint64, error) { tx, err := db.db.Begin(true) if err != nil { return 0, errors.New("failed to start transaction") } defer func() { if err != nil { if err := tx.Rollback(); err != nil { log.L.WithError(err).Errorf("Rollback error when getting next sequence") } } }() bk := getInstancesBucket(tx) if bk == nil { return 0, errdefs.ErrNotFound } seq, err := bk.NextSequence() if err != nil { return 0, err } if err := tx.Commit(); err != nil { return 0, err } return seq, nil } nydus-snapshotter-0.13.4/pkg/store/database_compat.go000066400000000000000000000141221453374237200226760ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package store import ( "context" "encoding/json" "io" "os" "path" "path/filepath" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/pkg/daemon" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/pkg/rafs" "github.com/pkg/errors" bolt "go.etcd.io/bbolt" ) const SharedNydusDaemonID = "shared_daemon" type CompatDaemon struct { ID string SnapshotID string ConfigDir string SocketDir string LogDir string LogLevel string LogToStdout bool SnapshotDir string Pid int ImageID string FsDriver string APISock *string RootMountPoint *string CustomMountPoint *string } func (db *Database) WalkCompatDaemons(ctx context.Context, handler func(cd *CompatDaemon) error) error { return db.db.View(func(tx *bolt.Tx) error { bucket := tx.Bucket(daemonsBucket) if bucket == nil { return errdefs.ErrNotFound } return bucket.ForEach(func(key, value []byte) error { d := &CompatDaemon{} if err := json.Unmarshal(value, d); err != nil { return errors.Wrapf(err, "unmarshal %s", key) } return handler(d) }) }) } // Snapshotter v0.3.0 and lower store nydusd and rafs instance configurations in the different folders. func RedirectInstanceConfig(new, old string) error { oldConfig, err := os.Open(old) if err != nil { return err } defer oldConfig.Close() err = os.MkdirAll(filepath.Dir(new), 0700) if err != nil { return err } newConfig, err := os.Create(new) if err != nil { return err } defer newConfig.Close() _, err = io.Copy(newConfig, oldConfig) if err != nil { return err } return nil } func (db *Database) tryTranslateRecords() error { log.L.Info("Trying to translate bucket records...") daemons := make([]*CompatDaemon, 0) err := db.WalkCompatDaemons(context.TODO(), func(cd *CompatDaemon) error { daemons = append(daemons, cd) return nil }) if err != nil { return err } var sharedMode = false var configDir string // Scan all the daemons if it is started as shared mode last time for _, d := range daemons { if d.ID == SharedNydusDaemonID { sharedMode = true } else if configDir == "" { configDir = d.ConfigDir } } for _, d := range daemons { var mp string var newDaemon *daemon.Daemon if sharedMode { if d.ID == SharedNydusDaemonID { oldConfig := path.Join(configDir, "config.json") newConfig := filepath.Join(filepath.Dir(configDir), SharedNydusDaemonID, "config.json") newDaemon = &daemon.Daemon{ States: daemon.ConfigState{ ID: d.ID, ProcessID: d.Pid, APISocket: path.Join(d.SnapshotDir, "api.sock"), FsDriver: d.FsDriver, Mountpoint: *d.RootMountPoint, LogDir: d.LogDir, LogLevel: d.LogLevel, // Shared daemon does not need config file when start ConfigDir: filepath.Dir(newConfig), }} if err := RedirectInstanceConfig(newConfig, oldConfig); err != nil { log.L.WithError(err).Warnf("Redirect configuration from %s to %s", oldConfig, newConfig) } } else { // Redirect rafs instance configuration files. We have to do it here to // prevent scattering compatibility code anywhere. oldConfig := path.Join(d.ConfigDir, "config.json") newConfig := path.Join(filepath.Dir(d.ConfigDir), SharedNydusDaemonID, d.SnapshotID, "config.json") log.L.Infof("Redirect configuration to %s", newConfig) if err := RedirectInstanceConfig(newConfig, oldConfig); err != nil { log.L.WithError(err).Warnf("Redirect configuration from %s to %s", oldConfig, newConfig) } } } else if !sharedMode { mp = *d.CustomMountPoint newDaemon = &daemon.Daemon{ States: daemon.ConfigState{ ID: d.ID, ProcessID: d.Pid, APISocket: path.Join(d.SocketDir, "api.sock"), FsDriver: d.FsDriver, Mountpoint: mp, LogDir: d.LogDir, LogLevel: d.LogLevel, ConfigDir: d.ConfigDir, }} } var instance *rafs.Rafs if !sharedMode { instance = &rafs.Rafs{ SnapshotID: d.SnapshotID, ImageID: d.ImageID, DaemonID: d.ID, SnapshotDir: path.Join(d.SnapshotDir, d.SnapshotID), Mountpoint: path.Join(d.SnapshotDir, d.SnapshotID, "mnt"), } } else if sharedMode && d.ID != SharedNydusDaemonID { instance = &rafs.Rafs{ SnapshotID: d.SnapshotID, ImageID: d.ImageID, DaemonID: SharedNydusDaemonID, SnapshotDir: path.Join(d.SnapshotDir, d.SnapshotID), Mountpoint: path.Join(*d.RootMountPoint, d.SnapshotID), } } if newDaemon != nil { if err := db.SaveDaemon(context.TODO(), newDaemon); err != nil { return err } } if instance != nil { if err := db.AddRafsInstance(context.TODO(), instance); err != nil { return err } } } return nil } func (db *Database) tryUpgradeRecords(version string) error { log.L.Infof("Trying to update bucket records from %s to v1.1 ...", version) if version == "v1.0" { daemons := make([]*daemon.ConfigState, 0) err := db.WalkDaemons(context.TODO(), func(cd *daemon.ConfigState) error { daemons = append(daemons, cd) return nil }) if err != nil { return err } for _, d := range daemons { if d.DaemonMode == "" { if d.FsDriver == config.FsDriverFscache { d.DaemonMode = config.DaemonModeShared } else if d.FsDriver == config.FsDriverFusedev { if d.Mountpoint == config.GetRootMountpoint() { d.DaemonMode = config.DaemonModeShared } else { d.DaemonMode = config.DaemonModeDedicated } } var daemon = daemon.Daemon{States: *d} err := db.UpdateDaemon(context.TODO(), &daemon) if err != nil { return errors.Wrapf(err, "upgrade daemon instance %s", d.ID) } } } } err := db.db.Update(func(tx *bolt.Tx) error { bk := tx.Bucket(v1RootBucket) if bk != nil { return bk.Put(versionKey, []byte("v1.1")) } return errors.New("boltdb is not v1") }) return err } nydus-snapshotter-0.13.4/pkg/store/database_test.go000066400000000000000000000043211453374237200223720ustar00rootroot00000000000000package store import ( "context" "io" "os" "testing" "github.com/containerd/nydus-snapshotter/pkg/daemon" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func Test_daemon(t *testing.T) { rootDir := "testdata/snapshot" err := os.MkdirAll(rootDir, 0755) require.Nil(t, err) defer func() { _ = os.RemoveAll(rootDir) }() db, err := NewDatabase(rootDir) require.Nil(t, err) ctx := context.TODO() // Add daemons d1 := daemon.Daemon{States: daemon.ConfigState{ID: "d1"}} d2 := daemon.Daemon{States: daemon.ConfigState{ID: "d2"}} d3 := daemon.Daemon{States: daemon.ConfigState{ID: "d3"}} err = db.SaveDaemon(ctx, &d1) require.Nil(t, err) err = db.SaveDaemon(ctx, &d2) require.Nil(t, err) err = db.SaveDaemon(ctx, &d3) assert.Nil(t, err) require.Nil(t, err) // duplicate daemon id should fail err = db.SaveDaemon(ctx, &d1) require.Error(t, err) // Delete one daemon err = db.DeleteDaemon(ctx, "d2") require.Nil(t, err) // Check records ids := make(map[string]string) _ = db.WalkDaemons(ctx, func(info *daemon.ConfigState) error { ids[info.ID] = "" return nil }) _, ok := ids["d1"] require.Equal(t, ok, true) _, ok = ids["d2"] require.Equal(t, ok, false) _, ok = ids["d3"] require.Equal(t, ok, true) // Cleanup records err = db.CleanupDaemons(ctx) require.Nil(t, err) ids2 := make([]string, 0) err = db.WalkDaemons(ctx, func(info *daemon.ConfigState) error { ids2 = append(ids2, info.ID) return nil }) require.Nil(t, err) require.Equal(t, len(ids2), 0) } func TestLegacyRecordsMultipleDaemonModes(t *testing.T) { src, _ := os.Open("testdata/nydus_multiple_compat.db") defer src.Close() dst, _ := os.Create("testdata/nydus.db") t.Cleanup(func() { os.RemoveAll("testdata/nydus.db") }) _, err := io.Copy(dst, src) require.Nil(t, err) dst.Close() _, err = NewDatabase("testdata") assert.Nil(t, err) } func TestLegacyRecordsSharedDaemonModes(t *testing.T) { src, _ := os.Open("testdata/nydus_shared_compat.db") defer src.Close() dst, _ := os.Create("testdata/nydus.db") t.Cleanup(func() { os.RemoveAll("testdata/nydus.db") }) _, err := io.Copy(dst, src) require.Nil(t, err) dst.Close() _, err = NewDatabase("testdata") assert.Nil(t, err) } nydus-snapshotter-0.13.4/pkg/store/testdata/000077500000000000000000000000001453374237200210515ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/store/testdata/nydus_multiple_compat.db000066400000000000000000002000001453374237200257700ustar00rootroot00000000000000 ռ  )_$& .R3cdnji9s58hm3b175j3q0{"ID":"cdnji9s58hm3b175j3q0","SnapshotID":"4201","ConfigDir":"/var/lib/containerd-nydus/config/cdnji9s58hm3b175j3q0","SocketDir":"/var/lib/containerd-nydus/socket/cdnji9s58hm3b175j3q0","LogDir":"/var/lib/containerd-nydus/logs/cdnji9s58hm3b175j3q0","LogLevel":"info","LogToStdout":false,"SnapshotDir":"/var/lib/containerd-nydus/snapshots","Pid":3995227,"ImageID":"hub.byted.org/gechangwei/java:latest-nydus-v6","DaemonMode":"multiple","FsDriver":"fusedev","APISock":null,"RootMountPoint":null,"CustomMountPoint":"/var/lib/containerd-nydus/snapshots/4201/mnt"}cdnjijs58hm3b175j3qg{"ID":"cdnjijs58hm3b175j3qg","SnapshotID":"4225","ConfigDir":"/var/lib/containerd-nydus/config/cdnjijs58hm3b175j3qg","SocketDir":"/var/lib/containerd-nydus/socket/cdnjijs58hm3b175j3qg","LogDir":"/var/lib/containerd-nydus/logs/cdnjijs58hm3b175j3qg","LogLevel":"info","LogToStdout":false,"SnapshotDir":"/var/lib/containerd-nydus/snapshots","Pid":3995565,"ImageID":"hub.byted.org/gechangwei/wordpress:latest-nydus-v6","DaemonMode":"multiple","FsDriver":"fusedev","APISock":null,"RootMountPoint":null,"CustomMountPoint":"/var/lib/containerd-nydus/snapshots/4225/mnt"} .R-cdnji9s58hm3b175j3q0{"ID":"cdnji9s58hm3b175j3q0","SnapshotID":"4201","ConfigDir":"/var/lib/containerd-nydus/config/cdnji9s58hm3b175j3q0","SocketDir":"/var/lib/containerd-nydus/socket/cdnji9s58hm3b175j3q0","LogDir":"/var/lib/containerd-nydus/logs/cdnji9s58hm3b175j3q0","LogLevel":"info","LogToStdout":false,"SnapshotDir":"/var/lib/containerd-nydus/snapshots","Pid":3995227,"ImageID":"hub.byted.org/gechangwei/java:latest-nydus-v6","DaemonMode":"multiple","FsDriver":"fusedev","APISock":null,"RootMountPoint":null,"CustomMountPoint":"/var/lib/containerd-nydus/snapshots/4201/mnt"}cdnjijs58hm3b175j3qg{"ID":"cdnjijs58hm3b175j3qg","SnapshotID":"4225","ConfigDir":"/var/lib/containerd-nydus/config/cdnjijs58hm3b175j3qg","SocketDir":"/var/lib/containerd-nydus/socket/cdnjijs58hm3b175j3qg","LogDir":"/var/lib/containerd-nydus/logs/cdnjijs58hm3b175j3qg","LogLevel":"info","LogToStdout":false,"SnapshotDir":"/var/lib/containerd-nydus/snapshots","Pid":0,"ImageID":"hub.byted.org/gechangwei/wordpress:latest-nydus-v6","DaemonMode":"multiple","FsDriver":"fusedev","APISock":null,"RootMountPoint":null,"CustomMountPoint":"/var/lib/containerd-nydus/snapshots/4225/mnt"}daemonsdaemonsnydus-snapshotter-0.13.4/pkg/store/testdata/nydus_shared_compat.db000066400000000000000000002000001453374237200254030ustar00rootroot00000000000000 2&[ A7 = cdnjekc58hm1um7tjjtg{"ID":"cdnjekc58hm1um7tjjtg","SnapshotID":"4166","ConfigDir":"/var/lib/containerd-nydus/config/cdnjekc58hm1um7tjjtg","SocketDir":"","LogDir":"/var/lib/containerd-nydus/logs/cdnjekc58hm1um7tjjtg","LogLevel":"info","LogToStdout":false,"SnapshotDir":"/var/lib/containerd-nydus/snapshots","Pid":0,"ImageID":"hub.byted.org/gechangwei/java:latest-nydus-v6","DaemonMode":"multiple","FsDriver":"fusedev","APISock":"/var/lib/containerd-nydus/socket/shared_daemon/api.sock","RootMountPoint":"/var/lib/containerd-nydus/mnt","CustomMountPoint":null}shared_daemon{"ID":"shared_daemon","SnapshotID":"shared_daemon","ConfigDir":"","SocketDir":"/var/lib/containerd-nydus/socket/shared_daemon","LogDir":"/var/lib/containerd-nydus/logs/shared_daemon","LogLevel":"info","LogToStdout":false,"SnapshotDir":"/var/lib/containerd-nydus/snapshots","Pid":3988706,"ImageID":"","DaemonMode":"shared","FsDriver":"fusedev","APISock":null,"RootMountPoint":"/var/lib/containerd-nydus/mnt","CustomMountPoint":null}daemons0Mo cdnjekc58hm1um7tjjtg{"ID":"cdnjekc58hm1um7tjjtg","SnapshotID":"4166","ConfigDir":"/var/lib/containerd-nydus/config/cdnjekc58hm1um7tjjtg","SocketDir":"","LogDir":"/var/lib/containerd-nydus/logs/cdnjekc58hm1um7tjjtg","LogLevel":"info","LogToStdout":false,"SnapshotDir":"/var/lib/containerd-nydus/snapshots","Pid":0,"ImageID":"hub.byted.org/gechangwei/java:latest-nydus-v6","DaemonMode":"multiple","FsDriver":"fusedev","APISock":"/var/lib/containerd-nydus/socket/shared_daemon/api.sock","RootMountPoint":"/var/lib/containerd-nydus/mnt","CustomMountPoint":null}cdnjf6458hm1um7tjju0{"ID":"cdnjf6458hm1um7tjju0","SnapshotID":"4190","ConfigDir":"/var/lib/containerd-nydus/config/cdnjf6458hm1um7tjju0","SocketDir":"","LogDir":"/var/lib/containerd-nydus/logs/cdnjf6458hm1um7tjju0","LogLevel":"info","LogToStdout":false,"SnapshotDir":"/var/lib/containerd-nydus/snapshots","Pid":0,"ImageID":"hub.byted.org/gechangwei/wordpress:latest-nydus-v6","DaemonMode":"multiple","FsDriver":"fusedev","APISock":"/var/lib/containerd-nydus/socket/shared_daemon/api.sock","RootMountPoint":"/var/lib/containerd-nydus/mnt","CustomMountPoint":null}shared_daemon{"ID":"shared_daemon","SnapshotID":"shared_daemon","ConfigDir":"","SocketDir":"/var/lib/containerd-nydus/socket/shared_daemon","LogDir":"/var/lib/containerd-nydus/logs/shared_daemon","LogLevel":"info","LogToStdout":false,"SnapshotDir":"/var/lib/containerd-nydus/snapshots","Pid":3988706,"ImageID":"","DaemonMode":"shared","FsDriver":"fusedev","APISock":null,"RootMountPoint":"/var/lib/containerd-nydus/mnt","CustomMountPoint":null}daemonsnydus-snapshotter-0.13.4/pkg/supervisor/000077500000000000000000000000001453374237200203255ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/supervisor/supervisor.go000066400000000000000000000215051453374237200231000ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package supervisor import ( "fmt" "net" "os" "sync" "syscall" "time" "path/filepath" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/pkg/errors" "golang.org/x/net/context" "golang.org/x/sync/semaphore" "golang.org/x/sys/unix" ) const MaxOpaqueLen = 1024 * 32 // Bytes // oobSpace is the size of the oob slice required to store for multiple FDs. Note // that unix.UnixRights appears to make the assumption that fd is always int32, // so sizeof(fd) = 4. // At most can accommodate 64 fds var oobSpace = unix.CmsgSpace(4) * 64 type StatesStorage interface { // Appended write states to the storage space. Write([]byte) // Read out the previously written states to fill `buf` which should be large enough. Read(buf []byte) (uint, error) // Mark all data as stale, the previously written data is cleaned Clean() } // Store daemon states in memory type MemStatesStorage struct { data []byte head int } func newMemStatesStorage() *MemStatesStorage { return &MemStatesStorage{data: make([]byte, MaxOpaqueLen)} } func (mss *MemStatesStorage) Write(data []byte) { l := copy(mss.data[mss.head:], data) mss.head += l } func (mss *MemStatesStorage) Read(data []byte) (uint, error) { l := copy(data, mss.data[:mss.head]) return uint(l), nil } func (mss *MemStatesStorage) Clean() { mss.head = 0 } // Use daemon ID as the supervisor ID type Supervisor struct { id string // To which nydusd daemon will try to connect path string // Hold the sended file descriptors. fd int dataStorage StatesStorage mu sync.Mutex sem *semaphore.Weighted } func (su *Supervisor) save(data []byte, fd int) { su.mu.Lock() defer su.mu.Unlock() // Always overwrite states and FDs // We should clean up the stored states since each received states set is atomic su.dataStorage.Clean() if fd > 0 { su.fd = fd } su.dataStorage.Write(data) } // Load resources kept by this supervisor // 1. daemon runtime states // 2. file descriptor // // Note: the resources should be not be consumed. func (su *Supervisor) load(data []byte, oob []byte) (nData uint, nOob int, err error) { su.mu.Lock() defer su.mu.Unlock() if su.fd > 0 { b := syscall.UnixRights(su.fd) nOob = copy(oob, b) } nData, err = su.dataStorage.Read(data) if err != nil { return 0, 0, err } return nData, nOob, nil } // There are several stages from different goroutines to trigger sending daemon states // the waiter will overlap each other causing the UDS being deleted. // But we don't want to keep the server listen for ever. // `to` equal to zero indicates that caller should call the receiver the receive stats // when it thinks is appropriate. `to` is not zero, no receiver callback will be returned. // Then this method is responsible to receive states inside. func (su *Supervisor) waitStatesTimeout(to time.Duration) (func() error, error) { if err := os.Remove(su.path); err != nil { if !os.IsNotExist(err) { log.L.Warnf("Unable to remove existed socket file %s, %s", su.path, err) } } listener, err := net.Listen("unix", su.path) if err != nil { return nil, errors.Wrapf(err, "listen on socket %s", su.path) } receiver := func() error { defer listener.Close() // After the listener is closed, Accept() wakes up conn, err := listener.Accept() if err != nil { return errors.Wrapf(err, "Listener is closed") } defer conn.Close() unixConn := conn.(*net.UnixConn) uf, err := unixConn.File() if err != nil { return err } defer uf.Close() data := make([]byte, MaxOpaqueLen) oob := make([]byte, oobSpace) // Out-of-band data // TODO: Handle EAGAIN EOF and EINTR n, oobn, _, _, err := unix.Recvmsg(int(uf.Fd()), data, oob, 0) if err != nil { return errors.Wrap(err, "receive message") } log.L.Infof("Supervisor %s receives states. data %d oob %d", su.id, n, oobn) scms, err := unix.ParseSocketControlMessage(oob[:oobn]) if err != nil { return errors.Wrap(err, "parse control message") } var fds []int if len(scms) > 0 { scm := scms[0] fds, err = unix.ParseUnixRights(&scm) if err != nil { return errors.Wrap(err, "extract file descriptors") } } else { log.L.Warn("received no control file descriptor") } var fd int if len(fds) > 0 { fd = fds[0] } else { fd = -1 } su.save(data[:n], fd) return nil } cancelTimer := make(chan int, 1) // Once timeouts, stop waiting for states if to > 0 { timer := time.NewTimer(to) go func() { select { case <-timer.C: log.L.Warnf("Receiving state timeouts after %s", to) // Wake up the blocking `Accept` listener.Close() case <-cancelTimer: } }() go func() { if err := receiver(); err != nil { log.L.Errorf("receiver fails, %s", err) } if to > 0 { cancelTimer <- 1 } }() // With non-zero timeout parameter, call should be aware that receiver is nil //nolint: nilnil return nil, nil } return receiver, nil } func (su *Supervisor) SendStatesTimeout(to time.Duration) error { // It is used to receive before if err := os.Remove(su.path); err != nil { if !os.IsNotExist(err) { log.L.Warnf("Unable to remove existed socket file %s, %s", su.path, err) } } listener, err := net.Listen("unix", su.path) if err != nil { return errors.Wrap(err, "listen on socket") } sender := func() error { defer listener.Close() conn, err := listener.Accept() if err != nil { return errors.Wrapf(err, "Listener is closed") } defer conn.Close() unixConn := conn.(*net.UnixConn) uf, err := unixConn.File() if err != nil { return err } defer uf.Close() data := make([]byte, MaxOpaqueLen) oob := make([]byte, oobSpace) // FIXME: It's possible that sending states happens before storing state to the storage. datan, oobn, err := su.load(data, oob) if err != nil { return errors.Wrapf(err, "load resources for %s", su.id) } // TODO: validate returned length _, _, err = unixConn.WriteMsgUnix(data[:datan], oob[:oobn], nil) if err != nil { return errors.Wrapf(err, "send message, datan %d oobn %d", datan, oobn) } log.L.Infof("Supervisor %s sends states. data %d oob %d", su.id, datan, oobn) return nil } cancelTimer := make(chan int, 1) if to > 0 { timer := time.NewTimer(to) go func() { select { case <-timer.C: log.L.Warnf("Sending state timeouts after %s", to) // Wake up the blocking `Accept()` listener.Close() case <-cancelTimer: } }() } // Once timeouts, stop waiting for others fetching states go func() { err := sender() if err != nil { log.L.Errorf("Sender fails, %s", err) } if to > 0 { cancelTimer <- 1 } }() return nil } func (su *Supervisor) FetchDaemonStates(trigger func() error) error { if err := su.sem.Acquire(context.TODO(), 1); err != nil { return err } defer su.sem.Release(1) receiver, err := su.waitStatesTimeout(0) if err != nil { return errors.Wrapf(err, "wait states on %s", su.Sock()) } err = trigger() if err != nil { return errors.Wrapf(err, "trigger on %s", su.Sock()) } // FIXME: With Timeout context! return receiver() } // The unix domain socket on which nydus daemon is connected to func (su *Supervisor) Sock() string { return su.path } // Manage all supervisors each of which works for a nydusd to keep its resources // for sake of failover and live-upgrade. type SupervisorsSet struct { mu sync.Mutex set map[string]*Supervisor // A directory where all the supervisor sockets resides. root string } func NewSupervisorSet(root string) (*SupervisorsSet, error) { if err := os.MkdirAll(root, 0755); err != nil { return nil, err } return &SupervisorsSet{ set: make(map[string]*Supervisor), root: root}, nil } func (ss *SupervisorsSet) NewSupervisor(id string) *Supervisor { sockPath := filepath.Join(ss.root, fmt.Sprintf("%s.sock", id)) supervisor := &Supervisor{ id: id, path: sockPath, // Negative value means no FD was ever held. fd: -1, dataStorage: newMemStatesStorage(), sem: semaphore.NewWeighted(1), } ss.mu.Lock() defer ss.mu.Unlock() // Allow overwrite the old supervisor ss.set[id] = supervisor return supervisor } // Get supervisor by its id which is typically the nydus damon ID. func (ss *SupervisorsSet) GetSupervisor(id string) *Supervisor { ss.mu.Lock() defer ss.mu.Unlock() return ss.set[id] } func (ss *SupervisorsSet) DestroySupervisor(id string) error { ss.mu.Lock() defer ss.mu.Unlock() supervisor, ok := ss.set[id] if !ok { return errdefs.ErrNotFound } delete(ss.set, id) supervisor.mu.Lock() defer supervisor.mu.Unlock() if supervisor.fd > 0 { // Prevent hanging after nydusd exits. if err := syscall.Close(supervisor.fd); err != nil { log.L.Errorf("Fail to close fd %d, %s", supervisor.fd, err) } } return nil } nydus-snapshotter-0.13.4/pkg/supervisor/supervisor_test.go000066400000000000000000000041121453374237200241320ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package supervisor import ( "net" "os" "reflect" "testing" "time" "github.com/stretchr/testify/assert" "golang.org/x/sys/unix" ) func TestSupervisor(t *testing.T) { rootDir, err1 := os.MkdirTemp("", "supervisor") assert.Nil(t, err1) t.Cleanup(func() { os.RemoveAll(rootDir) }) supervisorSet, err := NewSupervisorSet(rootDir) assert.Nil(t, err, "%v", err) su1 := supervisorSet.NewSupervisor("su1") assert.NotNil(t, su1) _, err = su1.waitStatesTimeout(2 * time.Second) assert.Nil(t, err, "%v", err) sock := su1.Sock() addr, err := net.ResolveUnixAddr("unix", sock) assert.Nil(t, err) conn, err := net.DialUnix("unix", nil, addr) assert.Nil(t, err, "%v", err) sentData := []byte("abcde") sentLen, err := conn.Write(sentData) assert.Nil(t, err) conn.Close() // FIXME: Delay for some time until states are stored time.Sleep(500 * time.Millisecond) // Must set length not only capacity receivedData := make([]byte, 16, 32) oob := make([]byte, 16, 32) err = su1.SendStatesTimeout(0) assert.Nil(t, err, "%v", err) conn1, err := net.DialUnix("unix", nil, addr) assert.Nil(t, err, "%v", err) f, _ := conn1.File() //nolint:dogsled receivedLen, _, _, _, err := unix.Recvmsg(int(f.Fd()), receivedData, oob, 0) assert.Nil(t, err) assert.Equal(t, sentLen, receivedLen) assert.True(t, reflect.DeepEqual(receivedData[:receivedLen], sentData), "%v", receivedData) } func TestSupervisorTimeout(t *testing.T) { rootDir, err1 := os.MkdirTemp("", "supervisor") assert.Nil(t, err1) t.Cleanup(func() { os.RemoveAll(rootDir) }) supervisorSet, err := NewSupervisorSet(rootDir) assert.Nil(t, err, "%v", err) su1 := supervisorSet.NewSupervisor("su1") assert.NotNil(t, su1) err = su1.SendStatesTimeout(10 * time.Millisecond) assert.Nil(t, err, "%v", err) sock := su1.Sock() time.Sleep(200 * time.Millisecond) addr, err := net.ResolveUnixAddr("unix", sock) assert.Nil(t, err) _, err = net.DialUnix("unix", nil, addr) assert.NotNil(t, err, "%v", err) } nydus-snapshotter-0.13.4/pkg/system/000077500000000000000000000000001453374237200174305ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/system/system.go000066400000000000000000000273101453374237200213060ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package system import ( "encoding/json" "fmt" "io" "net" "net/http" "os" "path" "path/filepath" "regexp" "strconv" "strings" "time" "github.com/containerd/containerd/log" "github.com/gorilla/mux" "github.com/pkg/errors" "github.com/containerd/nydus-snapshotter/pkg/daemon" "github.com/containerd/nydus-snapshotter/pkg/daemon/types" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/pkg/filesystem" "github.com/containerd/nydus-snapshotter/pkg/manager" metrics "github.com/containerd/nydus-snapshotter/pkg/metrics/tool" "github.com/containerd/nydus-snapshotter/pkg/prefetch" ) const ( // NOTE: Below service endpoints are still experimental. endpointDaemons string = "/api/v1/daemons" // Retrieve daemons' persisted states in boltdb. Because the db file is always locked, // it's very helpful to check daemon's record in database. endpointDaemonRecords string = "/api/v1/daemons/records" endpointDaemonsUpgrade string = "/api/v1/daemons/upgrade" endpointPrefetch string = "/api/v1/prefetch" ) const defaultErrorCode string = "Unknown" // Nydus-snapshotter might manage dozens of running nydus daemons, each daemon may have multiple // file system instances attached. For easy maintenance, the system controller can interact with // all the daemons in a consistent and automatic way. // 1. Get all daemons status and information // 2. Trigger all daemons to restart and reload configuration // 3. Rolling update // 4. Daemons failures record as metrics type Controller struct { fs *filesystem.Filesystem managers []*manager.Manager // httpSever *http.Server addr *net.UnixAddr router *mux.Router } type upgradeRequest struct { NydusdPath string `json:"nydusd_path"` Version string `json:"version"` Policy string `json:"policy"` } type errorMessage struct { Code string `json:"code"` Message string `json:"message"` } func newErrorMessage(message string) errorMessage { return errorMessage{Code: defaultErrorCode, Message: message} } func (m *errorMessage) encode() string { msg, err := json.Marshal(&m) if err != nil { log.L.Errorf("Failed to encode error message, %s", err) return "" } return string(msg) } func jsonResponse(w http.ResponseWriter, payload interface{}) { respBody, err := json.Marshal(&payload) if err != nil { log.L.Errorf("marshal error, %s", err) m := newErrorMessage(err.Error()) http.Error(w, m.encode(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") if _, err := w.Write(respBody); err != nil { log.L.Errorf("write body %s", err) } } type daemonInfo struct { ID string `json:"id"` Pid int `json:"pid"` APISock string `json:"api_socket"` SupervisorPath string `json:"supervisor_path"` Reference int `json:"reference"` HostMountpoint string `json:"mountpoint"` StartupCPUUtilization float64 `json:"startup_cpu_utilization"` MemoryRSS float64 `json:"memory_rss_kb"` ReadData float32 `json:"read_data_kb"` Instances map[string]rafsInstanceInfo `json:"instances"` } type rafsInstanceInfo struct { SnapshotID string `json:"snapshot_id"` SnapshotDir string `json:"snapshot_dir"` Mountpoint string `json:"mountpoint"` ImageID string `json:"image_id"` } func NewSystemController(fs *filesystem.Filesystem, managers []*manager.Manager, sock string) (*Controller, error) { if err := os.MkdirAll(filepath.Dir(sock), os.ModePerm); err != nil { return nil, err } if err := os.Remove(sock); err != nil { if !os.IsNotExist(err) { return nil, err } } addr, err := net.ResolveUnixAddr("unix", sock) if err != nil { return nil, errors.Wrapf(err, "resolve address %s", sock) } sc := Controller{ fs: fs, managers: managers, addr: addr, router: mux.NewRouter(), } sc.registerRouter() return &sc, nil } func (sc *Controller) Run() error { log.L.Infof("Start system controller API server on %s", sc.addr) listener, err := net.ListenUnix("unix", sc.addr) if err != nil { return errors.Wrapf(err, "listen to socket %s ", sc.addr) } err = http.Serve(listener, sc.router) if err != nil { return errors.Wrapf(err, "system management serving") } return nil } func (sc *Controller) registerRouter() { sc.router.HandleFunc(endpointDaemons, sc.describeDaemons()).Methods(http.MethodGet) sc.router.HandleFunc(endpointDaemonsUpgrade, sc.upgradeDaemons()).Methods(http.MethodPut) sc.router.HandleFunc(endpointDaemonRecords, sc.getDaemonRecords()).Methods(http.MethodGet) sc.router.HandleFunc(endpointPrefetch, sc.setPrefetchConfiguration()).Methods(http.MethodPut) } func (sc *Controller) setPrefetchConfiguration() func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) if err != nil { log.L.Errorf("Failed to read prefetch list: %v", err) return } if err = prefetch.Pm.SetPrefetchFiles(body); err != nil { log.L.Errorf("Failed to parse request body: %v", err) return } } } func (sc *Controller) describeDaemons() func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { info := make([]daemonInfo, 0, 10) for _, manager := range sc.managers { daemons := manager.ListDaemons() for _, d := range daemons { instances := make(map[string]rafsInstanceInfo) for _, i := range d.RafsCache.List() { instances[i.SnapshotID] = rafsInstanceInfo{ SnapshotID: i.SnapshotID, SnapshotDir: i.SnapshotDir, Mountpoint: i.GetMountpoint(), ImageID: i.ImageID, } } memRSS, err := metrics.GetProcessMemoryRSSKiloBytes(d.Pid()) if err != nil { log.L.Warnf("Failed to get daemon %s RSS memory", d.ID()) } var readData float32 fsMetrics, err := d.GetFsMetrics("") if err != nil { log.L.Warnf("Failed to get file system metrics") } else { readData = float32(fsMetrics.DataRead) / 1024 } i := daemonInfo{ ID: d.ID(), Pid: d.Pid(), HostMountpoint: d.HostMountpoint(), Reference: int(d.GetRef()), Instances: instances, StartupCPUUtilization: d.StartupCPUUtilization, MemoryRSS: memRSS, ReadData: readData, } info = append(info, i) } } jsonResponse(w, &info) } } // TODO: Implement me! func (sc *Controller) getDaemonRecords() func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { m := newErrorMessage("not implemented") http.Error(w, m.encode(), http.StatusNotImplemented) } } // PUT /api/v1/nydusd/upgrade // body: {"nydusd_path": "/path/to/new/nydusd", "version": "v2.2.1", "policy": "rolling"} // Possible policy: rolling, immediate // Live upgrade procedure: // 1. Check if new version of nydusd executive is existed. // 2. Validate its version matching `version` in this request. // 3. Upgrade one nydusd: // a. Lock the whole manager daemons cache, no daemon can be inserted of deleted from manager // b. Start a new nydusd with `--upgrade` flag, wait until it reaches INTI state // c. Validate the new nydusd's version returned by API /daemon // d. Send resources like FD and daemon running states to the new nydusd by API /takeover // e. Wait until new nydusd reaches state READY // f. Command the old nydusd to exit // g. Send API /start to the new nydusd making it take over the whole file system service // // 4. Upgrade next nydusd like step 3. // 5. If upgrading a certain nydusd fails, abort! // 6. Delete the old nydusd executive func (sc *Controller) upgradeDaemons() func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { var c upgradeRequest var err error var statusCode int defer func() { if err != nil { m := newErrorMessage(err.Error()) http.Error(w, m.encode(), statusCode) } }() err = json.NewDecoder(r.Body).Decode(&c) if err != nil { log.L.Errorf("request %v, decode error %s", r, err) statusCode = http.StatusBadRequest return } for _, manager := range sc.managers { manager.Lock() defer manager.Unlock() daemons := manager.ListDaemons() // TODO: Keep the nydusd executive path in Daemon state and persis it since nydusd // can run on both versions. // Create a dedicated directory storing nydusd of various versions? // TODO: daemon client has a method to query daemon version and information. for _, d := range daemons { err = sc.upgradeNydusDaemon(d, c, manager) if err != nil { log.L.Errorf("Upgrade daemon %s failed, %s", d.ID(), err) statusCode = http.StatusInternalServerError return } } // TODO: why renaming? err = os.Rename(c.NydusdPath, manager.NydusdBinaryPath) if err != nil { log.L.Errorf("Rename nydusd binary from %s to %s failed, %v", c.NydusdPath, manager.NydusdBinaryPath, err) statusCode = http.StatusInternalServerError return } } } } // Provide minimal parameters since most of it can be recovered by nydusd states. // Create a new daemon in Manger to take over the service. func (sc *Controller) upgradeNydusDaemon(d *daemon.Daemon, c upgradeRequest, manager *manager.Manager) error { log.L.Infof("Upgrading nydusd %s, request %v", d.ID(), c) fs := sc.fs var new daemon.Daemon new.States = d.States new.Supervisor = d.Supervisor new.CloneRafsInstances(d) s := path.Base(d.GetAPISock()) next, err := buildNextAPISocket(s) if err != nil { return err } upgradingSocket := path.Join(path.Dir(d.GetAPISock()), next) new.States.APISocket = upgradingSocket cmd, err := manager.BuildDaemonCommand(&new, c.NydusdPath, true) if err != nil { return err } su := manager.SupervisorSet.GetSupervisor(d.ID()) if err := su.SendStatesTimeout(time.Second * 10); err != nil { return errors.Wrap(err, "Send states") } if err := cmd.Start(); err != nil { return errors.Wrap(err, "start process") } if err := new.WaitUntilState(types.DaemonStateInit); err != nil { return errors.Wrap(err, "wait until init state") } if err := new.TakeOver(); err != nil { return errors.Wrap(err, "take over resources") } if err := new.WaitUntilState(types.DaemonStateReady); err != nil { return errors.Wrap(err, "wait unit ready state") } if err := manager.UnsubscribeDaemonEvent(d); err != nil { return errors.Wrap(err, "unsubscribe daemon event") } // Let the older daemon exit without umount if err := d.Exit(); err != nil { return errors.Wrap(err, "old daemon exits") } fs.TryRetainSharedDaemon(&new) if err := new.Start(); err != nil { return errors.Wrap(err, "start file system service") } if err := manager.SubscribeDaemonEvent(&new); err != nil { return &json.InvalidUnmarshalError{} } log.L.Infof("Started service of upgraded daemon on socket %s", new.GetAPISock()) if err := manager.UpdateDaemonLocked(&new); err != nil { return err } log.L.Infof("Upgraded daemon success on socket %s", new.GetAPISock()) return nil } // Name next api socket path based on currently api socket path listened on. // The principle is to add a suffix number to api[0-9]+.sock func buildNextAPISocket(cur string) (string, error) { n := strings.Split(cur, ".") if len(n) != 2 { return "", errdefs.ErrInvalidArgument } r := regexp.MustCompile(`[0-9]+`) m := r.Find([]byte(n[0])) var num int if m == nil { num = 1 } else { var err error num, err = strconv.Atoi(string(m)) if err != nil { return "", err } num++ } nextSocket := fmt.Sprintf("api%d.sock", num) return nextSocket, nil } nydus-snapshotter-0.13.4/pkg/system/system_test.go000066400000000000000000000012721453374237200223440ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package system import ( "testing" "github.com/stretchr/testify/assert" ) func TestBuildUpgradeSocket(t *testing.T) { cur := "api.sock" next, err := buildNextAPISocket(cur) assert.Nil(t, err) assert.Equal(t, next, "api1.sock") cur = "api2.sock" next, err = buildNextAPISocket(cur) assert.Nil(t, err) assert.Equal(t, "api3.sock", next) cur = "api23.sock" next, err = buildNextAPISocket(cur) assert.Nil(t, err) assert.Equal(t, "api24.sock", next) cur = "api222.sock" next, err = buildNextAPISocket(cur) assert.Nil(t, err) assert.Equal(t, "api223.sock", next) } nydus-snapshotter-0.13.4/pkg/tarfs/000077500000000000000000000000001453374237200172235ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/tarfs/tarfs.go000077500000000000000000000614221453374237200207010ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package tarfs import ( "bytes" "context" "encoding/json" "fmt" "io" "os" "os/exec" "path" "path/filepath" "strconv" "strings" "sync" "syscall" "github.com/containerd/containerd/archive/compression" "github.com/containerd/containerd/log" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/pkg/auth" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/pkg/label" "github.com/containerd/nydus-snapshotter/pkg/rafs" "github.com/containerd/nydus-snapshotter/pkg/remote" "github.com/containerd/nydus-snapshotter/pkg/remote/remotes" losetup "github.com/freddierice/go-losetup" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "golang.org/x/sync/semaphore" "golang.org/x/sync/singleflight" "golang.org/x/sys/unix" "k8s.io/utils/lru" ) const ( TarfsStatusInit = 0 TarfsStatusPrepare = 1 TarfsStatusReady = 2 TarfsStatusFailed = 3 ) const ( MaxManifestConfigSize = 0x100000 TarfsLayerBootstrapName = "layer.boot" TarfsImageBootstrapName = "image.boot" TarfsLayerDiskName = "layer.disk" TarfsImageDiskName = "image.disk" ) type Manager struct { snapshotMap map[string]*snapshotStatus // tarfs snapshots status, indexed by snapshot ID mutex sync.Mutex mutexLoopDev sync.Mutex cacheDirPath string nydusImagePath string insecure bool validateDiffID bool // whether to validate digest for uncompressed content checkTarfsHint bool // whether to rely on tarfs hint annotation maxConcurrentProcess int64 processLimiterCache *lru.Cache // cache image ref and concurrent limiter for blob processes tarfsHintCache *lru.Cache // cache oci image ref and tarfs hint annotation diffIDCache *lru.Cache // cache oci blob digest and diffID sg singleflight.Group } type snapshotStatus struct { mutex sync.Mutex status int blobID string blobTarFilePath string erofsMountPoint string dataLoopdev *losetup.Device metaLoopdev *losetup.Device wg *sync.WaitGroup cancel context.CancelFunc } func NewManager(insecure, checkTarfsHint bool, cacheDirPath, nydusImagePath string, maxConcurrentProcess int64) *Manager { return &Manager{ snapshotMap: map[string]*snapshotStatus{}, cacheDirPath: cacheDirPath, nydusImagePath: nydusImagePath, insecure: insecure, validateDiffID: true, checkTarfsHint: checkTarfsHint, maxConcurrentProcess: maxConcurrentProcess, tarfsHintCache: lru.New(50), processLimiterCache: lru.New(50), diffIDCache: lru.New(1000), sg: singleflight.Group{}, } } // Fetch image manifest and config contents, cache frequently used information. // FIXME need an update policy func (t *Manager) fetchImageInfo(ctx context.Context, remote *remote.Remote, ref string, manifestDigest digest.Digest) error { manifest, err := t.fetchImageManifest(ctx, remote, ref, manifestDigest) if err != nil { return err } config, err := t.fetchImageConfig(ctx, remote, ref, &manifest) if err != nil { return err } if t.checkTarfsHint { // cache ref & tarfs hint annotation t.tarfsHintCache.Add(ref, label.HasTarfsHint(manifest.Annotations)) } if t.validateDiffID { // cache OCI blob digest & diff id for i := range manifest.Layers { t.diffIDCache.Add(manifest.Layers[i].Digest, config.RootFS.DiffIDs[i]) } } return nil } func (t *Manager) fetchImageManifest(ctx context.Context, remote *remote.Remote, ref string, manifestDigest digest.Digest) (ocispec.Manifest, error) { rc, desc, err := t.getBlobStream(ctx, remote, ref, manifestDigest) if err != nil { return ocispec.Manifest{}, err } defer rc.Close() if desc.Size > MaxManifestConfigSize { return ocispec.Manifest{}, errors.Errorf("image manifest content size %x is too big", desc.Size) } bytes, err := io.ReadAll(rc) if err != nil { return ocispec.Manifest{}, errors.Wrap(err, "read image manifest content") } var manifestOCI ocispec.Manifest if err := json.Unmarshal(bytes, &manifestOCI); err != nil { return ocispec.Manifest{}, errors.Wrap(err, "unmarshal OCI image manifest") } if len(manifestOCI.Layers) < 1 { return ocispec.Manifest{}, errors.Errorf("invalid OCI image manifest without any layer") } return manifestOCI, nil } func (t *Manager) fetchImageConfig(ctx context.Context, remote *remote.Remote, ref string, manifest *ocispec.Manifest) (ocispec.Image, error) { // fetch image config content and extract diffIDs rc, desc, err := t.getBlobStream(ctx, remote, ref, manifest.Config.Digest) if err != nil { return ocispec.Image{}, errors.Wrap(err, "fetch image config content") } defer rc.Close() if desc.Size > MaxManifestConfigSize { return ocispec.Image{}, errors.Errorf("image config content size %x is too big", desc.Size) } bytes, err := io.ReadAll(rc) if err != nil { return ocispec.Image{}, errors.Wrap(err, "read image config content") } var config ocispec.Image if err := json.Unmarshal(bytes, &config); err != nil { return ocispec.Image{}, errors.Wrap(err, "unmarshal image config") } if len(config.RootFS.DiffIDs) != len(manifest.Layers) { return ocispec.Image{}, errors.Errorf("number of diffIDs does not match manifest layers") } return config, nil } func (t *Manager) getBlobDiffID(ctx context.Context, remote *remote.Remote, ref string, manifestDigest, layerDigest digest.Digest) (digest.Digest, error) { if diffid, ok := t.diffIDCache.Get(layerDigest); ok { return diffid.(digest.Digest), nil } if _, err, _ := t.sg.Do(ref, func() (interface{}, error) { err := t.fetchImageInfo(ctx, remote, ref, manifestDigest) return nil, err }); err != nil { return "", err } if diffid, ok := t.diffIDCache.Get(layerDigest); ok { return diffid.(digest.Digest), nil } return "", errors.Errorf("get blob diff id failed") } func (t *Manager) getBlobStream(ctx context.Context, remote *remote.Remote, ref string, contentDigest digest.Digest) (io.ReadCloser, ocispec.Descriptor, error) { fetcher, err := remote.Fetcher(ctx, ref) if err != nil { return nil, ocispec.Descriptor{}, errors.Wrap(err, "get remote fetcher") } fetcherByDigest, ok := fetcher.(remotes.FetcherByDigest) if !ok { return nil, ocispec.Descriptor{}, errors.Errorf("fetcher %T does not implement remotes.FetcherByDigest", fetcher) } return fetcherByDigest.FetchByDigest(ctx, contentDigest) } // generate tar file and layer bootstrap, return if this blob is an empty blob func (t *Manager) generateBootstrap(tarReader io.Reader, snapshotID, layerBlobID, upperDirPath string) (err error) { snapshotImageDir := filepath.Join(upperDirPath, "image") if err := os.MkdirAll(snapshotImageDir, 0750); err != nil { return errors.Wrapf(err, "create data dir %s for tarfs snapshot", snapshotImageDir) } layerMetaFile := t.layerMetaFilePath(upperDirPath) if _, err := os.Stat(layerMetaFile); err == nil { return errdefs.ErrAlreadyExists } layerMetaFileTmp := layerMetaFile + ".tarfs.tmp" defer os.Remove(layerMetaFileTmp) layerTarFile := t.layerTarFilePath(layerBlobID) layerTarFileTmp := layerTarFile + ".tarfs.tmp" tarFile, err := os.Create(layerTarFileTmp) if err != nil { return errors.Wrap(err, "create temporary file to store tar stream") } defer tarFile.Close() defer os.Remove(layerTarFileTmp) fifoName := filepath.Join(upperDirPath, "layer_"+snapshotID+"_"+"tar.fifo") if err = syscall.Mkfifo(fifoName, 0644); err != nil { return err } defer os.Remove(fifoName) go func() { fifoFile, err := os.OpenFile(fifoName, os.O_WRONLY, os.ModeNamedPipe) if err != nil { log.L.Warnf("can not open fifo file, err %v", err) return } defer fifoFile.Close() if _, err := io.Copy(fifoFile, io.TeeReader(tarReader, tarFile)); err != nil { log.L.Warnf("tar stream copy err %v", err) } }() options := []string{ "create", "--type", "tar-tarfs", "--bootstrap", layerMetaFileTmp, "--blob-id", layerBlobID, "--blob-dir", t.cacheDirPath, fifoName, } cmd := exec.Command(t.nydusImagePath, options...) var errb, outb bytes.Buffer cmd.Stderr = &errb cmd.Stdout = &outb log.L.Debugf("nydus image command %v", options) err = cmd.Run() if err != nil { log.L.Warnf("nydus image exec failed, %s", errb.String()) return errors.Wrap(err, "converting OCIv1 layer blob to tarfs") } log.L.Debugf("nydus image output %s", outb.String()) log.L.Debugf("nydus image err %s", errb.String()) if err := os.Rename(layerTarFileTmp, layerTarFile); err != nil { return errors.Wrapf(err, "rename file %s to %s", layerTarFileTmp, layerTarFile) } if err := os.Rename(layerMetaFileTmp, layerMetaFile); err != nil { return errors.Wrapf(err, "rename file %s to %s", layerMetaFileTmp, layerMetaFile) } return nil } func (t *Manager) getImageBlobInfo(metaFilePath string) (string, error) { if _, err := os.Stat(metaFilePath); err != nil { return "", err } options := []string{ "inspect", "-R blobs", metaFilePath, } cmd := exec.Command(t.nydusImagePath, options...) var errb, outb bytes.Buffer cmd.Stderr = &errb cmd.Stdout = &outb log.L.Debugf("nydus image command %v", options) err := cmd.Run() if err != nil { log.L.Warnf("nydus image exec failed, %s", errb.String()) return "", errors.Wrap(err, "converting OCIv1 layer blob to tarfs") } return outb.String(), nil } // download & uncompress an oci/docker blob, and then generate the tarfs bootstrap func (t *Manager) blobProcess(ctx context.Context, wg *sync.WaitGroup, snapshotID, ref string, manifestDigest, layerDigest digest.Digest, upperDirPath string) error { layerBlobID := layerDigest.Hex() epilog := func(err error, msg string) { st, err1 := t.getSnapshotStatus(snapshotID, true) if err1 != nil { // return errors.Errorf("can not found status object for snapshot %s after prepare", snapshotID) err1 = errors.Wrapf(err1, "can not found status object for snapshot %s after prepare", snapshotID) log.L.WithError(err1).Errorf("async prepare tarfs layer for snapshot ID %s", snapshotID) return } defer st.mutex.Unlock() st.blobID = layerBlobID st.blobTarFilePath = t.layerTarFilePath(layerBlobID) if err != nil { log.L.WithError(err).Errorf(msg) st.status = TarfsStatusFailed } else { st.status = TarfsStatusReady } log.L.Infof(msg) } keyChain, err := auth.GetKeyChainByRef(ref, nil) if err != nil { epilog(err, "create key chain for connection") return err } remote := remote.New(keyChain, t.insecure) rc, _, err := t.getBlobStream(ctx, remote, ref, layerDigest) if err != nil && remote.RetryWithPlainHTTP(ref, err) { rc, _, err = t.getBlobStream(ctx, remote, ref, layerDigest) } if err != nil { epilog(err, "get blob stream for layer") return errors.Wrapf(err, "get blob stream by digest") } go func() { defer wg.Done() defer rc.Close() ds, err := compression.DecompressStream(rc) if err != nil { epilog(err, "unpack layer blob stream for tarfs") return } defer ds.Close() if t.validateDiffID { diffID, err := t.getBlobDiffID(ctx, remote, ref, manifestDigest, layerDigest) if err != nil { epilog(err, "get layer diffID") return } digester := digest.Canonical.Digester() dr := io.TeeReader(ds, digester.Hash()) err = t.generateBootstrap(dr, snapshotID, layerBlobID, upperDirPath) switch { case err != nil && !errdefs.IsAlreadyExists(err): epilog(err, "generate tarfs from image layer blob") case err == nil && digester.Digest() != diffID: epilog(err, "image layer diffID does not match") default: msg := fmt.Sprintf("nydus tarfs for snapshot %s is ready, digest %s", snapshotID, digester.Digest()) epilog(nil, msg) } } else { err = t.generateBootstrap(ds, snapshotID, layerBlobID, upperDirPath) if err != nil && !errdefs.IsAlreadyExists(err) { epilog(err, "generate tarfs data from image layer blob") } else { msg := fmt.Sprintf("nydus tarfs for snapshot %s is ready", snapshotID) epilog(nil, msg) } } }() return err } func (t *Manager) PrepareLayer(snapshotID, ref string, manifestDigest, layerDigest digest.Digest, upperDirPath string) error { t.mutex.Lock() if _, ok := t.snapshotMap[snapshotID]; ok { t.mutex.Unlock() return errors.Errorf("snapshot %s has already been prapared", snapshotID) } wg := &sync.WaitGroup{} wg.Add(1) ctx, cancel := context.WithCancel(context.Background()) t.snapshotMap[snapshotID] = &snapshotStatus{ status: TarfsStatusPrepare, wg: wg, cancel: cancel, } t.mutex.Unlock() return t.blobProcess(ctx, wg, snapshotID, ref, manifestDigest, layerDigest, upperDirPath) } func (t *Manager) MergeLayers(s storage.Snapshot, storageLocater func(string) string) error { mergedBootstrap := t.imageMetaFilePath(storageLocater(s.ParentIDs[0])) if _, err := os.Stat(mergedBootstrap); err == nil { log.L.Debugf("tarfs snapshot %s already has merged bootstrap %s", s.ParentIDs[0], mergedBootstrap) return nil } bootstraps := []string{} // When merging bootstrap, we need to arrange layer bootstrap in order from low to high for idx := len(s.ParentIDs) - 1; idx >= 0; idx-- { snapshotID := s.ParentIDs[idx] err := t.waitLayerReady(snapshotID) if err != nil { return errors.Wrapf(err, "wait for tarfs snapshot %s to get ready", snapshotID) } st, err := t.getSnapshotStatus(snapshotID, false) if err != nil { return err } if st.status != TarfsStatusReady { return errors.Errorf("tarfs snapshot %s is not ready, %d", snapshotID, st.status) } metaFilePath := t.layerMetaFilePath(storageLocater(snapshotID)) bootstraps = append(bootstraps, metaFilePath) } mergedBootstrapTmp := mergedBootstrap + ".tarfs.tmp" defer os.Remove(mergedBootstrapTmp) options := []string{ "merge", "--bootstrap", mergedBootstrapTmp, } options = append(options, bootstraps...) cmd := exec.Command(t.nydusImagePath, options...) var errb, outb bytes.Buffer cmd.Stderr = &errb cmd.Stdout = &outb log.L.Debugf("nydus image command %v", options) err := cmd.Run() if err != nil { return errors.Wrap(err, "merge tarfs image layers") } err = os.Rename(mergedBootstrapTmp, mergedBootstrap) if err != nil { return errors.Wrap(err, "rename merged bootstrap file") } return nil } func (t *Manager) ExportBlockData(s storage.Snapshot, perLayer bool, labels map[string]string, storageLocater func(string) string) ([]string, error) { updateFields := []string{} wholeImage, exportDisk, withVerity := config.GetTarfsExportFlags() // Nothing to do for this case, all needed datum are ready. if !exportDisk && !withVerity { return updateFields, nil } else if !wholeImage != perLayer { return updateFields, nil } var snapshotID string if perLayer { snapshotID = s.ID } else { if len(s.ParentIDs) == 0 { return updateFields, errors.Errorf("snapshot %s has no parent", s.ID) } snapshotID = s.ParentIDs[0] } err := t.waitLayerReady(snapshotID) if err != nil { return updateFields, errors.Wrapf(err, "wait for tarfs snapshot %s to get ready", snapshotID) } st, err := t.getSnapshotStatus(snapshotID, false) if err != nil { return updateFields, err } if st.status != TarfsStatusReady { return updateFields, errors.Errorf("tarfs snapshot %s is not ready, %d", snapshotID, st.status) } blobID, ok := labels[label.NydusTarfsLayer] if !ok { return updateFields, errors.Errorf("Missing Nydus tarfs layer annotation for snapshot %s", s.ID) } var metaFileName, diskFileName string if wholeImage { metaFileName = t.imageMetaFilePath(storageLocater(snapshotID)) diskFileName = t.ImageDiskFilePath(blobID) } else { metaFileName = t.layerMetaFilePath(storageLocater(snapshotID)) diskFileName = t.layerDiskFilePath(blobID) } // Do not regenerate if the disk image already exists. if _, err := os.Stat(diskFileName); err == nil { return updateFields, nil } diskFileNameTmp := diskFileName + ".tarfs.tmp" defer os.Remove(diskFileNameTmp) options := []string{ "export", "--block", "--localfs-dir", t.cacheDirPath, "--bootstrap", metaFileName, "--output", diskFileNameTmp, } if withVerity { options = append(options, "--verity") } log.L.Debugf("nydus image command %v", options) cmd := exec.Command(t.nydusImagePath, options...) var errb, outb bytes.Buffer cmd.Stderr = &errb cmd.Stdout = &outb err = cmd.Run() if err != nil { return updateFields, errors.Wrap(err, "merge tarfs image layers") } log.L.Debugf("nydus image export command, stdout: %s, stderr: %s", &outb, &errb) blockInfo := "" if withVerity { pattern := "dm-verity options: --no-superblock --format=1 -s \"\" --hash=sha256 --data-block-size=512 --hash-block-size=4096 --data-blocks %d --hash-offset %d %s\n" var dataBlobks, hashOffset uint64 var rootHash string if count, err := fmt.Sscanf(outb.String(), pattern, &dataBlobks, &hashOffset, &rootHash); err != nil || count != 3 { return updateFields, errors.Errorf("failed to parse dm-verity options from nydus image output: %s", outb.String()) } blockInfo = strconv.FormatUint(dataBlobks, 10) + "," + strconv.FormatUint(hashOffset, 10) + "," + "sha256:" + rootHash } if wholeImage { labels[label.NydusImageBlockInfo] = blockInfo updateFields = append(updateFields, "labels."+label.NydusImageBlockInfo) } else { labels[label.NydusLayerBlockInfo] = blockInfo updateFields = append(updateFields, "labels."+label.NydusLayerBlockInfo) } log.L.Debugf("export block labels %v", labels) err = os.Rename(diskFileNameTmp, diskFileName) if err != nil { return updateFields, errors.Wrap(err, "rename disk image file") } return updateFields, nil } func (t *Manager) MountTarErofs(snapshotID string, s *storage.Snapshot, labels map[string]string, rafs *rafs.Rafs) error { if s == nil { return errors.New("snapshot object for MountTarErofs() is nil") } // Copy meta info from snapshot to rafs t.copyTarfsAnnotations(labels, rafs) upperDirPath := path.Join(rafs.GetSnapshotDir(), "fs") if !config.GetTarfsMountOnHost() { rafs.SetMountpoint(upperDirPath) return nil } mergedBootstrap := t.imageMetaFilePath(upperDirPath) blobInfo, err := t.getImageBlobInfo(mergedBootstrap) if err != nil { return errors.Wrapf(err, "get image blob info") } var devices []string // When merging bootstrap, we need to arrange layer bootstrap in order from low to high for idx := len(s.ParentIDs) - 1; idx >= 0; idx-- { snapshotID := s.ParentIDs[idx] err := t.waitLayerReady(snapshotID) if err != nil { return errors.Wrapf(err, "wait for tarfs conversion task") } st, err := t.getSnapshotStatus(snapshotID, true) if err != nil { return err } if st.status != TarfsStatusReady { st.mutex.Unlock() return errors.Errorf("snapshot %s tarfs format error %d", snapshotID, st.status) } var blobMarker = "\"blob_id\":\"" + st.blobID + "\"" if strings.Contains(blobInfo, blobMarker) { if st.dataLoopdev == nil { loopdev, err := t.attachLoopdev(st.blobTarFilePath) if err != nil { st.mutex.Unlock() return errors.Wrapf(err, "attach layer tar file %s to loopdev", st.blobTarFilePath) } st.dataLoopdev = loopdev } devices = append(devices, "device="+st.dataLoopdev.Path()) } st.mutex.Unlock() } mountOpts := strings.Join(devices, ",") st, err := t.getSnapshotStatus(snapshotID, true) if err != nil { return err } defer st.mutex.Unlock() mountPoint := path.Join(rafs.GetSnapshotDir(), "mnt") if len(st.erofsMountPoint) > 0 { if st.erofsMountPoint == mountPoint { log.L.Debugf("tarfs for snapshot %s has already been mounted at %s", snapshotID, mountPoint) return nil } return errors.Errorf("tarfs for snapshot %s has already been mounted at %s", snapshotID, st.erofsMountPoint) } if st.metaLoopdev == nil { loopdev, err := t.attachLoopdev(mergedBootstrap) if err != nil { return errors.Wrapf(err, "attach merged bootstrap %s to loopdev", mergedBootstrap) } st.metaLoopdev = loopdev } devName := st.metaLoopdev.Path() if err = os.MkdirAll(mountPoint, 0750); err != nil { return errors.Wrapf(err, "create tarfs mount dir %s", mountPoint) } err = unix.Mount(devName, mountPoint, "erofs", 0, mountOpts) if err != nil { return errors.Wrapf(err, "mount erofs at %s with opts %s", mountPoint, mountOpts) } st.erofsMountPoint = mountPoint rafs.SetMountpoint(mountPoint) return nil } func (t *Manager) UmountTarErofs(snapshotID string) error { st, err := t.getSnapshotStatus(snapshotID, true) if err != nil { return errors.Wrapf(err, "umount a tarfs snapshot %s which is already removed", snapshotID) } defer st.mutex.Unlock() if len(st.erofsMountPoint) > 0 { err := unix.Unmount(st.erofsMountPoint, 0) if err != nil { return errors.Wrapf(err, "umount erofs tarfs %s", st.erofsMountPoint) } st.erofsMountPoint = "" } return nil } func (t *Manager) DetachLayer(snapshotID string) error { st, err := t.getSnapshotStatus(snapshotID, true) if err != nil { return os.ErrNotExist } if len(st.erofsMountPoint) > 0 { err := unix.Unmount(st.erofsMountPoint, 0) if err != nil { st.mutex.Unlock() return errors.Wrapf(err, "umount erofs tarfs %s", st.erofsMountPoint) } st.erofsMountPoint = "" } if st.metaLoopdev != nil { err := st.metaLoopdev.Detach() if err != nil { st.mutex.Unlock() return errors.Wrapf(err, "detach merged bootstrap loopdev for tarfs snapshot %s", snapshotID) } st.metaLoopdev = nil } if st.dataLoopdev != nil { err := st.dataLoopdev.Detach() if err != nil { st.mutex.Unlock() return errors.Wrapf(err, "detach layer bootstrap loopdev for tarfs snapshot %s", snapshotID) } st.dataLoopdev = nil } st.mutex.Unlock() // TODO: check order st.cancel() t.mutex.Lock() delete(t.snapshotMap, snapshotID) t.mutex.Unlock() return nil } func (t *Manager) getSnapshotStatus(snapshotID string, lock bool) (*snapshotStatus, error) { t.mutex.Lock() defer t.mutex.Unlock() st, ok := t.snapshotMap[snapshotID] if ok { if lock { st.mutex.Lock() } return st, nil } return nil, errors.Errorf("not found snapshot %s", snapshotID) } func (t *Manager) waitLayerReady(snapshotID string) error { st, err := t.getSnapshotStatus(snapshotID, false) if err != nil { return err } if st.status != TarfsStatusReady { log.L.Debugf("wait tarfs conversion task for snapshot %s", snapshotID) } st.wg.Wait() if st.status != TarfsStatusReady { return errors.Errorf("snapshot %s is in state %d instead of ready state", snapshotID, st.status) } return nil } func (t *Manager) attachLoopdev(blob string) (*losetup.Device, error) { // losetup.Attach() is not thread-safe hold lock here t.mutexLoopDev.Lock() defer t.mutexLoopDev.Unlock() dev, err := losetup.Attach(blob, 0, false) return &dev, err } func (t *Manager) CheckTarfsHintAnnotation(ctx context.Context, ref string, manifestDigest digest.Digest) (bool, error) { if !t.checkTarfsHint { return true, nil } keyChain, err := auth.GetKeyChainByRef(ref, nil) if err != nil { return false, err } remote := remote.New(keyChain, t.insecure) handle := func() (bool, error) { if tarfsHint, ok := t.tarfsHintCache.Get(ref); ok { return tarfsHint.(bool), nil } if _, err, _ := t.sg.Do(ref, func() (interface{}, error) { err := t.fetchImageInfo(ctx, remote, ref, manifestDigest) return nil, err }); err != nil { return false, err } if tarfsHint, ok := t.tarfsHintCache.Get(ref); ok { return tarfsHint.(bool), nil } return false, errors.Errorf("get tarfs hint annotation failed") } tarfsHint, err := handle() if err != nil && remote.RetryWithPlainHTTP(ref, err) { tarfsHint, err = handle() } return tarfsHint, err } func (t *Manager) GetConcurrentLimiter(ref string) *semaphore.Weighted { if t.maxConcurrentProcess <= 0 { return nil } if limiter, ok := t.processLimiterCache.Get(ref); ok { return limiter.(*semaphore.Weighted) } limiter := semaphore.NewWeighted(t.maxConcurrentProcess) t.processLimiterCache.Add(ref, limiter) return limiter } func (t *Manager) copyTarfsAnnotations(labels map[string]string, rafs *rafs.Rafs) { keys := []string{ label.NydusTarfsLayer, label.NydusImageBlockInfo, label.NydusLayerBlockInfo, } for _, k := range keys { if v, ok := labels[k]; ok { rafs.AddAnnotation(k, v) } } } func (t *Manager) layerTarFilePath(blobID string) string { return filepath.Join(t.cacheDirPath, blobID) } func (t *Manager) layerDiskFilePath(blobID string) string { return filepath.Join(t.cacheDirPath, blobID+"."+TarfsLayerDiskName) } func (t *Manager) ImageDiskFilePath(blobID string) string { return filepath.Join(t.cacheDirPath, blobID+"."+TarfsImageDiskName) } func (t *Manager) layerMetaFilePath(upperDirPath string) string { return filepath.Join(upperDirPath, "image", TarfsLayerBootstrapName) } func (t *Manager) imageMetaFilePath(upperDirPath string) string { return filepath.Join(upperDirPath, "image", TarfsImageBootstrapName) } nydus-snapshotter-0.13.4/pkg/utils/000077500000000000000000000000001453374237200172445ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/utils/display/000077500000000000000000000000001453374237200207115ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/utils/display/display.go000066400000000000000000000012621453374237200227060ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package display import "fmt" func ByteToReadableIEC(b uint32) string { const unit = 1024 if b < unit { return fmt.Sprintf("%d B", b) } div, exp := int64(unit), 0 for n := b / unit; n >= unit; n /= unit { div *= unit exp++ } return fmt.Sprintf("%.1f %ciB", float64(b)/float64(div), "KMGTPE"[exp]) } func MicroSecondToReadable(b uint64) string { const unit = 1000 if b < unit { return fmt.Sprintf("%d us", b) } if b < unit*unit { return fmt.Sprintf("%.3f ms", float64(b)/float64(unit)) } return fmt.Sprintf("%.3f s", float64(b)/float64(unit*unit)) } nydus-snapshotter-0.13.4/pkg/utils/erofs/000077500000000000000000000000001453374237200203625ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/utils/erofs/erofs.go000066400000000000000000000023351453374237200220320ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package erofs import ( "fmt" "github.com/containerd/containerd/log" "github.com/opencontainers/go-digest" "github.com/pkg/errors" "golang.org/x/sys/unix" ) func Mount(bootstrapPath, domainID, fscacheID, mountpoint string) error { mount := unix.Mount var opts string // Nydusd must have domain_id specified and it is set to fsid if it is // never specified. if domainID != "" && domainID != fscacheID { opts = fmt.Sprintf("domain_id=%s,fsid=%s", domainID, fscacheID) } else { opts = "fsid=" + fscacheID } log.L.Infof("Mount erofs to %s with options %s", mountpoint, opts) if err := mount("erofs", mountpoint, "erofs", 0, opts); err != nil { if errors.Is(err, unix.EINVAL) && domainID != "" { log.L.Errorf("mount erofs with shared domain failed, " + "If using this feature, make sure your Linux kernel version >= 6.1") } return errors.Wrapf(err, "mount erofs at %s", mountpoint) } return nil } func Umount(mountPoint string) error { return unix.Unmount(mountPoint, 0) } func FscacheID(snapshotID string) string { return digest.FromString(fmt.Sprintf("nydus-snapshot-%s", snapshotID)).Hex() } nydus-snapshotter-0.13.4/pkg/utils/file/000077500000000000000000000000001453374237200201635ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/utils/file/file.go000066400000000000000000000005071453374237200214330ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package file import "os" func IsDirExisted(path string) (bool, error) { s, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { return false, nil } return false, err } return s.IsDir(), nil } nydus-snapshotter-0.13.4/pkg/utils/mount/000077500000000000000000000000001453374237200204065ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/utils/mount/mount.go000066400000000000000000000041311453374237200220760ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package mount import ( "os" "path/filepath" "syscall" "time" "github.com/pkg/errors" "github.com/containerd/nydus-snapshotter/pkg/errdefs" "github.com/containerd/nydus-snapshotter/pkg/utils/retry" ) type Interface interface { Umount(target string) error } type Mounter struct { } func (m *Mounter) Umount(target string) error { if mounted, err := IsMountpoint(target); err == nil { if !mounted { return errors.New("not mounted") } } else { return err } // return syscall.Unmount(target, syscall.MNT_FORCE) return syscall.Unmount(target, 0) } func NormalizePath(path string) (realPath string, err error) { if realPath, err = filepath.Abs(path); err != nil { return "", errors.Wrapf(err, "get absolute path for %s", path) } if realPath, err = filepath.EvalSymlinks(realPath); err != nil { return "", errors.Wrapf(err, "canonicalise path for %s", path) } if _, err := os.Stat(realPath); err != nil { return "", errors.Wrapf(err, "stat target of %s", path) } return realPath, nil } // return value `true` means the path is mounted func IsMountpoint(path string) (bool, error) { realPath, err := NormalizePath(path) if err != nil { return false, err } if path == "/" { return true, nil } stat, err := os.Stat(realPath) if err != nil { return false, err } parentStat, err := os.Stat(filepath.Dir(realPath)) if err != nil { return false, err } // If the directory has a different device as parent, then it is a mountpoint. if stat.Sys().(*syscall.Stat_t).Dev != parentStat.Sys().(*syscall.Stat_t).Dev { return true, nil } return false, nil } func WaitUntilUnmounted(path string) error { return retry.Do(func() error { mounted, err := IsMountpoint(path) if err != nil { return err } if mounted { return errdefs.ErrDeviceBusy } return nil }, retry.Attempts(20), // totally wait for 1 seconds, should be enough retry.LastErrorOnly(true), retry.Delay(50*time.Millisecond), ) } nydus-snapshotter-0.13.4/pkg/utils/parser/000077500000000000000000000000001453374237200205405ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/utils/parser/parser.go000066400000000000000000000035341453374237200223700ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package parser import ( "regexp" "strconv" "sync" "github.com/pkg/errors" ) var ( unitMultipliers map[string]int64 unitMultipliersOnce sync.Once ) func InitUnitMultipliers() { unitMultipliers = make(map[string]int64, 10) unitMultipliers["KiB"] = 1024 unitMultipliers["MiB"] = unitMultipliers["KiB"] * 1024 unitMultipliers["GiB"] = unitMultipliers["MiB"] * 1024 unitMultipliers["TiB"] = unitMultipliers["GiB"] * 1024 unitMultipliers["PiB"] = unitMultipliers["TiB"] * 1024 unitMultipliers["Ki"] = 1024 unitMultipliers["Mi"] = unitMultipliers["Ki"] * 1024 unitMultipliers["Gi"] = unitMultipliers["Mi"] * 1024 unitMultipliers["Ti"] = unitMultipliers["Gi"] * 1024 unitMultipliers["Pi"] = unitMultipliers["Ti"] * 1024 } func MemoryConfigToBytes(data string, totalMemoryBytes int) (int64, error) { if data == "" { return -1, nil } // Memory value without unit. value, err := strconv.ParseFloat(data, 64) if err == nil { return int64(value), nil } re := regexp.MustCompile(`(\d*\.?\d+)([a-zA-Z\%]+)`) matches := re.FindStringSubmatch(data) if len(matches) != 3 { return 0, errors.Errorf("Falied to convert data to bytes: Unknown unit in %s", data) } // Parse memory value and unit. valueString, unit := matches[1], matches[2] value, err = strconv.ParseFloat(valueString, 64) if err != nil { return 0, errors.Wrap(err, "Failed to parse memory limit") } // Return if the unit is byte. if unit == "B" { return int64(value), nil } // Calculate value if the unit is "%". if unit == "%" { limitMemory := float64(totalMemoryBytes) * value / 100 return int64(limitMemory + 0.5), nil } unitMultipliersOnce.Do(InitUnitMultipliers) multiplier := unitMultipliers[unit] return int64(value * float64(multiplier)), nil } nydus-snapshotter-0.13.4/pkg/utils/parser/parser_test.go000066400000000000000000000041511453374237200234230ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package parser import ( "testing" "github.com/stretchr/testify/assert" ) func TestMemoryLimitToBytes(t *testing.T) { totalMemoryBytes := 10000 for desc, test := range map[string]struct { MemoryLimit string expected int64 }{ "memory limit is zero": { MemoryLimit: "", expected: -1, }, "memory limit is a percentage": { MemoryLimit: "20%", expected: 2000, }, "memory limit is a float percentage": { MemoryLimit: "0.2%", expected: 20, }, "memory limit is a value without unit": { MemoryLimit: "10240", expected: 10240, }, "memory limit is a value with Byte unit": { MemoryLimit: "10240B", expected: 10240, }, "memory limit is a value with KiB unit": { MemoryLimit: "30KiB", expected: 30 * 1024, }, "memory limit is a value with MiB unit": { MemoryLimit: "30MiB", expected: 30 * 1024 * 1024, }, "memory limit is a value with GiB unit": { MemoryLimit: "30GiB", expected: 30 * 1024 * 1024 * 1024, }, "memory limit is a value with TiB unit": { MemoryLimit: "30TiB", expected: 30 * 1024 * 1024 * 1024 * 1024, }, "memory limit is a value with PiB unit": { MemoryLimit: "30PiB", expected: 30 * 1024 * 1024 * 1024 * 1024 * 1024, }, "memory limit is a value with Ki unit": { MemoryLimit: "30Ki", expected: 30 * 1024, }, "memory limit is a value with Mi unit": { MemoryLimit: "30Mi", expected: 30 * 1024 * 1024, }, "memory limit is a value with Gi unit": { MemoryLimit: "30Gi", expected: 30 * 1024 * 1024 * 1024, }, "memory limit is a value with Ti unit": { MemoryLimit: "30Ti", expected: 30 * 1024 * 1024 * 1024 * 1024, }, "memory limit is a value with Pi unit": { MemoryLimit: "30Pi", expected: 30 * 1024 * 1024 * 1024 * 1024 * 1024, }, } { t.Logf("TestCase %q", desc) memoryLimitInBytes, err := MemoryConfigToBytes(test.MemoryLimit, totalMemoryBytes) assert.NoError(t, err) assert.Equal(t, memoryLimitInBytes, test.expected) } } nydus-snapshotter-0.13.4/pkg/utils/registry/000077500000000000000000000000001453374237200211145ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/utils/registry/registry.go000066400000000000000000000041001453374237200233060ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package registry import ( "context" "fmt" "net/http" "reflect" "strings" "time" snpkg "github.com/containerd/containerd/pkg/snapshotters" "github.com/containerd/containerd/reference/docker" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote/transport" "github.com/pkg/errors" ) type Image struct { Host string Repo string } func ConvertToVPCHost(registryHost string) string { parts := strings.Split(registryHost, ".") if strings.HasSuffix(parts[0], "-vpc") { return registryHost } parts[0] = fmt.Sprintf("%s-vpc", parts[0]) return strings.Join(parts, ".") } func ParseImage(imageID string) (Image, error) { named, err := docker.ParseDockerRef(imageID) if err != nil { return Image{}, err } host := docker.Domain(named) repo := docker.Path(named) return Image{ Host: host, Repo: repo, }, nil } func ParseLabels(labels map[string]string) (rRef, rDigest string) { if ref, ok := labels[snpkg.TargetRefLabel]; ok { rRef = ref } if layerDigest, ok := labels[snpkg.TargetLayerDigestLabel]; ok { rDigest = layerDigest } return } func AuthnTransport(ref name.Reference, tr http.RoundTripper, keychain authn.Keychain) (http.RoundTripper, error) { var err error var auth authn.Authenticator if keychain == nil || (reflect.ValueOf(keychain).Kind() == reflect.Ptr && reflect.ValueOf(keychain).IsNil()) { auth = authn.Anonymous } else { auth, err = keychain.Resolve(ref.Context()) if err != nil { return nil, errors.Wrapf(err, "failed to resolve reference %q", ref) } } errCh := make(chan error) var rTr http.RoundTripper go func() { rTr, err = transport.NewWithContext( context.TODO(), ref.Context().Registry, auth, tr, []string{ref.Scope(transport.PullScope)}, ) errCh <- err }() select { case err = <-errCh: case <-time.After(10 * time.Second): return nil, fmt.Errorf("authentication timeout") } return rTr, err } nydus-snapshotter-0.13.4/pkg/utils/registry/registry_test.go000066400000000000000000000043701453374237200243560ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package registry import ( "reflect" "testing" ) func TestConvertToVPCHost1(t *testing.T) { type args struct { registryHost string } tests := []struct { name string args args want string }{ { name: "with no vpc registry", args: args{ registryHost: "acr-nydus-registry.cn-hangzhou.cr.aliyuncs.com", }, want: "acr-nydus-registry-vpc.cn-hangzhou.cr.aliyuncs.com", }, { name: "with vpc registry", args: args{ registryHost: "acr-nydus-registry-vpc.cn-hangzhou.cr.aliyuncs.com", }, want: "acr-nydus-registry-vpc.cn-hangzhou.cr.aliyuncs.com", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := ConvertToVPCHost(tt.args.registryHost); got != tt.want { t.Errorf("ConvertToVPCHost() = %v, want %v", got, tt.want) } }) } } func TestParseImage(t *testing.T) { type args struct { imageID string } tests := []struct { name string args args want Image wantErr bool }{ { name: "multi path", args: args{ imageID: "localhost:5000/hello-world/foo/bar:latest", }, want: Image{ Host: "localhost:5000", Repo: "hello-world/foo/bar", }, wantErr: false, }, { name: "no namespace", args: args{ imageID: "localhost:5000/bar:latest", }, want: Image{ Host: "localhost:5000", Repo: "bar", }, wantErr: false, }, { name: "normal", args: args{ imageID: "nydus-registry.cn-hangzhou.cr.aliyuncs.com/poc/tomcat:latest-app-nydus-platform", }, want: Image{ Host: "nydus-registry.cn-hangzhou.cr.aliyuncs.com", Repo: "poc/tomcat", }, wantErr: false, }, { name: "invalid", args: args{ imageID: "nydus-registry.cn-hangzhou.cr.aliyuncs.com/:latest-app-nydus-platform", }, want: Image{ Host: "", Repo: "", }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := ParseImage(tt.args.imageID) if (err != nil) != tt.wantErr { t.Errorf("ParseImage() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { t.Errorf("ParseImage() got = %v, want %v", got, tt.want) } }) } } nydus-snapshotter-0.13.4/pkg/utils/retry/000077500000000000000000000000001453374237200204115ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/utils/retry/retry.go000066400000000000000000000135101453374237200221050ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package retry import ( "fmt" "math/rand" "strings" "time" ) type RetryableFunc func() error var ( DefaultAttempts = uint(10) DefaultDelay = 100 * time.Millisecond DefaultMaxJitter = 100 * time.Millisecond DefaultOnRetry = func(n uint, err error) {} DefaultRetryIf = IsRecoverable DefaultDelayType = CombineDelay(FixedDelay, RandomDelay) DefaultLastErrorOnly = false ) // Function signature of retry if function type retryIfFunc func(error) bool type AbortFunc func(error) bool // Function signature of OnRetry function // n = count of attempts type OnRetryFunc func(n uint, err error) type DelayTypeFunc func(n uint, config *Config) time.Duration type Config struct { attempts uint delay time.Duration maxDelay time.Duration maxJitter time.Duration onRetry OnRetryFunc retryIf retryIfFunc delayType DelayTypeFunc lastErrorOnly bool } // Option represents an option for retry. type Option func(*Config) // return the direct last error that came from the retried function // default is false (return wrapped errors with everything) func LastErrorOnly(lastErrorOnly bool) Option { return func(c *Config) { c.lastErrorOnly = lastErrorOnly } } // Attempts set count of retry // default is 10 func Attempts(attempts uint) Option { return func(c *Config) { c.attempts = attempts } } // `abortFunc` return true means no further need to retry func OnlyRetryIf(abortFunc AbortFunc) Option { return func(c *Config) { c.retryIf = func(err error) bool { if !IsRecoverable(err) { return false } return !abortFunc(err) } } } // Delay set delay between retry // default is 100ms func Delay(delay time.Duration) Option { return func(c *Config) { c.delay = delay } } // MaxDelay set maximum delay between retry // does not apply by default func MaxDelay(maxDelay time.Duration) Option { return func(c *Config) { c.maxDelay = maxDelay } } // MaxJitter sets the maximum random Jitter between retries for RandomDelay func MaxJitter(maxJitter time.Duration) Option { return func(c *Config) { c.maxJitter = maxJitter } } // DelayType set type of the delay between retries // default is BackOff func DelayType(delayType DelayTypeFunc) Option { return func(c *Config) { c.delayType = delayType } } // BackOffDelay is a DelayType which increases delay between consecutive retries func BackOffDelay(n uint, config *Config) time.Duration { return config.delay * (1 << n) } // FixedDelay is a DelayType which keeps delay the same through all iterations func FixedDelay(_ uint, config *Config) time.Duration { return config.delay } // RandomDelay is a DelayType which picks a random delay up to config.maxJitter func RandomDelay(_ uint, config *Config) time.Duration { return time.Duration(rand.Int63n(int64(config.maxJitter))) } // CombineDelay is a DelayType the combines all of the specified delays into a new DelayTypeFunc func CombineDelay(delays ...DelayTypeFunc) DelayTypeFunc { return func(n uint, config *Config) time.Duration { var total time.Duration for _, delay := range delays { total += delay(n, config) } return total } } func OnRetry(onRetry OnRetryFunc) Option { return func(c *Config) { c.onRetry = onRetry } } func Do(retryFunc RetryableFunc, opts ...Option) error { var n uint // default config := &Config{ attempts: DefaultAttempts, delay: DefaultDelay, maxJitter: DefaultMaxJitter, onRetry: DefaultOnRetry, retryIf: DefaultRetryIf, delayType: DefaultDelayType, lastErrorOnly: DefaultLastErrorOnly, } // apply opts for _, opt := range opts { opt(config) } var errorLog Error if !config.lastErrorOnly { errorLog = make(Error, config.attempts) } else { errorLog = make(Error, 1) } lastErrIndex := n for n < config.attempts { err := retryFunc() if err != nil { errorLog[lastErrIndex] = unpackUnrecoverable(err) if !config.retryIf(err) { break } config.onRetry(n, err) // if this is last attempt - don't wait if n == config.attempts-1 { break } delayTime := config.delayType(n, config) if config.maxDelay > 0 && delayTime > config.maxDelay { delayTime = config.maxDelay } time.Sleep(delayTime) } else { return nil } n++ if !config.lastErrorOnly { lastErrIndex = n } } if config.lastErrorOnly { return errorLog[lastErrIndex] } return errorLog } // Error type represents list of errors in retry type Error []error // Error method return string representation of Error // It is an implementation of error interface func (e Error) Error() string { logWithNumber := make([]string, lenWithoutNil(e)) for i, l := range e { if l != nil { logWithNumber[i] = fmt.Sprintf("#%d: %s", i+1, l.Error()) } } return fmt.Sprintf("All attempts fail:\n%s", strings.Join(logWithNumber, "\n")) } func lenWithoutNil(e Error) (count int) { for _, v := range e { if v != nil { count++ } } return } // WrappedErrors returns the list of errors that this Error is wrapping. // It is an implementation of the `errwrap.Wrapper` interface // in package [errwrap](https://github.com/hashicorp/errwrap) so that // `retry.Error` can be used with that library. func (e Error) WrappedErrors() []error { return e } type unrecoverableError struct { error } // Unrecoverable wraps an error in `unrecoverableError` struct func Unrecoverable(err error) error { return unrecoverableError{err} } // IsRecoverable checks if error is an instance of `unrecoverableError` func IsRecoverable(err error) bool { _, isUnrecoverable := err.(unrecoverableError) return !isUnrecoverable } func unpackUnrecoverable(err error) error { if unrecoverable, isUnrecoverable := err.(unrecoverableError); isUnrecoverable { return unrecoverable.error } return err } nydus-snapshotter-0.13.4/pkg/utils/signals/000077500000000000000000000000001453374237200207045ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/utils/signals/signal.go000066400000000000000000000011361453374237200225110ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package signals import ( "os" "os/signal" "sync" "syscall" ) var ( once sync.Once stop chan struct{} shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM} ) func SetupSignalHandler() (stopCh <-chan struct{}) { // make sure SetupSignalHandler will not call twice once.Do(func() { stop = make(chan struct{}) c := make(chan os.Signal, 2) signal.Notify(c, shutdownSignals...) go func() { <-c close(stop) <-c os.Exit(1) }() }) return stop } nydus-snapshotter-0.13.4/pkg/utils/signals/signal_test.go000066400000000000000000000012771453374237200235560ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package signals import ( "sync/atomic" "syscall" "testing" "time" "github.com/stretchr/testify/require" ) func TestSetupSignalHandler(t *testing.T) { signal := SetupSignalHandler() var expected int32 = 2 var actual int32 var func1 = func(stop <-chan struct{}) { <-stop atomic.AddInt32(&actual, 1) } var func2 = func(stop <-chan struct{}) { <-stop atomic.AddInt32(&actual, 1) } go func1(signal) go func2(signal) err := syscall.Kill(syscall.Getpid(), syscall.SIGINT) require.Nil(t, err) time.Sleep(1 * time.Second) require.Equal(t, atomic.LoadInt32(&actual), expected) } nydus-snapshotter-0.13.4/pkg/utils/signer/000077500000000000000000000000001453374237200205335ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/utils/signer/signer.go000066400000000000000000000013011453374237200223440ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package signer import ( "crypto" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/pem" "io" ) type Signer struct { publicKey *rsa.PublicKey } func New(publicKey []byte) (*Signer, error) { block, _ := pem.Decode(publicKey) key, err := x509.ParsePKCS1PublicKey(block.Bytes) if err != nil { return nil, err } return &Signer{ publicKey: key, }, nil } func (s *Signer) Verify(input io.Reader, signature []byte) error { h := sha256.New() _, err := io.Copy(h, input) if err != nil { return err } return rsa.VerifyPKCS1v15(s.publicKey, crypto.SHA256, h.Sum(nil), signature) } nydus-snapshotter-0.13.4/pkg/utils/sysinfo/000077500000000000000000000000001453374237200207365ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/utils/sysinfo/sysinfo.go000066400000000000000000000010631453374237200227570ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package sysinfo import ( "sync" "syscall" ) var ( sysinfo *syscall.Sysinfo_t sysinfoOnce sync.Once sysinfoErr error ) func GetSysinfo() { var info syscall.Sysinfo_t err := syscall.Sysinfo(&info) if err != nil { sysinfoErr = err return } sysinfo = &info sysinfoErr = nil } func GetTotalMemoryBytes() (int, error) { sysinfoOnce.Do(GetSysinfo) if sysinfo == nil { return 0, sysinfoErr } return int(sysinfo.Totalram), nil } nydus-snapshotter-0.13.4/pkg/utils/transport/000077500000000000000000000000001453374237200213005ustar00rootroot00000000000000nydus-snapshotter-0.13.4/pkg/utils/transport/pool.go000066400000000000000000000054251453374237200226060ustar00rootroot00000000000000package transport import ( "context" "fmt" "io" "net/http" "sync" "time" "github.com/containerd/containerd/log" "github.com/containerd/nydus-snapshotter/pkg/utils/registry" "github.com/golang/groupcache/lru" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" "github.com/pkg/errors" ) var _ Resolve = &Pool{} const HTTPClientTimeOut = time.Second * 60 // LRU cache for authenticated network connections. type Pool struct { trPoolMu sync.Mutex trPool *lru.Cache transport http.RoundTripper } func NewPool() *Pool { pool := Pool{ transport: http.DefaultTransport, trPool: lru.New(3000), } return &pool } type Resolve interface { Resolve(ref name.Reference, digest string, keychain authn.Keychain) (string, http.RoundTripper, error) } func (r *Pool) Resolve(ref name.Reference, digest string, keychain authn.Keychain) (string, http.RoundTripper, error) { r.trPoolMu.Lock() defer r.trPoolMu.Unlock() endpointURL := fmt.Sprintf("%s://%s/v2/%s/blobs/%s", ref.Context().Registry.Scheme(), ref.Context().RegistryStr(), ref.Context().RepositoryStr(), digest) if tr, ok := r.trPool.Get(ref.Name()); ok { var err error if url, err := redirect(endpointURL, tr.(http.RoundTripper)); err == nil { return url, tr.(http.RoundTripper), nil } r.trPool.Remove(ref.Name()) log.L.Warnf("redirect %s, failed, err: %s", endpointURL, err) } tr, err := registry.AuthnTransport(ref, r.transport, keychain) if err != nil { return "", nil, errors.Wrapf(err, "failed to authn transport") } url, err := redirect(endpointURL, tr) if err != nil { return "", nil, errors.Wrapf(err, "failed to redirect %s", endpointURL) } r.trPool.Add(ref.Name(), tr) return url, tr, nil } func redirect(endpointURL string, tr http.RoundTripper) (url string, err error) { ctx, cancel := context.WithTimeout(context.Background(), HTTPClientTimeOut) defer cancel() req, err := http.NewRequestWithContext(ctx, "GET", endpointURL, nil) if err != nil { return "", errors.Wrapf(err, "failed to request to the registry") } req.Close = false req.Header.Set("Range", "bytes=0-0") res, err := tr.RoundTrip(req) if err != nil { return "", errors.Wrapf(err, "failed to request to %q", endpointURL) } defer func() { _, err := io.Copy(io.Discard, res.Body) if err != nil { log.L.Warnf("Discard body failed %s", err) } res.Body.Close() }() if res.StatusCode/100 == 2 { url = endpointURL } else if redir := res.Header.Get("Location"); redir != "" && res.StatusCode/100 == 3 { url = redir } else { body, err := io.ReadAll(res.Body) if err != nil { return "", errors.Wrapf(err, "failed to get response body") } return "", fmt.Errorf("failed to access to %q with code %v, body: %s", endpointURL, res.StatusCode, body) } return } nydus-snapshotter-0.13.4/pkg/utils/transport/pool_test.go000066400000000000000000000035271453374237200236460ustar00rootroot00000000000000package transport import ( "fmt" "net/http" "net/http/httptest" "strings" "testing" "github.com/google/go-containerregistry/pkg/name" "github.com/stretchr/testify/require" ) type FakeReference struct { Tag string Repository name.Repository } var _ name.Reference = (*FakeReference)(nil) func (t FakeReference) Context() name.Repository { return t.Repository } func (t FakeReference) Identifier() string { return t.Tag } func (t FakeReference) Name() string { return t.Repository.Name() + ":" + t.Tag } func (t FakeReference) String() string { return t.Name() } func (t FakeReference) Scope(action string) string { return t.Repository.Scope(action) } func TestResolve(t *testing.T) { var callCount int failed := false svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { callCount++ if !failed { fmt.Fprintf(w, "ok") return } failed = false w.WriteHeader(http.StatusBadRequest) })) defer svr.Close() pool := NewPool() repo, err := name.NewRepository(strings.TrimPrefix(svr.URL, "http://")+"/nginx", name.WeakValidation, name.Insecure) require.NoError(t, err) ref := &FakeReference{ Tag: "latest", Repository: repo, } url1, tr1, err := pool.Resolve(ref, "fake digest", nil) require.NoError(t, err) // auth request + redirect request require.Equal(t, 2, callCount) // reset callCount = 0 url2, tr2, err := pool.Resolve(ref, "fake digest", nil) // get transport from pool and call redirect require.Equal(t, 1, callCount) require.NoError(t, err) require.Equal(t, tr1, tr2) require.Equal(t, url1, url2) failed = true // reset callCount = 0 url3, tr3, err := pool.Resolve(ref, "fake digest", nil) // redirect failed and retry redirect + auth require.Equal(t, 3, callCount) require.NoError(t, err) require.Equal(t, tr2, tr3) require.Equal(t, url2, url3) } nydus-snapshotter-0.13.4/snapshot/000077500000000000000000000000001453374237200171625ustar00rootroot00000000000000nydus-snapshotter-0.13.4/snapshot/mount_option.go000066400000000000000000000304611453374237200222470ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package snapshot import ( "context" "encoding/base64" "encoding/hex" "encoding/json" "fmt" "os" "strings" "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/nydus-snapshotter/config/daemonconfig" "github.com/containerd/nydus-snapshotter/pkg/label" "github.com/containerd/nydus-snapshotter/pkg/layout" "github.com/containerd/nydus-snapshotter/pkg/rafs" "github.com/pkg/errors" ) type ExtraOption struct { Source string `json:"source"` Config string `json:"config"` Snapshotdir string `json:"snapshotdir"` Version string `json:"fs_version"` } func (o *snapshotter) remoteMountWithExtraOptions(ctx context.Context, s storage.Snapshot, id string, overlayOptions []string) ([]mount.Mount, error) { source, err := o.fs.BootstrapFile(id) if err != nil { return nil, err } instance := rafs.RafsGlobalCache.Get(id) daemon, err := o.fs.GetDaemonByID(instance.DaemonID) if err != nil { return nil, errors.Wrapf(err, "get daemon with ID %s", instance.DaemonID) } var c daemonconfig.DaemonConfig if daemon.IsSharedDaemon() { c, err = daemonconfig.NewDaemonConfig(daemon.States.FsDriver, daemon.ConfigFile(instance.SnapshotID)) if err != nil { return nil, errors.Wrapf(err, "Failed to load instance configuration %s", daemon.ConfigFile(instance.SnapshotID)) } } else { c = daemon.Config } configContent, err := c.DumpString() if err != nil { return nil, errors.Wrapf(err, "remoteMounts: failed to marshal config") } // get version from bootstrap f, err := os.Open(source) if err != nil { return nil, errors.Wrapf(err, "remoteMounts: check bootstrap version: failed to open bootstrap") } defer f.Close() header := make([]byte, 4096) sz, err := f.Read(header) if err != nil { return nil, errors.Wrapf(err, "remoteMounts: check bootstrap version: failed to read bootstrap") } version, err := layout.DetectFsVersion(header[0:sz]) if err != nil { return nil, errors.Wrapf(err, "remoteMounts: failed to detect filesystem version") } // when enable nydus-overlayfs, return unified mount slice for runc and kata extraOption := &ExtraOption{ Source: source, Config: configContent, Snapshotdir: o.snapshotDir(s.ID), Version: version, } no, err := json.Marshal(extraOption) if err != nil { return nil, errors.Wrapf(err, "remoteMounts: failed to marshal NydusOption") } // XXX: Log options without extraoptions as it might contain secrets. log.G(ctx).Debugf("fuse.nydus-overlayfs mount options %v", overlayOptions) // base64 to filter easily in `nydus-overlayfs` opt := fmt.Sprintf("extraoption=%s", base64.StdEncoding.EncodeToString(no)) overlayOptions = append(overlayOptions, opt) return []mount.Mount{ { Type: "fuse.nydus-overlayfs", Source: "overlay", Options: overlayOptions, }, }, nil } func (o *snapshotter) mountWithKataVolume(ctx context.Context, id string, overlayOptions []string) ([]mount.Mount, error) { hasVolume := false rafs := rafs.RafsGlobalCache.Get(id) if rafs == nil { return []mount.Mount{}, errors.Errorf("failed to find RAFS instance for snapshot %s", id) } // Insert Kata volume for proxy if label.IsNydusProxyMode(rafs.Annotations) { options, err := o.mountWithProxyVolume(*rafs) if err != nil { return []mount.Mount{}, errors.Wrapf(err, "create kata volume for proxy") } if len(options) > 0 { overlayOptions = append(overlayOptions, options...) hasVolume = true } } // Insert Kata volume for tarfs if blobID, ok := rafs.Annotations[label.NydusTarfsLayer]; ok { options, err := o.mountWithTarfsVolume(*rafs, blobID) if err != nil { return []mount.Mount{}, errors.Wrapf(err, "create kata volume for tarfs") } if len(options) > 0 { overlayOptions = append(overlayOptions, options...) hasVolume = true } } if hasVolume { log.G(ctx).Debugf("fuse.nydus-overlayfs mount options %v", overlayOptions) mounts := []mount.Mount{ { Type: "fuse.nydus-overlayfs", Source: "overlay", Options: overlayOptions, }, } return mounts, nil } return overlayMount(overlayOptions), nil } func (o *snapshotter) mountWithProxyVolume(rafs rafs.Rafs) ([]string, error) { options := []string{} for k, v := range rafs.Annotations { options = append(options, fmt.Sprintf("%s=%s", k, v)) } volume := &KataVirtualVolume{ VolumeType: KataVirtualVolumeImageGuestPullType, Source: "", FSType: "", Options: options, ImagePull: &ImagePullVolume{Metadata: rafs.Annotations}, } if !volume.Validate() { return []string{}, errors.Errorf("got invalid kata volume, %v", volume) } info, err := EncodeKataVirtualVolumeToBase64(*volume) if err != nil { return []string{}, errors.Errorf("failed to encoding Kata Volume info %v", volume) } opt := fmt.Sprintf("%s=%s", KataVirtualVolumeOptionName, info) return []string{opt}, nil } func (o *snapshotter) mountWithTarfsVolume(rafs rafs.Rafs, blobID string) ([]string, error) { var volume *KataVirtualVolume if info, ok := rafs.Annotations[label.NydusImageBlockInfo]; ok { path, err := o.fs.GetTarfsImageDiskFilePath(blobID) if err != nil { return []string{}, errors.Wrapf(err, "get tarfs image disk file path") } volume = &KataVirtualVolume{ VolumeType: KataVirtualVolumeImageRawBlockType, Source: path, FSType: "erofs", Options: []string{"ro"}, } if len(info) > 0 { dmverity, err := parseTarfsDmVerityInfo(info) if err != nil { return []string{}, err } volume.DmVerity = &dmverity } } if volume != nil { if !volume.Validate() { return []string{}, errors.Errorf("got invalid kata volume, %v", volume) } info, err := EncodeKataVirtualVolumeToBase64(*volume) if err != nil { return []string{}, errors.Errorf("failed to encoding Kata Volume info %v", volume) } opt := fmt.Sprintf("%s=%s", KataVirtualVolumeOptionName, info) return []string{opt}, nil } return []string{}, nil } func parseTarfsDmVerityInfo(info string) (DmVerityInfo, error) { var dataBlocks, hashOffset uint64 var rootHash string pattern := "%d,%d,sha256:%s" if count, err := fmt.Sscanf(info, pattern, &dataBlocks, &hashOffset, &rootHash); err == nil && count == 3 { di := DmVerityInfo{ HashType: "sha256", Hash: rootHash, BlockNum: dataBlocks, Blocksize: 512, Hashsize: 4096, Offset: hashOffset, } if err := di.Validate(); err != nil { return DmVerityInfo{}, errors.Wrap(err, "validate dm-verity information") } return di, nil } return DmVerityInfo{}, errors.Errorf("invalid dm-verity information: %s", info) } // Consts and data structures for Kata Virtual Volume const ( minBlockSize = 1 << 9 maxBlockSize = 1 << 19 ) const ( KataVirtualVolumeOptionName = "io.katacontainers.volume" KataVirtualVolumeDirectBlockType = "direct_block" KataVirtualVolumeImageRawBlockType = "image_raw_block" KataVirtualVolumeLayerRawBlockType = "layer_raw_block" KataVirtualVolumeImageNydusBlockType = "image_nydus_block" KataVirtualVolumeLayerNydusBlockType = "layer_nydus_block" KataVirtualVolumeImageNydusFsType = "image_nydus_fs" KataVirtualVolumeLayerNydusFsType = "layer_nydus_fs" KataVirtualVolumeImageGuestPullType = "image_guest_pull" ) // DmVerityInfo contains configuration information for DmVerity device. type DmVerityInfo struct { HashType string `json:"hashtype"` Hash string `json:"hash"` BlockNum uint64 `json:"blocknum"` Blocksize uint64 `json:"blocksize"` Hashsize uint64 `json:"hashsize"` Offset uint64 `json:"offset"` } func (d *DmVerityInfo) Validate() error { err := d.validateHashType() if err != nil { return err } if d.BlockNum == 0 || d.BlockNum > uint64(^uint32(0)) { return fmt.Errorf("Zero block count for DmVerity device %s", d.Hash) } if !validateBlockSize(d.Blocksize) || !validateBlockSize(d.Hashsize) { return fmt.Errorf("Unsupported verity block size: data_block_size = %d, hash_block_size = %d", d.Blocksize, d.Hashsize) } if d.Offset%d.Hashsize != 0 || d.Offset < d.Blocksize*d.BlockNum { return fmt.Errorf("Invalid hashvalue offset %d for DmVerity device %s", d.Offset, d.Hash) } return nil } func (d *DmVerityInfo) validateHashType() error { switch strings.ToLower(d.HashType) { case "sha256": return d.validateHash(64, "sha256") case "sha1": return d.validateHash(40, "sha1") default: return fmt.Errorf("Unsupported hash algorithm %s for DmVerity device %s", d.HashType, d.Hash) } } func (d *DmVerityInfo) validateHash(expectedLen int, hashType string) error { _, err := hex.DecodeString(d.Hash) if len(d.Hash) != expectedLen || err != nil { return fmt.Errorf("Invalid hash value %s:%s for DmVerity device with %s", hashType, d.Hash, hashType) } return nil } func validateBlockSize(blockSize uint64) bool { return minBlockSize <= blockSize && blockSize <= maxBlockSize } func ParseDmVerityInfo(option string) (*DmVerityInfo, error) { no := &DmVerityInfo{} if err := json.Unmarshal([]byte(option), no); err != nil { return nil, errors.Wrapf(err, "DmVerityInfo json unmarshal err") } if err := no.Validate(); err != nil { return nil, fmt.Errorf("DmVerityInfo is not correct, %+v; error = %+v", no, err) } return no, nil } // DirectAssignedVolume contains meta information for a directly assigned volume. type DirectAssignedVolume struct { Metadata map[string]string `json:"metadata"` } func (d *DirectAssignedVolume) Validate() bool { return d.Metadata != nil } // ImagePullVolume contains meta information for pulling an image inside the guest. type ImagePullVolume struct { Metadata map[string]string `json:"metadata"` } func (i *ImagePullVolume) Validate() bool { return i.Metadata != nil } // NydusImageVolume contains Nydus image volume information. type NydusImageVolume struct { Config string `json:"config"` SnapshotDir string `json:"snapshot_dir"` } func (n *NydusImageVolume) Validate() bool { return len(n.Config) > 0 || len(n.SnapshotDir) > 0 } // KataVirtualVolume encapsulates information for extra mount options and direct volumes. type KataVirtualVolume struct { VolumeType string `json:"volume_type"` Source string `json:"source,omitempty"` FSType string `json:"fs_type,omitempty"` Options []string `json:"options,omitempty"` DirectVolume *DirectAssignedVolume `json:"direct_volume,omitempty"` ImagePull *ImagePullVolume `json:"image_pull,omitempty"` NydusImage *NydusImageVolume `json:"nydus_image,omitempty"` DmVerity *DmVerityInfo `json:"dm_verity,omitempty"` } func (k *KataVirtualVolume) Validate() bool { switch k.VolumeType { case KataVirtualVolumeDirectBlockType: if k.Source != "" && k.DirectVolume != nil && k.DirectVolume.Validate() { return true } case KataVirtualVolumeImageRawBlockType, KataVirtualVolumeLayerRawBlockType: if k.Source != "" && (k.DmVerity == nil || k.DmVerity.Validate() == nil) { return true } case KataVirtualVolumeImageNydusBlockType, KataVirtualVolumeLayerNydusBlockType, KataVirtualVolumeImageNydusFsType, KataVirtualVolumeLayerNydusFsType: if k.Source != "" && k.NydusImage != nil && k.NydusImage.Validate() { return true } case KataVirtualVolumeImageGuestPullType: if k.ImagePull != nil && k.ImagePull.Validate() { return true } } return false } func ParseKataVirtualVolume(option []byte) (*KataVirtualVolume, error) { no := &KataVirtualVolume{} if err := json.Unmarshal(option, no); err != nil { return nil, errors.Wrapf(err, "KataVirtualVolume json unmarshal err") } if !no.Validate() { return nil, fmt.Errorf("KataVirtualVolume is not correct, %+v", no) } return no, nil } func ParseKataVirtualVolumeFromBase64(option string) (*KataVirtualVolume, error) { opt, err := base64.StdEncoding.DecodeString(option) if err != nil { return nil, errors.Wrap(err, "KataVirtualVolume base64 decoding err") } return ParseKataVirtualVolume(opt) } func EncodeKataVirtualVolumeToBase64(volume KataVirtualVolume) (string, error) { validKataVirtualVolumeJSON, err := json.Marshal(volume) if err != nil { return "", errors.Wrapf(err, "marshal KataVirtualVolume object") } log.L.Infof("encode kata volume %s", validKataVirtualVolumeJSON) option := base64.StdEncoding.EncodeToString(validKataVirtualVolumeJSON) return option, nil } nydus-snapshotter-0.13.4/snapshot/mount_option_test.go000066400000000000000000000160211453374237200233020ustar00rootroot00000000000000package snapshot import ( "encoding/base64" "encoding/json" "testing" "github.com/stretchr/testify/assert" ) func TestDmVerityInfoValidation(t *testing.T) { TestData := []DmVerityInfo{ { HashType: "md5", // "md5" is not a supported hash algorithm Blocksize: 512, Hashsize: 512, BlockNum: 16384, Offset: 8388608, Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", }, { HashType: "sha256", Blocksize: 3000, // Invalid block size, not a power of 2. Hashsize: 512, BlockNum: 16384, Offset: 8388608, Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", }, { HashType: "sha256", Blocksize: 0, // Invalid block size, less than 512. Hashsize: 512, BlockNum: 16384, Offset: 8388608, Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", }, { HashType: "sha256", Blocksize: 524800, // Invalid block size, greater than 524288. Hashsize: 512, BlockNum: 16384, Offset: 8388608, Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", }, { HashType: "sha256", Blocksize: 512, Hashsize: 3000, // Invalid hash block size, not a power of 2. BlockNum: 16384, Offset: 8388608, Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", }, { HashType: "sha256", Blocksize: 512, Hashsize: 0, // Invalid hash block size, less than 512. BlockNum: 16384, Offset: 8388608, Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", }, { HashType: "sha256", Blocksize: 512, Hashsize: 524800, // Invalid hash block size, greater than 524288. BlockNum: 16384, Offset: 8388608, Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", }, { HashType: "sha256", Blocksize: 512, Hashsize: 512, BlockNum: 0, // Invalid BlockNum, it must be greater than 0. Offset: 8388608, Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", }, { HashType: "sha256", Blocksize: 512, Hashsize: 512, BlockNum: 16384, Offset: 0, // Invalid offset, it must be greater than 0. Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", }, { HashType: "sha256", Blocksize: 512, Hashsize: 512, BlockNum: 16384, Offset: 8193, // Invalid offset, it must be aligned to 512. Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", }, { HashType: "sha256", Blocksize: 512, Hashsize: 512, BlockNum: 16384, Offset: 8388608 - 4096, // Invalid offset, it must be equal to blocksize * BlockNum. Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", }, } for _, d := range TestData { assert.Error(t, d.Validate()) } TestCorrectData := DmVerityInfo{ HashType: "sha256", Blocksize: 512, Hashsize: 512, BlockNum: 16384, Offset: 8388608, Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", } assert.NoError(t, TestCorrectData.Validate()) } func TestDirectAssignedVolumeValidation(t *testing.T) { validDirectVolume := DirectAssignedVolume{ Metadata: map[string]string{"key": "value"}, } assert.True(t, validDirectVolume.Validate()) invalidDirectVolume := DirectAssignedVolume{ Metadata: nil, } assert.False(t, invalidDirectVolume.Validate()) } func TestImagePullVolumeValidation(t *testing.T) { validImagePull := ImagePullVolume{ Metadata: map[string]string{"key": "value"}, } assert.True(t, validImagePull.Validate()) invalidImagePull := ImagePullVolume{ Metadata: nil, } assert.False(t, invalidImagePull.Validate()) } func TestNydusImageVolumeValidation(t *testing.T) { validNydusImage := NydusImageVolume{ Config: "config_value", SnapshotDir: "", } assert.True(t, validNydusImage.Validate()) invalidNydusImage := NydusImageVolume{ Config: "", SnapshotDir: "", } assert.False(t, invalidNydusImage.Validate()) } func TestKataVirtualVolumeValidation(t *testing.T) { validKataVirtualVolume := KataVirtualVolume{ VolumeType: "direct_block", Source: "/dev/sdb", FSType: "ext4", Options: []string{"rw"}, DirectVolume: &DirectAssignedVolume{ Metadata: map[string]string{"key": "value"}, }, // Initialize other fields } assert.True(t, validKataVirtualVolume.Validate()) invalidKataVirtualVolume := KataVirtualVolume{ VolumeType: "direct_block", Source: "/dev/sdb", FSType: "", Options: nil, DirectVolume: &DirectAssignedVolume{ Metadata: nil, }, // Initialize other fields } assert.False(t, invalidKataVirtualVolume.Validate()) } func TestParseDmVerityInfo(t *testing.T) { // Create a mock valid KataVirtualVolume validDmVerityInfo := DmVerityInfo{ HashType: "sha256", Blocksize: 512, Hashsize: 512, BlockNum: 16384, Offset: 8388608, Hash: "9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174", } validKataVirtualVolumeJSON, _ := json.Marshal(validDmVerityInfo) t.Run("Valid Option", func(t *testing.T) { volume, err := ParseDmVerityInfo(string(validKataVirtualVolumeJSON)) assert.NoError(t, err) assert.NotNil(t, volume) assert.NoError(t, volume.Validate()) }) t.Run("Invalid JSON Option", func(t *testing.T) { volume, err := ParseDmVerityInfo("invalid_json") assert.Error(t, err) assert.Nil(t, volume) }) } func TestParseKataVirtualVolume(t *testing.T) { // Create a mock valid KataVirtualVolume validKataVirtualVolume := KataVirtualVolume{ VolumeType: "direct_block", Source: "/dev/sdb", FSType: "ext4", Options: []string{"rw"}, DirectVolume: &DirectAssignedVolume{ Metadata: map[string]string{"key": "value"}, }, // Initialize other fields } validOption, err := EncodeKataVirtualVolumeToBase64(validKataVirtualVolume) assert.Nil(t, err) t.Run("Valid Option", func(t *testing.T) { volume, err := ParseKataVirtualVolumeFromBase64(validOption) assert.NoError(t, err) assert.NotNil(t, volume) assert.True(t, volume.Validate()) }) t.Run("Invalid JSON Option", func(t *testing.T) { invalidJSONOption := base64.StdEncoding.EncodeToString([]byte("invalid_json")) volume, err := ParseKataVirtualVolumeFromBase64(invalidJSONOption) assert.Error(t, err) assert.Nil(t, volume) }) invalidBase64Option := "invalid_base64" t.Run("Invalid Base64 Option", func(t *testing.T) { volume, err := ParseKataVirtualVolumeFromBase64(invalidBase64Option) assert.Error(t, err) assert.Nil(t, volume) }) t.Run("Invalid Fields", func(t *testing.T) { // Create a mock invalid KataVirtualVolume validKataVirtualVolume = KataVirtualVolume{ VolumeType: "direct_block", Source: "/dev/sdb", FSType: "ext4", Options: []string{"rw"}, // Initialize other fields } invalidFieldOption, err := EncodeKataVirtualVolumeToBase64(validKataVirtualVolume) assert.Nil(t, err) volume, err := ParseKataVirtualVolumeFromBase64(invalidFieldOption) assert.Error(t, err) assert.Nil(t, volume) }) } nydus-snapshotter-0.13.4/snapshot/process.go000066400000000000000000000142661453374237200212000ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package snapshot import ( "context" "path" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/containerd/containerd/mount" snpkg "github.com/containerd/containerd/pkg/snapshotters" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/pkg/label" "github.com/containerd/nydus-snapshotter/pkg/snapshot" ) // `storageLocater` provides a local storage for each handler to save their intermediates. // Different actions for different layer types func chooseProcessor(ctx context.Context, logger *logrus.Entry, sn *snapshotter, s storage.Snapshot, key, parent string, labels map[string]string, storageLocater func() string) (_ func() (bool, []mount.Mount, error), target string, err error) { var handler func() (bool, []mount.Mount, error) // Handler to prepare a directory for containerd to download and unpacking layer. defaultHandler := func() (bool, []mount.Mount, error) { mounts, err := sn.mountNative(ctx, labels, s) return false, mounts, err } // Handler to stop containerd from downloading and unpacking layer. skipHandler := func() (bool, []mount.Mount, error) { return true, nil, nil } remoteHandler := func(id string, labels map[string]string) func() (bool, []mount.Mount, error) { return func() (bool, []mount.Mount, error) { logger.Debugf("Prepare remote snapshot %s", id) if err := sn.fs.Mount(ctx, id, labels, &s); err != nil { return false, nil, err } // Let Prepare operation show the rootfs content. if err := sn.fs.WaitUntilReady(id); err != nil { return false, nil, err } logger.Infof("Nydus remote snapshot %s is ready", id) mounts, err := sn.mountRemote(ctx, labels, s, id) return false, mounts, err } } // OCI image is also marked with "containerd.io/snapshot.ref" by Containerd target, isRoLayer := labels[label.TargetSnapshotRef] if isRoLayer { // Containerd won't consume mount slice for below snapshots switch { case config.GetFsDriver() == config.FsDriverProxy: logger.Debugf("proxy image pull request to other agents") if ref := labels[label.CRILayerDigest]; len(ref) > 0 { labels[label.NydusProxyMode] = "true" handler = skipHandler } else { return nil, "", errors.Errorf("missing CRI reference annotation for snapshot %s", s.ID) } case label.IsNydusMetaLayer(labels): logger.Debugf("found nydus meta layer") handler = defaultHandler case label.IsNydusDataLayer(labels): logger.Debugf("found nydus data layer") handler = skipHandler case sn.fs.CheckReferrer(ctx, labels): logger.Debugf("found referenced nydus manifest") handler = skipHandler default: if sn.fs.StargzEnabled() { // Check if the blob is format of estargz if ok, blob := sn.fs.IsStargzDataLayer(labels); ok { err := sn.fs.PrepareStargzMetaLayer(blob, storageLocater(), labels) if err != nil { logger.Errorf("prepare stargz layer of snapshot ID %s, err: %v", s.ID, err) } else { logger.Debugf("found estargz data layer") // Mark this snapshot as stargz layer since estargz image format does not // has special annotation or media type. labels[label.StargzLayer] = "true" handler = skipHandler } } } if handler == nil && sn.fs.TarfsEnabled() { logger.Debugf("convert OCIv1 layer to tarfs") err := sn.fs.PrepareTarfsLayer(ctx, labels, s.ID, sn.upperPath(s.ID)) if err != nil { logger.Warnf("snapshot ID %s can't be converted into tarfs, fallback to containerd, err: %v", s.ID, err) } else { if config.GetTarfsExportEnabled() { _, err = sn.fs.ExportBlockData(s, true, labels, func(id string) string { return sn.upperPath(id) }) if err != nil { return nil, "", errors.Wrap(err, "export layer as tarfs block device") } } handler = skipHandler } } } } else { // Container writable layer comes into this branch. // It should not be committed during this Prepare() operation. pID, pInfo, _, pErr := snapshot.GetSnapshotInfo(ctx, sn.ms, parent) if pErr == nil && label.IsNydusProxyMode(pInfo.Labels) { logger.Infof("Prepare active snapshot %s in proxy mode", key) handler = remoteHandler(pID, pInfo.Labels) } // Hope to find bootstrap layer and prepares to start nydusd // TODO: Trying find nydus meta layer will slow down setting up rootfs to OCI images if handler == nil { if id, info, err := sn.findMetaLayer(ctx, key); err == nil { logger.Infof("Prepare active Nydus snapshot %s", key) handler = remoteHandler(id, info.Labels) } } if handler == nil && sn.fs.ReferrerDetectEnabled() { if id, info, err := sn.findReferrerLayer(ctx, key); err == nil { logger.Infof("Found referenced nydus manifest for image: %s", info.Labels[snpkg.TargetRefLabel]) metaPath := path.Join(sn.snapshotDir(id), "fs", "image.boot") if err := sn.fs.TryFetchMetadata(ctx, info.Labels, metaPath); err != nil { return nil, "", errors.Wrap(err, "try fetch metadata") } handler = remoteHandler(id, info.Labels) } } if handler == nil && pErr == nil && sn.fs.StargzEnabled() && sn.fs.StargzLayer(pInfo.Labels) { if err := sn.fs.MergeStargzMetaLayer(ctx, s); err != nil { return nil, "", errors.Wrap(err, "merge stargz meta layers") } handler = remoteHandler(pID, pInfo.Labels) logger.Infof("Generated estargz merged meta for %s", key) } if handler == nil && pErr == nil && sn.fs.TarfsEnabled() && label.IsTarfsDataLayer(pInfo.Labels) { // Merge and mount tarfs on the uppermost parent layer. // TODO may need to check all parrent layers, in case share layers with other images // which have already been prepared by overlay snapshotter logger.Infof("Prepare active snapshot %s in Nydus tarfs mode", key) err = sn.mergeTarfs(ctx, s, pID, pInfo) if err != nil { return nil, "", errors.Wrapf(err, "merge tarfs layers for snapshot %s", pID) } logger.Infof("Prepared active snapshot %s in Nydus tarfs mode", key) handler = remoteHandler(pID, pInfo.Labels) } } if handler == nil { handler = defaultHandler } return handler, target, err } nydus-snapshotter-0.13.4/snapshot/snapshot.go000066400000000000000000000746521453374237200213660ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package snapshot import ( "context" "fmt" "os" "path/filepath" "strings" "github.com/pkg/errors" "github.com/containerd/containerd/log" "github.com/containerd/containerd/mount" snpkg "github.com/containerd/containerd/pkg/snapshotters" "github.com/containerd/containerd/snapshots" "github.com/containerd/containerd/snapshots/storage" "github.com/containerd/continuity/fs" "github.com/containerd/nydus-snapshotter/config" "github.com/containerd/nydus-snapshotter/config/daemonconfig" "github.com/containerd/nydus-snapshotter/pkg/cache" "github.com/containerd/nydus-snapshotter/pkg/cgroup" v2 "github.com/containerd/nydus-snapshotter/pkg/cgroup/v2" "github.com/containerd/nydus-snapshotter/pkg/errdefs" mgr "github.com/containerd/nydus-snapshotter/pkg/manager" "github.com/containerd/nydus-snapshotter/pkg/metrics" "github.com/containerd/nydus-snapshotter/pkg/metrics/collector" "github.com/containerd/nydus-snapshotter/pkg/pprof" "github.com/containerd/nydus-snapshotter/pkg/referrer" "github.com/containerd/nydus-snapshotter/pkg/system" "github.com/containerd/nydus-snapshotter/pkg/tarfs" "github.com/containerd/nydus-snapshotter/pkg/store" "github.com/containerd/nydus-snapshotter/pkg/filesystem" "github.com/containerd/nydus-snapshotter/pkg/label" "github.com/containerd/nydus-snapshotter/pkg/signature" "github.com/containerd/nydus-snapshotter/pkg/snapshot" ) var _ snapshots.Snapshotter = &snapshotter{} type snapshotter struct { root string nydusdPath string ms *storage.MetaStore // Storing snapshots' state, parentage and other metadata fs *filesystem.Filesystem cgroupManager *cgroup.Manager enableNydusOverlayFS bool enableKataVolume bool syncRemove bool cleanupOnClose bool } func NewSnapshotter(ctx context.Context, cfg *config.SnapshotterConfig) (snapshots.Snapshotter, error) { verifier, err := signature.NewVerifier(cfg.ImageConfig.PublicKeyFile, cfg.ImageConfig.ValidateSignature) if err != nil { return nil, errors.Wrap(err, "initialize image verifier") } db, err := store.NewDatabase(cfg.Root) if err != nil { return nil, errors.Wrap(err, "create database") } rp, err := config.ParseRecoverPolicy(cfg.DaemonConfig.RecoverPolicy) if err != nil { return nil, errors.Wrap(err, "parse recover policy") } var cgroupMgr *cgroup.Manager if cfg.CgroupConfig.Enable { cgroupConfig, err := config.ParseCgroupConfig(cfg.CgroupConfig) if err != nil { return nil, errors.Wrap(err, "parse cgroup configuration") } log.L.Infof("parsed cgroup config: %#v", cgroupConfig) cgroupMgr, err = cgroup.NewManager(cgroup.Opt{ Name: "nydusd", Config: cgroupConfig, }) if err != nil && (err != cgroup.ErrCgroupNotSupported || err != v2.ErrRootMemorySubtreeControllerDisabled) { return nil, errors.Wrap(err, "create cgroup manager") } } var skipSSLVerify bool var daemonConfig *daemonconfig.DaemonConfig fsDriver := config.GetFsDriver() if fsDriver == config.FsDriverFscache || fsDriver == config.FsDriverFusedev { config, err := daemonconfig.NewDaemonConfig(config.GetFsDriver(), cfg.DaemonConfig.NydusdConfigPath) if err != nil { return nil, errors.Wrap(err, "load daemon configuration") } daemonConfig = &config _, backendConfig := config.StorageBackend() skipSSLVerify = backendConfig.SkipVerify } else { skipSSLVerify = config.GetSkipSSLVerify() } fsManagers := []*mgr.Manager{} if cfg.Experimental.TarfsConfig.EnableTarfs { blockdevManager, err := mgr.NewManager(mgr.Opt{ NydusdBinaryPath: "", Database: db, CacheDir: cfg.CacheManagerConfig.CacheDir, RootDir: cfg.Root, RecoverPolicy: rp, FsDriver: config.FsDriverBlockdev, DaemonConfig: nil, CgroupMgr: cgroupMgr, }) if err != nil { return nil, errors.Wrap(err, "create blockdevice manager") } fsManagers = append(fsManagers, blockdevManager) } if config.GetFsDriver() == config.FsDriverFscache { fscacheManager, err := mgr.NewManager(mgr.Opt{ NydusdBinaryPath: cfg.DaemonConfig.NydusdPath, Database: db, CacheDir: cfg.CacheManagerConfig.CacheDir, RootDir: cfg.Root, RecoverPolicy: rp, FsDriver: config.FsDriverFscache, DaemonConfig: daemonConfig, CgroupMgr: cgroupMgr, }) if err != nil { return nil, errors.Wrap(err, "create fscache manager") } fsManagers = append(fsManagers, fscacheManager) } if config.GetFsDriver() == config.FsDriverFusedev { fusedevManager, err := mgr.NewManager(mgr.Opt{ NydusdBinaryPath: cfg.DaemonConfig.NydusdPath, Database: db, CacheDir: cfg.CacheManagerConfig.CacheDir, RootDir: cfg.Root, RecoverPolicy: rp, FsDriver: config.FsDriverFusedev, DaemonConfig: daemonConfig, CgroupMgr: cgroupMgr, }) if err != nil { return nil, errors.Wrap(err, "create fusedev manager") } fsManagers = append(fsManagers, fusedevManager) } if config.GetFsDriver() == config.FsDriverProxy { proxyManager, err := mgr.NewManager(mgr.Opt{ NydusdBinaryPath: "", Database: db, CacheDir: cfg.CacheManagerConfig.CacheDir, RootDir: cfg.Root, RecoverPolicy: rp, FsDriver: config.FsDriverProxy, DaemonConfig: nil, CgroupMgr: cgroupMgr, }) if err != nil { return nil, errors.Wrap(err, "create proxy manager") } fsManagers = append(fsManagers, proxyManager) } metricServer, err := metrics.NewServer( ctx, metrics.WithProcessManagers(fsManagers), ) if err != nil { return nil, errors.Wrap(err, "create metrics server") } // Start to collect metrics. if cfg.MetricsConfig.Address != "" { if err := metrics.NewMetricsHTTPListenerServer(cfg.MetricsConfig.Address); err != nil { return nil, errors.Wrap(err, "start metrics HTTP server") } go func() { if err := metricServer.StartCollectMetrics(ctx); err != nil { log.L.WithError(err).Errorf("Failed to start collecting metrics") } }() log.L.Infof("Started metrics HTTP server on %q", cfg.MetricsConfig.Address) } opts := []filesystem.NewFSOpt{ filesystem.WithManagers(fsManagers), filesystem.WithNydusImageBinaryPath(cfg.DaemonConfig.NydusdPath), filesystem.WithVerifier(verifier), filesystem.WithRootMountpoint(config.GetRootMountpoint()), filesystem.WithEnableStargz(cfg.Experimental.EnableStargz), } cacheConfig := &cfg.CacheManagerConfig cacheMgr, err := cache.NewManager(cache.Opt{ Database: db, Period: config.GetCacheGCPeriod(), CacheDir: cacheConfig.CacheDir, Disabled: cacheConfig.Disable, }) if err != nil { return nil, errors.Wrap(err, "create cache manager") } opts = append(opts, filesystem.WithCacheManager(cacheMgr)) if cfg.Experimental.EnableReferrerDetect { referrerMgr := referrer.NewManager(skipSSLVerify) opts = append(opts, filesystem.WithReferrerManager(referrerMgr)) } if cfg.Experimental.TarfsConfig.EnableTarfs { tarfsMgr := tarfs.NewManager(skipSSLVerify, cfg.Experimental.TarfsConfig.TarfsHint, cacheConfig.CacheDir, cfg.DaemonConfig.NydusImagePath, int64(cfg.Experimental.TarfsConfig.MaxConcurrentProc)) opts = append(opts, filesystem.WithTarfsManager(tarfsMgr)) } nydusFs, err := filesystem.NewFileSystem(ctx, opts...) if err != nil { return nil, errors.Wrap(err, "initialize filesystem thin layer") } if config.IsSystemControllerEnabled() { systemController, err := system.NewSystemController(nydusFs, fsManagers, config.SystemControllerAddress()) if err != nil { return nil, errors.Wrap(err, "create system controller") } go func() { if err := systemController.Run(); err != nil { log.L.WithError(err).Error("Failed to start system controller") } }() log.L.Infof("Started system controller on %q", config.SystemControllerAddress()) pprofAddress := config.SystemControllerPprofAddress() if pprofAddress != "" { if err := pprof.NewPprofHTTPListener(pprofAddress); err != nil { return nil, errors.Wrap(err, "start pprof HTTP server") } log.L.Infof("Started pprof sever on %q", pprofAddress) } } supportsDType, err := getSupportsDType(cfg.Root) if err != nil { return nil, err } if !supportsDType { return nil, fmt.Errorf("%s does not support d_type. If the backing filesystem is xfs, please reformat with ftype=1 to enable d_type support", cfg.Root) } ms, err := storage.NewMetaStore(filepath.Join(cfg.Root, "metadata.db")) if err != nil { return nil, err } if err := os.Mkdir(filepath.Join(cfg.Root, "snapshots"), 0700); err != nil && !os.IsExist(err) { return nil, err } syncRemove := cfg.SnapshotsConfig.SyncRemove if config.GetFsDriver() == config.FsDriverFscache { log.L.Infof("enable syncRemove for fscache mode") syncRemove = true } return &snapshotter{ root: cfg.Root, nydusdPath: cfg.DaemonConfig.NydusdPath, ms: ms, syncRemove: syncRemove, fs: nydusFs, cgroupManager: cgroupMgr, enableNydusOverlayFS: cfg.SnapshotsConfig.EnableNydusOverlayFS, enableKataVolume: cfg.SnapshotsConfig.EnableKataVolume, cleanupOnClose: cfg.CleanupOnClose, }, nil } func (o *snapshotter) Cleanup(ctx context.Context) error { log.L.Debugf("[Cleanup] snapshots") if timer := collector.NewSnapshotMetricsTimer(collector.SnapshotMethodCleanup); timer != nil { defer timer.ObserveDuration() } cleanup, err := o.cleanupDirectories(ctx) if err != nil { return err } log.L.Infof("[Cleanup] orphan directories %v", cleanup) for _, dir := range cleanup { if err := o.cleanupSnapshotDirectory(ctx, dir); err != nil { log.L.WithError(err).Warnf("failed to remove directory %s", dir) } } return nil } func (o *snapshotter) Stat(ctx context.Context, key string) (snapshots.Info, error) { _, info, _, err := snapshot.GetSnapshotInfo(ctx, o.ms, key) return info, err } func (o *snapshotter) Update(ctx context.Context, info snapshots.Info, fieldpaths ...string) (snapshots.Info, error) { return snapshot.UpdateSnapshotInfo(ctx, o.ms, info, fieldpaths...) } func (o *snapshotter) Usage(ctx context.Context, key string) (snapshots.Usage, error) { id, info, usage, err := snapshot.GetSnapshotInfo(ctx, o.ms, key) if err != nil { return snapshots.Usage{}, err } switch info.Kind { case snapshots.KindActive: upperPath := o.upperPath(id) du, err := fs.DiskUsage(ctx, upperPath) if err != nil { return snapshots.Usage{}, err } usage = snapshots.Usage(du) case snapshots.KindCommitted: // Caculate disk space usage under cacheDir of committed snapshots. if label.IsNydusDataLayer(info.Labels) || label.IsTarfsDataLayer(info.Labels) { if blobDigest, ok := info.Labels[snpkg.TargetLayerDigestLabel]; ok { // Try to get nydus meta layer/snapshot disk usage cacheUsage, err := o.fs.CacheUsage(ctx, blobDigest) if err != nil { return snapshots.Usage{}, errors.Wrapf(err, "try to get snapshot %s nydus disk usage", id) } usage.Add(cacheUsage) } } case snapshots.KindUnknown: case snapshots.KindView: } return usage, nil } func (o *snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) { log.L.Debugf("[Mounts] snapshot %s", key) if timer := collector.NewSnapshotMetricsTimer(collector.SnapshotMethodMount); timer != nil { defer timer.ObserveDuration() } var ( needRemoteMounts = false metaSnapshotID string ) id, info, _, err := snapshot.GetSnapshotInfo(ctx, o.ms, key) if err != nil { return nil, errors.Wrapf(err, "mounts get snapshot %q info", key) } log.L.Infof("[Mounts] snapshot %s ID %s Kind %s", key, id, info.Kind) switch info.Kind { case snapshots.KindView: if label.IsNydusMetaLayer(info.Labels) { err = o.fs.WaitUntilReady(id) if err != nil { // Skip waiting if clients is unpacking nydus artifacts to `mounts` // For example, nydus-snapshotter's client like Buildkit is calling snapshotter in below workflow: // 1. [Prepare] snapshot for the uppermost layer - bootstrap // 2. [Mounts] // 3. Unpacking by applying the mounts, then we get bootstrap in its path position. // In above steps, no container write layer is called to set up from nydus-snapshotter. So it has no // chance to start nydusd, during which the Rafs instance is created. if !errors.Is(err, errdefs.ErrNotFound) { return nil, errors.Wrapf(err, "mounts: snapshot %s is not ready, err: %v", id, err) } } else { needRemoteMounts = true metaSnapshotID = id } } else if (o.fs.TarfsEnabled() && label.IsTarfsDataLayer(info.Labels)) || label.IsNydusProxyMode(info.Labels) { needRemoteMounts = true metaSnapshotID = id } case snapshots.KindActive: if info.Parent != "" { pKey := info.Parent if pID, pInfo, _, err := snapshot.GetSnapshotInfo(ctx, o.ms, pKey); err == nil { if label.IsNydusMetaLayer(pInfo.Labels) { if err = o.fs.WaitUntilReady(pID); err != nil { return nil, errors.Wrapf(err, "mounts: snapshot %s is not ready, err: %v", pID, err) } needRemoteMounts = true metaSnapshotID = pID } else if (o.fs.TarfsEnabled() && label.IsTarfsDataLayer(pInfo.Labels)) || label.IsNydusProxyMode(pInfo.Labels) { needRemoteMounts = true metaSnapshotID = pID } } else { return nil, errors.Wrapf(err, "get parent snapshot info, parent key=%q", pKey) } } case snapshots.KindCommitted: case snapshots.KindUnknown: } if o.fs.ReferrerDetectEnabled() && !needRemoteMounts { if id, _, err := o.findReferrerLayer(ctx, key); err == nil { needRemoteMounts = true metaSnapshotID = id } } snap, err := snapshot.GetSnapshot(ctx, o.ms, key) if err != nil { return nil, errors.Wrapf(err, "get snapshot %s", key) } if needRemoteMounts { return o.mountRemote(ctx, info.Labels, *snap, metaSnapshotID) } return o.mountNative(ctx, info.Labels, *snap) } func (o *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) { log.L.Infof("[Prepare] snapshot with key %s parent %s", key, parent) if timer := collector.NewSnapshotMetricsTimer(collector.SnapshotMethodPrepare); timer != nil { defer timer.ObserveDuration() } logger := log.L.WithField("key", key).WithField("parent", parent) info, s, err := o.createSnapshot(ctx, snapshots.KindActive, key, parent, opts) if err != nil { return nil, err } logger.Debugf("[Prepare] snapshot with labels %v", info.Labels) processor, target, err := chooseProcessor(ctx, logger, o, s, key, parent, info.Labels, func() string { return o.upperPath(s.ID) }) if err != nil { return nil, err } needCommit, mounts, err := processor() if needCommit { err := o.Commit(ctx, target, key, append(opts, snapshots.WithLabels(info.Labels))...) if err == nil || errdefs.IsAlreadyExists(err) { return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "target snapshot %q", target) } } return mounts, err } // The work on supporting View operation for nydus-snapshotter is divided into 2 parts: // 1. View on the topmost layer of nydus images or zran images // 2. View on the any layer of nydus images or zran images func (o *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) { log.L.Infof("[View] snapshot with key %s parent %s", key, parent) pID, pInfo, _, err := snapshot.GetSnapshotInfo(ctx, o.ms, parent) if err != nil { return nil, errors.Wrapf(err, "get snapshot %s info", parent) } var ( needRemoteMounts = false metaSnapshotID string ) if label.IsNydusMetaLayer(pInfo.Labels) { // Nydusd might not be running. We should run nydusd to reflect the rootfs. if err = o.fs.WaitUntilReady(pID); err != nil { if errors.Is(err, errdefs.ErrNotFound) { if err := o.fs.Mount(ctx, pID, pInfo.Labels, nil); err != nil { return nil, errors.Wrapf(err, "mount rafs, instance id %s", pID) } if err := o.fs.WaitUntilReady(pID); err != nil { return nil, errors.Wrapf(err, "wait for instance id %s", pID) } } else { return nil, errors.Wrapf(err, "daemon is not running %s", pID) } } needRemoteMounts = true metaSnapshotID = pID } else if label.IsNydusDataLayer(pInfo.Labels) { return nil, errors.New("only can view nydus topmost layer") } // Otherwise, it is OCI snapshots base, s, err := o.createSnapshot(ctx, snapshots.KindView, key, parent, opts) if err != nil { return nil, err } if o.fs.TarfsEnabled() && label.IsTarfsDataLayer(pInfo.Labels) { log.L.Infof("Prepare view snapshot %s in Nydus tarfs mode", pID) err = o.mergeTarfs(ctx, s, pID, pInfo) if err != nil { return nil, errors.Wrapf(err, "merge tarfs layers for snapshot %s", pID) } if err := o.fs.Mount(ctx, pID, pInfo.Labels, &s); err != nil { return nil, errors.Wrapf(err, "mount tarfs, snapshot id %s", pID) } log.L.Infof("Prepared view snapshot %s in Nydus tarfs mode", pID) needRemoteMounts = true metaSnapshotID = pID } if needRemoteMounts { return o.mountRemote(ctx, base.Labels, s, metaSnapshotID) } return o.mountNative(ctx, base.Labels, s) } func (o *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshots.Opt) error { log.L.Debugf("[Commit] snapshot with key %s", key) ctx, t, err := o.ms.TransactionContext(ctx, true) if err != nil { return err } defer func() { if err != nil { if err := t.Rollback(); err != nil { log.L.WithError(err).Warn("failed to rollback transaction") } } }() // grab the existing id id, _, _, err := storage.GetInfo(ctx, key) if err != nil { return err } log.L.Infof("[Commit] snapshot with key %q snapshot id %s", key, id) // For OCI compatibility, we calculate disk usage of the snapshotDir and commit the usage to DB. // Nydus disk usage under the cacheDir will be delayed until containerd queries. usage, err := fs.DiskUsage(ctx, o.upperPath(id)) if err != nil { return err } if _, err = storage.CommitActive(ctx, key, name, snapshots.Usage(usage), opts...); err != nil { return errors.Wrapf(err, "commit active snapshot %s", key) } // Let rollback catch the commit error err = t.Commit() if err != nil { return errors.Wrapf(err, "commit snapshot %s", key) } return err } func (o *snapshotter) Remove(ctx context.Context, key string) error { log.L.Debugf("[Remove] snapshot with key %s", key) if timer := collector.NewSnapshotMetricsTimer(collector.SnapshotMethodRemove); timer != nil { defer timer.ObserveDuration() } ctx, t, err := o.ms.TransactionContext(ctx, true) if err != nil { return err } defer func() { if err != nil { if err := t.Rollback(); err != nil { log.G(ctx).WithError(err).Warn("failed to rollback transaction") } } }() id, info, _, err := storage.GetInfo(ctx, key) if err != nil { return errors.Wrapf(err, "get snapshot %s", key) } switch { case label.IsNydusMetaLayer(info.Labels): log.L.Infof("[Remove] nydus meta snapshot with key %s snapshot id %s", key, id) case label.IsNydusDataLayer(info.Labels): log.L.Infof("[Remove] nydus data snapshot with key %s snapshot id %s", key, id) case label.IsTarfsDataLayer(info.Labels): log.L.Infof("[Remove] nydus tarfs snapshot with key %s snapshot id %s", key, id) default: // For example: remove snapshot with key sha256:c33c40022c8f333e7f199cd094bd56758bc479ceabf1e490bb75497bf47c2ebf log.L.Infof("[Remove] snapshot with key %s snapshot id %s", key, id) } if info.Kind == snapshots.KindCommitted { blobDigest := info.Labels[snpkg.TargetLayerDigestLabel] go func() { if err := o.fs.RemoveCache(blobDigest); err != nil { log.L.WithError(err).Errorf("Failed to remove cache %s", blobDigest) } }() } _, _, err = storage.Remove(ctx, key) if err != nil { return errors.Wrapf(err, "failed to remove key %s", key) } if o.syncRemove { var removals []string removals, err = o.getCleanupDirectories(ctx) if err != nil { return errors.Wrap(err, "get directories for removal") } // Remove directories after the transaction is closed, failures must not // return error since the transaction is committed with the removal // key no longer available. defer func() { if err == nil { for _, dir := range removals { if err := o.cleanupSnapshotDirectory(ctx, dir); err != nil { log.G(ctx).WithError(err).WithField("path", dir).Warn("failed to remove directory") } } } }() } return t.Commit() } func (o *snapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, fs ...string) error { ctx, t, err := o.ms.TransactionContext(ctx, false) if err != nil { return err } defer func() { if err := t.Rollback(); err != nil { log.L.WithError(err) } }() return storage.WalkInfo(ctx, fn, fs...) } func (o *snapshotter) Close() error { log.L.Info("[Close] shutdown snapshotter") if o.cleanupOnClose { err := o.fs.Teardown(context.Background()) if err != nil { log.L.Errorf("failed to clean up remote snapshot, err %v", err) } } o.fs.TryStopSharedDaemon() if o.cgroupManager != nil { if err := o.cgroupManager.Delete(); err != nil { log.L.Errorf("failed to destroy cgroup, err %v", err) } } return o.ms.Close() } func (o *snapshotter) upperPath(id string) string { return filepath.Join(o.root, "snapshots", id, "fs") } // Get the rootdir of nydus image file system contents. func (o *snapshotter) lowerPath(id string) (mnt string, err error) { if mnt, err = o.fs.MountPoint(id); err == nil { return mnt, nil } else if errors.Is(err, errdefs.ErrNotFound) { return filepath.Join(o.root, "snapshots", id, "fs"), nil } return "", err } func (o *snapshotter) workPath(id string) string { return filepath.Join(o.root, "snapshots", id, "work") } func (o *snapshotter) findReferrerLayer(ctx context.Context, key string) (string, snapshots.Info, error) { return snapshot.IterateParentSnapshots(ctx, o.ms, key, func(id string, info snapshots.Info) bool { return o.fs.CheckReferrer(ctx, info.Labels) }) } func (o *snapshotter) findMetaLayer(ctx context.Context, key string) (string, snapshots.Info, error) { return snapshot.IterateParentSnapshots(ctx, o.ms, key, func(id string, i snapshots.Info) bool { return label.IsNydusMetaLayer(i.Labels) }) } func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, key, parent string, opts []snapshots.Opt) (info *snapshots.Info, _ storage.Snapshot, err error) { ctx, t, err := o.ms.TransactionContext(ctx, true) if err != nil { return nil, storage.Snapshot{}, err } rollback := true defer func() { if rollback { if rerr := t.Rollback(); rerr != nil { log.G(ctx).WithError(rerr).Warn("failed to rollback transaction") } } }() var base snapshots.Info for _, opt := range opts { if err := opt(&base); err != nil { return &base, storage.Snapshot{}, err } } if base.Labels == nil { base.Labels = map[string]string{} } var td, path string defer func() { if td != "" { if err1 := o.cleanupSnapshotDirectory(ctx, td); err1 != nil { log.G(ctx).WithError(err1).Warn("failed to clean up temp snapshot directory") } } if path != "" { if err1 := o.cleanupSnapshotDirectory(ctx, path); err1 != nil { log.G(ctx).WithError(err1).WithField("path", path).Error("failed to reclaim snapshot directory, directory may need removal") err = errors.Wrapf(err, "failed to remove path: %v", err1) } } }() td, err = o.prepareDirectory(o.snapshotRoot(), kind) if err != nil { return nil, storage.Snapshot{}, errors.Wrap(err, "create prepare snapshot dir") } s, err := storage.CreateSnapshot(ctx, kind, key, parent, opts...) if err != nil { return nil, storage.Snapshot{}, errors.Wrap(err, "create snapshot") } // Try to keep the whole stack having the same UID and GID if len(s.ParentIDs) > 0 { st, err := os.Stat(o.upperPath(s.ParentIDs[0])) if err != nil { return nil, storage.Snapshot{}, errors.Wrap(err, "stat parent") } if err := lchown(filepath.Join(td, "fs"), st); err != nil { return nil, storage.Snapshot{}, errors.Wrap(err, "perform chown") } } path = o.snapshotDir(s.ID) if err = os.Rename(td, path); err != nil { return nil, storage.Snapshot{}, errors.Wrap(err, "perform rename") } td = "" rollback = false if err = t.Commit(); err != nil { return nil, storage.Snapshot{}, errors.Wrap(err, "perform commit") } path = "" return &base, s, nil } func (o *snapshotter) mergeTarfs(ctx context.Context, s storage.Snapshot, pID string, pInfo snapshots.Info) error { if err := o.fs.MergeTarfsLayers(s, func(id string) string { return o.upperPath(id) }); err != nil { return errors.Wrapf(err, "tarfs merge fail %s", pID) } if config.GetTarfsExportEnabled() { updateFields, err := o.fs.ExportBlockData(s, false, pInfo.Labels, func(id string) string { return o.upperPath(id) }) if err != nil { return errors.Wrap(err, "export tarfs as block image") } if len(updateFields) > 0 { _, err = o.Update(ctx, pInfo, updateFields...) if err != nil { return errors.Wrapf(err, "update snapshot label information") } } } return nil } func bindMount(source, roFlag string) []mount.Mount { return []mount.Mount{ { Type: "bind", Source: source, Options: []string{ roFlag, "rbind", }, }, } } func overlayMount(options []string) []mount.Mount { return []mount.Mount{ { Type: "overlay", Source: "overlay", Options: options, }, } } // `s` is the upmost snapshot and `id` refers to the nydus meta snapshot // `s` and `id` can represent a different layer, it's useful when View an image func (o *snapshotter) mountRemote(ctx context.Context, labels map[string]string, s storage.Snapshot, id string) ([]mount.Mount, error) { var overlayOptions []string if _, ok := labels[label.OverlayfsVolatileOpt]; ok { overlayOptions = append(overlayOptions, "volatile") } lowerPaths := make([]string, 0, 8) lowerPathNydus, err := o.lowerPath(id) if err != nil { return nil, errors.Wrapf(err, "failed to locate overlay lowerdir") } lowerPaths = append(lowerPaths, lowerPathNydus) if s.Kind == snapshots.KindActive { overlayOptions = append(overlayOptions, fmt.Sprintf("workdir=%s", o.workPath(s.ID)), fmt.Sprintf("upperdir=%s", o.upperPath(s.ID)), ) } else if s.Kind == snapshots.KindView { lowerPathNormal, err := o.lowerPath(s.ID) if err != nil { return nil, errors.Wrapf(err, "failed to locate overlay lowerdir for view snapshot") } lowerPaths = append(lowerPaths, lowerPathNormal) } lowerDirOption := fmt.Sprintf("lowerdir=%s", strings.Join(lowerPaths, ":")) overlayOptions = append(overlayOptions, lowerDirOption) log.G(ctx).Infof("remote mount options %v", overlayOptions) if o.enableKataVolume { return o.mountWithKataVolume(ctx, id, overlayOptions) } // Add `extraoption` if NydusOverlayFS is enable or daemonMode is `None` if o.enableNydusOverlayFS || config.GetDaemonMode() == config.DaemonModeNone { return o.remoteMountWithExtraOptions(ctx, s, id, overlayOptions) } return overlayMount(overlayOptions), nil } func (o *snapshotter) mountNative(ctx context.Context, labels map[string]string, s storage.Snapshot) ([]mount.Mount, error) { if len(s.ParentIDs) == 0 { // if we only have one layer/no parents then just return a bind mount as overlay will not work roFlag := "rw" if s.Kind == snapshots.KindView { roFlag = "ro" } return bindMount(o.upperPath(s.ID), roFlag), nil } var options []string if s.Kind == snapshots.KindActive { options = append(options, fmt.Sprintf("workdir=%s", o.workPath(s.ID)), fmt.Sprintf("upperdir=%s", o.upperPath(s.ID)), ) if _, ok := labels[label.OverlayfsVolatileOpt]; ok { options = append(options, "volatile") } } else if len(s.ParentIDs) == 1 { return bindMount(o.upperPath(s.ID), "ro"), nil } parentPaths := make([]string, len(s.ParentIDs)) for i := range s.ParentIDs { parentPaths[i] = o.upperPath(s.ParentIDs[i]) } options = append(options, fmt.Sprintf("lowerdir=%s", strings.Join(parentPaths, ":"))) log.G(ctx).Debugf("overlayfs mount options %s", options) return overlayMount(options), nil } func (o *snapshotter) prepareDirectory(snapshotDir string, kind snapshots.Kind) (string, error) { td, err := os.MkdirTemp(snapshotDir, "new-") if err != nil { return "", errors.Wrap(err, "failed to create temp dir") } if err := os.Mkdir(filepath.Join(td, "fs"), 0755); err != nil { return td, err } if kind == snapshots.KindActive { if err := os.Mkdir(filepath.Join(td, "work"), 0711); err != nil { return td, err } } return td, nil } func (o *snapshotter) getCleanupDirectories(ctx context.Context) ([]string, error) { ids, err := storage.IDMap(ctx) if err != nil { return nil, err } // For example: // 23:default/24/sha256:8c2ed532dce363da2d08489f385c432f7c0ee4509ab4e20eb2778803916adc93 // 24:sha256:c858413d9e5162c287028d630128ea4323d5029bf8a093af783480b38cf8d44e // 25:sha256:fcb51e3c865d96542718beba0bb247376e4c78e039412c5d30c989872e66b6d5 fd, err := os.Open(o.snapshotRoot()) if err != nil { return nil, err } defer fd.Close() dirs, err := fd.Readdirnames(0) if err != nil { return nil, err } cleanup := make([]string, 0, 16) for _, d := range dirs { if _, ok := ids[d]; ok { continue } // When it quits, there will be nothing inside // TODO: try to clean up config/sockets/logs directories cleanup = append(cleanup, o.snapshotDir(d)) } return cleanup, nil } func (o *snapshotter) cleanupDirectories(ctx context.Context) ([]string, error) { // Get a write transaction to ensure no other write transaction can be entered // while the cleanup is scanning. ctx, t, err := o.ms.TransactionContext(ctx, true) if err != nil { return nil, err } defer func() { if err := t.Rollback(); err != nil { log.L.WithError(err) } }() return o.getCleanupDirectories(ctx) } func (o *snapshotter) cleanupSnapshotDirectory(ctx context.Context, dir string) error { // For example: cleanupSnapshotDirectory /var/lib/containerd-nydus/snapshots/34" dir=/var/lib/containerd-nydus/snapshots/34 snapshotID := filepath.Base(dir) if err := o.fs.Umount(ctx, snapshotID); err != nil && !os.IsNotExist(err) { log.G(ctx).WithError(err).WithField("dir", dir).Error("failed to unmount") } if o.fs.TarfsEnabled() { if err := o.fs.DetachTarfsLayer(snapshotID); err != nil && !os.IsNotExist(err) { log.G(ctx).WithError(err).Errorf("failed to detach tarfs layer for snapshot %s", snapshotID) } } if err := os.RemoveAll(dir); err != nil { return errors.Wrapf(err, "remove directory %q", dir) } return nil } func (o *snapshotter) snapshotRoot() string { return filepath.Join(o.root, "snapshots") } func (o *snapshotter) snapshotDir(id string) string { return filepath.Join(o.snapshotRoot(), id) } nydus-snapshotter-0.13.4/snapshot/utils.go000066400000000000000000000006531453374237200206550ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package snapshot import ( "os" "syscall" "github.com/containerd/continuity/fs" ) func getSupportsDType(dir string) (bool, error) { return fs.SupportsDType(dir) } func lchown(target string, st os.FileInfo) error { stat := st.Sys().(*syscall.Stat_t) return os.Lchown(target, int(stat.Uid), int(stat.Gid)) } nydus-snapshotter-0.13.4/tests/000077500000000000000000000000001453374237200164655ustar00rootroot00000000000000nydus-snapshotter-0.13.4/tests/converter_test.go000066400000000000000000000630121453374237200220640ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package tests import ( "archive/tar" "bytes" "compress/gzip" "context" "crypto/rand" "errors" "fmt" "io" "io/fs" "os" "os/exec" "os/user" "path" "path/filepath" "strings" "testing" "time" "github.com/aws/aws-sdk-go-v2/aws" awscfg "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/credentials" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/containerd/containerd" containerdconverter "github.com/containerd/containerd/images/converter" "github.com/containerd/containerd/log" "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/platforms" "github.com/opencontainers/go-digest" "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "github.com/containerd/containerd/content" "github.com/containerd/containerd/content/local" "github.com/containerd/nydus-snapshotter/pkg/backend" "github.com/containerd/nydus-snapshotter/pkg/converter" "github.com/containerd/nydus-snapshotter/pkg/encryption" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) const envNydusdPath = "NYDUS_NYDUSD" var ( privateKey = []byte(`-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAw8mbbvEiQ6BSfsjSq8XEz9ZOS5lOzI2Up3zXlKU9mZN/JBc2 0TGQp0SnSCXYHmzJ9UrXqX2MDU2UFsQpVF0vTrvj+PURYHO5K2NIo8Dqj9uUTq5q ylwYLWWcuUQPLHeShOWDOeiVycaSP2dnSKwZOyhiQc/TvRXZ5oooFBHzMOrKhACv ZOfVxYNrrhwdsIX5+TRL8isxT4y8bkdzhY0R4J6z3aVhOAQhrp7fKtNtEA1edkIE Vd+F7k72qdTCSCNAhjy1Dyom3A9Yii2wNafcEtEr8D3dgnQMnkgpDhPCqLeeecmX n2BmELmBOW9Nio/tR8dc/wpW3OqB5ycmgnGu+QIDAQABAoIBAQCaAJUQmP/Yrdz1 +UUs9C0xRmLjuD1xTNRnQh3YwHlJuelCHDh0KEaeK7RhXdM3a18YYLxuh2CIfkND /Rx9TacOiWByzWHTunMmm7vhgrd+XLu1gCBj+DjUTJ8QY2aEFbHccyPbgwV/Z4BV +yIU2bom/Eb9eVoV24BAhN+tmcju6f6PtGDQciV3QJqnzn+YUpl+e1+qjs1UnvSH fYRDWdoKIeBr9C4NYMh9qMxuduKErld+01aJvthSdxC6E2GKyQNj726IZm5cYQPL tbGc+Om+tR3mI3uK1MJZ00yoThuG216SB2hFqGCqgW4gpXpWGZVyGlh/JiQDDuSL sSFiLqYBAoGBAPXUgX+eIOfwh88tUy+VNKkAQvazv/KF+/eosU2aazJQBxvLRIWL qm1pjEU0ZzUP3a2rEsnZxHh2SYERGGJQVBVUlITQSaeW+XbEZbGCh5x9dTnY0hvc BjRLOk8jGYxAVtvXl88zfhS+c8jNM5M0ECRCP/yFkGE99DzWhXLf/D4ZAoGBAMvj HoZZvNaku3ruNgmI/Kp3Gx3aUiMwXIKXjQ0xc3f0A1Ccc5SAgYXLmLvqB+ZNJ+Sd Fd/87Zpb8kEy+JC5UE4ZwZo2SnL1wDyMZWRw3cTsf8mhvQ1kCpj5fPWUrGzUs/bh ImL6w5sh5IB3BYN5nAtZiRyrqQCHxqW2HK+EJVPhAoGAXLevuABeDNzNfDhuHY46 9Fri5sVY6hHavMflR42sTKeeZr89stjAiM+8VgWzv3GifHP/fB4kWgLTKljWR45g iEMEWStt/EWXBVKBwHeoyj8PTagXZuaPeH2/GkX0xs8lc3lXCpEzRoOmi9/JSgXi 6KoMFCQUFnkVezS11GPicVECgYEAhacXrniK+qW4JIidMbjz8IbtZq9kIp8kNZNF Kn3dNKfnuGMmvRVUUrG5KI3sqcKwQQPcgB1cYFCfyK+yE6T3CIuHxyCJwzxnzQk3 uhTmu51Q04tL08hdzhPWH2JbeWghpNfGY94AdeRM1w2utpX0fdgusnWw7qESzjRI L6JPmeECgYBUkLNcEyrNMc90tk5jdQqCQb/frT6K5k04LjvXe+TlJPHBO3XJun0H OYrCC8EcKknH6jkHejHUdDTG/XjHvohzKI43xg61touKtgFOVpoq79vUBRVOuH85 6vNEksKyKXUKYya19LJS/EpfC2uHUENPSmq/Bh7TDb4y70JWnGTVWA== -----END RSA PRIVATE KEY-----`) publicKey = []byte(`-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw8mbbvEiQ6BSfsjSq8XE z9ZOS5lOzI2Up3zXlKU9mZN/JBc20TGQp0SnSCXYHmzJ9UrXqX2MDU2UFsQpVF0v Trvj+PURYHO5K2NIo8Dqj9uUTq5qylwYLWWcuUQPLHeShOWDOeiVycaSP2dnSKwZ OyhiQc/TvRXZ5oooFBHzMOrKhACvZOfVxYNrrhwdsIX5+TRL8isxT4y8bkdzhY0R 4J6z3aVhOAQhrp7fKtNtEA1edkIEVd+F7k72qdTCSCNAhjy1Dyom3A9Yii2wNafc EtEr8D3dgnQMnkgpDhPCqLeeecmXn2BmELmBOW9Nio/tR8dc/wpW3OqB5ycmgnGu +QIDAQAB -----END PUBLIC KEY-----`) ) func hugeString(mb int) string { var buf strings.Builder size := mb * 1024 * 1024 seqSize := 512 * 1024 buf.Grow(size) seq := size / seqSize for i := 0; i < seq; i++ { data := make([]byte, seqSize) if i%2 == 0 { _, err := rand.Read(data) if err != nil { log.L.WithError(err) } } buf.Write(data) } return buf.String() } func dropCache(t *testing.T) { cmd := exec.Command("sh", "-c", "echo 3 > /proc/sys/vm/drop_caches") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr require.NoError(t, cmd.Run()) } func ensureFile(t *testing.T, name string) { _, err := os.Stat(name) require.NoError(t, err) } func ensureNoFile(t *testing.T, name string) { _, err := os.Stat(name) require.True(t, errors.Is(err, os.ErrNotExist)) } func writeFileToTar(t *testing.T, tw *tar.Writer, name string, data string) { u, err := user.Current() require.NoError(t, err) g, err := user.LookupGroupId(u.Uid) require.NoError(t, err) hdr := &tar.Header{ Name: name, Mode: 0444, Size: int64(len(data)), Uname: u.Name, Gname: g.Name, } err = tw.WriteHeader(hdr) require.NoError(t, err) _, err = io.Copy(tw, bytes.NewReader([]byte(data))) require.Nil(t, err) require.NoError(t, err) } func writeDirToTar(t *testing.T, tw *tar.Writer, name string) { u, err := user.Current() require.NoError(t, err) g, err := user.LookupGroupId(u.Uid) require.NoError(t, err) hdr := &tar.Header{ Name: name, Mode: 0444, Typeflag: tar.TypeDir, Uname: u.Name, Gname: g.Name, } err = tw.WriteHeader(hdr) require.NoError(t, err) } func writeToFile(t *testing.T, reader io.Reader, fileName string) { file, err := os.Create(fileName) require.NoError(t, err) defer file.Close() _, err = io.Copy(file, reader) require.NoError(t, err) } func buildChunkDictTar(t *testing.T, n int) io.ReadCloser { pr, pw := io.Pipe() tw := tar.NewWriter(pw) go func() { defer pw.Close() writeDirToTar(t, tw, "dir-1") for i := 1; i < n; i++ { writeFileToTar(t, tw, fmt.Sprintf("dir-1/file-%d", i), fmt.Sprintf("lower-file-%d", i)) } require.NoError(t, tw.Close()) }() return pr } func buildOCILowerTar(t *testing.T, n int) (io.ReadCloser, map[string]string) { fileTree := map[string]string{} pr, pw := io.Pipe() tw := tar.NewWriter(pw) go func() { defer pw.Close() writeDirToTar(t, tw, "dir-1") fileTree["dir-1"] = "" for i := 1; i < n; i++ { writeFileToTar(t, tw, fmt.Sprintf("dir-1/file-%d", i), fmt.Sprintf("lower-file-%d", i)) fileTree[fmt.Sprintf("dir-1/file-%d", i)] = fmt.Sprintf("lower-file-%d", i) } writeDirToTar(t, tw, "dir-2") fileTree["dir-2"] = "" writeFileToTar(t, tw, "dir-2/file-1", "lower-file-1") fileTree["dir-2/file-1"] = "lower-file-1" require.NoError(t, tw.Close()) }() return pr, fileTree } func buildOCIUpperTar(t *testing.T, teePath string, lowerFileTree map[string]string, tarSize int) (io.ReadCloser, map[string]string) { if lowerFileTree == nil { lowerFileTree = map[string]string{} } hugeStr := hugeString(tarSize) pr, pw := io.Pipe() go func() { tw := tar.NewWriter(pw) defer pw.Close() if len(teePath) > 0 { teew, err := os.OpenFile(teePath, os.O_WRONLY|os.O_CREATE, 0644) require.NoError(t, err) defer teew.Close() tw = tar.NewWriter(io.MultiWriter(pw, teew)) } writeDirToTar(t, tw, "dir-1") lowerFileTree["dir-1"] = "" writeFileToTar(t, tw, "dir-1/.wh.file-1", "") delete(lowerFileTree, "dir-1/file-1") writeDirToTar(t, tw, "dir-2") lowerFileTree["dir-2"] = "" writeFileToTar(t, tw, "dir-2/.wh..wh..opq", "") for k := range lowerFileTree { if strings.HasPrefix(k, "dir-2/") { delete(lowerFileTree, k) } } writeFileToTar(t, tw, "dir-2/file-1", hugeStr) lowerFileTree["dir-2/file-1"] = hugeStr writeFileToTar(t, tw, "dir-2/file-2", "upper-file-2") lowerFileTree["dir-2/file-2"] = "upper-file-2" writeFileToTar(t, tw, "dir-2/file-3", "upper-file-3") lowerFileTree["dir-2/file-3"] = "upper-file-3" require.NoError(t, tw.Close()) }() return pr, lowerFileTree } func packLayer(t *testing.T, source io.ReadCloser, chunkDict, workDir string, fsVersion string) (string, digest.Digest) { var data bytes.Buffer writer := io.Writer(&data) twc, err := converter.Pack(context.TODO(), writer, converter.PackOption{ ChunkDictPath: chunkDict, FsVersion: fsVersion, }) require.NoError(t, err) _, err = io.Copy(twc, source) require.NoError(t, err) err = twc.Close() require.NoError(t, err) blobDigester := digest.Canonical.Digester() _, err = blobDigester.Hash().Write(data.Bytes()) require.NoError(t, err) blobDigest := blobDigester.Digest() tarBlobFilePath := filepath.Join(workDir, blobDigest.Hex()) writeToFile(t, bytes.NewReader(data.Bytes()), tarBlobFilePath) return tarBlobFilePath, blobDigest } func packLayerRef(t *testing.T, gzipSource io.ReadCloser, workDir string) (string, digest.Digest, digest.Digest) { var blobMetaData bytes.Buffer blobMetaWriter := io.Writer(&blobMetaData) pr, pw := io.Pipe() gzipBlobDigester := digest.Canonical.Digester() hw := io.MultiWriter(pw, gzipBlobDigester.Hash()) go func() { defer pw.Close() _, err := io.Copy(hw, gzipSource) require.NoError(t, err) }() twc, err := converter.Pack(context.TODO(), blobMetaWriter, converter.PackOption{ OCIRef: true, }) require.NoError(t, err) _, err = io.Copy(twc, pr) require.NoError(t, err) err = twc.Close() require.NoError(t, err) blobMetaDigester := digest.Canonical.Digester() _, err = blobMetaDigester.Hash().Write(blobMetaData.Bytes()) require.NoError(t, err) blobMetaDigest := blobMetaDigester.Digest() tarBlobMetaFilePath := filepath.Join(workDir, blobMetaDigest.Hex()) writeToFile(t, bytes.NewReader(blobMetaData.Bytes()), tarBlobMetaFilePath) gzipBlobDigest := gzipBlobDigester.Digest() return tarBlobMetaFilePath, blobMetaDigest, gzipBlobDigest } func unpackLayer(t *testing.T, workDir string, ra content.ReaderAt, stream bool) (string, digest.Digest) { var data bytes.Buffer writer := io.Writer(&data) err := converter.Unpack(context.TODO(), ra, writer, converter.UnpackOption{ Stream: stream, }) require.NoError(t, err) digester := digest.Canonical.Digester() _, err = digester.Hash().Write(data.Bytes()) require.NoError(t, err) digest := digester.Digest() tarPath := filepath.Join(workDir, digest.Hex()) writeToFile(t, bytes.NewReader(data.Bytes()), tarPath) return tarPath, digest } func verify(t *testing.T, workDir string, expectedFileTree map[string]string) { mountDir := filepath.Join(workDir, "mnt") blobDir := filepath.Join(workDir, "blobs") nydusdPath := os.Getenv(envNydusdPath) if nydusdPath == "" { nydusdPath = "nydusd" } config := NydusdConfig{ EnablePrefetch: false, NydusdPath: nydusdPath, BootstrapPath: filepath.Join(workDir, "bootstrap"), ConfigPath: filepath.Join(workDir, "nydusd-config.fusedev.json"), BackendType: "localfs", BackendConfig: fmt.Sprintf(`{"dir": "%s"}`, blobDir), BlobCacheDir: filepath.Join(workDir, "cache"), APISockPath: filepath.Join(workDir, "nydusd-api.sock"), MountPath: mountDir, Mode: "direct", DigestValidate: false, } nydusd, err := NewNydusd(config) require.NoError(t, err) err = nydusd.Mount() require.NoError(t, err) defer func() { if err := nydusd.Umount(); err != nil { log.L.WithError(err).Errorf("umount") } }() actualFileTree := map[string]string{} err = filepath.WalkDir(mountDir, func(path string, entry fs.DirEntry, err error) error { require.Nil(t, err) info, err := entry.Info() require.NoError(t, err) targetPath, err := filepath.Rel(mountDir, path) require.NoError(t, err) if targetPath == "." { return nil } data := "" if !info.IsDir() { file, err := os.Open(path) require.NoError(t, err) defer file.Close() _data, err := io.ReadAll(file) require.NoError(t, err) data = string(_data) } actualFileTree[targetPath] = data return nil }) require.NoError(t, err) require.Equal(t, expectedFileTree, actualFileTree) } func buildChunkDict(t *testing.T, workDir, fsVersion string, n int) (string, string) { dictOCITarReader := buildChunkDictTar(t, n) blobDir := filepath.Join(workDir, "blobs") nydusTarPath, lowerNydusBlobDigest := packLayer(t, dictOCITarReader, "", blobDir, fsVersion) ra, err := local.OpenReader(nydusTarPath) require.NoError(t, err) defer ra.Close() layers := []converter.Layer{ { Digest: lowerNydusBlobDigest, ReaderAt: ra, }, } bootstrapPath := filepath.Join(workDir, "dict-bootstrap") file, err := os.Create(bootstrapPath) require.NoError(t, err) defer file.Close() blobDigests, err := converter.Merge(context.TODO(), layers, file, converter.MergeOption{}) require.NoError(t, err) require.Equal(t, []digest.Digest{lowerNydusBlobDigest}, blobDigests) dictBlobPath := "" err = filepath.WalkDir(blobDir, func(path string, entry fs.DirEntry, err error) error { require.NoError(t, err) if path == blobDir { return nil } dictBlobPath = path return nil }) require.NoError(t, err) return bootstrapPath, filepath.Base(dictBlobPath) } func TestPack(t *testing.T) { testPack(t, "5") testPack(t, "6") } func testPack(t *testing.T, fsVersion string) { workDir, err := os.MkdirTemp("", "nydus-converter-test-") require.NoError(t, err) defer os.RemoveAll(workDir) lowerOCITarReader, expectedLowerFileTree := buildOCILowerTar(t, 100) upperOCITarReader, expectedOverlayFileTree := buildOCIUpperTar(t, "", expectedLowerFileTree, 3) blobDir := filepath.Join(workDir, "blobs") err = os.MkdirAll(blobDir, 0755) require.NoError(t, err) cacheDir := filepath.Join(workDir, "cache") err = os.MkdirAll(cacheDir, 0755) require.NoError(t, err) mountDir := filepath.Join(workDir, "mnt") err = os.MkdirAll(mountDir, 0755) require.NoError(t, err) chunkDictBootstrapPath, chunkDictBlobHash := buildChunkDict(t, workDir, fsVersion, 100) lowerNydusTarPath, lowerNydusBlobDigest := packLayer(t, lowerOCITarReader, chunkDictBootstrapPath, blobDir, fsVersion) upperNydusTarPath, upperNydusBlobDigest := packLayer(t, upperOCITarReader, chunkDictBootstrapPath, blobDir, fsVersion) lowerTarRa, err := local.OpenReader(lowerNydusTarPath) require.NoError(t, err) defer lowerTarRa.Close() upperTarRa, err := local.OpenReader(upperNydusTarPath) require.NoError(t, err) defer upperTarRa.Close() layers := []converter.Layer{ { Digest: lowerNydusBlobDigest, ReaderAt: lowerTarRa, }, { Digest: upperNydusBlobDigest, ReaderAt: upperTarRa, }, } bootstrapPath := filepath.Join(workDir, "bootstrap") file, err := os.Create(bootstrapPath) require.NoError(t, err) defer file.Close() blobDigests, err := converter.Merge(context.TODO(), layers, file, converter.MergeOption{ ChunkDictPath: chunkDictBootstrapPath, }) require.NoError(t, err) chunkDictBlobDigest := digest.NewDigestFromHex(string(digest.SHA256), chunkDictBlobHash) expectedBlobDigests := []digest.Digest{chunkDictBlobDigest, upperNydusBlobDigest} require.Equal(t, expectedBlobDigests, blobDigests) verify(t, workDir, expectedOverlayFileTree) dropCache(t) verify(t, workDir, expectedOverlayFileTree) ensureFile(t, filepath.Join(cacheDir, chunkDictBlobHash)+".chunk_map") ensureNoFile(t, filepath.Join(cacheDir, lowerNydusBlobDigest.Hex())+".chunk_map") ensureFile(t, filepath.Join(cacheDir, upperNydusBlobDigest.Hex())+".chunk_map") } // sudo go test -v -count=1 -run TestPackRef ./tests func TestPackRef(t *testing.T) { if os.Getenv("TEST_PACK_REF") == "" { t.Skip("skip TestPackRef test until new nydus-image/nydusd release") } workDir, err := os.MkdirTemp("", "nydus-converter-test-") require.NoError(t, err) defer os.RemoveAll(workDir) blobDir := filepath.Join(workDir, "blobs") err = os.MkdirAll(blobDir, 0755) require.NoError(t, err) cacheDir := filepath.Join(workDir, "cache") err = os.MkdirAll(cacheDir, 0755) require.NoError(t, err) mountDir := filepath.Join(workDir, "mnt") err = os.MkdirAll(mountDir, 0755) require.NoError(t, err) lowerOCITarReader, expectedLowerFileTree := buildOCILowerTar(t, 500) defer lowerOCITarReader.Close() var gzipData bytes.Buffer gzipWriter := gzip.NewWriter(&gzipData) _, err = io.Copy(gzipWriter, lowerOCITarReader) require.NoError(t, err) gzipWriter.Close() dupGzipData := gzipData gzipReader := io.NopCloser(&gzipData) lowerNydusBlobPath, lowerNydusBlobDigest, lowerGzipBlobDigest := packLayerRef(t, gzipReader, blobDir) writeToFile(t, &dupGzipData, path.Join(blobDir, lowerGzipBlobDigest.Hex())) lowerNydusBlobRa, err := local.OpenReader(lowerNydusBlobPath) require.NoError(t, err) defer lowerNydusBlobRa.Close() // Check uncompressed bootstrap digest in TOC bootstrapDigester := digest.Canonical.Digester() bootstrapTOC, err := converter.UnpackEntry(lowerNydusBlobRa, converter.EntryBootstrap, bootstrapDigester.Hash()) require.NoError(t, err) require.Equal(t, bootstrapTOC.GetUncompressedDigest(), bootstrapDigester.Digest().Hex()) // Check uncompressed blob meta digest in TOC blobMetaDigester := digest.Canonical.Digester() blobMetaTOC, err := converter.UnpackEntry(lowerNydusBlobRa, converter.EntryBlobMeta, blobMetaDigester.Hash()) require.NoError(t, err) require.Equal(t, blobMetaTOC.GetUncompressedDigest(), blobMetaDigester.Digest().Hex()) layers := []converter.Layer{ { Digest: lowerNydusBlobDigest, OriginalDigest: &lowerGzipBlobDigest, ReaderAt: lowerNydusBlobRa, }, } bootstrapPath := filepath.Join(workDir, "bootstrap") file, err := os.Create(bootstrapPath) require.NoError(t, err) defer file.Close() blobDigests, err := converter.Merge(context.TODO(), layers, file, converter.MergeOption{ OCIRef: true, }) require.NoError(t, err) require.Equal(t, []digest.Digest{lowerGzipBlobDigest}, blobDigests) verify(t, workDir, expectedLowerFileTree) } // sudo go test -v -count=1 -run TestUnpack ./tests func TestUnpack(t *testing.T) { testUnpack(t, "5", 3) testUnpack(t, "6", 3) } func testUnpack(t *testing.T, fsVersion string, tarSize int) { workDir, err := os.MkdirTemp("", "nydus-converter-test-") require.NoError(t, err) defer os.RemoveAll(workDir) ociTar := filepath.Join(workDir, "oci.tar") ociTarReader, _ := buildOCIUpperTar(t, ociTar, nil, tarSize) nydusTar, _ := packLayer(t, ociTarReader, "", workDir, fsVersion) tarTa, err := local.OpenReader(nydusTar) require.NoError(t, err) defer tarTa.Close() ociTarReader, err = os.OpenFile(ociTar, os.O_RDONLY, 0644) require.NoError(t, err) ociTarDigest, err := digest.Canonical.FromReader(ociTarReader) require.NoError(t, err) for _, stream := range []bool{true, false} { tarPath, newTarDigest := unpackLayer(t, workDir, tarTa, stream) os.RemoveAll(tarPath) require.Equal(t, ociTarDigest, newTarDigest) } } type ConvertTestOption struct { t *testing.T fsVersion string backend converter.Backend disableCheck bool encryptRecipients []string decryptKeys []string beforeConversionHook func() error afterConversionHook func() error } // sudo go test -v -count=1 -run TestImageConvert ./tests func TestImageConvert(t *testing.T) { for _, fsVersion := range []string{"5", "6"} { testImageConvertNoBackend(t, fsVersion) testImageConvertS3Backend(t, fsVersion) testImageConvertWithCrypt(t, fsVersion) } } func testImageConvertNoBackend(t *testing.T, fsVersion string) { testImageConvertBasic(&ConvertTestOption{ t: t, fsVersion: fsVersion, }) } func testImageConvertS3Backend(t *testing.T, fsVersion string) { testOpt := &ConvertTestOption{ t: t, fsVersion: fsVersion, } rawConfig := []byte(`{ "endpoint": "localhost:9000", "scheme": "http", "bucket_name": "nydus", "region": "us-east-1", "object_prefix": "path/to/my-registry/", "access_key_id": "minio", "access_key_secret": "minio123" }`) backend, err := backend.NewBackend("s3", rawConfig, true) if err != nil { t.Fatalf("failed to create s3 backend: %v", err) } testOpt.backend = backend minioContainerName := fmt.Sprintf("minio-%d", time.Now().UnixNano()) testOpt.beforeConversionHook = func() error { // setup minio server if err := exec.Command("docker", "run", "-d", "-p", "9000:9000", "--name", minioContainerName, "-e", "MINIO_ACCESS_KEY=minio", "-e", "MINIO_SECRET_KEY=minio123", "minio/minio", "server", "/data").Run(); err != nil { t.Fatalf("failed to start minio server: %v", err) return err } time.Sleep(5 * time.Second) // create nydus bucket s3AWSConfig, err := awscfg.LoadDefaultConfig(context.TODO()) if err != nil { t.Errorf("failed to load aws config") } client := s3.NewFromConfig(s3AWSConfig, func(o *s3.Options) { o.EndpointResolver = s3.EndpointResolverFromURL("http://localhost:9000") o.Region = "us-east-1" o.UsePathStyle = true o.Credentials = credentials.NewStaticCredentialsProvider("minio", "minio123", "") o.UsePathStyle = true }) _, err = client.CreateBucket(context.Background(), &s3.CreateBucketInput{Bucket: aws.String("nydus")}) if err != nil { return err } logrus.Info("create s3 bucket successfully") return nil } testOpt.afterConversionHook = func() error { if err := exec.Command("docker", "rm", "-f", minioContainerName).Run(); err != nil { return err } return nil } // TODO by now, the last release of nydusify doesn't support s3 backend // so skip the check testOpt.disableCheck = true testImageConvertBasic(testOpt) } func testImageConvertWithCrypt(t *testing.T, fsVersion string) { workDir, err := os.MkdirTemp("", fmt.Sprintf("nydus-bootstrap-crypt-test-%d", time.Now().UnixNano())) require.NoError(t, err) defer os.RemoveAll(workDir) encryptRecipient, err := os.Create(filepath.Join(workDir, "pubkey.pem")) if err != nil { t.Fatalf("failed to create pubkey.pem: %v", err) return } defer encryptRecipient.Close() _, err = encryptRecipient.WriteString(string(publicKey)) if err != nil { t.Fatalf("failed to write into pubkey.pem: %v", err) return } decryptKey, err := os.Create(filepath.Join(workDir, "key.pem")) if err != nil { t.Fatalf("failed to create key.pem: %v", err) return } defer decryptKey.Close() _, err = decryptKey.WriteString(string(privateKey)) if err != nil { t.Fatalf("failed to write into key.pem: %v", err) return } testImageConvertBasic(&ConvertTestOption{ t: t, fsVersion: fsVersion, // TODO set false when nydusify ready disableCheck: true, encryptRecipients: []string{fmt.Sprint("jwe:", encryptRecipient.Name())}, decryptKeys: []string{decryptKey.Name()}, }) } func testImageConvertBasic(testOpt *ConvertTestOption) { const ( srcImageRef = "docker.io/library/nginx:latest" targetImageRef = "localhost:5000/nydus/nginx:nydus-latest" ) t := testOpt.t // setup docker registry if err := exec.Command("docker", "run", "-d", "-p", "5000:5000", "--restart=always", "--name", "registry", "registry:2").Run(); err != nil { t.Fatalf("failed to start docker registry: %v", err) return } defer func() { if err := exec.Command("docker", "stop", "registry").Run(); err != nil { t.Fatalf("failed to stop docker registry: %v", err) } if err := exec.Command("docker", "rm", "registry").Run(); err != nil { t.Fatalf("failed to remove docker registry: %v", err) } }() if testOpt.beforeConversionHook != nil { if err := testOpt.beforeConversionHook(); err != nil { t.Fatalf("failed to run before conversion hook: %v", err) return } defer func() { if err := testOpt.afterConversionHook(); err != nil { t.Fatalf("failed to run after conversion hook: %v", err) } }() } if err := exec.Command("ctr", "images", "pull", srcImageRef).Run(); err != nil { t.Fatalf("failed to pull image %s: %v", srcImageRef, err) return } defer func() { if err := exec.Command("ctr", "images", "rm", srcImageRef).Run(); err != nil { t.Fatalf("failed to remove image %s: %v", srcImageRef, err) } }() workDir, err := os.MkdirTemp("", fmt.Sprintf("nydus-containerd-converter-test-%d", time.Now().UnixNano())) require.NoError(t, err) defer os.RemoveAll(workDir) nydusOpts := &converter.PackOption{ WorkDir: workDir, FsVersion: testOpt.fsVersion, Backend: testOpt.backend, } convertFunc := converter.LayerConvertFunc(*nydusOpts) var encrypter converter.Encrypter if len(testOpt.encryptRecipients) > 0 { encrypter = func(ctx context.Context, cs content.Store, desc ocispec.Descriptor) (ocispec.Descriptor, error) { return encryption.EncryptNydusBootstrap(ctx, cs, desc, testOpt.encryptRecipients) } } convertHooks := containerdconverter.ConvertHooks{ PostConvertHook: converter.ConvertHookFunc(converter.MergeOption{ WorkDir: nydusOpts.WorkDir, BuilderPath: nydusOpts.BuilderPath, FsVersion: nydusOpts.FsVersion, ChunkDictPath: nydusOpts.ChunkDictPath, Backend: testOpt.backend, PrefetchPatterns: nydusOpts.PrefetchPatterns, Encrypt: encrypter, }), } convertFuncOpt := containerdconverter.WithIndexConvertFunc( containerdconverter.IndexConvertFuncWithHook( convertFunc, true, platforms.DefaultStrict(), convertHooks, ), ) client, err := containerd.New("/run/containerd/containerd.sock") if err != nil { t.Fatal(err) return } ctx := namespaces.WithNamespace(context.Background(), "default") if _, err = containerdconverter.Convert(ctx, client, targetImageRef, srcImageRef, convertFuncOpt); err != nil { t.Fatal(err) return } defer func() { if err := exec.Command("ctr", "images", "rm", targetImageRef).Run(); err != nil { t.Fatalf("failed to remove image %s: %v", targetImageRef, err) } }() // push target image if err := exec.Command("ctr", "images", "push", targetImageRef, "--plain-http").Run(); err != nil { t.Fatalf("failed to push image %s: %v", targetImageRef, err) return } // check whether the converted image is valid if testOpt.disableCheck { return } if len(testOpt.decryptKeys) != 0 { if output, err := exec.Command("nydusify", "check", "--source", srcImageRef, "--target", targetImageRef, "--decrypt-keys", strings.Join(testOpt.decryptKeys, ","), "--target-insecure").CombinedOutput(); err != nil { t.Fatalf("failed to check image %s: %v, \noutput:\n%s", targetImageRef, err, output) return } return } if output, err := exec.Command("nydusify", "check", "--source", srcImageRef, "--target", targetImageRef, "--target-insecure").CombinedOutput(); err != nil { t.Fatalf("failed to check image %s: %v, \noutput:\n%s", targetImageRef, err, output) return } } nydus-snapshotter-0.13.4/tests/e2e/000077500000000000000000000000001453374237200171405ustar00rootroot00000000000000nydus-snapshotter-0.13.4/tests/e2e/k8s/000077500000000000000000000000001453374237200176455ustar00rootroot00000000000000nydus-snapshotter-0.13.4/tests/e2e/k8s/containerd.config.toml000066400000000000000000000022501453374237200241330ustar00rootroot00000000000000# explicitly use v2 config format version = 2 [debug] level = "debug" [plugins."io.containerd.grpc.v1.cri".containerd] # save disk space when using a single snapshotter discard_unpacked_layers = false # explicitly use default snapshotter so we can sed it in entrypoint snapshotter = "overlayfs" # explicit default here, as we're configuring it below default_runtime_name = "runc" # nydus snapshotter needs this config disable_snapshot_annotations = false [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] # set default runtime handler to v2, which has a per-pod shim runtime_type = "io.containerd.runc.v2" # Setup a runtime with the magic name ("test-handler") used for Kubernetes # runtime class tests ... [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.test-handler] runtime_type = "io.containerd.runc.v2" [plugins."io.containerd.grpc.v1.cri"] # use fixed sandbox image sandbox_image = "registry.k8s.io/pause:3.6" # allow hugepages controller to be missing # see https://github.com/containerd/cri/pull/1501 tolerate_missing_hugepages_controller = true # restrict_oom_score_adj needs to be true when running inside UserNS (rootless) restrict_oom_score_adj = false nydus-snapshotter-0.13.4/tests/e2e/k8s/kind.yaml000066400000000000000000000005071453374237200214600ustar00rootroot00000000000000kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 networking: ipFamily: dual nodes: - role: control-plane image: kindest/node:v1.23.4 extraMounts: - hostPath: ./tests/e2e/k8s/containerd.config.toml containerPath: /etc/containerd/config.toml - hostPath: /dev/fuse containerPath: /dev/fuse nydus-snapshotter-0.13.4/tests/e2e/k8s/snapshotter-cri.yaml000066400000000000000000000116151453374237200236620ustar00rootroot00000000000000apiVersion: v1 kind: Namespace metadata: name: nydus-system --- apiVersion: v1 kind: ServiceAccount metadata: name: nydus-snapshotter-sa namespace: nydus-system --- apiVersion: v1 kind: Pod metadata: name: nydus-snapshotter namespace: nydus-system spec: containers: - name: nydus-snapshotter image: local-dev:e2e imagePullPolicy: IfNotPresent args: - containerd-nydus-grpc - --nydusd /usr/local/bin/nydusd - --nydusd-config /etc/nydus/nydusd.json - --config /etc/nydus/config.toml - --log-level debug - --daemon-mode shared - --log-to-stdout securityContext: privileged: true volumeMounts: - mountPath: /etc/nydus/ name: nydus-all-config - mountPath: /var/lib/containerd-nydus mountPropagation: Bidirectional name: nydus-lib - mountPath: /run/containerd-nydus mountPropagation: Bidirectional name: nydus-run - mountPath: /run/containerd mountPropagation: Bidirectional name: containerd-run - mountPath: /dev/fuse name: fuse - mountPath: /etc/containerd/config.toml name: containerd-conf hostNetwork: true hostPID: true serviceAccountName: nydus-snapshotter-sa volumes: - name: nydus-all-config projected: sources: - configMap: name: nydusd-config - configMap: name: snapshotter-config - hostPath: path: /run/containerd-nydus type: DirectoryOrCreate name: nydus-run - hostPath: path: /var/lib/containerd-nydus type: DirectoryOrCreate name: nydus-lib - hostPath: path: /run/containerd type: Directory name: containerd-run - hostPath: path: /dev/fuse name: fuse - hostPath: path: /etc/containerd/config.toml type: "" name: containerd-conf --- apiVersion: v1 kind: ConfigMap metadata: name: nydusd-config namespace: nydus-system data: nydusd.json: |- { "device": { "backend": { "type": "registry", "config": { "scheme": "", "skip_verify": true, "timeout": 10, "connect_timeout": 10, "retry_limit": 2 } }, "cache": { "type": "blobcache", "config": { "work_dir": "/var/lib/nydus/cache/" } } }, "mode": "direct", "digest_validate": false, "iostats_files": false, "enable_xattr": true, "fs_prefetch": { "enable": true, "threads_count": 10, "merging_size": 131072, "bandwidth_rate": 1048576 } } --- apiVersion: v1 kind: ConfigMap metadata: name: snapshotter-config namespace: nydus-system data: config.toml: |- version = 1 root = "/var/lib/containerd-nydus" address = "/run/containerd-nydus/containerd-nydus-grpc.sock" daemon_mode = "multiple" enable_system_controller = true # Enable by assigning an address, empty indicates metrics server is disabled metrics_address = ":9110" # Whether tp enable stargz support enable_stargz = false # Whether snapshotter should try to clean up resources when it is closed cleanup_on_close = false [daemon] nydusd_path = "/usr/local/bin/nydusd" nydusimage_path = "/usr/local/bin/nydus-image" # fusedev or fscache fs_driver = "fusedev" # Specify nydusd log level log_level = "info" # How to process when daemon dies: "none", "restart" or "failover" recover_policy = "restart" # Specify a configuration file for nydusd nydusd_config = "/etc/nydus/nydusd.json" # The fuse or fscache IO working threads started by nydusd threads_number = 4 [log] # Snapshotter's log level level = "info" log_rotation_compress = true log_rotation_local_time = true # Max number of days to retain logs log_rotation_max_age = 7 log_rotation_max_backups = 5 # In unit MB(megabytes) log_rotation_max_size = 1 log_to_stdout = false [remote] convert_vpc_registry = false [remote.auth] # Fetch the private registry auth by listening to K8s API server enable_kubeconfig_keychain = false # synchronize `kubernetes.io/dockerconfigjson` secret from kubernetes API server with specified kubeconfig (default `$KUBECONFIG` or `~/.kube/config`) kubeconfig_path = "" # Fetch the private registry auth as CRI image service proxy enable_cri_keychain = true # the target image service when using image proxy image_service_address = "" [snapshot] enable_nydus_overlayfs = false # Whether to remove resources when a snapshot is removed sync_remove = false [cache_manager] disable = false gc_period = "24h" cache_dir = "" [image] public_key_file = "" validate_signature = false nydus-snapshotter-0.13.4/tests/e2e/k8s/snapshotter-kubeconf.yaml000066400000000000000000000123221453374237200246750ustar00rootroot00000000000000apiVersion: v1 kind: Namespace metadata: name: nydus-system --- apiVersion: v1 kind: ServiceAccount metadata: name: nydus-snapshotter-sa namespace: nydus-system --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nydus-snapshotter-role rules: - apiGroups: - "" resources: - secrets verbs: - get - list - watch --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nydus-snapshotter-role-binding roleRef: kind: ClusterRole name: nydus-snapshotter-role apiGroup: rbac.authorization.k8s.io subjects: - kind: ServiceAccount name: nydus-snapshotter-sa namespace: nydus-system --- apiVersion: v1 kind: Pod metadata: name: nydus-snapshotter namespace: nydus-system spec: containers: - name: nydus-snapshotter image: local-dev:e2e imagePullPolicy: IfNotPresent args: - containerd-nydus-grpc - --nydusd /usr/local/bin/nydusd - --nydusd-config /etc/nydus/nydusd.json - --config /etc/nydus/config.toml - --log-level debug - --daemon-mode shared - --log-to-stdout securityContext: privileged: true volumeMounts: - mountPath: /etc/nydus/ name: nydus-all-config - mountPath: /var/lib/containerd-nydus mountPropagation: Bidirectional name: nydus-lib - mountPath: /run/containerd-nydus mountPropagation: Bidirectional name: nydus-run - mountPath: /dev/fuse name: fuse - mountPath: /etc/containerd/config.toml name: containerd-conf hostNetwork: true hostPID: true serviceAccountName: nydus-snapshotter-sa volumes: - name: nydus-all-config projected: sources: - configMap: name: nydusd-config - configMap: name: snapshotter-config - hostPath: path: /run/containerd-nydus type: DirectoryOrCreate name: nydus-run - hostPath: path: /var/lib/containerd-nydus type: DirectoryOrCreate name: nydus-lib - hostPath: path: /dev/fuse name: fuse - hostPath: path: /etc/containerd/config.toml type: "" name: containerd-conf --- apiVersion: v1 kind: ConfigMap metadata: name: nydusd-config namespace: nydus-system data: nydusd.json: |- { "device": { "backend": { "type": "registry", "config": { "scheme": "", "skip_verify": true, "timeout": 10, "connect_timeout": 10, "retry_limit": 2 } }, "cache": { "type": "blobcache", "config": { "work_dir": "/var/lib/nydus/cache/" } } }, "mode": "direct", "digest_validate": false, "iostats_files": false, "enable_xattr": true, "fs_prefetch": { "enable": true, "threads_count": 10, "merging_size": 131072, "bandwidth_rate": 1048576 } } --- apiVersion: v1 kind: ConfigMap metadata: name: snapshotter-config namespace: nydus-system data: config.toml: |- version = 1 root = "/var/lib/containerd-nydus" address = "/run/containerd-nydus/containerd-nydus-grpc.sock" daemon_mode = "multiple" enable_system_controller = true # Enable by assigning an address, empty indicates metrics server is disabled metrics_address = ":9110" # Whether tp enable stargz support enable_stargz = false # Whether snapshotter should try to clean up resources when it is closed cleanup_on_close = false [daemon] nydusd_path = "/usr/local/bin/nydusd" nydusimage_path = "/usr/local/bin/nydus-image" # fusedev or fscache fs_driver = "fusedev" # Specify nydusd log level log_level = "info" # How to process when daemon dies: "none", "restart" or "failover" recover_policy = "restart" # Specify a configuration file for nydusd nydusd_config = "/etc/nydus/nydusd.json" # The fuse or fscache IO working threads started by nydusd threads_number = 4 [log] # Snapshotter's log level level = "info" log_rotation_compress = true log_rotation_local_time = true # Max number of days to retain logs log_rotation_max_age = 7 log_rotation_max_backups = 5 # In unit MB(megabytes) log_rotation_max_size = 1 log_to_stdout = false [remote] convert_vpc_registry = false [remote.auth] # Fetch the private registry auth by listening to K8s API server enable_kubeconfig_keychain = true # synchronize `kubernetes.io/dockerconfigjson` secret from kubernetes API server with specified kubeconfig (default `$KUBECONFIG` or `~/.kube/config`) kubeconfig_path = "" # Fetch the private registry auth as CRI image service proxy enable_cri_keychain = false # the target image service when using image proxy image_service_address = "" [snapshot] enable_nydus_overlayfs = false # Whether to remove resources when a snapshot is removed sync_remove = false [cache_manager] disable = false gc_period = "24h" cache_dir = "" [image] public_key_file = "" validate_signature = false nydus-snapshotter-0.13.4/tests/e2e/k8s/test-pod.yaml.tpl000066400000000000000000000004661453374237200230740ustar00rootroot00000000000000apiVersion: v1 kind: Pod metadata: name: test-pod namespace: nydus-system spec: containers: - name: busybox image: REGISTRY_IP:5000/busybox:nydus-v6-latest imagePullPolicy: Always command: ["sh", "-c"] args: - tail -f /dev/null imagePullSecrets: - name: regcred nydus-snapshotter-0.13.4/tests/nydusd.go000066400000000000000000000075011453374237200203250ustar00rootroot00000000000000/* * Copyright (c) 2022. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package tests import ( "bytes" "context" "encoding/json" "fmt" "io" "net" "net/http" "os" "os/exec" "text/template" "time" "github.com/pkg/errors" ) type NydusdConfig struct { EnablePrefetch bool NydusdPath string BootstrapPath string ConfigPath string BackendType string BackendConfig string BlobCacheDir string APISockPath string MountPath string Mode string DigestValidate bool } // Nydusd runs nydusd binary. type Nydusd struct { NydusdConfig } type daemonInfo struct { State string `json:"state"` } var configTpl = ` { "device": { "backend": { "type": "{{.BackendType}}", "config": {{.BackendConfig}} }, "cache": { "type": "blobcache", "config": { "work_dir": "{{.BlobCacheDir}}" } } }, "mode": "{{.Mode}}", "iostats_files": false, "fs_prefetch": { "enable": {{.EnablePrefetch}}, "threads_count": 10, "merging_size": 131072 }, "digest_validate": {{.DigestValidate}}, "enable_xattr": true } ` func makeConfig(conf NydusdConfig) error { tpl := template.Must(template.New("").Parse(configTpl)) var ret bytes.Buffer if err := tpl.Execute(&ret, conf); err != nil { return errors.New("prepare config template for Nydusd") } if err := os.WriteFile(conf.ConfigPath, ret.Bytes(), 0600); err != nil { return errors.New("write config file for Nydusd") } return nil } // Wait until Nydusd ready by checking daemon state RUNNING func checkReady(ctx context.Context, sock string) <-chan bool { ready := make(chan bool) transport := &http.Transport{ MaxIdleConns: 10, IdleConnTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) { dialer := &net.Dialer{ Timeout: 5 * time.Second, KeepAlive: 5 * time.Second, } return dialer.DialContext(ctx, "unix", sock) }, } client := &http.Client{ Timeout: 30 * time.Second, Transport: transport, } go func() { for { select { case <-ctx.Done(): return default: } resp, err := client.Get(fmt.Sprintf("http://unix%s", "/api/v1/daemon")) if err != nil { continue } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { continue } var info daemonInfo if err = json.Unmarshal(body, &info); err != nil { continue } if info.State == "RUNNING" { ready <- true break } } }() return ready } func NewNydusd(conf NydusdConfig) (*Nydusd, error) { if err := makeConfig(conf); err != nil { return nil, errors.New("create config file for Nydusd") } return &Nydusd{ NydusdConfig: conf, }, nil } func (nydusd *Nydusd) Mount() error { // Ignore the error since the nydusd may not ever start _ = nydusd.Umount() args := []string{ "--config", nydusd.ConfigPath, "--mountpoint", nydusd.MountPath, "--bootstrap", nydusd.BootstrapPath, "--apisock", nydusd.APISockPath, "--log-level", "error", } cmd := exec.Command(nydusd.NydusdPath, args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr runErr := make(chan error) go func() { runErr <- cmd.Run() }() ctx, cancel := context.WithCancel(context.Background()) defer cancel() ready := checkReady(ctx, nydusd.APISockPath) select { case err := <-runErr: if err != nil { return errors.Wrap(err, "run Nydusd binary") } case <-ready: return nil case <-time.After(10 * time.Second): return errors.New("timeout to wait Nydusd ready") } return nil } func (nydusd *Nydusd) Umount() error { if _, err := os.Stat(nydusd.MountPath); err == nil { cmd := exec.Command("umount", nydusd.MountPath) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return err } } return nil } nydus-snapshotter-0.13.4/tools/000077500000000000000000000000001453374237200164635ustar00rootroot00000000000000nydus-snapshotter-0.13.4/tools/optimizer-server/000077500000000000000000000000001453374237200220115ustar00rootroot00000000000000nydus-snapshotter-0.13.4/tools/optimizer-server/Cargo.lock000066400000000000000000000245101453374237200237200ustar00rootroot00000000000000# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" dependencies = [ "bitflags", "clap_lex", "is-terminal", "strsim", "termcolor", ] [[package]] name = "clap_lex" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" dependencies = [ "os_str_bytes", ] [[package]] name = "errno" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" dependencies = [ "errno-dragonfly", "libc", "winapi", ] [[package]] name = "errno-dragonfly" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ "cc", "libc", ] [[package]] name = "hermit-abi" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[package]] name = "io-lifetimes" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" dependencies = [ "libc", "windows-sys", ] [[package]] name = "is-terminal" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" dependencies = [ "hermit-abi", "io-lifetimes", "rustix", "windows-sys", ] [[package]] name = "itoa" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" [[package]] name = "linux-raw-sys" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "memoffset" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ "autocfg", ] [[package]] name = "nix" version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ "bitflags", "cfg-if", "libc", "memoffset", "pin-utils", "static_assertions", ] [[package]] name = "optimizer-server" version = "0.1.0" dependencies = [ "clap", "lazy_static", "libc", "nix", "serde", "serde_json", "signal-hook", ] [[package]] name = "os_str_bytes" version = "6.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5308e8208729c3e1504a6cfad0d5daacc4614c9a2e65d1ea312a34b5cb00fe84" dependencies = [ "proc-macro2", ] [[package]] name = "rustix" version = "0.36.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", "windows-sys", ] [[package]] name = "ryu" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "serde" version = "1.0.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71f2b4817415c6d4210bfe1c7bfcf4801b2d904cb4d0e1a8fdb651013c9e86b8" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d071a94a3fac4aff69d023a7f411e33f40f3483f8c5190b1953822b6b76d7630" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "signal-hook" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" dependencies = [ "libc", "signal-hook-registry", ] [[package]] name = "signal-hook-registry" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "termcolor" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] [[package]] name = "unicode-ident" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" nydus-snapshotter-0.13.4/tools/optimizer-server/Cargo.toml000066400000000000000000000006361453374237200237460ustar00rootroot00000000000000[package] name = "optimizer-server" version = "0.1.0" edition = "2021" description = "Optimizer server to generate accessed files in target mount namespace" authors = ["The Nydus Developers"] license = "Apache-2.0 OR BSD-3-Clause" [dependencies] clap = "4.1.8" lazy_static = "1.4.0" libc = "0.2.140" nix = "0.26.2" serde = { version="1.0.152", features = ["derive"] } serde_json = "1.0.93" signal-hook = "0.3.15" nydus-snapshotter-0.13.4/tools/optimizer-server/Makefile000066400000000000000000000007441453374237200234560ustar00rootroot00000000000000all: build .PHONY: .release_version .format build release .release_version: $(eval CARGO_BUILD_FLAGS += --release) .format: cargo fmt -- --check build: .format cargo build $(CARGO_BUILD_FLAGS) cargo clippy $(CARGO_BUILD_FLAGS) -- -Dwarnings release: .format .release_version build static-release: .format cargo clippy $(CARGO_BUILD_FLAGS) -- -Dwarnings RUSTFLAGS="-C target-feature=+crt-static" cargo build --release --target x86_64-unknown-linux-gnu clean: cargo cleannydus-snapshotter-0.13.4/tools/optimizer-server/src/000077500000000000000000000000001453374237200226005ustar00rootroot00000000000000nydus-snapshotter-0.13.4/tools/optimizer-server/src/main.rs000066400000000000000000000164751453374237200241070ustar00rootroot00000000000000/* * Copyright (c) 2023. Nydus Developers. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ use std::{ env, ffi, fs, io, io::Write, mem, os::unix::{io::AsRawFd, net::UnixStream}, path::{Path, PathBuf}, slice, time::Instant, }; use nix::{ poll::{poll, PollFd, PollFlags}, sched::{setns, CloneFlags}, unistd::{ fork, getpgid, ForkResult::{Child, Parent}, }, }; use serde::Serialize; use lazy_static::lazy_static; use signal_hook::{consts::SIGTERM, low_level::pipe}; #[derive(Debug, Clone, Copy)] #[repr(C)] struct FanotifyEvent { event_len: u32, vers: u8, reserved: u8, metadata_len: u16, mask: u64, fd: i32, pid: i32, } #[derive(Serialize, Debug)] struct EventInfo { path: String, size: u64, elapsed: u128, } impl PartialEq for EventInfo { fn eq(&self, target: &EventInfo) -> bool { self.path == target.path } } lazy_static! { static ref FAN_EVENT_METADATA_LEN: usize = mem::size_of::(); static ref BEGIN_TIME: Instant = Instant::now(); } const DEFAULT_TARGET: &str = "/"; const FAN_CLOEXEC: u32 = 0x0000_0001; const FAN_NONBLOCK: u32 = 0x0000_0002; const FAN_CLASS_CONTENT: u32 = 0x0000_0004; const O_RDONLY: u32 = 0; const O_LARGEFILE: u32 = 0; const FAN_MARK_ADD: u32 = 0x0000_0001; const FAN_MARK_MOUNT: u32 = 0x0000_0010; const FAN_ACCESS: u64 = 0x0000_0001; const FAN_OPEN: u64 = 0x0000_0020; const FAN_OPEN_EXEC: u64 = 0x00001000; const AT_FDCWD: i32 = -100; #[derive(Debug)] enum SetnsError { IO(io::Error), Nix(nix::Error), } #[derive(Debug)] enum SendError { IO(io::Error), Serde(serde_json::Error), } fn get_pid() -> Option { env::var("_MNTNS_PID").ok() } fn get_target() -> String { env::var("_TARGET").map_or(DEFAULT_TARGET.to_string(), |str| str) } fn get_fd_path(fd: i32) -> io::Result { let fd_path = format!("/proc/self/fd/{fd}"); fs::read_link(fd_path) } fn set_ns(ns_path: String, flags: CloneFlags) -> Result<(), SetnsError> { let file = fs::File::open(Path::new(ns_path.as_str())).map_err(SetnsError::IO)?; setns(file.as_raw_fd(), flags).map_err(SetnsError::Nix) } fn init_fanotify() -> Result { unsafe { match libc::fanotify_init( FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK, O_RDONLY | O_LARGEFILE, ) { -1 => Err(io::Error::last_os_error()), fd => Ok(fd), } } } fn mark_fanotify(fd: i32, path: &str) -> Result<(), io::Error> { let path = ffi::CString::new(path)?; unsafe { match libc::fanotify_mark( fd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_OPEN | FAN_ACCESS | FAN_OPEN_EXEC, AT_FDCWD, path.as_ptr(), ) { 0 => Ok(()), _ => Err(io::Error::last_os_error()), } } } fn read_fanotify(fanotify_fd: i32) -> Vec { let mut vec = Vec::new(); unsafe { let buffer = libc::malloc(*FAN_EVENT_METADATA_LEN * 1024); let sizeof = libc::read(fanotify_fd, buffer, *FAN_EVENT_METADATA_LEN * 1024); let src = slice::from_raw_parts( buffer as *mut FanotifyEvent, sizeof as usize / *FAN_EVENT_METADATA_LEN, ); vec.extend_from_slice(src); libc::free(buffer); } vec } fn close_fd(fd: i32) { unsafe { libc::close(fd); } } fn generate_event_info(path: &Path) -> Result { fs::metadata(path).map(|metadata| EventInfo { path: path.to_string_lossy().to_string(), size: metadata.len(), elapsed: BEGIN_TIME.elapsed().as_micros(), }) } fn send_event(event: &EventInfo) -> Result<(), SendError> { let mut writer = io::stdout(); let event_string = serde_json::to_string(event).map_err(SendError::Serde)?; writer .write_all(format!("{event_string}\n").as_bytes()) .map_err(SendError::IO)?; writer.flush().map_err(SendError::IO) } fn handle_event(event: &FanotifyEvent, event_duplicate: &mut Vec) -> Result<(), SendError> { let path = get_fd_path(event.fd).map_err(SendError::IO)?; let info = generate_event_info(&path).map_err(SendError::IO)?; if !event_duplicate.contains(&info.path) { send_event(&info)?; event_duplicate.push(info.path); } Ok(()) } fn handle_fanotify_event(fd: i32) { let mut event_duplicate = Vec::new(); let (reader, writer) = match UnixStream::pair() { Ok((reader, writer)) => (reader, writer), Err(e) => { eprintln!("failed to create a pair of sockets: {e:?}"); return; } }; if let Err(e) = pipe::register(SIGTERM, writer) { eprintln!("failed to set SIGTERM signal handler {e:?}"); return; } let mut fds = [ PollFd::new(fd.as_raw_fd(), PollFlags::POLLIN), PollFd::new(reader.as_raw_fd(), PollFlags::POLLIN), ]; loop { match poll(&mut fds, -1) { Ok(polled_num) => { if polled_num <= 0 { eprintln!("polled_num <= 0!"); break; } if let Some(flag) = fds[0].revents() { if flag.contains(PollFlags::POLLIN) { let events = read_fanotify(fd); for event in events { if let Err(e) = handle_event(&event, &mut event_duplicate) { eprintln!("failed to handle event {event:?} {e:?}") }; // No matter the target path is valid or not, we should close the fd close_fd(event.fd); } } } if let Some(flag) = fds[1].revents() { if flag.contains(PollFlags::POLLIN) { println!("received SIGTERM signal"); break; } } } Err(e) => { if e == nix::Error::EINTR { continue; } eprintln!("Poll error {:?}", e); break; } } } } fn start_fanotify() -> Result<(), io::Error> { let fd = init_fanotify()?; mark_fanotify(fd, get_target().as_str())?; handle_fanotify_event(fd); Ok(()) } fn join_namespace(pid: String) -> Result<(), SetnsError> { set_ns(format!("/proc/{pid}/ns/pid"), CloneFlags::CLONE_NEWPID)?; set_ns(format!("/proc/{pid}/ns/mnt"), CloneFlags::CLONE_NEWNS)?; Ok(()) } fn main() { if let Some(pid) = get_pid() { if let Err(e) = join_namespace(pid) { eprintln!("join namespace failed {e:?}"); return; } } let pid = unsafe { fork() }; match pid.expect("fork failed: unable to create child process") { Child => { if let Err(e) = start_fanotify() { eprintln!("failed to start fanotify server {e:?}"); } } Parent { child } => { if let Err(e) = getpgid(Some(child)).map(|pgid| { eprintln!("forked optimizer server subprocess, pid: {child}, pgid: {pgid}"); }) { eprintln!("failed to get pgid of {child} {e:?}"); }; } } } nydus-snapshotter-0.13.4/version/000077500000000000000000000000001453374237200170105ustar00rootroot00000000000000nydus-snapshotter-0.13.4/version/version.go000066400000000000000000000010051453374237200210200ustar00rootroot00000000000000/* * Copyright (c) 2020. Ant Group. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ package version import "runtime" var ( // Version holds the complete version number. Filled in at linking time. Version = "unknown" // Revision is filled with the VCS (e.g. git) revision being used to build // the program at linking time. Revision = "unknown" // GoVersion is Go tree's version. GoVersion = runtime.Version() // BuildTimestamp is timestamp of building. BuildTimestamp = "unknown" )