pax_global_header00006660000000000000000000000064147015065340014517gustar00rootroot0000000000000052 comment=7920be28f7f58020c4da8ab9bb78554ad7cd67ea fulcio-1.6.5/000077500000000000000000000000001470150653400130115ustar00rootroot00000000000000fulcio-1.6.5/.gitattributes000066400000000000000000000001001470150653400156730ustar00rootroot00000000000000/pkg/generated/protobuf/** linguist-generated *.sh text eol=lf fulcio-1.6.5/.github/000077500000000000000000000000001470150653400143515ustar00rootroot00000000000000fulcio-1.6.5/.github/dependabot.yml000066400000000000000000000026421470150653400172050ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "gomod" directory: "/" # Location of package manifests schedule: interval: "weekly" groups: all: update-types: - "patch" - package-ecosystem: "gomod" directory: "./hack/tools" schedule: interval: "weekly" groups: all: update-types: - "minor" - "patch" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" groups: all: update-types: - "minor" - "patch" - package-ecosystem: "docker" directory: "/" schedule: interval: "weekly" groups: all: update-types: - "minor" - "patch" fulcio-1.6.5/.github/workflows/000077500000000000000000000000001470150653400164065ustar00rootroot00000000000000fulcio-1.6.5/.github/workflows/codeql-analysis.yml000066400000000000000000000044321470150653400222240ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed name: CodeQL on: push: branches: [ main ] pull_request: # The branches below must be a subset of the branches above branches: [ main ] schedule: - cron: '45 10 * * 1' permissions: contents: read security-events: write jobs: analyze: name: Analyze runs-on: ubuntu-latest strategy: fail-fast: false matrix: language: [ 'go' ] steps: - name: Checkout repository uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 # TODO: uncomment when we bump to go1.22 in go.mod # - name: Extract version of Go to use # run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: '1.22' check-latest: true - uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 name: Install protobuf with: version: '24.0' repo-token: ${{ secrets.GITHUB_TOKEN }} # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@65c74964a9ed8c44ed9f19d4bbc5757a6a8e9ab9 # v2.16.1 with: languages: ${{ matrix.language }} - name: Autobuild uses: github/codeql-action/autobuild@65c74964a9ed8c44ed9f19d4bbc5757a6a8e9ab9 # v2.16.1 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@65c74964a9ed8c44ed9f19d4bbc5757a6a8e9ab9 # v2.16.1 fulcio-1.6.5/.github/workflows/container-build.yml000066400000000000000000000040731470150653400222140ustar00rootroot00000000000000# # Copyright 2023 The Sigstore 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. name: CI-Container-Build on: workflow_dispatch: push: branches: - main jobs: build: name: build runs-on: ubuntu-latest if: github.repository == 'sigstore/fulcio' permissions: id-token: write contents: read steps: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 - name: Extract version of Go to use run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: '${{ env.GOVERSION }}' check-latest: true - name: deps run: sudo apt-get update && sudo apt-get install -yq libpcsclite-dev - uses: ko-build/setup-ko@3aebd0597dc1e9d1a26bcfdb7cbeb19c131d3037 # v0.7 - name: Set up Cloud SDK uses: google-github-actions/auth@8254fb75a33b976a221574d287e93919e6a36f70 # v2.1.6 with: workload_identity_provider: 'projects/498091336538/locations/global/workloadIdentityPools/githubactions/providers/sigstore-fulcio' service_account: 'github-actions-fulcio@projectsigstore.iam.gserviceaccount.com' - name: creds run: gcloud auth configure-docker --quiet - name: container run: KO_PREFIX=gcr.io/projectsigstore/fulcio/ci/fulcio make sign-keyless-ci fulcio-1.6.5/.github/workflows/cut-release.yml000066400000000000000000000017341470150653400213470ustar00rootroot00000000000000name: Cut Release on: workflow_dispatch: inputs: release_tag: required: true type: string description: 'Release tag' key_ring: required: true type: string description: 'Key ring for cosign key' key_name: required: true type: string description: 'Key name for cosign key' concurrency: cut-release jobs: cut-release: name: Cut release uses: sigstore/community/.github/workflows/reusable-release.yml@main permissions: id-token: write contents: read with: release_tag: ${{ github.event.inputs.release_tag }} key_ring: ${{ github.event.inputs.key_ring }} key_name: ${{ github.event.inputs.key_name }} workload_identity_provider: 'projects/498091336538/locations/global/workloadIdentityPools/githubactions/providers/sigstore-fulcio' service_account: 'github-actions-fulcio@projectsigstore.iam.gserviceaccount.com' repo: 'fulcio' fulcio-1.6.5/.github/workflows/depsreview.yml000066400000000000000000000017101470150653400213050ustar00rootroot00000000000000# # Copyright 2022 The Sigstore 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. name: 'Dependency Review' on: [pull_request] permissions: contents: read jobs: dependency-review: name: License and Vulnerability Scan uses: sigstore/community/.github/workflows/reusable-dependency-review.yml@f57b2d1c73f8595fe268259720efb21388db2a27 with: allow-deps: pkg:githubactions/arduino/setup-protoc@9b1ee5b22b0a3f1feb8c2ff99b32c89b3c3191e9 # v2.0.0 fulcio-1.6.5/.github/workflows/main.yml000066400000000000000000000037221470150653400200610ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. name: CI on: push: branches: [ main, development ] pull_request: branches: [ main, development ] permissions: contents: read jobs: build: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Extract version of Go to use run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: ${{ env.GOVERSION }} check-latest: true - uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 name: Install protobuf with: version: '28.0' repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Build run: make -C $GITHUB_WORKSPACE all - name: Test run: go test -v -coverprofile=coverage.txt -covermode=atomic ./... - name: Upload Coverage Report uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0 - name: Ensure no files were modified as a result of the build run: git update-index --refresh && git diff-index --quiet -I"^\/\/\s+(-\s+)?protoc(-gen-go)?\s+v[0-9]+\.[0-9]+\.[0-9]+$" HEAD -- || git diff -I"^\/\/\s+(-\s+)?protoc(-gen-go)?\s+v[0-9]+\.[0-9]+\.[0-9]+$" --exit-code fulcio-1.6.5/.github/workflows/protoc-dependabot-hack.yml000066400000000000000000000011441470150653400234460ustar00rootroot00000000000000--- # This file will never actually run, and simply exists as a hack to trigger dependabot # to notify us if protobuf issues a new release that we should upgrade to name: Dependabot hack on: # yamllint disable-line rule:truthy push: branches: - never-trigger-this-dependabot-hack-workflow jobs: dependabot_hack: name: Ensure dependabot version checks runs-on: ubuntu-latest steps: # update the version in these places manually when Dependabot proposes a change to it here: # 1. the version in main.yml used to install protoc - uses: protocolbuffers/protobuf@v28.2 fulcio-1.6.5/.github/workflows/scorecard_action.yml000066400000000000000000000040341470150653400224340ustar00rootroot00000000000000name: Scorecards supply-chain security on: # Only the default branch is supported. branch_protection_rule: schedule: # Weekly on Saturdays. - cron: '30 1 * * 6' push: branches: [ main ] # Declare default permissions as read only. permissions: read-all jobs: analysis: name: Scorecards analysis runs-on: ubuntu-latest permissions: # Needed to upload the results to code-scanning dashboard. security-events: write actions: read contents: read id-token: write steps: - name: "Checkout code" uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: persist-credentials: false - name: "Run analysis" uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 with: results_file: results.sarif results_format: sarif # Read-only PAT token. To create it, # follow the steps in https://github.com/ossf/scorecard-action#pat-token-creation. repo_token: ${{ secrets.SCORECARD_TOKEN }} # Publish the results for public repositories to enable scorecard badges. For more details, see # https://github.com/ossf/scorecard-action#publishing-results. # For private repositories, `publish_results` will automatically be set to `false`, regardless # of the value entered here. publish_results: true # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: name: SARIF file path: results.sarif retention-days: 5 # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" uses: github/codeql-action/upload-sarif@65c74964a9ed8c44ed9f19d4bbc5757a6a8e9ab9 # v2.13.4 with: sarif_file: results.sarif fulcio-1.6.5/.github/workflows/validate-release.yml000066400000000000000000000050671470150653400223500ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. name: CI-Validate-Release-Job on: push: branches: - main - 'release-**' pull_request: permissions: {} jobs: check-signature: runs-on: ubuntu-latest container: image: ghcr.io/sigstore/cosign/cosign:v2.4.1-dev@sha256:a1bb112f1758703aa1d222bf30b9655d04cf196c0b7feaf3479d1222c2283590 steps: - name: Check Signature run: | cosign verify ghcr.io/gythialy/golang-cross:v1.23.2-0@sha256:8feb33a131baabdef112d924a4379ff6b0a4f00a4854f97b0dc73742198638bd \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ --certificate-identity "https://github.com/gythialy/golang-cross/.github/workflows/release-golang-cross.yml@refs/tags/v1.23.2-0" env: TUF_ROOT: /tmp validate-release-job: runs-on: ubuntu-latest needs: - check-signature container: image: ghcr.io/gythialy/golang-cross:v1.23.2-0@sha256:8feb33a131baabdef112d924a4379ff6b0a4f00a4854f97b0dc73742198638bd steps: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 # Error: fatal: detected dubious ownership in repository at '/__w/fulcio/fulcio' # To add an exception for this directory, call: # git config --system --add safe.directory /__w/fulcio/fulcio # Reason: Recent versions of git require the .git folder to be owned # by the same user (see https://github.blog/2022-04-12-git-security-vulnerability-announced/). # Related # - https://github.com/actions/runner/issues/2033 # - https://github.com/actions/checkout/issues/1048 # - https://github.com/actions/runner-images/issues/6775 - run: git config --system --add safe.directory /__w/fulcio/fulcio - name: goreleaser snapshot run: make snapshot env: PROJECT_ID: honk-fake-project RUNTIME_IMAGE: gcr.io/distroless/static:debug-nonroot - name: check binaries run: | ./dist/fulcio-linux-amd64 version fulcio-1.6.5/.github/workflows/verify-k8s.yml000066400000000000000000000175411470150653400211500ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. name: Verify-K8s on: [push, pull_request] permissions: contents: read jobs: verify-k8s-manifests: name: k8s manifest check runs-on: ubuntu-latest steps: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Extract version of Go to use run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: '${{ env.GOVERSION }}' check-latest: true - name: Install kubeval run: go install github.com/instrumenta/kubeval@v0.16.1 - run: kubeval config/*.yaml verify-k8s-deployment: runs-on: ubuntu-latest strategy: fail-fast: false # Keep running if one leg fails. matrix: issuer: - "OIDC Issuer" - "Meta Issuer" include: - issuer: "OIDC Issuer" issuer-config: "oidc-issuers:\n https://kubernetes.default.svc:\n issuer-url: \"https://kubernetes.default.svc\"\n client-id: \"sigstore\"\n type: \"kubernetes\"" - issuer: "Meta Issuer" issuer-config: "meta-issuers:\n https://kubernetes.*.svc: \n client-id: \"sigstore\"\n type: \"kubernetes\"" env: # https://github.com/google/go-containerregistry/pull/125 allows insecure registry for # '*.local' hostnames. This works both for `ko` and our own tag-to-digest resolution logic, # thus allowing us to test without bypassing tag-to-digest resolution. REGISTRY_NAME: registry.local REGISTRY_PORT: 5000 KO_PREFIX: registry.local:5000/fulcio GIT_HASH: ${{ github.sha }} GIT_VERSION: test steps: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Extract version of Go to use run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: '${{ env.GOVERSION }}' check-latest: true - uses: ko-build/setup-ko@3aebd0597dc1e9d1a26bcfdb7cbeb19c131d3037 # v0.7 - name: Setup Cluster uses: chainguard-dev/actions/setup-kind@29fb6e979a0b3efc79748a17e8cec08d0594cbfd # main with: k8s-version: 1.26.x registry-authority: ${{ env.REGISTRY_NAME }}:${{ env.REGISTRY_PORT }} - name: Generate temporary CA files run: | openssl req -x509 \ -newkey ed25519 \ -sha256 \ -keyout "${{ github.run_id }}-key.pem" \ -out "${{ github.run_id }}-cert.pem" \ -subj "/CN=ed25519" \ -days 36500 \ -passout pass:"${{ github.run_id }}" - name: Deploy fulcio-system run: | # Reduce the resource requests of Fulcio sed -i -e 's,memory: "1G",memory: "100Mi",g' ${{ github.workspace }}/config/deployment.yaml sed -i -e 's,cpu: ".5",cpu: "50m",g' ${{ github.workspace }}/config/deployment.yaml # Switch to one replica to make it easier to test the scraping of # metrics since we know all the requests then go to the same server. sed -i -E 's,replicas: 3,replicas: 1,g' ${{ github.workspace }}/config/deployment.yaml # Expose the prometheus port as a service so tests can grab it # without hitting the k8s API cat <> ${{ github.workspace }}/config/deployment.yaml - name: prometheus protocol: TCP port: 2112 targetPort: 2112 EOF # Overwrite the configuration to be what we need for KinD. cat < config/fulcio-config.yaml apiVersion: v1 kind: ConfigMap metadata: name: fulcio-config namespace: fulcio-system data: config.yaml: |- ${{ matrix.issuer-config }} server.yaml: |- host: 0.0.0.0 port: 5555 grpc-port: 5554 ca: fileca fileca-cert: /etc/fulcio-secret/cert.pem fileca-key: /etc/fulcio-secret/key.pem fileca-key-passwd: "${{ github.run_id }}" ct-log-url: "" log_type: prod EOF # Create secret needed to use fileca cat < config/fulcio-secret.yaml apiVersion: v1 kind: Secret metadata: name: fulcio-secret namespace: fulcio-system data: cert.pem: $(cat ${{ github.run_id }}-cert.pem | base64 -w 0) key.pem: $(cat ${{ github.run_id }}-key.pem | base64 -w 0) EOF make ko-apply-ci kubectl wait --for=condition=Available --timeout=5m -n fulcio-system deployment/fulcio-server kubectl get po -n fulcio-system - name: Run signing job run: | DIGEST=$(make ko-publish | sed '1d') cat <> $GITHUB_ENV - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: '${{ env.GOVERSION }}' check-latest: true - name: Install addlicense run: go install github.com/google/addlicense@v1.0.0 - name: Check license headers run: | set -e addlicense -l apache -c 'The Sigstore Authors' -v * git diff --exit-code golangci: name: golangci-lint runs-on: ubuntu-latest steps: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: deps run: sudo apt-get update && sudo apt-get install -yq libpcsclite-dev - name: Extract version of Go to use run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: '${{ env.GOVERSION }}' check-latest: true - name: golangci-lint uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1 with: version: v1.61 oidc-config: name: oidc-config runs-on: ubuntu-latest steps: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Extract version of Go to use run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: '${{ env.GOVERSION }}' check-latest: true - name: check-config run: | set -e go test -timeout 30s -run ^TestLoadFulcioConfig$ github.com/sigstore/fulcio/pkg/config fulcio-1.6.5/.gitignore000066400000000000000000000010301470150653400147730ustar00rootroot00000000000000# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ dist/* hack/tools/bin # IDE Specifics # intellij .idea/* # vscode .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json *.code-workspace .history/ #output binaries /client /server /fulcio # Vim *.swp # vscode .vscode/ fulcio-1.6.5/.golangci.yml000066400000000000000000000024651470150653400154040ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. linters: enable: - unused - errcheck - gofmt - goimports - gosec - gocritic - misspell - revive linters-settings: gosec: excludes: - G115 # integer overflow conversion int -> uint32 - G602 # slice index out of range output: uniq-by-line: false issues: exclude-rules: - path: _test\.go linters: - errcheck - gosec # the following section is due to the legacy API being deprecated - path: pkg/server/legacy_server.go linters: - staticcheck text: SA1019 - path: pkg/ca/tinkca/signer.go linters: - staticcheck text: SA1019 max-issues-per-linter: 0 max-same-issues: 0 run: issues-exit-code: 1 timeout: 10m fulcio-1.6.5/.goreleaser.yml000066400000000000000000000071341470150653400157470ustar00rootroot00000000000000project_name: fulcio version: 2 env: - GO111MODULE=on - DOCKER_CLI_EXPERIMENTAL=enabled - COSIGN_YES=true # If you need support for the the "createca" command, you must enable CGO - CGO_ENABLED=0 # Prevents parallel builds from stepping on eachothers toes downloading modules before: hooks: - go mod tidy - /bin/bash -c 'if [ -n "$(git --no-pager diff --exit-code go.mod go.sum)" ]; then exit 1; fi' # if running a release we will generate the images in this step # if running in the CI the CI env va is set by github action runner and we dont run the ko steps # this is needed because we are generating files that goreleaser was not aware to push to GH project release - /bin/bash -c 'if [ -z "$CI" ]; then make sign-container-release && make sign-keyless-release; fi' gomod: proxy: true sboms: - artifacts: binary builds: - id: fulcio-linux-amd64 binary: fulcio-linux-amd64 no_unique_dist_dir: true main: . goos: - linux goarch: - amd64 flags: - -trimpath mod_timestamp: '{{ .CommitTimestamp }}' ldflags: - "{{ .Env.LDFLAGS }}" env: - PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig/" - id: fulcio-linux-arm64 binary: fulcio-linux-arm64 no_unique_dist_dir: true main: . goos: - linux goarch: - arm64 flags: - -trimpath mod_timestamp: '{{ .CommitTimestamp }}' ldflags: - "{{ .Env.LDFLAGS }}" env: - CC=aarch64-linux-gnu-gcc - id: fulcio-linux-arm binary: fulcio-linux-arm no_unique_dist_dir: true main: . goos: - linux goarch: - arm goarm: - 7 flags: - -trimpath mod_timestamp: '{{ .CommitTimestamp }}' ldflags: - "{{ .Env.LDFLAGS }}" env: - CC=arm-linux-gnueabihf-gcc - id: fulcio-linux-s390x binary: fulcio-linux-s390x no_unique_dist_dir: true main: . goos: - linux goarch: - s390x flags: - -trimpath mod_timestamp: '{{ .CommitTimestamp }}' ldflags: - "{{ .Env.LDFLAGS }}" env: - CC=s390x-linux-gnu-gcc - id: fulcio-linux-ppc64le binary: fulcio-linux-ppc64le no_unique_dist_dir: true main: . goos: - linux goarch: - ppc64le flags: - -trimpath mod_timestamp: '{{ .CommitTimestamp }}' ldflags: - "{{ .Env.LDFLAGS }}" env: - CC=powerpc64le-linux-gnu-gcc signs: - id: fulcio signature: "${artifact}.sig" cmd: cosign args: ["sign-blob", "--output-signature", "${artifact}.sig", "--key", "gcpkms://projects/{{ .Env.PROJECT_ID }}/locations/{{ .Env.KEY_LOCATION }}/keyRings/{{ .Env.KEY_RING }}/cryptoKeys/{{ .Env.KEY_NAME }}/versions/{{ .Env.KEY_VERSION }}", "${artifact}"] artifacts: binary # Keyless - id: fulcio-keyless signature: "${artifact}-keyless.sig" certificate: "${artifact}-keyless.pem" cmd: cosign args: ["sign-blob", "--output-signature", "${artifact}-keyless.sig", "--output-certificate", "${artifact}-keyless.pem", "${artifact}"] artifacts: binary - id: checksum-keyless signature: "${artifact}-keyless.sig" certificate: "${artifact}-keyless.pem" cmd: cosign args: ["sign-blob", "--output-signature", "${artifact}-keyless.sig", "--output-certificate", "${artifact}-keyless.pem", "${artifact}"] artifacts: checksum archives: - format: binary name_template: "{{ .Binary }}" allow_different_binary_count: true checksum: name_template: "{{ .ProjectName }}_checksums.txt" snapshot: name_template: SNAPSHOT-{{ .ShortCommit }} release: prerelease: allow # remove this when we start publishing non-prerelease or set to auto draft: true # allow for manual edits github: owner: sigstore name: fulcio footer: | ### Thanks for all contributors! extra_files: - glob: "./fulcio*.yaml" fulcio-1.6.5/.ko.yaml000066400000000000000000000006371470150653400143720ustar00rootroot00000000000000defaultBaseImage: gcr.io/distroless/static-debian12:nonroot builds: - main: . env: - CGO_ENABLED=0 # If you need support for the the "createca" command, you must enable # CGO and use a base image with gblic (base instead of static) # - CGO_ENABLED=1 flags: - -trimpath - -tags - "{{ .Env.GIT_HASH }}" - -tags - "{{ .Env.GIT_VERSION }}" ldflags: - -extldflags "-static" - "{{ .Env.LDFLAGS }}" fulcio-1.6.5/CHANGELOG.md000066400000000000000000001470501470150653400146310ustar00rootroot00000000000000# v1.6.5 ## Features * use go1.23.2 (#1834) * fallback to json default cfg path if yaml does not exist (#1810) * Include IDP type and subject domain in configuration API response (#1824) ## Documentation * Update OIDC claim mapping table to reflect the current state (#1801) ## Contributors * Aditya Sirish * Bob Callaway * Carlos Tadeu Panato Junior * Hayden B * Nina * Richard Fan # v1.6.4 ## Features * use go1.22.6 to build fulcio (#1793) ## Bugs * Revert "If custom server url exists, use that instead of the default one." (#1791) ## Contributors * Carlos Tadeu Panato Junior * Fredrik Skogman # v1.6.3 ## Features * If custom server url exists, use that instead of the default one. (#1776) ## Contributors * Fredrik Skogman * Javan Lacerda # v1.6.2 ## Bug Fixes * fix: adding ci provider for meta-issuers (#1767) ## Contributors * Javan Lacerda # v1.6.1 ## Bug Fixes * fix: removing surplus slash, making logs richer (#1762) ## Contributors * Javan Lacerda # v1.6.0 v1.6.0 adds support for onboarding CI identity providers via configuration rather than code changes, which should greatly simplify the onboarding process. ## Features * CiProvider as a new OIDCIssuer type (#1729) * Add TLS support for CTLog (#1718) * Added support for email\_verified being a string or bool (#1744) ## Documentation * Update IDP requirements (#1742) ## Public Good Instance Configuration * Move codefresh and buildkite to ci-provider identity (#1743) * Move gitlab to ci-provider (#1740) * Migrate github to ci provider flow (#1738) * add Hellō provider (#1739) * Move configuration to yaml format (#1720) * Removes identity providers federation (#1736) ## Contributors * Andrew Block * cpanato * Dick Hardt * Firas Ghanmi * Hayden B * Javan Lacerda * Matt Moore # v1.5.1 ## Bug Fixes * Surface the right `Name()` from our principal. (#1726) ## Contributors * Matt Moore # v1.5.0 ## Features * Add Chainguard OIDC provider. (#1703) * Adding support for configuration from yaml file (#1687) * Upgrade go to 1.22 (#1625) ## Documentation * oid-info: fix table render (#1662) * docs: Fix extensions for digest values requiring a type prefix (#1661) ## Contributors * Bob Callaway * Carlos Tadeu Panato Junior * Facundo Tuesca * Javan Lacerda * Matt Moore * Tomas Turek * William Woodruff # v1.4.5 ## Features * Add Codefresh OIDC provider (#1593) ## Contributors * ilia-medvedev-codefresh # v1.4.4 ## Features * Add production OIDC provider for Eclipse (#1472) * Change parseExtension function to be public (#1584) * Allow exposed metrics port to be overridden (#1518) * add configurable idle timeout ## Bug Fixes * Fix docker-compose service order (#1537) * Fix debug docker-compose setup (#1529) * Fix docker-compose file (#1560) ## Documentation * Create new-idp-requirements.md (#1447) * docs: Add back descriptive content on cert issuing (#1494) * Added GitLab OIDC documentation to the /docs/oidc.md file that was missing. (#1574) ## Misc * update builder to use go1.21.6 * Move kubernetes CA processing in config.prepare (#1454) * Lots of dependabot updates ## Contributors * Bob Callaway * Carlos Tadeu Panato Junior * Colleen Murphy * Cyril Cordoui * Hayden B * John Kjell * Paul Welch * Tanner Jones # v1.4.3 ## Bug Fixes * Bump golang.org/x/net from 0.15.0 to 0.17.0 in /hack/tools (#1409) * Bump golang.org/x/net from 0.15.0 to 0.17.0 (#1410) ## Contributors * dependabot # v1.4.2 * move to go 1.21.3 to pick up fixes for CVE-2023-39325 ## Bug Fixes * update builder image to use go1.21.3 (#1407) * Bump github.com/google/go-cmp from 0.5.9 to 0.6.0 (#1405) * Bump google.golang.org/grpc from 1.58.2 to 1.58.3 (#1404) * Bump golang from 1.21.2 to 1.21.3 (#1406) * Bump go.step.sm/crypto from 0.35.1 to 0.36.0 (#1403) * Bump google.golang.org/api from 0.145.0 to 0.146.0 (#1402) * Bump sigs.k8s.io/release-utils from 0.7.4 to 0.7.5 (#1401) ## Contributors * Carlos Tadeu Panato Junior # v1.4.1 v1.4.1 disables CGO for released binaries and containers. If you need support for an HSM-backed CA, compile Fulcio with CGO\_ENABLED=1. The Distroless base image of the released containers has been updated to Debian 12, `gcr.io/distroless/static-debian12:nonroot`. ## Features * Do not block startup if OIDC provider cannot be created (#1389) * Gracefully shutdown HTTP, gRPC, and Prom servers (#1342) * Create interface for GRPC server which encompasses the GRPC HealthServer (#1334) ## Release * update builder image to use go1.21.2 (#1397) * Disable CGO on release builds (#1368) ## Contributors * Appu * Hayden B * Jon Johnson * Jussi Kukkonen * Priya Wadhwa * William Woodruff # v1.4.0 ## Features * Add "Source Repository Visibility At Signing" ext (#1279) * Expose SkipExpiryCheck OIDC Config Option in Verifier (#1271) ## Documentation * Update loadtest instructions (#1284) ## Contributors * Hayden B * Philip Harrison * Priya Wadhwa # v1.3.4 ## Features * Update GitLab claim mappings for build configs (#1206) * add container builds for each push to main (#1269) ## Bug fixes * always use non-TLS credentials to connect over unix domain socket (#1268) ## Contributors * Marshall Cottrell * Bob Callaway # v1.3.3 ## Features * add HTTP and GRPC health check endpoints (#1258) * add fsnotify-backed cache for reading TLS PKI material (#1256) ## Contributors * Bob Callaway * Hayden B # v1.3.2 ## Features * configure server-side TLS on grpc listener (#1252) ## Bug fixes * gitlab: remove build config URI. (#1183) ## Documentation * Update OID info (#1188) * Fix spellings, update protoc (#1184) * docs/oid-info: clarify source of issuer extensions (#1158) ## Contributors * Billy Lynch * Bob Callaway * Carlos Tadeu Panato Junior * Hayden B * Kristian Klausen * William Woodruff # v1.3.1 ## Bug Fixes * fix cert.URIs for GitLab CI (#1144) ## Contributors * Carlos Tadeu Panato Junior # v1.3.0 Fulcio 1.3.0 adds support for GitLab CI. ## Enhancements * Add GitLab.com OIDC to Fulcio (#983) * Change ParseDerString to Public Function (#1119) * Support enterprise-unique GitHub Actions OIDC issuer URLs (#1088) ## Documentation * Map GitLab OIDC token claims to Fulcio OIDs (#1097) * Mark GitLab JWT claim fields that are still WIP. (#1139) * oidc.md: Add section for how to select SANs. (#1127) * oid-info: Drop Build Signer Digest requirement from MUST -> SHOULD (#1126) * update docs to use CDN-backed TUF endpoint (#1108) ## Contributors * Alishan Ladhani * Billy Lynch * Bob Callaway * Carlos Tadeu Panato Junior * Hayden B * James Ma * Paul Welch * Reed Loden * Sandipan Panda # v1.2.0 Fulcio 1.2.0 adds support for additional extensions in certificates issued for CI platforms, starting with GitHub Actions. Deprecation warning: OIDs `1.3.6.1.4.1.57264.1.1` through `1.3.6.1.4.1.57264.1.6` have been deprecated, but are still present in the issued certificates. The new extensions `1.3.6.1.4.1.57264.1.8` through `1.3.6.1.4.1.57264.1.21` are correctly formatted as DER-encoded strings. ## Enhancements * Implement standardized CI extensions for GitHub (https://github.com/sigstore/fulcio/pull/1073) * Allow specifying ChallengeClaim for an Issuer in the Fulcio config (https://github.com/sigstore/fulcio/pull/1007) * Support custom OIDC issuers * Begin implementing Issuer interface for email and github identities (https://github.com/sigstore/fulcio/pull/1005) * Implement Issuer interface for spiffe and kubernetes types (https://github.com/sigstore/fulcio/pull/1033) * Implement Issuer interface for username and uri Issuer types (https://github.com/sigstore/fulcio/pull/1035) * implement Issuer interface for buildkite (https://github.com/sigstore/fulcio/pull/1037) * Create BaseIssuer type to implement Match for all Issuers (https://github.com/sigstore/fulcio/pull/1039) * Use Issuer interface to allow for custom issuers (https://github.com/sigstore/fulcio/pull/1008) ## Bug Fixes * Don't add nil issuers to issuer pool (https://github.com/sigstore/fulcio/pull/1053) ## Documentation * Standardizing Fulcio Certificate Extensions (https://github.com/sigstore/fulcio/pull/945) * Add documentation for adding a new OIDC issuer (https://github.com/sigstore/fulcio/pull/1042) * Update TUF instructions in README (https://github.com/sigstore/fulcio/pull/1079) ## Contributors * Carlos Tadeu Panato Junior * Hayden B * Philip Harrison * priyawadhwa # v1.1.0 Fulcio 1.1.0 adds support for Buildkite, supports running the HTTP and gRPC servers on the same port, and fixes a few bugs in the GCP CA Service integration. Fulcio 1.1.0 updates Go to 1.20. ## Enhancements * Add Buildkite OIDC to Fulcio (https://github.com/sigstore/fulcio/pull/890) * Update Fulcio to 1.20 (https://github.com/sigstore/fulcio/pull/989) * Add in --duplex flag to run HTTP and GRPC servers on the same port (https://github.com/sigstore/fulcio/pull/931) * Expose client options for google ca (https://github.com/sigstore/fulcio/pull/892) ## Bug Fixes * googleca: close certificate authority client when done (https://github.com/sigstore/fulcio/pull/930) * Fix bugs in googleca and update flag description (https://github.com/sigstore/fulcio/pull/897) * Fix pkcs11ca with no cgo compilation bug (https://github.com/sigstore/fulcio/pull/898) ## Miscellaneous * Add custom error logs when communicating with the CA backend (https://github.com/sigstore/fulcio/pull/966) * Add new format for AKS OIDC issuer (https://github.com/sigstore/fulcio/pull/971) * expose rpc options to add auth creds (https://github.com/sigstore/fulcio/pull/934) * Refactor kmsca constructor to accept x509.Certificates (https://github.com/sigstore/fulcio/pull/917) ## Contributors * Bob Callaway * Carlos Tadeu Panato Junior * Harry Marr * Hayden B * Hector Fernandez * Luke Hinds * priyawadhwa * Samuel Cochran * William Woodruff * Yoriyasu Yano # v1.0.0 1.0 release! No changes from the previous release v1.0.0-rc.0. # v1.0.0-rc.0 **Notice for Deprecation**: The legacy (V1) API will be deprecated by February 1, 2023, and no longer supported in the public instance. Please update clients to the V2 API, which supports for gRPC and HTTP. ## Enhancements * use same way to output version and expose build info to prometheus (#815) ## Documentation * Update swagger doc version for Fulcio 1.0 (#816) ## Contributors * Carlos Tadeu Panato Junior (@cpanato) * Hayden Blauzvern (@haydentherapper) # v0.6.0 **Note**: Changed username identity format to username!Domain, username now specified in the OtherName SAN. If you have deployed your own instance of Fulcio and are using username issuers, you must update to the latest Cosign release. ## Enhancements * Change username format, enforce identity format (https://github.com/sigstore/fulcio/pull/802) * Export Fulcio extension OIDs (https://github.com/sigstore/fulcio/pull/761) ## Documentation * Update how-certificate-issuing-works.md (https://github.com/sigstore/fulcio/pull/755) ### Bug Fixes * Fix documentation link (https://github.com/sigstore/fulcio/pull/798) ## Miscellaneous * upgrade to go1.19 (https://github.com/sigstore/fulcio/pull/767) ## Contributors * Billy Lynch (@wlynch) * Carlos Tadeu Panato Junior (@cpanato) * Hayden Blauzvern (@haydentherapper) # v0.5.4 ### Bug Fixes * adding tuf root env variable (https://github.com/sigstore/fulcio/pull/751) ## Contributors * Carlos Tadeu Panato Junior (@cpanato) # v0.5.3 ## Bug Fixes * Clean up unix socket (https://github.com/sigstore/fulcio/pull/739) * address Potential Slowloris Attack because ReadHeaderTimeout is not configured in the http.Server (https://github.com/sigstore/fulcio/pull/735) * fix example to explicitly set port for gRPC call (https://github.com/sigstore/fulcio/pull/732) ## Documentation * Create certificate specification (https://github.com/sigstore/fulcio/pull/703) * Add documentation for SCT formats (https://github.com/sigstore/fulcio/pull/718) * Update certificate issuance documentation (https://github.com/sigstore/fulcio/pull/702) ## Miscellaneous * Bump actions/dependency-review-action from 2.0.4 to 2.1.0 (https://github.com/sigstore/fulcio/pull/744) * Update scorecard-action to v2:alpha (https://github.com/sigstore/fulcio/pull/746) * update builder and cosign images (https://github.com/sigstore/fulcio/pull/743) * Bump google.golang.org/api from 0.92.0 to 0.93.0 (https://github.com/sigstore/fulcio/pull/741) * Bump go.step.sm/crypto from 0.17.1 to 0.17.2 (https://github.com/sigstore/fulcio/pull/742) * update github.com/google/tink/go to 1.7.0 and fix deprecation (https://github.com/sigstore/fulcio/pull/736) * Bump go.step.sm/crypto from 0.17.0 to 0.17.1 (https://github.com/sigstore/fulcio/pull/737) * Bump google.golang.org/api from 0.91.0 to 0.92.0 (https://github.com/sigstore/fulcio/pull/733) * Bump github.com/googleapis/api-linter in /hack/tools (https://github.com/sigstore/fulcio/pull/731) * Bump github.com/googleapis/api-linter in /hack/tools (https://github.com/sigstore/fulcio/pull/722) * Bump go.uber.org/zap from 1.21.0 to 1.22.0 (https://github.com/sigstore/fulcio/pull/730) * Bump github.com/grpc-ecosystem/grpc-gateway/v2 from 2.11.0 to 2.11.2 in /hack/tools (https://github.com/sigstore/fulcio/pull/726) * install protobuff 3.20.1 (https://github.com/sigstore/fulcio/pull/728) * Bump github.com/grpc-ecosystem/grpc-gateway/v2 from 2.11.1 to 2.11.2 (https://github.com/sigstore/fulcio/pull/724) * Bump github.com/prometheus/client_golang from 1.12.2 to 1.13.0 (https://github.com/sigstore/fulcio/pull/725) * Bump github/codeql-action from 2.1.17 to 2.1.18 (https://github.com/sigstore/fulcio/pull/721) * Bump google.golang.org/api from 0.90.0 to 0.91.0 (https://github.com/sigstore/fulcio/pull/720) * Bump golang from 1.18.4 to 1.18.5 (https://github.com/sigstore/fulcio/pull/717) * Bump golang from `6e10f44` to `8a62670` (https://github.com/sigstore/fulcio/pull/713) * Bump github.com/grpc-ecosystem/grpc-gateway/v2 from 2.11.0 to 2.11.1 (https://github.com/sigstore/fulcio/pull/714) * Bump google.golang.org/protobuf from 1.28.0 to 1.28.1 (https://github.com/sigstore/fulcio/pull/710) * Bump github/codeql-action from 2.1.16 to 2.1.17 (https://github.com/sigstore/fulcio/pull/709) * Bump google.golang.org/api from 0.89.0 to 0.90.0 (https://github.com/sigstore/fulcio/pull/711) * Bump golang from `f3d3d69` to `6e10f44` (https://github.com/sigstore/fulcio/pull/708) * Bump google.golang.org/protobuf from 1.28.0 to 1.28.1 in /hack/tools (https://github.com/sigstore/fulcio/pull/712) * Enable Scorecard badge (https://github.com/sigstore/fulcio/pull/706) * Bump golang from `9349ed8` to `f3d3d69` (https://github.com/sigstore/fulcio/pull/707) * Bump imjasonh/setup-ko from 0.4 to 0.5 (https://github.com/sigstore/fulcio/pull/704) * Bump google.golang.org/api from 0.88.0 to 0.89.0 (https://github.com/sigstore/fulcio/pull/705) ## Contributors * Azeem Shaikh (@azeemshaikh38) * Bob Callaway (@bobcallaway) * Carlos Tadeu Panato Junior (@cpanato) * Hayden Blauzvern (@haydentherapper) * Paul Thomson (@pauldthomson) # v0.5.2 ## Bug Fixes * Ensure GetTrustBundle returns array of strings instead of a single string with newlines (https://github.com/sigstore/fulcio/pull/690) ## Miscellaneous * Bump github.com/grpc-ecosystem/grpc-gateway/v2 in /hack/tools (https://github.com/sigstore/fulcio/pull/696) * Bump google.golang.org/api from 0.87.0 to 0.88.0 (https://github.com/sigstore/fulcio/pull/694) * Bump github.com/grpc-ecosystem/grpc-gateway/v2 from 2.10.3 to 2.11.0 (https://github.com/sigstore/fulcio/pull/https://github.com/sigstore/fulcio/pull/695) * bump cosign to v1.9.0 (https://github.com/sigstore/fulcio/pull/692) * Bump go.step.sm/crypto from 0.16.2 to 0.17.0 (https://github.com/sigstore/fulcio/pull/688) * Bump actions/dependency-review-action from 2.0.2 to 2.0.4 (https://github.com/sigstore/fulcio/pull/686) * Bump github.com/prometheus/common from 0.36.0 to 0.37.0 (https://github.com/sigstore/fulcio/pull/687) * Bump golang from 1.18.3 to 1.18.4 (https://github.com/sigstore/fulcio/pull/683) * Bump github/codeql-action from 2.1.15 to 2.1.16 (https://github.com/sigstore/fulcio/pull/684) * Bump github.com/googleapis/api-linter in /hack/tools (https://github.com/sigstore/fulcio/pull/https://github.com/sigstore/fulcio/pull/85) * Bump google.golang.org/grpc from 1.47.0 to 1.48.0 (https://github.com/sigstore/fulcio/pull/682) * Bump google.golang.org/api from 0.86.0 to 0.87.0 (https://github.com/sigstore/fulcio/pull/680) * Bump cloud.google.com/go/security from 1.4.0 to 1.4.1 (https://github.com/sigstore/fulcio/pull/681) * Bump github.com/prometheus/common from 0.35.0 to 0.36.0 (https://github.com/sigstore/fulcio/pull/678) * Bump actions/setup-go from 3.2.0 to 3.2.1 (https://github.com/sigstore/fulcio/pull/677) ## Contributors * Bob Callaway (@bobcallaway) # v0.5.1 ## Enhancements * pipe all log messages to stdout for dev logger (https://github.com/sigstore/fulcio/pull/673) * Add CORS support to HTTP endpoint (https://github.com/sigstore/fulcio/pull/670) * generate OpenAPI documents from protobuf (https://github.com/sigstore/fulcio/pull/666) * Add Tink signing backend (https://github.com/sigstore/fulcio/pull/645) * Refactor in-memory signing CAs to use a single implementation (https://github.com/sigstore/fulcio/pull/644) * change grpc response logger to debug level instead of error (https://github.com/sigstore/fulcio/pull/648) * Add interface for certs/signer fetching to remove mutex (https://github.com/sigstore/fulcio/pull/643) ## Miscellaneous * Bump github.com/googleapis/api-linter in /hack/tools (https://github.com/sigstore/fulcio/pull/674) * Update sigstore to pull in fixes (https://github.com/sigstore/fulcio/pull/671) * Bump github.com/spiffe/go-spiffe/v2 from 2.1.0 to 2.1.1 (https://github.com/sigstore/fulcio/pull/668) * Bump github.com/googleapis/api-linter in /hack/tools (https://github.com/sigstore/fulcio/pull/669) * add dependabot hack to monitor for new protoc releases (https://github.com/sigstore/fulcio/pull/667) * Bump github/codeql-action from 2.1.14 to 2.1.15 (https://github.com/sigstore/fulcio/pull/663) * Bump google.golang.org/api from 0.85.0 to 0.86.0 (https://github.com/sigstore/fulcio/pull/664) * Bump ossf/scorecard-action from 1.1.1 to 1.1.2 (https://github.com/sigstore/fulcio/pull/662) * Bump golang from `957001e` to `a452d62` (https://github.com/sigstore/fulcio/pull/661) * Bump golang from `1c3d22f` to `957001e` (https://github.com/sigstore/fulcio/pull/660) * Bump github/codeql-action from 2.1.13 to 2.1.14 (https://github.com/sigstore/fulcio/pull/659) * Bump github/codeql-action from 2.1.12 to 2.1.13 (https://github.com/sigstore/fulcio/pull/656) * Bump google.golang.org/api from 0.84.0 to 0.85.0 (https://github.com/sigstore/fulcio/pull/657) * Bump github.com/spf13/cobra from 1.4.0 to 1.5.0 (https://github.com/sigstore/fulcio/pull/658) * Bump github.com/prometheus/common from 0.34.0 to 0.35.0 (https://github.com/sigstore/fulcio/pull/655) * Bump github.com/googleapis/api-linter in /hack/tools (https://github.com/sigstore/fulcio/pull/653) * Bump actions/dependency-review-action from 2.0.1 to 2.0.2 (https://github.com/sigstore/fulcio/pull/652) * Bump golang from `b203dc5` to `1c3d22f` (https://github.com/sigstore/fulcio/pull/649) * Bump github.com/googleapis/api-linter in /hack/tools (https://github.com/sigstore/fulcio/pull/651) * Bump actions/dependency-review-action from 1.0.2 to 2.0.1 (https://github.com/sigstore/fulcio/pull/650) * Bump google.golang.org/api from 0.83.0 to 0.84.0 (https://github.com/sigstore/fulcio/pull/647) * Bump google.golang.org/api from 0.82.0 to 0.83.0 (https://github.com/sigstore/fulcio/pull/642) ## Contributors * Bob Callaway (@bobcallaway) * Hayden Blauzvern (@haydentherapper) # v0.5.0 ## Enhancements * code refactor (https://github.com/sigstore/fulcio/pull/626 / https://github.com/sigstore/fulcio/pull/620 / https://github.com/sigstore/fulcio/pull/625 / https://github.com/sigstore/fulcio/pull/619 / https://github.com/sigstore/fulcio/pull/604 / https://github.com/sigstore/fulcio/pull/599 / https://github.com/sigstore/fulcio/pull/590 / https://github.com/sigstore/fulcio/pull/580 / https://github.com/sigstore/fulcio/pull/561 / https://github.com/sigstore/fulcio/pull/558) * Add API for fetching Fulcio configuration (https://github.com/sigstore/fulcio/pull/608) * Split pkg/server from pkg/api (https://github.com/sigstore/fulcio/pull/616) * Restict issuer claim mapping to email issuers (https://github.com/sigstore/fulcio/pull/606) * Validate SPIFFE IDs and trust domains via library (https://github.com/sigstore/fulcio/pull/592) * Use principal in CA abstraction (https://github.com/sigstore/fulcio/pull/570) * googleca: Don't log all identities (https://github.com/sigstore/fulcio/pull/577) * Small `ca` refactor (https://github.com/sigstore/fulcio/pull/569) * Remove unused Subject field from code signing certificate (https://github.com/sigstore/fulcio/pull/568) * Add client options testing (https://github.com/sigstore/fulcio/pull/562) * Add timeout to OIDC discovery (https://github.com/sigstore/fulcio/pull/560) ## Bug Fixes * spiffe: correct trust domain checking (https://github.com/sigstore/fulcio/pull/588) * fix the digest image (https://github.com/sigstore/fulcio/pull/555) ## Documentation * identity: improve the documentation for Principal.Name() (https://github.com/sigstore/fulcio/pull/579) ## Miscellaneous * Use GenerateSerialNumber from cryptoutils (https://github.com/sigstore/fulcio/pull/571) * challenges: remove ParseCSR (https://github.com/sigstore/fulcio/pull/578) * Bump github/codeql-action from 2.1.11 to 2.1.12 (https://github.com/sigstore/fulcio/pull/629) * Bump ossf/scorecard-action from 1.1.0 to 1.1.1 (https://github.com/sigstore/fulcio/pull/630) * update cross-builder image to use go1.18.3 (https://github.com/sigstore/fulcio/pull/635) * typo: Github -> GitHub (https://github.com/sigstore/fulcio/pull/636) * Bump google.golang.org/api from 0.81.0 to 0.82.0 (https://github.com/sigstore/fulcio/pull/631) * Bump github.com/grpc-ecosystem/grpc-gateway/v2 from 2.10.2 to 2.10.3 (https://github.com/sigstore/fulcio/pull/632) * Bump golang from 1.18.2 to 1.18.3 (https://github.com/sigstore/fulcio/pull/628) * Bump github.com/grpc-ecosystem/grpc-gateway/v2 in /hack/tools (https://github.com/sigstore/fulcio/pull/633) * Bump google.golang.org/grpc from 1.46.2 to 1.47.0 (https://github.com/sigstore/fulcio/pull/627) * Bump gopkg.in/yaml.v3 from 3.0.0 to 3.0.1 (https://github.com/sigstore/fulcio/pull/623) * Bump actions/setup-go from 3.1.0 to 3.2.0 (https://github.com/sigstore/fulcio/pull/621) * Bump github.com/spf13/viper from 1.11.0 to 1.12.0 (https://github.com/sigstore/fulcio/pull/622) * Update sigstore to pull in go-tuf security fixes (https://github.com/sigstore/fulcio/pull/617) * Bump ossf/scorecard-action from 1.0.4 to 1.1.0 (https://github.com/sigstore/fulcio/pull/618) * Bump cloud.google.com/go/security from 1.3.0 to 1.4.0 (https://github.com/sigstore/fulcio/pull/613) * Bump google.golang.org/api from 0.80.0 to 0.81.0 (https://github.com/sigstore/fulcio/pull/614) * Bump actions/dependency-review-action from 1.0.1 to 1.0.2 (https://github.com/sigstore/fulcio/pull/609) * Bump github.com/grpc-ecosystem/grpc-gateway/v2 from 2.10.1 to 2.10.2 (https://github.com/sigstore/fulcio/pull/610) * Bump github.com/grpc-ecosystem/grpc-gateway/v2 in /hack/tools (https://github.com/sigstore/fulcio/pull/611) * Add e2e test that tests IssuerClaim (https://github.com/sigstore/fulcio/pull/605) * Bump actions/upload-artifact from 3.0.0 to 3.1.0 (https://github.com/sigstore/fulcio/pull/603) * Added additional tests for CA implementations and OIDC (https://github.com/sigstore/fulcio/pull/602) * Bump github.com/grpc-ecosystem/grpc-gateway/v2 in /hack/tools (https://github.com/sigstore/fulcio/pull/601) * Bump github.com/grpc-ecosystem/grpc-gateway/v2 from 2.10.0 to 2.10.1 (https://github.com/sigstore/fulcio/pull/600) * cmd/app: remove dependency on deprecated github.com/pkg/errors (https://github.com/sigstore/fulcio/pull/598) * Bump github.com/googleapis/api-linter in /hack/tools (https://github.com/sigstore/fulcio/pull/597) * Bump github/codeql-action from 2.1.10 to 2.1.11 (https://github.com/sigstore/fulcio/pull/593) * Bump go.step.sm/crypto from 0.16.1 to 0.16.2 (https://github.com/sigstore/fulcio/pull/594) * Bump google.golang.org/api from 0.79.0 to 0.80.0 (https://github.com/sigstore/fulcio/pull/595) * Skip tests that require network access with HERMETIC=true (https://github.com/sigstore/fulcio/pull/587) * Bump github.com/google/certificate-transparency-go from 1.1.2 to 1.1.3 (https://github.com/sigstore/fulcio/pull/586) * Bump google.golang.org/grpc from 1.46.0 to 1.46.2 (https://github.com/sigstore/fulcio/pull/585) * Bump github.com/prometheus/client_golang from 1.12.1 to 1.12.2 (https://github.com/sigstore/fulcio/pull/584) * Bump actions/setup-go from 3.0.0 to 3.1.0 (https://github.com/sigstore/fulcio/pull/582) * Add some tests for challenges (https://github.com/sigstore/fulcio/pull/583) * Bump actions/dependency-review-action (https://github.com/sigstore/fulcio/pull/581) * Bump github/codeql-action (https://github.com/sigstore/fulcio/pull/572) * Bump golangci/golangci-lint-action from 3.1.0 to 3.2.0 (https://github.com/sigstore/fulcio/pull/573) * Update to use go1.18 (https://github.com/sigstore/fulcio/pull/576) * Bump github.com/coreos/go-oidc/v3 from 3.1.0 to 3.2.0 (https://github.com/sigstore/fulcio/pull/574) * Bump github.com/googleapis/api-linter in /hack/tools (https://github.com/sigstore/fulcio/pull/575) * update go to 1.17.10 (https://github.com/sigstore/fulcio/pull/567) * Bump github/codeql-action from 2.1.9 to 2.1.10 (https://github.com/sigstore/fulcio/pull/565) * Bump google.golang.org/api from 0.78.0 to 0.79.0 (https://github.com/sigstore/fulcio/pull/566) * Bump github.com/googleapis/api-linter in /hack/tools (https://github.com/sigstore/fulcio/pull/557) * Bump google.golang.org/api from 0.77.0 to 0.78.0 (https://github.com/sigstore/fulcio/pull/556) * update go builder image and cosign image (https://github.com/sigstore/fulcio/pull/554) * add changelog for 0.4.1 release (https://github.com/sigstore/fulcio/pull/553) ## Contributors * Carlos Tadeu Panato Junior (@cpanato) * Hayden Blauzvern (@haydentherapper) * Jason Hall (@imjasonh) * Koichi Shiraishi (@zchee) * Miloslav Trmač (@mtrmac) * Nathan Smith (@nsmith5) # v0.4.1 ## Bug Fixes * Fix key usage for issued certificates (https://github.com/sigstore/fulcio/pull/549) ## Documentation * Add note about the status of the legacy HTTP API. (https://github.com/sigstore/fulcio/pull/531) ## Others * Bump google.golang.org/api from 0.76.0 to 0.77.0 (https://github.com/sigstore/fulcio/pull/552) * chore(deps): Included dependency review (https://github.com/sigstore/fulcio/pull/540) * Add @haydentherapper to CODEOWNERS (https://github.com/sigstore/fulcio/pull/548) * Bump github.com/google/go-cmp from 0.5.7 to 0.5.8 (https://github.com/sigstore/fulcio/pull/544) * Bump github.com/fsnotify/fsnotify from 1.5.3 to 1.5.4 (https://github.com/sigstore/fulcio/pull/543) * Bump google.golang.org/api from 0.75.0 to 0.76.0 (https://github.com/sigstore/fulcio/pull/542) * Bump github/codeql-action from 2.1.8 to 2.1.9 (https://github.com/sigstore/fulcio/pull/545) * Bump github.com/googleapis/api-linter in /hack/tools (https://github.com/sigstore/fulcio/pull/546) * Bump google.golang.org/grpc from 1.45.0 to 1.46.0 (https://github.com/sigstore/fulcio/pull/541) ## Contributors * Bob Callaway (@bobcallaway) * Hayden Blauzvern (@haydentherapper) * Naveen (@naveensrinivasan) * Zack Newman (@znewman01) # v0.4.0 ## Enhancements * Add CSR support for key delivery and proof of possession (https://github.com/sigstore/fulcio/pull/527) * Remove checked in binary (https://github.com/sigstore/fulcio/pull/524) * add GRPC interface (https://github.com/sigstore/fulcio/pull/472) * Embed SCTs in issued certificates (https://github.com/sigstore/fulcio/pull/507) * Add intermediate CA implementation with KMS-backed signer (https://github.com/sigstore/fulcio/pull/496) ## Bug Fixes * Fix null pointer crash and incorrect error statuses (https://github.com/sigstore/fulcio/pull/526) ## Documentation * Add documentation for setting up Fulcio instance (https://github.com/sigstore/fulcio/pull/521) * Add documentation for CT log (https://github.com/sigstore/fulcio/pull/514) * examples: This adds example code on how to fetch a fulcio certificate (https://github.com/sigstore/fulcio/pull/324) ## Others * Bump github.com/grpc-ecosystem/grpc-gateway/v2 from 2.8.0 to 2.10.0 (https://github.com/sigstore/fulcio/pull/523) * Bump actions/checkout from 3.0.0 to 3.0.1 (https://github.com/sigstore/fulcio/pull/522) * Bump google.golang.org/protobuf from 1.27.1 to 1.28.0 in /hack/tools (https://github.com/sigstore/fulcio/pull/520) * Update release images (https://github.com/sigstore/fulcio/pull/517) * Bump github.com/spf13/viper from 1.10.1 to 1.11.0 (https://github.com/sigstore/fulcio/pull/516) * Bump github/codeql-action from 2.1.7 to 2.1.8 (https://github.com/sigstore/fulcio/pull/513) * add changelog for v0.3.0 release (https://github.com/sigstore/fulcio/pull/508) ## Contributors * Bob Callaway (@bobcallaway) * Carlos Tadeu Panato Junior (@cpanato) * Hayden Blauzvern (@haydentherapper) * Morten Linderud (@Foxboron) # v0.3.0 ## Enhancements * Generate larger, compliant serial numbers (https://github.com/sigstore/fulcio/pull/500) * Use provided HTTP client instead when fetching root cert (https://github.com/sigstore/fulcio/pull/502) * Add missing reader lock to File CA when reading certificate chain (https://github.com/sigstore/fulcio/pull/493) * Add validation of public keys to prevent certifying weak keys (https://github.com/sigstore/fulcio/pull/490) * Refactor API tests (https://github.com/sigstore/fulcio/pull/483) * Update Username OIDC flow based on comments (https://github.com/sigstore/fulcio/pull/463) ## Bug Fixes * fix_certificate_readme_typos (https://github.com/sigstore/fulcio/pull/487) * Fix minor typs in security model README (https://github.com/sigstore/fulcio/pull/488) * Fix minor typos in README (https://github.com/sigstore/fulcio/pull/486) * fix build date format for version command (https://github.com/sigstore/fulcio/pull/484) ## Others * update cosign and golang-cross images (https://github.com/sigstore/fulcio/pull/506) * Bump codecov/codecov-action from 2.1.0 to 3 (https://github.com/sigstore/fulcio/pull/505) * Bump github/codeql-action from 2.1.6 to 2.1.7 (https://github.com/sigstore/fulcio/pull/504) * Bump go.step.sm/crypto from 0.16.0 to 0.16.1 (https://github.com/sigstore/fulcio/pull/498) * Bump github/codeql-action from 1.1.5 to 2.1.6 (https://github.com/sigstore/fulcio/pull/497) * Bump google.golang.org/api from 0.73.0 to 0.74.0 (https://github.com/sigstore/fulcio/pull/499) * Bump github.com/prometheus/common from 0.32.1 to 0.33.0 (https://github.com/sigstore/fulcio/pull/491) * Bump google.golang.org/protobuf from 1.27.1 to 1.28.0 (https://github.com/sigstore/fulcio/pull/485) * Fix concurrency properly in File CA implementation (https://github.com/sigstore/fulcio/pull/495) * Bump go.step.sm/crypto from 0.15.3 to 0.16.0 (https://github.com/sigstore/fulcio/pull/482) * Bump google.golang.org/api from 0.72.0 to 0.73.0 (https://github.com/sigstore/fulcio/pull/479) * Bump github.com/stretchr/testify from 1.7.0 to 1.7.1 (https://github.com/sigstore/fulcio/pull/478) * Bump github/codeql-action from 1.1.4 to 1.1.5 (https://github.com/sigstore/fulcio/pull/477) * Bump google.golang.org/api from 0.71.0 to 0.72.0 (https://github.com/sigstore/fulcio/pull/476) * Bump go.step.sm/crypto from 0.15.2 to 0.15.3 (https://github.com/sigstore/fulcio/pull/473) ## Contributors * Carlos Tadeu Panato Junior (@cpanato) * Hayden Blauzvern (@haydentherapper) * Jason Hall (@imjasonh) * John Speed Meyers (@jspeed-meyers) # v0.2.0 ## Enhancements * Use fulcio-system ns and drop -dev suffix for sa (https://github.com/sigstore/fulcio/pull/418) * Return an error if we fail get get the Root cert. (https://github.com/sigstore/fulcio/pull/416) * Add unit tests for oidc-EmailFromIDToken method (https://github.com/sigstore/fulcio/pull/413) * extract CA/KMS support info to separate file (https://github.com/sigstore/fulcio/pull/409) * add securityContext to deployment (https://github.com/sigstore/fulcio/pull/420) * Count HTTP request error codes with prometheus (https://github.com/sigstore/fulcio/pull/396) * Remove organization from subject for GCP CAS issuer (https://github.com/sigstore/fulcio/pull/391) * Update warning text. (https://github.com/sigstore/fulcio/pull/389) * Improve error messages returned by SigningCert (https://github.com/sigstore/fulcio/pull/388) * Allow parameterized application/json content types (https://github.com/sigstore/fulcio/pull/386) * Add AKS MetaIssuer (https://github.com/sigstore/fulcio/pull/384) * Move CTL logging logic over to CTL package (https://github.com/sigstore/fulcio/pull/353) * Move OID information to docs directory and reformat (https://github.com/sigstore/fulcio/pull/378) * Upgrade miekg/pkcs11 using 'go get github.com/miekg/pkcs11@v1.1.1' (https://github.com/sigstore/fulcio/pull/376) * Address signingCert panic with the last-byte calculation of finalChainPEM (https://github.com/sigstore/fulcio/pull/370) * Include instructions to download verify the fulcio root certificate with TUF (https://github.com/sigstore/fulcio/pull/361) * Make CA explicit dependency of API handler (https://github.com/sigstore/fulcio/pull/354) * Improve error message when an invalid OIDC issuer is provided (https://github.com/sigstore/fulcio/pull/357) * Make the the invalid CA error message actionable (https://github.com/sigstore/fulcio/pull/356) * Initialize CT log client once (https://github.com/sigstore/fulcio/pull/350) * Generate subject key ID correctly for non-GCP certs (https://github.com/sigstore/fulcio/pull/345) * Add chain in response for all CAs, fix newlines in response (https://github.com/sigstore/fulcio/pull/341) * Add some reasonable timeouts to API server (https://github.com/sigstore/fulcio/pull/337) * fileca: add support for intermediate certificates (https://github.com/sigstore/fulcio/pull/320) * Set max request size to 4MiB (https://github.com/sigstore/fulcio/pull/338) * Extract additional claims from github-workflow token (https://github.com/sigstore/fulcio/pull/306) * Enable server settings via config file and env vars (https://github.com/sigstore/fulcio/pull/315) * Add file backed certificate authority (https://github.com/sigstore/fulcio/pull/280) * Handle error when there are no roots returned by CA Service (https://github.com/sigstore/fulcio/pull/298) * Add RootCert method to client + tests (https://github.com/sigstore/fulcio/pull/290) * Add back support for building with CGO_ENABLED=0 (https://github.com/sigstore/fulcio/pull/293) * add usersnames list to the codeonwers to make it easier to check (https://github.com/sigstore/fulcio/pull/295) * Add a Root Cert method to the CA interface, and implement it. (https://github.com/sigstore/fulcio/pull/287) * Update readme for V1 CA Service (https://github.com/sigstore/fulcio/pull/286) * Fail fast if private key is not found when using PKCS11 CA (https://github.com/sigstore/fulcio/pull/285) * Do not close the PKCS11 context on startup (https://github.com/sigstore/fulcio/pull/282) * Localize flags to each subcommand (https://github.com/sigstore/fulcio/pull/274) * Make client request timeout configurable with `WithTimeout` client option (https://github.com/sigstore/fulcio/pull/272) * add the ability to set the user-agent string on requests from the `Client` (https://github.com/sigstore/fulcio/pull/264) * Consolidate the source-of-truth. (https://github.com/sigstore/fulcio/pull/263) * Move the deployment to the new v1 cert. (https://github.com/sigstore/fulcio/pull/261) * The v1 GCP CA requires this field to be set. (https://github.com/sigstore/fulcio/pull/260) * Experiment with FulcioConfig pulling from context.Context (https://github.com/sigstore/fulcio/pull/249) * Upgrade fulcios to use of the google privateca api at v1 (https://github.com/sigstore/fulcio/pull/218) * plumb through !cgo golang tags that removes pkcs11 support (https://github.com/sigstore/fulcio/pull/244) * break out CA-specific implementation from common API class (https://github.com/sigstore/fulcio/pull/220) * Add support for recoginizing allow.pub as an spiffe issuer (https://github.com/sigstore/fulcio/pull/228) * Various nits trying SoftHSM (https://github.com/sigstore/fulcio/pull/217) * Use MetaIssuers to simular EKS / GKE in e2e test. (https://github.com/sigstore/fulcio/pull/225) * Add support for "meta issuers". (https://github.com/sigstore/fulcio/pull/223) * Remove the cluster-local block by default. (https://github.com/sigstore/fulcio/pull/224) * Refactor the way we access `Config` (https://github.com/sigstore/fulcio/pull/222) * Enable Fulcio e2e testing. (https://github.com/sigstore/fulcio/pull/219) * use sigstore/sigstore instead of directly calling RSA/ECDSA verify calls (https://github.com/sigstore/fulcio/pull/221) * Refactor the kind e2e test. (https://github.com/sigstore/fulcio/pull/215) * Add issuer information to code signing certificates (https://github.com/sigstore/fulcio/pull/204) * Extract the OIDC issuer URL. (https://github.com/sigstore/fulcio/pull/211) * use request ID logger where possible (https://github.com/sigstore/fulcio/pull/209) * Rewrite "FulcioCA" to "PKCS11CA" and add AWS support (https://github.com/sigstore/fulcio/pull/187) * add pkcs11-config-path command line parameter (https://github.com/sigstore/fulcio/pull/192) * Add GitHub OIDC to Fulcio (https://github.com/sigstore/fulcio/pull/181) * Changes fulcio-server to fulcio (https://github.com/sigstore/fulcio/pull/186) * Add Github to `fulcioca` path. (https://github.com/sigstore/fulcio/pull/184) * Add support for Github OIDC (https://github.com/sigstore/fulcio/pull/180) * Generate client code with swagger in Makefile (https://github.com/sigstore/fulcio/pull/176) * Switch to the JSON logger in prod (https://github.com/sigstore/fulcio/pull/175) * add SCT as HTTP response header (https://github.com/sigstore/fulcio/pull/163) * fulcio: add version command (https://github.com/sigstore/fulcio/pull/155) * Script and process to generate OIDC config from federation directory. (https://github.com/sigstore/fulcio/pull/139) ## Bug Fixes * Fix the SCT header return value from the API to base64 encode it. (https://github.com/sigstore/fulcio/pull/288) * Fix the k8s subject parsing. (https://github.com/sigstore/fulcio/pull/254) * [Correction] Upgrade fulcios to use of the google privateca api at v1 (https://github.com/sigstore/fulcio/pull/252) * fix: go get complain missing version when dir not in module (https://github.com/sigstore/fulcio/pull/248) * Fix street-address and postal-code descriptions to be more descriptive. (https://github.com/sigstore/fulcio/pull/245) * fix cutpaste error, sets cpu correctly (https://github.com/sigstore/fulcio/pull/237) * Fix nil pointer, update dev docs (https://github.com/sigstore/fulcio/pull/236) * Fix the Github OIDC challenge endpoint (https://github.com/sigstore/fulcio/pull/206) * Fix misspellings. (https://github.com/sigstore/fulcio/pull/177) ## Documentation * extract development documentation from README (https://github.com/sigstore/fulcio/pull/410) * fixing link to external resources (https://github.com/sigstore/fulcio/pull/411) * Add feature stability and deprecation docs (https://github.com/sigstore/fulcio/pull/400) * docs: overview of certificate issuing (https://github.com/sigstore/fulcio/pull/383) * Add Logo to README (https://github.com/sigstore/fulcio/pull/381) * Move sec model out of readme (https://github.com/sigstore/fulcio/pull/382) * Update README for V1 Fulcio cert (https://github.com/sigstore/fulcio/pull/355) * fix link for SECURITY.md (https://github.com/sigstore/fulcio/pull/340) * Remove root CA whitespaces on README.md (https://github.com/sigstore/fulcio/pull/325) * Add Locust load test and README (https://github.com/sigstore/fulcio/pull/311) * add oid documentation (https://github.com/sigstore/fulcio/pull/307) * Add documentation for testing with `ephemeralca` as well as document (https://github.com/sigstore/fulcio/pull/296) ## Others * Bump actions/upload-artifact from 2.3.1 to 3 (https://github.com/sigstore/fulcio/pull/452) * Go update to 1.17.8 and cosign to 1.6.0 (https://github.com/sigstore/fulcio/pull/453) * add missing target name (https://github.com/sigstore/fulcio/pull/450) * Bump cloud.google.com/go/security from 1.2.1 to 1.3.0 (https://github.com/sigstore/fulcio/pull/448) * Bump golang from `c2ca472` to `b983574` (https://github.com/sigstore/fulcio/pull/447) * Move CI private-ca YAML to subdir (https://github.com/sigstore/fulcio/pull/446) * Add step in release to mirror signed image to ghcr (https://github.com/sigstore/fulcio/pull/441) * Bump actions/checkout from 2 to 3 (https://github.com/sigstore/fulcio/pull/443) * Bump golang from `e06c834` to `c2ca472` (https://github.com/sigstore/fulcio/pull/442) * Bump actions/setup-go from 2.2.0 to 3.0.0 (https://github.com/sigstore/fulcio/pull/440) * Bump golangci/golangci-lint-action from 3.0.0 to 3.1.0 (https://github.com/sigstore/fulcio/pull/439) * Bump golangci/golangci-lint-action from 2.5.2 to 3 (https://github.com/sigstore/fulcio/pull/438) * Bump github/codeql-action from 1.1.2 to 1.1.3 (https://github.com/sigstore/fulcio/pull/435) * Bump github.com/magiconair/properties from 1.8.5 to 1.8.6 (https://github.com/sigstore/fulcio/pull/436) * add indent to fix yaml error (https://github.com/sigstore/fulcio/pull/434) * Bump cloud.google.com/go/security from 1.2.0 to 1.2.1 (https://github.com/sigstore/fulcio/pull/431) * explicitly set permissions for github workflows (https://github.com/sigstore/fulcio/pull/433) * Bump google.golang.org/api from 0.69.0 to 0.70.0 (https://github.com/sigstore/fulcio/pull/432) * Add missing testing dependency (https://github.com/sigstore/fulcio/pull/429) * Workflow to kick off release. (https://github.com/sigstore/fulcio/pull/407) * Take advantage of Chainguard maintained versions of various actions. (https://github.com/sigstore/fulcio/pull/427) * Bump golang from `2c92978` to `e06c834` (https://github.com/sigstore/fulcio/pull/426) * create namespace as part of config yaml (https://github.com/sigstore/fulcio/pull/422) * Bump golang from `1a35cc2` to `2c92978` (https://github.com/sigstore/fulcio/pull/423) * Bump ossf/scorecard-action from 1.0.3 to 1.0.4 (https://github.com/sigstore/fulcio/pull/425) * Bump github/codeql-action from 1.1.0 to 1.1.2 (https://github.com/sigstore/fulcio/pull/424) * Bump google.golang.org/api from 0.68.0 to 0.69.0 (https://github.com/sigstore/fulcio/pull/412) * Bump cloud.google.com/go/security from 1.1.1 to 1.2.0 (https://github.com/sigstore/fulcio/pull/408) * Bump github/codeql-action from 1.0.32 to 1.1.0 (https://github.com/sigstore/fulcio/pull/406) * update cross-build to use go 1.17.7 (https://github.com/sigstore/fulcio/pull/404) * Bump golang from 1.17.6 to 1.17.7 (https://github.com/sigstore/fulcio/pull/403) * Bump golang from `301609e` to `fff998d` (https://github.com/sigstore/fulcio/pull/401) * Bump actions/setup-go from 2.1.5 to 2.2.0 (https://github.com/sigstore/fulcio/pull/402) * Bump google.golang.org/api from 0.67.0 to 0.68.0 (https://github.com/sigstore/fulcio/pull/399) * Bump go.uber.org/zap from 1.20.0 to 1.21.0 (https://github.com/sigstore/fulcio/pull/393) * Bump github/codeql-action from 1.0.31 to 1.0.32 (https://github.com/sigstore/fulcio/pull/392) * Bump google.golang.org/api from 0.66.0 to 0.67.0 (https://github.com/sigstore/fulcio/pull/385) * Bump github/codeql-action from 1.0.30 to 1.0.31 (https://github.com/sigstore/fulcio/pull/366) * Bump ossf/scorecard-action from 1.0.2 to 1.0.3 (https://github.com/sigstore/fulcio/pull/367) * Bump go.step.sm/crypto from 0.15.0 to 0.15.1 (https://github.com/sigstore/fulcio/pull/377) * Bump google.golang.org/api from 0.65.0 to 0.66.0 (https://github.com/sigstore/fulcio/pull/363) * Bump github.com/prometheus/client_golang from 1.12.0 to 1.12.1 (https://github.com/sigstore/fulcio/pull/362) * Bump golang from `d7f2f6f` to `301609e` (https://github.com/sigstore/fulcio/pull/358) * Bump go.step.sm/crypto from 0.14.0 to 0.15.0 (https://github.com/sigstore/fulcio/pull/359) * Bump golang from `0fa6504` to `d7f2f6f` (https://github.com/sigstore/fulcio/pull/352) * createca: Address panic when no private key pair matches (https://github.com/sigstore/fulcio/pull/351) * update version marker (https://github.com/sigstore/fulcio/pull/346) * Remove Google CA v1beta1 API and associated config (https://github.com/sigstore/fulcio/pull/349) * Bump ossf/scorecard-action from 1.0.1 to 1.0.2 (https://github.com/sigstore/fulcio/pull/347) * update to v1.0.29 of codeql-action (https://github.com/sigstore/fulcio/pull/344) * Bump github.com/prometheus/client_golang from 1.11.0 to 1.12.0 (https://github.com/sigstore/fulcio/pull/333) * Bump github.com/google/go-cmp from 0.5.6 to 0.5.7 (https://github.com/sigstore/fulcio/pull/334) * Update github/codeql-action requirement to 8a4b243fbf9a03a93e93a71c1ec257347041f9c4 (https://github.com/sigstore/fulcio/pull/332) * Bump ossf/scorecard-action from 0fe1afdc40f536c78e3dc69147b91b3ecec2cc8a to 1.0.1 (https://github.com/sigstore/fulcio/pull/331) * pin one additional set of actions (https://github.com/sigstore/fulcio/pull/329) * Bump google.golang.org/api from 0.64.0 to 0.65.0 (https://github.com/sigstore/fulcio/pull/321) * add OSSF scorecard action (https://github.com/sigstore/fulcio/pull/328) * Bump golang from `8c0269d` to `0fa6504` (https://github.com/sigstore/fulcio/pull/326) * pin github actions by digest instead of tag (https://github.com/sigstore/fulcio/pull/323) * release: add cloudbuild to run the release for fulcio (https://github.com/sigstore/fulcio/pull/322) * Fix docker-compose dexidp startup (https://github.com/sigstore/fulcio/pull/316) * Bump go.step.sm/crypto from 0.13.0 to 0.14.0 (https://github.com/sigstore/fulcio/pull/319) * Bump golang from 1.17.5 to 1.17.6 (https://github.com/sigstore/fulcio/pull/317) * Switch to use fileca in e2e tests (https://github.com/sigstore/fulcio/pull/309) * Bump google.golang.org/api from 0.63.0 to 0.64.0 (https://github.com/sigstore/fulcio/pull/318) * Remove hack/tools (https://github.com/sigstore/fulcio/pull/308) * Bump cloud.google.com/go/security from 1.1.0 to 1.1.1 (https://github.com/sigstore/fulcio/pull/312) * Bump go.uber.org/zap from 1.19.1 to 1.20.0 (https://github.com/sigstore/fulcio/pull/313) * Bump github.com/sigstore/sigstore from 1.0.1 to 1.1.0 (https://github.com/sigstore/fulcio/pull/299) * Change ports for docker compose to avoid conflict with Rekor (https://github.com/sigstore/fulcio/pull/297) * Bump github.com/spf13/viper from 1.10.0 to 1.10.1 (https://github.com/sigstore/fulcio/pull/283) * Bump github.com/spf13/cobra from 1.2.1 to 1.3.0 (https://github.com/sigstore/fulcio/pull/278) * Bump golang from 1.17.4 to 1.17.5 (https://github.com/sigstore/fulcio/pull/269) * Bump github.com/prometheus/common from 0.29.0 to 0.32.1 (https://github.com/sigstore/fulcio/pull/270) * Bump golang from 1.17.3 to 1.17.4 (https://github.com/sigstore/fulcio/pull/265) * Wrap the server with the Prometheus so we get metrics + add an e2e te
 (https://github.com/sigstore/fulcio/pull/267) * While working on #267 noticed this, but didn't want to bake into it. (https://github.com/sigstore/fulcio/pull/268) * Drop OpenAPI from Fulcio (https://github.com/sigstore/fulcio/pull/262) * Drop useless package. (https://github.com/sigstore/fulcio/pull/259) * Drop gratuitous `sync.Once` in google CAs. (https://github.com/sigstore/fulcio/pull/258) * Remove `viper` from `pkg/`. (https://github.com/sigstore/fulcio/pull/257) * Bump github.com/mitchellh/mapstructure from 1.4.2 to 1.4.3 (https://github.com/sigstore/fulcio/pull/256) * Consolidate `viper` usage in `pkg/ca/ca.go` (https://github.com/sigstore/fulcio/pull/255) * Bump cloud.google.com/go/security from 0.1.0 to 1.1.0 (https://github.com/sigstore/fulcio/pull/246) * Bump github.com/go-openapi/strfmt from 0.21.0 to 0.21.1 (https://github.com/sigstore/fulcio/pull/247) * Use `CGO_ENABLED=1` via `.ko.yaml`. (https://github.com/sigstore/fulcio/pull/242) * Bump github.com/sigstore/sigstore from 1.0.0 to 1.0.1 (https://github.com/sigstore/fulcio/pull/239) * Add commit sha and trigger to github workflow (https://github.com/sigstore/fulcio/pull/232) * Bump golang from 1.17.2 to 1.17.3 (https://github.com/sigstore/fulcio/pull/234) * Bump actions/checkout from 2.3.5 to 2.4.0 (https://github.com/sigstore/fulcio/pull/233) * Bump github.com/go-openapi/runtime from 0.20.0 to 0.21.0 (https://github.com/sigstore/fulcio/pull/229) * Bump github.com/go-openapi/strfmt from 0.20.3 to 0.21.0 (https://github.com/sigstore/fulcio/pull/226) * Bump github.com/hashicorp/golang-lru from 0.5.3 to 0.5.4 (https://github.com/sigstore/fulcio/pull/227) * bump go-swagger to v0.28.0 (https://github.com/sigstore/fulcio/pull/213) * Reproducible builds with trimpath (https://github.com/sigstore/fulcio/pull/210) * Bump actions/checkout from 2.3.4 to 2.3.5 (https://github.com/sigstore/fulcio/pull/207) * Bump github.com/go-openapi/runtime from 0.19.31 to 0.20.0 (https://github.com/sigstore/fulcio/pull/202) * Bump github.com/go-openapi/spec from 0.20.3 to 0.20.4 (https://github.com/sigstore/fulcio/pull/201) * Bump github.com/go-openapi/validate from 0.20.2 to 0.20.3 (https://github.com/sigstore/fulcio/pull/198) * update go.sum (https://github.com/sigstore/fulcio/pull/205) * Bump github.com/go-openapi/loads from 0.20.2 to 0.20.3 (https://github.com/sigstore/fulcio/pull/200) * Bump github.com/go-openapi/strfmt from 0.20.2 to 0.20.3 (https://github.com/sigstore/fulcio/pull/199) * Bump golang from 1.17.1 to 1.17.2 (https://github.com/sigstore/fulcio/pull/197) * Bump github.com/spf13/viper from 1.8.1 to 1.9.0 (https://github.com/sigstore/fulcio/pull/189) * Bump github.com/coreos/go-oidc/v3 from 3.0.0 to 3.1.0 (https://github.com/sigstore/fulcio/pull/188) * Bump github.com/mitchellh/mapstructure from 1.4.1 to 1.4.2 (https://github.com/sigstore/fulcio/pull/185) * Bump github.com/ThalesIgnite/crypto11 from 1.2.4 to 1.2.5 (https://github.com/sigstore/fulcio/pull/182) * Bump golang from 1.17.0 to 1.17.1 (https://github.com/sigstore/fulcio/pull/179) * Bump go.uber.org/zap from 1.19.0 to 1.19.1 (https://github.com/sigstore/fulcio/pull/178) * Bump github.com/go-openapi/runtime from 0.19.30 to 0.19.31 (https://github.com/sigstore/fulcio/pull/171) * Bump github.com/go-openapi/errors from 0.20.0 to 0.20.1 (https://github.com/sigstore/fulcio/pull/169) * Bump github.com/go-openapi/strfmt from 0.20.1 to 0.20.2 (https://github.com/sigstore/fulcio/pull/168) * Bump golang from 1.16.7 to 1.17.0 (https://github.com/sigstore/fulcio/pull/166) * Bump cloud.google.com/go from 0.91.1 to 0.92.3 (https://github.com/sigstore/fulcio/pull/167) * Bump cloud.google.com/go from 0.90.0 to 0.91.1 (https://github.com/sigstore/fulcio/pull/162) * Bump github.com/go-openapi/runtime from 0.19.29 to 0.19.30 (https://github.com/sigstore/fulcio/pull/161) * Bump go.uber.org/zap from 1.18.1 to 1.19.0 (https://github.com/sigstore/fulcio/pull/160) * Bump golang from 1.16.6 to 1.16.7 (https://github.com/sigstore/fulcio/pull/159) * Bump cloud.google.com/go from 0.89.0 to 0.90.0 (https://github.com/sigstore/fulcio/pull/158) * Bump cloud.google.com/go from 0.88.0 to 0.89.0 (https://github.com/sigstore/fulcio/pull/156) * makefile: add rule to download and set swagger and make rule to build the dist (https://github.com/sigstore/fulcio/pull/154) * Add missing code of conduct (stock sigstore one) (https://github.com/sigstore/fulcio/pull/153) ## Contributors * Appu (@loosebazooka) * Asra Ali (@asraa) * Bob Callaway (@bobcallaway) * Carlos Tadeu Panato Junior (@cpanato) * Christian Kotzbauer (@ckotzbauer) * Dan Lorenc (@dlorenc) * Elizabeth Thomas (@elizabetht) * Evan Phoenix (@evanphx) * Hayden Blauzvern (@haydentherapper) * Jake Sanders (@dekkagaijin) * Josh Dolitsky (@jdolitsky) * Jyotsna (@jyotsna-penumaka) * Kenny Leung (@k4leung4) * Luke Hinds (@lukehinds) * Mark Bestavros (@mbestavros) * Matt Moore (@mattmoor) * Matthew Suozzo (@msuozzo) * Nathan Smith (@nsmith5) * Naveen (@naveensrinivasan) * Nghia Tran (@tcnghias) * Priya Wadhwa (@priyawadhwa) * Radoslav Gerganov (@rgerganov) * Rafael Fernández López (@ereslibre) * Scott Nichols (@n3wscott) * Thomas Strömberg (@tstromberg) * Tuan Anh Tran (@tuananh) * Viacheslav Vasilyev (@avoidik) * Ville Aikas (@vaikas) * Zack Newman (@znewman01) * endorama (@endorama) fulcio-1.6.5/CODEOWNERS000066400000000000000000000003001470150653400143750ustar00rootroot00000000000000@sigstore/fulcio-codeowners # The CODEOWNERS are managed via a GitHub team, but the current list is (in alphabetical order): # bobcallaway # dlorenc # haydentherapper # lukehinds # mattmoor fulcio-1.6.5/CODE_OF_CONDUCT.md000066400000000000000000000062071470150653400156150ustar00rootroot00000000000000# Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ fulcio-1.6.5/COPYRIGHT.txt000066400000000000000000000010631470150653400151220ustar00rootroot00000000000000 Copyright 2021 The Sigstore 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. fulcio-1.6.5/DEPRECATIONS.md000066400000000000000000000013131470150653400152110ustar00rootroot00000000000000# Deprecations This doc lists deprecated features in `fulcio`. You can read more about Sigstore's deprecation policy [here](https://docs.sigstore.dev/about/api-stability/)! | **Feature Being Deprecated** | **API Stability Level** | **Earliest Date of Removal** | |------------------------------|-------------------------|------------------------------| | My feature | Experimental/Beta/GA | DD/MM/YY | |------------------------------|-------------------------|------------------------------| | Legacy (V1) API | Beta | 01/02/23 | | | | | fulcio-1.6.5/Dockerfile000066400000000000000000000030221470150653400150000ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. FROM golang:1.23.2@sha256:adee809c2d0009a4199a11a1b2618990b244c6515149fe609e2788ddf164bd10 AS builder ENV APP_ROOT=/opt/app-root ENV GOPATH=$APP_ROOT WORKDIR $APP_ROOT/src/ ADD go.mod go.sum $APP_ROOT/src/ RUN go mod download # Add source code ADD ./ $APP_ROOT/src/ RUN go build -o server main.go RUN CGO_ENABLED=1 go build -gcflags "all=-N -l" -o server_debug main.go # Multi-Stage production build FROM golang:1.23.2@sha256:adee809c2d0009a4199a11a1b2618990b244c6515149fe609e2788ddf164bd10 AS deploy # Retrieve the binary from the previous stage COPY --from=builder /opt/app-root/src/server /usr/local/bin/fulcio-server # Set the binary as the entrypoint of the container ENTRYPOINT ["/usr/local/bin/fulcio-server", "serve"] # debug compile options & debugger FROM deploy as debug RUN go install github.com/go-delve/delve/cmd/dlv@v1.22.1 # overwrite server and include debugger COPY --from=builder /opt/app-root/src/server_debug /usr/local/bin/fulcio-server fulcio-1.6.5/Dockerfile.ctfe_init000066400000000000000000000015551470150653400167540ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. FROM golang:1.23.2@sha256:adee809c2d0009a4199a11a1b2618990b244c6515149fe609e2788ddf164bd10 AS builder WORKDIR /root/ RUN go install github.com/google/trillian/cmd/createtree@v1.6.0 ADD ./config/logid.sh /root/ ADD ./config/ctfe /root/ctfe RUN chmod +x /root/logid.sh CMD /root/logid.sh fulcio-1.6.5/FEATURES.md000066400000000000000000000012211470150653400145450ustar00rootroot00000000000000# Feature Stability This doc covers feature stability in `fulcio` as described in the [API Stability Policy](https://docs.sigstore.dev/api-stability) for Sigstore. ## Experimental ## Beta * The Fulcio API, defined [here](https://github.com/sigstore/fulcio/blob/main/pkg/api/client.go) * Support for various Certificate Authorities (CAs), including Google Private CA Service, PKCS11, and File backed CA * Support for SPIFFE challenges and OIDC based email challenges * The Go client library defined in `fulcio/pkg` * Issuers defined in [fulcio-config.yaml](https://github.com/sigstore/fulcio/blob/main/config/fulcio-config.yaml) ## General Availability fulcio-1.6.5/LICENSE000066400000000000000000000261351470150653400140250ustar00rootroot00000000000000 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. fulcio-1.6.5/Makefile000066400000000000000000000137341470150653400144610ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. .PHONY: all test clean lint gosec all: fulcio # Ensure Make is run with bash shell as some syntax below is bash-specific SHELL:=/usr/bin/env bash SRCS = $(shell find cmd -iname "*.go") $(shell find pkg -iname "*.go"|grep -v pkg/generated) $(GENSRC) TOOLS_DIR := hack/tools TOOLS_BIN_DIR := $(abspath $(TOOLS_DIR)/bin) BIN_DIR := $(abspath $(ROOT_DIR)/bin) GO_MODULE=$(shell head -1 go.mod | cut -f2 -d ' ') GENSRC = pkg/generated/protobuf/%.go %.swagger.json PROTOBUF_DEPS = $(shell find . -iname "*.proto" | grep -v "third_party") # Set version variables for LDFLAGS GIT_VERSION ?= $(shell git describe --tags --always --dirty) GIT_HASH ?= $(shell git rev-parse HEAD) GIT_TAG ?= dirty-tag DATE_FMT = +%Y-%m-%dT%H:%M:%SZ SOURCE_DATE_EPOCH ?= $(shell git log -1 --pretty=%ct) FULCIO_VERSION_PKG=sigs.k8s.io/release-utils/version LDFLAGS=-X $(FULCIO_VERSION_PKG).gitVersion=$(GIT_VERSION) KO_PREFIX ?= gcr.io/projectsigstore export KO_DOCKER_REPO=$(KO_PREFIX) GHCR_PREFIX ?= ghcr.io/sigstore FULCIO_YAML ?= fulcio-$(GIT_TAG).yaml # Binaries PROTOC-GEN-GO := $(TOOLS_BIN_DIR)/protoc-gen-go PROTOC-GEN-GO-GRPC := $(TOOLS_BIN_DIR)/protoc-gen-go-grpc PROTOC-GEN-GRPC-GATEWAY := $(TOOLS_BIN_DIR)/protoc-gen-grpc-gateway PROTOC-GEN-OPENAPIV2 := $(TOOLS_BIN_DIR)/protoc-gen-openapiv2 PROTOC-API-LINTER := $(TOOLS_BIN_DIR)/api-linter $(GENSRC): $(PROTOC-GEN-GO) $(PROTOC-GEN-GO-GRPC) $(PROTOC-GEN-GRPC-GATEWAY) $(PROTOC-API-LINTER) $(PROTOC-GEN-OPENAPIV2) $(PROTOBUF_DEPS) mkdir -p pkg/generated/protobuf $(PROTOC-API-LINTER) -I third_party/googleapis/ -I . $(PROTOBUF_DEPS) #--set-exit-status # TODO: add strict checking protoc --plugin=protoc-gen-go=$(TOOLS_BIN_DIR)/protoc-gen-go \ --go_opt=module=$(GO_MODULE) --go_out=. \ --plugin=protoc-gen-go-grpc=$(TOOLS_BIN_DIR)/protoc-gen-go-grpc \ --go-grpc_opt=module=$(GO_MODULE) --go-grpc_out=. \ --plugin=protoc-gen-grpc-gateway=$(TOOLS_BIN_DIR)/protoc-gen-grpc-gateway \ --grpc-gateway_opt=module=$(GO_MODULE) --grpc-gateway_opt=logtostderr=true --grpc-gateway_out=. \ --plugin=protoc-gen-openapiv2=$(TOOLS_BIN_DIR)/protoc-gen-openapiv2 \ --openapiv2_out . \ -I third_party/googleapis/ -I . $(PROTOBUF_DEPS) lint: ## Runs golangci-lint $(GOBIN)/golangci-lint run -v ./... gosec: ## Runs gosec $(GOBIN)/gosec ./... gen: $(GENSRC) fulcio: $(SRCS) ## Build Fulcio for local tests go build -trimpath -ldflags "$(LDFLAGS)" test: ## Runs go test go test ./... clean: ## Clean the workspace rm -rf dist rm -rf fulcio clean-gen: clean rm -rf $(shell find pkg/generated -iname "*.go") *.swagger.json up: ## Start docker compose docker-compose -f docker-compose.yml build docker-compose -f docker-compose.yml up debug: ## Start docker compose in debug mode docker-compose -f docker-compose.yml -f docker-compose.debug.yml build fulcio-server-debug docker-compose -f docker-compose.yml -f docker-compose.debug.yml up fulcio-server-debug ## -------------------------------------- ## Tooling Binaries ## -------------------------------------- $(PROTOC-GEN-GO): $(TOOLS_DIR)/go.mod cd $(TOOLS_DIR); go build -trimpath -tags=tools -o $(TOOLS_BIN_DIR)/protoc-gen-go google.golang.org/protobuf/cmd/protoc-gen-go $(PROTOC-GEN-GO-GRPC): $(TOOLS_DIR)/go.mod cd $(TOOLS_DIR); go build -trimpath -tags=tools -o $(TOOLS_BIN_DIR)/protoc-gen-go-grpc google.golang.org/grpc/cmd/protoc-gen-go-grpc $(PROTOC-GEN-GRPC-GATEWAY): $(TOOLS_DIR)/go.mod cd $(TOOLS_DIR); go build -trimpath -tags=tools -o $(TOOLS_BIN_DIR)/protoc-gen-grpc-gateway github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway $(PROTOC-GEN-OPENAPIV2): $(TOOLS_DIR)/go.mod cd $(TOOLS_DIR); go build -trimpath -tags=tools -o $(TOOLS_BIN_DIR)/protoc-gen-openapiv2 github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 $(PROTOC-API-LINTER): $(TOOLS_DIR)/go.mod cd $(TOOLS_DIR); go build -trimpath -tags=tools -o $(TOOLS_BIN_DIR)/api-linter github.com/googleapis/api-linter/cmd/api-linter ## -------------------------------------- ## Images with ko ## -------------------------------------- .PHONY: ko ko: # fulcio LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ KO_DOCKER_REPO=$(KO_PREFIX)/fulcio ko resolve --bare \ --platform=linux/amd64 --tags $(GIT_VERSION) --tags $(GIT_HASH) \ --image-refs fulcioImagerefs --filename config/ > $(FULCIO_YAML) .PHONY: ko-local ko-local: LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ ko publish --base-import-paths \ --platform=linux/amd64 --tags $(GIT_VERSION) --tags $(GIT_HASH) --local \ github.com/sigstore/fulcio .PHONY: ko-apply ko-apply: LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) ko apply -Bf config/ .PHONY: ko-apply-ci ko-apply-ci: ko-apply LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) ko apply -Bf config/test .PHONY: ko-publish ko-publish: LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) ko publish . .PHONY: sign-keyless-ci sign-keyless-ci: ko cosign sign --yes -a GIT_HASH=$(GIT_HASH) $(KO_DOCKER_REPO)/fulcio:$(GIT_HASH) ## -------------------------------------- ## Modules ## -------------------------------------- .PHONY: modules modules: ## Runs go mod to ensure modules are up to date. go mod tidy ################## # help ################## help: ## Display help @awk -F ':|##' \ '/^[^\t].+?:.*?##/ {\ printf "\033[36m%-30s\033[0m %s\n", $$1, $$NF \ }' $(MAKEFILE_LIST) | sort include release/release.mk fulcio-1.6.5/README.md000066400000000000000000000150311470150653400142700ustar00rootroot00000000000000[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/sigstore/fulcio/badge)](https://api.securityscorecards.dev/projects/github.com/sigstore/fulcio)

Fulcio logo

# Fulcio _A Free-to-Use CA For Code Signing_ Fulcio is a free-to-use certificate authority for issuing code signing certificates for an OpenID Connect (OIDC) identity, such as email address. Fulcio only issues short-lived certificates that are valid for 10 minutes. ## Public Instance Fulcio is in General Availability, offering a 99.5 Availability SLO, and follows [semver rules](https://semver.org/) for API stability. For uptime data on the Fulcio public instance, see [https://status.sigstore.dev](https://status.sigstore.dev). Fulcio's certificate chain can be obtained from the `TrustBundle` API, for example for the public instance ([https://fulcio.sigstore.dev](https://fulcio.sigstore.dev/api/v2/trustBundle)). To verify the public instance, you must verify the chain using Sigstore's [TUF](https://theupdateframework.io/) root from the [sigstore/root-signing](https://github.com/sigstore/root-signing) repository). To do this, install and use [go-tuf](https://github.com/theupdateframework/go-tuf)'s CLI tools: ``` $ go install github.com/theupdateframework/go-tuf/cmd/tuf-client@latest ``` Then, obtain trusted root keys for Sigstore. You will use the 5th iteration of Sigstore's TUF root to start the root of trust, due to a backwards incompatible change. ``` curl -o sigstore-root.json https://raw.githubusercontent.com/sigstore/root-signing/main/ceremony/2022-10-18/repository/5.root.json ``` Initialize the TUF client with the previously obtained root and the remote repository, https://tuf-repo-cdn.sigstore.dev, and get the current Fulcio root certificate `fulcio_v1.crt.pem` and intermediate certificate `fulcio_intermediate_v1.crt.pem`. ``` $ tuf-client init https://tuf-repo-cdn.sigstore.dev sigstore-root.json $ tuf-client get https://tuf-repo-cdn.sigstore.dev fulcio_v1.crt.pem -----BEGIN CERTIFICATE----- MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl LmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7 XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex X69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY wB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ KsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM WP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9 TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ -----END CERTIFICATE----- $ tuf-client get https://tuf-repo-cdn.sigstore.dev fulcio_intermediate_v1.crt.pem -----BEGIN CERTIFICATE----- MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl LmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C AQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7 7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS 0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB BQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp KFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI zj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR nZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP mygUY7Ii2zbdCdliiow= -----END CERTIFICATE----- ``` ### Verifying releases You can also verify signed releases (`fulcio-.sig`) using the artifact signing key: ``` tuf-client get https://tuf-repo-cdn.sigstore.dev artifact.pub > artifact.pub curl -o fulcio-release.sig -L https://github.com/sigstore/fulcio/releases/download//fulcio-.sig base64 -d fulcio-release.sig > fulcio-release.sig.decoded curl -o fulcio-release -L https://github.com/sigstore/fulcio/releases/download//fulcio- openssl dgst -sha256 -verify artifact.pub -signature fulcio-release.sig.decoded fulcio-release ``` ## API The API is defined [here](./fulcio.proto). The API can be accessed over [HTTP](https://www.sigstore.dev/swagger/?urls.primaryName=Fulcio) or gRPC. ## Certificate Transparency Fulcio will publish issued certificates to a Certificate Transparency log (CT log). The log is hosted at `https://ctfe.sigstore.dev/test`. Each year, the log will be updated to a new log ID, for example `https://ctfe.sigstore.dev/2022`. The log provides an API documented in [RFC 6962](https://datatracker.ietf.org/doc/rfc6962/). We encourage auditors to monitor this log for both integrity and specific identities. For example, auditors can monitor for when a certificate is issued for certain email addresses, which will detect misconfiguration or potential compromise of the user's identity. ## Security Please report any vulnerabilities following sigstore's [security process](https://github.com/sigstore/.github/blob/main/SECURITY.md). ## Info Fulcio is developed as part of the [`sigstore`](https://sigstore.dev) project. We also use a [slack channel](https://sigstore.slack.com)! To check more information about Slack and other communication channels please check the [community repository](https://github.com/sigstore/community?tab=readme-ov-file#slack) ## Additional Documentation In addition to this README file, the docs folder contains the additional documentation: - **certificate-specification.md**. This file includes the requirements for root, intermediate, and issued certificates. The document applies to all instances of Fulcio, including the production instance and all private instances. - **ctlog.md**. Certificate transparency log information, including information on signed certificate timestamps and a sharding strategy for the CT log. - **how-certifcate-issuing-works.md**. This document walks through the process of issuing a code signing certificate. - **hsm-support.md**. Using Fulcio with a pkcs11 capable device such as SoftHSM. - **oid-info.md**. Sigstore OID information. - **security-model.md**. Fulcio’s security model and a discussion of short-lived certificates. - **setup.md**. Setting up a local Fulcio instance If you are making changes to any of these subjects, make sure you also edit the appropriate file listed above. fulcio-1.6.5/cmd/000077500000000000000000000000001470150653400135545ustar00rootroot00000000000000fulcio-1.6.5/cmd/app/000077500000000000000000000000001470150653400143345ustar00rootroot00000000000000fulcio-1.6.5/cmd/app/createca.go000066400000000000000000000123531470150653400164360ustar00rootroot00000000000000//go:build cgo // +build cgo // Copyright 2021 The Sigstore 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 app import ( "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "fmt" "os" "path/filepath" "time" "github.com/ThalesIgnite/crypto11" "github.com/sigstore/fulcio/pkg/log" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/spf13/cobra" "github.com/spf13/viper" ) const ( LABEL = "PKCS11CA" ) func newCreateCACmd() *cobra.Command { cmd := &cobra.Command{ Use: "createca", Short: "Create a root CA in a pkcs11 device", Long: `Create an x509 root CA within a pkcs11 device using values such as organization, country etc. This can then be used as the root certificate authority for an instance of sigstore fulcio`, Run: runCreateCACmd, } cmd.Flags().String("org", "Fulcio Root CA", "Organization name for root CA") cmd.Flags().String("country", "", "Country name for root CA") cmd.Flags().String("province", "", "Province name for root CA") cmd.Flags().String("locality", "", "Locality name for root CA") cmd.Flags().String("street-address", "", "Street address for root CA") cmd.Flags().String("postal-code", "", "Postal code for root CA") cmd.Flags().String("out", "", "output root CA to file") cmd.Flags().String("hsm", "softhsm", "The HSM provider to use. Valid values: softhsm (default), aws") cmd.Flags().String("pkcs11-config-path", "config/crypto11.conf", "path to fulcio pkcs11 config file") cmd.Flags().String("hsm-caroot-id", "", "HSM ID for Root CA") err := cmd.MarkFlagRequired("hsm-caroot-id") if err != nil { log.Logger.Fatal(`Failed to mark flag as required`) } return cmd } func runCreateCACmd(cmd *cobra.Command, args []string) { //nolint: revive if err := viper.BindPFlags(cmd.Flags()); err != nil { log.Logger.Fatal(err) } log.Logger.Info("binding to PKCS11 HSM") p11Ctx, err := crypto11.ConfigureFromFile(viper.GetString("pkcs11-config-path")) if err != nil { log.Logger.Fatal(err) } defer p11Ctx.Close() rootID := []byte(viper.GetString("hsm-caroot-id")) // Check if CA already exists (or a cert within the provided ID) findCA, err := p11Ctx.FindCertificate(rootID, nil, nil) if err != nil { log.Logger.Fatal(err) } if findCA != nil { log.Logger.Fatal("certificate already exists with this ID") } // Find the existing Key Pair // TODO: We could make the TAG customizable log.Logger.Infof("finding slot for private key label %q", LABEL) privKey, err := p11Ctx.FindKeyPair(nil, []byte(LABEL)) if err != nil { log.Logger.Fatal(err) } if privKey == nil { log.Logger.Fatalf("no key pair was found matching label %q", LABEL) } pubKey := privKey.Public() serialNumber, err := cryptoutils.GenerateSerialNumber() if err != nil { log.Logger.Fatal(err) } rootCA := &x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{viper.GetString("org")}, Country: []string{viper.GetString("country")}, Province: []string{viper.GetString("province")}, Locality: []string{viper.GetString("locality")}, StreetAddress: []string{viper.GetString("street-address")}, PostalCode: []string{viper.GetString("postal-code")}, }, NotBefore: time.Now(), NotAfter: time.Now().AddDate(10, 0, 0), IsCA: true, KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, BasicConstraintsValid: true, MaxPathLen: 1, } caBytes, err := x509.CreateCertificate(rand.Reader, rootCA, rootCA, pubKey, privKey) if err != nil { log.Logger.Fatal(err) } pemBytes := pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: caBytes, }) log.Logger.Info("Root CA:") fmt.Println(string(pemBytes)) certParse, err := x509.ParseCertificate(caBytes) if err != nil { log.Logger.Fatal(err) } // Import the root CA into the HSM // TODO: We could make the TAG customizable if viper.GetString("hsm") == "aws" { log.Logger.Info("Running in AWS mode; skipping root CA storage in HSM") if !viper.IsSet("out") { log.Logger.Warn("WARNING: --out is not set. Root CA will not be saved.") } } else { if err = p11Ctx.ImportCertificateWithLabel(rootID, []byte(LABEL), certParse); err != nil { log.Logger.Fatal(err) } log.Logger.Info("root CA created with PKCS11 ID: ", viper.GetString("hsm-caroot-id")) } // Save out the file in pem format for easy import to CTL chain if viper.IsSet("out") { certOut, err := os.Create(filepath.Clean(viper.GetString("out"))) if err != nil { log.Logger.Fatal(err) } if err := pem.Encode(certOut, &pem.Block{ //nolint Type: "CERTIFICATE", Bytes: caBytes}, ); err != nil { certOut.Close() log.Logger.Fatal(err) } certOut.Close() log.Logger.Info("root CA saved to file: ", viper.GetString("out")) } } fulcio-1.6.5/cmd/app/createcanocgo.go000066400000000000000000000025731470150653400174670ustar00rootroot00000000000000//go:build !cgo // +build !cgo // Copyright 2021 The Sigstore 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 app import ( "github.com/sigstore/fulcio/pkg/log" "github.com/spf13/cobra" ) // Just a placeholder for erroring with a meaningful message if the // binary has been built with GCO_ENABLED=0 tags. func newCreateCACmd() *cobra.Command { return &cobra.Command{ Use: "createca", Short: "Create a root CA in a pkcs11 device (**not supported in this binary**)", Long: `Create an x509 root CA within a pkcs11 device using values such as organization, country etc. This can then be used as the root certificate authority for an instance of sigstore fulcio`, Run: runCreateCACmdPlaceholder, } } func runCreateCACmdPlaceholder(cmd *cobra.Command, args []string) { log.Logger.Fatal("Binary has been built with CGO_ENABLED=0, createca is not supported") } fulcio-1.6.5/cmd/app/grpc.go000066400000000000000000000216151470150653400156230ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 app import ( "context" "crypto/tls" "fmt" "net" "os" "os/signal" "runtime" "sync" "syscall" "github.com/fsnotify/fsnotify" "github.com/goadesign/goa/grpc/middleware" ctclient "github.com/google/certificate-transparency-go/client" grpcmw "github.com/grpc-ecosystem/go-grpc-middleware" grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap" grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/prometheus/client_golang/prometheus" "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/config" gw "github.com/sigstore/fulcio/pkg/generated/protobuf" gw_legacy "github.com/sigstore/fulcio/pkg/generated/protobuf/legacy" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/log" "github.com/sigstore/fulcio/pkg/server" "github.com/spf13/viper" "google.golang.org/grpc" "google.golang.org/grpc/credentials" health "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/keepalive" ) const ( LegacyUnixDomainSocket = "@fulcio-legacy-grpc-socket" ) type grpcServer struct { *grpc.Server grpcServerEndpoint string caService gw.CAServer tlsCertWatcher *fsnotify.Watcher } func PassFulcioConfigThruContext(cfg *config.FulcioConfig) grpc.UnaryServerInterceptor { return func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { // For each request, infuse context with our snapshot of the FulcioConfig. // TODO(mattmoor): Consider periodically (every minute?) refreshing the ConfigMap // from disk, so that we don't need to cycle pods to pick up config updates. // Alternately we could take advantage of Knative's configmap watcher. ctx = config.With(ctx, cfg) ctx, cancel := context.WithCancel(ctx) defer cancel() // Calls the inner handler return handler(ctx, req) } } type cachedTLSCert struct { sync.RWMutex certPath string keyPath string cert *tls.Certificate Watcher *fsnotify.Watcher } func newCachedTLSCert(certPath, keyPath string) (*cachedTLSCert, error) { cachedTLSCert := &cachedTLSCert{ certPath: certPath, keyPath: keyPath, } if err := cachedTLSCert.UpdateCertificate(); err != nil { return nil, err } var err error cachedTLSCert.Watcher, err = fsnotify.NewWatcher() if err != nil { return nil, err } go func() { for { select { case event, ok := <-cachedTLSCert.Watcher.Events: if !ok { return } if event.Has(fsnotify.Write) { log.Logger.Info("fsnotify grpc-tls-certificate write event detected") if err := cachedTLSCert.UpdateCertificate(); err != nil { log.Logger.Error(err) } } case err, ok := <-cachedTLSCert.Watcher.Errors: if !ok { return } log.Logger.Error("fsnotify grpc-tls-certificate error:", err) } } }() // Add a path. if err = cachedTLSCert.Watcher.Add(certPath); err != nil { return nil, err } return cachedTLSCert, nil } func (c *cachedTLSCert) GetCertificate() *tls.Certificate { // get reader lock c.RLock() defer c.RUnlock() return c.cert } func (c *cachedTLSCert) UpdateCertificate() error { // get writer lock c.Lock() defer c.Unlock() cert, err := tls.LoadX509KeyPair(c.certPath, c.keyPath) if err != nil { return fmt.Errorf("loading GRPC tls certificate and key file: %w", err) } c.cert = &cert return nil } func (c *cachedTLSCert) GRPCCreds() grpc.ServerOption { return grpc.Creds(credentials.NewTLS(&tls.Config{ GetCertificate: func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) { return c.GetCertificate(), nil }, MinVersion: tls.VersionTLS13, })) } func createGRPCServer(cfg *config.FulcioConfig, ctClient *ctclient.LogClient, baseca ca.CertificateAuthority, ip identity.IssuerPool) (*grpcServer, error) { logger, opts := log.SetupGRPCLogging() serverOpts := []grpc.ServerOption{ grpc.UnaryInterceptor( grpcmw.ChainUnaryServer( grpc_recovery.UnaryServerInterceptor(grpc_recovery.WithRecoveryHandlerContext(panicRecoveryHandler)), // recovers from per-transaction panics elegantly, so put it first middleware.UnaryRequestID(middleware.UseXRequestIDMetadataOption(true), middleware.XRequestMetadataLimitOption(128)), grpc_zap.UnaryServerInterceptor(logger, opts...), PassFulcioConfigThruContext(cfg), grpc_prometheus.UnaryServerInterceptor, )), grpc.KeepaliveParams(keepalive.ServerParameters{ MaxConnectionIdle: viper.GetDuration("idle-connection-timeout"), }), grpc.MaxRecvMsgSize(int(maxMsgSize)), } var tlsCertWatcher *fsnotify.Watcher if viper.IsSet("grpc-tls-certificate") && viper.IsSet("grpc-tls-key") { cachedTLSCert, err := newCachedTLSCert(viper.GetString("grpc-tls-certificate"), viper.GetString("grpc-tls-key")) if err != nil { return nil, err } tlsCertWatcher = cachedTLSCert.Watcher serverOpts = append(serverOpts, cachedTLSCert.GRPCCreds()) } myServer := grpc.NewServer(serverOpts...) grpcCAServer := server.NewGRPCCAServer(ctClient, baseca, ip) health.RegisterHealthServer(myServer, grpcCAServer) // Register your gRPC service implementations. gw.RegisterCAServer(myServer, grpcCAServer) grpcServerEndpoint := fmt.Sprintf("%s:%s", viper.GetString("grpc-host"), viper.GetString("grpc-port")) return &grpcServer{myServer, grpcServerEndpoint, grpcCAServer, tlsCertWatcher}, nil } func (g *grpcServer) setupPrometheus(reg *prometheus.Registry) { grpcMetrics := grpc_prometheus.DefaultServerMetrics grpcMetrics.EnableHandlingTimeHistogram() reg.MustRegister(grpcMetrics, server.MetricLatency, server.RequestsCount) grpc_prometheus.Register(g.Server) } func (g *grpcServer) startTCPListener(wg *sync.WaitGroup) { // lis is closed by g.Server.Serve() upon exit lis, err := net.Listen("tcp", g.grpcServerEndpoint) if err != nil { log.Logger.Fatal(err) } g.grpcServerEndpoint = lis.Addr().String() log.Logger.Infof("listening on grpc at %s", g.grpcServerEndpoint) idleConnsClosed := make(chan struct{}) go func() { sigint := make(chan os.Signal, 1) signal.Notify(sigint, syscall.SIGINT, syscall.SIGTERM) <-sigint // received an interrupt signal, shut down g.Server.GracefulStop() close(idleConnsClosed) log.Logger.Info("stopped grpc server") }() wg.Add(1) go func() { if g.tlsCertWatcher != nil { defer g.tlsCertWatcher.Close() } if err := g.Server.Serve(lis); err != nil { log.Logger.Fatalf("error shutting down grpcServer: %w", err) } <-idleConnsClosed wg.Done() log.Logger.Info("grpc server shutdown") }() } func (g *grpcServer) startUnixListener() { go func() { if runtime.GOOS != "linux" { // As MacOS doesn't have abstract unix domain sockets the file // created by a previous run needs to be explicitly removed if err := os.RemoveAll(g.grpcServerEndpoint); err != nil { log.Logger.Fatal(err) } } unixAddr, err := net.ResolveUnixAddr("unix", g.grpcServerEndpoint) if err != nil { log.Logger.Fatal(err) } lis, err := net.ListenUnix("unix", unixAddr) if err != nil { log.Logger.Fatal(err) } defer lis.Close() log.Logger.Infof("listening on grpc at %s", unixAddr.String()) log.Logger.Fatal(g.Server.Serve(lis)) }() } func (g *grpcServer) ExposesGRPCTLS() bool { return viper.IsSet("grpc-tls-certificate") && viper.IsSet("grpc-tls-key") } func createLegacyGRPCServer(cfg *config.FulcioConfig, unixDomainSocket string, v2Server gw.CAServer) (*grpcServer, error) { logger, opts := log.SetupGRPCLogging() myServer := grpc.NewServer(grpc.UnaryInterceptor( grpcmw.ChainUnaryServer( grpc_recovery.UnaryServerInterceptor(grpc_recovery.WithRecoveryHandlerContext(panicRecoveryHandler)), // recovers from per-transaction panics elegantly, so put it first middleware.UnaryRequestID(middleware.UseXRequestIDMetadataOption(true), middleware.XRequestMetadataLimitOption(128)), grpc_zap.UnaryServerInterceptor(logger, opts...), PassFulcioConfigThruContext(cfg), grpc_prometheus.UnaryServerInterceptor, )), grpc.MaxRecvMsgSize(int(maxMsgSize))) legacyGRPCCAServer := server.NewLegacyGRPCCAServer(v2Server) // Register your gRPC service implementations. gw_legacy.RegisterCAServer(myServer, legacyGRPCCAServer) return &grpcServer{myServer, unixDomainSocket, v2Server, nil}, nil } func panicRecoveryHandler(ctx context.Context, p interface{}) error { log.ContextLogger(ctx).Error(p) return fmt.Errorf("panic: %v", p) } fulcio-1.6.5/cmd/app/grpc_test.go000066400000000000000000000235671470150653400166720ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 app import ( "bytes" "os" "path/filepath" "testing" "time" ) const keyPEM = `-----BEGIN PRIVATE KEY----- MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC9zcw1BhE7nK0b 7wWw+fnRnyShQbixg9/pktMw/vz6xFh/PaCBlo/joeXd/nvUAHyddIFFshz1vIOA 5Wk6z23NGdgDq3K/1yC04K2AV+5y0cV15akldCvjBaEHShSyma7rpyYUph93Ct+e uO9GRnb7fd8YrSELoRe00hfuyD5j3yNPWJbQAiIFnEwF/ynl3l9MR+h1U381nQU3 nz9M486OaRK2q1r59ms8vTZNVn8h0PHtFJZWoP4pyo4l1Kd64K3mqeJCBwvAEwiT nKbIws/7IqXUZBcd9qDGHd7zgeUT3deBUJOGT1crwdJB6tSYfSiSUjHY+BxJLQU+ OzPj1Swp3tDB5kDNxppqhqkrRCRdG9RktLA+A6OuIm13o+LlLvE33UOcabIMcDsE aAK17DvUFSBbYDNZcmrcRfSQeMxoSAcIvn1JTD+k6UyI1cwLqGdRIfmWdjaKw2z3 4NRT5dr9n0wT4HRKJEJpEartlR1eIe5o34OJGPeFfVU73rBWO9kCHQmSUjqlUHtz Poe87DGIC1KJfGohBmTJpzeU/3f20AXMtW+mpKpofNQXxuoFKRbHLyJlVb0QmIhv zABUTxFKXhayydSud4x9ePGzJDbvUfoMgMtY/gEe2iupw3S8ac4Tfs3oOOs4lppP JpOGfaoqOa3qCGq9NjQJFWnJDPezNQIDAQABAoICAArbyzhSsImzMkl20zcyFei4 LLr3rOlQR28ax0T2UY1xzjOkAvARp7Rjfr3EjAZaQMbWniQD8e7dFL47DFog+Sx9 XgOtEKjeVdtYlJR9yKvTnx2vleMJUmQaiQExwR1hTXCN5M/URoM49rIjQmJy2uZo Z8BcUez9ulgjQjCW+XrH4+1A1DVHlKAINmaMF97ev0pN6C6jfZOY+BjGiN3ilTPw hEbkZsAGKPxrQWq17XAHKXq2ws28nXh77htGnzjtwa/V6EEpcLKnDsaNymeR6El7 IfbqAv3j2Nl8u/89CdipHbsi26MYxuk/SBgdUdb80hAM7m0gmf2rEFxkZq48yS9C kaTzZJeOYLsP8wNNaGpoyHw+M66WPEzmmecw7fi9WhQRSoW9EL7GaXchVSOZu6KG wOFvxA5fL4IXKydVUwKQj4w17BVgK+EmBOqovlQkEB4tvBt7fx4/7XNIYDu5aiBP JueQXOJSXjlN1aMztels09RpLJVyxmkv4+PJHw8dQEt1zj/xBwZ1Y9yU11XttI2X TjaRAsVc0bUaXAX4dPLVNzri7E8rgBIqC1GIcIrmzWCGpqLQx+dO+9e7Eui2i1Ty eUYgnGTc/qB/KGw3r+r0mduUSXSOPDruG/kGtBFSYYojEptzAa+q7rLIbiVy5WzR nlVyc9JmtkP4ikQqedwBAoIBAQC/cRcZEkzo8cuJFqYDp4GAJiaqe3nZl0zZXAyn JW3IyZFcRfP6F6a6+OqqmNgipHV50JZn2X2MY0fiuVeqSndsFOhI2TxlY72iEjVW QmJZrVAf5L1XA4kbIWGKoHKVYDKcsWTvwgnG4KAGGN8VemvzOXhyA1Y7EE+G7ivs qFCCWbM9nJ3iRK4rcBWnFFJtWAJtgfFqXVSlI5rA6ODyTTJgLkFDm+gXs7azNwbG 7giu22Ug3GvI+lraDIQtDzy6pc/rBDMK9bA6WgEdam9/hJtqcPh4TF8jXoh1cUb+ tFvQ6jb8WusiXv3E9avBXUChNHIdlDdkBnAHPJcs7UxYWH/FAoIBAQD9z1Alv2rQ WPSFKz42lXNg2rCn48d+Jxz9lnwXVcAvVuS55STSkwi5bfeAIFWryGvq1CBUG1oJ 3IW60P3H+ZKp6ZuIvSJHRiVrOqTdPWbeRsdBGyNBEe5sI6zhbvUMWP246rPoBF3p izruJXfUOea05xuaOUhlSXGeHONbzkm1iC5pJBiJtEVRfqrtH6dUQaB7gbfOC0VO kG/8ztzlF8nu+Qo0hawsg8gJ4F9miK+A8yT3kio0RIZMSe/h8qeA1/CVyc8vOO3w fJSK/NZjxudxOJaG4LGXNolOaFQFCnsaspL/8Lj44fzHjvHuEgCZzjpcKIKFK4a6 ku/8opWCI6yxAoIBAHd4mQSRciPReca0tqgDKgMSTAEKi7FqBZCELHVHG2s5t5hR I4AIsIlwe+o49nEwFwwNSz/F797jumHYbsgcLsjph0inIVTY2OhC2rxZM01ppl4w /qRF1ZNz0o6TsM5duVgmMKqbekR9u//yF44s1x9z1yG3yWGUvTykeA75vzyJxB0I F1O0rsj26txZB1Orn+A9Pq61TfS88n+/FVrBKFXzp9EMg9v+0F6pUXZl6E9PJZ5L UIydCIOZWgdQwgJtJgMxnLUTPIY90wJLgQegdukHVViluJ23CgvYxIiBf+cxs1zr VGAfzdjTw/spOgMgWrLw41xt1A4AFwv3jzR3Dk0CggEAO8iyW0HcWhkp95g4/khz tfOtOs6ndeqmpIDm1+RF8aCpHbSA2OzzWCIz80UqiN0btmOi/cy3h60e/uMtdAYw ar9w+GN8iIdYVwqoPMiyy1ampopK4o/jtistFKi7Jd5sXTtDhzpIGLPH/MJsmFvP IPty///QMrN7BMBPOZe8uvrJ29A5y23gChMpFdOn6WvP7meesPTsrVXOWyEq3Pee hCC7K6X06UNdQh5Mum0l0dzz7zDJqigd7ihYTcOHewziSZYQrFHfkg72OkrWAQig CYZHxpt0mWaqLwLaD5npZ196yricCVvJ3AOqruYkqBXwnzaXj+Cxyo7D4qE1UEMw 8QKCAQAgKB8pSvgdP1nrdsiFjvJwXHVabyaHlLUU2xW8CcWNrX4z7tuOorHnFKu7 D6AvkW2nM7K4W7Knn/TACSTEzXytvKU2Am+JHJbi+SrGSr3VM4JNklnDSWtvDSZ2 uv1ycM5ct/2YXfZehSFXXciL99mLl3BWslH758E7LQNL8tCyaOelPaHGoRkApgAX C8mMosCuTBWKSIEMyrhSAuJvWgSt2F5hAONtwhky+VxGY/Zh+vlGbDB2m7kFOSll kOTOQEUICKT3kjwVCnekB7FRdHr05zy5DbqOJOaKRGQaQAGk18UjiFgqH6y9iVPm qYtj1Qkj5x+/YNNEPPyaPZ54nh3F -----END PRIVATE KEY-----` const certPEM = `-----BEGIN CERTIFICATE----- MIIFqzCCA5OgAwIBAgIUTmTZD9FuR4UNUNVOkB2IMeWqv1UwDQYJKoZIhvcNAQEL BQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMREwDwYDVQQHDAhLaXJrbGFu ZDERMA8GA1UECgwIU2lnc3RvcmUxDzANBgNVBAsMBkZ1bGNpbzESMBAGA1UEAwwJ bG9jYWxob3N0MB4XDTIzMDYyODAwMTQzMloXDTMzMDYyNTAwMTQzMlowZTELMAkG A1UEBhMCVVMxCzAJBgNVBAgMAldBMREwDwYDVQQHDAhLaXJrbGFuZDERMA8GA1UE CgwIU2lnc3RvcmUxDzANBgNVBAsMBkZ1bGNpbzESMBAGA1UEAwwJbG9jYWxob3N0 MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvc3MNQYRO5ytG+8FsPn5 0Z8koUG4sYPf6ZLTMP78+sRYfz2ggZaP46Hl3f571AB8nXSBRbIc9byDgOVpOs9t zRnYA6tyv9cgtOCtgFfuctHFdeWpJXQr4wWhB0oUspmu66cmFKYfdwrfnrjvRkZ2 +33fGK0hC6EXtNIX7sg+Y98jT1iW0AIiBZxMBf8p5d5fTEfodVN/NZ0FN58/TOPO jmkStqta+fZrPL02TVZ/IdDx7RSWVqD+KcqOJdSneuCt5qniQgcLwBMIk5ymyMLP +yKl1GQXHfagxh3e84HlE93XgVCThk9XK8HSQerUmH0oklIx2PgcSS0FPjsz49Us Kd7QweZAzcaaaoapK0QkXRvUZLSwPgOjriJtd6Pi5S7xN91DnGmyDHA7BGgCtew7 1BUgW2AzWXJq3EX0kHjMaEgHCL59SUw/pOlMiNXMC6hnUSH5lnY2isNs9+DUU+Xa /Z9ME+B0SiRCaRGq7ZUdXiHuaN+DiRj3hX1VO96wVjvZAh0JklI6pVB7cz6HvOwx iAtSiXxqIQZkyac3lP939tAFzLVvpqSqaHzUF8bqBSkWxy8iZVW9EJiIb8wAVE8R Sl4WssnUrneMfXjxsyQ271H6DIDLWP4BHtorqcN0vGnOE37N6DjrOJaaTyaThn2q Kjmt6ghqvTY0CRVpyQz3szUCAwEAAaNTMFEwHQYDVR0OBBYEFGgoph9DIwXUHUT0 8y7CtcviGmPhMB8GA1UdIwQYMBaAFGgoph9DIwXUHUT08y7CtcviGmPhMA8GA1Ud EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAIzLEKyA1KAEgHmH4/gipKct qMYfmTPTgKm3s5sEQlFZVQS9BzjgAnHq943JDn/GqPOipAZUw3iE3sueZSVypwEi zSjbJTPJPZn4Z/RcTK8ovtjVJDUUPxAe9ScpA8YShcwcITxiXt+CzLm4lSs67kDP BqOSfrjnCSazjtFJnTEpysynTe9B8hD9ODWm4k+/hh+PGB3fqi7ZJm0+9fMr86lR QW6ZMvwUXfWUVCfalOINk17Z42hXk4+jhj8mjnMtflt9o4xPdSl3qkVwoUFRCwfy RMYL+gaKONClOogxa/sMgqycENH31DJX+lPwXUFQ+bH2SKnz3+Dgmds5O8EgheUL BDQ1Tbz7d4MTAgo/ZefZE94ZBfcz6KNwgTcxlLfl3mBc5bxhri8Y1aR8tlhOV5JS hRa/vAPlpdglBFTO0wThjJEy0xlGlUQgQ1Y1HrqATOO6ACxkbX7DEouezRe0q6e5 VOUjno7qtSq6Sgj5ufWaI3qyZhJtCa0db1p6xnjIzwCblhrFKtJObqQI1Rr02Wz+ H165IZ5Lwe4VyrYGTPJTzK8f0NmwVGcgB0llNi8jdmKuLc/MWuBkKdW0FtUksfzv tSLmTWsb+j/Oxljalf+rAlItYk297HN0xMvlkHkB80O5Un6OMCHAjJmfOVZal2Y5 o4ZDR+PzKEbU8eUQbooS -----END CERTIFICATE-----` const renewedCertPEM = `-----BEGIN CERTIFICATE----- MIIFqzCCA5OgAwIBAgIUYKKd201v0q4S0FVSdKvRvrC9JQIwDQYJKoZIhvcNAQEL BQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMREwDwYDVQQHDAhLaXJrbGFu ZDERMA8GA1UECgwIU2lnc3RvcmUxDzANBgNVBAsMBkZ1bGNpbzESMBAGA1UEAwwJ bG9jYWxob3N0MB4XDTIzMDcwMTE4NTUzM1oXDTMzMDYyODE4NTUzM1owZTELMAkG A1UEBhMCVVMxCzAJBgNVBAgMAldBMREwDwYDVQQHDAhLaXJrbGFuZDERMA8GA1UE CgwIU2lnc3RvcmUxDzANBgNVBAsMBkZ1bGNpbzESMBAGA1UEAwwJbG9jYWxob3N0 MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvc3MNQYRO5ytG+8FsPn5 0Z8koUG4sYPf6ZLTMP78+sRYfz2ggZaP46Hl3f571AB8nXSBRbIc9byDgOVpOs9t zRnYA6tyv9cgtOCtgFfuctHFdeWpJXQr4wWhB0oUspmu66cmFKYfdwrfnrjvRkZ2 +33fGK0hC6EXtNIX7sg+Y98jT1iW0AIiBZxMBf8p5d5fTEfodVN/NZ0FN58/TOPO jmkStqta+fZrPL02TVZ/IdDx7RSWVqD+KcqOJdSneuCt5qniQgcLwBMIk5ymyMLP +yKl1GQXHfagxh3e84HlE93XgVCThk9XK8HSQerUmH0oklIx2PgcSS0FPjsz49Us Kd7QweZAzcaaaoapK0QkXRvUZLSwPgOjriJtd6Pi5S7xN91DnGmyDHA7BGgCtew7 1BUgW2AzWXJq3EX0kHjMaEgHCL59SUw/pOlMiNXMC6hnUSH5lnY2isNs9+DUU+Xa /Z9ME+B0SiRCaRGq7ZUdXiHuaN+DiRj3hX1VO96wVjvZAh0JklI6pVB7cz6HvOwx iAtSiXxqIQZkyac3lP939tAFzLVvpqSqaHzUF8bqBSkWxy8iZVW9EJiIb8wAVE8R Sl4WssnUrneMfXjxsyQ271H6DIDLWP4BHtorqcN0vGnOE37N6DjrOJaaTyaThn2q Kjmt6ghqvTY0CRVpyQz3szUCAwEAAaNTMFEwHQYDVR0OBBYEFGgoph9DIwXUHUT0 8y7CtcviGmPhMB8GA1UdIwQYMBaAFGgoph9DIwXUHUT08y7CtcviGmPhMA8GA1Ud EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAJp6m3a6nMlpzZ9doLh9WOmj dCz68oStA0HMflHGkGgtZ9BDNWQI5EL8rnsdj4l5h4nte7s4AQrtoHGdT/QkIwUu 1Zv3XBypubeof2iUJ+UhIz2Lm9vqt1hOT1HM3U7/4HCf/730y7LqwWIm580PLw1v 73C4kizrzg4T7C/4Jy5/lF5PzmJOVPWd0LDomWzbpw0pM2h8cYUY02HVEaeVOfHP lCoTW7cL36q3I/0RAyjGmK8nNGNpJTB4xjdTT4TJRotkhcKEsTVfIrVJFGlVMDoT Fe9T6rAnYQ2TlnPRhp9tDqiRb3Y027nJouddjulgGTRudUAzNkg7lVWJSDc4PwO2 7gm7I5/mbil6bI1r4djV0FPJZZI7EHgOM8OmKKqo5sLN0WQigZ8GSH1KHOuR1d2j m6GJOdUJ7+ZQ+tej0pwNERMSl0+OY+FtsFMusLXoIUUTyaOs1cpFO0ifqZSp9eUP 50QDoeDGYS0T/0RicNDXMTltE24G3L7mHiPa5rr4tlYvVHYeoez7qFtG5LvDvBH8 OVZzfoJGB4MbgrFxymai/9i+hdYadt2UHL9BfnUUInDhi/2l0MB1a45DYOzf5Zf0 IYjZh058kDhlL7WOkAhPdvm2wD9KAm4FDInw49PYxpasmDKaOTf1WeWfNa5CVOYp wpLmyTovgQl/NcXO7caU -----END CERTIFICATE-----` func TestCachedTLSCert(t *testing.T) { dir := t.TempDir() // not PKI material bad := []byte("not PKI material") badPath := filepath.Join(dir, "bad.pem") os.WriteFile(badPath, bad, 0644) // priv key keyPath := filepath.Join(dir, "key.pem") os.WriteFile(keyPath, []byte(keyPEM), 0644) // cert certPath := filepath.Join(dir, "cert.pem") os.WriteFile(certPath, []byte(certPEM), 0644) type testCase struct { desc string keyPath string certPath string success bool } testCases := []testCase{ { desc: "invalid path", keyPath: filepath.Join(dir, "not_here"), certPath: badPath, success: false, }, { desc: "invalid key and cert", keyPath: badPath, certPath: badPath, success: false, }, { desc: "invalid key, valid cert", keyPath: badPath, certPath: certPath, success: false, }, { desc: "valid key, invalid cert", keyPath: keyPath, certPath: badPath, success: false, }, { desc: "valid key, valid cert", keyPath: keyPath, certPath: certPath, success: true, }, } for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { cachedCert, err := newCachedTLSCert(tc.certPath, tc.keyPath) if tc.success != (err == nil) { t.Errorf("unexpected result: %v", err) } if tc.success { cert := cachedCert.GetCertificate() if cert == nil { t.Fatal("unexpected error reading tls.Certificate object") } // update the cert on disk to a renewed value (representing same public/private keypair) os.WriteFile(tc.certPath, []byte(renewedCertPEM), 0644) // sleep for a second to let goroutine fire for fsnotify event time.Sleep(1 * time.Second) renewedCert := cachedCert.GetCertificate() if renewedCert == nil { t.Fatal("unexpected error reading renewed tls.Certificate object") } if bytes.Equal(cert.Certificate[0], renewedCert.Certificate[0]) { t.Fatal("got same certificate after overwriting renewed cert to same file") } } }) } } fulcio-1.6.5/cmd/app/http.go000066400000000000000000000125611470150653400156470ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 app import ( "context" "crypto/tls" "errors" "fmt" "net/http" "os" "os/signal" "strconv" "strings" "sync" "syscall" "time" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/rs/cors" gw "github.com/sigstore/fulcio/pkg/generated/protobuf" legacy_gw "github.com/sigstore/fulcio/pkg/generated/protobuf/legacy" "github.com/sigstore/fulcio/pkg/log" "github.com/sigstore/fulcio/pkg/server" "github.com/spf13/viper" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" health "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/proto" ) type httpServer struct { *http.Server httpServerEndpoint string } func extractOIDCTokenFromAuthHeader(_ context.Context, req *http.Request) metadata.MD { token := strings.Replace(req.Header.Get("Authorization"), "Bearer ", "", 1) return metadata.Pairs(server.MetadataOIDCTokenKey, token) } func createHTTPServer(ctx context.Context, serverEndpoint string, grpcServer, legacyGRPCServer *grpcServer) httpServer { opts := []grpc.DialOption{} if grpcServer.ExposesGRPCTLS() { /* #nosec G402 */ // InsecureSkipVerify is only used for the HTTP server to call the TLS-enabled grpc endpoint. opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: true}))) } else { opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) } grpcHealthEndpoint := fmt.Sprintf("localhost:%s", viper.GetString("grpc-port")) cc, err := grpc.NewClient(grpcHealthEndpoint, opts...) if err != nil { log.Logger.Fatal(err) } mux := runtime.NewServeMux(runtime.WithMetadata(extractOIDCTokenFromAuthHeader), runtime.WithForwardResponseOption(setResponseCodeModifier), runtime.WithHealthzEndpoint(health.NewHealthClient(cc))) if err := gw.RegisterCAHandlerFromEndpoint(ctx, mux, grpcServer.grpcServerEndpoint, opts); err != nil { log.Logger.Fatal(err) } if legacyGRPCServer != nil { endpoint := fmt.Sprintf("unix:%v", legacyGRPCServer.grpcServerEndpoint) // we are connecting over a unix domain socket, therefore we won't ever need TLS unixDomainSocketOpts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())} if err := legacy_gw.RegisterCAHandlerFromEndpoint(ctx, mux, endpoint, unixDomainSocketOpts); err != nil { log.Logger.Fatal(err) } } // Limit request size handler := server.WithMaxBytes(mux, maxMsgSize) handler = promhttp.InstrumentHandlerDuration(server.MetricLatency, handler) handler = promhttp.InstrumentHandlerCounter(server.RequestsCount, handler) // enable CORS // cors.Default() configures to accept requests for all domains handler = cors.Default().Handler(handler) api := http.Server{ Addr: serverEndpoint, Handler: handler, // Timeouts ReadTimeout: 60 * time.Second, ReadHeaderTimeout: 60 * time.Second, WriteTimeout: 60 * time.Second, IdleTimeout: viper.GetDuration("idle-connection-timeout"), } return httpServer{&api, serverEndpoint} } func (h httpServer) startListener(wg *sync.WaitGroup) { log.Logger.Infof("listening on http at %s", h.httpServerEndpoint) idleConnsClosed := make(chan struct{}) go func() { sigint := make(chan os.Signal, 1) signal.Notify(sigint, syscall.SIGINT, syscall.SIGTERM) <-sigint // received an interrupt signal, shut down if err := h.Shutdown(context.Background()); err != nil { // error from closing listeners, or context timeout log.Logger.Errorf("HTTP server Shutdown: %v", err) } close(idleConnsClosed) log.Logger.Info("stopped http server") }() wg.Add(1) go func() { if err := h.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Logger.Fatal(err) } <-idleConnsClosed wg.Done() log.Logger.Info("http server shutdown") }() } func setResponseCodeModifier(ctx context.Context, w http.ResponseWriter, _ proto.Message) error { md, ok := runtime.ServerMetadataFromContext(ctx) if !ok { return nil } // set SCT if present ahead of modifying response code if vals := md.HeaderMD.Get(server.SCTMetadataKey); len(vals) > 0 { delete(md.HeaderMD, server.SCTMetadataKey) delete(w.Header(), "Grpc-Metadata-sct") w.Header().Set("SCT", vals[0]) } // strip all GRPC response headers for headerKey := range w.Header() { if strings.HasPrefix(headerKey, "Grpc-") { delete(w.Header(), headerKey) } } // set http status code if vals := md.HeaderMD.Get(server.HTTPResponseCodeMetadataKey); len(vals) > 0 { code, err := strconv.Atoi(vals[0]) if err != nil { return err } // delete the headers to not expose any grpc-metadata in http response delete(md.HeaderMD, server.HTTPResponseCodeMetadataKey) w.WriteHeader(code) } return nil } fulcio-1.6.5/cmd/app/http_test.go000066400000000000000000000117021470150653400167020ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 app import ( "context" "crypto" "crypto/x509" "errors" "fmt" "net" "net/http" "net/url" "os" "path/filepath" "strings" "sync" "testing" "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/identity" "github.com/spf13/viper" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) func setupHTTPServer(t *testing.T) (httpServer, string) { t.Helper() httpListen, err := net.Listen("tcp", ":0") if err != nil { t.Error(err) } viper.Set("grpc-host", "") viper.Set("grpc-port", 0) grpcServer, err := createGRPCServer(nil, nil, &TrivialCertificateAuthority{}, nil) if err != nil { t.Error(err) } var wg sync.WaitGroup grpcServer.startTCPListener(&wg) conn, err := grpc.NewClient(grpcServer.grpcServerEndpoint, grpc.WithTransportCredentials(insecure.NewCredentials())) defer func() { if conn != nil { _ = conn.Close() } }() if err != nil { t.Error(err) } httpHost := httpListen.Addr().String() httpServer := createHTTPServer(context.Background(), httpHost, grpcServer, nil) go func() { _ = httpServer.Serve(httpListen) grpcServer.GracefulStop() }() return httpServer, fmt.Sprintf("http://%s", httpHost) } // setup with GRPC TLS enabled func setupHTTPServerWithGRPCTLS(t *testing.T) (httpServer, string) { t.Helper() httpListen, err := net.Listen("tcp", ":0") if err != nil { t.Error(err) } tlsPKIDir := t.TempDir() certPath := filepath.Join(tlsPKIDir, "cert.pem") os.WriteFile(certPath, []byte(certPEM), 0644) keyPath := filepath.Join(tlsPKIDir, "key.pem") os.WriteFile(keyPath, []byte(keyPEM), 0644) viper.Set("grpc-tls-certificate", certPath) viper.Set("grpc-tls-key", keyPath) viper.Set("grpc-host", "") viper.Set("grpc-port", 0) grpcServer, err := createGRPCServer(nil, nil, &TrivialCertificateAuthority{}, nil) if err != nil { t.Error(err) } var wg sync.WaitGroup grpcServer.startTCPListener(&wg) conn, err := grpc.NewClient(grpcServer.grpcServerEndpoint, grpc.WithTransportCredentials(insecure.NewCredentials())) defer func() { if conn != nil { _ = conn.Close() } }() if err != nil { t.Error(err) } legacyGRPCServer, err := createLegacyGRPCServer(nil, LegacyUnixDomainSocket, grpcServer.caService) if err != nil { t.Fatal(err) } legacyGRPCServer.startUnixListener() httpHost := httpListen.Addr().String() httpServer := createHTTPServer(context.Background(), httpHost, grpcServer, legacyGRPCServer) go func() { _ = httpServer.Serve(httpListen) grpcServer.GracefulStop() }() return httpServer, fmt.Sprintf("http://%s", httpHost) } func TestHTTPCORSSupport(t *testing.T) { httpServer, host := setupHTTPServer(t) defer httpServer.Close() url, _ := url.Parse(host + "/api/v2/trustBundle") req := http.Request{ Method: "GET", URL: url, Header: map[string][]string{"Origin": {"http://example.com"}}, } resp, err := http.DefaultClient.Do(&req) if err != nil || resp.StatusCode != http.StatusOK { t.Error(err) } defer resp.Body.Close() if resp.Header.Get("Access-Control-Allow-Origin") == "" { t.Errorf("missing CORS header") } } func TestHTTPDoesntLeakGRPCHeaders(t *testing.T) { httpServer, host := setupHTTPServer(t) defer httpServer.Close() resp, err := http.Get(host + "/api/v2/trustBundle") if err != nil || resp.StatusCode != http.StatusOK { t.Error(err) } defer resp.Body.Close() for headerKey := range resp.Header { if strings.HasPrefix(headerKey, "Grpc-") { t.Errorf("found leaked Grpc response header %s", headerKey) } } } func TestIssue1267(t *testing.T) { httpServer, host := setupHTTPServerWithGRPCTLS(t) defer httpServer.Close() url, _ := url.Parse(host + "/api/v1/rootCert") req := http.Request{ Method: "GET", URL: url, } resp, err := http.DefaultClient.Do(&req) if err != nil || resp.StatusCode != http.StatusOK { t.Errorf("unexpected response: %v, %v", resp, err) } defer resp.Body.Close() } // Trivial CA service that returns junk type TrivialCertificateAuthority struct { } func (tca *TrivialCertificateAuthority) CreateCertificate(context.Context, identity.Principal, crypto.PublicKey) (*ca.CodeSigningCertificate, error) { return nil, errors.New("CreateCertificate always fails for testing") } func (tca *TrivialCertificateAuthority) TrustBundle(_ context.Context) ([][]*x509.Certificate, error) { return [][]*x509.Certificate{}, nil } func (tca *TrivialCertificateAuthority) Close() error { return nil } fulcio-1.6.5/cmd/app/root.go000066400000000000000000000024541470150653400156530ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 app import ( "context" "os" "github.com/spf13/cobra" "github.com/sigstore/fulcio/pkg/log" ) // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "fulcio", Short: "Fulcio", Long: "Fulcio generates certificates that can be used to sign software artifacts", } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute(ctx context.Context) { if err := rootCmd.ExecuteContext(ctx); err != nil { log.Logger.Error(err) os.Exit(1) } } func init() { rootCmd.AddCommand(newCreateCACmd()) rootCmd.AddCommand(newServeCmd()) } fulcio-1.6.5/cmd/app/serve.go000066400000000000000000000434511470150653400160160ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 app import ( "bytes" "context" "crypto/tls" "crypto/x509" "errors" "flag" "fmt" "net" "net/http" "os" "os/signal" "path/filepath" "strings" "sync" "syscall" "time" "chainguard.dev/go-grpc-kit/pkg/duplex" "github.com/goadesign/goa/grpc/middleware" ctclient "github.com/google/certificate-transparency-go/client" "github.com/google/certificate-transparency-go/jsonclient" grpcmw "github.com/grpc-ecosystem/go-grpc-middleware" grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap" grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" certauth "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/ca/ephemeralca" "github.com/sigstore/fulcio/pkg/ca/fileca" googlecav1 "github.com/sigstore/fulcio/pkg/ca/googleca/v1" "github.com/sigstore/fulcio/pkg/ca/kmsca" "github.com/sigstore/fulcio/pkg/ca/pkcs11ca" "github.com/sigstore/fulcio/pkg/ca/tinkca" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/generated/protobuf" "github.com/sigstore/fulcio/pkg/generated/protobuf/legacy" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/log" "github.com/sigstore/fulcio/pkg/server" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/spf13/viper" "go.uber.org/zap" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/keepalive" ) const ( serveCmdEnvPrefix = "FULCIO_SERVE" defaultConfigPath string = "/etc/fulcio-config/config.yaml" ) var serveCmdConfigFilePath string func newServeCmd() *cobra.Command { cmd := &cobra.Command{ Use: "serve", Short: "start http server with configured api", Long: `Starts a http server and serves the configured api`, Run: runServeCmd, } cmd.Flags().StringVarP(&serveCmdConfigFilePath, "config", "c", "", "config file containing all settings") cmd.Flags().String("log_type", "dev", "logger type to use (dev/prod)") cmd.Flags().String("ca", "", "googleca | tinkca | pkcs11ca | fileca | kmsca | ephemeralca (for testing)") cmd.Flags().String("aws-hsm-root-ca-path", "", "Path to root CA on disk (only used with AWS HSM)") cmd.Flags().String("gcp_private_ca_parent", "", "private ca parent: projects//locations//caPools/ (only used with --ca googleca)"+ "Optionally specify /certificateAuthorities/, which will bypass CA pool load balancing.") cmd.Flags().String("hsm-caroot-id", "", "HSM ID for Root CA (only used with --ca pkcs11ca)") cmd.Flags().String("ct-log-url", "http://localhost:6962/test", "host and path (with log prefix at the end) to the ct log") cmd.Flags().String("ct-log-public-key-path", "", "Path to a PEM-encoded public key of the CT log, used to verify SCTs") cmd.Flags().String("config-path", defaultConfigPath, "path to fulcio config yaml") cmd.Flags().String("pkcs11-config-path", "config/crypto11.conf", "path to fulcio pkcs11 config file") cmd.Flags().String("fileca-cert", "", "Path to CA certificate") cmd.Flags().String("fileca-key", "", "Path to CA encrypted private key") cmd.Flags().String("fileca-key-passwd", "", "Password to decrypt CA private key") cmd.Flags().Bool("fileca-watch", true, "Watch filesystem for updates") cmd.Flags().String("kms-resource", "", "KMS key resource path. Must be prefixed with awskms://, azurekms://, gcpkms://, or hashivault://") cmd.Flags().String("kms-cert-chain-path", "", "Path to PEM-encoded CA certificate chain for KMS-backed CA") cmd.Flags().String("tink-kms-resource", "", "KMS key resource path for encrypted Tink keyset. Must be prefixed with gcp-kms:// or aws-kms://") cmd.Flags().String("tink-cert-chain-path", "", "Path to PEM-encoded CA certificate chain for Tink-backed CA") cmd.Flags().String("tink-keyset-path", "", "Path to KMS-encrypted keyset for Tink-backed CA") cmd.Flags().String("host", "0.0.0.0", "The host on which to serve requests for HTTP; --http-host is alias") cmd.Flags().String("port", "8080", "The port on which to serve requests for HTTP; --http-port is alias") cmd.Flags().String("grpc-host", "0.0.0.0", "The host on which to serve requests for GRPC") cmd.Flags().String("grpc-port", "8081", "The port on which to serve requests for GRPC") cmd.Flags().String("metrics-port", "2112", "The port on which to serve prometheus metrics endpoint") cmd.Flags().String("legacy-unix-domain-socket", LegacyUnixDomainSocket, "The Unix domain socket used for the legacy gRPC server") cmd.Flags().Duration("read-header-timeout", 10*time.Second, "The time allowed to read the headers of the requests in seconds") cmd.Flags().String("grpc-tls-certificate", "", "the certificate file to use for secure connections - only applies to grpc-port") cmd.Flags().String("grpc-tls-key", "", "the private key file to use for secure connections (without passphrase) - only applies to grpc-port") cmd.Flags().Duration("idle-connection-timeout", 30*time.Second, "The time allowed for connections (HTTP or gRPC) to go idle before being closed by the server") cmd.Flags().String("ct-log.tls-ca-cert", "", "Path to TLS CA certificate used to connect to ct-log") // convert "http-host" flag to "host" and "http-port" flag to be "port" cmd.Flags().SetNormalizeFunc(func(_ *pflag.FlagSet, name string) pflag.NormalizedName { switch name { case "http-port": name = "port" case "http-host": name = "host" } return pflag.NormalizedName(name) }) viper.RegisterAlias("http-host", "host") viper.RegisterAlias("http-port", "port") return cmd } const ( maxMsgSize int64 = 1 << 22 // 4MiB ) // Adaptor for logging with the CT log type logAdaptor struct { logger *zap.SugaredLogger } func (la logAdaptor) Printf(s string, args ...interface{}) { la.logger.Infof(s, args...) } func runServeCmd(cmd *cobra.Command, args []string) { //nolint: revive ctx := cmd.Context() // If a config file is provided, modify the viper config to locate and read it if err := checkServeCmdConfigFile(); err != nil { log.Logger.Fatal(err) } if err := viper.BindPFlags(cmd.Flags()); err != nil { log.Logger.Fatal(err) } // Allow recognition of environment variables such as FULCIO_SERVE_CA etc. viper.SetEnvPrefix(serveCmdEnvPrefix) viper.AutomaticEnv() switch viper.GetString("ca") { case "": log.Logger.Fatal("required flag \"ca\" not set") case "pkcs11ca": if !viper.IsSet("hsm-caroot-id") { log.Logger.Fatal("hsm-caroot-id must be set when using pkcs11ca") } case "googleca": if !viper.IsSet("gcp_private_ca_parent") { log.Logger.Fatal("gcp_private_ca_parent must be set when using googleca") } if viper.IsSet("gcp_private_ca_version") { // There's a MarkDeprecated function in cobra/pflags, but it doesn't use log.Logger log.Logger.Warn("gcp_private_ca_version is deprecated and will soon be removed; please remove it") } case "fileca": if !viper.IsSet("fileca-cert") { log.Logger.Fatal("fileca-cert must be set to certificate path when using fileca") } if !viper.IsSet("fileca-key") { log.Logger.Fatal("fileca-key must be set to private key path when using fileca") } if !viper.IsSet("fileca-key-passwd") { log.Logger.Fatal("fileca-key-passwd must be set to encryption password for private key file when using fileca") } case "kmsca": if !viper.IsSet("kms-resource") { log.Logger.Fatal("kms-resource must be set when using kmsca") } if !viper.IsSet("kms-cert-chain-path") { log.Logger.Fatal("kms-cert-chain-path must be set when using kmsca") } case "tinkca": if !viper.IsSet("tink-kms-resource") { log.Logger.Fatal("tink-kms-resource must be set when using tinkca") } if !viper.IsSet("tink-cert-chain-path") { log.Logger.Fatal("tink-cert-chain-path must be set when using tinkca") } if !viper.IsSet("tink-keyset-path") { log.Logger.Fatal("tink-keyset-path must be set when using tinkca") } case "ephemeralca": // this is a no-op since this is a self-signed in-memory CA for testing default: log.Logger.Fatalf("--ca=%s is not a valid selection. Try: pkcs11ca, googleca, fileca, or ephemeralca", viper.GetString("ca")) } // Setup the logger to dev/prod log.ConfigureLogger(viper.GetString("log_type")) // from https://github.com/golang/glog/commit/fca8c8854093a154ff1eb580aae10276ad6b1b5f _ = flag.CommandLine.Parse([]string{}) cp := viper.GetString("config-path") if cp == defaultConfigPath { if _, err := os.Stat(cp); os.IsNotExist(err) { log.Logger.Warnf("warn loading --config-path=%s: %v, fall back to json", cp, err) cp = strings.TrimSuffix(cp, ".yaml") + ".json" } } cfg, err := config.Load(cp) if err != nil { log.Logger.Fatalf("error loading --config-path=%s: %v", cp, err) } var baseca certauth.CertificateAuthority switch viper.GetString("ca") { case "googleca": baseca, err = googlecav1.NewCertAuthorityService(cmd.Context(), viper.GetString("gcp_private_ca_parent")) case "pkcs11ca": params := pkcs11ca.Params{ ConfigPath: viper.GetString("pkcs11-config-path"), RootID: viper.GetString("hsm-caroot-id"), } if viper.IsSet("aws-hsm-root-ca-path") { path := viper.GetString("aws-hsm-root-ca-path") params.CAPath = &path } baseca, err = pkcs11ca.NewPKCS11CA(params) case "fileca": certFile := viper.GetString("fileca-cert") keyFile := viper.GetString("fileca-key") keyPass := viper.GetString("fileca-key-passwd") watch := viper.GetBool("fileca-watch") baseca, err = fileca.NewFileCA(certFile, keyFile, keyPass, watch) case "ephemeralca": baseca, err = ephemeralca.NewEphemeralCA() case "kmsca": var data []byte data, err = os.ReadFile(filepath.Clean(viper.GetString("kms-cert-chain-path"))) if err != nil { log.Logger.Fatalf("error reading the kms certificate chain from '%s': %v", viper.GetString("kms-cert-chain-path"), err) } var certs []*x509.Certificate certs, err = cryptoutils.LoadCertificatesFromPEM(bytes.NewReader(data)) if err != nil { log.Logger.Fatalf("error loading the PEM certificates from the kms certificate chain from '%s': %v", viper.GetString("kms-cert-chain-path"), err) } baseca, err = kmsca.NewKMSCA(cmd.Context(), viper.GetString("kms-resource"), certs) case "tinkca": baseca, err = tinkca.NewTinkCA(cmd.Context(), viper.GetString("tink-kms-resource"), viper.GetString("tink-keyset-path"), viper.GetString("tink-cert-chain-path")) default: err = fmt.Errorf("invalid value for configured CA: %v", baseca) } if err != nil { log.Logger.Fatal(err) } defer baseca.Close() var ctClient *ctclient.LogClient if logURL := viper.GetString("ct-log-url"); logURL != "" { opts := jsonclient.Options{ Logger: logAdaptor{logger: log.Logger}, } // optionally add CT log public key to verify SCTs if pubKeyPath := viper.GetString("ct-log-public-key-path"); pubKeyPath != "" { pemPubKey, err := os.ReadFile(filepath.Clean(pubKeyPath)) if err != nil { log.Logger.Fatal(err) } opts.PublicKey = string(pemPubKey) } var httpClient *http.Client if tlsCaCertPath := viper.GetString("ct-log.tls-ca-cert"); tlsCaCertPath != "" { tlsCaCert, err := os.ReadFile(filepath.Clean(tlsCaCertPath)) if err != nil { log.Logger.Fatal(err) } caCertPool := x509.NewCertPool() if ok := caCertPool.AppendCertsFromPEM(tlsCaCert); !ok { log.Logger.Fatal("failed to append TLS CA certificate") } tlsConfig := &tls.Config{ RootCAs: caCertPool, MinVersion: tls.VersionTLS12, } transport := &http.Transport{ TLSClientConfig: tlsConfig, } httpClient = &http.Client{ Timeout: 30 * time.Second, Transport: transport, } } else { httpClient = &http.Client{ Timeout: 30 * time.Second, } } ctClient, err = ctclient.New(logURL, httpClient, opts) if err != nil { log.Logger.Fatal(err) } } ip := server.NewIssuerPool(cfg) portsMatch := viper.GetString("port") == viper.GetString("grpc-port") hostsMatch := viper.GetString("host") == viper.GetString("grpc-host") if portsMatch && hostsMatch { port := viper.GetInt("port") metricsPort := viper.GetInt("metrics-port") // StartDuplexServer will always return an error, log fatally if it's non-nil if err := StartDuplexServer(ctx, cfg, ctClient, baseca, viper.GetString("host"), port, metricsPort, ip); err != http.ErrServerClosed { log.Logger.Fatal(err) } return } // waiting for http and grpc servers to shutdown gracefully var wg sync.WaitGroup httpServerEndpoint := fmt.Sprintf("%v:%v", viper.GetString("http-host"), viper.GetString("http-port")) reg := prometheus.NewRegistry() grpcServer, err := createGRPCServer(cfg, ctClient, baseca, ip) if err != nil { log.Logger.Fatal(err) } grpcServer.setupPrometheus(reg) grpcServer.startTCPListener(&wg) legacyGRPCServer, err := createLegacyGRPCServer(cfg, viper.GetString("legacy-unix-domain-socket"), grpcServer.caService) if err != nil { log.Logger.Fatal(err) } legacyGRPCServer.startUnixListener() httpServer := createHTTPServer(ctx, httpServerEndpoint, grpcServer, legacyGRPCServer) httpServer.startListener(&wg) readHeaderTimeout := viper.GetDuration("read-header-timeout") prom := http.Server{ Addr: fmt.Sprintf(":%v", viper.GetString("metrics-port")), Handler: promhttp.Handler(), ReadHeaderTimeout: readHeaderTimeout, } idleConnsClosed := make(chan struct{}) go func() { sigint := make(chan os.Signal, 1) signal.Notify(sigint, syscall.SIGINT, syscall.SIGTERM) <-sigint // received an interrupt signal, shut down if err := prom.Shutdown(context.Background()); err != nil { // error from closing listeners, or context timeout log.Logger.Errorf("HTTP server Shutdown: %v", err) } close(idleConnsClosed) log.Logger.Info("stopped prom server") }() if err := prom.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Logger.Fatal(err) } <-idleConnsClosed log.Logger.Info("prom server shutdown") // wait for http and grpc servers to shutdown wg.Wait() } func checkServeCmdConfigFile() error { if serveCmdConfigFilePath != "" { if _, err := os.Stat(serveCmdConfigFilePath); err != nil { return fmt.Errorf("unable to stat config file provided: %w", err) } abspath, err := filepath.Abs(serveCmdConfigFilePath) if err != nil { return fmt.Errorf("unable to determine absolute path of config file provided: %w", err) } extWithDot := filepath.Ext(abspath) ext := strings.TrimPrefix(extWithDot, ".") var extIsValid bool for _, validExt := range viper.SupportedExts { if ext == validExt { extIsValid = true break } } if !extIsValid { return fmt.Errorf("config file must have one of the following extensions: %s", strings.Join(viper.SupportedExts, ", ")) } viper.SetConfigName(strings.TrimSuffix(filepath.Base(abspath), extWithDot)) viper.SetConfigType(ext) viper.AddConfigPath(filepath.Dir(serveCmdConfigFilePath)) if err := viper.ReadInConfig(); err != nil { return fmt.Errorf("unable to parse config file provided: %w", err) } } return nil } func StartDuplexServer(ctx context.Context, cfg *config.FulcioConfig, ctClient *ctclient.LogClient, baseca certauth.CertificateAuthority, host string, port, metricsPort int, ip identity.IssuerPool) error { logger, opts := log.SetupGRPCLogging() d := duplex.New( port, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.KeepaliveParams(keepalive.ServerParameters{ MaxConnectionIdle: viper.GetDuration("idle-connection-timeout"), }), runtime.WithMetadata(extractOIDCTokenFromAuthHeader), grpc.UnaryInterceptor(grpcmw.ChainUnaryServer( grpc_recovery.UnaryServerInterceptor(grpc_recovery.WithRecoveryHandlerContext(panicRecoveryHandler)), // recovers from per-transaction panics elegantly, so put it first middleware.UnaryRequestID(middleware.UseXRequestIDMetadataOption(true), middleware.XRequestMetadataLimitOption(128)), grpc_zap.UnaryServerInterceptor(logger, opts...), PassFulcioConfigThruContext(cfg), grpc_prometheus.UnaryServerInterceptor, )), grpc.MaxRecvMsgSize(int(maxMsgSize)), runtime.WithForwardResponseOption(setResponseCodeModifier), ) // GRPC server grpcCAServer := server.NewGRPCCAServer(ctClient, baseca, ip) protobuf.RegisterCAServer(d.Server, grpcCAServer) if err := d.RegisterHandler(ctx, protobuf.RegisterCAHandlerFromEndpoint); err != nil { return fmt.Errorf("registering grpc ca handler: %w", err) } // Legacy server legacyGRPCCAServer := server.NewLegacyGRPCCAServer(grpcCAServer) legacy.RegisterCAServer(d.Server, legacyGRPCCAServer) if err := d.RegisterHandler(ctx, legacy.RegisterCAHandlerFromEndpoint); err != nil { return fmt.Errorf("registering legacy grpc ca handler: %w", err) } // Prometheus reg := prometheus.NewRegistry() grpcMetrics := grpc_prometheus.DefaultServerMetrics grpcMetrics.EnableHandlingTimeHistogram() reg.MustRegister(grpcMetrics, server.MetricLatency, server.RequestsCount) grpc_prometheus.Register(d.Server) // Register prometheus handle. d.RegisterListenAndServeMetrics(metricsPort, false) lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", host, port)) if err != nil { return fmt.Errorf("creating listener: %w", err) } logger.Info("Starting duplex server...") if err := d.Serve(ctx, lis); err != nil { return fmt.Errorf("duplex server: %w", err) } return nil } fulcio-1.6.5/cmd/app/serve_test.go000066400000000000000000000063731470150653400170570ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 app import ( "context" "fmt" "io" "log" "net/http" "net/url" "strings" "testing" "time" "github.com/google/go-cmp/cmp" "github.com/sigstore/fulcio/pkg/api" "github.com/sigstore/fulcio/pkg/ca/ephemeralca" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/generated/protobuf" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) func TestDuplex(t *testing.T) { // Start a server with duplex on port 8089 ctx := context.Background() ca, err := ephemeralca.NewEphemeralCA() if err != nil { t.Fatal(err) } port := 8089 serverURL, err := url.Parse(fmt.Sprintf("http://localhost:%d", port)) if err != nil { t.Fatal(err) } metricsPort := 2114 go func() { if err := StartDuplexServer(ctx, config.DefaultConfig, nil, ca, "localhost", port, metricsPort, nil); err != nil { log.Fatalf("error starting duplex server: %v", err) } }() // wait for duplex server to start up time.Sleep(time.Second * 5) var rootCert string t.Run("http", func(t *testing.T) { // Make sure we can grab the rootcert with the v1 endpoint legacyClient := api.NewClient(serverURL) resp, err := legacyClient.RootCert() if err != nil { t.Fatal(err) } rootCert = string(resp.ChainPEM) }) var grpcRootCert string t.Run("grpc", func(t *testing.T) { // Grab the rootcert with the v2 endpoint conn, err := grpc.NewClient(fmt.Sprintf("localhost:%d", port), grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { t.Fatal(err) } grpcClient := protobuf.NewCAClient(conn) tb, err := grpcClient.GetTrustBundle(ctx, &protobuf.GetTrustBundleRequest{}) if err != nil { t.Fatalf("error getting trust bundle: %v", err) } if len(tb.Chains) != 1 { t.Fatalf("didn't get expected length certificate chain: %v", tb.Chains) } if len(tb.Chains[0].Certificates) != 1 { t.Fatalf("didn't get expected length certs: %v", tb.Chains) } grpcRootCert = strings.TrimSuffix(tb.Chains[0].Certificates[0], "\n") }) t.Run("compare root certs", func(t *testing.T) { if d := cmp.Diff(rootCert, grpcRootCert); d != "" { t.Fatal(d) } }) t.Run("prometheus", func(t *testing.T) { // make sure there are metrics on the metrics port url := fmt.Sprintf("http://localhost:%d/metrics", metricsPort) resp, err := http.Get(url) if err != nil { t.Fatal(err) } contents, err := io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } // make sure there's something about hitting the GetTrustBundle in there // this just confirms some metrics are being printed if !strings.Contains(string(contents), "GetTrustBundle") { t.Fatalf("didn't get expected metrics output: %s", string(contents)) } }) } fulcio-1.6.5/cmd/app/version.go000066400000000000000000000013171470150653400163520ustar00rootroot00000000000000// // Copyright 2021 The Sigstore 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 app import ( "sigs.k8s.io/release-utils/version" ) func init() { rootCmd.AddCommand(version.Version()) } fulcio-1.6.5/cmd/create_tink_keyset/000077500000000000000000000000001470150653400174305ustar00rootroot00000000000000fulcio-1.6.5/cmd/create_tink_keyset/create_tink_keyset.go000066400000000000000000000041361470150653400236370ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 main import ( "context" "flag" "fmt" "log" "os" "github.com/sigstore/fulcio/pkg/ca/tinkca" "github.com/tink-crypto/tink-go/v2/keyset" "github.com/tink-crypto/tink-go/v2/signature" ) /* To run: go run cmd/create_tink_keyset/create_tink_keyset.go \ --kms-resource="gcp-kms://projects//locations//keyRings//cryptoKeys/" \ --output="enc-keyset.cfg" You can also create a GCP KMS encrypted Tink keyset with tinkey: tinkey create-keyset --key-template ECDSA_P384 --out enc-keyset.cfg --master-key-uri gcp-kms://projects//locations//keyRings//cryptoKeys/ You must have the permissions to read the KMS key, and create a certificate in the CA pool. */ var ( kmsKey = flag.String("kms-resource", "", "Resource path to KMS key, starting with gcp-kms:// or aws-kms://") outputPath = flag.String("output", "", "Path to the output file") ) func main() { flag.Parse() if *kmsKey == "" { log.Fatal("kms-resource must be set") } if *outputPath == "" { log.Fatal("output must be set") } kh, err := keyset.NewHandle(signature.ECDSAP384KeyWithoutPrefixTemplate()) if err != nil { log.Fatal(err) } primaryKey, err := tinkca.GetPrimaryKey(context.Background(), *kmsKey) if err != nil { log.Fatal(err) } f, err := os.Create(*outputPath) if err != nil { log.Fatal(err) } defer f.Close() jsonWriter := keyset.NewJSONWriter(f) if err := kh.Write(jsonWriter, primaryKey); err != nil { fmt.Printf("error writing primary key: %v\n", err) } } fulcio-1.6.5/cmd/fetch_ca_cert/000077500000000000000000000000001470150653400163255ustar00rootroot00000000000000fulcio-1.6.5/cmd/fetch_ca_cert/fetch_ca_cert.go000066400000000000000000000143531470150653400214330ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 main import ( "context" "crypto" "crypto/x509" "errors" "flag" "log" "os" "path/filepath" "time" privateca "cloud.google.com/go/security/privateca/apiv1" "cloud.google.com/go/security/privateca/apiv1/privatecapb" "github.com/sigstore/fulcio/pkg/ca/tinkca" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/tink-crypto/tink-go/v2/keyset" "google.golang.org/protobuf/types/known/durationpb" // Register the provider-specific plugins "github.com/sigstore/sigstore/pkg/signature/kms" _ "github.com/sigstore/sigstore/pkg/signature/kms/aws" _ "github.com/sigstore/sigstore/pkg/signature/kms/azure" _ "github.com/sigstore/sigstore/pkg/signature/kms/gcp" _ "github.com/sigstore/sigstore/pkg/signature/kms/hashivault" ) /* To run: go run cmd/fetch_ca_cert/fetch_ca_cert.go \ --kms-resource="gcpkms://projects//locations//keyRings//cryptoKeys//versions/1" \ --gcp-ca-parent="projects//locations//caPools/" \ --output="chain.crt.pem" go run cmd/fetch_ca_cert/fetch_ca_cert.go \ --tink-kms-resource="gcp-kms://projects//locations//keyRings//cryptoKeys/" \ --tink-keyset-path="enc-keyset.cfg" \ --gcp-ca-parent="projects//locations//caPools/" \ --output="chain.crt.pem" You must have the permissions to read the KMS key, and create a certificate in the CA pool. */ var ( gcpCaParent = flag.String("gcp-ca-parent", "", "Resource path to GCP CA Service CA") kmsKey = flag.String("kms-resource", "", "Resource path to KMS key, starting with gcpkms://, awskms://, azurekms:// or hashivault://") tinkKeysetPath = flag.String("tink-keyset-path", "", "Path to Tink keyset") tinkKmsKey = flag.String("tink-kms-resource", "", "Resource path to KMS key to decrypt Tink keyset, starting with gcp-kms:// or aws-kms://") outputPath = flag.String("output", "", "Path to the output file") ) func fetchCACertificate(ctx context.Context, parent, kmsKey, tinkKeysetPath, tinkKmsKey string, client *privateca.CertificateAuthorityClient) ([]*x509.Certificate, error) { var signer crypto.Signer if len(kmsKey) > 0 { kmsSigner, err := kms.Get(ctx, kmsKey, crypto.SHA256) if err != nil { return nil, err } signer, _, err = kmsSigner.CryptoSigner(ctx, func(_ error) {}) if err != nil { return nil, err } } else { primaryKey, err := tinkca.GetPrimaryKey(ctx, tinkKmsKey) if err != nil { return nil, err } f, err := os.Open(filepath.Clean(tinkKeysetPath)) if err != nil { return nil, err } defer f.Close() kh, err := keyset.Read(keyset.NewJSONReader(f), primaryKey) if err != nil { return nil, err } signer, err = tinkca.KeyHandleToSigner(kh) if err != nil { return nil, err } } pemPubKey, err := cryptoutils.MarshalPublicKeyToPEM(signer.Public()) if err != nil { return nil, err } isCa := true // default value of 0 for int32 var maxIssuerPathLength int32 csr := &privatecapb.CreateCertificateRequest{ Parent: parent, Certificate: &privatecapb.Certificate{ // Default to a very large lifetime - CA Service will truncate the // lifetime to be no longer than the root's lifetime. // 20 years (24 hours * 365 days * 20) Lifetime: durationpb.New(time.Hour * 24 * 365 * 20), CertificateConfig: &privatecapb.Certificate_Config{ Config: &privatecapb.CertificateConfig{ PublicKey: &privatecapb.PublicKey{ Format: privatecapb.PublicKey_PEM, Key: pemPubKey, }, X509Config: &privatecapb.X509Parameters{ KeyUsage: &privatecapb.KeyUsage{ BaseKeyUsage: &privatecapb.KeyUsage_KeyUsageOptions{ CertSign: true, CrlSign: true, }, ExtendedKeyUsage: &privatecapb.KeyUsage_ExtendedKeyUsageOptions{ CodeSigning: true, }, }, CaOptions: &privatecapb.X509Parameters_CaOptions{ IsCa: &isCa, MaxIssuerPathLength: &maxIssuerPathLength, }, }, SubjectConfig: &privatecapb.CertificateConfig_SubjectConfig{ Subject: &privatecapb.Subject{ CommonName: "sigstore-intermediate", Organization: "sigstore.dev", }, }, }, }, }, } resp, err := client.CreateCertificate(ctx, csr) if err != nil { return nil, err } var pemCerts []string pemCerts = append(pemCerts, resp.PemCertificate) pemCerts = append(pemCerts, resp.PemCertificateChain...) var parsedCerts []*x509.Certificate for _, c := range pemCerts { certs, err := cryptoutils.UnmarshalCertificatesFromPEM([]byte(c)) if err != nil { return nil, err } if len(certs) != 1 { return nil, errors.New("unexpected number of certificates returned") } parsedCerts = append(parsedCerts, certs[0]) } return parsedCerts, nil } func main() { flag.Parse() if *gcpCaParent == "" { log.Fatal("gcp-ca-parent must be set") } if *kmsKey == "" && *tinkKeysetPath == "" { log.Fatal("either kms-resource or tink-keyset-path must be set") } if *tinkKeysetPath != "" && *tinkKmsKey == "" { log.Fatal("tink-keyset-path must be set with tink-kms-resource must be set") } if *outputPath == "" { log.Fatal("output must be set") } client, err := privateca.NewCertificateAuthorityClient(context.Background()) if err != nil { client.Close() log.Fatal(err) } parsedCerts, err := fetchCACertificate(context.Background(), *gcpCaParent, *kmsKey, *tinkKeysetPath, *tinkKmsKey, client) if err != nil { client.Close() log.Fatal(err) } pemCerts, err := cryptoutils.MarshalCertificatesToPEM(parsedCerts) if err != nil { client.Close() log.Fatal(err) } err = os.WriteFile(*outputPath, pemCerts, 0600) if err != nil { client.Close() log.Fatal(err) } defer client.Close() } fulcio-1.6.5/codecov.yml000066400000000000000000000011761470150653400151630ustar00rootroot00000000000000# Copyright 2023 The Sigstore 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. coverage: status: project: off patch: off fulcio-1.6.5/config/000077500000000000000000000000001470150653400142565ustar00rootroot00000000000000fulcio-1.6.5/config/aws-cloudhsm.md000066400000000000000000000077301470150653400172150ustar00rootroot00000000000000# Running Fulcio on AWS CloudHSM Fulcio includes support for AWS CloudHSM as a backend for a self-provisioned root CA. This document outlines how it works and how to set it up. ## Background AWS CloudHSM provides a [PKCS#11 compliant library](https://docs.aws.amazon.com/cloudhsm/latest/userguide/pkcs11-library.html) for interacting with instances of its CloudHSM product. For the most part, this serves as a drop-in replacement for the [`SoftHSM`](https://github.com/sigstore/fulcio/blob/main/config/crypto11.conf#L2) PKCS#11 library that Fulcio was built upon; as long as keys are set up beforehand, just as Fulcio expects to be done when using SoftHSM, it (mostly) works with no code changes. The exception is that CloudHSM [does not support certificate storage](https://docs.aws.amazon.com/cloudhsm/latest/userguide/keystore-third-party-tools.html) on their HSMs: > AWS CloudHSM does not store certificates on the HSM, as certificates are public, non-confidential data. In its current state, Fulcio does attempt to store the root CA it creates as part of the `createca` command within the HSM it's using, and this causes an error when running with AWS CloudHSM. Many possible workarounds (and just as many dead ends) for this limitation were explored during development. While those might change in the future, for now, Fulcio includes a simple workaround that allows it to work with CloudHSM: effectively, during root CA creation when running on AWS, instead of attempting to store the root CA in the HSM or in some other certificate storage service, it's just stored on-disk as a PEM file. Then, later on, when running `fulcio serve`, another option is exposed to load the root CA from disk instead of the HSM. This works around the lack of certificate support on AWS' HSMs. ## Setup Guide AWS provides a rather comprehensive [setup guide](https://docs.aws.amazon.com/cloudhsm/latest/userguide/getting-started.html) for getting a CloudHSM instance deployed and setting up an EC2 instance that can interact with it. For a complete setup, you'll want to make sure the CloudHSM Management Utility, Key Management Utility, and CloudHSM's PKCS#11 library are all installed on your EC2 instance. ### Provisioning an HSM and creating a keypair First, you'll need to make sure your HSM is set up using the Management Utility using [this guide](https://docs.aws.amazon.com/cloudhsm/latest/userguide/cloudhsm_mgmt_util-getting-started.html). Next, you should provision keys within the HSM for Fulcio to use. Do this with the Key Management Utility: - Log in: `loginHSM -u CU -s -p ` - Generate a keypair with appropriate label and ID: `genECCKeyPair -i 14 -l PKCS11CA -id 1` With these steps done, your HSM is set up! ### Setting up Fulcio Next: clone Fulcio with this patch included onto the EC2 instance that has the AWS PKCS11 library installed. You'll also need to adjust [`config/crypto11.conf`](config/crypto11.conf) as such, in order to make it work with the CloudHSM setup: ``` { "Path" : "/opt/cloudhsm/lib/libcloudhsm_pkcs11.so", "TokenLabel": "cavium", "Pin" : ":" } ``` The `Path` variable replaces the `softhsm` PKCS11 library with AWS CloudHSM's. On AWS CloudHSM, the `TokenLabel` must always be `cavium` - or things won't work. The `Pin` takes the format of a crypto user and corresponding password on the HSM, as seen [here](https://docs.aws.amazon.com/cloudhsm/latest/userguide/pkcs11-pin.html). With this done, you're ready to use Fulcio! ### Usage Here are some example commands: ``` fulcio createca --org=acme --country=US --locality=SomeTown --province=SomeProvince --postal-code=XXXX --street-address=XXXX --hsm-caroot-id 1 --out myrootCA.pem --hsm=aws` ``` This command creates a new root CA using the private key stored in AWS CloudHSM and stores it in the `myrootCA.pem` file locally. ``` fulcio serve --ca pkcs11ca --hsm-caroot-id 99 --aws-hsm-root-ca-path myrootCA.pem ``` And this command uses the generated `myrootCA.pem` file to run the Fulcio server. fulcio-1.6.5/config/crypto11.conf000066400000000000000000000001431470150653400166050ustar00rootroot00000000000000{ "Path" : "/usr/lib/softhsm/libsofthsm2.so", "TokenLabel": "fulcio", "Pin" : "2324" } fulcio-1.6.5/config/ctfe/000077500000000000000000000000001470150653400151775ustar00rootroot00000000000000fulcio-1.6.5/config/ctfe/ct_server.cfg000066400000000000000000000003631470150653400176560ustar00rootroot00000000000000config { log_id: %LOGID% prefix: "test" roots_pem_file: "/etc/config/root.pem" private_key: { [type.googleapis.com/keyspb.PEMKeyFile] { path: "/etc/config/privkey.pem" password: "foobar" } } ext_key_usages: [ "CodeSigning" ] } fulcio-1.6.5/config/ctfe/privkey.pem000066400000000000000000000004461470150653400173770ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-CBC,05BAAA9143C46320 AttbquLclNy7ZEnlDFpReZvV2PZKuv89YMWqDvGGtnBVw+3eXYIa54Xli1CyXEPn qNGvibjIxj+Q19+VhA3n42SE2fHyULHKPZHebSL5qcVvZTqmbtAe/dZNH1SiGG2f bWauIw0oeHhXW5i9isxrLggPMRmPA65Ii3W7gyWFmjE= -----END EC PRIVATE KEY----- fulcio-1.6.5/config/ctfe/pubkey.pem000066400000000000000000000002621470150653400172010ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbbQiLx6GKy6ivhc11wJGbQjc2VX/ mnuk5d670MTXR3p+LIAcxd5MhqIHpLmyYJ5mDKLEoZ/pC0nPuje3JueBcA== -----END PUBLIC KEY----- fulcio-1.6.5/config/deployment.yaml000066400000000000000000000057601470150653400173320ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. apiVersion: v1 kind: Namespace metadata: name: fulcio-system labels: name: fulcio-system --- apiVersion: apps/v1 kind: Deployment metadata: namespace: fulcio-system name: fulcio-server labels: app: fulcio-server spec: replicas: 3 selector: matchLabels: app: fulcio-server template: metadata: labels: app: fulcio-server annotations: prometheus.io/scrape: "true" prometheus.io/path: /metrics prometheus.io/port: "2112" spec: containers: - name: fulcio-server image: ko://github.com/sigstore/fulcio ports: - containerPort: 5555 - containerPort: 5554 - containerPort: 2112 # metrics args: [ "serve", "-c", "/etc/fulcio-config/server.yaml", ] env: - name: FULCIO_SERVE_GCP_PRIVATE_CA_PARENT valueFrom: configMapKeyRef: name: private-ca key: connection_v1 volumeMounts: - name: fulcio-config mountPath: /etc/fulcio-config - name: fulcio-secret mountPath: /etc/fulcio-secret readOnly: true - name: oidc-info mountPath: /var/run/fulcio livenessProbe: httpGet: path: /healthz port: 5555 initialDelaySeconds: 5 readinessProbe: grpc: port: 5554 initialDelaySeconds: 5 resources: requests: memory: "1G" cpu: ".5" securityContext: readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 65533 capabilities: drop: - all volumes: - name: fulcio-config configMap: name: fulcio-config - name: fulcio-secret secret: secretName: fulcio-secret optional: true - name: oidc-info projected: sources: - configMap: name: kube-root-ca.crt items: - key: ca.crt path: ca.crt mode: 0666 --- apiVersion: v1 kind: Service metadata: namespace: fulcio-system name: fulcio-server spec: selector: app: fulcio-server type: LoadBalancer ports: - name: http protocol: TCP port: 80 targetPort: 5555 - name: grpc protocol: TCP port: 5554 targetPort: 5554 fulcio-1.6.5/config/dex/000077500000000000000000000000001470150653400150365ustar00rootroot00000000000000fulcio-1.6.5/config/dex/docker-compose-config.yaml000066400000000000000000000021721470150653400221010ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. issuer: http://dex-idp:8888/auth storage: type: memory web: http: 0.0.0.0:8888 frontend: issuer: Fulcio in Docker Compose expiry: signingKeys: "24h" idTokens: "1m" authRequests: "24h" oauth2: responseTypes: [ "code" ] alwaysShowLoginScreen: true skipApprovalScreen: true connectors: - type: mockCallback id: https://any.valid.url/ name: AlwaysApprovesOIDCProvider staticClients: - id: fulcio public: true name: 'Fulcio in Docker Compose' # Dex's issuer URL + "/callback" redirectURI: http://dex-idp:8888/auth/callback fulcio-1.6.5/config/identity/000077500000000000000000000000001470150653400161075ustar00rootroot00000000000000fulcio-1.6.5/config/identity/config.yaml000066400000000000000000000240571470150653400202500ustar00rootroot00000000000000# Copyright 2024 The Sigstore 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. define: - &github-type "github-workflow" - &gitlab-type "gitlab-pipeline" - &codefresh-type "codefresh-workflow" - &buildkite-type "buildkite-job" oidc-issuers: https://accounts.google.com: issuer-url: https://accounts.google.com client-id: sigstore type: email contact: tac@sigstore.dev description: "Google OIDC auth" https://agent.buildkite.com: issuer-url: https://agent.buildkite.com client-id: sigstore type: ci-provider ci-provider: *buildkite-type contact: support@buildkite.com description: "Buildkite Agent OIDC tokens for job identity" https://auth.eclipse.org/auth/realms/sigstore: issuer-url: https://auth.eclipse.org/auth/realms/sigstore client-id: sigstore type: email contact: security@eclipse-foundation.org description: "Eclipse Foundation Production OIDC provider" https://dev.gitlab.org: issuer-url: https://dev.gitlab.org client-id: sigstore type: ci-provider ci-provider: *gitlab-type contact: distribution-be@gitlab.com description: "GitLab OIDC tokens for job identity" https://gitlab.archlinux.org: issuer-url: https://gitlab.archlinux.org client-id: sigstore type: ci-provider ci-provider: *gitlab-type contact: sigstore@archlinux.org description: "GitLab OIDC tokens for job identity" https://gitlab.com: issuer-url: https://gitlab.com client-id: sigstore type: ci-provider ci-provider: *gitlab-type contact: support@gitlab.com description: "GitLab OIDC tokens for job identity" https://issuer.enforce.dev: issuer-url: https://issuer.enforce.dev client-id: sigstore type: chainguard-identity contact: mattmoor@chainguard.dev description: "Chainguard identity tokens" https://issuer.hello.coop: issuer-url: https://issuer.hello.coop client-id: sigstore type: email contact: contact@hello.coop description: "Hellō OIDC auth" https://oauth2.sigstore.dev/auth: issuer-url: https://oauth2.sigstore.dev/auth client-id: sigstore type: email issuer-claim: $.federated_claims.connector_id contact: tac@sigstore.dev description: "dex address for fulcio" https://oidc.codefresh.io: issuer-url: https://oidc.codefresh.io client-id: sigstore type: ci-provider ci-provider: *codefresh-type contact: support@codefresh.io description: "Codefresh OIDC tokens for job identity" https://ops.gitlab.net: issuer-url: https://ops.gitlab.net client-id: sigstore type: ci-provider ci-provider: *gitlab-type contact: distribution-be@gitlab.com description: "GitLab OIDC tokens for job identity" https://token.actions.githubusercontent.com: issuer-url: https://token.actions.githubusercontent.com client-id: sigstore type: ci-provider ci-provider: *github-type contact: tac@sigstore.dev description: "GitHub Actions OIDC auth" meta-issuers: https://*.oic.prod-aks.azure.com/*: client-id: sigstore type: kubernetes https://container.googleapis.com/v1/projects/*/locations/*/clusters/*: client-id: sigstore type: kubernetes https://oidc.eks.*.amazonaws.com/id/*: client-id: sigstore type: kubernetes https://oidc.prod-aks.azure.com/*: client-id: sigstore type: kubernetes https://token.actions.githubusercontent.com/*: client-id: sigstore type: ci-provider ci-provider: *github-type ci-issuer-metadata: *github-type: default-template-values: # url: URL of issuer, https://github.com url: "https://github.com" extension-templates: # event_name: Event that triggered this workflow run. E.g "push", "tag" github-workflow-trigger: "event_name" # sha: Commit SHA being built github-workflow-sha: "sha" # workflow (Deprecated): Name of workflow that is running (mutable) github-workflow-name: "workflow" # repository: Name of repository being built github-workflow-repository: "repository" # ref: Git ref being built github-workflow-ref: "ref" # job_workflow_ref: Specific build instructions (i.e. reusable workflow) build-signer-uri: "{{ .url }}/{{ .job_workflow_ref }}" # job_workflow_sha: Commit SHA to specific build instructions build-signer-digest: "job_workflow_sha" # runner_environment: Whether the build took place in cloud or self-hosted infrastructure runner-environment: "runner_environment" # repository: Name of repository being built source-repository-uri: "{{ .url }}/{{ .repository }}" source-repository-digest: "sha" source-repository-ref: "ref" # repository_id: ID to the source repo source-repository-identifier: "repository_id" # repository_owner: Owner of the source repo (mutable) source-repository-owner-uri: "{{ .url }}/{{ .repository_owner }}" # repository_owner_id: ID of the source repo source-repository-owner-identifier: "repository_owner_id" # workflow_ref: Ref of top-level workflow that is running build-config-uri: "{{ .url }}/{{ .workflow_ref }}" # workflow_sha: Commit SHA of top-level workflow that is running build-config-digest: "workflow_sha" build-trigger: "event_name" # run_id: ID of workflow run # run_attempt: Attempt number of workflow run run-invocation-uri: "{{ .url }}/{{ .repository }}/actions/runs/{{ .run_id }}/attempts/{{ .run_attempt }}" # repository_visibility: Visibility of the source repo source-repository-visibility-at-signing: "repository_visibility" subject-alternative-name-template: "{{ .url }}/{{ .job_workflow_ref }}" *gitlab-type: default-template-values: url: "https://gitlab.com" extension-templates: # url: The URL of the GitLab instance. https://gitlab.com # ci_config_ref_uri: Ref of top-level pipeline definition. # E.g. gitlab.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main build-signer-uri: "https://{{ .ci_config_ref_uri }}" # ci_config_sha: Commit sha of top-level pipeline definition, and is # only populated when `ciConfigRefURI` is local to the GitLab instance build-signer-digest: "ci_config_sha" # runner_environment: The type of runner used by the job. May be one of gitlab-hosted or self-hosted. runner-environment: "runner_environment" # project_path: Repository path building built source-repository-uri: "{{ .url }}/{{ .project_path }}" # sha: Commit SHA being built source-repository-digest: "sha" # ref_type: The type of the ref # E.g. "branch", "tag" # ref: Git ref being built source-repository-ref: refs/{{if eq .ref_type "branch"}}heads/{{ else }}tags/{{end}}{{ .ref }} # project_id: ID to the source repo source-repository-identifier: "project_id" # namespace_path: Owner of the source repo (mutable) source-repository-owner-uri: "{{ .url }}/{{ .namespace_path }}" # namespace_id: ID of the source repo source-repository-owner-identifier: "namespace_id" build-config-uri: "https://{{ .ci_config_ref_uri }}" build-config-digest: "ci_config_sha" # pipeline_source: Event that triggered this workflow run. E.g "push", "tag" etc build-trigger: "pipeline_source" # project_path: Repository building built # job_id: job ID run-invocation-uri: "{{ .url }}/{{ .project_path }}/-/jobs/{{ .job_id }}" # project_visibility: Visibility of the source project source-repository-visibility-at-signing: "project_visibility" subject-alternative-name-template: "https://{{ .ci_config_ref_uri }}" *codefresh-type: default-template-values: # We are setting the default value for "platform_url" as the ci-provider # principal gives priority to the claimed value over the default # when they have the same name. Then it will use the default "platform_url" value # for cases that the claimed data doesn't exist. # platform_url: Codefresh platform url platform_url: "https://g.codefresh.io" scm_repo_url: "" scm_ref: "" runner_environment: "" extension-templates: # workflow_id: The ID of the specific workflow authorized in the claim. # For example, 64f447c02199f903000gh20. build-signer-uri: "{{.platform_url}}/build/{{ .workflow_id }}" # runner_environment: Whether the build took place in cloud or self-hosted infrastructure runner-environment: "runner_environment" # scm_repo_url: Applies to Git push, PR, and manual Git trigger types. # The SCM URL specifying the Git repository’s location. # For example, https://github.com/codefresh-user/oidc-test source-repository-uri: "scm_repo_url" # scm_ref: Applies to Git push, PR, and manual Git trigger types. # The SCM name of the branch or tag within the Git repository # for which the workflow should execute. For example, main or v1.0.0. source-repository-ref: "scm_ref" # pipeline_id: Codefresh Pipeline id build-config-uri: "{{.platform_url}}/api/pipelines/{{ .pipeline_id }}" # account_name: Codefresh account name # pipeline_name: Codefresh pipline name (project/pipeline) # account_id: Codefresh account id run-invocation-uri: "{{.platform_url}}/build/{{ .workflow_id }}" subject-alternative-name-template: "{{.platform_url}}/{{.account_name}}/{{.pipeline_name}}:{{.account_id}}/{{.pipeline_id}}" *buildkite-type: default-template-values: url: "https://buildkite.com" subject-alternative-name-template: "{{.url}}/{{.organization_slug}}/{{.pipeline_slug}}" fulcio-1.6.5/config/logid.sh000066400000000000000000000040351470150653400157120ustar00rootroot00000000000000#!/bin/bash # # Copyright 2021 The Sigstore 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. function get_log_id() { curl -s --retry-connrefused --retry 10 http://trillian-log-server:8095/metrics |grep "^quota_acquired_tokens{spec=\"trees"|head -1|awk ' { print $1 } '|sed -e 's/[^0-9]*//g' > /tmp/logid } function create_log () { /go/bin/createtree -admin_server trillian-log-server:8096 > /tmp/logid echo -n "Created log ID " && cat /tmp/logid } function update_config() { cat /root/ctfe/ct_server.cfg | sed -e "s/%LOGID%/"`cat /tmp/logid`"/g" > /etc/config/ct_server.cfg cp /root/ctfe/*.pem /etc/config/ } # check to see if log id exists; if so, use that echo -n "Checking for existing configuration..." if ! [[ -s /etc/config/ct_server.cfg ]]; then echo " none found." echo "Checking for preexisting logs..." get_log_id # else create one if ! [[ -s /tmp/logid ]]; then echo "No log found; let's create one..." create_log # update config file accordingly update_config else echo "Log ID known but config not found" update_config fi else echo " found." configid=`cat /etc/config/ct_server.cfg|grep log_id|awk ' { print $2 } '` echo "Existing configuration uses log ID $configid" fi curl -s --retry-connrefused --retry 10 http://fulcio-server:5555/api/v1/rootCert -o tmpchain.pem csplit -s -f tmpcert- tmpchain.pem '/-----BEGIN CERTIFICATE-----/' '{*}' mv $(ls tmpcert-* | tail -1) /etc/config/root.pem rm tmpcert-* tmpchain.pem cat /etc/config/root.pem echo "Fetched valid root certificate from Fulcio to limit entries in CTFE instance" fulcio-1.6.5/config/softhsm2.cfg000066400000000000000000000001171470150653400165030ustar00rootroot00000000000000directories.tokendir = /tmp/tokens objectstore.backend = file log.level = INFO fulcio-1.6.5/config/test/000077500000000000000000000000001470150653400152355ustar00rootroot00000000000000fulcio-1.6.5/config/test/private-ca-secret-ci.yaml000066400000000000000000000057501470150653400220370ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. # used for CI only this Certificate is mention https://github.com/sigstore/fulcio/blob/main/config/DEVELOPMENT.md#testing-with-the-client apiVersion: v1 kind: ConfigMap metadata: name: private-ca namespace: fulcio-system data: connection: | -----BEGIN CERTIFICATE----- MIICyjCCAlCgAwIBAgITEfJ495apY+Xh6mwKJSeVKElaSjAKBggqhkjOPQQDAzAq MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx MDMwNzE0NDU1N1oXDTIxMDMwNzE1MDU1MFowOjEbMBkGA1UECgwSbG9yZW5jLmRA Z21haWwuY29tMRswGQYDVQQDDBJsb3JlbmMuZEBnbWFpbC5jb20wdjAQBgcqhkjO PQIBBgUrgQQAIgNiAARGGPRUeASYE7ilcb59Lplt1HS21EktIc3WyUc3rVd17BZ+ OzVKUKlATQ8FZQ1Bcs5KFEQY+gDbSH/jmyA6LqNN1heIBh6vw9AoLQj/uMaocIAs MkR2gWntT9zf2g8ysGWjggEmMIIBIjAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAww CgYIKwYBBQUHAwMwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUH4c4aC1y99X3F+Oa yiwx13lnwjgwHwYDVR0jBBgwFoAUyMUdAEGaJCkyUSTrDa5K7UoG0+wwgY0GCCsG AQUFBwEBBIGAMH4wfAYIKwYBBQUHMAKGcGh0dHA6Ly9wcml2YXRlY2EtY29udGVu dC02MDNmZTdlNy0wMDAwLTIyMjctYmY3NS1mNGY1ZTgwZDI5NTQuc3RvcmFnZS5n b29nbGVhcGlzLmNvbS9jYTM2YTFlOTYyNDJiOWZjYjE0Ni9jYS5jcnQwHQYDVR0R BBYwFIESbG9yZW5jLmRAZ21haWwuY29tMAoGCCqGSM49BAMDA2gAMGUCMQCsr95C BNieKlQUj41RB9p4IB2c+8XbMK69jXm6IHZRca65nOP4nMwFUqlE1W/OnlACMAht LTUlNndCw2IbG027fRqpElrc/IoIDBUa6aW7E1IL6gcnRk3MK38lkAg/jYaucw== -----END CERTIFICATE----- connection_v1: | -----BEGIN CERTIFICATE----- MIICyjCCAlCgAwIBAgITEfJ495apY+Xh6mwKJSeVKElaSjAKBggqhkjOPQQDAzAq MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx MDMwNzE0NDU1N1oXDTIxMDMwNzE1MDU1MFowOjEbMBkGA1UECgwSbG9yZW5jLmRA Z21haWwuY29tMRswGQYDVQQDDBJsb3JlbmMuZEBnbWFpbC5jb20wdjAQBgcqhkjO PQIBBgUrgQQAIgNiAARGGPRUeASYE7ilcb59Lplt1HS21EktIc3WyUc3rVd17BZ+ OzVKUKlATQ8FZQ1Bcs5KFEQY+gDbSH/jmyA6LqNN1heIBh6vw9AoLQj/uMaocIAs MkR2gWntT9zf2g8ysGWjggEmMIIBIjAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAww CgYIKwYBBQUHAwMwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUH4c4aC1y99X3F+Oa yiwx13lnwjgwHwYDVR0jBBgwFoAUyMUdAEGaJCkyUSTrDa5K7UoG0+wwgY0GCCsG AQUFBwEBBIGAMH4wfAYIKwYBBQUHMAKGcGh0dHA6Ly9wcml2YXRlY2EtY29udGVu dC02MDNmZTdlNy0wMDAwLTIyMjctYmY3NS1mNGY1ZTgwZDI5NTQuc3RvcmFnZS5n b29nbGVhcGlzLmNvbS9jYTM2YTFlOTYyNDJiOWZjYjE0Ni9jYS5jcnQwHQYDVR0R BBYwFIESbG9yZW5jLmRAZ21haWwuY29tMAoGCCqGSM49BAMDA2gAMGUCMQCsr95C BNieKlQUj41RB9p4IB2c+8XbMK69jXm6IHZRca65nOP4nMwFUqlE1W/OnlACMAht LTUlNndCw2IbG027fRqpElrc/IoIDBUa6aW7E1IL6gcnRk3MK38lkAg/jYaucw== -----END CERTIFICATE----- fulcio-1.6.5/config/tls/000077500000000000000000000000001470150653400150605ustar00rootroot00000000000000fulcio-1.6.5/config/tls/ca.crt000066400000000000000000000034051470150653400161570ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFAzCCAuugAwIBAgIUTk3GiBCpBRhm3reO3ME5fUF9ShEwDQYJKoZIhvcNAQEL BQAwEDEOMAwGA1UEAwwFTXkgQ0EwIBcNMjQxMDAzMTIwNjEyWhgPMjEyNDA5MDkx MjA2MTJaMBAxDjAMBgNVBAMMBU15IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAv3XTL+SV18XG9R8yVcIya6Oqyb82Im2B/G38ta2feryUfswh3ofn gZQ+qEXV5/LcRKlVVzHgiQjFOIx2+k7z6bzh6FkGuDY8yVHsBW61GsRnDNhBFnas KCMDktWMphXfFrtUlUzOrdHVl/xw6tguJLeo5Eeb7RKq+/I7DUxGC2xSa64SgAfH hjSLVIaeWxghjjyF/FSyqiOkg0f9S28tCtVvQm+Gv8Ft+quM8DdWgQCTO7x/ec2V 08KmlmFcYuNdmKRrI68X8Z+WnZJ7HvsdP/OGmqwSOUjjp1nxw+6YW7zjsD3EKoXZ mw9NsyXonXkxuVfHYlmkTqQTXTJlWEZCDHcVKhsSs2JMf8VUw9plsakMhjQvuTeN aTy6+wF4PhG8JFnhNE3OXk+7q1CIC+KWEHatlcBgOlgpFcVhJTqInyPeSKz+zTuD 4ysxMYW5SEbuGI2jgkP5nyQQMn+BT4SK5n6ryKHfx8FSXERpwn2p2VIeldnK+kki CBDnoRXNQvzvjz8xLSNeKGLyGdYV/MA++N+qw7vtNVC7Ah/IojStGLK4JXMiasKg gS767Yqx7w8/6GZBNS+xf9g3xxfnZ+inWlO9o4J1Chy4Hdybr8W6Up23IBzOaUDh A7wABO3zxr1hyd02asFxHXAt0sxUTjCzCI6m34gwFqW9FGdT464v1P0CAwEAAaNT MFEwHQYDVR0OBBYEFP5blxkbLO2PnaKM9zvKMB7U4hVCMB8GA1UdIwQYMBaAFP5b lxkbLO2PnaKM9zvKMB7U4hVCMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL BQADggIBAIaG8jVKZ49qEf5HoC2QRAzUYAdBiB/ZqEnBeNDUaBWyyb1YU4hwK04n VsxGwo9pJ9lL7KgYw8zD+qb5hW4P6hWw9HpJTTiGXu8IzOVOIp6QXupgDhzFu064 yBVTMBwwVwcbGRLf6YtYG1XJYWW/cploiyJ/KpIn/biUGyToZWG8AnM9XtRKOYaV aoGyuQG0jg2GTwA5HPGrMRvQj2ANX2F7EtxNhoNdSRh3mjP8A6ZvJu7M0PMsRSuz wZJLAeQFHBPAIolUA4UrCqF8QrFzKfW6BCG97D00QP8ICAEaLKINC+9ObBDn7gmA XhN6v4XHBk0Y1jiw48d50+XmreE7rvx5z4YJ/hcIjAnzAqzKwNW4I4s179g56ea2 88tTdxqaQQVoR76trYt+94LbBD0K6IFjkps3MU5PF7G3Ef2uI6gAGO2ugfZVn0Wv VF9XSJBKW2/WcXf29ffw/Ezc7Vb2cNe9wT0mb06yLmtKuDn1Ti92jeny1dy59SiK Bry6dKR5WggKZ8RaXvcTfjnMyKEOMQjoQrr+0mKnMrFICvRowimJhOJr9ODay4LS riWGOGMYbumOZRCG9OKA0+80B0gAqq3HG7WP+mD6Pl2ILMNO+3wVsNtBkCdSY7ft qpXRrluffm9CDm6Vi+LfOLKKuRSEddFjye30/OzfkEjRPDbDXtkr -----END CERTIFICATE----- fulcio-1.6.5/config/tls/key_cert_generation.md000066400000000000000000000014431470150653400214240ustar00rootroot00000000000000# Generation of ct_server key/cert and CA certficate ## Commands ``` # 1. Generate CA's private key and self-signed certificate openssl req -x509 -newkey rsa:4096 -days 36500 -nodes -keyout ca.key -out ca.crt -subj "/CN=My CA" # 2. Generate ct_server's private key and certificate signing request (CSR) openssl req -newkey rsa:4096 -nodes -keyout tls.key -out server-req.pem -subj "/=Server TLS/OU=Server/CN=*/emailAddress=tls@gmail.com" # 3. SAN echo "subjectAltName=DNS:*,DNS:ct_server,IP:0.0.0.0" > server-ext.cnf # 3. Use CA's private key to sign ct_server's CSR and get back the signed certificate openssl x509 -req -in server-req.pem -days 36500 -CA ca.crt -CAkey ca.key -CAcreateserial -out tls.crt -extfile server-ext.cnf # 4. Clean-up rm ca.key ca.srl server-ext.cnf server-req.pem ``` fulcio-1.6.5/config/tls/tls.crt000066400000000000000000000035221470150653400163760ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFPDCCAySgAwIBAgIUP1HBTqmRjZIVkmIXH5o5fCXhjOwwDQYJKoZIhvcNAQEL BQAwEDEOMAwGA1UEAwwFTXkgQ0EwIBcNMjQxMDAzMTIwNjUzWhgPMjEyNDA5MDkx MjA2NTNaMDsxDzANBgNVBAsMBlNlcnZlcjEKMAgGA1UEAwwBKjEcMBoGCSqGSIb3 DQEJARYNdGxzQGdtYWlsLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBALWPVLrIww+AHpzDKPbAIyd+geuCeTpcyvnBk2ikjBsdC1u0ahZAnuZjQvwh U1hPb1BAkFCq3T6gKH7rapdPZaCrLstHPeIFMr9hpcVo+h4D07DgAtaCfcH4jvUz pgycQBNRggryoEj4LAjcKcqcbBZuY6mCQiH2REmMwLUzdBXTmRrVzIVJatecrwzf rz1018vSp+uQnXCkRX1K63PpEFBgWoSmgwK78p/03U0Fmj8vRD1RM2PJxM1LJtE4 VBSjVSsfS1awAg0YUERwvetrSpdSES0Rh0TsXJ/wSkvOz3KGv2IYppor+0vgsyq3 2X98VAXVeqDObPYYALM7mLHjzYJ0tXOXKmRVTjZugMDU993tOf7C2Ac7wMbjGwJr r9/jzMdUXjh+yj238PqHKblS7SYI+R4/Y/z5USAgtEbTjlhcdqrtnUfC39kCVsfH wli0lGhoyKlY9EK8T40PfQdNDPBFwmgTiHEJ42P47XNcYNNuO3ZsKTYI4Z0os2kz 3vvcvZRuLrYfxVCZ0oh9l1F62A/7oAJ4lIQGUR+nCkWFLELcOuEDiQMUvd4c3UOo XX6oDWQ6kIV9YHWGt0sOYm1Y3INetidGr37N3p0+R8I3JfpOOlE1Vaeyhcwq7Onm oHLAN1XxsItDmyIcs7U3jHCFHw+sNcHGAsf5O6z12c5nvUJdAgMBAAGjYTBfMB0G A1UdEQQWMBSCASqCCWN0X3NlcnZlcocEAAAAADAdBgNVHQ4EFgQUWud+Jbj22WG5 gMPTTFhNFC6G18UwHwYDVR0jBBgwFoAU/luXGRss7Y+dooz3O8owHtTiFUIwDQYJ KoZIhvcNAQELBQADggIBAIkxlgEM+U6/yvEL1CKewNTbeyJPdbJcpAuH9LIqr4bc 5Dcl417GwXL/vqwhGhaPcIeFWSSr5yrLLPqk9OknKqJO90XQIBJik/00sz84inoM pKIfPDjaMpE3A/ihWkpaz9BAxh3yXblxM5H7bgbmcXBdF2Ccwsq0Ph169NuFwL/M RkhB7yzou1CXm0PMRV+l0pQx2c7p65NtQXQqPGDNw8WX0VoDgPgkQiN1mtBX766k WhmxFwKwqHuxdyRRJmwCuQKZiDv1b1tCpBZI3Qwlh5qZPR9e7G/E6m/BSsLjKcm8 vxZCHiyHmo+vfWJbj9BhsqRFioioc5PM5+vyyiWcGGVnCtTeTCG/8+myqFdbsmMp TY6FDHOrG5dDAFjckXiMqTicqGboHCIHn1x4kEYCWWrdXsk1xWBMA1x89tUryhXc fBVTLAkCDFEwLZ3lk0sq90h4wP5Z3DUWntORZ02d3tl4c8MCY+V8DofONMQV55Jy jW0qsoh77U4Y4A08iksH6kNcQPMsGKz8F0rbc21oT9FhV6SRaUFnmY/fNiiwD1G7 8GQYhiAXIIT9e9bK67epH4VVO5JX4k8xWQ7kSUFSUjKjbHYT6CbaL47Ne1Hni8ke ofA8DthqfkHm7P4kOaV5/j6dTmTsKdlwGwIZ1RaBt+0+czik44wyirYJ4hxfxUYU -----END CERTIFICATE----- fulcio-1.6.5/config/tls/tls.key000066400000000000000000000063101470150653400163740ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC1j1S6yMMPgB6c wyj2wCMnfoHrgnk6XMr5wZNopIwbHQtbtGoWQJ7mY0L8IVNYT29QQJBQqt0+oCh+ 62qXT2Wgqy7LRz3iBTK/YaXFaPoeA9Ow4ALWgn3B+I71M6YMnEATUYIK8qBI+CwI 3CnKnGwWbmOpgkIh9kRJjMC1M3QV05ka1cyFSWrXnK8M3689dNfL0qfrkJ1wpEV9 Sutz6RBQYFqEpoMCu/Kf9N1NBZo/L0Q9UTNjycTNSybROFQUo1UrH0tWsAINGFBE cL3ra0qXUhEtEYdE7Fyf8EpLzs9yhr9iGKaaK/tL4LMqt9l/fFQF1Xqgzmz2GACz O5ix482CdLVzlypkVU42boDA1Pfd7Tn+wtgHO8DG4xsCa6/f48zHVF44fso9t/D6 hym5Uu0mCPkeP2P8+VEgILRG045YXHaq7Z1Hwt/ZAlbHx8JYtJRoaMipWPRCvE+N D30HTQzwRcJoE4hxCeNj+O1zXGDTbjt2bCk2COGdKLNpM9773L2Ubi62H8VQmdKI fZdRetgP+6ACeJSEBlEfpwpFhSxC3DrhA4kDFL3eHN1DqF1+qA1kOpCFfWB1hrdL DmJtWNyDXrYnRq9+zd6dPkfCNyX6TjpRNVWnsoXMKuzp5qBywDdV8bCLQ5siHLO1 N4xwhR8PrDXBxgLH+Tus9dnOZ71CXQIDAQABAoICABKBgYloXTl/PZ+M5OgBvZOQ +X0f12tzedzrNjM8UmuREk9OnGGYRJoHFBTO8MfXkOkFK7CNOe/gM0B8jmjN1vYB fMuLf2tCTGHlehgdEyFsEm+85Y0nz9mtlCS6FvrCEmXlsPOct2m4ogRlLH1SZFIE /nOQq1z61QsKJbpSfEqdPsXVdPtA+HrxpYYSZrJE7pn/5s3D98g7djnHISi3YMpQ h+ltb30f2yMiukvXflliX/pABJTvQ/gI6PP6YdeYrl2u2ucDGbJsAAJ522HblcbG vqlxV/BWhzpmK6x+b/akdW1yRckBIqQhSyHXi3vLGGVf1Rf+8mxDFg8uy+mV5qRx CX+ZBk8gl6ghXRFpSBrMHIrCwgfoSbBz+SjQjMXcJAPXAcvbWYU9wjY0xMR6zTgl euxevU2UN7xRkrt8MdM96yaZFrR2TMATXuNqaAp8W6asuXtaqlz5xrrjKB5kUlF5 YIsthhGKkMgm6D0a9gVINmH1HC119HXyEDs6i8XjVdPzaIKnSwfNk48u1ye/sYBS OfkVd+gXVV2HW3Ua4WWyJ2854osxVmx0x1Iy5zWj2dV4hk5h/KmJebfLwssxDN1k 1hL7Ef/g0GrEH40WjcN6U1/TKBR/uczSrzaFNAx9+V/+0vm3OlNLKcT9bXpT3Lav yPITDIRTNVS3wFRcL8YBAoIBAQD45XFFMG7hsBQRqgiG15q6+MGa1zv1tIG2kD5L oSndB3q9Gre4Af62CT+P7onpHsSWPpCj5ZSpHhI3eXGUk8DCg/sI0scjdmvctn5Z sCTVqNb0wNLpI4Kh2L1trK9HqUJWIRJlwVownp8cRKQ5lh9PpdYNMg/6Qb/WzR6B zoG2rnSweC29S0Da0am2wC/3jmuSZpBimio6b1pUMUUkTYQtWEVnvHiDCQGDHKEW 5zcMVTcESXC/Yykxuaxf1EDFSoKCHl0/uhkH2q4z1erz5wRnBfvmW20Hd9u5oNvX EwOtKTPyZmlIEaWhrxXj4PZEmo1Wc2+QPE0/yUWUcjbvcUjtAoIBAQC6veVnhIe8 U0yh7ZuMnJSWOjsJd6XH+sQwxcD+bOTmM11WW50Xg9rH+zMv1fa2FMhbnfg8Y0Mo cjDP0clUiwQkljs6bp7Icq+r82sa2oXeEmNzaVRI92TjcWucyxKP8Hy9lEiR1J1q gHMD4zajvrzFiKqpOxzHHbjkhJgn1PuP/ub5ohDSxr4rtn5qnxRfrPnOT2SeEIS/ aMoMS35zBCBZJp4CvozfhIFr7SEac85jolu5C6UiIGus2zvAPPgAtov8ptGl4uOs QDGz5f2oneyzveiGx6fSDmDJvvqTl8r5E7qrej8GHNueY1oRqLpG/iBchKA8kv8u MWkGdiZ5DuExAoIBAHUog43/A2Km4HuEHylh2crDB1cck3PP+PL3qOsuvKb3O1ZC elJaVgxYBBx7O12Jhx31613K1pRYvFhyiP1YI3csawE3Ple6CYHGQWl0WZJdPHnP PjhR587JWDmE/KjtynUCckeFoS+bqufCg887lBeIx15Ev3KcenHg8chGbZaRPgpH N7iP8MJPyORmSO3tk0NBlhtj2BbTjaBt5M720g4KK/ltpQiBN74Avu8p/SaIAjK5 YyIjyiNG9BXTsn1r2kzngBtcPSYOUMvDmSogB1l7XpyLUqIeUEZrqq/tmmBrMbGb dVlgPSgDY3l1zlZyra8Q/WXWjMJGusLqlGNXXu0CggEBAKli0pFhX5XtoRdIZc3X wde6ng5qXw/UYN00o2ik8cP1V3abxxSrX2oCa126oPxsQYkI80AjcalgWvJHAm4T YwCk3LiV2qVLkhlQxRgom0DiQR9QrUk6TmMYYFpqwT2bECsOM/1DdD5EoQ8nrEo/ Gw+6dcLngaUDStDNjQ6kXEMzHePVo5js+VbBRE4GWf6m8ji3Pzc5GJBextb8K4i8 d3MmWjF3EmU01ghFob9SyCUMAlMJQxJ/gevbOImZRAOxkazszEHCWm3GFM9vkPS/ uxMW8bI/q/QXYqfc+YGjMFNaF/qu+jfbOUKkL/DQsZbvr/77tjT7yUfnPbLEvQUW ACECggEBALQI7DtKWcadkqTxwspdoHOx25m8xTWla87GbJ7o0l9Fsz7alA0o7zT2 0rl3z2h/hrnyDETkhPOtR62/2x+PxlO210SmkhS/ismqW9LFvEyXgsT6YYoXMEiR ++DEZcuKNnqpgNcTjtcbXsSbvENRPXSq+MS3wCwgG+uzgjhIYjhxm/zzXc4bVFoo 8eSjnUFxA4qaT66yZyPPKM+c535e/ts57Md7yJEFkclhGDV3UwCYNRNKmYEjhHX0 c7DL00QpiJwztOZuwMa1CGruZwOHUvVk/7bS4cx1y7F868+nXqSAuNJExX8ZBv3D neKw1mF9SjXQJhWie2mOac+GxBMaV/4= -----END PRIVATE KEY----- fulcio-1.6.5/docker-compose.debug.yml000066400000000000000000000022041470150653400175310ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. version: '3.1' services: fulcio-server-debug: build: context: . target: "debug" entrypoint: [ "dlv", "exec", "--listen=:2345", "--headless=true", "--log=true", "--api-version=2", "--", "/usr/local/bin/fulcio-server", "serve", "--host=0.0.0.0", "--port=5555", "--grpc-port=5554", "--ca=ephemeralca", ] restart: always # keep the server running ports: - "5555:5555" - "5554:5554" - "2345:2345" - "${FULCIO_METRICS_PORT:-2112}:2112" fulcio-1.6.5/docker-compose.yml000066400000000000000000000103441470150653400164500ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. version: '3.2' services: fulcio-server: build: context: . target: "deploy" command: [ "fulcio-server", "serve", "--host=0.0.0.0", "--port=5555", "--grpc-port=5554", "--ca=ephemeralca", "--ct-log-url=https://ct_server:6962/test", "--ct-log.tls-ca-cert=/config/tls/ca.crt", # Uncomment this for production logging # "--log_type=prod", ] restart: always # keep the server running ports: - "5555:5555" - "5554:5554" - "${FULCIO_METRICS_PORT:-2112}:2112" volumes: - ~/.config/gcloud:/root/.config/gcloud/:z # for GCP authentication - ${FULCIO_CONFIG:-./config/identity/config.yaml}:/etc/fulcio-config/config.yaml:z - ./config/tls:/config/tls:z healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5555/healthz"] interval: 10s timeout: 3s retries: 3 start_period: 5s depends_on: - dex-idp read_only: true dex-idp: image: dexidp/dex:v2.30.0 user: root command: [ "dex", "serve", "/etc/config/docker-compose-config.yaml", ] restart: always # keep the server running ports: - "8888:8888" volumes: - ./config/dex:/etc/config/:ro healthcheck: test: ["CMD", "wget", "-O", "/dev/null", "http://localhost:8888/auth/healthz"] interval: 10s timeout: 3s retries: 3 start_period: 5s ctfe_init: build: context: . dockerfile: Dockerfile.ctfe_init depends_on: - trillian-log-server - fulcio-server volumes: - ctfeConfig:/etc/config/:rw ct_server: image: gcr.io/trillian-opensource-ci/ctfe volumes: - ctfeConfig:/etc/config/:ro - ./config/tls:/config/tls:z command: [ "--log_config" ,"/etc/config/ct_server.cfg", "--log_rpc_server", "trillian-log-server:8096", "--http_endpoint", "0.0.0.0:6962", "--tls_certificate", "/config/tls/tls.crt", "--tls_key", "/config/tls/tls.key", "--alsologtostderr", ] restart: always # retry while ctfe_init is running depends_on: trillian-log-server: condition: service_started trillian-log-signer: condition: service_started ctfe_init: condition: service_completed_successfully ports: - "6962:6962" mysql: image: gcr.io/trillian-opensource-ci/db_server:3c8193ebb2d7fedb44d18e9c810d0d2e4dbb7e4d environment: - MYSQL_ROOT_PASSWORD=zaphod - MYSQL_DATABASE=test - MYSQL_USER=test - MYSQL_PASSWORD=zaphod restart: always # keep the MySQL server running healthcheck: test: ["CMD", "/etc/init.d/mysql", "status"] interval: 30s timeout: 3s retries: 3 start_period: 10s volumes: - mysql:/var/lib/mysql trillian-log-server: image: gcr.io/trillian-opensource-ci/log_server command: [ "--storage_system=mysql", "--mysql_uri=test:zaphod@tcp(mysql:3306)/test", "--rpc_endpoint=0.0.0.0:8096", "--http_endpoint=0.0.0.0:8095", "--alsologtostderr", ] restart: always # retry while mysql is starting up ports: - "8095:8090" - "8096:8091" depends_on: - mysql trillian-log-signer: image: gcr.io/trillian-opensource-ci/log_signer command: [ "--storage_system=mysql", "--mysql_uri=test:zaphod@tcp(mysql:3306)/test", "--rpc_endpoint=0.0.0.0:8095", "--http_endpoint=0.0.0.0:8096", "--force_master", "--alsologtostderr", ] restart: always # retry while mysql is starting up ports: - "8097:8096" depends_on: - mysql volumes: ctfeConfig: {} mysql: {} fulcio-1.6.5/docs/000077500000000000000000000000001470150653400137415ustar00rootroot00000000000000fulcio-1.6.5/docs/certificate-specification.md000066400000000000000000000137771470150653400214020ustar00rootroot00000000000000# Certificate Specification This document includes the requirements for root, intermediate, and issued certificates. This document applies to all instances of Fulcio, including the production instance and all private instances using the service defined in this repository. The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). ## Root Certificate A root certificate MUST: * Specify a Subject with a common name and organization * Specify an Issuer with the same values as the Subject * Specify Key Usages for Certificate Sign and CRL Sign * Specify Basic Constraints to `CA:TRUE` * Specify a unique, random, positive, 160 bit serial number according to [RFC5280 4.1.2.2](https://www.rfc-editor.org/rfc/rfc5280.html#section-4.1.2.2) * Specify a Subject Key Identifier * Be compliant with [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280) A root certificate MUST NOT: * Specify other Key Usages besides Certificate Sign and CRL Sign * Specify any Extended Key Usages A root certificate SHOULD: * Use the signing algorithm ECDSA NIST P-384 (secp384r1) or stronger, or RSA-4096 * Have a lifetime that does not require frequent rotation, such as 10 years A root certificate MAY: * Specify a Basic Constraints path length constraint to prevent additional CA certificates from being issued beneath the root * Specify an Authority Key Identifier. If specified, it MUST be the same as the Subject Key Identifier * Specify other values in the Subject ## Intermediate Certificate An intermediate certificate MUST: * Specify a Subject with a common name and organization * Specify an Issuer equal to the parent certificate's Subject * Specify Key Usages for Certificate Sign and CRL Sign * Specify an Extended Key Usage for Code Signing * Specify a lifetime that does not exceed the parent certificate * Specify Basic Constraints to `CA:TRUE` * Specify a unique, random, positive, 160 bit serial number according to [RFC5280 4.1.2.2](https://www.rfc-editor.org/rfc/rfc5280.html#section-4.1.2.2) * Specify a Subject Key Identifier * Specify an Authority Key Identifier equal to the parent certificate's Subject Key Identifier * Be compliant with [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280) An intermediate certificate MUST NOT: * Specify other Key Usages besides Certificate Sign and CRL Sign * Specify other Extended Key Usages besides Code Signing An intermediate certificate SHOULD: * Specify a Basic Constraints path length constraint of 0, `pathlen:0`. This limits the intermediate CA to only issue end-entity certificates * Use the signing algorithm ECDSA NIST P-384 (secp384r1) or stronger, or RSA-4096 * Have a lifetime that does not require frequent rotation, such as 3 years An intermediate certificate SHOULD NOT: * Use a different signature scheme (ECDSA vs RSA) than its parent certificate, as some clients do not support this An intermediate certificate MAY: * Be optional. An end-entity certificate MAY be issued from a root certificate or an intermediate certificate. Clients MUST be able to verify a chain with any number of intermediate certificates. ## Issued Certificate An issued certificate MUST: * Specify exactly one Subject Alternative Name, as a critical extension. It MUST be populated by either: * An email * A URI * Specify an Issuer equal to the parent certificate's Subject * Specify a Key Usage for Digital Signature * Specify an Extended Key Usage for Code Signing * Specify a lifetime that does not exceed the parent certificate * Specify a unique, random, positive, 160 bit serial number according to [RFC5280 4.1.2.2](https://www.rfc-editor.org/rfc/rfc5280.html#section-4.1.2.2) * Specify a Subject Key Identifier * Specify an Authority Key Identifier equal to the parent certificate's Subject Key Identifier * Specify an empty Subject * Be compliant with [RFC5280](https://datatracker.ietf.org/doc/html/rfc5280) * Specify a public key that is either: * ECDSA NIST P-256, NIST P-384, or NIST P-521 * RSA of key size 2048 to 4096 (inclusive) with size % 8 = 0, E = 65537, and containing no weak primes * ED25519 * Specify the OpenID Connect identity token issuer with OID [`1.3.6.1.4.1.57264.1.1`](https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md#1361415726411--issuer) * Be appended to a Certificate Transparency log. Clients MUST NOT trust certificates that do not present either a proof of inclusion or a Signed Certificate Timestamp (SCT) An issued certificate MUST NOT: * Specify a nonempty Subject * Specify multiple Subject Alternative Name values * Specify other Key Usages besides Digital Signature * Specify other Extended Key Usages besides Code Signing An issued certificate SHOULD: * Use an ephemeral key. A client MAY request a certificate with a long-lived key, but a client MUST adequately secure the key material * Append a precertificate to a Certificate Transparency log, where the precertificate MUST be signed by the certificate authority and MUST include a poison extension with OID `1.3.6.1.4.1.11129.2.4.3` * Specify the Signed Certificate Timestamp (SCT) from the Certificate Transparency log with OID `1.3.6.1.4.1.11129.2.4.2` An issued certificate SHOULD NOT: * Use a different public key scheme (ECDSA vs RSA) than its parent certificate, as some clients do not support this * Specify a public key that is stronger than its parent certificate. As weaknesses in keys are found, an issued certificate should be weakened before its parent, since once the parent key is compromised, it can issue new certificates. An issued certificate MAY: * Specify Basic Constraints to `CA:FALSE` * Specify values from the OpenID Connect identity token in OIDs prefixed with `1.3.6.1.4.1.57264.1`, such as values from a GitHub Actions workflow * Specify multiple SCTs with OID `1.3.6.1.4.1.11129.2.4.2`, denoting that the certificate has been appended to multiple logs * Specify the Signed Certificate Timestamp (SCT) in a response header `SCT` instead of embedding the SCT in the certificatefulcio-1.6.5/docs/ctlog.md000066400000000000000000000140361470150653400153770ustar00rootroot00000000000000# Certificate Transparency Log Information ## Summary Fulcio maintains a certificate transparency (CT) log, writing all issued certificates to the log. Users of Sigstore can verify via cryptographic proof that certificates are included in the log along with monitoring the log for inconsistencies. The CT log is backed by [Trillian](https://github.com/google/trillian), a highly scalable and verifiable data store. The `certificate-transparency-go` [library](https://github.com/google/certificate-transparency-go/tree/master/trillian) implements [RFC6962](https://datatracker.ietf.org/doc/html/rfc6962), the RFC for certificate transparency. ## Signed Certificate Timestamp (SCT) [SCTs](https://datatracker.ietf.org/doc/html/rfc6962#section-3) represent a cryptographic promise that the CT server will include an entry in the log within a fixed amount of time. The SCT contains a signature over a timestamp and certificate. It is verified using the log's public key, which is included in Sigstore's TUF metadata. SCTs can either be embedded in a certificate or detached from the certificate. If an SCT is detached, this means that Fulcio returns the SCT alongside the certificate, and it's up to the caller to store the SCT. For example, with Cosign, the SCT is not stored, so it is only verified during artifact signing. All callers should be storing certificates, so SCTs embedded in the certificate can be verified both during artifact signing and verification. For each of Fulcio's signing backends, a backend always implements support for a detached SCT, and optionally implements support for embedded SCTs. ### Generating an embedded SCT To generate a certificate with an embedded SCT, two certificates are issued: A precertificate and a final certificate. The precertificate is an invalid certificate that contains all of the same valules as the final certificate, except for one extension, the poison extension. The precertificate is written to the transparency log, and its values are used to generate the SCT. The purpose of the precertificate is to solely to generate an SCT. If the CA fails to write the precertificate to the log and no SCT is issued, the CA has not signed a valid certificate, so there is no issue. If the CA had to sign a valid certificate once to write to the log, and again to embed the SCT, if there's an error after the first step, a valid certificate would have been issued, and must then be revoked. The SCT is signed over a timestamp and certificate body, called the to-be-signed (TBS) certificate. The TBS certificate is a certificate without a signature. Since the signatures for the precertificate and certificate will never match, the TBS is used to generate the SCT. When generating the SCT, the poison extension is also removed from the TBS certificate. Additionally, the SCT is signed over a hash of the issuing certificate's public key, to bind the issuer to the certificate. After the log returns an SCT, the CA embeds the SCT in a specific extension, before signing the final certificate. Note that a certificate can contain a list of SCTs, for each log that contains the precertificate. An example SCT from `openssl`: ``` CT Precertificate SCTs: Signed Certificate Timestamp: Version : v1 (0x0) Log ID : 7A:42:62:CF:F6:69:1B:E5:04:9F:9C:3F:19:A2:2B:EB: E6:B0:23:E4:4A:7E:4A:6D:FD:5F:53:7A:EE:EF:6B:59 Timestamp : Apr 2 22:05:57.390 2022 GMT Extensions: none Signature : ecdsa-with-SHA256 30:45:02:21:00:F0:7F:46:BA:48:5C:5C:7D:7B:CF:3A: 44:C7:AB:7A:AD:0B:EC:13:18:A9:D1:1F:D6:31:0A:C8: 4A:FE:08:A3:8C:02:20:67:33:86:4A:02:F8:B9:21:7D: 33:9F:45:F7:77:1D:6B:C1:6F:23:3A:41:91:BB:20:96: 5A:AA:FA:09:C3:B5:47 ``` `Log ID` is the SHA256 digest of the DER-encoded log public key, which can be used to look up the SCT verification key. See the `certificate-transparency-go` [library](https://github.com/google/certificate-transparency-go) for more details. [1] The additional extension, the poison extension, is used to make the certificate invalid. It is an extension with a specific OID, a null value, and is marked as a critical extension. Verifiers must reject a certificate that has a critical extension whose purpose is not known. Therefore, either a verifier is not aware of the poison extension's OID, rejecting a certificate with the critical poison extension, or the verifier is aware of the purpose of the extension, rejecting the certificate nonetheless. ### Verifying an SCT To verify an embedded SCT, a verifier must have the final certificate and its issuing certificate. The SCT is verified using the log's public key, which is distributed out of band. For Cosign, it is distributed in the TUF metadata. The client will reconstruct the TBS precertificate by removing the SCT extension and the certificate signature. With the timestamp of issuance and a digest of the issuer's public key, the verifier can reconstruct what the SCT was signed over, and verify the SCT's signature. ## Sharding strategy A CT log can grow indefinitely, only bounded by the size of the underlying database. A large CT log will take longer for auditors to verify, and will also increase the burden on log replicators. Therefore, we need to create log shards, where after a certain period, a new log is turned up and the old log is frozen, accepting no more entries. We will create new log shards each year. The log's name will be the year. Currently, the log is accessible at `https://ctfe.sigstore.dev/test`. After sharding the log, the log will be accessible at `https://ctfe.sigstore.dev/2022`. We can use the same signing key for each year's shard, so that we don't need to distribute a new key each year in the TUF metadata. ## Test secrets There are test secrets in `ctfe` for **DEVELOPMENT ONLY**. They were generated with: ```shell openssl ec -in <(openssl ecparam -genkey -name prime256v1) -out privkey.pem -des openssl ec -in privkey.pem -pubout -out pubkey.pem ``` The password is `foobar` and is stored in the `ct_server.cfg` file.fulcio-1.6.5/docs/how-certificate-issuing-works.md000066400000000000000000000126361470150653400221720ustar00rootroot00000000000000# Certificate Issuing Overview This document walks through the process of issuing a code signing certificate. This is a great entry point to understanding how Fulcio works if you're interested in contributing to the project or want to learn more about what's happening under the hood. ## 1 | Certificate Request Input To begin, the client submits a certificate request to Fulcio. ![Certificate request diagram](img/certificate-request.png) The certificate request contains the following: - An OpenID Connect (OIDC) identity token. This is a signed JWT containing information about the principal (identity of the client), the issuer (who issued the identity token - Google, Microsoft, GitHub, etc.) and additional metadata such as expiration. The principal identity can either be a maintainer identity in the form of an email, or a workload identity. - The public key. This is the public portion of a cryptographic key pair generated by the client. The public key will be embedded in the issued X.509 certificate. - A signed challenge. This challenge proves the client is in possession of the private key that corresponds to the public key provided. The challenge is created by signing the subject (`sub`) of the OIDC identity token. - Alternatively, instead of a public key and signed challenge, a client can provide a certificate signing request (CSR), which also provides a proof of possession and the public key. See the [service definition](https://github.com/sigstore/fulcio/blob/main/fulcio.proto) for more details. ## 2 | Authentication The first step in processing the certificate request is to authenticate the OIDC ID token. ![OIDC Authentication diagram](img/authenticate-token.png) To authenticate the token Fulcio must: - Use the issuer claim from the token to find the issuer's OIDC discovery endpoint - Download the issuer's signing keys from the discovery endpoint - Verify the ID token signature ## 3 | Verifying the challenge Once the client has been authenticated, the next step is to verify the client is in possession of the private key of the public key they’ve submitted. To do this, Fulcio verifies the signed challenge or CSR. For a signed challenge, this is a signature of the `sub` claim. The challenge and CSR are verified using the provided public key. ![Challenge verification diagram](img/verify-challenge.png) ## 4 | Constructing a certificate The client is now authenticated and has proved possession of the private key. Fulcio now issues a code signing certificate for the identity from the ID token. ![Certificate contruction diagram](img/create-certificate.png) At a high level, this consists of: - Embedding the provided public key in the certificate - Setting the certificate's subject alternative name (who the certificate is issued for) to match the subject from the OIDC ID token. This could be an email, SPIFFE ID, or GitHub Actions workflow identity. - Including the OIDC ID token issuer in a custom field in the certificate - Setting various X.509 extensions depending on the metadata in the OIDC ID token claims (e.g GitHub Actions workflow information) ## 5 | Signing the certificate The code signing certificate is now populated, but needs to be signed by the certificate authority. This will form a chain of trust from the issued certificate to the certificate authority root certificate. ![Signing diagram](img/sign-certificate.png) Fulcio supports several signing backends to sign certificates: - KMS: A KMS key hosted on GCP, AWS, Azure or Hashicorp - [Tink](https://github.com/tink-crypto/): A secure KMS-encrypted Tink keyset created with [tinkey](https://github.com/tink-crypto/tink-tinkey) - PKCS#11: This works with any PKCS#11 devices including AWS CloudHSM, [softHSM](https://www.opendnssec.org/softhsm/) and others - [Google CA Service](https://cloud.google.com/certificate-authority-service/docs): A GCP-hosted certificate authority - Files: An on-disk password-protected private key - Ephemeral (for testing): An in-memory key pair generated on start up See [Setting up a Fulcio instance](setup.md) for more details. ## 6 | Certificate Transparency log inclusion As part of certificate issuance, the certificate will be appended to an immutable, append-only, cryptographically verifiable certificate transparency (CT) log, which allows for issuance to be publicly auditable. A special X.509 extension, called a poison extension, is included in the certificate before it is appended to the log. This certificate is called a precertificate, and is not yet usuable by clients. ![Transparency log upload diagram](img/ctlog-upload.png) The certificate transparency log returns a _Signed Certificate Timestamp_ (SCT). The SCT is a promise of inclusion in the log, signed by the CT log. It can be verified without accessing the log, though a client can also request a cryptographic proof of inclusion directly from the log. The SCT is embedded within the certificate, and signed again. ![Signing with embedded SCT diagram](img/sign-certificate-sct.png) Note that the Certificate Transparency (CT) log is separate from the [Rekor](https://github.com/sigstore/rekor) transparency log. Fulcio's CT Log only stores issued certificates, while Rekor stores artifact signatures and attestations. See [Certificate Transparency Log Information](ctlog.md) for more details. ## 7 | Return certificate to client Finally, the certificate and SCT are both returned to the client. ![Return certificate diagram](img/return-cert.png) fulcio-1.6.5/docs/hsm-support.md000066400000000000000000000043071470150653400165700ustar00rootroot00000000000000## HSM Support ### PKCS11CA Fulcio may also be used with a pkcs11 capable device such as a SoftHSM. You will also need `pkcs11-tool`. You will need to specify `CGO_ENABLED=1`, since PKCS11 support requires C libraries. > :warning: A SoftHSM does not provide the same security guarantees as a hardware-based HSM. > **Use for testing only.** You will need `pkcs11-tool`. On Debian, you can install the necessary tools with: ``` apt-get install softhsm2 opensc ``` To configure a SoftHSM: Create a `config/crypto11.conf` file: ```json { "Path" : "/usr/lib64/softhsm/libsofthsm.so", "TokenLabel": "fulcio", "Pin" : "2324" } ``` And a `config/softhsm2.conf` ``` directories.tokendir = /tmp/tokens objectstore.backend = file log.level = INFO ``` Make sure `/tmp/tokens` exists ```shell mkdir /tmp/tokens ``` Export the `config/softhsm2.conf` ``` export SOFTHSM2_CONF=`pwd`/config/softhsm2.conf ``` ### Start a SoftHSM instance ```shell # Note: these pins match config/crypto11.conf above softhsm2-util --init-token --slot 0 --label fulcio --pin 2324 --so-pin 2324 ``` ### Create keys within the SoftHSM ```shell pkcs11-tool --module /usr/lib64/softhsm/libsofthsm.so --login --login-type user --keypairgen --id 1 --label PKCS11CA --key-type EC:secp384r1 ``` * Note: you can import existing keys and import using pkcs11-tool, see pkcs11-tool manual for details ### Create a root CA Now that your keys are generated, you can use the fulcio `createca` command to generate a Root CA. This command will also store the generated Root CA into the HSM by the delegated id passed to `--hsm-caroot-id` ```shell fulcio createca --org=acme --country=UK --locality=SomeTown --province=SomeProvince --postal-code=XXXX --street-address=XXXX --hsm-caroot-id 99 --out myrootCA.pem ``` `fulcio createca` will return a root certificate if used with the `-o` flag. ### Run PKCS11CA ``` fulcio serve --ca pkcs11ca --hsm-caroot-id 99 ``` > :warning: A SoftHSM does not provide the same security guarantees as a hardware-based HSM. > **Use for testing only.** --- **NOTE** PKCS11CA has only been validated against a SoftHSM. In theory this should also work with all PCKS11 compliant HSM's, but to date we have only tested against a SoftHSM. --- fulcio-1.6.5/docs/img/000077500000000000000000000000001470150653400145155ustar00rootroot00000000000000fulcio-1.6.5/docs/img/authenticate-token.png000066400000000000000000004757331470150653400210420ustar00rootroot00000000000000‰PNG  IHDRŠ{M¥³ IDATx^ìÝ|Veûðß:1btw+¢(¡ tKƒŸ %‚€€4"ˆt)"%Ò%%Ý%ÝÝ£ÖùÞ×ýЍ± ·ßy?ûo{v⟿猿ûë¹Ž]žZÀ… (@ P€ (@ P€  +`Ǡذçž§(@ P€ (@ P€ ( óB (@ P€ (@ P€ (`pÅ¿8} P€ (@ P€ (@ P€ Šy P€ (@ P€ (@ P€0žƒbƒ_œ>(@ P€ (@ P€ (@ÅŒ(@ P€ (@ P€ (@ \€A±Á/NŸ (@ P€ ¯@xxžuðÏ󵝝d»çÙÖràgmÝÏå5ÛõŸµNl¯Ûž±šû³ÌéEÎjÔ}È÷±-±­ó"?ºm|Ÿ·]×òu\^‹iØæ›N $LÅ óŒpT (@ P€ @"°„lò9,,̺Y^î5ÛmâóõËܗðF·?Ku\1œ.¡Qhhh€¹?k}KšÝŒe{{{„„„D /mƒLÛí¢Ãöûšc²ý™íÜ-¯ÇôswwwøøøD 8ÅÎv[Ë÷–ËÖbuÿ2?±ŠéžQÝ÷ɓ'Ǔ'O"ý–DìÉ 1œž"E <~üغŽø>Ï~ÄÈÏÏ/ÚßÚØBMË­6–Å%ŒºŽ««+_è_777øûû[÷]žõQ×qppˆ4۟Çe^úº³=ÿ–í¢+ºñY¶.È·=϶¿“–9Ék–kãYתí9Š˜ºé þ—"y øøšÆ.?³ä슯ÕÍ ëë*€—kÎ^œ®W’%K?œËúÖëØœ×ËþlCoÓ×ápuuÓçÞ²u=óú–ïõú–×Ô®n.j» ó8LcÔ»4×ºi ÖñÚ;ØGš£uŒj[{ó€enr0{óLÿ–š—Ô¿V#ù¹ÚFþ°XȶzóXåg²8˜k9ŸÞ·e\ú³_íG¶“ý™ç#ÛYmd{œoÙ^WßtóH^·\&]ÓM)Óµcþ™ù|è×ô:ŠEŸ;óºŠ FÙN3ÚÃÅ!œí=ÔgӇ£œ«yüôŠ¿)y— (@ P€IH@B1 ­$ԐL>äk___Égùãý‘ï<öœÛwnãÞu_*XÔVZ‚5ÛÏBõ{KÈ&¯[Â9ùãVÂEË÷q lm×µ=Ž‹‹‹ˆ¢þüYA°å4Úúïb5&ggg›þN¶„Q*£{=n¯™ÿ$·ì×üç¹%ؐðÅ.è/-ÅK  ›Jx¡ÿž—ÐÆŽ®u.6ò›Bs@ ÿø—ÐÂôœÞV‡<êµpSpjZLÛØÖ`šöf r¬ÂÓ!¢iú˜áŠ0Ç?èyXöj“‹9b2­«¶‘DÏ_~¢“sø)û3ÿLBÓ׊y˜¬lf` ®LӑŽEÏʲRĺ—y7Š}:˜MCÒ¡ˆ›»«ÀŽ…ZÇt ä ¢éàzì[”™f1ÇÈA®égf3sàäDÌ'"±Œf9§¶ëD6°lcŠŽ$òÖ3i‡lmjõ6îjþ~~û± ¢,—\äÀ3bv–àʌa>¿6׆ù*1]7f›jëȳ6_pækÇŽ–ºÝcNÄ "íÓô«)3OJ²¯f›_=„™Çižæñ†‡Ùþž™ÇeÛÙèZöi ç,.¿‡–ãFº",û–Šr›0Ê ŽñÛš7,»Ž“#ÌCԟ̿»‘ΏÙ*"ü¶\Šm-rĹSçÅü{b{ÝGš“mZiSÄ¿Ší,³5¢6¯™ÎkÄëŠjºž"ìͱ©^Wªñ£\rjî‘N›õçæ×åŸ!õË,WZÄþM—®ieÓÍÿŸÊ5i bÍècZ|-0Ev)rHˆº!¥×“ÍÇ6o=ŽúgÛÞQÝŒ ŽžÑgùÿ!:Ÿ6‡Ïzë0ßòœ5Ô¶ ·å5ýº)wr‘?aúkýºŠM_›‚i;ø> Äã>ÈU0³úÿ—prv»«’¹&‡‡{J$O– ©’§Aªiáá–J}€Ößˍ)¹Ãåå 0(~ùŠÜ#(@ P€ ’”@€ õîß¿¯ƒ`ùxðànÞŒ‰;wîèלœœõëò€T‚=zôA~ptR,:Ž®ê{õGšCÕ‚ÎΎ° qÁCo_äʟYW]épL‚8s8§ÿ”¿Åu!UD¥“ü±®+ªÔⲝü¡i çÌ êL„ËëReþÞvߖª)S8hþãW‚=󙳗¯ågæ?zeg²/ËxdŒÖ}衛ƒ?ÉKÍ™Õpš)ì’jRsµšùx‘ÃRs`hZZCf›KË&³|i»ŸHyŽ5LŽØi€PÔºƒˆýG·¯Hã4ï*ÒzVA›À1Ê8uðilQ¢äçQËH!®l÷tÀl–€~9 $,žT3G“Ñۄû‘ŸŒÒöÄf®ÖP=â5KÄ+¯<¶GyÍv ñZ׿æ‡%}ÖŸ"Âæ ?"ÃæÜ"UåêqÛÌÇ66ÿ,Ò|­|DËë8¢˜ET‹› 劀ÍöÑíWßhU7-BՇ|36}­nЪ„…š~ªnÊçp}ã6bÝ0Ë­CœžúZßhU_›Ö‰X×ç±n_ˆLÙÒ 8(D‡ÛòYéïŒàÀ#Hœæ(Á°ùÿg;ªÿžÿÞH•*2eʌT)=‘9c€ñôBšTé‘Ö3#Ò€I©ªç?ÅñóâÚ (@ P€HÒüÞºu ·o߯ùóçqáÂ<|øP‡ròǝTÇJP›.]:xy©?ÈÒª ŸÔ.êÃnêíŸ.q|' ‡ŸJþ’4'G P€ À+êd¿'ðyì¯?Þ÷U>ꊳúžgú¬«—Ս^WWPÛ#™»²çȊŽê¿Y2€Ï„Lé³ kæœH“2œju‘\ÝpfUrÔÓÅ ø]ÀÜ-(@ P€ º€„—.]ÒÕÁgϞÕ¶m$Ε+ræÌ‰Ô©SÃ%¹êÿ˜B•"¹šVÁ÷ÕÇ=„>NèÓäø(@ P€0€€ÈŸ*L–ùþíǪZùn\Ÿ·dÎpquÒUÍÁªÍF2€öJÜÙó£P®Ò(ž¯<\“@(ö)2(ŽÝˆkP€ (@ P IH|îÜ9ý±oß>ÝBBúüIۈŒ3¢`Á‚È–-ŒÒ§…»§ñP…Áwá|Ÿ!÷ÕÛMÕÛA¹P€ (@D$pïÖ#Ü¿óX‡Ç÷n?ÂíkÂÓ]õDvÔm1ü}‚‘9}vÌýŠ(‹üù ö]Q Šх͡R€ (@ P ŸÒBB‚áÇãȑ#prR5ª…„„ÂEŠQ}œ"#‚í«PøŽ …ïÂ?äa|Ãõ)@ P€ @¢pøŸ Œ¯]Œ‡«îê–)S{šð9šG 8Âûj(ŠäW¡q¡w‘/o>ý®*£, ŠrŠ9O P€ (@ÃÈÃä8€={öè¶ò‘ü‘SªÜ[H›É©39# Ü[‡ÂÁaþ†qáD)@ P€ @Tß@_»š>Ôç YU»-ÕªÂÑÞv)áá腒ÅËéìɓ'OҀ Š“ôéåä(@ P€ Œ$pâÄ lÙ²ǎƒƒz:xŸb™‘.›Œ²»Â)EzŽ{š‘88W P€ (oë—îéÀøÖ5ox€pCºŒ©äŒ;‚‘7[qŒ]¬Š+ïý&† '†³Ä1R€ (@ PàÒgXª‡—-[Š[J€J“EËfAê\Ápñ (@ P€ Àó \9§\ÕÈ+P<+<Ózàæ¹Ü¹„Ê|‚2¥Ê!mÚŽÏ»û·ƒâwJ8 P€ (@ Ä.pùòe¬Y³DpHÞ«\9Š»Á)[IÄ®Ç5(@ P€ @Ü|ûëÀøôѫȜ#-rʄÇÞ~*0†WŠìšV±rdË÷&Ð5'ÐÃaQ€ (@ P :y8Ý… qüøqdÍé…ü%œŸ†`‚Q€HpÛ×Óoß®ÿe…76ˆ Àó\Ï®ßø6 Šßø)à(@ P€ (»€< nþüùعk;2æH‰RgEº.±oÈ5(@ ŒAÑœþ†%°öìˆ78 š ÀËðŸóûþ= ;;;”|?‚CpêÈ„Ÿ|\ …s–C*—¬°SÿK, ƒâÄrŠ8N P€ (@C bɒ%Xºb!²æO…’U2#Sö4†Žà€)@Ä'0ªÇB¬š¿/ÿ€²iŸø&ÀS€ˆE@~w`Û€L“ ï”χÇü°_Èòý{K d–zHé’9Q82(N§‰ƒ€(@ P€0¢Àæ×c”±pM†ªK [n/#2pΠ@"Ù}V/؋õç~„³«S"ž ‡N P f 'oâÀö3Ț;ÞQÆWÏÝÅ¡gQè­ÜhQí;ž;¥Nð„ Šü)â)@ P€ Œ$Š+ÞÇðã?àâÅ šÿÅÈ[4‹‘8W P Œè:ëïÇŠ+£“Ь8 P€Ï8yè NŸ‚·ËæFαoëiܺüšD®lù4ƒâ}z88 P€ (@£øßÅ-ßÿ°qÛj,˜¶%?ȇêMÊeúœ'(D†už‹þÃêS?$ÑrZ ¢غêˆî_üÁ§ÅððŸŽl¿Žrùë¢r¥,ƒâ{j80 P€ (@#Üð=Š›ŸÇà|ó'mË÷Ѐc%dÌÆ>ÄF8ÿœ#’ºÀÀ¯~ÇÑœ°äà €>UΏ ÀSçOÞÀžM'Q±ÖÛȐ%5ÎۙЌyKž¹¹%81Å î”p@ (@ P€Fžãw '¬Áµ‹÷0säj-•uÛŒo”ésž €ú}ù+.žº‰¹Ûû`¶œ"(@§‚‚±qÙ!€Ë˜Rœc,?‚œ“ãȆGšQœòåKX­(ó Š(@ P€ À ÆŸÛ¿aÇæƒê‡ƒšÿeä.˜é Œ„‡€(ðêz5ŸŽ{·aæ†î¯î Ü3(@D plßEœ;~Ÿ6.iJ`ÿê»È’% >øàƒ3zÅ æTp  (@ P€FžøxŠLyàIçÁµáìâd€és® €A:ׄã—v~é3 ŁmgqÿÎc|;räËðҏÁR€x™Ò«xÝ¢ýšÚ $Še¯Œ ûýqïÞ=4lØðeæ¹÷Å ø¹éž!(@ P€ žO ô1Ÿî×AA!hÝí“çÛ ·¢’„Àé#W1Cµžùoÿ%$OéŠûX¶ù¶*œ]#nm]}@ß_šÂ-™K€y‡††aóòÃØÿïiÜŸþcv€šò6ç3G¯ÁÎÞ©Ó%ÇgŸ—A O÷—fæç€YcÖaåŒÝêíÔ©ði£Òúj¶Ë—ÿ„ÔéS`ämŸ:¶TË>¶­=†ð°pýÏv}k }fÏXÇyãò} éøNŸb]·V‹røfX=ýð(Ër]µöùýçõºGh zûwú,ž(S© êŽ*¯û…r¡(ð&–þ¶e+ÂEáÁe{lߟmÛ>ýïäëƒâ×-ÎãQ€ (@ ^ u§ºðÊé€ÞzXÆð €‘þœºS†®@xxž[Ü{‚àPžŸ‹£Yiw˜M* ~ïãÂ2£5ìííõ϶®:‚i?¬ÂõK÷Ò3Zt­‚JµJ W‹éZy]Bç\2â»_šèï£.0[ÂÙ5î…<|©µ «“%wŕówЧåtT©[­Ì7¶dŒký‚/GÚU¶<^9§m€öórC‘¯hV šÚ2ÒºGvŸGï–3à܊öéóÈYs¥Ã¬Íœàà`šctË¥3·Ð¥ÞDÎøã?Ð¥K—76.ÅoŒžŠ(@ P€0š@=¡HJVÎfŽ©sŸ €À“‡~:~¬>\¯$ÊU)€ÚNžcÒ:„Í_<+Š®êÉlßÖÓèÓj†®8vvuDP@ª6,…΃êèÊ_YŽû]WKÈ+Uɖ¥·ª0Þ­Z/È2nQG/“Ûú3©F–±HµðÎ ÇqæØ5ý³ß×Ä?KêïSŠN†GÞŸ8¥>¬þFv_€Õ öêõº ©‹:­Ë›öÝo1–Îځ–]?Öɲ|Z ª5,­ªwëXÙµá$ÚyEKçT}:K«ªàÔ8~à2~»N·XŽà3ÛdìÝr =›MSÁznŒù³œµº:,, û·žÁÛï偓³#.žº©Co ²Ý þí͹̈́T7ÿà|˃ö”¬z§G–œiõd©Xó-Ž/Ÿ³Ëj ᎎ·àB Pàe È¿ïŽ.h[wž3fÌ@Ϟ=_ÖîãµÅñââÊ (@ P€x>/¿üR…AE»Œ*›ãB Z`강˜?y“n%!c ð²zxŠõÀªŸoŸ¢‘+j¥Ýƒ¬‡w×ëÖl^Ý~šoÝNd eß*—'R?à£{. Ký‰ºœ…,…ßɁ‰Ë"ÞÚl Š¥bXö!շ҆ÁÕÍY«ùוuEp§ÚãñEÏjêû*ªjy¢u¿mì©Û3ÈrçÆ4,=T+†ÁÓ[é×*çì¡ÚìŒk«ô –ÖEKåÔ=•ïÜxhƒŒáÛ t%ô³–¿߁Ÿû.V•¿t5ñ³–‹§o¡u¥‘x[yHßæš‹ōÞ¬éd˜·£¯Š-­?¢HïäÁÓZ¡ö[ß«qçÒí-žP€x™ÿªÊâŒyó£Q…^xðà!æÌ™óFÚP0(~™g•û¢(@ P€ @4Ý»wG©2%‘õœ  (`p©à•‡Á->8R]ŒyÅÜV­²çõÒ7”¢>tNÚ-Œë·ËÿØ©+n%ôM›!…@³æòҚRQ[%gOä*˜ÿþŽÎú!wc¿[€úõ†êáɃã.šJÛ6Ý«¢Å7ëí,A±|9GÕÚ¢²n‰!‹¥W²ô®UŽ¿õû†¥[^ÛÀúØÞ è\wJTÀVœ§'Þýš nÙ Ëš ±jþnüöOdQýˆÿ]}çU yà]ي…YUôF]îÞ|€’ç 7wHðýuœ ºŠºÏØÏQŸjôm yû Þ;ƒ”SJÌ\ßÝZu-û–@xä·bׯÖVK@î€Ü†ÿö%z4ª‡!œ'­è¢ƒó6ªB90 s·÷5øÌéS€¯B@*‹s{•FÊmpóæM¬]»­[›þí|] ƒâ×%ÍãP€ (@ R`ĈH—.>š—7|Ҁ“Š" Ô-1~O±èÀÝÚ Šåä¡+×1NŸªzçWœ~?Çß¿oÇ¿ü·d.šði1ôø©‘~øÛ ö³õCØþÜÓ_CúK?áÑ ÔCçÊç‹õҐp|\ÿ%Ȕ- foí­÷!A¶ôx–E*€‹•Î¥ÛX~'»jáaݧ%”öʔ ¥*ä×^WÎÝÖm/”Ok˜7ë\Y¯o Š¥jZÂo Æ¥ÿ³„î–ðzòÐåX8u+–¢\Ýc;W (_-+Ž¢vyÕ"šHI?~'Nœ@ƒ ⻛ç^ŸAñsÓqC P€ (@ Ä,0wî\œSDúK°¢ÛT šÚJ?TN–ÄXՂ!4$LµNøN÷ڕÊßq굜ª*M‚ãwÊçÅ=>T¥+A©ô:ŸyÅ[·yšT§„~˜Ý'õK¢}ÿšôÆÂé[P§UùH!¶„»/Ãâña–núpÔÒÁ¯TùÊ"É-»~¢û.[Ë\§¬üÞÊŠ^ z¥µ†ôK–ð6Š¥UÅqéÌmœŠ„Íò°†›*žœ¥7~³VW WmPJÙ¶‹Žä8}ä NšªëSj—ÏÞVÕÒÞš¬Æ&ًê$ó”À… (@„.°á׫è×c8\]]±hÑ".\ |åÃfPüʉy P€ (@£ ܹs:uÂ… qÏÿŽ{¯0çK Ä" ¡æw­gêpT{{;¢F<ìÒÁÑM;UR•Ÿ¥!‹§bÊ"A±T ÷ù¹És I$7žÃسù€ÞÞÒwÙvgeÔôärήNÏu nD P 1 „9bçü‡èû]=‘#Gêÿ¶twµmo'櫆c§(@ P€HMš4AϞ=Q¬xQìœýCŸ$ÈqrP À›Q=·¬<‚Ý›NàþíÇpuw†ŽN(ñ^]EìîáúføŒ£Z Jš¶CgŽy¡ñÙ}ëPÆ{ «š3dIbïæÒœ‹Óš‡Ûq¡(`d»G^žzhÚŽ©~žÝòåËÑ®]»WJ ø•òrç (@ P€F3fŒz µºté‚ËOöâÒãF#à|)@$.ТÂÝfbҊ.I|М(@7+pÿ°2xæD¹rå°mÛ6Õ¢(•*UzeƒbPüÊh¹c P€ (@£ ‡vÅâý‘<Õ«}t§äô(@ Ä(àæ˜;T ŠV-[ÃÓÓ³fÍB•*U9sæW"Ç ø•°r§ (@ P€FšW¯žî!—;wnœz°·ýLý7¹P€HJËÿ؉1}¡ÓÀZšÿe…€45΅ @‚pñ́Ûn㫯Ÿ‚<CnסC‡W2Nů„•;¥(@ P€0šÀèÑ£áììŒÎ;ãqÐMº»Àhœ/(`ï»Oаô`”þ°†ÿö…AfÍiR€xo¿®. IDAT3vvöð9žɜӠB… X¿~=<<õ8ú÷ïóçÏcçΝhÞŒùK;*ƒâ—FÉQ€ (@ M`îܹ8{ö,ˆ‡WqäÞ"£pŸ (@ P€¯QÀ÷d6ž9€ÆG}„yóæéêâ9rŒ”0(~)ŒÜ (@ P€ €jÖ¬‰I“&!CŠtØçw†ú‘sŠ(@ P€xMN^X3í"z÷îK—.a÷îÝhÖ¬ÙK9:ƒâ—ÂȝP€ (@ M`þüù8v솎“Þ«qÇÿŽÑ8_ P€ (@7 às&#ƒ<ñÉ'Ÿ`ʔ)š]»62dÈðÂ#aPü„Ü(@ P€ €ä?ÈǍw¯@œð^eDΙ (@ Pà ž8xàßÙÞèØ±.^ŒˆS§N¡~ýú/<Å/LÈP€ (@ M`á…8räŸÜûnÿŽÐð £pŸ (@ P€oPÀ÷B:„çK P€ (Àö­¹…êå[#$$ä…jÇ 8\‡ (@ P á ,ZŽë·ýŠ=ßIžƒäÈ(@ P€  #píâ]\Ȋ6Ϳ Aƒ0pàÀçž;ƒâçŠã† (@ P€Føâ-Q€²J”ÏcŽ©sŸ (@ P€ T`ù̃ðÍD¬[·… Bá…Ÿk€ ŠŸ‹Q€ (@ MàÊÕËhÑ®.úOúŽNF›>çK P€ (@ï:ÉË"_¶8zô(5jô\#ePü\l܈ (@ PÀhCÆtÃõûgñy‡ŠF›:çK P€ (€ü}±vÞQüµœ¿í‹Þ?7w—7; (@ P€QNŸ‚TÁo!{†üxøð!ªV­o#Åñ&ã (@ P€Fó[OìÙœŸ¯eŽ©sŸ (@ P€‰@Àç‘?ö¯|€N_ôÆŒyóйsçxšAqŒÉž(@ P€ €Ñšv¬‚ogÁՊmêœ/(@ P€ @"Ø8ï:·ú˗/Gݺuáé鯑3(ŽWŠ(@ P€0šÀ#ÿÛš^§2º ­‹tSmúœ/(@ P€ @"8Ÿó6Šgª;wî W®\(^ŒxŒFΠ8^\\™ (@ PÀh›÷.Áà!ƒ1pJK£Mó¥(@ P€HD·®=„ßÉ(Z€(nݺ…êÕ«Çkô ŠãÅŕ)@ P€ Œ&0dÜ7žxõ4ZvýØhSç|)@ P€ ™Àæ_ïã‹Ví°råJŽoß>^£gP/.®L P€ (`4m*¡ä‡¹PŠR!£Mó¥(@ P€Hdg7Û¡ìÛUtŸânݺÁÅÅ%Î3`Pg*®H P€ (`4{޷аM5Žï[^™ØŸØhçŸó¥(@ P€‰MàÉŔ¹—>>>(W®œîUׅAq\¥ž(@ P€ €á¶í_ƒû¢ÿÄf°··7Üü9a P€ (@Ä%à”V>Dþüùááá¡Ãâž. Šã*Åõ(@ P€  '0~Ö ìØœíû×4ÜÜ9a P€ (@Ä'àhs|ñþûïãæÍ›šS§Nœ'Á 8ÎT\‘ (@ PÀhú4‚[ª0Ôl÷J £qŸ (@ P€ KàÒŠ”È—§ >¯Ú1(NX瑣¡(@ P€H ááašÑô=|\ï/“;ŒŠÃ (@ P€ @ÌÿˀT®™°{÷nôêÕ+Î\ ŠãLÅ)@ P€ Œ$pûÑy4h\]†ÖEÚ )4õ7>×qý— À/œF7¶Žeëª#˜9j f®ï'gÇ7>F€ (@ $Tð;Ùpãd ŒœœÑžqc€M›6NCeP'&®D P€ (`4]Ǘ£W÷~8¥Œ6}=ßMËaæÈÕèós)™óµ h÷;.žº‰Ù[{[¹tÖvŒë·KDj¯¯m, ý@“/áç0z~{€ðtOèÃMRãó÷ ıœ‘9GZdη?À“'C P€ V YhVlYx ™2eBɒ%‘/_Ÿ8•Aqœ˜ž(@ P€ €ÑŠ/„¯Ã·#mêÖùv®3Çö]Ä׃ë n›÷_›Ã÷ÿ›…‡.aÑþÖc.ùu~ù~)ælëƒ,9Óœ¶±$äø¡F០ůz WÁŒ yžqÛýۏñuœ úš{·bÁ8mó&V EûãpæØ5ØÛÛ¡z“2è4šœ]Xíþ&ΏI P€‘Ü=±}®7²gώ̙3£L™2q"bP'&®D P€ (`4Þ?¶ÂýwѬse£M]Ï÷ô‘«h÷ÙXýõ؅íñv¹Œ¯Í¡ß¿êãÿµ€õ˜‹flńË0wÛw¬Þ4«ü9u &Yw,Üû=v=&.û…ßɁswá矋‘¿XVŒšÛ.I„Å#ºÍGHp(úoö"Tܖ ސ€ß©œžwã \\\аaÃ8‚Aqœ˜ž(@ P€ €Ñj7«€ªMJ `ñlF›ºn7!m'jµ(‡®Ãë¿öùwo2OúaêênÖcÏÿfüžkNÿ·d.±Ž©w‹éptvÀÐmb]71®ðÇ/Tÿè50¹>ªñV‚Bxx8þYzßΧ–!¿ú[VÁՊaðôV v^£z,ÄÖÕG°òø0ë÷n9©†ÏS(³ûŸ­§ñ~Õ¢ðH™8+œ¿ý| í8‹.Rí5ìŸ:WÎÝÆÙÿ®ã£šoEûó{ò80 P€p~PÇw_Gpp0Ú·o§Y3(ŽW¢(@ P€0’@`` ªÕ+‡vý?E†,I£R3>ç¯c­_pûº7~ßÜûTF~Ó`¢îÏuŽ{֘uMW~ŠS(5žÃlœ>zs·÷ÏÔźïû iùáÖV yЇw‡œOÏŽ˜²ª+ÒgöŒqž_Tù çOÞ@¥Úo£ÿ„æ vjÒvâ‚zàâ‚]ý"qûÚc‡1)•GvŸ×çhôü¯à䜸zwk4UPŒìè`õÖe<ôöAXhÒeL¥oÖ|Ó`ï:‡&*¢íwÕì¹âÀ(@ UÀ-0¶-œ€ÐÐPôìÙ3N ŠãÄĕ(@ P€ Œ$pïÞ=4hù ºÿT/Iô}Ï¹“*ÉmGß_š JݒñÙô¥­+AurU…9böÿ¬ûœ>bÏ܆µgGÄé8#ºÎdž%°þüpptˆÓ6‰e¥qý—`¥ju0kc¯߯YZLŒkþ܃¢¥sbäœv12WË×þ~Ahð¿ è8 V‚=%œšOÇÍ+÷#µG± ¶MåQȞ7=€=ÈÞͧðEÏjhÒ±R‚‹íÀn_ æå[׌õ™[Wœõú‚C¬«å/žSUètÏŒ°TW[Zp$ŠIr  "Ì!=ÖL?ywO¿~ýât£A±A.N“ (@ P îçϟG›ÎõÕÛÇ[Ä}£$°fpPZUüÉÕº€ï­Ý™•%h“¶ –å—þK±yÅ!,=<8Nc’þªkîòcCÒ3™u›PUyG…aé³xÆéŠ8ì5®tåüŽ®4õ¿üíûÕ|G~±C‰»Ï#?€LíãŽ*fûaaáøfX=Ônùދôn-ÅgŽ]Å¢ýŸ:ÊÕ wàæî‚ŽR"Ð?!!¡o€2?ŸÓ_5Fõøó©Í€zžà[ِ·hfÝVã­²yTUqJëzÒ&ÆÕÝ9QVMÇ׈ëS€HLövŽØ· òN¹: eʈ»Ÿ5ʼné s¬ (@ P€¯E`ëÖ­;ó{tý¡ök9^B9ȟS·`òå¿Ž3Šª·ÎÇŽøû"@U~zŠMãzÒ§uHÇ?0hZKŒ]./€mÂìŸ7`㲃W`é  CÿšH핺ŸÆe‡âòy#=ÌL‚ßc{/ŕDÔ Xª?×-ڏåì„÷Ý'èöC}Ôl^NW}ºº9ëcßž|Mߢ*_s¡bÍ·#Íë‘zÛœT(_<}î.È[$3ÊU)üTŹT`JSÈ.ՙƒ;ÎÆ“~·ž“>ŽŒãqtàÖŽS¥g†Ø}ZÍÀÉCW0g[Ÿ§Ž×1Êñ6¯8ŒíëŽ!gþŒšÚ ”5£[b;_AÁpR§–ùþýû\»pÍ»TŽ5Žz<¹QQ%—é­±ÒÒ!>軚Ú@H¥õ©ÃWÕvžø\µCø€~©H‡ýKÿãÿö_Ôã͚;ÊRô©v1];Öÿ‡¡æèðWö1æÏöÚ0Yr×8ÿïÜpËfïTx˜~h߇Õ#÷˜–pÙç±?Ò€øxÖÎ¥JLzwo_÷îßyŒ|E² „úÝiØöC] l»œ>rU¯#7‚²çIžî‘~ny`€Ì¥€ †å|æ8åAh«æïVnöhùÍÇ*T­‚ïZÍÄ®'ô6ÖRÞÚþÀ¶3Œu¡Bîfå¬?Ïe£Á*žßŽìu{G§µQ§UùHÇŒpòf¬ç«kÃIÖÀtÁä͘2l…ÞGùOŠ`èLӃ¥šøî‡‘‚_yڄAËpîøu€MŸmû|ŠÃÉê…ú"WŒøõŸq:ϲҖ•‡1ü›y ˆh ¯ûµ ÞûžˆÞÏ¡g1ö»ÅžrîN€ýʹ®ÙŒ¬®ÎvvuÒíbº&ü|Уé4HK ÛE®çìùÒëОFÓ2ÈŠ‚Xß'jœk`.7W€2~͟{#mû÷‘Áú»òОŸz.Ô×ÜOóÚ¡äù#­+ý›×«rÉ"×åÜ õ×rClqș?ƒ~ žŒrMÿ¿ßTÏîkÖ}I?ñﯟ £¯]Œ‹LÙÓèqLTçç¯é[1g_d̖&Úóq÷æ#U±ï®í^гüîq¡(@žžÍ 7/>Aýúõ‘7oÞXwÈ 8V"®@ P€ (`4É“'ãÈÕuøŒãÓa]Rµ`uÓòC˜œ¥w¬ðÛ³é$zµ˜®)Vm5¥Tv®;^70fA{də_|üž<òÇ·#à“ŠþǝjÇ‰ƒ—UK‰AÖêäóôTAëGø¢G5+wÏæÓàïˆñK:ë׿Nø¿ŽZ«ÃV7'ªÊV©PΞ7ƒyÇôùK·ž°,~Éþ*ÖzÛZý*•¥r| “·¬:¬>v™s€ÁõK÷U¥gUÑÜP÷i•Y€ïlï1Ÿ«uÒª@ñ<LÙ¬ªS/¡U·OôGûê?ãäá+1ö×ݶæú«Ð®Lłد‚_©\öLç?§l±[ö?wûw‘.5©Üý_µ1°w°ÃŒuÝu˜mYâ3FyØZ¿/ӛºšpOÆ-}©¥·}¿hôÕGúgÞªò4.ç«{“):|ýZh7K·ùó$}†ÿÚ÷œ~ðن%ûuH»pÏ÷ðPœ§åB»OÇÂÏ'Pšø"…ªrí7ŸŸüd4Þy?Ÿ~\\γ\;2ñhûÝgš­Bû]ÿœÐs¬Õ¢º¯¯žfz ž,îwS×߻ĺ.Sæÿ>€ªÝó`” fOºë5ñàÞüØmv«ßƒüŲèjx¹yrýÒ=…ªÕ?þÑVØWUUî/æªñ>-gè›ÒÆ¡ƒê¿œ¿XVÝ 8}&OŽüh„®D·šZW‰‹§né›'rÅv±„Èòû"˜kPjŸ™1nQG*‘CØ»Õ1~ÿyœþÝøîç&êæÂTe€ê†Dá’9TujÕŸÄÔ»{ο}t…qt‹åºšºº«ktKÓòÃԃK M÷j/Ý9ÚòE P€ˆ—ÀõCŽ8wðêÔ©ƒ¢E‹Æº-ƒâX‰ž(@ P€ €Ñ†ŠÇ.'ðY“Èo]Oª–ðRª:ãòÐ-i}ПÆÏ*PöĂÝýuØ%ûšR÷€JcêA;Š÷_X>g—µ×¬ŽXúÛvä,UUK€lyŒT+‰‹:lM™:š«%ôª˜­»ýštˆxX—úT 쌑*€“Eª×,Ü«F p¥šRªKªQ*t%P“ž«²89;`с‘zËë»7@ï3tų„›U–B‘ ÑŽüp8:9êöó&mÄŽá«TÅq&Õ&¢c€v2V©–Àwގï0º×"ìÙ|R…ɍQEUDK .y…ÏŠëqH@úÕg?k# öê—d=¶TÑNø»3ÆöYŒ KšÞ·"µƒJÔ¿ߎ_–tB‘’‘Û‚ÄgŒ3G®Ñ-8dé=ös]]-Aí—U~Ò-9ä|JÿÙžž¯¯ªUëMÝWX*b¥mÉ)u}ŒRþüV®SB±1Dµk°ŸÝMV¡â9tZ×Z-ãéÙl*ön9­æB…Ìt Ûy–^Á ÷ý¥©Ÿþ,‹Žñ(^&·® ?¡Âß5Æik©¢Í¥ªÇm‹ß÷“šëë(¶kB¶?iŠ_)̕Êé[êApAúzÝë/¬_ŒëÎý©ÔmŠ*öåZ_°»ŸîalY–ÏÙ©~_© WUÖ«›r£ÄNýoõ©á‘ªõåmöÁ Ó×Ç¿kŽbp‡?ÔïIEõûRý©ž$4–°ÿæÕû¿ž³®—Eú\·š`z(äçí+ªwN<œ­üì·ÑkñûØõjL_ë:º¥¹OFuF~/_…sŽå‹ (gÛgÂqlÓÔ¬Y¥JÅþßµ ŠãLË)@ P€ Œ"ðí·ß"u¡G(_µp’Ÿòýۏ!Ë-µ©l+UŸ5ùSªjö+U=[£iYÕǹž LA˜<`MZ,šù/& ø[¯R+n“÷†êj_y>ÞÙÿ®[wíŠÞr?`J Ua[H¿&ýa«æí­[؆ÖHJ(gÛw‘Ng™‡„ÄÿüWGõ»Üúe¹)pd÷yÔimjS"ïžuõ®ÎqúeçJ (ðLïØõ—7jÔš÷ß?V)űq P€ (@£ ŽiÓïÔLŽ"¥r$ù©÷j>‡vÅԕ]UµoäJKÛÉKµ€„ŒRõ{ö¿køŸê=,•»ò6{ ”d‘6Ÿ6~“/×v£ç·×UŠ–@VBÈ÷>)¬ªnOA¬%©ÄRÁjY,4kض:|_ËúzÇZ¿èêÜikºÅzNdœNµÑ=YÇ« ÜAf«‡èùêØÉø,‹%“þ²¿mì©Û"ȲzÁŒìþ§®(>~à~øf>šu®Œ/{EîY-îÀ¯~GFK…°<ŽoÇúãøsO]qí}ç‰ÞŸŽtذô nu }sËV.¬Ã¶.õ'j¿ ËTÅŠ¹Å€ªUG+Õ&@*P§¯ûÖúà=[„u‹öÅyŒR--7déûKU…kj"­<ŠX­«€ÅOôØÎ—TTËÃç€ÂÕ [ÆÕ°ô`]Í+û»tæZU©oȃúš0"Rg Çè:)S%à ÕW·³j"y“±-r“CzMw\õÚ|íêRñþyÙaúš”6¶Œ~ñžnr÷ÖC]mŒyÅŽÆtMdə{Õ5,íPŸý±ŸaÝ"öû¹ïbk,•ÕÒâEBṋTQÏßÙOU¿;¢CÍqº‹%8ç?®ÁŒ‰Š^Äé3K%?Huøœñÿè*øÏš”yjŸr}öh:Õj-É¿þŽVÌrc$w¡LX4ã_ÝeðŽVÖ>ÖIEþšêQVøÔT/•úUkK0/׿< PÆ#ËËvŽíüóç (³€üwÄÚ)×Q³FmT©R%V.űq P€ (@£ 4oÞŸŽÍ¢•”—µªuÃÕk5аKæâà%ŠÍÒ!åï›{©ŠQÝU+©&•Ÿ¯þÁÖ|I6Qœ]]úÕʲD=àíõ ·¯×AÝ61W³Èç>ÎÝS·W»°ƒ•_úÐWý€—ʃ¿Ô8bZ$„n÷ÙX]Å) ;£ã¯ëMÐ}Œe[Vª{Ə«uÐf˜Ê~åkÒ+WÂÚ*uJª‡ü Sáê] ›§PfÝïõ° zå8ÒöBBbi'ayHŽäžuí~íá}ëPmç¿ÿßÓª·îTˆJ¥­e‘ù×Pó“ðNBÖ]Uïè‡t²;º%PÙÇeŒÉU^9gOäªt"' IDAT-’Y?PúWVýe%œ” r`ÖŠžØ¹áxœÎ—<œ­Fá~È€t&Ÿ“jlËÒï‹_µÏBUi*œˆ?+øé…ª"ºvñþúÁvR!-ÕšVJËé,¹<žpÿ¶Óº‰m‹†èæ.•ÈU¶ŽYx§|^Œ«ÜŠ¿›y gŠÔ¶¡ß—¿bûÚÿt{YO–ÓÇ®áЎ³êf†“ê)ü?}ÍÅ嚐_Âviò¬*oÙ¿8JkŒž?5²Þ ¶-û¶žÂ=õGé ,Ÿ“þÔuZœ§ZqÔÓã’êõR!tP z(ºy#כÜ@ª^iŸ!­6äAwûÔ5$ÛJïm¹ž£.ò0=¹éð䡟~ОXKX,”V:©›8ûÌS=€š¹çÐכœËb©·ÜŽ‘wÈÃåÀ³ŸÔ«Yªœçíè«‚÷²cüEç)@ P N‹FÂgUë jÕª±®Ï 8V"®@ P€ (`4êÕ«ã‹!¥ôCª’ê"AWˊ?¢ô‡thÓ2¬ó\Ý7W©èÍW4 Z|8B?ÄLÂâ¿©C«ÉCVèVÃg}¡^—κËs'®£­ª@N£<'­ø&Ú·¹Û_ªœ%L“PØ6[zÑZ¶1?ŒEªg—¢ªLëXߒ/ýSGª*ÙKgn£Z£Òè5º±n°fÁ^ÔV!m•©ŒEªLK}5›—ÃÅÓ·TÕô:ÚyŒ}Uxé¬ûœÖlVNõ.f $7©JËÁªªX–Fí>Äçªw¬T‡ÞV¡q³¯+£õ·‘ÿ@“ŠÍòªÂ:ejS_g˲pÚœQ!f՞AØmD}}¬˜–žŒÑR­]»å{šÑ¬¬nq!çPæ^ìݜè8 ¶>·ñ9_RY›Ú+¹ f#‡Øâ-×Íì-œŽÏ`UÕýVÙ<ÚÓ&Zæ#a{ÿ‰Í¬AžT·®4 ƒT›ieÛrhçYÕêdۊmË"ç(ŸzМ<ŽNZ˜HXúÛèuº/µ„®Ò*#{žôêú(©«q=R˜ªÉãzMȺR,lþuôZðJ‹–AS[éjûèyàÝÀ¯fcèÌ6:Àµ,r>¥z÷ԑ+Ú¶’zc=u“åöõ‡ú¡RÅ,ע޷hôՇªjœfŽû—6þ¬$(íWäÁ‚5š–AýÿU°¶˜‘€}hç9º*XzAƒ±¿S‡A1¯& P€ (@ Ø„„„è>nÆŒéÁeI I‚»SªâsúÚo‘,¹kŒÓ“þµÒŠABå^£éàO‚¬ëÿÓÁ“%è”*I ¥25ê"öZ1w—®:ì8 JšªNGµŸ«çïê‡rÉÃð€šV*SœUïÖcû.ê@ØÒ3Yª+wýs\? ÌòÀŒ˜-˜m…«¬+Aéöuÿéc[èøžWi ÁjÔ`Ù²y0™ô¹}¿š)̖ªÛàÀP€ðt×¡BU¥icÕ.A*`M}º¯nL;{ÖÅPªµë¡zIª­œ«0Pªv¥EˆíŸó¯‰©•åÜH0é}÷±ºÒªV…žê}몷nM"ÕÎq]€òý?Uu.•¯çNÜÐYÌ[8‹zÀ^§H×€Ì[>¢»Nãz¬—µžŽü¶+Ž÷¿7rm é8mzT}fµy\Ç)}¥=Ó&jõE3€òr€U碢„Õª \ziÇeIHÎq/ס(Tþþù<Þ*R -[Æþß Š“êUÀyQ€ (@ <—@@@jÕª‰î“«<ž=×èFÒ¶€ªŠÍšÚŒŽEzOž :K€$A«|¶,RáY§UùhÖö:ƗЎ!aï²Ù;ñi£wá¢|÷2KPµÿstûN çËr}=+ÔŠ/ºé}x×9ݟ8¡.HK˖„ì˜Pí8. P€ A`Íäkș5Úµ‹ýÀ ŠÂã(@ P€ ŒÀãǪ÷hƒúèûkµ3Š€4+çncí_ûU¿Ôû WAuj+K÷_u÷ˆ¹²9)9Œ©¹|œ§§niaÛ9бð|œÜ3u÷æ#õÐDWkïåÎuÇëJbKÏߗ{4(lžuž^èÒ¥K¬ Šc%â  (@ P€Fž~ý:ŸîÒ_‹ù¡kF2á\“Ž€<ÜLÒ(oãòzä!uß4˜š,7~Igý`ºZÅúë>«Çðë!F P€IQ`÷B8Ã]»vuz Šc%â  (@ P€F8þÅ°‚û5Ÿósǯ£Ýgc† Yz.?Ík‡’äOŽóâÀ)@ P€ €Q̀‹7bƌ±N™­'b%â  (@ P€Føã?°gÿNÔí–ŽFšºu®>ý±hÆ¿êc+|è×ÓeL…òU‹ Â§ÅðVÙ<†tá€)@ P€ @b‡Ù­XŽ3gΌuè Šc%â  (@ P€F˜5k݇sÀÉÙÑHS×s=~àú}ñ+ÜóÑßW¬ùj6/‡âerŸÂÚp'L P€ @¢`PœèO!'@ P€ (ðŠ€Úâä飸žmfžž9œ©aŒ±ãvš9'^FêtÉñý€ªz8÷ L P€ (ðbÿˀ +v`„ ±îˆűq P€ (@# L›6 ç/ÂG­œàæîb€©ë¹Z‚⢥sbü’Ά›?'L P€ ’’€÷Q/¬\މ­'’ÒIå\(@ P€ ^ÀäɓqíæEŒ×Äɒ»Ÿžƒ& £¬[Ž?|3_šZ£Òè5ºq‡B P€ (ï#*(^Ì 8>f\— (@ P€Z@ޖw÷Á ”ª› ÉS¹N¥O«ØõÏ ëŒGÌþe*2œ'L P€ ’‚ÀýÃé°jÉfV'…“É9P€ (@ Œ^qãÆá‘ï=ŒUÓ)=“œÞƒ¿á£ÝºêÆe‡FE›îUÑ⛏ßðÈxx P€ (@çžw(V/ePüƒ/عe}%ƒµ\:¶—Pt¯ÉÁåõØÖ‹i–}ØNäYDz]W֑_‚èŽmÙ׳~¬¯‡‡êUMߛ],¿6ê÷K¿nù^æùŒu,¿ŠááaÖiÈfúuù?f#ËöÖ_]óJz.‘΀ÉÔ4GÓ,c¶·³G˜ú_Ä1#¯c9ŠeŸ–íô~ôtLǒ±D:ŠúÆ4T“ƒ¬oúÚNýÏlc³Žœœikëúæ¹FýgɲÓ?Xÿ$Ù[ΝÙG~nõ2[XŸ·®«Ç¥Ö³3Ñ²žŒÅ|=èaØ|¯Ç®·1mkYÏâjù‡Ôúï©Íù·ž{Ûs£üaï ;W„«Ï°wÔ×vn‘Î ¿¡(@„)0dÈxŠK¯‘>³gÂä+•Ž›öõ\„……cÀäæø°ú[¯øˆÜ=(@ P€ À«žœßVîÀŽiÓ¿ àW±Ï€€øúúêùZ>õ÷=‚Ïcoøû=ƓG÷è‹À?ø"8ÈA* FPPˆ9³ ‡úoz}9bÿ±‹x§hS¢§Kh(Ÿ1K@èê℀À`shhjJÐfÞ§9 Ž~o ÛÔ:š"D9®9TŸ$ԓÅę¿±—uôL!Ÿlïì舠k`i òÌ–Õ­£yšúšæ¯ìÎÚÞ=Ñcµ‰Bmo¬8Ø«°U‚ŽŽöQÛGœéb £Ä·:€Ô㷃ƒÚ(Ô&TÕӌá² $eâfœFÝ>ê K(.c }úPLw…l`™wŽ‹M&n:Š©:š9‡„©‘ê,=bÛèö#p ‘ò ± ám"bó.,ÛËúj÷úz •ã˜VМ)Ù6mµe.¡ò‹ œâ«O‘^3SƬÆbZ-bKo™’‹“üÕC~¢œgóÿ.ãÝ·rÁÁA8:Øë¯Ôu쬶wusƒ›|ž{À]}$KŠ>R€BŠä)á™:-RyЃ»G*ž©,3\Žá7†?¢(ðjˆ YRóÈ]dȚúÕ$ïõê…;h]iB‚CÑö»ÏЀC¥T°ë®‚_w7gUÍêð&ŠÀcR€oH@n*Y‚ä‡Oüàííƒ[÷Ÿàžú|ÿ¡Œø 0(Ϊ_€ƒªVΐ6%2¥O…¬Ùs!s¶üH›1’¥Î©*‘ÝßÐ xX P€‰[ ((H¿-ÏÕÃîyn sÎŽ‰{BÏ1úåsvbLïEºíÆo{šwºD.:xŽ]r P€ (@7$p}O l]·—Añëò—@øÆ:Ÿyí<|œU(šú Tõ ¶SœƒÝ]TU`2xªªàÔò9e2ý™ (@ø ªv0O|pëÎ#\œõ×Ôǭۏð𱟟¹$-c²e͈õW}„ƒt{ˆtiRÀ+mrx¥1}Äv"žc܄ @$éù,-,._¿óWîâÒÕ»žsï‰î³*¥òå͋¢ÅßA–…à‘&ûóú¡(€Ž›4i’Ší3_DöŒÆlïsëª7zµ˜ŽËgoëÖT+ж}ª²Âš¿( (@ P 1 \ߝÛþ9€ &ĚO2(~æ™VÝjƒÁõǵËçpéâ9\¹|Yu9 QŠrÐýkƒ‚M_gJï‰ÌR"œzx2w—Ä|ýpì @ðøŽj]qQ…ÆÇÏÜÀ¹‹wÔÐZDž äÄÛ%J!»ª:¶sÍ úËÛ«czÜb‚áT(@ øðc~·.ãDyF9h P Ÿòpâ… ê Ø?Åqä)œ9Ÿ»àú (@ P€H0ïÞz ãÆSÏ0rŒq\†îQ,o-”€øÄ‰ª¿p*„{ïÃÿÙ» °šž·{l±»ó¯?»»»»»»[°PQ±»»;±EÅÄn° PüæŒßÅ¥ÜX`ÞçñQÙ¹gæÞåž9sÞwïß#CÚ$øOÄJ9l2kZuD! hQaù>œ‹Í3/”)W•ëtDüD‘3±SLjR! ^¿~;w"QŠØøç²åMœPM* …€B@! P(ŒƒÀ“3fžpJÅ¢éêê GGG(N ~ž¿ƒçۋÈý_rdÿ_äMXbœå§jQ(""E2Œƒ'œpûþ+äÌU5êw@Öù"âP՘ HŽÀ‹/°ÿ~$L c:"{þô‘5|…€B@! P( ðŒÀ‹ ñpá€f̘¡<Šu'ÒÅÅððð€™™™$Š“'ŽœIŸ!eR•.â%J‡: Û£P±2¡ÓžjE! P„Ϟ=ƒ$‹‰÷ѯ G ¡ÐªjB! P( …€B@!2<: —íoaÖ¬YÊz‚¿v—.]Â÷ïß+V,P)’;wnÈ1¿:¿=Cf&T­ …€B #pùú#ì9r žQ¡N£(SŸJ­šB@!Yxüø1Nœ8xI¢ãMÔËÈU0cdzˆóû7ôn0æ#j£X…!ޞ©5°oÃyßë›uæˆ5ªQºÙ15 ˆ‘šOŸ˜3jZõª„Ô’F¢‘û?TuÿDú% PDžŠ ûۊ(öôôÄÙ³gÁ€$ޘà/þ @¡lñDÒºkÀ/÷H³(Ô@ …@H!póÞ ì:| ŸŸÇFãæ]Q¢LŐjJÕ«P(B‡â̙3’(~íu¹ g ñ6#rÛWœÆÍ+1j^[Üœö ÝjÏD“ÎåÐ{\ƒˆC\è5Š>šv-nµfàý7lœ4:XÍEfL ÎËË M XÁÈÙ­P­q/3ޜ!m†—2o^}BÓ¢ãЮUt\3ŒtÛ(ýܹÚ³,l%Q̈ŒÏ$£©*Q(Â%QìY‰b’Â'OžDüøññõëW$Ož%ó§Btwa1áù!\NšêŽB@! O\qz‚Í{."M†œèÒwŒ|«P(ၻwƒøI£ãñ×ӊ(æÄ‘Ô$Asø¡ l—ŸÂŒ±»°x߀H‘$P#Š;­‰¶}«¢Nn ä-’“Vw ª‘SC€;¶ë*¬z­•Eî鏜ý÷7ޜ!m†—2®/? Y±ñhÕ³ÌGÖ /Ýv?ÿþ•lðÄÙ©Ò%Á[—O‘ò™l U …@žEàÁ‰èžzþžŽžˆTŠb€qôèÑåŸÂ¹Ó qÔÀ7áv2UÇ …@xEàØÙ[Ø~ð&*×n),):„×aš~+‘ Û·oãÞœ{ˆû¹BþY"Æ.ÕÄSm»“°iÑq¬ži'•|šªÏž­™VmT¬¶*mòµòI_æjYsQ IDAT†¡Q§²Raœ0Š¿~þÂAâWªWI’ëßÔ¥uȋ'oeyS bÞ¥ÚtIÒv¢x¥œþvÕÐrŠ:Πöëõ³÷hQr:ªöªµšpwÝ á >¶û”ëkb¶åöHùL w§:¬P û‚(vŒLD1“Ó>|)R€ÀóçÏQ©L~ü/±« ˆ]ŒªªH! P(‚†Àҍ§q梁õ±D¶lكV‰ºJ! P„NNNžsçÌ÷?G’YC©åˆÛÌœϑ-o:éQÅ*æ€ÍZsœ×HežPˆ/ØÓ¹ fÔ[>Ž üøæ‰6å&!f¬hXqx(b™Å𷠆– íþ‡F{ïœ– '7Aœ6¥B£É0oƒ÷ÅìQÛ1ØŠ)êŽ*æýQP(a€ó±šžvñŸLf5jÔv!Ü&³óôôÄÞœ{#F ŒyýU‹%Eš_ÂoÕŠB@! PˆÀ¶ýWpÎé †XNAš4i ŒJS(¡‡€££#?~ŒX ŒpûÍa.“-ôD-Yõ\ƒc»‘"M"é#K•ŸŠà!°qÁ1€ßã4Ñ Š^>y'¬1&Ê9è2¬ø÷/ßA?×âs¢hyŸ§€¬ûm€íe™˜/M†€p~·ž?„X'Q¡N-8ñþ$ «Ø0ÿ(–LڇI«:£d•ÜvÃÐra5ސl÷þ­ҚÃbN+Tmä’¿l?Žëþêö]Ú¿€L—‹öö4'Bg՞B@!`úÜ;·®>ÁôéÓ#&QüôéS=zIÅ/%±œ^ Jq6PüB£B! P(LÇÏÞ`Æ*{T©Õ ·0ý«*‘ &²£•‰b§WQ€œ²Ì ‰à!Æý›.àò©»šÙŒJWËÍDª:·¯89£w`ó…QH™6±¿c¿xüìïáõ³xzߏîŸöS.fìèhØ¡ŒLÀÇD„¯žŸÇëçïq[Œ`~uûá§|ªôI0}cw€Í”,ÌðþøÎ ­ËX#G ²/…¡åÂl !Üðí«OÑ£î,Œ_Úekæ áÖŸú¥“÷aýŒ£Òî&oÑÌaß!Õ…€B@!F<:S|ÿ߉˜Šb|úè>»:¡Àÿ¢#G–Ta³jV! P(‚ƒÀâgà-l‚SºV! PŒ|ùRÅמïG± 9ŒZ¿ªìßüúåÇs÷qjÿuܺòÏŸAæ©1}Sw˜Å‰åãâÀ” )ÜI Îµw®=ÉŽ£!Gþ (_;*7(€·IÛ§p`ÓE,³¬·¬!öm8©ÂGxîöÞÈ[ì~.qûü us[JŰnÄ6‹‰͊"wáŒÈš;2dI.}•Xí–%'ýԓ«PF鵜=zd͕ “Ä3€{~ÊfþÆõX#ډ‹þûÛÖ̑۰wýy,;4H®—€ÂÐrAP8žÈáÌ= j±H’é…ËÿŽ“å]¿øPªË‹”Ë®­° ޛí*LF± 5zA»°ê†jW! P˜w7.?Ĝ9sôž®WÖ'OžÄ‡×wàþú2êW+€8f>Y4 ôU' …€BÀ`Nž¿ÛÃÎ;i>’¥P•§ *!†À¥K—àêꊘñÁñé>éߪ"ä ižbêÉÈÞ»þµ“#є8yØ.?…ÅÖ{áéñKgG›uæbó!­÷å^^^Ø·ñ‚À×Oº"žH2Dòj Ëû˘I.Ç÷^‹ÓbŒkN GªtIô A}®P("4wH_z€yóæégž!Šwî܉ß?Þ!Ö'Ô(°ç”Þ« …€B@!`RŒxý6‹ s·(P¢†IõMuF! ˆ|\žpïß¿—DñåG»P¢R®ÈB(øâ‰;H“1)ÒeNŽ£;¯`|ïu²eT!K5w¢€~Õª)Ëúš'rš|’¥Ž&Ѝ›1©ÿFù™Fdòó͋O`ф=R}K²óÃÛ/øéùKžÅ1djsYÅæEDZP”É–7ÆÅb*ÑoW‘ ŽDØÖ¥'Q®f>XÌm šû®GÆÿR¢MŸ*FA\#GÍkã­hÞ²ä„$lÙúûŽùGK¥îêãÃôö6³,l1fa;T¬[ÀßòÄ«Wý9R ®²Š€! »ÀΉס­— ÓþZÁ iœXÚb¬;=Òßõ¢õC_¹w.Ÿ1 Ù<}àŠ1£!‘PJsÝÄËì!ýÿRx‰Ä5 ì£ê¡y· òçž?…û6.<·OßäÜöµj(78†µ[ŠOïÝiIS$­Wê¶))Öyu©Þ֍OïÝD"Ÿ˜RKbyç{ä.” åÄæƒJïK²eÒÊ. íãœëg©žuûüÝG]Ž—5·÷æÆ!‘X˜ë›™³ÿ=™ûëç/Xõ\‹“bs€Áz©fâgL¥ö®5gåøèoýáÝÜq|&íhûÀž{ýfŒØnÀ0’¥J æ+>Ýy%7òɄ Ë;É9$>î_Ÿ!q²øøþÍCÞOÜTiÕ«²Œ–›sF3A]3ŸÑN—¡OÃyhÝ»²¿ëÞHê? …€B  pûðoÜtx„¹sçêmž Š7n܈XQ=Öì!ŠŠm …€B@!±øöÝSDɒeQœI ªÿ™Ê#ÖšÕh SDàܹsøüù³ Šâ‚óŽ&Å2Åþ‡§>u¬b#}m',ë$‰®Ÿçãù£7’Xkf^;—EŒTšº˜²Ÿ„*Ž~ÞQ‚Œ‹Šœ·&ú±¯Ð®ÙÛz!‰,²œS‡l–1I²%³JRž$Âöݶ–åº×™)H¯ç’dŠ ƒnx£Ÿ/œ…VÐïyp«Å’ȮюloÆ¡m—œ›§}‡ïäŒ-KM ãŽVz»©‘Œ¬£~»Òþ–?žõ&Ø(?‹/FÌl%’䜕„:}“—$÷ŸϵŸNí^w3†oCïq Ѐs¹‹ë+÷íët«5Sø6»¢QDz’À寲›ñÛkL}™ÄO‹œÎaÚЭr=X‹äy‰á9±ßzy= Xú;Wš›N—K’˜X œÔDn~Ĉ–ÃÞî&º[ÔE‹}ô{Ê MR?u}7Œé¶Tùr-nœ4Z*µù‡ÑžSYôD4còÀ8žå’ü7 ê!S›aǪ3‚”¿*ža¹`œ²³Tëî^+ðd­oknZÞî Öz¹~x_ž;z #Ú/þá¹1qEç±Õ,O'‹‡ÉkºJ:‰ßÎU§ âú¶]+¯íÓh.n\|äÝ÷ž£ëI’ü󇯂>!œ„3eK…¥Â>äÈ̳¶âÚý›/`¶åvyÝú3#%yNLýô’Ö'Ÿ­[8—LØGâž fqÕ)d}÷‘ú\! ˆøܶóÂÍ+#QŒjÕ*č…Ò¿Cæt*rÄ_Ÿj„ …@dF`ÖòÃH:Zt(fi"3jì …@!`oo¯_¿ â_8o;ŠWÊF=‰øÍö¶ î_ŸcÍÉár°<ö¿qá1©æýæN’ÕLaåаc$L× †–œë…$Hä.Þ7ÀG$šÚ–Ÿ$ÛÚucŒ$‘i@Bø³ø»Zã"(U5—°ˆ#I4’ ºõ4.<îBÁyÐy²ILÖµóЯÉ|Ij:]z$Õ¡ô‰%qG.§PS/€¶nŽ(1ßQŒëúxœc8(¬&Ü$ìÉdwþ…ÍàM"IáEùQ¿ñ¢œ˜;ÆlK[A\Ú£ý€jR-nèüý«SτuA×ê3„µA̟̺ º×RN#`S€I„&]Ê!‹ ߌú„åSöKUñ€Õ]P²²ÏÓ+§Äê™vˆ#~{ý–VÝF֑ì U±\K\Sów÷E–œ~¯!ÙšÐñóoroŽ·ô¡f'i{úÀ ÖVœÖÊk’€ˆ^‚ª{^ÃuG•öªc”à­JO„ü;ISý̶ØÕÝ÷n<ÇÌ-=P°ÔRñŒÀj7ö8MðÞÄp<÷ý›Î—ãhÙ³’ôª& »qÁ1i»ÒŒ{ô°¬àTô¬7[*ÈglîB¥ÿó.ÇþŽÕÆ=Æ|•\“$âûŽÿCpëÆ†G±ÄzŸŽ6áýÇ͚‘³[I’˜Ï Ƅe1YéßÄ&Œ™ ß©ÜÞyÍʇ’|ê-b³çâ~À?ÐÔѺê}Ýr$ÝIŸ“ŠÏ1ïOb@Ë*ªßŒú(Ÿä Æ-n·Å܋±ÐڂŒ3‡œ`Ùy…\ûÃgŽô¯zF57ï¡°Lħ·“ª€B@! $N=qïú ̞=[ï•&Ióá¿~ýzñe÷õKÄDB³¿¿ é‘* P(áå›O#šPãt4ï( ó‡ûñš(á&Oæï¢ÑãþÀ©[$y¢"d˜6t‹ôÏՔˆ$eéãJ²N ’aëçÅÅãw€§éŒ}¥Ï­¡e“¥LˆÆ…ÆJ…"É%úŒRé9}Øo[†˜±¢Ëãñ$kIš2›í•±R z|Ï5ž<ÿ Žó§êâ<ބ. Èʙ†Ènî¿cýÏ€u¡W'×Hé)Kï^Z7H®êºRVC‚X‘hd,œ°[x*ŸðÓVÿŠ ±{‡œ§_Ü?¶O]kü9¶¯©Uµ~iÊÓVBuj.”³ {;'a£°cµC…:lחågõږ’v Œ ëyRáI¥§¡óǹŸSšÂ«O÷a„kËEòÃþ£A{ÿm0Ø®!åš'9«) Îܓ$,±+X*«ðÎýCBê-MhËÀ ñ$WiÛ@å1•é / ªkic±fÖaáœX*³Ç÷Z'‰ÐñB)«­(f'7Á¶e§€¥-hsBk‰9£v`ûÊÓҎ‚€*ÅZŒž/k‘NwüY­©v™ŒJ_n4-:LŸ8nI0áßÙ#7ñõËéç]Bœš Y«ŒHÚk÷éÀæ qÅÞYn®ÐjD×ë[÷:&F€×°FZë~vl÷Uaå±)Ó%Æ\Û>RyL¢˜Á±Ð‚†¶ Í3™€öh¡RÖþÏ9éXÉFàK ú'iígBÿÿÇà–‹ä&‰žÞ]§~®P(L³Z0X·Ú3ýØhVS„·lá²Ùp@ØKL¶UxD—GOau š*8o±Ì˜¹¹'Þ %2í rq˅Ñòø¥ ƒð?A@’dw‰ý˜ Œ ôãå&ýo™00ó÷àöKáw;Mªû™ìŒ*qóšÓQªJnIn†–Óü‹Ûö«ŠÎCjêˋ­÷áÏÒ_ž…PW3AÕñTŸ6ÖT\sŽ-?Yâ@5ú¡<æ$AË́€)H‚uXÛ%bsê·°wš+-=hïÁ68Ó7vœŒŸ:»Ê$‚ZB;Í?˜V ôÁŠåH± Ùá(î_ž^(%HÛ‚à%áʵµxÿ@靬%$"Tìµ[•‰ûډ>rNçnÿ“tî_A‚˜ªug§‚ mª K52FU1×@!q_QáË?™s€ö^Û/œEǪ6ðüñ EËg“~ÄÄäêÙûRíÎõ:kkO‰¡æNÕóÊcC¥/3×7}¢i­Â ’»AÑh ü²éQ=¡Ï:éçÌ Ú­%4k}ž×A©[]£P(û=ðàÖk̜9So7LŽ(^»v-Ÿ}û†ö5S#Æ/œP …€B â"°uï%Œ~=‡ÎF”˜fwÄjd …@X#pôèQ!Xˆ‰š‚(>zeœPÚ©S !5'„m€e—•Ò;˜*Dzšl±P’F i$»š`d29†v€<0eyÝõ 1ËÂOî»H¯ÞÊõ ¡^»R’4×c­ô€%¥©9덖ÿ ÿ?¹ï:6žµR¬…ãwËê{Œ Øÿ50؟?v WH¥*U¬ŸÃ²Ë üêS&ӂ$9“§‘L€‚–J_úô.90Їï«VžžÆ¯…šd4m'æ#„µ‚P`2*€ˆŠu H,é¯KÜi3%þÄÕ¥ï3#0óG…_¡FnÞ­¢$@{՟-Ig&Æó/Ù!ëg25CʱìS±&:V™*Ç4OؐÀ (h‡¢%V£1=}µö–ˆÄwTùf͕ÖÛ š$7“í=žõRÚBT¬W@&ºÓµh ‰Í ?êÙÙ¶œpùä=¡¢ÂRƒª]&)ü!HçÒÕþÚàpîQw– ÝKˆþŠ– À$ƒ™³§†uÿ Þ÷ÉZÎÕÁr¬‚ŠKÑrÙå: rŒ]…É"AÜ{¹͘ʼnœŽÛ},R³y1imÂ`‚¹%“öIë b¯…Yœ˜²íŸÂ¯šD5U֛„µ‹ÓåGr³†˜çþáu۔”ªf&·cÜtx,mLÆ,l/7H2Ÿ?~KússE z_xë& k*ÛýS+ÿs@Ÿ>ä3‚dºò7 jª¬B@! Qüð¶ f̘¡·»&EoÙ²?~Dë`æõ\oçU…€B@! ˆø¬Ûq?£¡Ë@aŒMe®Žø3®Fš[Ž9333‘Pó+Ž\DqmE‡æŒž¢ªõ°­^ ò‰„ I5’—ô·mf^ÁÛ"!0e }PIR­Èö: ¬.m'œùé_? -§]KҞI©ˆ¥_pYa9/aláßüOÜÊÜkpÊYÚk,öí+¬ÕC ]"Sß|iŸ“ §×°æÕ˜zhB¢XS “š•÷ðýÖìDtûÁòŽ“Ð,5hbÙy¥ŽöhÞ­ê‹ ªz¹¶o\z(7CxM•…‘\XڛĊCz g͝Ölj—“Ã#ÜŸúTxa>Ç«gïÄž~c²°ä ºX7ž@¬Â+0ôi8Wž@ ê:8Áä$©7Ø[HÏm …€B ¢ pçÈoéQ<}útœC2¢øÐ¡Cxòä šUÿ ~ÿI€ B! P(D`ÕÖ3â%3¥ &AŒ*P …@ˆ!`gg‡xñâI¢ØîâZI ©ˆ\G€Éó= #\ ÅT÷Rå” ¿5•ÈšJÜ÷Øã%ˆ-ˆáÖ§;wPªñkh{Á͍àXž`¯c€LšŒOøŽÓ‚H…B@! ˆ(8îù.lŒÞ†¢øüùóžtéUˋԱîG”yPãP( #!À_Þ§.>ˆâ%Ë rÁFªUU£P(ü"pðàA$J”ˆíŽƒç×Ècô*"TڞØ{ Žs J2¶8BOÅm¡ÒY‘¿D– %¯‹ (ÖÊ1BzÔNXÖ)\—{6œ“É㟺ýÊڄÈ.¬ŠÕô¿,)Âr°ô6¯9Cúô6é\.È]¡¯4œo_}‚B ž(i|iAÅx®‚Œm!‚Ü€‰_HûŒ–¥&"_ñÿÉÓ* …@DBàÊî¯xñàŠM›ŠwXa®(Ÿwïš&®T2+r&{¡·Ãª€B@! PDNÞŸÿ‚•[íQ¥fS.×bêÔ©z;ŠDñ»wï°zõj”(ô?”ÈôNtöï‘.œ=W …€B Ò!pÿ±+vÙ9¢a›þ"YŒßD=‘5`…€BÀèìÛ·)R€Šb7ì9µ•…/§ …€BÀ0†µ]Š«çœa{yl€>džՀJŠœ~kçŽ@f‘„Oô†¢æ·Üç_Ñ¥ú4XÌi-O šP( ‡îpyúSŠLÑ;¬0%Š™m/Oötš’Ç]pÄ¿ôvVP( …ÀY‡ûžzëZ›[!IÊÌ …€B@!`Töìك4iÒÀ+ægì>¹B$oRD±QV•Ehv¯=‹#¶¡÷ØúhÒ¥|„«) ÎJ$<¶ÛË ò“`Δú©ú¢P(aƒÀånxóÌ“'OÖہ0#Š÷ïߏ›N70šeFà—›ÞŽª …€B@! ÐX¿ó<ÜŸ݇-¹íb*` …€ÑØœ{7Ò¥K‡ß±Ÿ`ç‰eš¢ÅFÃVUñx/Í5+f…brÀzeçˆ?`á©ý×1Ú|zŽ®'ÿV0‘^©n( …€© piûŒ}ñÕt‰â[·naǎèÚŽ’Å|e*ž©~( …@8AÀýë,Ýx yòæCµf#E¯EŠj …€BÀìܹ™2eÂ/¡(Þqt1ª6*b„ZU Èƒ€ÓåG" \"€L›8ò ÚFz搊–ËŽXf1L 7ª …€B@!`J\°ý„¯=`mm­·[¡®(þüù3fϞú5J"OòÇz;š ( …€BÀ?î=|C§n¢Jõ:È]²µI! PŠþ÷¿ÿI¢Øöð"Tk¬ˆb£+*ùþÍœ̅ùˆÚRqªB! 0Ó‡” IDATöm8ã{a³ÎQ£F5JÇÜ~‰qÝ×`斞Hš2QêT•D\<=~bΚhÕ«RgHqªFf²Lê¿A®œ«›lƒÚ± Û>ᓫ'&Nœš·ŠP'Š-Z„Ô©R náïÂrâ«Þª …€B@! »Ó7ñäÙ;Žhß ÓU@) `#`kk‹lÙ²Á3úGl³[ˆêMÔ³%8 n_q7¯<Æšymq÷Ú3t«=M:—Cïq ‚S­ºV! &$å:U™ Ëym=_zŒh¿ çŽÞÂޛ/¡YkÓm5 •ΊúíJcó¢ãX8a&,ëˆ25ò¹ÎˆvẹG@?oÚ³d͝6ÀáZ.¢àóÎå3‹îuÑ¢Gň2,ƒÆñæÕG iœ¹ g©Í ºF >üœdҀ XŒo <Q3Ûp€Í” Ëì¿r«Dñç7?1aœ= U¢ØÑÑüå{t¯Šˆöý¡ÞΩ …€B@! ø?þ‚5Ǒ>mR4jo(±Ó(À …@°ضmräÈ!‰â- FSEÐycwâÀæ‹ØwÛçŽÜĈËåKpí–ŃS­ºV!fž}ú†>çŠ òáz»}þ†:¹,ÐkL}4íZÝjÍÀû7nØzit°°íR}º°I„‰+:cáøÝØŒø֟)É€——š'°þ‚‘³[xjÅÐr Ó7¯>¡iÑqh׿*: ®‘†Šw,;WÛc–…-ÒdLŠ özË«ÆA€–=–W`éÁH—99jf!,Ç ÃbNÄ;­zyç|ÿ ú×WšÅîîî˜4iÚ6­‚ÿÞ7άªZ …€B Ò#pçÁ+;{åJäFŸŠ}€èñ#=& …€B èlÙ²yòäDñlÚ75š zeêJ(æ ðá‡6°]~Jü—Pî @öüé: p‰€¶áQ¬bج5—c`§5¢žóКhÛ·*êä¶@Þ"™1iu—`‰DqÂ$q1}cwIÀ\±w–EQ¢š|öØ®«°êµVbŒpOä,˜Á_Œ -¬É2±‹]_~É0Ç£UÏJ0YÇÄzrÝùýû7:T²Ág¯˜SÖv ¹ÆTÍ>Јâ¹;úÀ,NLðùÕò.šwxŠö³›ßãÛÇ(°²²Ò» B(^µj¢EõB늱„å„HU¯B! P(FB`ϑkxüü-ÌÛ7‚YæŠFªUU£PDFxúDñ(o±aï<Ôl®ˆâପ‰§ ڄw'a“8†ŸzŠ$âƏœjuí/qúd‡ «+Õ+ˆ$ÉÕf¢žÂ%PËÈ»0²TÊ(™³¶ö Z%!|•!sKÅj«ÒÖ(_+Ÿô ¯–eu*+ÆÁ z|>Ÿ÷‹÷D¿&óðÕM$ >8(ÐU2ÝJOî¿&“(æ*˜1Ðm…ÖÄŒKµé’€íDñJ9ýmÚÐr¡ÕïÐjçõ³÷hQr:ªöª…V³aÞÎ á >Vxy—ëV0ñÝú%0ƒ¡í‹'oåwcdÞ¢mùIâD'ÄDñ€f å¿KWËá ±DñOQ1nÜ8œc ¢øÞœ{X¿~=†w)ŽX¿^êí”* P( À ðÅí6Li“¡zó‘ˆ+y`.We …€77nD¡B…àõÖ힃Z-”EBp—Çœϑ-o:éQV ƒ;œsœÂ%hS9cøVì^wÿˑ+Ž Z%!|•¡sK_ÔhÑ£É ” }Ö¡Lõ<šP§@°z÷ã›'^?Œÿ¥Ä®5ö‚uEßñ¿ï ƒÖÙ6e'!VìX~ØtœEn¹ˆÉ7éUÌZ.Xe‚“Žk]Ö=G×C3ó &ØCãwé§ç/ޝ8Ÿ>žcõ±a¡šôqÚÐ-8Ží6Ÿ…$)"o²ÉGw^!­°àæÔ€æ 0jn[ñÿˆg•c¿é<ŸDÇØ±cõ.äP!ŠG:e3 Èzû£ ( …€B Hœužëwž£VíÈT IêP)  6 H‘"øõ-Ö=HÕlþAÀåÅ4/>ÿ² رò Þº|B×áµC 6&nÖn)òû_ˆŽàvÔ\6,8Š#Û¯`Ĭ–ø/Oºà6!®Ðl®žœ¬¹Ò„X£àânÈ܆ödö ìZ–š€w®Ÿawß&އfP{$Ð۔›„˜±¢aÅá¡2q–ah9ƒ g…šD§ÃÀÉMP¯M©pÖû u—÷ÅìQÛ1ØŠ)êŽ*ŽJ‚x•<í#Ný,ØÓ/@%~‡JS0u}7©Ö­îó/ŽúÞÚ±ßôžn11fÌœ]q¢øÌ™38~p,ºÒÛU@! P(AE€þ^óVCŠd‰Ð²×\ Jô V¥®S("1<W¬X1|òFÅdŒ|òN±Ÿˆi¡Ë°ZàÿÝ¿|¿7èYŽ|vl\p |9Ýã41ÔFMýýò‚æj‹† ÁŪçÛí(±£ŸjҔ‘WuŠÍMÓ¢V —ë†JHDpq7dnC¢ßÿª3°÷X`Çܘ\_~Ä )MÁ„ƒß¹ … ÒgIŽúíJ‡öpýŽ·aþQ,™Ž“VuFÉ*¹쏡åÂ|@!Ёû·^Hk‹9­DB±"!ЂiUùÕí»ŽI™.1ííª'mˆ„u¿ °³œ,“YŠÉ.Â#ÚóÇOÄOG(ºË#NŒØšžu˜ð‹®-Nä” 5ð‚ûü µŽ†³†Îl|‹Ÿî&@{xx`äàèÙì?dJñ€Ûál]šî* ÀõÛÏqþꔩÜyŠ×‹ðãUT(ŒÀºuëP¢D |ǬÙ1 µ[•0~#ªÆGàâñ;p°¿‡×Ï>àé}<ºûÚO›1cGGÃeDâšzØŸâ4æŒÞÍF!eÚÄ!Þ?­·_b°1øðæ Æ-éâíAìßt—Oݕ~ÝÑ·1° ×Ì>ß܈Ó%0dj³À^nPù àع5š#F,dÈ=˜1Ô‰FŠÄpôµå§ËåænD¹ eÄŒ}8’ÀWEÒºukä(A&ù ( -ø„+n_}ŠugaüҎ([3oøèt0z¹tò>¬ŸwTÚ1å-š95v)X2¹ì«§âžö0·¯>‘âŸ#Uú$rŠÍ” õòX¢Ž°€6œ…a¡TPžFh6ÂWqzÃx}‹ :>è‹UÛn\Œ·ìѵUèí>è°ú\! P("6¶û/ÃåÃOô¶X±ªF§P„k×®E©R¥$QŒjûŒP? "ƒŠd•òežnnK?€Ql³˜šÑ¬(rΈ¬¹Ó!ƒPҟ•±oÃyL~s·÷F^aaÌØºô$owÀóGo)[*I\µìQÉ_u.ûîìô\ô1³8¢nܓ1AÁŘ8D”º*g,Uàc¶CźÁóó5&!1·¶+NáÀŠ‹F³×Ðwv æ5g€þ矣|íü(X*+²åK'}€yß%8ǎçîãÔþëžuå ž?|ƒÌ¢Ÿé›ºÃ,N,ï*y:¡gœÙhׯ**7ðÿõ̑۰wýy,;4HÖPZ.(ã ×8œ¹‡A-I’²pÙlFï27®_|(•²EÊe òÚ0FÇHÔ¶«0eDÒŽÑ Ú£Jœu,°Ú…-KNú)Çï$ú“gϟ^Zê$LÏ»LSáïŸ!k ±î{è­?08þ9£và姈.Ÿ‡säπòµóxÝ€v’dñA[EÐ8µÁø£FÒ[Aˆş\îÂʲ/Fô¬‰$‰ÿ.4œ=R …€B@! î±Íb!uÆ$šÛº€Ÿ—€ÖÉ1‘gß 5tbñ_ dÔmSyŠüUÆÝœþLÞ1ö©$qOÕö™7Ъwe©æ‰8¹ïÖÎ>Œg‚ØK! šv)ïãdU«ÿåM+ûLÜÆv_W‚@²˜ÓZô™Œ»DŒv­µÇ³o€²®Ž8]`7&*g"Iü×¬$á€IÅùãv‰ ·ÂZ ê·-…ü%²øb`֎olþÕo®‰À®y}ؓÄâ:\ytšŸ¢}®ï ìú\8~7ι…\bã'WÁŒØ¶ìž>pö1|6°£<î¿jÆ!ì›Cô]­%”òT‡ÇKh&ÇA‚xÅÔò~zïúÅ{l$œ''ÈÞÁˆÿïŒÛ}V=×bÜâö‚èÊï úîv®: uZ—Àë€shRŽÙ®<%ž=gñY$?#ÞyH-ä+îsskñÄœˆ"ÔÔæ#üz®“§/íµ €Ý@ÏÑõÅœbø3Ø Éö§!÷Ǚƒ7`Ùee€ž¹úîí€úÆgíòSXlœž¿d1>_m֙‹MÿÏÓàܟÅe|ïµ8-Æ»æÄp€Jç—üdb5*æï].ç’ýå:MØÿïœã{œŸÃõ…›|Feϗ9 fŠâ§8uàú?¿÷“$’ÉWϲÅc·ñã»§ŽÔ(Q9§|Ö뎑ÏÝîufáÅã·~ºZŸV> ›ÑÂdz•…Ú o>ÓyïÉïEaƒÄúÓÿ/…°—IÂeþÏç¿8ZÅLŠÉûXÿöú-7ºYÔ Õ“C]!UþÔzWDñˆ KKKœM„QüÛã6.¶À·ïßѱiÈü wdª€B@! PDZÖï8?â¡ÏðY‘5p…€B h¬^œåʕÃ×ß.X¹m†$ÛT„TαM’31bF“^žŸ>|•GúË×òKºL쳇w8 »xÑkÑ£¢Ž}ûú]«ÏÀÐiÍý' ò*©žX}|˜¿ƒÑŠQóÚx+š¶,9!É€r5óIoc‰Oö÷îµgòÿÉR%@¢€ñA¿aŽ!O‘L˜°Œ“øY\xÍÅw&cR€YáÇy1_(ӘŒ‘ñ¿”øéùËû¥¿žh·ßÄÆ’ddâ7ª>÷ݶc>ˆÕ3íä5ÑcDêcCœë4Æ #±BÂî€ CTžQAÈÐ+ Õç±NcŎ!T߃$aŠE£‚cäNQõÐŒ[ùcOŸBMz—Μ۟V å=˜gð§÷n"_L©ÆåÆÔÎ5öÈ](Ê ‚AÕê%aU3ieoõ§!÷¯=Ží&õß(ï-ÞcZroÿk‘R©œkÍYù|€/ý‡w_pÇñ™Ž{ í#0÷'Ÿ¯î_ŸÉuÆg6Oðy§Ýë$dçŒf‚ºfâYãs3mqÍôi8­Å†™öÝ¢ÛZð™®}Ï$L1Å>£ Å, ÛžŽèRmšüZ{j„Œ–ë…§ožá`!6;3dM)×-4žyHl¢E*•É./>J¯p®Ñ>V ŒOhm^t 'ìA¶Œé0Fš©S‰ûÌU$å,ûÊïܪbãU÷{‡äóލçåɜoÝDœî>N ñùì[õ|íü±¶LZqsÖKÜÿ\ûéÅŠë*ñ»ç,2Å©õ.ˆêz‡mt¢ø·çgž=Ü‹É1º_=$Iäsëí‘* P( `"pËù%Î^yˆ"Uz¢PábÁ¬M]®PD&V­Z… *À]Å+¶L‹4™×ÃbŽùBHuUœý&4Ê®4’€«“k€x ý.“§Qõ€«ØRöµL"ÆdbºAEÕžk$±Ó~@5Ÿµ,5A*Œw8Zù;TzðnµXÔÍQ£iØ Þ,H‹ËÞeyÜŒp™lèÓh.n\|$ÞžSY¡Æ«'‰ØÏ‚ÜÞºô„|YŠœÄRqÄüÒÉ;’<€º”$’ïà5ôQ×}$züS “Øš)ˆéÝÂǘAÕ#“i€íõ %¡'^, œÔDZ1bF‡E§å°·»é/¡®Û}ž°,1§¢v²N’®–e(Œ„2‹ªZ!ÕÿI:E‹$7j ڗFAè°LªËMnŠiö"IŠøÂò#…$-H‹„dû$6iñAe3ç‘}>wôF¢ tµÜ˜žâIBáìB‰IRðàÖK’Ü+H8 óvö‘ŠèþMç ہRñÍDƒL^ç!È’úËŠì—Û.•õqŽè?Ëäk *⚠rnÆðm u˺hÞœb Ö ]Ü íw`çÖߛ!„~hè=Ô1LŽI*e¹DÔ¿à|O°Q~Ä{fÄÌVbÞÞJҊÞäKkü'ú6ž/ )ª›™W@ãÎe/ÁÅq`b÷º³rô×M:lÇ©¯7ÁºÕš)üÖ]ÑšcY¹Äg²›ñÛkL}™L‹œÎaÚЭ’µÉó‹Í¬‰ýÖËëIÀ¶í[êæ*ÛӁ~gn€ð<ŠÛjPåKeöÖK£¥r“|>öDŽ¡÷¯ÙœVà%žwŸœâ œ·ý›Íò$q²x˜ŒŠ«TÓÊ¢U§J²S»ól?"6+¹9`+žû7_ÀlËí²éõgFJòœÏd&R$YºÌn°nq.™°ä*תoì{×Ïâù³@œrx'áu€7<מö}ÉM.ŽC7N1æ«åwéü]~ýžÛWœ"7œݟâƒՈù֍LøØ»ÁIør~o\z„QBñMò—A%ûÛÞÐ,Cø3®… Ë;Jœül¡ÕnÜ¿õқî^gŠ ÁŸËï2Ú]è7è›Ü·É<ïïÿæ•y8g$~ÚwŽV–‰IƳŸŸã¢z“¢b-BX›,”ãXzp < ™âÄ:ÄFb æÿ†¹.F'Šœ\`˖­øâþ›—Lž«±* …€ !°j«=ŸGOžü'Lš«ª+ …€ !°råJTªT î^¯±\Å!63|‰ëVsŠŽSX(TµÚ~ªcy$•AŸQªgu£Nn |¶{nNôqü›e6_(l)œ¥‡(I]ÝhQb<Ÿ ¢x×õñþމÊ#*HIž8‰—HªRyD•/»$sŠ$T ÅKíóUò3’5|ùôÅë}ò(ïG¡Œ›.ÈQÿÔÏÚu$QI*ŒžßVÚVè1šm±]ŸÔR)V¿])I8jªE*·HPòïüÝ}‘%gy9 ˆF…ƈŸGðͰÑÞÒûXœïþêÅå{ˆù Õ̓ÃååõóŽ’*i+¡®ÕT„Zœ$…HŽ“ ±`Ñi…ToF‰EŒ!f Rªq*K ò–ä³1‚€.É]*•[ö¬$}šIÔl\pL&9kÞœ‚LZHÌHt“@#ٝ)[JÌÛÑW®›ÑbnIè.ýŸ i§JÏÎñË:zÛwPÑÙFŠ:¡ ®/? Y±?ëŠò7It3ôÑe?šr%AièÚa"/]Ü é·o"Ґ¹5ö†Öaè=˜ûV·,ñ%ì[ª[Æfð&‘œñ¢üQ¿ñÐ°ãŸÓϳ-m±c•œÜ`âF-6.<†Í‹OÈùæ}ÔžS9YÞ·š3 ñÓ΁'ž6GxŸsÌ¿0€œFÀòÞiÒ¥²òÍ«OX.6-š*žŽº‹MÁÏ{‚Gîi_ÐmdIz³/A}“Ž=-ìcxrê×Z9$nõŽÍ!Vîb£*íUdžÁÐûƒ„)Ï ©škbèœÐ<Ð?šÏ ›{ ž·µàÆI[í¹˜gûgñ̝:d3F E-Ib>Äób² Ò¿ ¢ÓLlDÄ€E®}ê-B9{6kÍQ¬b?ÝÖÈwnvÕnYÜûóáâ{âŒøŸëu[/§J¶ [y‚žÖžsº•j÷]ÞbB=œýzZ‹ƒÂ^eòÀMr£6 + ªØÞ~%Ÿ…ÃÚ.‘já6}ªÊÓ6ÜL™"Hk®K>3¹ù²âð?>ÂćÖT`/?< •kÄ?õ³Ö7ßß;ÚÏùý¶uÙI¬uX~§sÓ¯ý€ê(U5·±±ßܐäžk4-&ÔÉIpÓá‰8ÕrH>Ó¹AG@k)ŒÿüŒíGx¹ÇƈÔáÿ £Å¿œ~â›ó XNÛËÞµ‘(¡Rë›õ¹B@! P„ 7î<ÇÕ;oQžr7äÍñ3'‡ ŠªV…@äC`ŊšR¥Š$Š—mšŠzÂgT…ñ ‰ Z/Ð_”ÁãõÃÚ.JÜ»Þ úV×Ï7JªwIøêŸäÙÙ^†u¿ òº5'†Éã°ºAŸÅwÂÊáÀœ¿Çro¿,ÉŠœÂÐ6K$¡Ê—{&œc–wŸP’Œ¥ÚtÏÍ ˜2h³TÐù~Q×ÚÒÆEÁåù,^§ºöŸ‘€-ÉÄV‚Ü4$ƒ*·UšbǪ3RW«EqtX]ú2ê†F˜ö=ÿØ0ÖÎ9Œå6ŒÿÏãÍ]‡ûõ*e}ž°ÌȎËqáømIސÐ簏‡ÚøK~i/è[.Ž’ÊLbG…,Uf%«üy™ç˜£F‹"eŒ²žH*Ë25òÊäcÄM  <’LU(µ(1A~DÂ}Áî~’Ô ‘AK -<ÂOˆ"$‹TR*múWnPPØ\•Ö'Ü ÷*€ zÔÒ«V ˜$yBïNC×UÚºž“˜Ò×oöE7 ™ÛO•âÑW¥j܄С÷˜®ïs`Æ0M‡'yµxßo•âý›/@mˆ•ÿšRœãÖ%”52“GÞ­–vð†…¶$Ey/’lä†MÍæEÑ®5o{ ®¹Â{›I05b*Æ^B‰ùPXÒÐӘ*zÿrTo¶,5ñų‰ªgné}kiÕã;øœlUf¢·ârô±UïïfTPŸÁšº—4O/D÷ñ7wI ’$!K«>ŸìØÈ¿ ¹?þ—35ÖÍ="ûÛ¯ŽóÞ3ôÞh-ӂ…ÒþF×[Úwy 5äÙNŸc>#ˆŸ TÑòÔ×¿Çø x ÈUŽ…ÖŽž`œ9äËÎ+ä÷Ëð-ýt™uÕÊ1Ä&)‰d-xr„™ÚsÍ·r˜ë“„57‹žÙ¥7<º×)OáTªWÀOÒ<Í7\;õÀëž1BOÿNƒkJëíš×<çzÖÖ^Òי§7žø€Z·ce7wY'ï‘æÅ­Äs$®ØH³‚rœp}Ÿ¿wXÎáô=9Nž^I›)©ü^«PÇoBQm–ž»K חœ›áœñ„ •Ú†¿ëHNdgcHŠRæÄº×ˆé•( ˆâ¯±gãt<~þœÛW2AË5‚ å˜é¹#h_²MšçÝ%grãÁdŠÜ$¢ý Ä†”Ó9MMµ>ûÂçO]è&Ôڡ⟖+ššŸ#-Yøl4‹ó'áWPŸÁQÌ:èœ.“ K *‚i%Àµ?gÔl_yZž*à3Ӑûƒ†Ú‰ ªN©ô Ìœ­êûo¿xϝv҄ö3Žђúžm­òlçÉÅ žá&m3š:7¬xJAû?ç€c%™sɁAþ’Öҋ<óP4çs$ºð¢æsƒÄ;Éi&ÜäŒq¢Óàr¡m8RíÎ5˜6s2I\óD?cÐ⁛(º¡}‡ènTÚÛ9ÉëÆ.j'IX&b€…ƒßGZînšÖÏ?Jžº™$ìM'73— « ]Bžsa#6Xi4ØFŽÍŠÉ„ Œýw¬ý$­Óúçû{gRÿ ÞvP ;”›tõŒ¿Ë}Ï¥ŠÚ^ydˆ<µÄ¹àwV‘¯€ðŒ&>†7[Z—ˆŒbã™÷{xk_!’`øð?§ƒþÆU¿=‰ÃÆ£O‡*ȜÞ0ðõuP}®P(  "pêÂ=»bTkÔ 3þQ¬©P„GªW¯;»?I † ›€Uáq|ŠÔg&³#O¢xéF›}ûL©Ïá±/<ÊJ‘F"áù፛üwՆ…eÆs{š2–Þ’#fµ’dÕg™Ð‰äó’@ãÑkªB©æ£’–Çöiý š²“Çd —͆âÈ-‰hÄݱR(²Fm—dÇ2á/L[-˜Pš[í™RmZ¯u)t¬jÏ¿„Gr6éGüEŒ0óˆ+•³ŒŽ$fK&í“É}ª4,˹mü&’ÛŽBÈ'ԈŽÙX1í€$zµ`H,ĉ[ª:9Îⅿb݂â|Ž-?Y*ЈûAR– Éœ€â¥˜– <.L›ªÆxŒ˜ÊJ-ôáÂršòPSÚiÄûVRdŽçXهËBíEò€„ÌžÅà%ÆV7¥L"žöä/õš‡*Õi$° &ÒzâìŠÇίápêÎ1‰œPæ1‰G«}׫©°}+YnBŸu"áš“Ž  â™‘Jþ!ÌdNëGÍIÐQL"‰“ÇwEâK¡Ž§ú˜ŠAœ/]5P/›\$,Hzºv|ãÎÿSQø¯~ïŒn%™Ûá^OÌõۅm†1’>zÑ"$(cÐNŽìQ Ý,êHåíˆöK…*2™ÜÔ`TÊ0Hpi€] ×,ý©i‘@?oÃÚqm}R­K?`]5¿Ffj÷µíŠSBQŒœÇÖ¶åAïTóšÓQJšç¹qPZNó/nÛ¯*:©©÷Váý¹Øzðþ,՞-„] Äq£ƒ÷ja=A › >ƒ5¢˜ÏÑé»ËM“§âž³°·æ N+*k ¹?˜¬MK®FxíV%€rŽxÆro’’<âìôB’ªÜô!QʟQUÌïŒB"镊ü“Y$‡ÓÖ6Âz2é‰bžJX)’r’ŒåúŠO4í‹|6(0 ڕ–*_>_øÜ ášù÷ú7™ôÙ§ß~Œ±Åæçooëk‘}ææ"}ƒù|¡2™–ñE¢6œ§R7ØXåé ’ËLfÈïb¢ðZ»š’žøÎÜÜS&P¥Ç#±Ù¶åÂh‰—f5Dë£ÖM|t™›<)°ëÆx,¿GZjp³ùøýðôŸ‹ünôãè(ˆmzÒ3Ékµ¬Ëñ÷ƒ8ò»1–TÚ'ý€4¿KJ_yZ 0éª6Tzo _ŠF£Ù$Š}c—=.ˆâØ¡OÿÆÅœã°÷°ÆðÇÜØUõ) …€Bà_Œûà†í¯"}Ÿ&šUÛç‘L…œBÀÔ Š8I’$øþý;'N,xÿúõKk€n‡L}aÚ?b-Ú_BÌÐÎ,[¶ 5jÔÀ—_‚(Þ ˆbCq J9Ÿ4“L}óú£$Ó¶/ƒºmJz{²N~Î éTÈ®>>\Ÿ R)ÅDMTÖQÑW¡N~ñ‚^NŸ,ÏžŸTùNèÃ$WT‰’ ÑGÅ _hI ñeøŒ -:®*\ÿTä–]Và§xéf!ª°6 ÿRf®gÒ=Ÿ¬’Œeß©jՈXzÔv©>íÁCß܀‚É›H8PqËDFó„ ÒQŒ\“ (šØZ+<ƒ?òC&Mc&![Q/f¢*]E-šèb̶džs¥õ®V.,øHš×,…Ê™j4MÇQûŠÎNÏ¥ï/‰jª©²ÖU8«˜±£{ۋh ÿžug ¥Ÿ a"®°Žà³u1é ‰ŒOÝ_$¡GñŽ`ð9„¢e_=}/ yxÿ iì«o+gñžBºôŠ%ÉOa*»IÒÕi]‡Õ}msÎ,}:I11 7çQk®Uz8÷ÛÀûœ¡kÇ?Ü é·nÂ5Cæö_8-¿[~ÜcÔ_â6(÷¹vM`î1íšÀŒ÷}P¹)B¯T&Ċ!™<‘¿ÄŸÍˆ éJŸdýuy€ŸÁ“ ô9Õ3Ò¿v PƒsÍ1žéÂM)®OíŸÔìX†‰0IJqMõª?[’ÎLŒPÐ֓®âÚÐkM±Ü±Õ/'Z²PNf÷ý&XöFùÙPºÈ_“pSHõI! P("»8â•[Žî4 $ˆ<W# ×<þ™3gF·nÝP»vmÔªUKþbשS'”-[V*/ïÝ»‡D‰…ëq†Dçííí¥âšɒþ„ÛÒ¥K%Þ$Н›òÏcÃ!ÑU§_HÆ/ôšDP0â‹%_ì™ØŒ &Ÿž7‰©H.kÁ—á€|INSèû>ÉMºä€nÿxt• Ӏ>ìXš&c’<’©þ9š>³Tøêú¿²¬!žèë#‰— *NIƒÀ Lðx5“ÅQIΠ3ý[v^)}/© £úêI&7.=”€ÕœUòö‚Ö×&IAn8ù&G|_§á_z€$sš˜swûŽbm骷}_§oíè럟ύ1·úÚì灜Ç;†E÷Hûnšp©±ðlÕõ&QÌS s[Ë®S¡Î9òÐ%Iɓ‡mðR$¹à &z73¯àçè;=T¹©2S؀€ ( -§]OҞ›ÜÔ¢/kYAöÅK[ø®ŠÎ»"Iâ58 å,­HäKÎß‚ò,òý L=œ?xŸr“E{Ÿ‘x4ôÞ®"æ–B±„:™êzéêñrrx„ÛWŸâÞõçxõìT»N–T놟û30ôi8Wn"Pum¬ ¿µ›Ø24¹b@íž9xãz®‘É‹WÌ)ÐT‹kÁ{ðOBǿߕºuÑR†1º>æÄ†JàÈÏøl6†÷9ûB/fa_E?ádbSGnØÔ›ƒÛ"9.•ÆÝÅiš²ÿ|ŽEk§HOW …@ø@€ÊGú‡ÞŸúD*¯%/”S!—«`†*|ƒ:Â-KN`Õn,³äÃÖ#šõ©ëBZ9FHÚ Ë:…\#!X3-öl8'“ÇÑZ#yê„2IY±ŸÿeI‚]Ò[µ±î°ž·õN0yèKo'NЏ™ï„Ž«bòØÂe²IK™Eóâã¥oó;“$“M]õ b¥ÆàÁƒõvÛ(Dñïï.èmÞ#{ÕFê”ê€^ÔU…€B@! UŽœƒ¯£ n‹H“&Mš¶­‹ø\žpA’œ;wÔ`é1ÌÄi 6”¶›6m¬Y³0mÚ4 4_¿~EŠ)$Z­Z5:tÈ»~‡3f ^œz%-L1žW( …@š#ðìå{ºU«Võn’IëæÍ›ç£ $:·mۆÿþûÏÇÏïß¿Ä‰K%nd‹'NH‚œfȐvvvèÞœ»$Ùµû˜ö 4-#Œ‹-’õ}ò|Š…«…G±"Š«ªC!¡˜3j¶¯<%"[Þtz¬áypïE¢¹fŬP¬BX¯ œ]TxwX÷]Ýa=ª}…prýkď‘  Ð G°‰âSû—áÌÉýÞ£–ÞÆÂkw?Sã©gNœÝ׈âĉâÃì×K“&‹7ì<¶–ãðúAšTJyiéÜ è3fvºŠŒÙÓbÒðÆÈŸ3}kR—)ÁEàù«Øü:rkŒòU”URpñT×ûD€Š™œ9sâÑ£GxðàôÐ¥Wî͛7e²9&Ó ͟˜ Y™\C(‰iC¡›¥ž»–––Hž<9h㙂vš‚:Q¢Džvíš<*G‚˜öZОb„ %æ0?EŠ”*§Ph|sÿÇs÷Q²JnЉ#àtù‘H—)Ó&6ñžFœî©û#âÌ¥IøEÀN(Š“ÇψþýûëD°‰âc;"W–DšV6â~)ºü̈—žYô‚©K³pH‘ŏžœÅ»ÏñBï?º#cÚ€hV§šPtG×ÛG­ÀºíçÐ~Ð ì[Õ5ÊG\˃ ‚;í®¢q·Þ5s~–OiV J„@kªJ…€BÀ­;8‰3¢C¯‰†WeB€Å]»vEëÖ­áì쌋/¢J•*2 .ÌJ;uꄕ+WJb™þœŸƒVޜ`$‹ÇšŸ„×ÂóçχT3“Ó‘nÓŠ!=|øY³f• ìFuž .”u~ôx¢ÅFEøþÍœ̅ùˆÚRѧB!`lBjíÛpÇ÷:Âf¹Ÿç¹±Ç ê ÿœ9x¯Ÿ¿Wöá*ýAH=g"(\jX&‚€Ýò'Hž S(Å?ÝЩU Ì×qÌb™Èðß (þíõw?•>;ZDA€M• âŁo¢˜eŒA“>sÉYþ9qþ.î?võ3È.-Êbñ€v~õ6{t² Ç7 A¹âÙ Ÿ.2Ž=à€t©£xÿjøæÃ×`ùæÓÙ»6 åɀá“mñàÉ,œØ][– T]Æ.|ùúc<|úFn0˜Rüúå…V}—àãç¯Ø¿ª¿H\5ÈÝ êŒ¹A#\hªób„¡™LGíoãhÑ}šð4Mn2ýR‰ØÌœ9³ŽœÐbïÞœš]»¶Ÿ._Ÿ]ºt‘>»$;uíPvîÜ)ýÃh·Ð«W/̚5K&m‹šáææ&ÕÃööö2™ÇMu6ĕ*Uò3lÚO0ñߝ;wBÄFfÁ‚hÒ€ >üx¬ˆb#,ºí+Nãæ•Ç5¯-î^{†nµg¢Içrè=Nì0Œª @H¬1OŸèTe*,çµAö|é1¢ý2œ;z {oNDŒ„f wÀ›W1€õbä.œ CŠ6CËE$P§ۊÃÛpÐyrD–AcY7÷èMk¬¹ÓtMx(ϙð0nÕLjƒÀ!A§ÅýúõÓ;š`)Š/ŸÜ„ÝÛ×cì€úz ÏtÅnîßðËë—÷p¢ˆʼnc†è"÷µ;Î(”;’ˆ¬Ýº²øÍ»/=c'ìNÝÄãçKš8ª”ɉ|9Ò!Cš$rGûÞ#$MœÚû}™ ÷å›N 5Ç\Úc)HLÓöêä‘Ü=G¯Áñæ3Ď]æ÷a=Žò;‡Ðˆ•,a&þ]=0&PÍUn9 ÷ŸžâљÉrž>|r— ãS±`Bk˜· » ÝÄܯªrö-UrŸë5Pƒ4rá+NOPŽîYëÇs?^ì ·Ôy rƒFžÐTçÅC3™*žÑvDÅÅ+¶BáR5MŠ_ª#Ё7‚IÚNŸ>? ے%KúÛ9&S»qãhA’—^ÄLÚÆ„kÇ÷Ÿ&V¬X˜6mºuë&Õ±çϟ—ä'ÿ]Œxq™”-šø‚ ژÍÁÁOŸ>…™™™LxG?ވŽè AŒnÝ:”)SgΜù?ö®,ªmþêœvwww‹Ý……­ØÝ­š„XØb€b+&&awwba‹Ý×÷¯Ÿwpˆaf`èó¿Ïïy{¯œÏY{íµD9 ‚8oÞ ±çΝKVVVäååE2dh–/_NŠŠŠôæû=r\a¯z‡åyÖ[Ésýir¿>‰NìœF£;/R©AÛr¡Œ²zzhžqñ!Y÷^AvKºFiB',æØ§_©aAKêgՄZöšJœLgқ—Ÿ$¬N-_¶®8F³-])c¶TärÌR+,úp6|¹¯=IûL•ð%ªa‚ߣZ”²ágå#™cNuš—Žj]ÐÚÞ°xÏDpԎD v9ß§ô)r…}˜Ý©}(}ÊØÔ€v‰(LH©Iÿþƒ‰â¿Šb\3 Œ;Ý~ð˜âýûåȜ‰bAÖš¬q.S²8Ïõn‚ÕÌmdçà&Çg͔’:·šHŠÕ‹P©"ٌ²ÝiáªÔŒ yí›@ùrþMg×ÕÀœGœh ÕZÕ·>ul^A×á¡þüÙË÷ÔuØ2Úń¹f êZKãrWMO_Œ§Ï7þÚHhÞW&kŽ£”LàuýK|ÿþ“L;Ï¡C§nÑÒiiÎÒœT©LšcÝ6<ºâwn#–ÓòÇèø–Ñ+¥Ã²¡¶ëhî²}ì?‡ŸÝr Õ­tÛåëi°ÍZñérÙÐFb±à篎iaJ–4¡¿Ó#ëžÚÇÈ|<ԊËxî§ÏZˆšŽûûlFæ6«m F7nÜ8! Q–)YµªÿE=ÃmÛ¶ïaÍJœ8±Ä :óåËGϞ=“¿Ãk÷ǏF?]š]]]ÅÚ dkkk!J?~,—Kš4©„â¡-P'GÇ:qâ„ÄgϞ¥,Y²æ¶¶¶bÇogm…ð Øuœ:uJ0«RÅ*Ql„ñåDў»öäºä0ͳÞFN˜šÛ`„C~•…¶Óz§ƒÔsL2ï[3äŠà3ÃbŽ)Dq·õ©ÃÀÚÔ°%)ƒ&¯èÁœ·‡§s {zpû9/Ÿ ©«zÙ0}‹œ2^+쇭#u§i·÷TŠÿ¯¯Ÿñî9¯ŽÛ²í·J·pÇ`*P"kälhZï™4C=EE Äì\|Ÿ2€ k¢ø÷Ø­îoJéRGEbˆQ æDM뉫·ïúSãŽì™2Rò€‰éûŸôàÉ3úúõýáÿiVÅìŸ)oÊ·z7靖óV·€Ì铓×Þ ­Æ¬¹Ëö’…ízzpÜ^lô-§5‡šïØÕBäy®LÕˇ¿Ü뷟šRó)¢˜nT³{û–e±ËÖSlu—nš.jØìGÒ£'oÈqR±DxÁjï_¿~ ÁÞ»}5҆I†2CXažM| 5ëÃǯT°Ö8n{Rº|Ç`·0aš™XT„Wu²„Vo9Iƒ»ÕМYRÓCîßwÞbbۂÿ-4Jސö$zf“á⻝6uzzffH/%çé·ÓïQùŠ“è‚‡->éÔkŽëÉówT·J!Ú±t ?’:2ŽKš!’ž ÿð‡OÞS?Ë¥ü.‹I[©6+Œ€0W‰âРø\š‰§]Gž7'Ó:ÇŽbÖnQ'Jòw×Ð!K.U°DäÞåf\d"þj£;³Â^/ê<€®ü‰Œ»Ÿ¯šFcíÂ$}昡}ƒ2ÒŒâ$ªjZT<µëäIͺV…±¡¥O”kþæï[xaýM™&‰¡· ·ã²_³uï•dR£€Øs$NއŸÇ…[ÃÃéFS,ÖÒn׳ŽÿáŒpºcÄßÏL÷:3dñ¶åxn ¢Ëû=,Þ3?jj b;ߣŒ©òЀtv;ÄÖ>7Ҕɶ¬„4×y“š~€.E±¶þáË`üxŸ_öòÇ;E b6Šd…ûS®¬i錇ñ·8MsÚ)ž¹¯.ΊÉŽ«w‚jðŽœ—hƒûʓ=ÔÈ >rp“îä¶ï²±ó'Žó;µŒÙ$:}éُnAC{ÿ—Z¯ÛOhÝöÓtßç5ÝgèãçîH"œfÅf¹I‰œtd“¯"1(L2—FEØÃs¥E †¡ö IDATn÷¿†¿ ÿŠþl²hí!zñêmXÐÇx :ö=Ü V$ø]?ðyE§˜$ýøé[ kdϜŠv¯B¹²¥5èúÆ8XQ¹ãZ á¡v7€ ·+7Sñú6Ž|FWêÐ,è­å†Ü_ßcŸ¿üÀcq€N]žK3Ƶ¢í{.EêqÑ·_Qé8,œœrŸ·HYóª[Ÿ£Òس­ðÁ…G0È_TñâÅiÖ¬Yb!Tœ}û– ,(Ja„ÕA¬YžNݺu… †ºØÒÒRTÃP+‚dqžà¯žœ§¥mš9“Òl#ç˜üúù›:UŸJïß~ŠûGRªtA?gúg0 Qà„‰Öб=WÉãÆä(ÐZã4qç†Ó4eÈ:ޝPƒw)4ô»š1ßïžh‡*“i€MS*[=ìkÚ ‹÷ŒqÐW¯¢" ÏE÷(sšŒÔ¿‡˜(v[cCwœo ÑÝKSQ|å֝@ÖÚú‡‰âÂùrRìX±CLgJ—Â`ÂLŸñ?c+MœçÎÛû²¢Î@T³{Žx±â/ªY± ¥cåkx—¢ö¬S¹ (r5Óâ§,ð Ëi[š[ëÊŽhŠþ~ûÕö ëµt†ƒÝ .S4;5¯_Šf,ÞEç¯> Ô劥ššI>*Éö €µ8ú<{K7ï>§öƒS¶L©èÄÖ1!‚ïþc1d?ã$IPmö¥M`䰉h–óž@íÙÝžvq*Í}/ƪÚÔ)#F¹…m¡ÚãÅ ú5+Š‹ÌB§¶i÷: Ð2&4nðªÍǪ}Û!MÈrÀß_fB4XNÚ}äM™ïAœqØe *S,;õnWÊ÷¿<$ãUòÇÏßxƒÛ cŽ;Š\ãñÓ·ŽmÏ*cR•LêôŠ)ÝVû©À®]»šS§Nôü¹¯%”X=hWƒÇð¢E‹äŸa;ÒX³àmܲeKµq:uêP›6mhíÚµ1{x0Ã^qîܹEA ßaą Ö“Ì™3Ó»wï„`N›6|1U¢Xïá1ځm+ØÑëx›¶}𝠢[â-çšSífÑÇ3ÔÀž”«uóŒ"ya.øúùÙq1-›3ÄDŽšÑY•Ÿ`Ç H£8ï\c*M[ÓKTðú”!}xîó–Z—› $˜ýªžú\>܏ٲì(Í·™†Ù·€†æÚÅúî‡Âûûò黎ùŒM8Ü-âoñýëOjÏnÜxqhéž/ÁßÝÐÆ|¿£§fÅÆSÅ:…‚ PŒxDÔšD><Ý¥¬ióKP¶® Qüç¿4ÕҜÊË!ÄYt/MEñP–ú—jï> %bÿ_-RE1,˜ÆiçqÄþ€æYþsõŠ=gjޜéhåÌnô·íÃJ J¹Œzyà v‘Ëá@Ÿ»ðÛírŒ®Ò…§®óu}Þ¬ç|&î.rþ^¢PV?oç¯ß~è5·‡OÚHî¬@7)™S¯q9…­.t®I³­Úèj"íã4{žã'Y ŒðÊ|üìaaŠ÷D ãùlkp!Ú­YðA¶b>,F2*$ã‚ùåêyNˆtÍ ÊÏ_Ÿ³ÿõl¶GùJû\†Fé¯ÈHp¶Æá¹Î‘-5ë1›[ÀT>ŽQmBØ ðíÛ79r$988ÈN‘d>ûþý{š?>õíÛ7؛Ž;–&Nœ(d¥B0+'|üø‘LLLÄ@ŠnÛ¶òçÏŠ^ºaƒRè®êãã#10…Ïóõë×%œ1|š )(ÿý—Ãd9ð/I’ð[ÈTˆâ·?î«av† X(ŽmU֖^Z4ٝ&/ïFåkò× cŸßqaŒ·RŠMB›uoŸªxªíV ž(þòˆzvk'[ÿ†1…E‡"úš QüߟÿèÒuoÉ O*–/݅”(þôù»üÁ©IBh–ûý>?7ËïPØ-t°pæþý[ÜÊÈxqÿ¥'§§SR&=Q×nùˆO¯âOŒ~û;Úmð#—Aˆþd•‚B‚,žgÛNïÀ0ü2™ŒÈ¶?HC=­õÚß137É/Tð_¡þ“Õ][W¢ÅS:ɱ3í’cJÎJkzQŽÿûô.Y„f/ÙKM땠U³|Ã*Z÷s¢MgÙ3w{ç­®ÖÄd“Ç9üs‘û,ïy²§åë—€<¿~ÿ&ÏWØÙÄïÐ~ã֐ãꃬ¢ŽEõ«a¬?ЙK÷©"ׇ7Žô;8õ³’–m8&ÿ²2CÚdÒoWÇŸT$¿vß]ÅæaÝŒžÔ²A™`1ÖOƒIã„ù+öÓ@Vv÷jW•ص§$ûÉžÚàÛWCç¶ri]ãå|ªbƒšGÛ*â?<|âFV‚§$‡ž” ~\YøÀüÆó‚sþ\éù9xÂäü™côö lǗÜ÷_–ù6qXSñ}†²x:Ï9̍…ÜÇžqãP+^ŒÀõ5KŸqÇ1Þ÷Mõw>|w”/î?ôð„œJ똔Û÷^$ï{/Èbô4Š“XõÄ Í3U΅0¬  FHÜâŋåÿ ( Vø÷àş?ëXGÀAñÉÅßnwùòe‚oõêA/`FœBÚNôa~°àH—.õ îÓÇp[%üž‡äl÷áã„øÒ¯¿Dñ=r\9šv®dÈéê±z Õï>=zöèü¹zö~6_Kf£yl!aHœyù‘š•°¢z-ËКYálH;#ú؛—Q/Sßï–sÛ±úºT˜4éÎõ'Žcõ zËãb³š³Î{ Dá‡OòÜxü†®_x@_>}t^ú,)iÆÚޔ){j×4ö ¥ŠlC1rFÐBCûàsï;v‹Ÿ…·ôÐû9Ý»ù,P“ãÆÿGÞE}Æ66vw ºÞâ)îŽfÞ>±)RF{ટÇtó(tðÈ‹ÅFÄv:‘œÛXØy›¿xVy&Ãòý,:V›B?Ÿý€ulG£–ЀЀþx²¢8KX*Šo]ÚK«œg“ pńŠHE1ˆb¬@ނF¬4¿Ð‚˜œ¿òê[Ÿ&oæoXžŸxGYˏ`…o^ÚëâëýÖvÀ"&ï‘÷a_߀ëÞO©„©¬ø/±ïL›Wïc¹J”Ç7öÛQžéäßp/—m§Xa;Gì)æï+ä2ªE“;ú©¡ÂËPMöéPMÈb} Þ¹ ŠÑO(L ©¥ë²*b…w+Xi Å;Ô®©‰šòAÒæ€GŒj,ÛQ@…®ØŽàß𠭟ß[”Û8*þ‘ìõýƒÿ~Îmœ(¿S(ÿ}Ÿ] P@šŸ_³ŸÈÞYã[ÓÀ.þÕ;ºÆ‰™H¯Íφ„7°KMŸ¶n…tHÇ,ºœ‡÷ß9~4á`²L…ý‡ŠE—>ªýø‹À±cÇšaÆbaP»vm “CªK—.Ž|ùròôô€zõ|Sµ,*¬­­)gΜԪU+ºyó&yxx©‰kÀz"Ь6  þúõ+=yòDÈtš‡5 Y†Áo^@…­l*vìØ!pªŠâ°‡œgý™¯Ç€UµA1*Q!7å-š™ræÏ@ñyg¡¥Å5š” ñó}‚Q°X8Ÿç=eb„[Üxþ­× œOT?þ o‹Ðlž|Ÿp=giüœØn£ ‹‚‹ðÎW, å.˜‘’¥L¬×@Û·ñêÈ óšfºwÑésіì!œ5wZš±.è…0CúR¹Q¡±J0÷ëµ*C…Je£Ü…2SVV×Ã/9$Âòˆç:±ß‹î]J_yüë¶ð/ñbRÞªÇršãڟ2fKèV îAÒUªS˜Æ/Ðnÿ§ïq!éKT9g@3Ù¡ BÝØۘsGn‹]OY){ÞôÆŸ…Aכ5f¹­9Iλ†R~o‡åû ÃÄsÐÖïŽk簏x1ÂB’Z**þسô¡ŰÓÓU!²žØ¶n=ö>F}ÚÇ ÕŒŠ¢øÊÍ»z+ŠAL ¥GñïߪOÄÁùÇBIEáö%šA¢þÆÝÎÁ¬fn2ÑöÿäŸY÷yjöš.xZɱcì7Óԅž~ä˜rXJœœò€jTøk<„áù°Ê8}šd”¶€“_ŸhãÂ>Ԍ•²šuk£®si/+5·×ªÈ x,~1Az“ j}U밓È[͒ްÇm{&ÿÖ,ÆdoBZ³õ­t=.„°â{‹ ¹÷Ü·^óu=#ÔeØ29ÿò.k*”7SÇĵìÌV§èñ©i¬ôõïa2êbσWša—¹ä2·µnT–*6›,Ö{Ö õ‡ù݇/™\þNEYEŽZÀ‹˜°WHN¥QP­Žd¥4ÊÚ¢1ôõ›ŽQ×áËÉÁÆ\«}‡!xê1ˆ0N%Ø ~fûXYˆÀ|y[¢P:°nž(f ÛÊ­ô·röä9[BìQ Fú0q>–mK@ÐcŽ»ðüâóçðöÜú¿}‰rÝšrš[Xôå‘5ÇiUö㚁è'¶, 'þý‹Ït ìg@2››•óSŒã<øbç¯1–â²ßø­ƒ)U ýŸ<…dÜ¢Ë9XžÙÁ»*ª™¢âõÆF—n©ýû÷ïS±bÅD™Ú¡CZºt)¿ÿDǏ§Š+ ¬Ûi$&’‚å}• AjÞŒ¹øƒØŒIµråJ!ˆüø!–ð!†‚ždÉÐ1 ­J”(Açϟ08U¢8ì¡_8a;ØëE™+X"mr>,¡j;®ò"+[ h+(/WÌÞM§ö_§ï¬(Ãöw“š„øMŸÙ—HcëŸûړˆöêÙ!F§¯íE¥*ý}fá¯éºì0m[qœ>ð‚.ˆênÃM©h¹œrÍlupæÐ *S%ÅåÐ=Ü“­¡„Œ ?yE7œIKCÕÕ&X}Z²"ï^ä>íÜx†–Nó€âåsÓèÙmý J`DZ}õqzýü=Ÿ—ª7*FOÜ¡¡mEªIfÁ2`ùÌ]äærRÇ!ØÒÙÞCv$ṅ…®CëÉó¥Ôã{/iÚðõ4drKʖÇW°€Y˜ÃÀúÆ¥‡¢Š‡ºü<÷õÌÁ›ôßN΋ Ux΀Œ4VA¬ãŸö­˜µK0­Ù€$™±=NŠþ•íÝëL§”ò”Ï4žægÈûšÜ¿ãàÚÔu˜Û¡Cî—h՜=ôèîKʐ5%µì^•˜ûî荈÷»1°W¯¡"`(Nw){†‚zíö Q+VA5˜^ºþX,ûõEëZ‹U jeïC“‚\` "ö1C{úŠÎCåÜÛrµ„»å̚† ÁS'ˆÀ/Y°hð-Z­ZO„Ç` øé Û%ÚrÑFǀõ“3°ÝÄ$ŸÔƒì‚ªô¹Ï;ñ3ŽÇäÒ[3 ÖRˆâ,9ӈÏëùcÞ²°“2M^$¯ÇdcQJ–"‘ß-žfÑjÕÿ²5È¥—LäàšÎ»‡R–œiéÒÉ;4šÅ|êgՄ‰¡⻋û  ú5ÓžúŽiŬݎlÆNZŒs}x÷…†›;ù‘°Ü€õêÜÑ[4ŸÇrñ¹U ÞÍ ÏÆv[Ê${Ed绳8õk2—ŒÎ?ð7PÏÚ¯îéGîgېù¬üE;Q ñ Ø†ï1ª1“Ń˜ž‚ ßGnÛI&ök }Û­46³-]ÉjaG&ž‹<¯žœGV[Ù;µ»ÌcH@,T¬:/ŸŸ£TLhcN mv\_øùÒKÇtYBñK;ç.A*ڇ·s{˜ÕGÆPòTA UŒù~G›A?üVì_ŽîºÂ6¿d‡H«žÕÈŽM9jxš¯±PtˆP˜Kx^QJàix¿ßµ°úŠ@#àît‡rd(vDñ >ædÑ®(eÍþžPaŒ]—×$Š?}þJ¿ÿóݚ®«âĎçïê{H‰â¯üKȗ „Œ ®f/Ù#ŠÈrT†-û A`µì»^œù$§"TÍ~Œï¶Øç0!wWì#PŠêÞ«Päð5m¥YÊÖ|X\ºþˆÎìë/l AlX͈%»%]DqŠÂg m·“·×!¡š„G±R Åã Ž*ÔŠwõ@Ág؂ŸÞ‡Þ/šY—ÊLÕå¬Ó$7Z·ð€ÃQSü|[t«B™LQuëé7(6;Û.O0š•…ŸmÙå^ë&ޜIc:U˜Ñ…ât—ÞB¢w®aOïß|‚¯jƒ¢BæŠJ—L‘gßb;†4nžï'š’§X¬•¿ƒü=˜ÃÔ^qŸÂ!Ôï*ÿ^'×!¥AÎ ³oEuš—–s@®9Oñ°Y§Š¢r<äq‰¬z®ÒĖ>í֜HP‚OŒ–ÕŠÍ 6 ñ„Ôqb³¹²H±ñÌxºræëŸL°FA…>—­BӐŒPo¹hdK@°ÂêRTUÓ¢ÔªW5š9j“}Æ6¢Ö<ß×; G&6q|1“œ¢²ÔTë‹æd÷:3„„Ä3Šg*šÒç8šq¡Æs ¢ x,º ?øýßýºoÀ"J± ypû¹à:ueQ…bŎÃY.­ËÉŒN“!YõZ!öP¿wTK5n_}L=êÍäŧÄärÌÒ_»A·1±c5}JÄâš.µ|íý†OkMe«å§>fÉÑg,`A¥Û©ÆT!µQ å±(0Å…Ÿ±2|öÆŸ~jzŒƒÊÕ(àÏÇÚÛËGÈv—'øZðÐð»m¡Ì#,úä)tÆ .í8äð€x¶úŽo"ÏmlYa<ÌŸ¥,”ò®Ä æZCVւd5¯0Qɰš3jfÁ>ËçŽÜ’Ÿ¥èÇ.̹þ6f„w£¶2æûmQŒw6 s–2]‡Õc¥p`»”‰×ОÍçd·ÆªóûŒxÀ™*Ö)D—v ×÷»ŸÏœzœŠ@X ŠD1’œ-úu E¶ âí‘òš QŒ­!7ï?4HQœ/{Ö‡Ù!h Ûòß\š£Ó~Ä*ˆ¿Ó컩„šÝyðRT™ÓÆŽïUØ0gWñ}^±’¥éœ¬­m«ÙÏ·ûù"pÊšæt쬷Øi lO!b‚k)€ßä‘͘ :u[QµV.“[ü£A<š2‰U1|paùQéÿãP$_f¿Uf„Ý!ô S(‡±nWê+U8›ô¥BÓI¢*VTՆÎm¥=ºÆíêM*VÏZ_ËÁu—S s$[…BÂß<šŠÔ±"xn—(”•m*g¬­ë IDATrñbÑöžŸ/ÐæMŒžUô®Ã×ÈŽÓlʘ.¹ŸŸtPø@~øômúvk¡?U‡>㢌}Àë‚Üɯ–þ`Œ.±¯÷ð‘£)NJß/¹jÅLð%JâK—.HãÆ#6,(²ŒÂÕ«WÅ^ÂÝݝ&L(þÃP7eoocBá!íàÀžŽ‘ V¬XAuëÖUÅá8 'AR.Û7B”lëލ§B䀀\ºgx ÿIJPO‚Ì™¹¡5)òw±ٜMþ‰;åúØþ?P·è^…r±J6 KŠza2yEw*_³ >xƒFŽ_$¿k ­ÕŽ€luw¿•6/;âG‚2}ÛŽh²»(¬•6 Ú’µ+O]§¬t»6‘¶,;JsÆmö#Œ•öÛ}•,».•ÿL’<meBþ·öÃÖù)2MhFM»ø9ÎëJ[–£NuDq |¡jŽåpº*LRjÞ§Pº‚°ÁvëòcÙq±øEÃ^@Ÿvk^oç†Ó4eÈ:V=s{"I°$èwÙëw«,GvX$ ÷öj‹]ì@h‚$TÊÐ>Ž1áÝ Lc"šzñä-µ*ëûYêôI™eû1& ±Øß¿þu>]ø/`{ X< `UÒn@MÖ+ºæíŽáÄŸ6 e«ÿµ# xž®ã .! <*Ô.ȶ …ÈÃóÿi'w —E_û5qå+ý …]Í&™3çðxlYÎó|ìf!8ñ\*…ÅljŸ^÷˜·˜¿J+Žjax—+žé}Ç7Šœ[ÎËCՍEkǎì{[œv»že˹Èy%œñ ÛE²îœRÈxå]cš4ÕoUVŒ •ÂŒb»HÙ¬ø/ËÊה⩋EQ6µŠ€)‚ )ï ž3×÷ñûþ€]šgÝ¢sóŽˆȐw%‚öZ–aÑQÞtŒejyÆQ5§ÄI°]Í ? ”…¥/îŸ ug²vF𻹰¡³Æ|¿£Í]jÙs?}¡þ^Ï¡v­qð¬I·œ/d?¬Và÷gcí‚ýò<Žî]MÂ!Ãóý®ëYS?WKܜ8Œ;cêÝÛW4\l=­™î›œh|_O—˜PšŠâö7$Šb„²œ…2–Išà’Ø•6!èjûÓ.gÿYÄMj—`ßԢʄTÃð‚MËA[JHÙT¶öëmÙÌÞA‹øXx+b¹{ã‚(¥p¥Sh҈fBŽ¡–°5Ã2V5‚èüΟÃꡚI~¹?ü_CS …pÐØ±3ÞtýÎS&ƒ¿É¶}ÓêEhP×Z~¶‡,¡5.ÖœMerbKˆà $««ç9±fÐøŠœçÁ ñŐ‚P3CÙŒk¥Uáp3TP˜€®×qµ33¡Î-+jmNß±«%üÌj°/1¥éè©®ˆk(…€²Å²Ó붔ŸÃß ˜…%Ƨ/߄dË~Ě^ÒØZߢ÷Ú}ċ:4+OËY¡¬Y9+ŸjüJh"Æ*Z”!xê;Ÿ¶ëIJ±[—å¥[ŒŸ5]¹á#Êx„¢ ™ÛúŽÔÜ ¬Y±€Åk./PXr#|¬1&X¹»-M?}+ᒅXu±íÖº’ßÂ恉Ù$&Š“‘[h+šœ×m?dX£®qQž7»ynôž·8þ`UÈtx™·là?”Dßq‰©Ç!üq?iÇöm)]Aÿ! 1“˜Üïõë×S›6m(cƌäååEɒ%‹±pÀ¢ñå˗%€! ˆË”1þ;Áu•+óÏm'§Hƒ7ڂł·?îÓâ53Dœ¥VØ"0·íƒdI²ÕîŠ%‡i8+VÞyI]jÚKÐݬ Ÿ‹ýš¢žu9[&Y|·ë×Î9BÈ_üþ åàt—^¬²õýB)(@Û²‚þšPËBѧYP&ŸÖJþISi e#¶yƒ”Á„­ÙSVv'“Ÿ¿‡Š iӔ!L®o8#·3g€ç_€æyk²šý@¹yMâTØKŒá°ç µ ɖl¥ý U@® 4I{…˜„bÙvqgjRtœØ,ì¹k$A€bNc¥íg!/•6êÓîü;¯R íì¬öSÉâß¡ž†/²A…®iŽæ†Ãø-LÎå‹cÂñ 2Ëß·â°²uöÆ~L˜e¬¡`lÓ§:Û¹ýÍ 1Žð@†ŸŽç­)~Íݳù¬,bÀV– ƒ[.Ï໬io ýXPÑŽ[±íÉ€;ž3à‡ö"àO“èÇ1K§{R‡µýžÃ£»®ŠE‰.‹}ŽSl äDÛ7 ›@š~§2·H`E-ÚŽröéožÂ™hޖ/Á_Û'Ì·;Œ£`ã+¿ÇBÞo^øZÄ`‘iíqK?û …(‰…0Î £"ˆvuXKÈþþfÔmD}ÁDYÄÁõ.\˜³ÚÛÙgU+Çp±A2Ù×·ŸêX0'8ÞI/žŒó[Ža蔖¬.«uz*ö%­zV5±¶ºwó™ÞïJš¬A+Ö1ÀÎ,™ç]že|ß{((¢û±ªþ./à9ïÆA‹iƒ}¬Œù~G›¡èÑ ,ñÞn? Vv(}οRœ"âeE,¥ò±=Â(ñ^4ÖûïVÖ! a5Æ{Iœ†Š€.ܙ(ÎVD1ŸHýþpÚÔΪ«Ñæó¿²ÏÏ<¡êOÁx'(^ì¿äkš.f„“±úèêyžJáЄÿo·W. ¯Úãì{šUgYaìÍDéóWhŽUÑÒœ@r38%#4?ÈK€ÀƒB*f„êԈm'2q}Ñ둄ýy°¥”ɰyxûþ‹Ÿ…®6! Aq8·…iiØ¥Š(aòž²ÁñsŸãdåo·KRá|A‡ê՞çüE ]š€>m°:†¿DÕ¯V˜zsˆ›Büã`Cð<ŽA»‡šrc®Á_Ê]x;ƒtª`‹²óÐU¿€¿Ð`¬kÜ0W²‚^±4ÑŒHß ngš=“ìš…_2ðG›¿H[|ž0AÐÛòtõGמ<¿j«©2¿aƒÒ{êjStýüÁãײ`dZ·¬20ºvS헞 š^Æ7oޔ?1-œ0­]»–&Nœ(Á>>>4vìXQdÈ`Œ ÍáØžq#ݺu‹,-Ù'<•J‡ÿ`(ŒŠb!]e$T³ÍKÙ°z2-Ù=LTdJä°º^¶cû5\X”­–šw­B£;; IdãÔYÈ/…0UH=E9 ,Œ*q>iÍ@6lw_ÂAqð6^yx”ŸÇ1ˆ¥mdÛsÇÁՊ!EА6a»ú¹£·E!:cÝ_k,…”„ýoˆßYöÒ%^˛еš^xWŠj~jÉí¯ÀĶ–·*këG`5æ`4…äºrú. h6OÔ€£õf1·ÈsˆŽJÁš`%‡ ®š»Wԝcد>ÆÀH±dЧÝJˆ ®«š5ÉpE­(=ƒÃ{“ó!ñ³EP܂íÚñ 3„wÁâe³ˆCòL}ó]@6)6NlQ4ïeh@ƒ Þu{ªñ ́ïòý#Yõ}ŠÕßëåž ŠæoègÙ¢à»`Ç QނÅ¢ æµÒÆ­+I€$&4I6 |AFÃVAÈV¶.I(.õPϝ&^ú/Â]Ï[‹wõ—Äk6[žŽ¬..€šÖ#xŸ!ØÁï× U­ÙbäŸRÀËëÂ}Zy€Cö؃*êiŒHSø)?fŸfØ`íØI0Uˆb\#SöTÜçZb‰RŒ’Ñ/šç•ÿ†šªbÞ%³yÑ ªm,FŽ)?A|«w{ÛËçur rÕ Ès…RÔÖËö§ÌìG âÏïÊó"SÀ0<œƒ…ÄÉâ³ßr<º|ê. l>OÆ`4{kößßXð.S}ߕ°ªQ ‚þ쓖u'x£ªˆ9Ò»Ÿó÷›5G}V+ïCXË賐jÌ÷;ëÞ fÉwb„*‚ –Å(ž¯f췎ïtØìZ–±ñS~ÃßùøÞkôåãwñé6áEÌ%Íþ„æýŽÅaŠg'8oͱRÿ®"Þ„)Q º2yÿ¡ªÅOáÝÑðºß—ÿ’ÐÍïØ–+D·Œë+Š’Ïý»Š¢ ©'éDàº÷S±\ðŸÿ×·HIùÅÉPGbŬ ¶Z¯Þ|bYAhèõ"ÃñAy=k¶Ë˜xÂÄ·¢ÂÖÖàŒÒõ„/BEڊŠãŠk\LÞŸÿÌa’Cš={€/æû‹šZú#€ŽkRU“TÞÌW¢VÌFV [·nâRŸ<Ñ­9s搝%H€~þüI£F¢AƒŒCšDEŒ-Z$VP;»ÌÔë‹pTìgdj³²¥»mŸÔ˲¡šÄ$•1[j!#Q ÑÒ«LÕ|BÐ<ô~.[¹ÿûý‡º0Y Òk$ûjž:pݏŒU|-žšØ^ïel%°Å|ãéñBèæ,QH<š —ÎάiéØîk²Ÿ ÍBcPŸfQcâø³ìg ²ŠQó b §qQVôB ®O»5ÃÃ53¶ëÏZߗ^±ÒÖªçrºÇÄφSãµh)x   !ðrnÑÝ·Ï¡-Åzq“|£JÁû[Ù·]™à·(ahU0,,P%ðŒ‘ÙGÖWMªÌÇJæuUìC*2Ñ ÿZÌða!—1?ãĉ#ö#•êöûóáíêV{šX¬¬>2ZlÆõX&>¿Î»ØOš ä>ä~‰æ1­x‚…ŸÇ5+i%DÝŠsV~Øh ,0 0Œ rÇÏï(„&Û dKó;`0‡0BQŸ‰oÌsØo`Nb®bΰi*ö)xÞÆtY*ï…L¶ßç@\㜀g÷¬ðÒÆ‚➪HIV;óæî‹å,Ògx,_9sW›ƒÏS0Æû}⃌›ƒ=ãuø5ëÂJý\E ,psôŠÜ™‹R¯^ºí* ¶ž°°° íJP¶Ô?²‘îÚï§¢7¿2ke jÛ¿±ŸSúÈbµÂŸ?Ñ&sä~à =cU.ÈÆÜÙÓQõòùšj¹|:Ã맕Qç.*ž‘w¬œ×Š^£Wù³éˆŒ­œ-›ºÐ“ŠÌBŠæóoÌYœ£¡_«•àééIϟ?§J•*‰·°Z†#ðþý{ š›:•}éÓ€¡Ì™3 AÜŒysÃ/ÍÎð#Š¿ßck­Y‘&@+šÁì¯; Má1ŒÅ}š¿|ú. 7²)á[Ø%Ô€nû 2dMÉJÄB¬®ìd„/ý»]ÏøS@B¹€ƒß@b*_äA2Ã÷ÄÒŒ-اSûN1(9±e¿qûò¢VÓ,Œ™LƒéKÞNå&ŽÿÁ–pŸ>|c?ÖÏB\a«9ԓ „Šbi^ ÛÏg3q«O›p+§ïISÀ™‚ŸË¶}Wщœ^B¢`Û>ˆxM¢ ϱݖ<ŽAœ!, €"ˆ-šQ ê:YÔõ ­Ã¿¡ß@ˆÀ°ß ) %v3 M56Žù2M!¯õi7¶ùk<{A‚Ø&   „zOW={ô††™; A‹c¬; d‡_ªŠM® |Ccڋ¯Œ¶Òçý>mMðÄÚlKW‚=ˆ.ïàpR?SkŒ(ƶÌ.]ºÐ ûÖôçÛÓ°î‡z}`@ðß3¶¹sdrŒR?sR¬Ú|œ~²Ò€û…Is,•Œ‰ax^ëôéÓÔ€IzöÌ7Ä›€ž=ûŒ‡g»¢Òœ`õÿá-[¶ˆzžN:4lØ0*WÎ8ޝQ mm]Œx1™ššÒ»Ÿ÷iÉZ•(¯1Eè§ U­a1jÞ­ŠVïK]6P aÂFiÿ›D} "Mن¿Éc(ŽAŸõՀ*óvvlõ†šñôÁ›ìß{‰n³Çåˆm„ÒV [Í+N’­üúºä¬üÂÄ'H>x[í°×(mÒlÈUà¡ô[[«eBµ›r ˜ƒo Ø{VY‚<ÒE…µíL›Ÿ+% ÛùÍ:V¥mDæ0M’<èà1šr±À¡LfHp}’ða¥j3VÆ*÷Sˆâ5Gƈêó+l?óLÊí žŒ@nB‰yãÒC&ß Ž86/ªù‚EEÀÐÔAÈY+¶y®ô=׀"‹3X°ß5ˆUØNÀîÍûÚ!ªa!Ü"jPšáÞ!Ùùóæ%ïý?‰nè50&>÷^ÑÆ³VÒ<·Ø1 ,¶¶g™”6á÷ì"`û²õ:+’sshfﱍš0{ìb1D*lŽx\¡§LÃRaÙ̝BR×kYFˆlÍÂóv“ÇÒëÂCQ8c|Ÿ=~Ãdh)‚•ŽfézWò ãc»/ce‹ ú\#¬ßïX\€GÉJyüÆ‹XCØdë^ÕDmŒÝß}ø!÷Ë¢À¯Å‹mŠÇ»>} ê,];wŸƒ%-uúЇôêy*¡EÀŹÂBQ|ûöm‚Êbª‡züxÚvªç«ššš„k·|šh]k²ì߀l‡š…ð*êi³;yñY޵¡XÉ|=ՊœŒ}û–Š/N>b8{öìdkkKɓ'§§OÕÅk]£vôèQÁ ¡Ä)SŠ$333 šË”IÏ{]÷ˆ.Ÿ;;;K€ßû_T¢8œÄ$Ȱð²ù‰²ÄÞS—Jж¬kږ!šiÒònBØi+šKá[ ’Ûѱÿ‚ $RB&Šq6C¢€ñAÍ·ÚaØN pÏXm ÉЁ(†Ârôl󐜊瀌‡…‚fˆY˜Þ0 .nH0 ÜÄ"FÀRˆb„³E¢£éXôÀ³š+wFßã”6ÔD$ÈQTÀç €^»þ5Ùò§’„Gk#ãÑGC¯¢ U(|CR –¡ð‡J±ÃÑŒŒs ېÈV˜“oAާ ÙŒð~¿?,ÚLìâ·!à|KÌïä1sÚÉĐˆûùÇðxòN‹“ÂíçWHÛ«žspsŒMy²×K`cõĞ={èʕ+4ž5§ÿ|sV{®" " "Á ŸŽ‘f.ÞMçÜÇQñ‚ª6€ÃqáÚCòˆòæHG—wلÓ]£çm^ŸþHN.‡šU£ò”¿ÚÈèÙÉ(Ô+XHxxxP’$Iü‘š^ƒÅÔà >‘™€™·qãFJšTUà/_ŸÐ… i̘17n\ û7nUš *b y ¢ø-+ŠWlœËf*~†à§uÙa1]8q›\ÏZGª-ÿQѰiùuöŠíÓh6™³¿phœUʅÑóªðyvšäŠôÑsxCÜ+Øu¯;,ç¶ó _ ñÅÔUÂ(Šóe+a|¢xäȑԹsgʗà87ÿOvAœŽŠ€Š€Š€Š@p ›žJÊJæf&*P¡@à§ÒOYàIfu‹S‰:#)Ö?Ÿiàj—qéÚµ+%H ЅïÞœKëÖ­“pµsçÎùù„âï%KúŠT?zôˆ²fÍ*„g5äz_kÔš‘?Eý˗/…(5j”¥1¥îß¿/vkÖ¬lzõê%3µ G`ÕªUTµjU ³[é:µ+oøEÔ3T¢ ÛW§™£7Që&Ô¢{Õ(؃˜ÑdŒç[–±¥ß¿þ“D]!…1•°ïåCïçÔ±ÚTªT·0Ù-Qw¡…=âêTTŒ‰@˜yC¢}èû÷ï4oÞ­µÖæê{\dï¯!í›1r#íÙ|ŽvޞbÈiÑâØÕ{ ~ê°ÇÉ]HµŒÓwP­z­ ’sS“ŽiœãZh·ƒìœ»P¥zEôœ„z\G LÅð|òä õîڂþ<ÝÅ!R›¯" "§tL IDAT " " "à‹À™K÷Èmß%²ކbgi¯ÂJB¥ëÄ "þü¢ÎìׯŸXBXYYù³•€µU¡B…èñãÇBg̘Q¬)–.]JºCÁßjcšgAƒ<~öì%J”HBÇRŠLÊVGŸÓáï<|øpñrFà°aÃDM“Bú"jT`ebbbÂDñÚäáLõ[—šŠD‹ûγÞJžëO“ûõItbï5Ýy‰>1A©ýñݲÝ}Ieªæ§î#ëSŠÔI¢ÅžêÓ ×¥‡i÷г4{c?J(ž>§DÊcÂbÝu•Æv[J‹w¡Ì9ÒPý|£©v³Rd9·]€Ä "µuÅ1šméJ³¥"—c–Z› ïqч°ºçŽáÈ}íIÚ÷`:ÛxÅ«ÛDºë"ȱE)‚Ÿú˜9æT§yéH×Fc5ÈØ??º×Á–BÉiâÒnŽpÂvZïtÖ# TjÅ Ü (Î^Šºw﮳ñX±óGçQ|ÀŠ+äËIÛŠÕè¿gîúœ¢£" " " " "éðºý„Vº²2aD3Š“­#Ŋ?Ò·9²6änïÞœéçϟb)QŒxqñ¡ %°¹¹¹ÇP 'IâK–XXXÐìÙ³… .W®A] í?ÿü#°€hÒ€‰šŒcB!è™ ÍóæÍ+^ÄðpV+üpqqk“¿’ëÎ%T¯•J‡}l röܵ'×%‡ižõ6VQZPŸbYBsÙ(qî<«­Ž‰û¬TêôIiÊÊ”»`ÌPÁõ2I7/?Š;EiO×°˜Ã Qì°e%H—@âôۈZ÷þëÏ%&y5Eçöôàös*WœM]Õ#È;é{\53Â.k?ly¬;M»œ§RÜø1ã÷#€œÛ²í盗µpÇ`*P"k„AXߨØ??ðŽI–2ÍXÛ[©Î»- žø=]­˜€›#{g-a\뉹sçJâxœª…èϋÝ1Iµ—****сû_ÑÂUÉÚ¢1%Êތ(~ô³/Aėµ,Y²”°POž<ُ Vî®]»vb¥,Œvá-üû÷o¿&&NœXVºA gÍ}¿éóƒDa=cÆ TS+üX»v-•,Y’Þÿ~@[v/§z-˄#¢Ñ¡&ž:tyޜLëx»ëŠY»åËi¢$ÑQ®]¥Iâ# •(ÔaŽÝ(Î?±iúš^”¿xô¿™æM_>}Eqñò¹"å¬>äqIÂû‚ ' ‹9ìsïuš:™Õ}])>Å­Êß+Ö1^QÆƒ^µýöÕGÚízŽZõ¬© ¢ƒnY¿’Lj ±óÚS†‚ì’ŸÇEÊÉŠFM±XËãx–ö?œŠ«D­S¡&î^g†,Àv¢ύè\Æþùôû·ž‘“ÇÔbžŒ›ï!Tûxç7¶¢Á2µk׊rEÒП—TÐUTTTT¢Ï_~ ™Î»ht¿”"GmŠ•$zÿâVƒvçÎʝ;·Å>Ôz›Š+ÒñãÇÅo€±©©©ØT.\˜ÌÌÌšoߟÑÒJB dkkKoÞŒ¡†  A Պ8Ö¯_OE‹¢xÇþUÑzkkx¡|ëÊcÊ[$³x;Xm!š(£»Š €Fí#šZ£bâόòöò¡Ñ–Ð×ÏßhښÞÑZ ÷æÅjVÒZúm»š3U1-^ÓÍ ûޝ<™â±"sÉžàœÃbß»ñ”2±íÄï_¿É¢õçЁÿÛðmàÓGl ]›ÎÐú“ã(eÚàƒ©ön9OvVӄÅ]šrýÈéMúëçoêT}*œû™Vì©5lKß㠚Qäà‰Öб=WÉãÆä(ÒâÐ7sç†Ó4eÈ:2ï[ƒzŽ‰Þ™"añóãûן²p™-O:Ú¶òî/hà„Š¡õ Q7Ç[¬(6r˜Ýˆ#š[·n”—wJýyu$ʀ¡6TE@E@E@E@E 8>|üJÜhXº”>weŠ•BU†dƀΖ-›x»ž8qBë%`­P¶lYa|èÐ!9Šâ8qâ„ä¶Qò|€zØÉÉIÚ»Ž)SŠPüøÑ_alÆ ²pë ·ƒ«Ø74úz F…ñˆè6ŽíŸ”Ÿ|üN¶‹;kU5ÕF…(m׿&õÕÀ_SÿŠôãûOZºgžšY£c]:y‡Ukó¥ka˜ôúùÙq1-›3ĄGÛ vôšIíÝÞö‘bî\Bã·ÐŒu}ôöžÅ>+÷õ±ø¡‚žËöƒ‚Z­È…‚¢ØýÐ ˜R+f"ðû÷Ôºœ-œzöÊVËG“WôЛŒÃöhš"ƒ"ä ¬îÕ`uT›º ¯-Áu_{ŠŠ _/}›¿m *•Ýèý„"Ÿ›§n#êS‡µ ŸG«²¶ôâÉ;:µ%}zÿ•ÞœþÄ ßÿ(K®4Ô€cEƒ¯Ú®_xH}Í…s®õºÜ€A.bCвGUʘ5=ò–~~ÿEI’'‹‰„‰ÿ.Bz¬;EöÃÖsžb>ªÞš8=yðšŸ}ùAqþÍ€¬ eəV¯{†ÕA_>}#óŠ“(]æäè6XëÎ} «vFôuA@bþ¯9ª=ä/¢ÛhÌû»ÌßG‹&»ÓäåÝš|­BÆŒt˜]KýùfЪ!;ïŠ¢žK—.:¯ w˜]çΝÉÙٙâ|ºBޝÓyaõš‚ÀÐ ë©oÇꔻh-V«ÁUÇíëׯԫW/!‰2W°`AJž<¹XLÜ¿ŸòåËGGŽ!KKKZŒx17NìÔòEà… ‚ÔÔ%J” ©S§R5Tx") Š$øñ¿GŽ÷ÔªÚ X$m©Ú¬ð@àÍˏÆw”ŒÎ? Ó[SڌÚÁ4Ûóèî êPe «‰M©]ÿZšÚ­ötjÕ«*Õm=w±¬w:H 'l—~oÄzöèü¹zö>Ìv;,™æmšërFÿüîõ§Ôµö4=»­Ö¹ñéÃW ˆ|úûÀ[ɯ_x ~£+}–”4Ý¥]8îMw™TDœ¯úÐËgï›8Ynß*Âßw‹§žÓšyûĞŠH™ZñÕ÷8£P$¹àÈ‹yëœN˔HÒÜP5‹7ð녯;‚Ø¢R©??¢ÒhEÿ¶Ýzꠞ={ÒòåËéÏÛ³ôçýÅ菢ÚCƒÀš)›šC³òTžŒiŒ°žøùó§(Zõ­öíÛӚ5kÄjØ9þ~y³¶¶–Göööb'? $ 7nÄš0º °Üžq#Áº „zõêÕiÁ‚B@ª¹زe å̙SˆâÝÇ×SM³’‘»Á1šuPh]<áM‡=. qûøîKʑ?oÓïM Æ 1gÝdrj/y_ó¡Ôé“ !Ñ€CÅ{ƒŒ„¢Ø¶ï*jÛ§õ²ŒÞ~šA¿jÎZ2ÍSü0Wâ±1ö‰=ëÏ$ø ,,•š›òÍL9yNÅOW¯[þøú6žCYnŒwBîÚUž$Js(΃ª¶ÛhÃ"_ë&͹]©naÊW, å.˜‘’¥LLÇ÷\£1]–:6=+vk4))„xîB)}æ”zõ7šƒ@XñŒB'ö{Ñ=&º¿~ùNl›"º]—&Ïu§ÉywÐ~Ð œ;V›B•8Ðoü‚ŽZÛ£ïq!îP8q@3ö%!ԍ]ðÌ>wä¶X²(‘•²çØçYc6‘Ûš“äŒkšŒïCZaõócãâCŽgó9z|ï¥`…g ïýTé‚÷ ×ÖõçGHGX=O;Ø£8Ÿ1=а2fÌÂVÑ?¯OП×tµAý\E@E@E@E@E Ê 0~ÆV2«[œJU4c¢8úû‘–.]šZ¶lI#Gêþòîææ&ö(š…»wïîo\<($(BÙ`AkŸ;wNŽøœ!&–„ÒÁž}óçϧ„ ÆD(¢dŸ·mÛ&‹Ÿè1í=±‘É”Q²Q¡Ñ—OÝU\õÆÅƒ ·Ãü¥L:zr˜Ñ›ýº2/EšÄL £DI‚öø>ä~‰@Z>bR9C֔Բ{UjÀ[ì•ÂVÿÁ-çÓ÷o?ýA'Nlê<€.µÈ;MbÅò÷Ùé7(O‘L”"uúøî Á/ô)«5-ç¶‹…ŠÅÇÓÛWŸäœùғi›r”-w:ʖ7+’“ºÈÁ³wÓ©ý×¥ØvoR³5í\)T^psž/Ÿ¹‹ŽìäÝ¢ÿý¡ÒUò2¡ÝˆÒeòULãóÞÏ©dÅ<ÒޝÏÈ/Ÿ[Ô®š˜x¿O‡˜ŒÿʪV¥ÅLrÑ{Z5w/ÛAÔb[S¿ŠÀ2÷us9)þÌŠ­ËRƒ¶&E«f…]ívŽÛA'özQÁRÙš`‰lŽÉù0=Œó‚v\µ«Ckÿö ² `ãÔÉ(j\Ž¿EijÞµ²­AJæÛl£|E³‘‡9|ØóruèÛØ®K) Ï;XëÕ{ƒœ>î /}؇¬˜µ‹ÿþ‡j2©lÆVša{÷%Óv҅c·åTœb³ÕEoŽÍ3}ŸîuŠSJ&"íWõ t)]ÏvpsV$ú­¢ëÿ†7éXOlîï™éóièó…Ø}Ѱ YLjáïôÈðóCñÉد€ü.=ǜÊ×,èï£l sæÐ *S%ŸÌE,ZMކ&ŠÏÖFÝdqÇПçŽÞ"—ùûeñÏ_V¶©Ú (5æq ͪ¡c¥ù0º¢J|á™3gÅG˜(ŸùQP[š" " " " " 'vfW³B~ªP³%ÅJõýH±6 ±¡ BÔà»{÷nªY3ø0Ä ‹AtŸ~ý:Pàڐ!ChÖ¬Yt÷î]Q>|˜Ú¶mK 6ô kÓs¢ôaÀ$:ì9à× \Ǝ¥ûS¿cÇʘ1#}&ÚÆU|<Õ Z2!†mðð"…ŠW³®»/¡[øìԁë4¡ÿjùdo&|ÊVËOÉS%ÖÚ0: ð@`¢° [ïQ–sÍýB GwrŠûŒ˜ð)GÝGšŸà{_{BëÐA·K4tr ú'nž%$@IÒèsŽ “8à® kë([ûQ³¥¢ÕGF3Iê)d@òÇ$HWTq ˜<®ÝŒ”|Á‡ÿ&|ɇô¹Ï;ñʍÇDÂ[³`œB22šÅýþúù»ô÷?~ÁŸ7KÎ4ŽœÕ¿ óVÌÚMËfì€Å;‡Ð&Ǜ;ù‘£fµ¥z-}-3Ðvç©~ŸáßæºöâhšxOök2W Íʚ;-Ù¯î)äàÏ¿Äz@_L@ԟd‚]ñ×·ÝÊýAòcœ·\Žâßкzö9XmeïÔîB†¶0 YR£våÅ7"h¡ívY@?¿c  /ØP̶t%«…uŸ¯@Œu®aÏþËošmwšèFkî÷×ÀxΗªì»3Ї‹a…ëÕmQZžãرc ÃākDaÞ~@`+à8 é<¶i©)Ï¡¶Òç8؞`Aó ‹o_}€_?Ë3>|Zk¿KÛö]Iû™ ®X§Mpîâ×n,.Á×çþ+J–"uŽ`µ8åNÂ¿ƒèƒú| ¿Oðß ³²ð‚°A(Eñî¢üѝË{ R(}žåaÌ[$‹<_š¥Ï³­ [̍AÍçÓû·Ÿå]–»`&™{PÍÃòãnèóùòé;QÖbN mv\ïo, áýµ{|~'"ð2Î?C‡·sk•ÕGÆzßGôϏŒš×²Œ­à5dJ yÅá~ž?~›ß»è6“ÀËö ëüŸS~~(!Ÿý¬šðœ*!ë°§@ÕkU†FÍlK°UÑç簜ϟ­ä|<Ÿx—Þ¿ùœŸ}ý!sßfQ'YSKE(Ÿ~ýºØNÀSïÏËýôçó]ihƒ€œãN*[,U¯×†ÅQ›(>zô(µjՊ–.]JõêÕó#///†0µžqãRîܹåÿ¯]»Fñâù*iŸ|ù"$ïÕ«WiÒ€IÔºuk:qâUšP’$IBØab¥\\\šS§NÔ¢E Z»vmŽ™†täùóçÔ§O‚]ˆrXpµ¢.îîî”6mZúë <·™ª5T‰â°M|¹nRdœ£n^)Ÿ°ÝxÛÊã4gS?!02­œ YZõ¬FÍ»UŠÄIý«P5Û R ہ‹—Ï%äPŠì©…1 bhâÒnBT4(0†UÉIhÕ¡QþB¿p-|Ù~ÿæÚÙQ3jÑ­ŠÜ¢~ŸÑ¬æÌ,Ä&”¶…Kg§WÏ?=oëþïBN!”+NœXÜÖ*ôãÛ/zòð5DÏ j<"ý­Íüßð¥ÞnIQ‰¢rÐÛë‰^ Ÿcäíå#„ˆô|í˜O£¡mҕ3÷„ÎS83)Ãý­›Ðr&U•úE…èúxºKo:ÏJÒ¡m… €Ú/}–ì›ûšÉÀô4¢ý"!»Av‚ôD«)Ÿ?+pÎèYæŠöŠ2©BmñΡtûÚc¹&JL  µê¹‚í † ±¥O»5±š:tÄƒ=Ḧ.šµr Ò JWÀV[$`Õqpmê:Ìâ®MgdQÅbRs| /[—› „2ˆå  ó³S©B®¢zŽnÀT:;~&~Òì}eޝçÅG&”Ap3É)킚ÜЂUE÷:3„„Ä8T÷*×Óç8%Ds BPÀƒˆƒÇ-Œ§Ý¯Oòk¬f4u`«ŒdÞ¯&?ߕiڈ ¢8Ç"<ěvª$spËŒkà5cÑê³ ïX@ٍE£)+{øë6pncbÇÖý)‡ v©5M>Ç»‹\}͒ÌþÃÞãe‘BŸçCQ/7+aEåøŸ#gŽùÛ=Ÿí Æ êv'²çõ[2ëT‘úŽoBqãýCûYAmË ãaö-eÁ ï%CžOÚIÄ;ÛŒÂDYÄÜ5³ `ŸåsGnIs°Q¹~MÛŸú8͵Éß»W9 2üü8ÉV+£::sž^AY( XÞ~¡_¿S³âV~}žy™ƒLMgÉϒ‹Lœc¢ßØ¥›è¶]ž žëóó£VӒâώÂÏ9kÇN2oñÜ"Ü‹=ìÆ{?ÿÔRpsºMy³” =ü¿¯‚BF¯0»³gϊš>„ÿ=ßEôÕw%M-è€Àœ¥{)oÎtdj։ÅQۏÔÇÇGËT©R‰Ê÷ŋ4tèPÚŒy3%K–L‚Õ²gÏ.¶ 8§OŸ.Ÿ£fϞM~CŠ|škÕªEûöí#X*àØ[·nÉ.£e˖‰'ñÞœ{ýÈæè0ôéñcÇ?,Š›˜˜ˆ-Gþüùõ9U=&’#àááA©S§뉣—¶SUS5Ì.,† „%È!ø©:¹ÿ}ïà^ø‚Ý¡êd!h¶]™ $òw&š pˆO’<oŸ¯BM»T €æ»xâŽØI€„ÁøBl3¢mí‚ý²œuïjÔglcVCúÎEô(}Æ}ëæIÛ—gÕXKQþÖÉ5BH'l·ÏÎvó¶ Òt|ÏåþH¥­¥í«ö!TÉØõqÿæ3!@š.Ý3\TϚ%T› ‘–ì Ú×Õб±hµ@ÐEÊæ`UpYVŠ€kçˆÅڎ鬵l¥‡¢ª^¥Ÿ áەÛû‚U‚n×&2A»œŽîºJ ¶’qT äH4”BÊãïöÃ֑{Ô¢Mh&c‡š3֕¶,?F,êP5ö 6Øu@é9~~±Чݚ˜žA;š#CUÏ2”Iù"œ›CˆÈÌ9Ò0yW•Ûž¢hw=gíÏ&c'[²L²ŽÙ1ŠlW\a1£My;±ÉšFUÎÉ4i‹ügUÓ¢~!Ý.²ÍÊÿØ» €šš5ú ŠböûíîîîîîNìÀÀîî°[±»[,l,zߌžàâ^zæûŸ؝;qæÆî™3çÛ Háù;úŠ÷°Ús ÷×V%múU¡"eÕûñÏfÇ6—…BñJ!?Gu•ƒº„0ð՛¥ÒÕr³í„‰X0Âk»×ÀŸ|dÇU‚\3N_,è@ÙÙϺQ Íøë *cŒP%+1‚Ï;šÙÅ9Ì Zš$9ÔÈè ÔÂð‰V|±{«OÇwß›[˜òB”;|íł€šëŠdDíœ#©VóâAìIÔ^ÛÚΏ«§‰ÅŽsl{ª«qŸ]?ó„ •ÉNFÆñé'E Íõ Å-€×8¢2[ hßÇ$§‚ÈiØ[({s·s„ö‚]}ÿR©ëÃócÿæK4{øvêɖ=-{UÒzÙ~(8+÷UœXZ8níZ{.pÁ •éz~ìa<çÝ%Î녻ú ‚Y3pmö®7_§ÍÌ?oòÍ…ÀÁŽ”=}‘NWš"б~ƒøòèÿá ù{Ÿ×U¯|_" H$ƒÀjÛ³”:¹9ÕkÚÉà‰b€Þ±cGZ¿~=•*UŠÈÍ͍ʖ-+ÒÁ{Dµ9rä A('L˜PÌ?~üjâ©S§Ò›7o! 2dñׯ_‘õ¶vêÔIË°Zˆ-BÉûÞ¿O 6€ 6©éß[Nc 1qœGŽ¡€I“’;+Š/ÞÝOå™(‘ñŒIZe†°ZžÜjæ0[Ꮚ­ü»nYi*_$Îڜ0€Oq­ÅXiY=Ð: WÝy‚ˆ)[3ŸH|‡{–PÏÞÖKWŸS¿Æ‹Xá÷[ôq e2³JvÉþ¬žc¢•‚ô$)^ºus$4ˆHÞ¯¬HÞoŠÖº D šÁu¶(1‘‰[SÚratž'A!Uó1 ţ󻯁u‚TÂD8Ԓˆiƒ™@µ»&~oÍd{÷Q ù”Dj‡ŸL¥öŠ ¢IŠ”a Ø@% B>ƒŒ‰Ð$fß}¡æÅ' År§¡5Åy¡Ì3Ô)}TÓoMßÎY¬ …_2+²*¿«ÏÒ°͵n‡×œÌÑÂq»™xÏ„D ëd) fI’ÛwO&ÊÒÓ\&îàŸ¬¥Ó6tåō?Þ§ '÷Ûċõøü ¬°˜2{Äv¡ò…€Š2ŒS§®ÿ£‚\6e?bõ-TªðÆ?Dpò¹5«Na±=5ã9'±ƒ‡8°DÛè7üiÞ?¡þ>±û«S›úúb¡aLÞõ{Û}Hž©)§Øe`qÉØp¯P"Y 3šÎDôÿòeÒî X•ó²~»Ò4˜íf”Œë¿ _£š~ÀðÇÐtqàœÞä‹÷öð7NøåƋÔÿmõêÕÂWwʔ)T°`AªS§Ž°N6l˜°€¹ ’ùرc”6mZš6mš ’ *$ì-@4ǖ@â¿¥K— 5õ!wƒŒ˜‰Œ»±øáï=]r8ø×vؘ9êšȓ&…'õ” ”@’ÍnGGw\‚BJ!l Ü=?ñ>ŸofÕ+¶íŠH“„mú‹û\³bցJHøn^<~Ÿ~þðþ©PƒŒA`ÛóöyŽâðàAh[nªØv~äÉ4zÄIž@.#°[ە@9$«ƒ"ÿM‡OÕº¶MŠXsßÍiµ}Є| Wf ±vʶïðΒB4®=>Œ2°Hôglm€X¥˜xÔLT+ŠçŸ …èìm=}ïR>İ÷ɱòè`¡œÆ{ ' Ða³[ø,Cýúú5Î IDATÝŒøÄ@rZ“ $ìYM:š@……øé‚>©é7Ê*¡¢šjVE­Æ·xǪ3ŽhÂ^‘(co@[/o€¿=È⇇œŠu H)SJ( zMBÿ‚ý=ÍI쵪RVxlg±'Xø@ž}÷ zyÆŸaš:¡&†ªò|/bÀ€xËR“„÷¶œã ñ>Qœó8D]L"ïÙpAx¬Âz~ĊçpÝÜ£ù ?jØ/À> û%'25ã )!¥ÚrPð"ÜΛD’ÉSûïÐG¶RȔ#«‹óþ•tv ÚömŒžŽûm2rB0„‚WÖ\ii1ß_àWŽ$w°Æñþå+Ô 8‡@jvæE,X)ž ?ˆô™“3‘X5ÐfFñJV씿Õ\ Y]=»•š”KX6 Bsm+ç§÷ß8‰dBqí‚øîßd‘˜ƒ‘ìAŽE6mÚ{ˆbäFŒ›ÍÚ®ÏaŒqþ8Ç./Ï_Žù|Àb˜BÀâ\„ÒX[èÃóCIØ©‹\×|~l[zŠ@»`6œžF¹ižCºžÊ5Õÿ~†jæ&ÁÚdöõÿüñ?§úüµ@Så>8kK¶úO+æòEÃG ‰b(+?~L ¿·üð÷þfø(ÉH$‰€Dà7+·ž¥äIM©IëÇܰýH·mÛF$xç"ú÷ï/TÁZ?hûøPîܹéóçÏB}Œ-÷H`›1cÀâsçÎ Õ,ŒŒ=z$¬+b[À§¶)SŠ„{ϞŠ1$ °Q|õá*[#oÌl4ìäŸ[‚”—~šrÝŸýDR‘²9(«Q᫐Œ¶\¢YVÛYµY’T5¹ªÄ–%'h…ÍAÂ6^5í+LÖ ØŽû¯P¶ƒ!R@q"娋¬B~!”„Ú¶îCÕyþÈ=Úsw¢ @”/ß DBJ(€< ۊUøOrNŽ…=„Ÿ¯¿PØjKþõ¯qA‘ï哏‚À:È*O~Æ Œ8y×-Aüê²À˜Aį`Ïbxÿ*ŸhØRÿêéGáYŒ±&Mn*üMAnN^ÝElaG?àÇéËääÚãVTÙre͕NxP4ÃÛɗ.Øß‹ÊÖþÐ`²V ùYÑ ‚OM¿•äa“b³ÐªWeê1º®ðiF’±t™Rüsñ@Ác皳bÛ8Œœ›v­î+JÙڏŠÆ-a;ú¯Eò,&Ûq­hÚµ(Šlœósm{ r¶ /x‘ÄîÊž¿’€Aìêüƒl¯²G8û¢.å„XPðÛ¬í„j!D@~c±þŠXqžöœÏMç@ÿdôÛã±8ƒä\ekæ T#Â>ŠKµ™Â“ aŸQŸ pY»8q ÚÅõK,ð(ÞÜÚT[®qáñbAhǍñÿô/Go9ñ¶ý<Î×bGÁðÙ­ØúÒžŠpNÁºÇÜâÏαÐ\Ÿ Q Õ4‡àK]îÊÂÔÒÉûÈnùÚÇ6Cðzï^k6•®š'Ðò$€‹*ºŸŠÍ ž;c¶UõüØ8ÿžHªÍ&×R†,©Äù‚ÐõüÀœ -HŒ˜#ozaUãǯ=ℋHº<ùä¿nN )­xœ‡ûF&+ÐK®`EqúT#ù Ÿ8"ŽßN@à㮗—’H$‰@XXµí%MbBÍÚ°jÊÜpýHëׯ/Ö!2dÈ@ð+Δ)“ð622Ò Í… ™ŒH“&°TЌׯ_Sߟ}…Ê ãØ¯^œ¢6mÚ|ˆóæÍK‹-¢ ÂOÄìbÂa¹†€nþ¯éú{öX•DqdÎ+Øy£wÒ+&Gs±â·JƒÂTŸ• ­{m€llMêÝ+Ì*Wx¬"’³ ֈ•ÁP!kf‡}BûŠÓ8©š«øòŽ/ñ!’gÁŠ"yjsޖrrl>¹÷f =LG¯),`‘+W®PÁBWñîܹ3-Y²D» ‚5Ö¡RøïرƒZ¶l)¬$Ò§OOîîîT«V-¡*Ž­Äœ°Ù‚gs¥J•hûöí«VFìBÖ-¯øéŠã1A~ÉÐð%>šÇvÞ wü„¶JC ÛæÝ+R‚DF‚„Óe­ /[ôš(¶ÔÃóÇW¡ŠºãÄãÑ”ýûƒ@ÓŠŠï×h¡Xh¿ôo2\sŒjËáeHŽüp?¡ ۉ_Œ™ãýw¬öwV.ÀÖñÞ;±ŒàIÀPÎ;mcý×üBAïÆXÁV ,u„æúy}‰ë’ì5{ ,2@¶ªœ¶×Î9"È5›D¶f`Qà1ÏåV]CYŽù…7{UŸv‘„R3"òú„И®k…'7ÈÈx~ŽäX@ í¹ÑcSÎ7mÏ]ma>ÊX|Å␌˜‹À¡•ŽLç8¢ØÎÎNx⋧ßËÕžuÆ\ôäÈ$‰€D Ö!°nûJ”ЈZvèGq’h÷e‹ P,^ÀØö5°‰‰Išš]·ny{{S·nÊ8,ò"A’­œ|ùRԋ8sæ U¬X‘¶nÝ*ÈâV­Z,+œn͚5¡j3&ž9sŠðfY«‰µkׯ„aÉ1„X®`1嗑3Ýyy’ôI†á!€„w6¬œTԕJ–ye$ØF>j~ƒX€_1TŠ 2a€ädø µ19&ŠLÍø)8á 5ߊ…Ç„',Œ'AúM윑®œz( P”jÎ0|œ‘dʘŸ‹  °9¯uDV!uŽFÂ8CN䄨@€Õ Í@™™'ú«(ˆb(c¡4¬À¢ðVÈéÚQ[N9€&¶Ñƒ G¿î±xÔŠo>‹QNÜ\ÕYãUSox¯èŒ¶ÕŒOWœXŒ°H•DWÑH?&=?tõàæKê͋ ÅÙ#^3a£®ãäû†‡¬'²¥‹@E1Œ }}}ið Aä÷ D± ‰€D@" Äf¯8*%ýŽbEqôÅ^^^"‰–{oÞŒ™Z·V÷eJ$€k×®eΜ9ÈÄÀVªb<Ë‹ øÃfž»ÖÖÖtï«ï8Ùr@I[~Ãëׯ§D‰Ñ þŒ3vlä})Ž-˜Æ„qÂräçϟämü‰œNqò3IêŒÂ [²Þz%ù€\Øó6¡‰±°Ÿ(\&»P›ð¢Š>FD]Ñqmë#žáíSly~ÀZfúmìï_2Ö /lòx=FÀ~í ʜ:_  è_]Ue=1yòd±:9Òj0ùœÞšÇC—]“H$‰@è°Y|€âð£ÆMŠ8‰£w›yŽ9Èё·DW­JǎS5OOO¡>†î©S§‚KŠœ9sŠ÷‘.yòä"9[“&MhÞŒy‚ŽMR͛7'$ê…ÚÚÆÆFšˆeH._ŸLP÷û%r¡ûoÎ %Š ‰€D ü É l&ÜO†þ"0gÄvö’œDGŸNW¥NÖߑVÏäõaXóSzk»ì-ŒŸŠ¬é,s2ĔI a‡Ùz"sš|ªs«"Š7nÜ(¶áŽnѐü‘ÌN†D@" Hb[ö\YÙÛwÌÖÑK—(Q‚®^œ*¶Ã+7žB€°b!¡9ðöððvÁ·Î‚ =z4•+WN$€A -ü¡,Ž qåÊñÁèöíÛŒa±‘;·TŠÆ†¹íqýá:òMèBÞŸ—Dqh”å%! 0ŒÝJºué)íŒ>AØÈÐOà7ŒÜæ€Ø†Žíè2¢y}D β• ÜŸôŒllŠ5Ç8 «+‰WÌAàȪgd™*õêÕKç TÅ6lŠâ6-ß›m:+•$‰€D@"`HlÝ{…Œ9 I‡nC™(Ž^ò0_Ÿ| 1räH¡xEÀŽÄ&È`(Ž$HbxøðvïÞM 6 òŽI ¥$ÂÜܜìíí©xñâ†4Maê+|›a)ñîÝ;ª_¿>!‘nÿÆ05&ŠÜžÁ‰Òø|ñKäJŽŸ. _W‰@øØ·ñ"͹ƒúNh@M»V…²†HAÀÉñ#µ¯8ÊÖÈK“WK›HYK¥òúˆ*€e;Ø‰À‘5Ï)cò\Ô»woš"Šá߇/U­›×c¢ØVg¥²€D@" H ÛýWÉÃӛ:õŽbë‰\ÑÚõ$I’Ðÿþ÷?‘Ì µ`Ûä €mÄ·o߄*¶@ýT¬'à3™:ujAçϟ?È8~üøA£F*eÏšÇGë€#©qìøübœC‡BE-C" \_HþH&_éù—+³U†D@"~\9QUóâ…Jßfm—ðW(kˆ4:WIÞžÒ¡GS#­ YqPäõ!ω€D 28ÊDqz‹œÔ§OÍš&Š©U³:LÛé¬TH$‰€!!°ýÐuúþúöÉDqôm³tvvD/à3f€#FÐâŋW~ëÕ«G e˖Q=!Þ·o5hЀ Fvpp )RГ'O(Y²d†4 áî«»»;uîܙvîÜ)0@²>5«æánXV£ž{÷®Píû3QüÆí,•=FOF"Ü»þ‚RŠMJ©ÓÇ®çStb–¶ß;¹Ð7Nú˜),‡Ëcˆ€Œ>œ$šŠ‰‰âOÞ”¯xÖÈh&ÖÔ¹kÍ9ºó%]ԎßyM=êÌ¥Š]ÊS_ë ^걐èøë©p™ìÔ }R2×O^ՉÊÖÌæVä|é†îúÙÇ4}ð6ê8€&ÕiU"ÄԖÓÝ¢á”hW~*¥Ïœ‚Šmèf8Ž€žÂúkTÇÕäúé;ÍÛч™Í#Mü³ mžÏŸŽíºAGžN‹ìæ ²þèž3ƒMG§åóC¿gÕ~Ý J“$õë×OgGUÅøòijjʊâêLïÔY©, H$CB`ß±Ûôöãê=pÅ9¢­ëM›6ÖðŽ?Ÿ Aç̙#ú³uëVjÙ²%}ùò…†N°›øøñ£ð-†=E‹-¢­ßQÝðôéÓiƌ¯¹U«VŽråJJ˜0aTwC¶C€m kâ˜}'Wÿ”·h–:ÒšÖ¢ {è°íU:øÐ†.¿O#™L6³Å? ¶šé™á·ÒµÆl¶pHJSÖt¡¥“ö‘íòÓŽùü(Aԅ5ä|éFnBÏõtúÀªÝ²8YÍjâjËénÑpJŽ)k#í vêV¬Κt÷ôå“Ô±ò QÐîêXJ•.j­UŽá>s˜Üz™NŒšEñâÅÕ=ˆXV"ºç,&Â-Ÿú=«öë^2Qœ=b‰b333jÞ°*ùœÛ¥ß£—œ“H$‰@(8pâ.œzû™ú™HqL£Ï4C† ›xõêÕÔ¿:qâ„H&ëííM={ö€¥K—ˆb Q&ŠÇϟ?iàÀ"AHaünmmӇ-Ç @¡“ž‰Ýè{ŒG”»pæhèEÌi_÷¬¿@ǞϠ«ÏÒ¢ {iùÁAô_Œ1gÑ4ÅæŠ4{kOÓe ÝŒðTòqâÄ sä|ýºo¿H9o_ê1ª.µê­ÝæHm¹0O”žغÌJjaFKöÐÓFN·æŒØNû6]¢ÄIÑÎÖdœ ~ä4B­ÚpŸ1tÚv•ì§“q˜ÿ91Ž€G÷œ…¶¿†P^>?ô{–Ž­E©Ì²Šï˜ºB•¢_X‘…œYƒÊLïÖU§|_" H$…À¡“ôÌə ›ÌÛͣǏ^à ŠÍÍÍÉÍÍMà7vìX±ê[ @zóæ íß¿ŸêÖ­kP؆·³PwÂK žÌI“&%ØsÄ&õtxñ“LJx}Ÿ>}šâ%q'wcGÊUÈ2ô•È#€šxúmtøñTÚ¶ì­Ÿk/ÈLÓÄr@xO“©·TqË ŠMÑO7/ZydHžªÈù:sèŽH\§&!lIÞŸúL•ë Wÿ#ûày£wŠ…ƒªSûÕ(^üxZ›T[.²ûÕõ·,9‰ÒZ&^Ù±%œß}¡¶l¹ažÌŒæ³íDºLÉ£|èÚpŸ6h+ÙïŒN'fGyôœA}˜3}Ç(,ý‹ÈçGXڗÇüã_Qò„™…ØFWš"ŠW­Z%Ÿœ5­_‘‰â=ºê”ïK$‰€DÀ 8rځžŒøH¬X‰e=~€Û¶m6 ˆŽiӒ­­-•+WNüÄt , Œy󒃃ƒAaÖΞQ‡JÓE²¶E{ú‰$³ÚBm¹P6ośµŠ|­Û¬íbýˆN‚=²ýMg_æ•sED•¡®CîSúmŠ ÇîÑ¡GSUÕwp ÛTìœEsl{©*oȅ"kÎàÝϺ¯”Ӑá Wß#êù®Nȃµ"pr£%K˜)âˆbxÿakk“ºåÉïý^ »D@" HbÇÎ= OßÒ œðÃ$züH»uëFX˜íÒ¥ M™2…R§Nˆ1<‹ç͛Gɒ%S•©Ö'gŊ4nÜ8úôéÕ¬Y“-ZDY²DϜ2޲ïaGàÝ»wÂ+ÜÈ܃|̝Á)#røñõ'oÕ6 wåð‚}zï ûóŽw]úZÁ˜®kèç/šž²#™%IåÝ|öð-·›foë¥ÚïŽUéÉäâü·Ÿx·þ+„êœÕç°,P£@ÖU_dŒ?Ÿû:&Þî Õv–ÿ҄؄Úr‘ÑÇ讳aqTžl·ž]tw%JÚÇuэ-`*7(Dc¶’6µ5¢ wÜï^}N»nª³é‚RJøíׯ‰15ŽÍYD=‹0eªç>ü‘Ÿ>Ÿôˡ™FmÒÄÈ“¬;ò8¹É‰’[Ò Aƒt6ŠJQŒ/mH–Ó€n9&Š÷é¬TH$‰€!!püüºûð 5ÅQOJº»»SúôéÅ¿û÷ïtÒWOOO=zŽP ûøøHsXL˜˜„Ÿ@АÊJbðþÞµk%HæEþo({žô±jüQ5X|Yï^su^;DŸWµ}AÒŠ#vWéÈÓiddµÞ jûžrŸŸ~Ô¢ÄDúüá;¯øM]ßM5Yžv5}xˉz՛'ÔÁÙr¥SUmóâÉùÝW2œ¹}ó ¯.näëãG³¥€íË©ªpl“oÖ­¥c낏Œß›‰,$4ï^L̢תäÁ͗ԻþjÑ£"õ[?Äñ«-§ @,T7ÏhªP;€eúUÛåäpí%m:;R$ñ‹®Ð†;—^ÍHꪬ6!5» ŠãŠz¯š‹EEÈP‘ì«CÅéŒ8äKsX¥š¿DØmæŒÜAû6^€m—ÆPšŒÒ?}«ÄõÓöÆ=OnŸ"«Y-(UºdQÚÅçßSçj3iäŒVT£i1­mÃ/[×?Œvÿî]IþþþAÊÆ‡Df¢iŒM Æ÷N\–í3Þz%<–ƒæÉúÒgN¥ã ÞXŸ –›Ïú§¢[m¹hL$6^#ûpªÛº$õ›~ ”Hìf„T}íÌcÖf¹XìjÛ¯j„ÔÖJŽá>ŒÝJ^\úŠÊúížÜw‹&öÞH#掀šÍ‹‡µ+z}œ¶9;sðxM>-;8’¥;ñÚŸâ4úåéMÛØB'2cþ˜Ž{Ý*ÉV'6뺄hƒ™}u§·Œ!³žéT}×R­(N‘"5®]šü>0 Ÿ\4~/}ûâ.8ÍðñfüŽ' Ó,_Íe6[‡7œA–ÙRŸ bïò‰l’1 Ò‰ÖnžJ/˜ÜLd’€flìFYrР߀Ây4HŒÍ‹Ž“ãý·”"9å,hI ڕ SBÅLŒŽï¶Žæïì!ɵޟøLmÊÙP—aµš'qÓÝkÍa•Û›¿ÞªP§*þ—?eeŒ&2Š%÷’ÝŠ3•‰\¶F^á ž=w:2·û3Qí<ï\s–o»J«ìµ{)ŸÚ›¬{m ÁS›Rýv¥CœeµåÂyšèíáPŸWɔNCs IDAT4”Úõ¯J]¬jGx?¡J¿~î1yÿò¥"åþ­JJŒµkYäÁ‹N cöâÖjîi~~~ÂâÅõ“Y/ï «Jñ~Hž÷kŒˆ×ià ¯&¢xð4>ÏÛþ9Ï¿ùIçßå1Ƨj‹ª©*Le" ¥3ÿš3xL¯u„Š–ÿÕðÍCý,RæíèŽë”ÐÄø/»¶¹ãU¬[ p1ý¹}ɑκ+ß<ÿ$žAPtã™ô¯œ~ž=“ÅçiMSž—"AЇ§î0Mž<È ˆp¢xùòå”*U*jT«$Å ÙI‰€D@" šEàì•Çté&ˆâ¹L[ª=,ÂÊá9›&MjРA„Õ©mÞŒ™FŽIŸ?Š‚ u±bڕiúØ٧؁À·oßhÆ "™iŠ/"Q˜ŒÈE ž?$¶?ãËó¬-=(_ñ•Æç;Ð8ö5MœÜŸ{¢¶ì9×Î<"??A/`ÂÉÒ¶-;ÅÛ±?È8A|áó8ie§p©šµ!âꎂ¥tog†µÃÀf‹É‹ ͈/®HÒזɷ8q⚞Eeœ÷îÄp‘­JƒP&6åDeM:— Q-ºtÒ>ºtüå.’Iø ïXu–œž9Óþ{“ÿò¢Æü.¶Þ+Ãå*dɊb':Ëdæ¡\­|!Ž„ÌÁ­WhýÜ£bn«4(L ÙÆ"}–?ŠãÐÎ3T€Àyí «¿Ú…(ÞOdjL«Ž ÑòCm9š7Î?F¯™JkiAͺV :¬ÀÕ ,bÛyƒF/hó—) SûnÓõ³ ªü¹vœÙÎÃW(¹ŸÜ}CqX±­èuZ•€$É"Ο駛'­›s”ð ükk·(.Ú03ÿ㗠"ÝGÕ¡Öœ«ü…%’Y®šqH(Íóqðõí<€Š*’õƹ'd3p ¹|ü.ê?. ŸÝ’ª7 J\Þ8ÿ„¶,>)ˆ7”±ÌšŠ*ÔÉOõۗÖIŸ©Ÿžžàþ͗höðí4~i{ªT¯à?Ñ:€ÕRúòù­;1<fÁ\4~íX}V`«–ºp ÷®Õg‘ÛaÌØØ]ÕЂÅ×^ð}ô æû˜ÇÏ_â\„±'ÿþÊñ#.“Cܓ@²®™y˜ïsÙŎÍû˜@h^9ùPÜÛRgHF%«ä¢FËRš »?‚“°¯pìZXÀäúy~Žî[EÔ­-tÍî-ØÕ xÀ‡¥_fIŠóŸÐ˜—£;¯±÷ú5±ø‡h?°uTCàu˜í’\v hÉRš‰û žijÂÓã—Pã9†Àý!Žu«¹fpÃóŽéml&ӄl…Ô%Bž1jÆ+˄3ÛÞR"¿Ô4lØ0©R/[¶L|mX³8ŇtV* H$‰€DÀ8í)»ú”FMœOqe4€®ë}_œœœiÚŽi4}út‚q£FÄïY³†}›¹ÞZvР€g8ü²%÷¡€9ŸSF&dD œªdøӟ·¯7fbR[€žìRmy{ûˆí·'™<ƒ7*’7}ùì&OÙœð [7€èD@×eh-*ÍI‡"k~.ŸüÃ;9xl_y†n]t$›µ]Ä[#;¬¢K¬~®Óª„ØÊž„œyï¿Äöéwh«YãÇã1¢‰t«¡’Eý“WuސÉSÈšzmJ Ïa†¥÷ ògÜâöõ ÉŽÐ÷Ý·­unçVié"ޖO9@[—ž 2&³¢*S…ÐÍ#)Ö€U·•ƒd^1õ œ}ù™Ì“™RûAÕQ>ŒýJ™ˆÀë r ÜÅõâoÍáãþÃCÌH&œ‡ É[÷ vAà/·‹†ÎhÎ×Unñˆ8Xj€|Õ Ëì©hƊˆë%&рɍÿ"ël—ŸŠe“÷‹º@4ƒ4…‚ç»®Ä_'öÜÞ¹X€âäôuVßÏ|×-kAª¹rÒÄŬR?±ç–è"Î ôïåãbœhÓzE‡ÀD‰è+¬H¢ÏôNLZ£.,nŒì°RÌ i‚®…vŠ ;”E{ú‡xN(o€äÒj™øsͱa”5—ö WO?"ØE`îïë/”÷jp w$“Än Me2ÎCfrµ.x(D1߯.?è哏¢ÏHèÚyXM*T*‡žÆ×ϵ§µ³pRÇÁôwr kœ\Ì bÄÜVT³Y1V}ûðîˆLڟI×@Úc‡ÀÇ·_…Wy>GûMlÈ6%¥(,øàùzð¡è ú„À.”u'­(C–”Aæ%Žs†ƒÃÒ¯_¿ŒÉ™ÇX†‰ìóG؆ÂGžÍ»W€Ú-KˆÝ8Ÿ'õÝ$ú‡Å"œwÅ+怀Éß{BlhêÍ5sçò3Ðt1õ߀ï9…XM?›Uï$wÍæÅØ®€•Îë@ˆ~În{G ýREQŒtéRJ—.Õ¯^”ü?ŽþÊH$‰€D žtӑN^xDc&/b¢8CÖ{«zùò%?^lá/ 8&L˜ ÔÅÞSÂ`FîååEsæÌ!ӔŸ”"—GŽ{£ páè(’Ñ•­‘‡JUÍ#j©õßHòp÷ÞŽ ÿ@Üà˶¢@Á4šù¡LœŽ²#]eÒÅJä-š™ºš$1ª1]Ö°Úø>oqšzÓ¢Ô~@õ±eÐ6tšBÇw_OyŠdæ„C“I*M„ßQÇéÂÓ²N®Q¬&KLYs˜­ kAŠƒˆɄÄ_žAö…¯ž~€.¬Œõc¥€+ˆAB"æŒØNû6]¢MçF Rp5+4¡ÔFã Ë:¬p® I"°š„Ÿ‚LlYr2[2ô%SN’Ø©êLqæ„]¯zsEâH”ƒ‚6žgíÄ>LøóȒý„"^W€ÄïQg® G±he.<¹ak€\ëΜŒ±'÷ôgÂuù¡AL &Êy5ž…„{ãB㩟P^# TYù…¢þðPùZð¢Á^°‚U3”Hà @ Êq¯„jU ×Ø=ÐwBZÇ-ÎÃòµòvP-ÿ?^Té)‘†Ž Ç1ï“Ww ÄJY`r|ðN(²± $Žø@A •òiÍh+»‘@¶CXÓæ­fΠ ž6x+«¡x.„eÞpý89:‹qãܮҰ0ßkŠùTmÿ&‹ÞX˜‰Ü„¯qEɬë|Ò|ÿÞõÂ~D-NBSwh®ìØéQ{®xöÜfÒ÷(ìüžzêÅå…Šœw'ªšCÓY6j8gûŽŒŒSÐðáÃu6¬JQ¬Å ª!¿GtV* H"|Ðǃ͗€ø‰L_Þ*‚­âþ?ýÄ{ÿøw>ù4ð^ÃÊûšÿP›úPGÀk#‰Ãeù°ÀPs Ž?/âÈ  ;ıŒj«Y.ןWU}}Êb!Êàg\Q6àoüð?˜E™?å”òš+ðX~€+eâü"PâŸø=®ø]©Süÿ)ø»8ŽËkÖ¡ñ!2çWÖ-ˆ®ÜzFögÐ8›%L§Ž.Ę6ϟ?Ocƌ¡k×® RxÒ€IÔ³gÏ3>9˜€PÁ›Šô£tŒclr4}šÉÖeЈm᫏xÄÖÏ;†I_:ôȆιGc»­e²ÆŒl9AԒŠ­‚BNλ‹v¯=8€¹vœØ7‡Ö!ß}“¢Ŷ}šÜ°uœU¯J‚pŒÈ)ƒmä-zV€^cê©ZQgå+ž…îêÇ6ÎÔ®ü4­Äžr ¡5r gïÐR4˜É‘èˆJ‡0!”òË"ˆHt ;”ŠUÓ‹ÏÚ;oLb1rQx²¥¶ˆÿ+Žð6ìiƒ·iU£*ǁð³°Eü õžõŠŽâ÷Ónӄžxa +ÍßÑWŒÞyyߣ.ÃoÂ. 9oá×jÊÝŸôL؊€xlÕ»2“Ù™Y·uÉI±Ø¡í_õȎ«Ñ <”‰Pîõ³nž- ž 2Á e®#˜¬ºÌ$bþŽ>ALòqÔüւ$vÿá)ÊMfåò4&öṛˆÉ`(0÷ܙ(ÈÖC· +ĀI¬î°µ_IšÕaPu¡ŠÄvtøTkڇÀV„0”§žÖJWËÍ$¥‰ ÍqnÀ‹zùÁA!žPPC•|!ý~|÷µ°?@àúÇ}õášR¶â+ó»wœùÂ:»Ð' ÝôÕî=®Ÿ8o0s S^œqg¹=ûÊþ±–@¿AúƒÀÇB…šPA*Ä=<ˆw®9ž@ ^øzÊíNg›ˆbþžëjqӆ;úU;çHªÅIé”Ăˊì j ¬ÓeJ!v-ž~úNæ<Ç ®=‹[J(ó|ŒÊœà{$ŸKc‡vtfÂÝùýW:p ÛûŒ< ¢ždó×®üTAÂcá ‰2CƒOïúó…Âß]²Ê^ì©Ò%%ãØ)¢¹“Bíœ)ÊlÅ^',óÖ©êŒ@k#ÀxfiÚ³(Xâ~Ž Ý1ÿ‰“&âs³Œž¶‚ïø×9ŠÜ5¯9µu‡æšÁ‚ƒUÛ‚;ÀœWmTXÌÛÂq{h×ÚsŒš4„—ä÷'5÷ƒè,sÎî=Å÷² #Fèì†*¢ÛïÒ§Oϊâ¬(>ª³RY ö"€•Ú_üÆ‹·›üâßœx« ~z3¡‹ø°ãõûï_œˆÄêOþ †/ŸŸŸ =ÉÝÃ+ ¬P(ø“'×áÃïXÅO·ñyå îãÿ&?±e*ÿn?žðæÂïñâñƒ#‘šG!Lñ·÷ï¿A”¢<êSV”K`ŸŒ™¯ ÚíñMQƒwKþ€«‚Ð (i­„ÒŒ¡Ò “AÌ*$µ ³¹0^óáþj›û Úx0‚ôÖ|M©+óâ[ä¿ sc^iôðü@”‹÷(l”1I”€~žy”ýýžB²'æÕö/ß~ m Í¿›ð‡ Ž…9øC,ÿ.Ã}4aCÿ_|>ĉà iñÌsÄÿ¡<ÿ!ðÆ˜Èé8˜;”$v<2âՀ¯q!þ_Œ€c¹|<`Žþċ/f åEXœ@ ãoèš—çãø]цxMÌYÜßsû{ސ”ìK™Ú<`ÛªŒØÀÕ;/èði²žÊꇄébÇ #x”Û¶m£±cÇÒǏÅ.€©S§ › CDêw³Tþ”©˜?ù ؞,#ò¡ˆ/ó‡OD0|NÍY¡žæ˜«ûæÑs&‹öôãätiÓÂã"áÙDVã³Ãªé‡Äkù˜À„¯&~.ØÕ7DO_|î¹uÁQø­‚hÃg©RUs3ÙUƒr䍘]%Pyˆƒ *`%ð%Ÿ'+á“\¹~A·€=!ÑQ¿Æ‹XÍøoåï"Ð ~2çH#”Œº$ǚY‡9±X5Až…7°}Œz6+VœÁړ²çIOsm{ bŠðƒ[/³zµk ]ڛÅ*X` "Pé”h ч±µA<þ®ºÉý61©^‰ÓJâe¡*gå(”ÊPøÁ#ÿÁí °Ørsû!+¡vž¡þ>±û–°[P|}M`¯XöXV¶Ò‡„ŸšrP%ƒÌ+[3Ÿ°vP'šó?Nð7{[¯¿Ô„(ÕwpM! ®%ÜJ?4Iš`›Ÿ$Ô€ž¡nìÛp!ŸÓíøÜ.$ºªX…@5}ãÜSa¡@ŒÂÚ €PìK`ÑRºZÀŽm¡\o ¬ApeqŠvËâÔŠoUAÂjÃýC2>cK+NÞÈ×Db&4-R%>²ÁÉèúæøà-u­>[ù8·{0™µ80‡Âxtç5tóÂSQ uihqӆ;êÀØhž7!ÈoÀ÷z(ÛHÀÞãÑm'¡|ÞraÔ_þ³Pݱ»&ªjÍ ÝGÕ¿+ *?™Ê¶*_šS•"‰%|ރˆâ%&òõf*ΝÐâÓ²Ôda݂ï„P++»Q°P—¿·/;°øÚ9kYr’ž&pî‡eÞú6\ ”gìl p)pŸÁkç/ˆoœµZㅑê:ízP'0ÚHêª;4×LþÙwÀó»} `ÆBËšN«ÿº÷ÿë<“ïEv| 8?“Š|1ºBQ E±¥¥%Õ©œÅþ/2b.ßÙ·Êå«;¹|q£ŸŸ‘Ó[rf/¡ïn?éßÔñ¡Âí§“kÌÞñë—o¿3Ç4x5$ >hð‡›øLÖA9 Rÿ@Ò3)’-ʳ×èX”ÅMÝå~“ŒØª ÂS‚<ŒC‰øËHS„BâŠß3¶ q«ùwŸ‰žV"x"_¿?*^ 5ãÆrSh‰Aü[ÒË¿ù ‚˜ÿæ×A(†ñ“ ÇHÄÿðÊqPSê èêH`lÌ$žw µ¬Ž£š˜EWžœÒcc#òdß#ü:SÙíˆÆñ3€µÆOŒfddÌãø0دÀñ(åˆâõïºøw…@Ö¿Pds§@z rÊlñZ±Œ6ñÓWÌ\ÿŸQ|§(ãÏÙ?Q6 Mžcà͊†ß¯‹røeW__ÆIãµ¢›ëùý3€4çùe}ßSÎQ”Iíççó›$WúÂ#„qúúå3`4b?öŒ” A"2e‚;scúŸ¥e˘˜2€MF©R$¡Tɵ+J&F†¡"pýî :p&N_ÎDqôfœ7$ qϝ;—fΜÉ÷#ʞ=;M™2…J—9+Œ!Oö5ö"%Œ‘9“a¥øK£yì"ŠF®|a…ç%ˆZxkbKtΖ⋚P§!Ùˆ¥ù;û²&ñŠ„uH–²¬Bd5«Ä;ÛŽ5Õð3°]~J$BLd•ªB:„gøŠÊê°%ûˆdk ä@ á=„¢ŠTŒ01®‡‡ØlÛrS…ÍÀ‘'ÓÄgÕìΜ*åã¿êƒÂ±+œ ‹WhÛ¡X(WY*Ä.ˆLØ7  D†5BpßbEu«I¹ð¯F’»¹£v°?¬¯Pû,²`ë;ˆ'„Bãw$“ÃvwŶEñJ™$‘Êß͋O$çw_Åñš„uàÏ-æXQíÂ{êHY$ÂÛys‚PɞÚ‡>ŸA’ÐTLüæÕšp×dÚLâûßN„¶fÖá7Œkv ÚB9W 4ŸÀd·æ÷=\o“ÙöóÇolOÒG(²Ñ/DúÌÉù©*,Šgò·/îÔ ßØ ÊðƘáKü/rõ`ÞÍÌŠ{”¢Ti rýíK—À!(÷Žà;Bƒ›6ÜÑ@õìVT¢R.¡ðVŠU ”Òž äÆN€©ëºŠ!%Áڐ–KÙZâ©PsÏÞÖ3ke±÷aÌo“"Ö|ޚÓjû ÉÙàO=cˆ­°^:£+šs okµøàzš–ÕJpP…kúHcqÊ~×u:øÀFÜ#C3gÀ*}æ°C íŒÁ&¥'[Œà»ò†Ó#„mÍWw¡KÎ4l·P:ÐKj¯¥¬šxxËIšŽ¡Ä‚šÔÃݓý.ç ¥>#€°Xw2ÀOI0E’òhú‹*d Ÿ ï`ÿVµäPðFâ'rYA IȔm¹ØÎo\‰‡{P>œ÷VØmž|ü.¶õêj SàÇ^Ì⪭¯°ë€RmÕQÞÌêßð†²•õh*Fñ7ìš1™ˆíåš6ʶèVœ*SÑu…ÚI°í=8!®šSaÇ1×¶· õÆ3Yù‚‰U»+ã„Æ¥# ªàó ¿[l™‡/šâŸÚy†Õ Ε]¬îôáùÁ6x|6„Ÿ­BŽÇ jÊÁ_»}…i€ØŒèšœÏóÇîäqŸ óá³[±ôyÚžàž ÅAê ãi¬{mŸ° îñÝJÙÂn³¶«P4‚āÂñ³°­è3®ås€šûa¯å€_ “±œY· âš@@™Ý°à8jØŸŒPÃW¶„t:Aô‚<)â~ß »ë à+Ï jØÇzaQWãÂã)ŸãÆxU¬Sú±—óîœä¬€PxÃ7ÖªÝr,0ßÀ2oÑ,”‹‰v%±#ÈõNÜ6ðΑ7œ°GšåûÃkV3á!®W±˜søZeÿoX.àŒ‘¬(…á›ëËd$Œšl¹Ä ùíÿŽFQæÄ;l0pÍo`Ïq،€ÌSl>°“ÄëÞ ŸêðõÎ^Қ ûÐàŠ wÔÛ°À81Û+cCÜ]¡y>ÖÈ>\,¶€èÍ[,3íºVÌ1pÂ=lÛ¥1⟋ë€æ ^ØÓŽ€ç.³òVÙiKØiàüÅ|„Átâ (nAø†Üo°h{gFYTæ óøæ…³ê9SpP·¶]汊6U¿`%³Üæ€ Ðçðn (œîùÀ°AûÒ4pJєÒÏ:­JŠ,Êó ïmYr‚VØöc¶¥û7^ Õ® õÖ·ú+oÿžÆ1?¡©{äŒÖª¯%¡¶D•M‹N`¢TâZ’¡ßD8QŒpáB‘ŒN¥<äç|\¿G/{§ š…ï>z#þAŠ뀟Œ²fŸœ)›eJJ—:)Y$ À\ÝÑû¯fôîkúüÃDU²D Š!"9Þ¯§äõí.œ}ëDŸ\;?Ž¡4.^ ÎkÉÄqª˜6ìX1žÛ÷hçΪ=k5Q‚ˆõ©ŒI^ŒxQxÇ‹+£F¢¡C‡òBaø35Ç$œäX šäÝ|?PáÚI#$¹á#¹#€Â¬QÁñ‚@í5¶Ÿø‚ ’"_±¬4|NKAÖÁšŸlk&—B’(»ZÕL‚åîœ;„b þðÌDÀ>aT§U¬{"þ†G'$ìT©†Ÿ°8˜ºŸ+}fE iÞ°Sã`PØ}çw Æ ®„*äæGÎp¯$WÓD ͝ƒ4Ú0ߞI6A–@±Åòƒ›/y+ï6¡6C9šÏ’311}cÐäcšuÂÓõäޛÿާPʟ?âÀ„ÃI‘HO`@× Ÿ.ÕfqrÁÂ.#xÀNbÕŽCtäéŽÀ·0_ð!®Šr҈•¯HvU d¶¿êÀ¶o ”@z"€”Ê"PíÙ]'(!ü=Ž+#*šsÕÎ3ž$æBà܃âÄì¢ÝýÿiÙ¡¶Οö§q¢8WAú€ü ) |±‹þêÁzyÇ@µñ‰=7iî蝂t„®š^çókHæâžHÙÔeXm¡^WÄŒŽÑ>ef…(p¿Žƒ°o©~ùÔjÜ©\óþÃ_>» EuÅ ƒ©Rœ‚‚HFR0,V¿ IDAT  Æí0ˆ“±÷0sц-@àGŒŸ¯9ôIIâ§¿ÿ:ÏŸòV›ˆŽ–Žõbñ…$ŒýœŒN![ñ:ÈK$݃ï3|„‘Œo=+aq{Î(±€€ëNI†úÌ®'i܃ô·[yšu,„Ì>¹÷-žž—m  ŒHÙÿ ›]ё.bá’ ÿ ¢_?÷(ò…ß2îð§EŸÐ·à;Bƒ›6ÜѶRúõº®© òUQÑ—5³ӎ•gÅÜ*>Žžï9\}!µމEØug$„ÚûÕӀo˜WXˆÀX3Á[hñÁxwç.”)HÐ&ŒšÛ š*HbµsŠT‚…,ÀL]×EܧCÓ¯[ŸÒˆö«„E’ba„gٌ¡¶b!«lÍŒÞÉï^¹Ð`VfcAtØ-âÚG¢Gwà=¯q$EO‰×°‹`߯KtàÁñ¬ MÝj¯ÜÇ`#廿‚ÚÇâèi¶pš¹9dÛ$]çž|?jžÄŠbŸoŠ"—Œ®P¥(^°`ØNZ«B.òÿtBWò}=FàÉótýî+rýæN–é,ȃ?øâµ²EsPV&‡3eÈÈéñ+>}øš˜>°bøã73þÛHG%»&ˆzàcœ3­3ýüú”nÞs¢+·Ÿ ?l#þÐZ«R~*˜;#Û±$ŽúŽÉÄÀ‡¯iûë4eöŠ“PÅÁA޵µñû÷œÄðoíÕ«W˜°–I 9s搋û+*Ù(•֭ц0Cë#|‰s²TE‚H—àÛ÷QæòɔЭ£°=_3®ž~D»8™Ô+&Ñ@€&`5r2V¬bësÓ®åEFzVjägRÞü“ÉMYP7o¿6.Hb7]u”Á>;«¯¥)œÚl/@$€dQHCe H µmé)A@U¬[€š°g³e6í‹ê ·­{oy*°eŠÖ"åþN›Û¯¯k$¶ᯍ ÿ×<·PMx‘jHŠz|öߐ“ô• qԖS*Q6ŠËZAlb1‹h‹PCŸ9x—=€ÅB’ƁD‡ †6\(CKüCõîÆX)I²B[ˆbM•ð7Và‚,RˆWM  è}ñø=+Ÿ ˆ—AØ"©ÎxƒÌ‡ÊŽ÷ßq²J± ƒócÖæž4ŽÍ2úÀ€6|oAðjàÿúÓA)Œ…ˆ/Lª!Y[ð²JNØWh‹Ð`°šíl0GXtXW@M ’¹f³b‚ˆK„7$ï Ž;ÚÄBÂu^D(Y%wˆÊxÍŸÁڛ]E.ÀÈp~†5tÍGXë éžÐΙRâK¬¹@šŸi{ü…Ka^ȁ’_ Ü3aytlç zNjÀD/ØžVàWûíÑ×hÙäýb̘Emÿºî”Ä©KöõgU|fQœÚº5ÇÕs\eوAàòîOôëK"‘SFW„’(ÎÉDñI]uÊ÷õÇÏÞә+O(±iB*Q(+ùäòƒ å±€b¬„üåWÂÎ?ÌAüÝC?€ê!Œ²K±$&ì1—æ3eIù…Þ}t¡ ×鱇„€ùsf êåóPÚTA¿ˆÄbžôv茻bûÁë4yöZ"ã”zÛÏšì>0‚,³±±[œS§NM'N€ÆGe7d[hA"‰7.©BËôª¶KGK'cX£PA‰žéœî$+‘9tš›¡œqk(Œñê7¡@æ/òŠüŒ7åíþÁI]l“ߎð˜ð¹-Z>ì€JdŽ/:걂-$ÒN³Oð³EžÅR@ó=ÅPÆB¥Yšût…ÚrJ=°±ž%P)œ-PZ+ûˆQóÛ0‰šš}I“ý¥ÚÓ՟È|D1Էت–€ [çAì"‚z›ŸUDÒB} ,â€xÃ CÇ-*± ÞVXç ‹@µþ7RšŒa}bOc«v+tîX0„±È>F.Wö~&ÏÏ hÜž€ÿŠPÅÿ1Q|JWò}=B«ì;ÝÉãJÍFO^|€Ë7Ÿ3y•ÒfÈ)<†ß31üÅ=Qhìrõh„²+ý@ ‘±7ý/+ûu»°S·7Ý~àDv¬PõðüE% f¥zU P’ÄQûS?1Œ^Üò–6íæŒíóXɔ vÅoÞŒ¡Ù³gÓüùóÉÜܜŠ/.>P”)²ºÊ0fYöR" øo;Ÿ¹CÕ;fÛàeD>HTvrß-²6]¡ù=’-è ïr21ÅJDßú§«?ðøE29(bዛ”wž!YTÓPÓßÒ­«Ÿšz¿vΑB 9yUç07 ¥åéw„Ê${BN!KJösÍ.Ô&Œø"ão$nQV ycƬ)9QŸa윃ÕDk¶|é2¬[nT‹zÀd‹ƒÀÕœ.ô󓍰+ç_¡Š(F2;XOÔ(—‰âÓºê”ïë wY5ŒÿøjZ§(¥ædt+loPêt9x»W)úôÔœ†B•zMOF%»!ÐoŒâûQ¶”®”3Ý'JdìCWo¿`¥ê5òb%B³:Åš\ñú=€XÚ»GŽïiíö 4cÁ&&ŠÿxûÅ&8.]âD-³fэ7IS­Z56l˜xþːÄ6V¬XA÷¯Rî9ôÚ ÀÐæ*¯ãvqR*cê?©Qî#£:ü,w°­€fbC£ìoä!0gÄvÚÇ>µGŸNת8ŽŒ–cwÍHÆ›‰%œDR†D & ›ãvSåY-_,Ȑú5^Ȗ&nÑŸ»%8ΰh±]vŠúOlÄN ‹ Õ³YQ햆£‚Ž ç!ŽáÆWòtI$rÌè UDñŒyó(gΜT£l6òÿ|FWò}=@àèÙûl’ïCuª ¯hí~Ê_Ž%N,·ÀëÁôÈ.ÄâÆñ'Ë_)wúOdžÈ‹ŽŸ@‡N9oðm*P"þ’,CxÄö|úÊö—è퇯4šKõÀ䑱ýùS¶åYŸù Í^²â[èOÇ"±'x¶O›6Œ9È€Û§OŸHlQV-06lØ@箥Và éívpÃAóOOáó9©Ï&:{ø®x‰ÏÚ¬&¶ /du×NN07kKéïkˆ“}vâäƒí+N§²5òÒäÕa·Aˆ‚®Æš&ömŒHsFî Ÿp²Ç 1jlr0±$ Òj99:“qÂøÔ¶oUjÔ±¬HlÚ¿ÉBztû5{>C¯бÐ:Ÿû:rûîÉ»n’PQõšRœ‚ÂÛ¿Y1kÊUВíé;'TŽZ7~!××þ"A¹®PMçɓ‡ª•ÎÄDñ9]uÊ÷£ƒ'ïPºÔÉD’º}ÇoÓG·Ld–º|4öH6-ÔænT&‡%0ò¥=ö·èÂ5GÒœ:¥Ii.ÒžœrŠ%OÑÜ¥vDFÉô G‘Ó…·oߊuø—>}zJ™2¥Ø~Ô¬Y³ÈiPÖ*0P¶nÝJGOï¡NãJèô»Ûö;¯‹,~ˆŽ"‘Ÿü"6œÁ6i©ô{²wц@çª3éÃW:ôhjŽõ!¶5ŒëŸ­HÒh³¶KlŸo Eà—§7­›kO;VŸ¡_ž>"É"Œ³ºy‰„–;oLл‘þðŒÝžØjœ >»‰¢ÿU¢±‹Úé]Ÿe‡ôÛ‡¿Ñ§—>4yòd Q\ʒü]Îë¬Tˆ¶í»J9³§¡‚¹-éâuGzö1)Å·š=‘­J$!` ïÊç|IÉL=éÌåÇtàä]jךåϕA¢ÍŒzãBK6¢™ ·1Qó,z®^œ*Èa{{{222 êà?\ŸŒ\HŒæSO6¯§ØÚÚґS»šãXIGÖýòò¡ã»oй#ôÄá yñ—ö:ì±ØklýÈjRÖxïäB_\Ü8ù[Š0Üë/(eÚ€„­ú2$1 /ŸЁ͗ Š]ÇûoEbÅî#ëRÕF…õv˜/ ýì×~ÿÆ zõԙw倠s[Qö<éõ¶Ï²cяÀ#ßéÃ3/²±±ÑÙUD1²ŸçϟŸª–ÌÀDñ•ÊQŒOS$3£â³ÐA&ŸŸx$§x5£Ÿ#²E‰€DàŸċëOŲŸ¡,)¿Òùkì÷vèõh[rfK+‘‹F@Ï]}Œ¬ØÉDqÌQyй›®dšŸ9ùû³Y ‰€D@¯°0ó rÿœ¢[wКíçiõŒNzÝߘܹ×ï\iöJ{š·|'Å56LEñ‡ý‡³fÍJ?~ü #FЀbòÔɱI";wÒÁãÛ¥¢8RЕ•J$‰€D@" D%÷NžÓ«{ßiƌ:› %Qœš‰âË:+•¢M».Q©"Ù([ŠT4bÆ*T~ùùǍº %?_2þñŽâ{~#ÿxñÉÛ45ù$’ªµšٚ¡"€ävHr·v³™ Ón§ª†:ƒî7ˆâ¹«íiæâíd”аî_7nÜñáDžb8iÒ€deeE-ZŽ0è9‘—D'Pï··•DqtN‚l[" H$‰€D Bžò'œžûUì:Õª‰â"EŠP¥¢)™(Ÿ¢«Nù~!pÿÉ[zôì5©U„ÖìžE?╣Ti²DQë͘Ÿ»AIÎS\ïŸAÚõ4·€¯Ù«“·IÊ(ílL"`ˆÄá ¹ÒŸ¡y gS¿ŽUšp^™ %ªçñÍû/4g•BF2»œ{÷ ‚øÕ«WäííM… þÃ+VŒjød{‡®¯œG·Ri=ãæVH" H$‰@lCàáiOzzó3!®PECš\¬X1ªX89ù¹ª«Nù~!°lÓijT£0}úòƒ¶žJ@yóWŠ¢–šIöô0™}ž­µMŠ#Ôşò¶ _I2Fi¿dcCEÀ‹wlœ<Ÿ•6ÌíjšC0Ø~¿ýð…¬=A“çn¥&ú­(^Œx± ˆ$H@¯_¿ŠæÍ› ‚8W®\‹¿ìžD@ߨ·oí9ŒE*Šõmbd$‰€D@" HBÀã3žôèú'ñ=RWš"Šav\Œxq&Š-˜(ŸŠ«Nù~ ðèÙ{ºóà5µšWœÆÌ=GY t D‰L£ å€& $¶xfÿW{þ—œ Žeû‰””òžyžÐû"ÝÉÏ(Q”õMMCOžÜ¥T©ÒóíäjŠëe™wï^’¿Ÿ?¥Ïµ*rœ#uê⑱T¥LjXœP •þåÝǯ4kÅšŸp»^ş?ŠÕ«WÓžqãš@tëÖ-a/‚X&šÓÿóKöÐðØ¿?í:Ž™:Ž‘Éì oöd%‰€D@" H4xrî=žòæÎ«˜PÅɘ(Ÿ®³RY ò€7q¥Ò9ɉ}5OÞµ ¬ÿ•üF•ü})ݕ%ÏÛí¯6}Ìè]É~âuóWg(‰ÓEúfY–Ÿg*uýÓђ§§õèV•üüü(GŽ|T¢dU*^¢“-†e“a=Ÿ=}ê@iÒZR‰•Å8,-³ë β#aC EüŽiËFZ=³ŏ?l•È£BˆâÙ+Ž’Í;Jdª?Šâ;wîˆíA ­²dÉBÎÎÎ4aÂêÚUªÎC=Éò‰@(8xð í8°QÅ¡ÀL•H$‰€D@" ÐOÏÿ¢»ßÑüùóuvPQŒ/©E‹¥ò’ÿ×:+•"ׯîŽyÏeáe:eÉÊR°ŁÉi…я÷”æöº[sKW˜~™€"ó—g(žy%NGÎ;„©wgΠ·ož“Ó«§ôæÍ 222„h¹rµÿR҂޷w=¥H‘† 6#ºyóœxþ’'OM>Œ&SÓ$4lø\V§£Ë—ŽÓ†õ³éû÷/¢_ñâÅcÕ|eªY«%e˞'T}ýòå]ºxŒ<<ÜÉßߏÜÜŸSÇNÃBU‡fá;w.Ñ3Çû”2eZrwÿA{÷¬£ŽL£Þïß]©JÕÆÔ¬yOö%}J˗Z“““càáÿýW@Œ¡HÑò7nŒ0÷!º:€9µk?ˆ“¥¢« ÑÞn ³Ÿd¿•-–T“ªâšš÷ά(^ÎDñ|&ŠÍ¢Ÿ(I…mA/^Œ „ ’‰‰ 6L&š‹ªB¶ë8tèmß·ž:Ž-뱐H$‰€D@" 6Ï.ùÐí³¯iÁ‚:¢Š(†õD©R¥š\~3&Šoê¬Tˆ\N_~,0IhLgRzN•aòé%Ž[u“>ÆfôŸD€ÊXmøùùÒÒÅèÒ¥c‡$HP$lÂ{ v›4íNuëµcB4®(³sÇJÚœkuˆM˜˜˜Qžã‰Šðòò€ë×NӉã»VJäg’²]»”6î„bç΢õëf‘§ÇŸd~ ©,ÚGI’„žlúõ˓ÕÎ5xœ^!Ž#gÎB4fÜRñŸ¿¿?Ý¿wÐ 珓.]fjËcÈ_ b¿à¢ ì_ŸxL\§oß\ÉÏחܺ± †“YfdÌó„~¥I“‘I­^dj–DíŽSšpárÔµû(ÕÇÄĂɌwÓîÃiùÔö1qxz9ŠŸŸÑÌåGhÊ<;2‰F¢xŊþÃߟ}£M+Öϧ“£0„Ÿ û#H$‰€D@"#žyЕ\œüi2 Òt…*¢xʔ)L¶U 2yxKù·Ûºê”ïG"·8ÑË7.ôËۏÞz–¡4érDbkÚ«ŽãíIin®¢ø¿~šjûc¶ô+IFUeaY0Ѻ=e+ˆ¶ìU[³f‹‘i3¥/' %Ë‹ŸJÀ×w»Ý2š0q5e×á9 rÒÓ󧰋Pý€¢yóŠù‚oœRšy•˜9}Ýœ{™F]J9s |ÝÇLJzv¯XŸ…E*Uã©P‡ve)OÞbdÅÞÊÿ …(ž=w¥N!°èƒû7hÞŒ®cìžå‚èUw˜ôžÉ€7ˆá&MºQ‚¥Y™üGœ>vtGᏌ~ãyµUê,œŽWxüø9râŸâ¬‡wslˆ F‡iõ–£ŽnN—Ø0Üh£óçï4sÅšÀ‹-‰#™(¶··êawwwŸoÓÇ9Œ“_Óþ,d4 ş>yÊlå[·.ÊŠ~::iDæ³6lÝ<ù£öŠŒŒ€ÃÒ©žéüCš&§±··x—LŒaçËläo"ºa@¿zÒ m6f.æZMønË9ººù1ß~×?³E)žbRÖôÁžx|.jþW[TVö2žGޟýa+>™0Ín²fSŸPìïï•?\©R%ñæŠ €ƒžI“&q¬–/cL@Óîܹƒ™s'aÌšފ×gL€ 0&À˜`%pxÕSÓ«Œ¡CcPnÒMüóϐþù«Šw¯:ÄH©ƒÐÌy˜§"Â3©Þ„kçŽBˆÝ€±vš\¹Þ_KVˆŸu뵆É0«hs'Œë)s…­Š¯ŠõØ?\ÉáŽùJŒÎYŠ¥1¬µp€æ„ý¢=RôgPG|ڑí…+2â7‘þçœ)Šc@¿ú2ošßAƒ-Q·^+9ÅSž‘Ip§fZŸÈ IDATyM›ubñ8){xŒ–¯S&rí:ÍÑÅÐXˆºz¿Éqùt™ÁL祆}¹q÷î,oT®ROæ2Ó<°1Š)…\BHŸtñŠ‹Œk_o)*Óóñkþu\ï—&®óyµ_}?ÃrDM,ÏkþDàÓÌu<+!gSƒPLqäÞ±cjÖ¬)žÍ»hݺµˆË•Óܟ|S™PGaò !7WK¿zªJÜ«Œwû„|ú9¢œAëï$ßÔ͚#ú§bš›žOÏÕ3&À˜`L áìZ|5Ê7EŸ>}b-B)¡xæÌ™hÖ¬j–L!„âG±.Ê4C@ÑÈî™g6T¬Öå·kšÙUv‘aÐ üˆϏB'èsÔ6ásãcy#|ÓÉ ¶­/ ±s¥=»vŠüqÝ  L›:^^o¥`kðKñÐ!ÍE4D#)LÆ6âä›MÌðµœÐ îî/¥˜|þÜAPÔC×n&¢Æþ±-ç×O߉MNöXºì²‹æqŠŒâ¿å:oܰ§Nî‚倥2÷8ŸÃlT'éøýÕÍý뺟A119°) ššÿ=‘#”M±#ïg” œH4ñûµ‘ œöäÉ̙5©R¥F»ö}„`_ßÄGùÚ$ó­[·é£^Š¢Ÿ0)T“èLb5åM“8üØå/²Œ5;ŸŒâ{}°÷i8_?Ö}ã»_ ŠmcŠí6dϑ#ÎŒùÃnnn"ò€0èk‡-,,ÄñË,sQ|!`*xüø1&O7Çp›FH“NGåëù‚èæ˜nÁ©}·ÑÖš&,æu“/ºÜ~IÖ"8(ëOGþ¹ä÷cšË<™`L€ 0&ÀâN`óÜhÙ°«è?Õ%ÖE”Š›7oŽſ㻿K¬‹òÍxùæ#Ž]xŽϲ!ÌH3›ü²*eë>Ü"„bïh¯hB$Š š9Ú€‰œe®°í!þøGÃσ" –;XáåËÇ1æ÷’ˆl<ž)Úwè‡n݇ÅʉCŠ/ ¹tÍÏ#,,{÷¬Áa!@(h›¹›¥8J"ihh°È-¶F%k ‰±yÓ"?¶ë7^”nÜ¿ ÊcŠ\昲IŒ¥_rà’`:ß~'ræTÝíýëþ=ñ勷šïÂ_k&âA‚‚üÅŒK1Æ®®÷1kƏ žÉSD,G™ÿÅrXŒíŠB0Ÿ$Dem[Ö Ã»>ȕ#³6—™èk#¡xފã˜h­ŒP„ Ȉ‰Zµj‰n_é"Ј‰Þœ{'z&|&œ Œ|ù–Vca4Ÿ ²çâ?ãó,„‡Ã¢× xœýãImѬó¿×Ø}+fBÉ 1ÅA˜„ ÿ§¹ñٟ¯eL€ 0&À˜@r'à0ñ4L‡L@ýúõcE¡”P<}út©:W+ø?‰uQž o<Ö~(XކÄ49RF„"dzƒÐ ðFêЯQ[iZ$ŠHàŽ·A@± iӥǯw2> MšŽèÕ{ŽgÛ¶:àÁýkB\}Íaª˜“6mz,\ŒY²d—ùŽîî/€ÐKÕŽß!ÄÝ)°~úäu=]Ó a[ŽiÛû7îë×®X/"(ÈÙL‚pAá8 ÆçÏä:zz…1OžªŒçÏâÐA'<}rWžpbŒ”j!, Øn¯žJœö¿}û"\D„CF!j+ªœVY4‡kߟïoªÔöë܉ã$ëYsD=áâýÓP÷éÒe@¥ÿj ·Š.>ú€‡œ$j§<áQ£m„{z¶o[&Þš*Å[r“Û˜e:ÝoÊ1ŠlãqÝQ²dEL¶ò¯G ޳g 1$ÅÖÑæ._6 ·o]Àr!ŠM›.>(4zímæ˜8Ž1*•-€Ñ}’ûâ$Û,? K!çÊõû'~æóìÙ3)oÚŽ ôi›çϟ‹Ÿw=é Š˜&L€ $~¯_¿Bñt6-]=õ5žLüdøL€ 0&À˜`‰À³£˜ni+̓1÷ŽúùwI(._Ÿ<._Ÿ,…aˆ+Tš˜ŽËµ2& wwwL³žˆŠ} #¿þßß-Æ\j­;Ì_ zte eÆÀnuSى®VŠ­ŽaüìR Ç… eqõêÕåyœaaa!bL€ $m~~~0g‚òM²¡râIû°|:&À˜`L€ 0$KÀýÕGìux€k¶#sæØ{o(-·oß• ‹õŠè ŠIìÃý2¥ÿ†á}%ö£huý_…P<[Å=gÁÉÉ +V¬@—.]„;? îÞœ+âŸ}ûjõž8&ÀÔG ,, ÃFD‘*iP¯Uyõ-Ì+1&À˜`L€ 0HàÉÝ·8œùvo? Ô®J ÅS§NEǎQY?ßY(V ¬&&­Ù~ ×\Ÿ¡i둚Xž×dL@ Œº»™ÓÇšMްº€SÒɋ.0¶ ¡‘iКQ#Ü¿_FPLš4I~̓ 0äGÀdTdÓA«5’ßáùÄL€ 0&À˜`I‚À¥ãðþNj8.[­Ôy”Š'Ož,U• ~_*µ0OR?•[.à΋ThØüß8ŠÕ^‘ 0U ŒŒ³Y3~‡iŠUe§Ìü]GnÂ~õ)‘wþA¡ðö jPW±bEe–à9L€ $Q㧘¯ÑcXã$zB>`L€ 0&À˜@R'°ßé ²†•Åôi3”:ªÒB±¡¡!*ðÅwŠ•«‰I˜Dƒ®wéQ§‘±&–ç5™ÐB/o/B¶L)0²? êŒ= לĵ§P¥|adΘ[Ü@årúX»i?X V'i^‹ $^¶‹ŠãžëE˜Li—xÁ•3&À˜`L€ $kžFõbí`bb¢¥„búèm·nÝPAï3äŠÔŠ1V«?þd@‡È˜@löلc·¡N³r(Z:_lӓÜëïŸÁ<óíxýì ×ÇÈéʹP’>`L€ 0&À)O^_±gùŒ7‰J•*)u ¥„â & OŸ>(+„âï,+V“&ÛíCÆeP€Œ¡&–ç5µ˜€Ï'˜Žh‹žF#ÑŠmo-®”KS7w¡0Ò\ÝK'Ùõ6ž êNŠüa}äϛ {ŽÝAƒš%…ƒž9*•)ã¹)†búâc0›² H²lø`L€ (OàÔ¥ýØutµø$—ÊU+¢ü…Ihæç~0i³ŸÄçoŠ*uK$¡ÓñQ˜`L€ 0&Ž ž¹zâúAOŒ5E‹Uê°* Åer¿‚Ý•Z˜'©ŸÀž9;‘·`Uèï þÅyE­&ðåËGŒÙ; „aWnfšÕ7KÍÅy=qŸaÌ`Šÿ†öƒ·ŸŒ— _ý k#µøˆôêm1²_c1¡—'Û_ï ÅRL[t”…b5?¿ŒHÌn<8 §=K§@64h]11%^µï\uËg”“—öŠ×Z|1`L€ 0&À˜À¿#à|þ)\/bá0`L€ 0&( Ðþ[–žÅÀ.Ñ¢E ¥Ï«P+++ Gñá(öTzqžš^ýÆ®E›Ö™±ŸzŽaµC7áê•ã:Ì … —Ôø~ŒÁß Œç† ã{bà  hÜ€ãJFü߬“Bñød=áóUd*­9%âSèÛ¥rç̌»¯¢æE¥ƒžj…Âñ~"€PŒðFY.…ŸŸ~Œ×ã˜HlV˜Á7Ð …KäA™Êñÿ³&1Q¹wíf߄/Þþ²ì*u‹#{îÌÐ͗ ,ZB'MêÄt®• 0&À˜`ɊÀË'8»ïƵE… ʛªTŠË ¡ø; Å ö`õµ ] {"X§¶ÆkpX:ׯFΜy0}æZdϞKã{ò&ðæÍsL¶ìƒaç WyKF•Œø¹­çG/L7K~M,¹Ÿ—Í霌‹aœ"<ò¯; ãžõ¥@\PO}°LŽbӉKěcÉK JF?N|T& 2Mãég‘Sœõ[+ÿl•7Ò² ^?ó fó)þ܍iÌÛdŒêJiYÕ\`L€ 0&À˜€‚€ó¹§p¹î Û©«‘'O¥ÁÄ*‡‡‡cÚŽi2z¢tŽW@è¥ç‰ê%Ðmž#öéTWïÂ1¬† çááƒhа*W©§ñ=yƒ?xùÂÓ¬ÁlÌ\T­ÖQ%#o×ÁýÝ{Ì4ï˜lN}öêSØ­8_ѳ}u‘=ü »ÞŠjP—F.¶ððLš/„bKŠ“ÍƒÆeJžà|ǯlBpP:õO> í.ˆ)ƒ×KBYsdDʔ)ŽàÀ0dɞëOCÝ,Jä)L€ 0&À˜` AàÈöøð2—ïSiûX…â°°0̘1ãGôDÎWÂQÌB±J„Õ8¹³ñ2˜š Wh5®ªúRîo_ÀÙù\ÝÄ»÷nH—6=ÆMXˆ‚ ¢-öí[$ž<Ÿ#ç’ÐééùVΙ8i)Ò¥K578(PŒ1; DíÚÜš/Š;B¬m¬M1QˆXåÊ«ÿj–çúôÒ§Ï(×O›6ê_¡îëñæ­;fY$ýȑ »®ÈüáºU‹¡Xáߟ}Ãùs%_O·È îeW×©× µj5LSÄéŸñE±y·oß¿Ç4³ö±ON„3‚CÂ`¿ú€ÌîØâ?”+‘;ßoV€Æ‘Ëܪaùr*Š-I(¿E‹ý'{ò&L€ $C'tB–\:šÖ òäϞ8ŠVC•=j͆—û,;0 e«VÊŒ`L€ 0&À˜À¿ àûÙœ® VK ìaŠÒ–± Å¡¡¡˜5kzöì‰29^à{( Å*VÓäàà0[nİÁñÆÿ‡ «éñàþuèæÉŒy ÂÇÇŠ#ÚÉ-utÒ°«±Œ£È—¯Ðoe\œzˬä÷s ÁµK—!šP±&²d‰ùWϞ=À&§…°·@Š”ªÑèËzö!êŸAêÔ:Ȝ%|Ÿx#MšŽ˜c³)Z#†µÆ×¯_`ÔkZ·1’[‘@zôÈV>ŒAþÐË_}ûŽ…÷'O¬_;O ߎ.å5û|Åà!“Pœz£ßÊ$19Mštҍûñ£NŸÚ#„åršöÿsI ~øÐæ󅘛O^ïÞU̟7ö·µHÈnןoÔ÷I€_é8sçmEÿ±"##„È>7…k[òë’;˜†2yÆë×ÍÙÓ{¥x^±R-øùùàÕËÇ(Q¢¬Š¯’ëžœzŠuëlşȯ³gÏ-糧xÀØsnjµ•ߣÈÜé>†††àø±mâ㪩¢ÎBu:mŽÇ !–š€fÁ]Õç&±Ìõ؀g/^ÃzB—ÄR²RuŸxýQº‡ö\ÃØÁ͐%Sz8n>'әiê•þ­«—r8'Ì;‚‘âÓ,+u yH6æ,ƒ°TŸ¯PN”þ/ù4»Ü·þ2O݋–ݪa¢}Ïds¿ù L€ 0&À˜Hì\n¿ÆÝ+/D”£1׉ÝDøóycŠCBB0{öl=Q*›«°nþÏ!šØÁ%ŠúýB0ÔÒ c†Æ ߊÿ€ô‰z‰ÀëR$çéBûñžsû’ë ')EEüë ñì™&Ò!KQ$ȶhÙ]žP3©œî`XM×hÞ¢«¥3dÌ,²G„ðK®àV­ÿ÷›sg`íyóq󥞹bù y= °:@šM€Ë–„]r÷ío}ýBðL ãÁM¥:C8{ ~qö®Z9[ ê&.ƒœ@.ß9t±Äá öîY#ÑhÑ¢úô+™š1¢ò{ù}”‰Õúµ¶x+â=z™¢MÛ^ò5sIÔ]Žd?råÊÅÑqùt\¹|¥KWÆ`ãIò~Ýœ{ ìÌ¥?ÖÜîÌϝ,VÛHㄋ²HÑRRøµœÐ[žqé²CòÚY3†ÂÕõ~TíFœG!UªÔ¢ù±£Ûpð€“`WDˆòNž"Ü×$ú;ˆk/œ?ŒæËë,Ü-Åóù󯈯8‘(€_ÖBÄç;p/'¹òfÕ®¹&À˜`L€ 0 œØ-¢bÝ>ÁvÊjäË¥šÑA%¡žŽŠ¿³Pœ ¡¯_Œ':a‚™1ž}þ7BñŽ©…`»;¢ÎL1 ;v8âó'/!ŠBº­Ð¶]oèéŽÆ…¢ Ú,º!!AȘ1‹‹»¡Yó®ÈœY}ÿÐP°äömѪ;ô Ǘ/±sç é*6.eŠsøyìÙœûö®•b'‰µ›Ð£ç)f“üæÍsLÜyó”‚0‰Ý4Èik%˜Ð(SŠ &MYm]moÝ~xÐ`*TL~oñ"KéX&!Ÿo?óßÖ;tpvl_&íøaÍjk˜ ›&Eâàà@9ßLŒÙ@BzHpèŸA:·—‹fer™'È™–nùqî?z»É]µŽBåÊÚvàŽˆwž>èÙ¡:n?|‹í‡œeþ0 ÄéÓ¥Qn! Íb¡XC`yY&8?ž€#WÖÂý¥7úŒn*ÿ®TåۍÛ!sˆ3eI#Û®ÿø»ÀîšX“ßDKª÷ÏŘ`L€ $ôiÙuóŽ!~¡=Y®Uù`± ÅÁÁÁ°µµE·nÝP*«øèyžÊ›ðñ'@®;“IN˜bn—â¿ +,˜o÷¯a…'b)]F‚Êc—[ Gªó Š<øŽJBŒíb8DæÖþ<(~€ÄÓS'wKQ’bê7h+ÝȊ˜ jfçäd’%+¢a#åsX)&a¬Y!Àf–±añó µ(&â×ANرÂÉKb%‘гQ³VÓši$"“˜üs0ÙNža>ž5œÃå+ԈúZáî%á–_ú‡$9žIP§læIB%WðÓ'w±~ãEùß9³d%S63e4+ÆêUsd^²ÍÜÍ((Ûû7`—¿I8Vp#!ßÍÍU«5B.‰ÞŠAÍ$ÿÍÅ=Ü€•ŒšXœæLŽÌè_y)ÜÑSŠ:þ–LsŒHŠЉÅb£š„{ºïĐÎHni:‹ÕŽ•(!î9¿øþi3>~›D=AÏ€"žQíRhV·4žº§ÂMl6š†ô¬¯5·Ÿjg{ÃE4L±b?Þ$áÁ˜ âï Öœ «—ÅË@!Ý$ †2‰)›øçQ€d^8ìÅ ì’ì]çƒ1&À˜`I‰5%ŸpäšÖ2D¡œ©:bŠƒ‚‚`cc#3ŠKg{"Å,« YóœEõˆ©›1mü0<ðü7͝(¢¢~vœRDÃÏîaŠ— ×05®£1ÚÌÿU®+ói)³÷ç˜Ft’â39h§‰ Ü\"S÷ø±íØŒi‘gÊ qöG<ƒ2ƒ"Hœ%—+¹]]Ý.Û»B€ÕAiáø¥œÝ_‡¿htG± $Z““˜Ä!Šm çqºtéåt…KY! “ó—âHðŠ\ÝÊUêcÝÚ¹2æa‚åÙøŽ†B(Šß4Aœk‡ŒŽ GðŒYkÅ»9ED>ïœ<± K–yÅ7@‚0 ŠË 4‡†µ©<B¬Vžv­…pLN__Gl/ã*ˆùûwnžsç²t𔑠÷R§Níø”Lù̊{b=g€ü)¢bš 9ž3Lj}ËŠÅ8&²†ûŠžŒæ"6ãçA׬±kæÃT«R°&¡˜5¹£sQl Ef2Í!—²2ÊÊ<I~ŽŠï>ÁB«‰æšä^žö¯;-ó‡Kˇõ;/Ëúͅƒžcó„iÈ@s›Ã"z‚…âØ8ñëL 9˜0·?tõÓ!<,µšþÞT6)1Ùºì ž=|'T°hnôÕ iÒé$¥#òY˜`L€ 0&d \=傷®_0ºŸ5J•*¥ò9cŠ¥£žGÂQì"Å_Uބ/ˆ?/ï¯5mæLŽ[îÿæ( §šÂIJ¢°ÅØ®(Yªz÷6“™¶Šñâ… Š[ ’0eÛ*²€ÉÕKNcúŸb(DÏÚuZ`øˆ"x§bíÑ»Z¶R^ ;{fŸlm…;y€h®74VÈ$,Sv1å·iÛ[æÿRƒžûBž&ç+EOÐ÷܅ãu²ˆ~ 9kÖìR\¥ßSœÆC§JöÀþõ»RF'“–šõ)„âråDӗIKAÏï_ÃtÔ욆vŠü`Šb }ȹ\EÏ·o_”Ñ$Ú~Môž<Ÿ#…hÛ-²)5ÆÛ°ÞN6kÔš<=Þ`œEwéž*œ¹± :ƒíŒ~í%к¹=•ß#W1ƒâ'ÈáK{ÁB²  ºï”[†òåk ¿È#îª'oËÆyTçä)ˑ#§.Ο;(…br=ϝ·MŠî§NîB«V=Ñ«Ïh¹]KnæŠÍº Oß1±•žì_Oùy ®ÞrÁâéÚßHÈùž›lPwíÎKŒŽá éÓ`þªšPªÆŠx‰ÚUŽÛ©k1÷špÏcGq²ÿ©cLàwk÷Ø ïñ\š]‡4`DL€ 0&À˜`L@+ ì\u©‚u±Ðf…ü„»ª#V¡8 vvvèÞœ;J ¡ø; Ū2VËü÷^>7gæL6Áu·#»»¿Ä"û ˜9{œt›’#•â(=t–gÊ$²rÓ¥Ë(DÔoÂáê-ÿ««›_6.óËl¬GJ!‘F¶l¹„Àª#Ö•Â+úõÛÀØdªœck3JŠ«?;cGn]K!ÆŠŽÝiӄW˜}¡h¬FyÄmÛõ‘S)˜Äcrùê‹k3f­“ß§Ft;¶/—çʓ·š Q³q“N҅¬ôú‘Ã[[ž¢mí¶ Á{»lìFMÝè§ð°P)þ*FDD„ÔI@'–„TÊ+~ìr;Eö39‚)¶¡ºp ÷"ª"f‚„ቌ€Pk1Þ^F<PLœIl'ûoãÆõ3Xºdòî"úÃxèù{j0GùÂ7ÏKŠ‘6mzéLŠF~ÔäòˆÌiŠ÷ œerI-ZZ2©Vœ¡¬™Æóçen²éš9šRµŸ™ïß»&ß?³£{á÷ÕŠ£8ªyü™@jáØ¿þKgi-Ѓ§ïa„ÃÂ"1²cž¹’qÏöÕe±~âø˜¶…Í Bqñâŵ–5Ƙ@žrÿŽ_ڎ¿`4hSÙsÅü)œ„©ŽweL€ 0&À˜`ÀoÝzµËt€þªÇNC•„âRY G±³Oî_0iÞXO†Ë/K'@ÿÛòÁýëBX݉÷Bš¥†qiDþ,9R©Á[ǎ€³”‰™IqùÒ1)HReæRžpÕj E³µžÂ-›.^gÙºe‰ŒŸ ý»u&óz3dÈ _ŸOxðà:œEÌÁkᜭQ³‰ÌInß¡Ÿœ÷ëP4µSµ˜@ÑŒ-­ˆ¬ œ†*ë(".æÛïBÞŒ…È*…bàÂëÏõË8•p3+"5îÜŸ„…öã¥ó—œÐMšv–ÎèÀ@?ÃbÎN,™cŠó® +ÿۓÿ}7%)âÐÁQÍÜR€H)Ý͊‘/Ÿ>ÆZؑŠ‹|zúZSŸB(¶_Ž7*çXÕâ(7y…ˆÏ ’—þzvæM†OCåÊÿs5«ºÏOXi¿nÇ©Kwà8ç‡ >¡ÇW¿ )Û¯9…~†µeƒºmoÂùþ+L3kþ†uºÄ8ïOB±±™µˆt‰Þ”3Î ò…L€ $)ӖõCöÜñáœZv«ž€ÎƇaL€ 0&À˜HüNï}»ŸÀxÐPaḨ)%ÛÛÛË艒™ï ›h@œ6â‹âGàõ»O0Ÿœ+ç™á” ‹¿Ò€ˆÊEŠ8 MÉY[DD#”/Wý¯‘ñ»+ñ»úèѭغy‰ˆªØ$c/â:ÈÕ|þüAÑ Ïþ~ŸÈ"r•).‚²’ Š•ÑלøºO ­ßvœŒp+¬V(~òÂSæï9zæ"ožtq=8l8ƒ 0ñu tmSõßÃQóŽã懱ˆCa¡XÍ`y9&Dl=e‹·ž/àñúÚöª%>QÄ Þ’È­åc0&À˜`L Ñðý€ËÞ HÎÊ>|xœÏ«PüõëWé(îÖ­›pߎâÀ8oÆƝe~šÏށuöcqì,:î$µçÊkWOa™ÃTŒ›°+ÖҞž­"NÅÇÎ߯J!ÿ)îC“Ÿœú …@LÜ\ԙ?L¹ÃæÆÍÑ FÒyãj’ý)ô>#Na5yxm&ÀރÀc¯3X²tJ”/ b·R£|õ¢ÚQWÁ˜`L€ 0&ì 8ŸŠÞúš^¹®è V?ÎfŠO›pÏå&olY2šå68uö«O ,,ㇷDP`Žž{€/Ÿ¢A] 4­›<ÿŒ™Žð z ž„òåË«…3/˜@Ò$àìz»n„nŸìȔ5ÊT.œ4ʧbL€ 0&À˜Ðz¯¿ÁwÏ¢(QŒ$ZŽhïzUŠo¡8<ޛòªžçòó…ÓoýcìŸYNõø &X˜wCÞ<`1Þ> œF¹#|ÿž/ßx`DŸ†È‘=“rýaÖÊ-dÄDÙâz;€9nÞw®œD“º¥1Á€%ʖȯõûœžB±% ʼnýFrýL@Ã"Ÿ…Âr~?!Äý¯Ð©?*HÃÈyy&À˜`L€ 0?žžó2¡€Ì&ÖÕՍ7§X…booo¬\¹ò‡£8ýuà{DŒ7åT'p×å –¬;ƒ5óa§3 Ūä+’ó1†È–=ŠZ­H ÇQê ß>nÀÓçî5  rçTœs©¿hžŽvÇ%XÙ@oќn`·:ØsìŽ|㉲‡)b"oî¬JՒÔ'M^t=N@… ’úQù|L€ ēÀŸ ŽxüòBCÂP¶Jaä-#ž+òåL€ 0&À˜`L@5OŽw)€O›FFFª]ü‡Ù± Å?~ÄêÕ«d§¿&„âHµl̋šFàփ×XºþŒpω[Äpq¹…ukæÂrÒRäʝO5<;YkÖ™³d̙k“ ‡Èëñòµ†öj ’ ûâõG,ñÛ:cŠyGÔ©R «¶^ÀŸw…8Ü\ Ä)SŠL6•9è”ÅçÑœÿ8T¬ÈÍ©”áÅs˜@r&ñãgBíæeqïÊ Ž1ª™œqðٙ`L€ 0&À€ÀUP*-4oÞ… VK* ÅW…PüM-ó"ªžõð –;Å:»Øv-qçgnÚh'vbŽÍ&èëW ÏNÖÌFu¥ÐÀ)˒ ‡0ϵpÿQ8ëB/O¶XÏ}åÖ ‘?|žœ‡¹ˆ—(Q4¯lPçæþ ãEŒDß.µc]#¹N˜ºøºö3G¥J•’+>7`*ØxdŒ¿Ÿ‡ŸO Š—/€BñÿšŸ ÛóT&À˜`L€ 0dLàñ×øîU™ÒæDߟ}ÕF"V¡øÃ‡X³fŒž(žî²Š¿«ms^Hy·žÁaÃYl°„×ËáÛ÷Ê_¬e3—/›†«WN`™ãQdÍÊÕÔ²Û£Õ嘎l'Þ%+ s‹ùZ]§:‹ õX‹Ï_|ЭM5ÔûóÏËþ“wa·â8R¥J)ó‡ÃÂ"„£ø$2eH+Ôµn”žß`R'Ó?­5mÙeöÎâ›÷`I€ÀÇ g˜4Ý ­ºWÃå.èØ¯N8 0&À˜`L 1صüÊlˆ¶mÛ¢@j+9V¡ØËË ëÖ­“ÑÅÓ^RÛÆŒjn‹è‰%Î`£ŠwÝ(‹ˆo‰÷#ãóæšáÑ£›Øàt‰?úþ‡Çà»xCæò¥£8yr7Ÿ¢Y3CŽhÙMˆ€©U{p’Øìá&­P¶lUŒ0•ÄNöçãDz­ƒç‡OèÖ¶:ô äüm¢ãŠsR®UÙ#ú5ÆÓž˜Ÿè üšÅU+N6¬â{P«¥—й×hT®\9ŸKñõL€ $ßñ+öCHXü¿¡`]-͑ZÉàÖó™`L€ 0& Þt÷ù+³ŸÚ²‰ŠU(öôôĆ йsgŠð1 ¡x¹„ÖŠè‰ÝÎe™*«‰ßÖS§ €¯Ï',]v(~ %á«×®±Á¹³ä IŽŒŒ@‰0Ár ÒŠM—„Oþ÷£i†êÕa°ñ€dà È}|}ýйU)˜Kž;X4O²u<&ҝDÿ®µaÒ«!v¹»•Ç1idôñs'x*ÔÊAÅF,«ˆ§3dMàÿ ̱ž…¶=kàÔŸÛ0Ü YóàÃ3&À˜`L€ hžÀÖ¥PŸ`Sv1DÞŒyÕºa¬B±‡‡œœœÐ©SG!‹è  BàöCá(ÍìÈQŒ÷Vi„†'^gé˜Ñ!Cf‘Qì” ,µ}ÓíÛpøÐf”*õºu7A‚8~l;öí]‹ Ú%+‘ô×{5°4jÔ}úÕöÛš¶ú‚Þ®‚Ÿ¿?Ú7«ýù—]‡9¢Bé0l]ÏbóŸk7Ž%Ɖˆ‰ŽiuÔ¶wr[hšÃt22eGqr»ñ|^&áßB°þød|ñþ*ÓÙræÉ‚’ ÆcEŸ” 0&À˜`L€ ü™À£[nöȆB9Ë¡[·njG¥ŒPܱƒÈ(Ÿ¢öxAåÜ¡fvÂQŒf^ì¿U ÁáÿF œ»WqëÖyŒ~ý >_>¢nœÖ0pŒr…Ç0kð Æ(fP'-uÇwâ…C°ï’Ã8tpvl_†5›`ØðHúo:è$^[ޑгQ³VÓä€#Ú¿}‹DßÞuСctíf¢öóúãÑCgDD„£\ùêZ“Ÿøv%‚ЊI+ü¿FI|Q¿«-,„8lÒ»¡Úy$ǧ/»Šö݇£jÕªÉñø|f&ÀâHà©Ïq¬X¶µš•Áõ3O8«8Žù2&À˜`L€ 0¿ Áá­ÎšP 9:uè]]õ7SVJ(Þ²e :Žo‹biY(Nš‡öΣ7XŽöœÆÁ;¥ªY¡øë×/زy1nߺ€ÐÐyì)R"]ºô(]Š2ƚÛECqýúi)¬•.ý÷lϐ` ØU«5„Ù˜¹±âoÑCæϝ·5Ö¹1M ðŋ‡áýÑCF6èêæG£ÆÅY~oèöê)tÒ€!àE…+è;œ6ÚKŒ}û~hÖÜP.†‡D`žÓ€I 7·§X±|ҥϋq 9s¶ßÊpŸqû÷¯‡—ç[äέ‡–­{HWì¯ãþýk°³ƒB…Šaú̵rýŸ ˜ÇÉ ûE{c<ƒ2{9;ŸÃ•KÇ0lÄtq?3DÛƒÄØë×Nã¡L?ò€)Ëä~×®ž’gM)ž¬Ùr a£öȔ)kœîILbïž58wîräЕÎiÚ#cÆÌQÓIÈ*¢'º÷víûü¶Ì«WO°kç <öP^W³V3t1òǘö'x…ãLñðIŸœ*U* 1ž"Þimº‹ÈÖ&ÁþÅ €sòå+„êÕ£IÓÎògC#àõ ñò 4ê×oc“©Qe’Àê°t*n a–FîÜùàíí)?løtÔ©Û2j. Ž“&ö‡ÇØØnFþüEb<î•ËÇALf!Ù XÙ8íå°tŠƒ+W©'ÄzÛš†‚$2“cùÇwRîÔy8c3ÉÐMˆ°4èû$`q&⠙3G‹IH oÐ Ǐmë§Ân_y=± ~ÐKTªT[~Dyz&^ŒxíÌtßÇOXˆ\‚OBž6Õýú[D ÷Š Žيm[—ʵHhŠ{Bü6lkTÇÕ«'ážlºžöŠ+‡ BdŠ7ttt°lùQ€ÏQȟå'×Ä\ôÆÕ÷þÝ+yNÚs”™žþÇ=¡Zsåú‘táÂaž¿}!‚‘kyŠ{<ßÎ\ÞÿÎ]ÇxŸþŠ¿›#Â#ÂÐŽn”,ªÞì¡X7Of¬WßD‹ŽƒY(Nf÷ËÔAàž÷ÜL6Ž{öè*Ö(Š|…~o@ªŽœx &À˜`L€ 0äGà霷ù(4¿ì=zŽÆ(%oÞŒ…P\,Ý5 ÿÀýÇîXºáŒŒž8r¯ü‚5+?yr ì,@ÑäÂíÔeêÔi!E¿_9T—,²Dñâå1mÆêß^?®>xœÃúÄGûobž­ÙK‘ ÃGÌøMÄUõùxúôæ “³M@…Š5EŒƒìŒÃÛ—ÐÓh$ÚŽímY:ïœ{W1pð¬ByÖ¬9…š/EnŠ: ±š\ÇS§ôG‹–Ý¥hüæÍ3éŽ~ ÜÀÄÆQ4ÓÑI#×%A—„]rYSóµkö7ŠAjŠ’èØi »GM  Ä+·'(+œï4èÞ:m\ ׳÷Bñf€âŠ¢˜n5-ZtCó–ÝäóGná;w.ᵛ«œfÔ{®ŠºèkŠ(!§»éš92úoãëËå♌Dý%Qº˜æþgð×"’É‹³W9£U§!ì(N&÷›ÉÔM€"(ö\Xw·ÐÓÏ /÷/šÛ²Œº·áõ˜`L€ 0&À’Û‡}?[YñÉå\hÒäïB|ÑÄ*¿}ûÛ·oGÇö­…P|=Ÿûñõq$àâú6âcð›Á‰‡Åð%@óB±¢TúØ= \'N씹µÙ²åQÝůž²Ù‰y$ê‘3µOß1Q' •pOŸs)›¯Q6ʂk3JŠ K…ëôç¡• ˆXƒ¹¶[äKäVŸ&öŠše3qëüše{@äïÚùCp¥Ñ^ˆÞ$Ì*¹@)‚œÁ$ “èHcÊä~ò{3g­“â£ÂýZ²T%XІ|$š“ h?œtؒÓvÚԁBØt‚f·@‘ŠQ€H)XNvî\ÅgÞžžo¢ŸŠ†—NU⫆]\nÁfÎÈh9œªîE›P=µA"3 ÊØý¹A!9e‡ˆŠƒ¥EÜÅ?(9µçˆè Åy~u‘+„bÈI„&—/œá@±$äÚ5ÚoE e “àZBŒ@‚º¢Ê¢ŠŒhŸ?ÀhÓBŽkˆÑB~&ö™Ó£5ó͇۟m–B>å+òŽéz¡Ç‰Ú‰÷ŸÆÒœqãÆŒµ°CåÊõþ8OñŒ“`MÂõ¯Cñ̑뚞+Šcb@õ‘3œ¢xFè,]» _øãŸô‚Ï €FþzÕK°PüWRñqÖʛhÙq jÔšÿÅx&À’%ïàçpÜ4EKçÃó‡ïQ¬¬ û_Ÿ|²„‡fL€ 0&À˜ˆ3@7]ø¹è˗/05nΌó¢¹0V¡øÍ›7عs':Žk)„âšš×T‚Àãgï1cñ!ìXf‚“ ð90z2%–PyŠÏ')ð)MþÈ]LÌw"›•>â?aâbž !˜œž$äNŸ¹F:¿|þ{ûqQnJ…³“¢,† m%EÄ©ÓVÈž ÅPžjé£ý“§.—ß6ÜTfގŸ°H~l_™¡pØ*ÄOŠP8rx³ˆX'ón)ãv™ÈŠ(£—Ö%á³ßzò{äý9;ví\Ÿt\Dœ–¢$ÅÐYíìŒÊè¥(Ó퀠۠a[ŒÙÕª7Âh‘[ûþ›’/Kw­A)’Àþó0ÙNºˆiPD…­ÝvéâŠìgZ)³˜r’7¬·ÃéS{0NÒŽœŠê^ŽîÆ pæô†xtvî©q5g£A¢.ñ 7¶ÕôUR §†…Ö͓ÎlrQSó9º÷?»›B1­QK4“£Œ_ڇ†"—™„óÅ"ªDñ5‰Á$ ÓøY°vuœY""£BÅZR¬VžvÉõÜBžvi K\–‘Nñ×ψ|`ORDˆÇuc|s2µ)N…š$îÛ»NäQ¯’yÃt¯òˆ9Z B÷”Ä!’Óy¹Ã4øøzcò”åòç…êRÜKŠ÷ h ŠÌdÿ¯â砅RÊ_ž; ]ڔš]Ù¥‹ë)ó#ÀsâH€…â8‚ã˘ˆFà¿3fϙnÆ °uÙYôۂ 1&À˜`L€ 0• ÊPG·Þ”úEçΝ…^€yB¬Bñëׯ±k×.tB± Å*ßTu]ðô¥'ŠÎߏ]ŽÃpúQQxûÿˆÐäXŸlnߺ EÓŠÍ £ّÐh¿`<ÝAƒ-Ñšqù±|úx~ªT©[ˆpŸ„3—ÅÖmŒðØå6^¿v…õÜÍRx€8‹Ã"‚"šyXz‘#üæÍs«ð^Šlä¶Už@MŒ›‹#Š1GcÌGŽéüaa¡gÑ]ºŸÉU(bHŠœÇ Á9{ö\ g®íÑÓÈTæïŽÖZFØ-Ø!£'ãÜÙ ±˜ÄkrŽR£»˜ª‘Pœ7_A 8AÛPæ™·ñ _åÔL™²ŠEFñ(¡ž6±'…«;]ºŒ2ۖD|jŒŠÊ^/EDÂFq¯šÑ_… 51dè!<ïÆýdž3 ¡CDž29š—.n[!ŒÒ=!á˜D~Šì0î[r“8>cš±f)¶‚üÝŒy^Š¢ÔÌnîŒmRL>urZ ÷y¯>?ÂÖé~ 7i%3–ɁާWmyo„ÐK÷¬x‰ 2šÄYŠgPD_à>a|O÷A9Ö4Fo#…â¥ËGshÿ‰9=Ó䎧g–ž]b>O<ăšôћt¶%+HQ_ñÐ3?aœ‘t}.\RÖHß{%šüQ£?z–ÍÌæ‚âTš "™„c?qÊðŠgž!ElÅÔ)äsi-âJþ6‚ÝWÈ\çºÕг£X™Šx̙µò–p`Gq<ò¥L€ ü pîÑ&;vDS»×ÏŒP¯UFØ`L€ 0&À”&P"[Sl]qRh7„6‘ 4PúÚøLTA(n!„bçøìÅׯƒÀ“ž˜µäœìá¢k1|ðû_lA<–ýë¥$ԑ°F! •9AÙŒAAþÒåKcšÉÔš`䥆_äì,_Ÿ†Ìµ¥ø†ÏÉž†î=‡£jÕ65k;rx‹\›­K1 $JÑбuËù[£^£T:&ÅPæñ۷ϑIˆ¿5k6EG!)òwi1еX-rsiL±Z!ÏEyœÅŠ•¶ÅPþ,9YI@$ážq“Ž¿5Ü;wî€Ìô5·˜/Å[o‘'L‚& ›± Šx)ÄÊ_9‰É•K¹ÆŠAUj.GƒÄxe÷"ç+ÅP†3E5ŒmålŸzõ€t+SŽ25ž#¡—\¯7ØáÈ3N%„ã²åªŠß¡Ò1®Ô`ŽšRv25€ØŠ’ ìÝ*UëƒÜ»÷ï]“¹Ã?»p)ªÄ𢡊l ×ÛšŠÌéíÝÇ Âéí*â-h³šbêÖk%¿&av¬™È#üŠU«Oýhøÿ Âïß8ûùùHšFn]=,\ôÃéL÷—mj^§ÈTŠïÓ3_šPq‘™ÝGÖGgÜ/žÛG"ₜÜ-Aç­S·¥|ÖÎ{ZbLšnzn)‚…6kÞ5š˜}íê)ÙÐaùá¿>ŸŸ-AÚ4©X(Ží‡H ¯Ï^yÍEtH͚Ê}zA [òL€ $QߟGbÓ1| öBšŽ:øê€šË$ÑÓò±˜`L€ 0&ÀÔI Tö8ŸëŠÐ_òÂÏÏ]»þèåô/F¬B±››vïލŽm›Ã ýÍQ/<`íp+çöōW%àù5ó?áDb!‰\\§§œšYXŸ|úR#‘,®ƒD9S Á„;rŽþëA¢ éӫסM"ûBûñRÌlÓ¶—ŒT Œ^џ¹>‚2EdÔªÝ\4G¶‚DqSÉœ.\ÑÅK”—|©ŸõëìðüùCéRî×ß<šãYÙœHŒ¿pál>GQ¿6d#öCñ³ «Ìý Wlhþ–9sV9]Õ5H(þÙ%L.baÎpVÔAjw{R]8ŸiPÄÉĉœds<Ê2Š7ôòbx8ÞŸy†[ÂïîUYÛË۵ÞèÑcÄoÏ.œiñüÙCqñêÕcé ŠF‚ôÁ¯Ï9‘~ÑÇ?bª2øgŠÓ ¡ž;Š•yã5gÎêÛh֎…âxA䋙ˆ"ñ-ö,«P:|ùèôÓ \՘#Ž`L€ 0&À˜ e©ì-qóì ©ÍŒ{÷ÆÆÆÿL¬Bñ«W¯°wï^thÓTÅ·þiqŒÙÿ<~î[Çcp˜Ù wÜKÂÃ7 ãÑr·D à ǙÑ\Óu¡$„š Ÿ&›š‘`MyŒÑAîØŸýÌcrÿtde÷"‡r®\ysC'$JŠ©yŸÉ0«8•ñþœ›l$HÂ. úƒõgÎä nןŸpCÿÛ?\ãt˜.úá(N)›Ù•2ȧ®ey°P̏`ê&ùV †¡fӒxàü EJæEáyÕœ ¯Ç˜`L€ 0&È €@J”Îѯ|±—žpuuń þù©bŠ_Ÿ|‰ ]«Æ,ÿóÛó¿ ]D3;ûÕ'a7¹\ŒJãÏ÷&í&à‡óçJ—ª¿Ÿ/²dÍ.ã ʕ«qAÎYÅø*Ü« A‚gö¹eLåچ†Ë\_r#û‰5|}?‹Æwen09’;v —Pe/m¢6xPc”-[ cÆÚƹ¬ˆˆáÒ>ƒ{÷®ÂW6aL/#2ʔ­"ÔêvŒÇ¹Ð8\øÙU8ŠÓ¥Bq1”,ÊBq*}ɜÕw„£ž/GO(MŒ'2&  ¯¡˜:o:ô­ƒc;œQ«IäÊˏS†ÏaL€ 0&À˜@r!P6G;|~)bRáááQ£F -#ý??~¬Bñ‹/€PÜ¡ueGñ?¿AŠ I(vÜ|V£ÚáÙçrpÿÂÿÀH°›¡Á)êãÐÁ¢ÜŸãNä˜Í™3lœ×ŠM/”¯PCƒi~éqæÝEs&̘¹Vó›%ÂH(N£“ k•D‰¢ìBÓä-ŽY{MÚôf¡X“ym&L x<ÅäcÐ׬9¶-?‹NêŠFši’) >6`L€ 0&À˜€‚@Ê©Q.Gø}øŽK—.‰hÏ ŽmÛzzz I¡ž±Šo'H‘Œ)ðÈõ=–9ÅÓ¶xíWo?gg,I˜¹‹_Ÿt—§»p{#{ÎÜÒ!K¿rçÖS)–BÛ1ÙَÁãÇwà°ì2fâH•_ï×'×ÅH“:%×)âEòhûíLÔõY ¡žq+#Ô®];QŸƒ‹gL@; <ýp —ÌG“FØœúÚöª… ™Òig±\`L€ 0&À˜€Æ €J©#DâŽøê‰#GŽ uêÔhÕª ,šñœÿŽA¬BñóçÏqèÐ!ŽoÕPÅw¬ÐäŸ19ŠWn¹ó!ÍáR¯œY(NîÏDR9ÿ™Ó{E³ŸyèÝÇ -[õH*ÇRÛ9H(ÖBqÓºeP¬°®ÚÖå…~'`œöŸŠ{²PÌ`#àâu+V:¢Ë zعê·ÿ¹óñ§Ä4œfL€ 0&À˜€–H2-ÊçìŒ÷/}pýúuYeÓŠMT$ŠbŠŸ={†Ã‡ ¡žŠïj)Þ€_ Å«„Pl:  >GV«9“þ¡ù„É‚¹§Gl kÂÜb~²8³*‡üôt‘Š›Õ/ }ŠUa§ê\ŠU%Æó™ˆ oÿ7˜nc.&5Efñ ”¯VúÅù#qaÉ×0&À˜`L 1ÐI™•rwœû¯EO«¢WÕtèÐúúú ~œX…bê²wôèQŽmQî%xÁɵŠ7A=êÁ•ñâ ÅÉõYHŠç~öìräÐE®\œÁûëýõBqÆt:h"Ņ æJŠ·_kÎd³î¶èŽ:uêhMM\`I“@ˆhT;y–šö6Àõs·`”ù/áÿa4ió©˜`L€ 0& =ҀʈйºâÎu)?}úÆ šH­(2V¡˜ >~ü8Ú6¯ƒ¢îkEÑɱˆÇÏ=°vûe èV!iªâ¹ FÉñ9à3'?Ao–#8$íšV„~~ƒH“O€Íú‡hØŒ Ś„Ìk3&€ÃŠÅ(øßwž>{ŒTâÓ#Uë—dBL€ 0&À˜`I”@úÔYQ!—!®]ŒÏŸ?K7±¹¹¹èC¥£5'VZ(nÓŒ¶p?К“[!O_zÂiÏ5tmSß3U‡«Gî䆀ÏË’%O®‹ðýÛwtjYõŽãÆ€z#殄úÍ Q·nÝ€zD>`ZH`ë֭Ȑ+ žÁáýñ3êµ,”)Sja¥\`L€ 0&À˜@\ dHEÒ¶Äέ{¡««+ÝÄ#FŒˆër».V¡øÉ“'ø?öî0Šbøw%œ@HJš¡w€wéV¬Øë³€‚"‚Ò;Rl4Á‚`EéœJï`H$@€ €×7³{—\ž ä’+ßúò.w·;óŸß.hŸ›Ì®Zµ vm…JœQlµ3aŠaÏ[º wo —’Íqü<×*-®sÁ~)P”WÃg -=O>Ð!exKkÚOYt-;<ʠؚÈl›ž¥Àúõëq-á ܂¯bÙÒ_Юg=„VçrLŒ\(@ P€ €#x¹ ûLlݲS,¹///<öØc694³Añ±cǰnÝ:ôìÜ¡î Š‹ë,žŒŒÅwËwŠ_?¯wÿæ8۞×¹`¿(Jk§f 9%Ï<Ò ÁA%‹²k§ëkÒÂchݱƒb§;ó0lC@.÷¶|ùr<ðx;ü±i²‘†¶=êÙFq¬‚ (@ Pà®|]ƒqb}R’Ò”å&:uê„FÝU[EqÙ XÎ(^³fŠ›‰ҋ¢&öq ðÓ•ÅÝÛ×Eɲ-q$š³Lx¡PÀ®GÌ3Š3Ñû¡ûàë C.¶1N˜m:õB›6mŠ­vL 8·@zz:/^ŒòÊ!Í=¿ý¹j€à \£Þ¹¯ Žž (@{HŸì†œ+® lp²³³Ñ»woe6±-ofƒâ#GŽ@þ:\ûï7³;bËcqèÚ"Ï\ÆÂ_¶£]³0•oƒC Šú|sp0 $DΕk‰xã™vð÷ó&Œ&Î?ŽÖaPlEc6M X&°mÛ6ìÙ³í:߇ßÖ͇—ȉ›¶«aÙÁ܋ (@ P X2Äd¯“»®#벞¿XŽ 6Ž›Ÿ3- ŠåÒvi†PÅÅu¥EÅÄá«ï7£C‹©ÔΖ-®RØ/(P„‰Q³qþâ5ôå~”ðõ,ž¯+ÅÎwÎ9b زÀÕ«Wñ믿¢T©RÐø^Åo+~B£6UQ§I%[.›µQ€ (@§8°#чÒQ%ž!äo‹ÉYÄòæuö²™ Š>Œ 6ˆ¥'šŠ¥'ŽÚËž®ÎèóñørÉ&Žo†r•Û`_ƒb‡;ÉnÐhrõ9Μ‹Çà·ºÃËӍFV˜ f·áŒb+ ³i Pànöïߏ7¢a“zˆ¹r ;÷nFœ–åV¯üÝ4Çc(@ P€ ¬ ðïáìÛ‰J ‘r#:t@Û¶m­Ð“u›4:t›6mBNQÉó˜u«a뷐3 g/X–Mª¢ZÍvØUŽZ €ƒ È 8)ê œ:s #ú?77qño‚hÓña»ù• âÕbï @Q ¬^œò¿Ëå:ê1‡pðäÔlˆJaŒoEQŸ öG P€ Œ1§/c÷ƓpÉ) ”G‹æ­pÿý÷C£ÑØ%R‚âF"(>n—ƒt„¢/Å%`Ú7kвqUÔ¬Û»#;Âyå(p'­Š“ÏÎÁ±ðó?è1èõ:‚YQ`¢Š[3(¶¢0›ŠîU 1120Ÿxñ"j×®èó§yáª6ñFÙÊ%ïµyO P€ (`¡@äñ ˆ5{ îQ ..[·nÅ©S§P«V-$%'âà‰©áŽò5œàS’kÚß#1§(@ P€ÿHº‘ŠÏâèÞ3Ðj5ðñ(‰ûjuG÷.¢D‰!f6(>pà€ò¢Ý;4@%/ÅÅuÖn€`ì¬âŠjšS¯-vœªP\¥°_ P ˆdPœûöÁä!OQ¯ÎÛÍÔ%hÖº»]®#åŒg#§€s ÈÆò¿Ówî܉:uêˆß<Ñãdäaäž_G™0Tªa?7Nqî3ÉÑS€ (`Ëry‰¢õo,\ÝôÈÅvlÙ]Z? @Çúï-‹‚â-[¶ §˜QÊÅÅvÝ&'§aüç£AíòhÒŽ¶‡W,¶ZØ1(P4ZM6’ÎÌ?ôÇbâG Š­­>qa8ZµïÉ ØÚÐlŸ°ŠÀÞœ{±gÏ%,ö÷÷ÇõWqìÔn”³Œ+Ô(‰RA>V闍R€ (@Gˆ¿”€óÑñ8Ž+©IéÈÊÎF…*Ašß z¶|Þ.Ž8l˜ Šå–·mۆ닠ø€C"ØÃ 222ñÁ؟жYš5k-'Cí¡lÖH ܃€ ŠEPu ãÄÅܬ+0q‘ŠÛ1(¶®2[§¬-pþüyÈß{8¶o[…Æ«¯}€ŒV}­^8; €ƒèÄÒ×O+W1øí2*ÛÆ€ï"ТM7Žk×Îv‹de  A 99gϞEttŽr󻓧A﮿Y™‰Ìì €§§Ú”*í©„Æ2@.(dñ(—²àF P€ lY ùF*â”Pø:Μº„óQqA±V'þ{G|@î&–àªRœªT­ŠªU«£jh xèD0,Ba} [šÕk3ËcÈ;)÷h_[ý„Ü©׬Œî÷ߏµG«Xœ–ùó&cíšeJ?oŒõ ڮ遄„«xûÍîÊkAe1múråû‚ìkõÂÙD@/f_ø—®ÜÀÐwpQÙî0&})‚â® Šm÷±2 PÀJò&¹¶qlllî×µk× ¿rr2‘ž™ŽÔŽ1Û& ûúy¢€¿7ŒKžÁÝÛE¬ß§…›·î^Zžxå@§c˜l¥SÅf)@ P€N/ ß$''ŠâÊå\‹KÂõxõëÆuù•77d€g)¡pH…`T©R•+UA¹àPT©Š2¥Bf†pA/³A±Œ{ò®]»DP\KÅmŸû¢ÀðOC…rþxž{g¬9Rµ[ŸuS[¶ü…ïÏDåÊ5ñvßQðôô3LR1q|?\º|O?Ý­ZwS.ÈŸV/œPÀAdP|åÔl\œ–„úôtQÙî0&-ŠDËvÝžF±íž"VF ±@BBâãůe^œª<&%%A.a§<ÏÈÈÿ}è 9CY~oü*UÊi)Ðé5Ðè¡ÇZñ(ƒf9k9GüÆ ŽYHLŒK±WPŸj€™¡Åleu²n‚Ò§ IDAT4'/kį„ªÏÅûâû±x éÌfa%4å}ñÆ“UÒDꎲÝÜýLû1t(ۑ¿†š-û1®²fÒöÍukSúëÞê}ã©3Ö­ìcØQ+”ý–܃uæfîùM”CÄàäÀ7·}«çʘMòûe<ꊒçœyó€q£¿º¯ayä?ù>#09ù»È=Ÿù‹ÈŠò6_!rœŠ5*'ñ–[®¿éñ&ãœõAù_Í;OyמÀηÓm'×ßò ÕíN¡Üq¶Ÿh3ÿ¹ŸõØó.õϋÉÅ!ºÏ_¿™ åí|NoƒìÀtL¹—”"¥nŠ%Ë}åŸKùçßìv§]Lê0ö«:nîÃŽù÷Â9-Ž+<æÛÔ:ò®õ[ÕusÓò4Ë×L÷Íýþ6–Ž+ÿ¶Î=7aÜÞ-ÿßr¿[QüçµÜqG¯^ïùö3ŒåæŸs‡h:VyìMõ+o›ìss ¹íw2ì+ÿS[“õ˜6`ŒH ×jî5›[h®šñ°ÜǛm çÏx.MÿläWmÎøïÀÜRŒcÍ?Œ|šÊ«Öeü³™#nÜfüsv󟵛ÿæûc§\pyõÈÀ™œBƒUžOž[žŸü÷«qKLHAœ˜õ[¶B23²•™%–ÈÊV³ÄcŠáQ>—GɀXnÆGxùxˆ®Ýá[Ò[ÜÄ7¥K£LP9” ¬ˆòe+£bÙêb_ñ!Ü,(@P\Ső7Ì _`âÃßÏœèŒU‡«~l‘°)].˜É©d˜ÉoS:X1S—DáŸV9£ØÁÎ+‡C XO 557nÜ˔¥"--Mù’ßˀ9%%EL0HWŸäšÈò=ùÃdVV–ò(¿d-g2W¯^=÷på‡qåHõ‡rå;ÔÙ9Y"(҉cÅ‹†}äè²Õ”$7P&6üP,’åbñ\ö)7õg\C c°š¯©ýéįŠ*µ~úÍZšûÛ3Ö Çdf‰> Çš?ƒã1ÆŽ œ‰§:±.¢F$OÒ*a“R”zA’|ªÓëÄՙê2,º)@ËÉÚ$¿PãGþ~ò~|7¬D7Ò_ºän†sd|ž¿OõŒ7l››/˜1ìŠÓ‰1eeªj7%9¹GŸshp1H«F†ô-/ˀ‹°Êס1ƒ3^[ºÿö¥ôzÉÚMÏwÞ¹È×qKžj „¶7MŠû˜œc=ÒÅ/ÆÚ”G“þojšœ9åÛŒçzÑfîµrs¿&ÏóŽÈ|žòŸÅ[еêåõ*ρIeÿùàAŒç*fŠ¥å¿ÃE¯WÏã7ã¹»õNz“?77}(e<ÂøwAn±ÆZŒ×©KŸ?·«Ç47œé3–ÿ~j Öíê&οqü†¬?÷r4¹ÜŒ×§NŒ'K„kÆ{nú¬Æpê …kPÆ£î)Ç*·[º²Æ›Ë6œ.MÇ ›“oÊ¿oYÃmŒdÿÊGJ†ƒä‡²ñ×|î‡AÊ[Ó¿Ô÷îԏ:ŸüWtŸcn÷AÓ>lTÿì+×jŸÏ^Ô'¹/¿1~àh:^ÅFü»KþûÁpPŸQ ¯éÅ¿ d@ª6ahÐø`xM'ÿ•õ䟞W”é ùj5ñÍý€R|€›“er]ä[އªÆaäÿÜ)ogùï¯lَrMåîmR_ÞXò> Î'‡ä€TÄ_ºÊ5ËÂE\ÏòÏšò%þœé\Äo*)ÏõÊ£\GX~P"¥|ƒP²,ŒÄRž.~pÓúry¬;þÝhù›–ÅíDPìÍ ØrÚÂßsÜìJPüäC]±’Aqá³E ؘ€ Š/›)~XÈĀ׻ÚXuŽWÎÔïÏ¢Y«û9£ØñN-GD P€ (@BÈË2å~b H•…Ô.ò s‡`Œ œ8._{ÿù ÌŽ Ó…LÂ^µã›jÈ-.wìw_·I ·ë-²ù|º˜÷wSƒ:—âr…vߟ!³AñîÝ»!×)îÖŠ:*pFqœ’Ûw1iÎJx{¹á¹ÇºbÅÁ°b­…S€ÖЋ_Ë=t†2›éœW;[¿C'ïaòâ(4oÍÅN~pø (@ P€ œVÀlPüÏ?ÿ‚âjbFq”ÓBÙÂÀŸë÷•òë³ÆŸ…?0(¶…sÂ(`M9£ø—Åý•_»Y0õUkvŶ…À”%gp_ËNhߟ==(@ P€ (@ P€N'`6(–7³“_ÝZWEÅÅzÌ]²ñגñî«ã÷}5еvN X_ÀUŸ…Ã[Ç£r…@ŒðXKëwèä=L3Š[pF±“_>(@ P€ (@ç0ïÚµ ûöíC÷62(>ãŒR60ò…Ë·#"êõy¿í«i± PÀšÞîéØžbÚ6«Ž‡;7ŽfWl[L^|V,=щ7³ãÕ@ P€ (@ P€N)`6(Þ¹s'öïß/‚â*"(>ë”H¶2è¥+vc÷Á(Œø4–ï©e+e± PÀJþÞÉXþýp<ýÐ}hߜ¿E`%æÜf'->ƒ–m:ófvֆfû (@ P€ (`“–Å­+£‚OŽMÂYŠZ±þ 6ì8qƒzcÙîÚÎ2lŽ“N+\â|3 ýōìêתàŽE5ðIbFq Î(.*nöC P€ (@ P€6&`6(Þ±c<ˆn­BEPccå;W9»DbÖüõ˜7õu,ý§Žs ž£¥€ ”ó‹Ç€Iƒðíä—èïã„E;äɋ£ÅÒ¹ôDѲ³7 P€ (@ P€°³AñöíÛqèÐ!toŠòÞ Š‹óŒ>ƒóÖaÌÀ^XÎ[ç¹`ß( wñáÐì‰Xúù›puÕE—NÝÇ$·lӉKO8õUÀÁS€ (@ P€p^ÅEP|Îy¥l`äg.aú7kðö qàršˆ%P€ÖЧîį¿,Æâÿ³f7lÛ 0õ‡shÞª#ÚŽiC P€ (@ P€ €Ó ˜ Š·mۆ#GŽ [Ëò(ïsÞé€liÀ.]Ãä¹+ñhׯˆÉêeK¥± PÀ  ç~GøÉݘ2äI+ŽÎ&o˜Ž8FÌ(îÈÅŒ4(@ P€ (@ PÀ)ÌÅ[·nÅÑ£GEP\NÅœÉV”œŠq³þBÓ•  |‰©®¶Rë ¬ qàkžk¯áƒ7ºZ¡u6É ˜×(@ P€ (@ P OÀlP,of'gwi^–A± \9cgþ N‹fíû öº· TÄ(@k ¬û}êXun`­.Ø®‰À€%çвuÎ(æUA P€ (@ P€N)`6(Þ²e Ž?Ž®-BÛÀ%²pÙvDœ¹ŒÖŸG\JEšˆ%P€ÖÈÎÎÆóÞÅôa¢JÅ ktÁ6o˜üýy4oÙíÚµ£ (@ P€ (@ PÀé, Š;†î­Ê¡œ7—ž(î+äqøD ª„µEº{óâ.‡ýS€Vžrå"¶®šˆo&ô†——»•za³ŠœQÌ끠(@ P€ œYÀlPŒyófœ8qB¬Q\VűÎlec?xì,6íúŸ~•áVúa›š‰EP€…/pèÐN$œû³G=]ø³Å[ LúþZ¶jÇ¥'x}P€ (@ P€ €S 0(¶³Óž˜”ŠÙ Ö#1͵š¿ggÕ³\ PÀRe?…žÍ2ñò“­-=„ûÝ£À”bÑBÅmÚŽ¹Ç–x8(@ P€ (@ PÀþ,Š[”A9ŸKö7B¬xÎw‘œèü{!štˆސC¢>›ö!OîÊõ‰‹ðRàŒâ"ÄfW (@ P€ (`sfƒâM›6!<<]›—Fˆ÷E›€3Žvë1DŸÇ‰žºhА³ ñà˜[àüù³øó·¯±aáŽ=PÝԟ.¡y‹6œQlcç…åP€ (@ P€ @ÑXŸ_>)w׏º+‰‹cEPܞAñ]éñ P€ (@ P€°w³Añ† pêÔ)tkî/‚âx{¯CÕ¿líE¬Ý“­V‹Ömº;ÔØ8 8£@tt~ûu>Þí7 7= 6ÇŠmÌDPܖAq±ù³c P€ (@ P€(^³Añúõ뉮ÍüDP|µx«eïù.'x¢ÿ„íðòòEíÚMT:„B € |÷ÝgšU«1îoÓ]ë²ã‘Øgé_Aq;Î(¶ÏÓǪ)@ P€ (@ Pà,Šï+‰ßk÷Ø/Lä4=fþ₳gўžŠŽ-ÌæÙ(P„§NÁ†õ¿ãõÿ}Œª¥¯ iåóEØ;»’ãŌâöí; U«V¡(@ P€ (@ 8€Ù xݺuˆŠŠB—Š%Ûàå±ôŸÚضmn$^G¥Ð0T©ZÛ«dI €9éÓ£÷3}Qºt94¯ƒJü sf…ýþx1£ž}ûö Š –íQ€ (@ P€ €]˜ Š×®]‹3gΈ ØWÅ×íbPÎT䕨pŒ~^¶:îï/g"àX)`÷+WþE×nOÁMŸ%–‡—[†ÝËÞ0þ»XtèØ-[¶Ž·ÒY/(@ P€ (@ Pàž,Š›ø €DÂ=wÈ _ !Š˶•Àºëàåéö*üNØ"(`OÄÖm+ñÊ«ƒà6agàáši•ŸØè&,¹€Ì(fPÌ+… (@ P€ œQÀlPŒqãFœ>}÷7òAñ g4²‹1'¥¹`ñzw¬Z»ÕªÖAýœg'ŽE:µÀùóg°lé—xý!ššŠF¡ç¡Õä8µIq^.=Ñ¡CÅÅyØ7(@ P€ (@ ›€Ù x͚5ˆŽŽFçÆ2(N,¶BÙ±yÔ =ŸßàŽŸ–/G‹Q­z=óq P Xâ¯\Â?ÌÂSOœ[d¡b—ö)–‘Û©F¹™ƒââ= 읠(@ P€ ŠOÀ¢ øìÙ³èÚÄ eߙ²°çŒL-–nñǟG£ÆmP³f# än @Q \Œx¿ýò-^µº7Ÿ?¯Ô¢êšýÜN@£ÅžEçÑ©S'ñA[ :Q€ (@ P€ œN A±§Š“œÈœ•­Áòmޘ1wZŽì‚† [Ùã0X3Ràĉزy^}îq<Ñ. ®âæuÜl@@£Añ9Å6p*X(@ P€ (@ @‚b'O•ìµÀÙ9l:„‰3!00=z>Sà6x(PxÙÙÙøëÏÅžpá,†öï…õ3 Ñh ¯¶to=&.¹€Ž;¢Y³f÷֏Š(@ P€ (@ Ø¡€Ù xõêÕ"Øž€N ô"(N±Ã!:oÉ9âžX»O‡`îwpòäAô|àY„††9/GNb?,fÿ…r!å0úÝf(çÏ¿K‹éTÜŸ[­ Æ.8‹Î;£yóæ6W ¢(@ P€ (@ X[À¢ 8&&]¹¢lI®£iíböÄ”ÆÊIøõ—y(]ºÚŽí¡—7ÔÈ ϕGåÿL^39ÆxÆÐ˜ÜWmÖПòš6lÜGÝ!ï¹ì_“#{5}ÍX›R¢Z£Ò¯:\õÑP“AÀtõ˜ÿŽÅˆ¥6“W›:Hñ\9NR¶òZÞsu#”øN©+ÝyǘÖ+^Ulÿ;µï[ž‹¶•c”qšÃÕj³¡×eC§ÉFZÊ €€%#5% —â® .þâã¯âêõ81WâáïçÐòhP3­šVG™ÀF>Ú£€Î£¿=Å ØÏkŠ(@ P€ (@B0¯Zµ çΝC×FZgJ§lĶäLãèóñž|õΉï£b® !1YYÙb6q¶R|ZZ†Ò2–ž‰è ×EÈŠG¹à%`vÑË/œXûX WWœòÜÕEN'‚8­òºüÞUŒ®_^^nÈÌÌûê Óê”ðN+Vœ¡¡V+Cù¥†zZãkòuñ‹«Ù¢ŠŒýÄ1†DU«{‹@P}ÇRAùŸ^ôŸƒl“¶e_rŸŒct†ÀWí_#jÓæ†ŽÊkò¥.ÓGõ{%œTö1Ÿÿß}òŸ¿-ãñÊ£!í4ö¥Ÿg ]óú2ŸnÚwn;j"{áegg#;[ˆ/ùÁ€éólåyŽ8ßYPŸÏ}.ŽÉRŸËk!÷=ñ}–²¿|ׇ]å£Ò†xTöUÞ_9¢Mنñ=¥ãûY¹íȚÔöÔ}å>Zq퀥fäö­ŒgèÓ8¥?ٞèC¥gˆþ”×Äu Î_ºž^sû3©Q.ö*22³Pª€7ÜÄu+¿ýœÅuª‡)o1ËÞW„ÁŸš*f ך w7ÛþƒÌê & óÄšoþEϞ=9£ž`rܛ (@ P€ DÀò ž¡Šý;Èy/ð0dh—–®ÃòK†m2 –Á° ï’ÓҐ“­áq:RÅóÔŽL€Š§#%U<Š@9;; ‰b†rŠâ2Dx—ž‘iø’Ï3E@'fsŠÐø†€eˆ«ÓÉàVÊ"Օ­Æøœx]Îr–  ‡sƒP%•ÆrË sýˆ×¥‰Üä¹0ömlS96GT!ۗ•‹GOW$&‰sdŸš™›„ðÂR†ðnnzÅV†€ò\Cr5h×l¡„€òóf,CV5 5ÞÊ÷†ýòÂV54͌慯ùޓ¡jŸ –7)4{¢¹ƒó èœ1ò«ãx衇Оqcç?GL P€ (@ P€N/P€ "(Vg8r£(@ 8”€ÞGÅÇ;ÔIå`(@ P€ (@ P  fƒâ•+Wâ… èR?Á¥ÔٗÜ(@ P€%àâ‹sà‘GA£Fjh (@ P€ (@ PÀ³Añúõë…® dPlI“܇ (`_—>÷0ƒbû:m¬– (@ P€  QÀlPœ7£8SÅ&w+Ä"Ø(@ P X\JbøœƒèÕ«6lX¬¥°s P€ (@ P€ @qXw®—²þŒ Vqœ$öI P€ÖОúá“/à±ÇCƒ ¬Û[§(@ P€ (@ Ø €ÅAq—zéö×ÙàX(@ Pà\ü0òËCxôÑGß#%§(@ P€ (@û0ÿý÷߈EçzibF±Þ>Gɪ)@ P€wp-…O>߇'žxõë×§(@ P€ (@ PÀé,ŠëŠ¢l€‹ÓqÀ (à®þ6{žzê)Ô«WÏ Ì!R€ (@ P€ ò X_ºt ÷×IKOžÒ (àx®bF±×­[×ñÆÇQ€ (@ P€ ÌXË¥'ºÔKaPÌˉ SÀ-CgîBïÞœ;ææš(@ P€ (@ Pà^ƒâÕ«WãܹsèR7Án¥(@ 8ž€[†Ì؁gŸ}uêÔqŒñqD (@ P€ (@{ Š7³ëRW,=àNP P€ €ã ž•Añv<÷Üsš]»¶ã#¢(@ P€ (@ 0(æ5@ P€ž³€Æœ >šŸ/ŒðjÕªE. P€ (@ P€ €Ó XŸFqÝD1£ØÃé€8` P€p|{0Oی—^z 5kÖtüs„ (@ P€ (@›ÌÅ+W®Ä… ÄÅ7DPìI@ P€ €Ã hÜˊ xƒb‡;³(@ P€ (@ X*P€ 8AÅ^–¶Ëý(@ P€v# ñÁÇÓÕÅaaavS7 ¥(@ P€ (@ –€åAqëô.¬~Ù(@ PÀvÜC0hêzŒþúëš^œºíÔÅJ(@ P€ (@ P€E$`6(^»v-¢££Ñ¥Î5ûQY솠(PtÏò8i Þxã T«V­è:fO (@ P€ (@0ç®Q\窊}m€l–A P€(DòøpòŒù曚Zµj!6ÌŠ(@ P€ (@ P€ö!`6(^µjΝ;‡®2(*a£b• (@‚xT3ŠWá­·ÞbP\7îK P€ (@ P€#P€ 8^Å%fà(@ PÀ( ñ¬ˆþFŸ>}P¥JÂP€ (@ P€ œN€A±Ór˜ þ#àŠ&ü…Ÿ}û¢råÊ¢(@ P€ (@ 8€…AqŒaé Î(vº+„Š(à¯Jxܟx÷ÝwQ©R%'1‡H P€ (@ P€È/`6(^œz5¢ÏžA·z×¹ô¯ P€pHWeŒ7öwôïß¡¡¡9FŠ (@ P€ (p'³AñÚµk}k‰5ŠKsF1/' P€p<6c Î IDATWÿ†÷Þ{+VtŒrD (@ P€ (@3fƒbãŒâ®u¯£,ƒb^P (à€ïªè?ú|ðÁ(_ŸŒސC¢(@ P€ (@ ÜYÀ² øLºÖK`PÌ«‰ R@ã] Æý† $$Ä!ÇÈAQ€ (@ P€ î$À ˜×(@ P@ÅýFþŒÁƒ3(æÕ@ P€ (@ P€N)`6(^³f ÎDEˆ›Ù%rF±S^"4(@ÇÐø„áá?âã?FÙ²eÀ!(@ P€ (@ Pà& ƒâS"(NbP섗OzŠW“dS²q šQÝßðº¡ùŸÚŠxG£<æŸgšCŒ;GŒE­Ë°oîQw>¥âšÿì™#^LÉÐ!5CŸò‰¡O¥¥Rùzœ|”ŽÊë†} ¹ÏSÓuHI× ¯g+ÊýåŸjk†ïE[Êsñ†lÖØŠì+SœïT¥.qî”å1êÑ@m+÷5C†öä{±gV¶ÜO}/5C‹Ž ñjîqyï‰ï”ý4✬ì,C»êûy_†çò:ç0++S”!&9YJqÝeffü÷8Cùے‡šm*­ˆvãã/ÁÍÝիׁbEÔªÕ¡åP9ð*Bƒ®ÂÛ-ãÎ'˜ïÚ€€Æ§ú~ò=† †2eÊØd,Š (@ P€ (`M³Añúõëq:ℾ™ƒbkžˆân[Îþþ¯H,ûk/._KGP`0*Vª_ßRš_)-jŠ+Á› eœ™•%ՐO>—ßg‹ðN‡òKî§ì›ûŸºŸ ež)÷IJÓ %M'ö‘ûªaœÜGy”AŸæŒm©a:ƒE™mÊðN†ŸÉ©£gå+²=5íTB>¥ñ\/ÂیL*Š€ªª!5„•éY:df» [†ŒÊ^†¶”oÕPÒž)·HÊRÝWŸ­}e‹±€giÄdè¬æ»zœ^„”™w>ÝJÚ«ö¡×»(¡Š1šVÂ`Cð¬Ó ;ч²™ÜÒÒˆ;2>ύžˆd­¹¡¶Ò“Ò˜²iµ:uü†×”Ýp¬N§®¢/C®Ÿ¬øÆÞ «­ªiºˆïÕP^î«ò† ^9N~8 ób'C o|Íðá€VÜ"-–4šûªûÉOŒ šhÈÔ>Ôð_§ô«“c2Œ®Ž¡|@ 3|  ?TP•mš>ÞS>ؐ×wWâ.âÒÅsˆˆ<OO4iÚÍïk‰Nµ#á'fs³3Ÿšè;l1FŒ   ;+žåR€ (@ P€ î]ÀlPŒvíZŸD÷)œQ|ïÞ6×ÂÕ$wœŒ€qÓ狠5 ͚uB͚ óÕéå–/Ã,Iùë÷Iâ×ð¹Q€yǰsÇZ$'ßÀk/¿Ç[^‚«^|xÀÍn4>µÐgØw Ší挱P P€ (@ P€(l‹‚â(1£ž[ƒTŅ­oí­;Z£&LFÃFmѬyGšˆ%PÀ~N…Á¯¿ÌÃýú¢w{®ëmOgRã[oYˆQ£F!00ОJg­ (@ P€ (@B0¯[·áÇУaƒâB!·FälâGÞú-[vFœú-l§0VB;˜2y& }q »9•>µÑgèBŒ=vS6 ¥(@ P€ (@ –€Ù X®Q|êäôh”Πž°Ôm€wÇïBRF)Üß¹—TÄ2(àé驘1ýc,ó*—ŸæƒrðQäxׯ;Ÿ,Rf3(vð“ÍáQ€ (@ P€ À-ÌÅ6l@ø‰CèÞ0!eüÈè Gþœ„÷'ýƒz âÆuÜ(@ÂØŒù/\‹?‡Ï?iϛÛ.­UZËñ©ƒŸC`̘1ð÷÷·Jl” (@ P€ (`ËÅEPœÁ Ø–ÏdkþÙvDÅù¢[Þ<’»S€– ÌøìcŒþJ<×ñ:ong)Z1í—í]ï [€±cÇ¢T©RÅT»¥(@ P€ (@ Ÿ€Ù x˖-8~dgß9*ôž“’ÓðÄûkКIgԮ݀ÐÛgƒ €*°ò܇Ò%xs;[Ÿ.r|ê¡ÿˆE9r$ƒb[>Q¬ (@ P€ ¬&`6(ÞŽiNÛ'Ö(Îksé «‰"lxëþë5{;éõ2üü‹°gvE爎ŽÀo¿ÌÃò9¯2(¶ñSŸå]qãÆ‰¿ùï:?], (@ P€ ¬ `6(ÞŒy3Žލž³¹ô„N@q4ùŲx,ýc+^cHqtÏ>)àTŸMÿsÇ<ŽúÕ\jÜö6ØLϺè7|>Ə’%KÚ[ù¬— (@ P€ (pÏ–ŇDP܄Añ=kÛ@é™: œy§#¡÷3ïØ@E,Ž-0øß“µðx—PÇš.CÅïX Ì(fPlç'“åS€ (@ P€ À] ˜ ŠåÅGîBÆ9(Ì_Çœ+e:èä…ŒñÑ7ÈHKEßwÇØPe,…Ž)0sÆPÔ,Ÿ†o&œà˜tQƒb9£žD‰2*ƒ (@ P€ (`¹€Ù xëÖ­8|`»XzBàØrW›ÝSÅãçlAfVzö|Öfë4-L£ÑÀÝS­N{Ûz3‚^Ÿˆ‹MFNNŽ]ŒËÒ"/\8‹5«—*3À]\ž|¥n¶²ßŠ?£yõËèûb'[)‰uÜB Ý£.Þ¹@Yz‚A1/ P€ (@ P€pF˂âý"(n Ø.‹×œ1èÓÝvkµT¬Vnú;ò8Ž&µk +]ƒGc*,ÞŸ}5>Ÿõ Fþ•«Ôr„ËЩưbÅŽ ‹Ã[ÏwpªqÛÛ`ÓDPüá˜ï”¥'|||ì­|ÖK P€ (@ P€žg³Añ®]»°ïŸM Šï™Ú6°· žD)wW0Úƒb¿’>ˆ»”èPañ¶­+ñÅç#ðѐYš]»‰m\H¬Âb¿ÿú+Å¢ß+÷[| w,zT÷ºø`ÔLœ8‘AqÑó³G P€ (@ P€°³AñöíÛq`÷&có#2Å9Ù98uÙÙÙ¹5k AH™ øz{âæ ø^ÂâÌÌLŒþšÒW¯Ç^Cƒ†-¡ÓÝy鋂Bîٜӧ Æs/Œ‡nݞºãá›7­À—sGcè°/P£fÂvÅý‹Y`ûæe(_"ŸÙœ˜+a÷wHq¯‡£æ3(æeB P€ (@ P€N+`6(Þ¹s'öî\'f» |ÙRN åHyä €§¥áŸ³ùa™Î(NLJ3¡³L‚bÀÓÓzO„£Qíê(U¢DŸ1©3‹/ˆ5‹-jll4>xÿ‰ÜÜ=ë¥(@ P€ (@ ܳ€Ù X®QŒ{ûZ<،Añ=kÛHŠGÌ¥$<òÈË6RÑíË0 ŠÓÒÒEPœ7£Xåáæžá]ø™ž¹èQ©\4šüíEŸŸ†ëñ©ëÏK¿Ä¯¿|{Ëc*V¬Žî=z£y‹ÎÐëïnб `üás‹f ¯]³ óçMÆä)?"žlEüñû"lß¶oŒõ BCà 4®‚ì|òäAŒùjÕjŒ‡ÎÎ=T†Ä_΍­[ÿV^“!òC¿XŠjßÝÛ~@ ç|ôv§·œ 6É­>™É“'3(¶·“Çz)@ P€ (@ P PÌÅÿüóþÙ¶JÅnœQ\(äÅßÈÇ3#ñï™ËxL,«`ë›éÒGÂ#óÍ(–µ‡†”EI_o€¥gàÌùX1û59âÓÍK㋬T]†zæL8†|ô<üü1nÂ"ÄÅÅâð¡]8|xÂÿ=ŒÌÌ ” ®€MGPPÙµ-w^²x&þZ±S>]jv†òʕ?⻅Ó0cæï(å„Y3‡b玵ð÷/£Ÿ5žKXöóWøeù7h×þAŒþ¿!Ê!9bj¶\/YÞ`ÏÕÕ /Œ8mÛõ„V[0_Kúw”}vmY‚²Ÿ1\zÂÆOh¢K= ;S§N…‡‡‡WËò(@ P€ (@ P€…/`6(Þœ{7vŠ›i=ÔܝAqáûK‹c¿ŽÄ?‡bðtï>ÅÒA:57£øvmiµZž»¹*oGžˆGzjޒ–ôôèŒÛ»<Ž_ú ß!ii©Ø²y…{gˆ@É þ +V³€ÙÜ}äŒÜÍ¢/¿^+f/ÞùÆYþ±?|?s¿\ /o_dd€cÓÆ?”àZ†ž·)PߖîŒ`þ¬Yý3žzº|èy尅 Šbõª¥pssWÆVßÒæœv?ûÄ`Ð[\£Ø–/‚úzøhÜ||úé§pww·åRY(@ P€ (@ PÀ*fƒâ={ö`ǖ¿ÄÍìÜP!Äß*E°Ñ¢ølqÖl?ƒgŸëWŽßEoŠ3ŠÿñŸ¥'n×€NÅuÂ*C«ÑÞUPŒjåOXŽðSŒõöŽjÝí?ÝÈÅß-š¹,Dƒ†­ðÁÀ©ÝÔ)àÐÁX°h«Ùã~^:W,ƒ1ónµh©‹ÈÈãˆ>{ A¥CDÛ@Ìö՚íãV;̞9 ;v¬ÁÀAÓP¿~ üöë<,ýi®rc¿÷LBý-ïª]yPbâux{ç_Oú®³ñÿÙòʖŒ€ÿûïudã¥;Uy7\ê㣱ó0mÚ4ñAˆ›Sƒ¥(@ P€ (@ H³AñÞœ{±mãŸÊŒbŎqÑ|þÓü±î$^xi€ÍÈtFq¶Œ#¥7¥ëk ‹ß͌⯿‡~G÷îœZ) ..®žxñ.\8ƒ çÏà̙‘žž&fzâœ÷'¢vŠžté<މ™ÈM›¶WfþÞi6ôe\íÍýjµÙs°H,;±~ݯ˜·`Ó÷MMMÆÂùS•™ÊÆ­ZµºJˆm®ž[5Vv{ó­á· ύm\œz˗}=»7‰¥*²•>Ý»/Ê(»×\~î…÷ЭÛSùº–k1Ø¿oŒ9 5k52kc;Úù5ü<â¹ô„Ÿ¬œ Š¿ÅgŸ}&–UQ(@ P€ (@ PÀ™ÌÅûöíÃÖõ¿á¡ž ŠäÊXºê4æÿvÏ=o?3гEàxðø)È©Y²étZÔ«ŠÜèîn‚âáÃ^ADı[v%׿­T¹&ªW¯‡-» B…ªÊ~ŸÏ.n2· œŸé‹ž<—ïØÔÔ ýøŒ&Öú•ÇœöJe]ßÁÍ@|ü%e†­œ©+oV'Ã]ÉùŸœ;û÷mÅsWæ¶)g#ËÃeʔW^“!± v#EÍr9Œzõš+õÇÅ]ÀÏŒ„'ž|Ó¶|û|0àI\ŒÆð‘_+Ëp€¥¥˜mëÄñý˜2y€R·ËežŸœtCYÏyÒäï•1Ïù|€r#ŒQ£¿Eå*µrûŒqã:Þ~³».ø` 6j]àšmñ€£ÿ|‹îW0ð Î(¶Åóc¬éºЇŒ›‡éÓ§3(¶åÅÚ(@ P€ (@ PÀjfƒâ(AñƒÍ=žF±ÕNCÑ6üÓÊH|¹ô8^}mpÑv|œnjbF¿þjGeÆp¹r•Q]¬Ã[Ÿ|”-ŠÒeÊ¡T© |A®qXƒ=‹˜è k÷Ö­×,ßhwî\‹Y3†â±Ç_Ç>—_l{[ Ùç  oR'o^'Cßiӗç#û*]ºœ2›YnƐZ†Ðïö’%ýqåÊEŒßÿ14kÞ o÷Y ýìì,Qc;dee*¶|lÜž-úœ7á¶KYÈŽù†²¯ŒÉ]›¶=”›ßɐùßaÌž ÃÈÿÙš“øúÛ ùڒë.õåX±Þsue_Ó°Œ@ÅÛØÎû·ÍE wŸÉ ØÆNMŸr®ëàã±ß`æÌ™-ñbËcam (@ P€ (@»0|2ÒâÅr]Þºw¹Fñŋ1ðÞãhz_ô¡«¥Ûÿ^ä$|ùÕxxzå;ÌžŒÃGÏT‚gcP,Ãç®ÝžDU1‹X¯×ã§ŸÀÞœ›QEÌŽ)fÜÊM®g|%.ã&|—ÛМñœ,úš<õG¥Ï·ßê!–ÁðÀ„IKP¢D©ÜýN: ÿÒ¹¡³¥c‘!s¿wÎÝ]Î:ìs¥öÛmãÆôÁ±c{•ܵiÛAA!ʒ¿,ÿF }gÎþCY—X†×™é˜9ëÜŠd8?lÈKʒÒH.åá(ÛŸ­s ‚bÞÌζÏè5]1£˜A±mŸ%VG P€ (@ P€Ö0:tëōœn郊åx3;kžŒ¢j{Ó®9ç_» Š¥MjZz‚bw7uÑ‚.=qüØ>Œó6º÷è] þœ%–KHÈ%"LoÔ¶uËߘó…:£wҔ”UÅr¶í”O—æ.!ߗ7É{ýÕNÈÈHí¬‚O Lÿ.â¯\RŽ5nêÍðv`Η«•÷}š®¥m2ž°°ðòòÁµkqÊZÄ2˜•3p;tP—~˜ùÙìÚµ.ßìc¹œÃ²Ÿ¿ËA|5bóŠøæëqb}à,%”­U»‰²D51Ã7(š¬¥CÈÝO·­X¬Œãý“•›ìõ&¢Å̕*ÕÀ[}F(k67cøkɲg¢þňá¯)³ŠM7¹®ò ±…\6đ¶ý›'¡rˆÞ|®œ# ËáÆ¯mˆaã¿ÆçŸî0ëc;ÜIâ€(@ P€ (@ PÀªfƒâcǎáï_âѶ%[õT]ã«6Å¿.¢CçW”€Ò–7ÓÅw[gAgïß¿ S'@ë6=ðæ[Ÿš[¹ „œí{äÈn% Ÿ¯Y'±„ÅÓÂÙWYZAβ>ò+¥Í={6aÑÂiÊúÃÆ­²X›øQ1#ža£Ö¹¯mÜð;äŒÝÞÏôEÏžS^—íôOaԘy¹çP.™ñӏ_(ë›n2ì «Ño‰ÙÑ®®–}0°òïÄLèéùfGÇ]Ÿ€OÄÚÈrf±üÕüÏç¬ÌíÛX£\þB†×r™Š;m²Æ…ó§"&æ4\\]‘œtîï%f¹X o{Øù˜Q\>H‡·_èhå:m2(:î+̙3Çi 8p P€ (@ P€pn³AññãÇñׯóñh?År­ü±ö æý…^O¶ù¥'ü‚ƒ3"èþjîå†yN³Õµ\åþ#Å,a9#º‚XÞ÷3ï(ëË@ùbl ö‰Ô{voPj‘k-×p–ë4/ûùKüúË< ýdjˆ@ÛѶý›&£|ŒóR'GšCçŠFÎ(fPìP'•ƒ¡(@ P€ (@ ˜ ŠOœ8?—}‹^íJ1(.­íîŒüïœømÃyt{ôcÛ-ÒP™›‡¡Õýį‚ß]©2 >}"^Ü8îîŽçQ– €$'aÖÌ¡8(n²'7¹„† ‚M7¹^ñ»ýÇ+k0·¡C^D’˜QüéŽeù+ÿG·OC _úœÒÙrLîYäq"(3uf̘Qä}³C P€ (@ P€ €-˜ Šÿý÷_üŸôk±ôD)T*Ï5Šmá€Ýk ó—nÎC‰hßãƒ{mªHŽ÷òu7Es‡VgyZ,ãÉ̌,\¹˜‚Œô‚Í&.’A9p''ŽïÇÖ­ãʕ‹JP,g3Ëu˜k×i ?qs;Ó-66Œÿz=öšòåˆÛùӕ™×ïœÆ Ø–ÏïŜú3eŸr3;n (@ P€ (@g0‡‡‡ã7q®GÛ0(v+dÎ⠈ˆÉA£¶ýdD†œ üðýlüùÇ"Lö3J—.g¯ÃžcÝŽNA±ý9£ØŠÏolv}Œûtf͚eÓu²8 P€ (@ P€ €µÌÅøyñl<Þ!ˆA±µÎB·;ãÛµž–ä‚jMúqÏìŽyÙÙYx·ïCJ@Ÿó7|}ýrÌnˆÇŸËGãÃ7»£F•`‡££ **¥6f}µŸ~ú©£ ‰ã (@ P€ (@ HÀlPƒ_NÄS÷—eP\ ZÛÝù§»±ïðYŽì2Ii.¶[(+sh-›WàܹÓxº·ã®•pq+Žü CúöD ¿¯CŸO{\T²Š¿fPlïç‘õS€ (@ P€ ÀÝ ˜ ŠÏŸ?y_ŒÃSCßœ³M¹çÐi̜¿/Œ:—Œlª6CGØ¿íKžk.bԀGiX9–È€Z˜S…)Ä IDAT3o9ŠLáÚíy‚9( P€ (@ P€0+`6(ŽÅ׳G‹Å!šR1ÈlƒÜÁöâ¯%¢ßˆï1nÈ;ØzªšíÌ )`‡±Î"å⟹VÁOôlb‡#p®’ÃoÔÄ7‹~ÀI“œkà-(@ P€ (@ PÀ `6(ŸtéæLާ»”GÕPŎråŒ7êthQA•ÄéË%eXlF`ÍêŸÑžÊthŠZÕÊÚL],äÖ'¯×Àü%`âĉ$¢(@ P€ (@ 8¥€Ù 8..³ŠÅ3]+0(v Kd͖£X³åÆ|ø4~߆Œ,ŽC¡@ñ œ<±))Iv݅þ¯u)ÞbØ»E'DPŒðû?1a‹öçN (@ P€ (@G0ÇÇÇ㳉ƒñl÷PÅvöGNÿ ®®xøÑç±/*ØÁFÇáP x"#Žáêµ+ðr¹';hQ»zHñÂ^ $pôj~øy%Ǝ[ ãž3(@ P€ (@ PÀQÌÅ×®]çã*AqµJ¥e܇A`Ôg Ž¿ª6|…7¶ãUA{ˆŒ<ŽsçN£\ÂB®á±Î¡÷Ø"/*#qÕñã/«8û¡(@ P€ (@›0'$$`òè÷ð\Ê ŠmîôNAãg¯À±ˆx”®ü7n[8² 8‘@ll4څРeQ·b*ŽYçðpçN$`ÿC=W K]ƒ1cÆØÿ`8 P€ (@ P€ À]˜ Š1eÌ{âfvQœr™»è‚‡ØƒÀ?"1kñ„ŸMB)ÿ „V¬ŽàP”,ñüæ-''99ÙÈΖ_YÈʏYâQ|¯>ÏT•÷Å{òueÿÌLd‰ÇñzV¶ÜGŽ#÷Ïåkrc»²¥ ٗ|O'þOyTޓí‰>Å»Jyò{¹¿xK9F<üGŸ­Ž™{ŒÊv”öĹSŸË÷ÔGyõzq¬x®#ž+ïË}ŗúœìKýÞX“¬KÚÆÅÅâê•Kˆ<}%K”@œ*z$\9‰FuBЩUÍÿØóÛ8x¹–ÿŸ£G¶íBY(@ P€ (@ PÀJfƒâäädŒÖ/ô¬Â ØJ'ÁVšMÏÔaû-;‰“á‘8) ×o úÜÔ¹ ”_‰ÜÐV .eˆ§ÄyJçîî†LːN†p­%EH,CH òÄ£«0ežgúš

hÈkËØ¶lCžÞéi)ŠŠ †3e˜oŸÉxäyLHžªŒWŸBU£”w2j‡jQ³J Z6® ow[ù#Í: °ÿbüþ×FŒ9²GqW P€ (@ P€ €ã˜ ŠSSS1ò£7ðâƒÕ;Îy/ÐHSpùj"ü|=Å Lô"ÔՉ/5l͛õY Fí|ç«IîHÁtQlYZ\ýÕv5ÙSŒM έœeˆ'®&ÝØn5c­ÎØ6„솙åù߃ø# ))‰pÑ»¡|@2ÂÊD#4Ø]ùóÀÍŸö^šŒ«6cĈö=VO P€ (@ P€žK³A±üÕóO>| />Ta\zâ.™y(` …ð»ê3áç•j Cb …$°ç\e¬\·Ÿ|òI!µÈf(@ P€ (@ P€ö%`6(–K ð’ŠÃP£J°}ŽÕR€ ,Ø-‚â5¶cèСìÍ](@ P€ (@ P€Ž'`6(–ë}î÷<^z€ƒbÇ;ÿ(@ Ñ¡Ø°y† B P€ (@ P€ €S ˜ Š¥Ê÷_À³=«1(vÊK„ƒŠ(àøÛ¢ÊcëŽ}øè£°!(@ P€ (@ PàŃÞ}VÅÕQ',„ˆ (@‡Øzº<¶ïڏÁƒ;ÜØ8 P€ (@ P€ €%ÅõOu­‚z5Ë[Ò&÷¡(@ ؕÀЈrØœ÷>üðC»ª›ÅR€ (@ P€  KÀ¢ x؀ÐëþPÔ¯Y¡°úe; (@›Øx*{÷ÁÀmŠ&B P€ (@ P€(J‹‚âO>xŽ+&uC‹²6öE P€(õÿãБ“xÿý÷‹€?vB P€ (@ P€°5‹‚⟄n-Ë⟕m­~ÖC P€žg5ÇKãøÉôïßÿžÛb (@ P€ (@{°((?ôuŽm€«ØãY3(@ PàŽ«•ÆÉðHôë׏R (@ P€ (@§°((ûñ+hÓ0­›VsJ$š [`å‘@Dœ>‹wÞyDZÊÑQ€ (@ P€ n#`QPûìݵÁ£(@ P€ (@ P€v.`QPŒxî'ÈL:Ç ØÎO6˧(@[h]°XÅZ­–A1/ P€ (@ P€pZ‹‚â%ߌGÚÕñâ㭜Ч(@Ј x3ƒb=»(@ P€ (@ X(`YPRåÛMyB–?)fqM˄£HPJ…FõJ¡hހй €Oq žž @Ù²e]pì2(@ P€ (@ Pàî2GGGcÜžqxœsJcP|÷ìÎWCÄõ¬Øðví;‰ÔT *— A• Å‚Kn€––ñ°-Cµ…’*DK³Í"Ö>ËàVÍ*Ÿå–&ZœŒÚ¥×Ê9Ô!>Ë@055Eí×f§¿kŸeøçž_«Ó××ññ1êž6 W†ÐFÛ»ö]í—áŽížÙì¥ê²³í7ˆ P†Ž*l¶ЎçšLf-ÕgÛg ë3}µóÔl^ÙñŸ Æ-²-u’mf±-uœ©l?ÏÖW5ÛLc-AMÿí Ð`}ÓÃrˆfvÁšÇÅfŸ…­¥Ä¶}ún­€ÙdA€w‚šÙ­ŠØkm·Ã,qÛg9õ›¡«üO¶%ôpV»–Úy²y“ ))Y„¶b¿Ãlus²º¬G„µjÖºE„Ÿ>"ô×f‹:äM íF…Œ1‘þÙ,öùвò\³YÞÔ7#ôwўãgofë7+ ˆÌ·hAyŽŒQaÒ^"\OIMS7 äu¹“€¿ŸÇés8râ2Ô«€·_{*³ü,ç$¿Òè3r5Əàà`'é»A P€ (@ P€È[LÅIII9r$z¶-‹J%¹ôDÞ^¢Ümíôùlÿí6m?ˆ:ÕË K«ûQŒX1œœŒ“W #*Ÿ@îv j¿5dÖÂem™ mf©ö])o 9mA€ ƒež}Ó¹²Ë*WPµ2öTš¶}2G•!Мi,Y˜f(oKgí³€õºTþ*gîšÄ9b&ŽmF±–ÜЃéçé{d9yŽf7£ °E¿äf_RÂa =ÔVÇU¹†­¬†ë»¶~F†0\†®Zùô€^ñöï*ÌחäeÄw[˜/g˜«Ð^Ÿ1nþÓoZ°«·“Ùqçd¹òÅ"Q¯Ü%DEEbÕ÷{±þÇ¿1qXgÔšR2'›a]¹(`ð¯€ßZ„y󿉿\l‰US€ (@ P€ œW SA±ìþ!Cð\ËJšQ–k’:ïåÌZÏ»ˆ­»Ž 2:oôx Ñ©%pZ„Ãç#³VKSÀÃŒLišš¥¯âFtý¿ ³(@ P€ (@ PÀM2úé§(Žià犞3¬ðkÑXùÝ^èÇÕ,›wü?üþ÷)<ßñüpø>WûO§(U8«žQýùhæFòCïg›:Mÿؑ[~9lÆÎ¿/cèСä¡(@ P€ (@ x¬@ЃâM›6áÀŸ]Ô­”Çb¹ËÀ}ó+ʄãrx4jÕkƒ繎ª»\[ŽÃ9šU?…â…bÕzÅœ‡%Ózåë÷œCÅy{±vW"®Ü0£wïÞÎÛIöŒ (@ P€ (Ë™Š÷î݋oŸYޱœ*Ã`àírùºäjõŸ-ýf³ êVÀñ˜fˆKòÎÕöX9ëɁbFñ©+Þž¯qŸ|hÝùšLMMhL&³óu.=JMMÁ¢…“ÑŠí  ³×°vÍBTšP µîåZ¹Ù`Íò)å‹E¡A¥s?ã[ @¯îd¹žûÇO_ÁgëÃ1iòÔÜoŒ-P€ (@ P€ œX KAñ† ðïÁx³['»ö_óWü‚}GSÐðñþÿUÔíoúék€˜RQžpT.S !…]ÿŸžGFFà~­Ñý™×ѪõsökøÖà®(QŒÞzgŠÛ_Wg`H`«q£§®EÕ ¡èÖ¶Ÿ3t‹}žIàçߎâ÷SE0dèPÚP€ (@ P€ ŽA:¡``ÆŒ?ÏeÇæJ׃âŸÃ¿ÄÓmÀ#",ææ|ŸÌۂ{›Œ„æÍ›;_çØ# P€ (@ P€ @ d)(ŽŠŠÂŽiÓЭ‰•Ë»n–‡ŸNÙԖ_cþê£hÕé=§ì_nwêçßbÏÞm·4£‡Å!ÅK£~õ&¹Ý\«?<üŸÙ:÷B‡Ž=íí èßA­YüÖ6+Nð2¥¡sýCxaàçг9êÕ,K'=m#žym<ªV­ê„œc—(@ P€ (@ P€y'¥ XvkÜžqxšr"šÖgè‘w—)g[ÚùçqL[ü7Úw³»@mÛ~û'OBdøÕÛöV†Å6z ëeovadd8ví܌„„8X­ÄÆFãŗòv‰Ë—Ïá­A]ðÌsýѲå3öqŸñz”+WƒßšäWÊ=ºØý¡èÜg& 턊eCÜcPn6Šo}E+¶ª%hžQ€ (@ P€ ÷Šœ ë¿Àúu_`ÎÜrÅÿ̙1|ØóèÓw4=ü”œW{5GýÅ+¯zîÚÔ¹þÿTÚñþÐá•)X6ýU Ìú͇Œî¯§µ·q뜌˜ŒþÃgyÚÐ9^ P€ (@ P€ À-YŠåí–Ì›ˆ^ª x1>ÐÎS{öŸÂÇsw ý3»b÷³ÜçmÛ×áÏ};ìçe‹‰°øZ8J„•AǶ=³5“øÄñ0zT/àœQsP²dyÕÖ_íÄ€‰ƒà[Às?ÿÉ~cå‡M+°xÑLýt Š-‘åñü× ²?£FöáþšÚ‹¿üâ#xôÑvxŸÇ ÿª‚ÇsH É=ÇñÊ ñͬ>ð÷óÉ¡ZYMN ÌXŽå*VG›çFäT•¬‡ (@ P€ (à²oà¿r IDATYŠ£££1ã“1hÕ 5«”tف{rÇÿAñ”;ѺëGnϰíg1“ø¯í·ŒS‹œÄ2±×¢ðÔãÝ`2š²åññ„Ø¿7†¿7K<«ŽœŽÔÔTô~õ $&Æ«å'‚ƒµ5j·n]‹ys?T¡r•*9¿„Ë?ÿÀ‡ãßÀÐaŸ¢f­úªM‹% /<×íÚ¿ˆ.]{gkœ<)ë +E¿!cåìŸðññÊz<#W†~ŽR¬!ÞÕ윫í°r P€ (@ P€ €+d9(–ƒúdòDT*|­šÕr…1²7 ü¹ÿ4&~ö3Ú?ëÞ5ûyǷسwÛ¯¿ ‹«ÔšƒŠ¶†——w¶~'§Oňw{ þƒÍÐÿÍñ·ÔñÕò™Ø·÷Œ~|E{rÛùë&̜1ê–¿ÿ_þùgˆ0:))I¬w€f —.]ñ¶§ìÙó3ŠN¢Ú¬T©†*ƒ×ÄÒOwë‡6mŸ¿å<ùŸU+?Ǟ?~Vá“s·î¯Ûg<Ÿ:y^b¹ŽR¥*ˆãV5#zϞmhÛ¶š?qkÈ&ë;zôoÅ=÷Ü{Ç…%''bÓ÷_ãÇW"6æʗ¯ŠÎ]_ËžgëÂ8ÉI ÊFßw>Æúùýa6gïF„“ Åíºa±XÐkèb,X¶0i6¹Q€ (@ P€ >DøZD}–KK”.Sé–6åCõæÌzM\ª‚]¹ED\ƀþíÑãÅ·n vއIV3ŸaApŒ–K„–Á×„ñôéSG0wÞOXùÍ\¬^5OÕk2™1A”)Q¢Žúžšš¢çï6.GJJ’Ú÷ÐCÍoûœÈÈUï¥KgDˆê…‚"ŒooŒû𠄊ö]}»§Ø Œ7v<6,èǰÜÕÇèªý—7Ì6ürc&.pÕ!°ß (@ P€ (@ÈVP|ôèQ,_<ýºT@pŽvˆ•åŸÀیân<£8!)Ÿ‹ 89Y +oÞr"$–u.ùršE—aô˜ÏQ©rÍL]Œ~DŽûã•^ï¢q“–˜ûÙxü"Â]}öîtÔšù€X.‚O§œ+fùnCÓGÛ¢}û—PŽX(ô݁…1eêJ1S9ãCÒ~úq̟˜a ä‹O㝷ºáµ>#ÑžqK{[òÁwcÇŒ†ŽŽTŒÐc°êœ1üáž×qìØ~|0~ʕ«‚É¿¥Ö\~ù•!˜/‚ëB…Š ,¬,úS-e!—ސKmLœ0‡Äìg8×­×X…Ú²î®O÷ŚÕóQ­z=Ôšq¿¥0rÄKýzâÉ.èÔ©üü bù²øv×êáò!€®Ÿ• <ŽÉÓ&aÕgý\}(n×ÿ/VØCxö…^n76ˆ (@ P€ (lÅ111˜2y:44£æ=¡Ùi—çä£ÀoûNbê‚_ѶûÄ|ìEî5mA*Í18öŸ[ýšåêžåTH,ëÜòÓj̟7Á–ffTrïcûš0T†±üŸU-õP¡B5ÈÊÅõƌÍ?|ƒE '¡ÑÃO¡OßÑöªeºléÿÔ÷N{¡CǞ𕳓—~ù)æ|öüE`+79øœá/޲܅œÑ+Ã^¹Vrã&­Rÿþ{@Í6 ˜>cœ} aôÈWpüøAµÏÛÛ#FÎB‘"ÅѯO+Ô»¯1š€ ë¿PAoXX9 6M×·m[×áó¹ãQëÞ1dè45ëXŸd™'[<²e*ãúõ«X±b¶šU<øíÉš[·Qf8ºLÙB'0nâxµô„ÑhtêŸzZçFNû ]^ŠÚµs~pO³äx)@ P€ (@ PÀ=²Ë¡O›6 eƒcжq ÷ð Qüºç8þ·x—[Å©ÆD$ãÅÕŽª+zñüYl\%Ââ”dõœb…êb¹‰îj¹ ǟŠ\cw@ÿbíàŒ!Ö(®S§áþ’öÿœ[ÍŒ•3håMD@Ûëµ*„<°3ÂÃ/aÎÜÄZàïàìÙՃðd8+·±Žï°!Ï *êšúî[ÀŸL]…‚ƒìí®]³_‹ÀuƬbæo°Ú/é÷G¿Š×ßø z\íû[Ìþxâ µ†ðµkWÔKßä’/¿2<ÒZíøfÕ/¹ … …ëÖ{Xí1Œ‡Ú÷Ÿ¶§:¿íþ O>ÙÏ÷d¯ëúµ«?®._>‡Î]^C³ÇÚcЀNðã—A±ì›ã&gOËÙÖî°U >ÑãÇbÝŒ7žF±]P9kþÅá›ðÅÒoœšWì (@ P€ (@ P ²oÙ²ûþ؊O—Íß°õ, üüÛQ|±rë09Ëç:ë V 'ãfŒu©‰ðK—±oçn—Àà ŸTëêæä&×O§ WË\ŽhÙ =Þŋ—RMÈ5†âãT(,ƒ`¹É¥$Š~2T}–o5f®Z£WnK—LÇÆo—à!S±~ýbÿ÷LœŽÅĒǏÿƒÏ?‡óçOªÌ2xݱý[Ô3oû¿9Î&¯_÷ŸZ>ã?úelkËsGì‰ç_„'ŸêªÚ’3|åLß',Qëÿ.f6ŸKQ.ªo}ÝaªœÐX-!ѱÓ+ê¥oó>ÿP,›ñœX»øGÈ|Êä·Õ!9ËXÈe2Žÿ{P¬Wœ,ÖWöÅŽékE@œ ³fŽVK]Èe'þ9ø‹YÖ^^^biŠûTpí.[o$fÏ‚¯gö×G»ÆÜò_à¯#‘øîÏd ><ÿ;ÃP€ (@ P€ œD ÛAñÙ³g1þ<ŒÚº(Jåãäzfª?ýr«7íC£–eªŒ+J1& YÌ$6YŒ`5X`1€Ù»í›r7€“è±ʼn‡T \ºtEµ¯œ¥+V¹ƒ |åöʯ±xÑdµ¶ðžÛCeyìäÉÃjíޖ­žË@„aႏE€ê­Êƈô FöT«¬wÊ€·ñ÷ß»ÔrœÅò2ðýqóJu^Ï^Ãðè£íT›ϐwº£a£'Ñ·ßµoÆô÷°k×fèk"ßé:ËŒ÷«OšYËOþÊHËò[·¬ÛûÃߛ‰jÕêaûÏߊ¥8>ºe¹YöÑfíÑSÌR֗ëhßá%5ÃØ·`¿˜:eVÎî¿>î²îønëløéo<ÜjBלÕ%ËÙĆH s‹-ˆ7GªÎxYüàmÉ»Ń궋YŸ/œV3~åç*T¬†ÇÕêª>ɇÂɀ·Ç‹ƒÕì㛷OŠ AšXWyÐ[‹u|ç‰Y¿kUè,g·ïø²zœŸÉýÓŠŁý¿áañºÞâau—.žÁP±S¹zûÔ±8±œFDÄeÄÇÇ páb*<^·v¡X²b"‰z€Ý°!ÏÂG„ߣF}†’¥Êçß'—[.V0V<ðM,Ÿþ* f|è`.7Íêï$`òÇÀI»1xð`1㟠(@ P€ (@ P€° ÜUPŒzõj\8}};„ԅÖÿø¶ÿv õšu¡^ÿÿ]M2ƈ€Ø/«/Ґ‚“œ],fâZ :åoÜžn_?øæÊ5}åò÷ÖnéŸß\ßáC{a2›3,ã äs¢ÞúõUõZ,ŒõŠš]Šletæ UÞd2áÊåóØ»÷±LÆVµ6±œ -j—mö¬÷±ó×M˜ýÙ&øùš*–.ùT,±±Té]ŸîƒûxD+ˆšÈìß¿[-ƒqZ<€O®Ýìʵó÷IÆÂ9ý1{Üs)š=¿ì˜óœ; œ)…ió7á“O>!(@ P€ (@ P€w;v K–,Á›]J#HËž¹€ÀšM{ñ³Šë7çœÍ\“ ¢ UÄò0ZMðM+$¢cm]`n·ë'ÿoúµ|…Üä²rMbÇM®WÜÀ‡bɉì-0FjÔ(<Õž¬”äºÔó—ßžää4Žêö©šCÍ %_LÃwß-SM•-{’’qùÒYLþä/^*/ºàtm|œh 1oâ‹N×7OꐡdgŒ=ìôîÝ•*qOºö+(@ P€ (@ dN G‚âM›6áÀ_bÐÓ!™k•¥òU`ÌŽu(Z¡U^DdŒoŸö…»—€\ßxÛ¶u±\sXnÕª×ÃðžûOýOî› ?ï |å ÷ºØ.4ƒ_iœˆ®ˆÙ³gcÒ€I.Ôsv• (@ P€ (w9_Ÿ|sæÌA¯öP¢gçÝåË^Kß_ާ©sÑvž͵¥³§È³þ?ùºeKŠ#**¯÷§Žç©Û…à {#ú·öT‚|·±DKÌ[òÑ¥K—|ï;@ P€ (@ P€pF ŠåÀŠOŸŽ2ÅMhSßÛÇÉ>9ôþºµ­”€ ŠùË @. \<º 1§0â ŹL}ûêœ ÃX²úöí‹ & `Á‚ùÒ 6J P€ (@ P€pv Š=Šó>ǘW+ÃËltöq{tÿÞùðkÜ_«Š”šA±Gÿ8øŒø{ÇT«„ù0»ŒðŸ¹ c±Gñã®SØ¿? ”]`› (@ P€ (@—ȱ XŽöœ÷ÞC›&%pe—Œ§vrêüÍ0Œš^¿ƒbOýpÜy"àeJʕï g·ÆhP·bžŽÉFL~0–~Æ ÃsÏ=‡5j‡ (@ P€ (@;ähPŒ}ûvlÿi-Þ}©ÁX`ûî£XñíŒ÷ÖkØršŒ÷”]£€k x¥ǒ/?ÆêÏ^w큞hï!ãð™,\žP-;Á (@ P€ (@; ähPœ€ñã>ÀK-‚Q®d!º;±Àó?Çš7Û upôRQ'î)»FרðõhŽnZÝŚàÜòXÀ·$Œ%Z`êÔ©š^œ:žxâ‰<(@ P€ (@ ž–@ŽÅrèk×®ÅÙ#;Ðï骮%áaœý~Û|»å&|ß﯌ž$/àp){å‹Eá÷]ku ƒ{=__>ä3÷ŽoS³Á$`×Q±):t(fϞ§Í³1 P€ (@ P€ €+ äxP‡Ñ£GáÍgë ,(ÑM<ŠÏ‹Wî#çñÖë/q ¹êhn øû€ B±ëžtî7ì?x ‰‰)xZÌ$®T.$·šdœw0~†Bµ0kÖ,„……¡]»vŽ¢(@ P€ (@ Pà?r<(–í­^œ—/]Dïöa°&_ãEpb¥kÃößŽâ±æÝê{Ÿ÷”]£€s „ÆÁœt×®ÂñÓWP¯fYœ<{­šÕFÉ…³ÓîÜ+ï"0†µGtt Œ¹sçºóh96 P€ (@ P€ @Ž äJP‹1cÆ`@ÿ>5ìR£s¬Ã¬(ç¶í>‚ù+vábT!Tª\a¡eZ²3ݘÅbÕ*_°œ[Å»ö{ŽwõúgõI•׏keåùúyéÇŽZwìuh…m}4dܟáXúyú€dƒ8Çö®ï7ÀqÌ¢Œý˜ãgÇRw,#ûdíUiٞøÿê]û¬méßµ}Fý˜­œœOâpÆ:ôŒb¿ã±ôzo×^Æò[Väo&55†ø°$ÁÙsgP­R(J‰P8>1‡þœ$Bâ{QŸ4×þΪíݗZÂ:ÀàŒ9sæ $$:tžûjY(@ P€ (@ PÀr%(–nrVñõë×ѳÇÓ°\Z €%x§kñÛí±vË)D\=‡Ø˜kð2[––Š+á7`2™P*ް 1Fù2ªwPšÄg³Ù$ÊmŸå» ))Uí7Ëcâ%Ï3™ ªœV^|¶gŽ•óñ1#%%Maj!*˜bBJª¶Ž² Kmaªž©úúx#)Y„wA¯C›~žíÉcÞÞ^HçØ³fqL«õ+™á˜ˆ}}ŒÌHJIÍPαŒce².颏Ežµ0Ý!×Ûµíó2‹6d¿lAzª HHc—ºmŸc˜^À×ñ ‰ö€]Îµp^ ãåyÊNüçïW@š‰š­îi·ÖÂj=Œ–NF£ Vq#ÀÑ\ºe é¹¶>â:$'§ÚêÐÃëôwǺågÙ÷Ä€${ßä‹íF>Æ81öTQ¥ ÜÓ,ié㎗7(,"’wønßÍÂ11Éæ¢ndXÅùÚ»Œ±!·4+opÈ-U4bŸå¹rŒ²Œö=ãçèáð6$¡Ñ•Q³jIx‹k—(þ¬XP·f4šSA8pÍoýÏP^ŸkÂÜr $¹6ñôéÓó²y¶E P€ (@ P€pi\ ŠÓÒÒðÖ[oaàÀ(]"ÖKëEZ•âÒXžÖùøø$ŸÅÇ'‹À-FðЉ-E¥©"KM/qeš"?‹Ð-EŒŽc¶Ïb¿ü-È2'Š—òž Õä¹Ú»ö]ÿì+‚b™ãÉ Z“µ€Y –õ°ÙßÏG…’*޶ØZ-CE-ÐÖ^2à•íhÇŽ—'‰? Åo/Aܹ“€‚Ÿ($nŠù{Ú_Î5^“? %»ˆ¿gÌøôÓOQ¹reŽhѹúÈÞP€ (@ P€ œX ׂb9æ_ý[·nň#`MŒëåNLÁ®9‹€kA¢ ßî³ &µ0SiåCM}†š›^>£WÍu Im3}å~2Š€hÁêí؛ƒZ*&Ëi¯¶íNÁ¯cè+ƒQœÜ‚eY}Æ®ø,ÙÛÕw ŽåùÞ"ܔ!¹>;Ûþn_Ã!ח»3‰õ@Ý!˜uܧÂv[š«Öxǐ^†±¿§ÏHw …eH{ó²Îò›d?œ_Àò ~epüøq̞=“&MrþN³‡ (@ P€ (@'ÈÕ XŽsÔšQhÕªêׯëý°FþîDÃgW(@ PÀåüÊÁòžÆ{N:¡N:.?,€ (@ P€ (—¹Ÿ>}Z­9yòd5.ëÕ`?›—cd[ (à®F/ñ;±ä„ÙÛ·oÇΝ;ÕúÄÜ(@ P€ (@ P€Ț@®Ų;Ÿþ9 *„.]ºˆ…LS`¹žZ,šµž²4(@ Pà&CðC0ÖP{ûõë‡qãÆ!((ˆN (@ P€ (@ dQ O‚bùÀª`øðá(Q¢%Ââ5bzqúš®Yì7‹S€ €§ x1¬ƒR˜5kÂÂÂЮ];OWáø)@ P€ (@ P€Ùȓ XölïÞœXœz5Ǝ«:j; kø–luš'Q€ €§ ˆÇ:АØàŒ`ùòåj617 P€ (@ P€ ²'gA±ìž\«ž|ùòhݺµ_ß kôÁìõœgQ€ €Ç  Ý Cáújürɉ‘#G¢xñâëÁS€ (@ P€ îV Oƒb¹ÅÀ1jÔ()RV«žŒÖ€«w;žO P€ž"`ò‡¡€x€ÑŒ… "00;vô”Ñsœ (@ P€ (@\ÈÓ XŽàøñãj-Éɓ'kJKë¯RïÜ(@ P€ÿ%`,þP vî܉­[·ªõï¹Q€ (@ P€ (pwyËî®Zµ áááxíµ×Tשּ—`œüíݍ„gS€ €Û ü+ÂPìQÄÆÆª¡2g΍F·7H P€ (@ P€Èm| Šå äC‡š6mŠFiañý°FþžÛãeý (à¢ï"0„¶ f 2/œôªV­ê¢£a·)@ P€ (@ P€Î%oA±ÕjU ’qá…µ°øê°ÆŸu.!ö† ò_À(Bâ¶0˜|±`Áõ¿íÛ·Ïÿ~± (@ P€ (@7È· Xú]¿~Æ SÿtXm–±^ñj 5ÚMx9 P€žkSCÛæ¬_¿gϞU7¹Q€ (@ P€ (sùËaìÛ·O­Y}:J–,‰Ž;ЇÛ%ÃriœX·8Ò¥‘Ùy P€ÈŒ€¡`5Š4BZZšzhÝG}„   ÌWÀ’ (@ P€ (@ dYÀé‚b9‚µk×"""={ö„U„ÅÖ+ßIáYO (@×0()–œx Ib&ñÀ1qâDÎ$v­KÈÞR€ (@ P€ €‹ 8eP,-åÌâbŊ¡[·n",N®þkâEef·)@ Pà?Œ ÃÖ‘Q16l—›øO0 (@ P€ (@ 䜀ÓÅrˆ .Djj*^yåñt; ¬á?Á&çFϚ(@ PÀ9L~0„¶Ç™óWÕRòÁuþþþÎÑ7ö‚ (@ P€ (àNKÿ¯¿þáááèÛ·¯‹­°Fl5î”\‘ €‡Ì0†¶ÅïÇÒ¥K1eŽ $å rIDATʍF<‡I P€ (@ P€p§Š%ӏ?þˆM›6aìØ±ðõõ…%b;{Ì9Ù P€ž  şÄò5;pòäI >ü.êâ© (@ P€ (@ dWÀ%‚b9žcǎ©Yfo¿ý6*V¬ëõݰFÌîžy(@ 8€¡HCL˜±%J”À‹/Ÿè=b(@ P€ (@ P€ž)à2A±Œ<ñññ1bZŽhæÍ›ÃµWœžQ€ €ë „'–ÀøY›Ñ©S'4iÒÄõÀS€ (@ P€ ÜHÀ¥‚bÝ}ƌˆ‹‹Ã Aƒ`J8뵝ntI8 P€î/°aÇylþ-C‡ Cɒ%ÝÀ!(@ P€ (@ PÀÉ\2(–Š[·nŊ+Я_?Ô(ç%r·ÃÉ©Ù= P€HLJÁäyÛ\æ!ô{œ?A(@ P€ (@ P€p— Š¥_dd$&NœˆZµj¡{»",ÞX-NBËnP€ €£ÀŽßaÙúœxŸ×»hÔ€q(@ P€ (@ P€p"—ŠuǯŸú Û·oÇ+Ï·AíÐK",Ns"bv… €g \ŠÅÌ/¶ÁÇÛý‡~‚…žÔ„gÿ"8z P€ (@ P€pF·Š%ì¥K— ×..VØ/=U þfgôfŸ(@ x”Àòõ¿ãçÝGñBdžhز JyÔø9X P€ (@ P€ €«žMP¬ƒoÜž?oùV1£M³j0™Œ®r-ØO P€n# —™Øðã~T«Š»4‚!ž! ÕÝf|(@ P€ (@ PÀÝÜ.(–(** ˖-Á‘»ÐŸiYS€ù+ðëÿbÖýðö)€6mÚ¢~㶀wpþvŠ­S€ (@ P€ (m Šu¥cǎaíšU¿xµÊû¢ÉP:ŒG¶E<‘ðÈqønëAü²ç*ÞS -ÛtAºM=bì$(@ P€ (@ PÀÝ<2(Ö/ê™3g°uËfþûöMÀ“Mª¢bÙbð÷u÷ëÎñQ€ÈŽÀŸûOãÇ_âÔ¥4jÒ ­Ú=‡¢ÅB2}> R€ (@ P€ (àüë—'::{þ؍Ÿ\‰”˜‹(_:Õ«ˆJeCàímvþ«ÈR€ÈaGÎã×=Çñ×Ñk(W©:~€%š4},‡[au (@ P€ (@ 8‹ƒâ›®Äñc‡ðûöÕ8ð×n¬iš[£ ªUC±4g;Ëϖý rC`ÿásØ÷Ïüq𠂊–Bý†ÍÑŽÙ ʍæX'(@ P€ (@ P€N$À ø#91ÇömÄîßãÌùp @‰b…p_­²([2!E 9ÑedW(@ d] >! »ÿ:‹}G"pädJ„•AÝû¢ñ#ÍPŒxñ¬WÈ3(@ P€ (@ P€pYÅÿué,Iˆ‹<3gÏãŸCGñ÷Cb9 /˜L&ÜS¹*W,°Ð )ªj²Z-@r¬ €ËbGÚµÀã òD &6NÜÀ¡S18}>×n$¢r•Zš[·.4hÿ<é¡(@ P€ (@ PÀùgãšÈ‡à={ĕ+WÄlc1ÝXl5kÖDéÒ¥QŽhQ+V üaMº $ŠÐ8ñ’ø|EÇ"HæF P 'Œ>0˜ýcÀ$^ê³/NžÀ¿§.âÜ1cøßÓž‡òåË£J•*šQ£ªU«–“œ`] (@ P€ (@ ž°ƒâ»Œx žté.\ž€cǎáܹsj¶±Åbʕ+§^… FP¡‚(ì— /Ë51ãø‚˜q.Z·Þex:(à–"蕡¯ €eø«B`_L¶ïrŸmԍêæÕŋqêÔ)õ÷ü\€HuóªbŊ*®T©’[RqP (@ P€ (@ Üœƒâ»7ÌPCjj*"""ÔKÈ2޹ví’’’T¹ŽŽ4",, !Ŋ HA+Œâ`Žïñ|`^_VçB“謘¯fèk/ƒÁ(n¥Èwƒz×÷Ë2ꘞÏ"ßå÷›ëç;ž#?ëåôóìÇmmkí‰:å=£xwl×Þ?é*ûj;îÐg} öŸË6o:®³õÝÖ'µÏè;\:yãIþ녫W¯ª¿[®_¿ŽË—/Û÷É¢!!! E©R¥T0,g {yy¹Ð€]¥(@ P€ (@ P ?ç‘~TTä놘ù'"GFŠ5BEˆ¬oK Ғ¢Q$Ð_S"ü},(èï#^Ÿb _€XÙÛË, “ön6©Ïò]fQFle}³ŠÄMŸ,m†³|WûÄgý˜ åd`•þ.Ê;ìËpŸ™1ŠZ¶pT^C«~eôú޶Tx© úf3صjK 8­ò˜¢7ڎ9°Ú1™ŽÚÚ²…¯&£˜/ûnû®ŸF¹_•£Ÿõ¶Œz`+öÉ@Tÿ ÊzôPV/oP牞ÚX­ ­oò]žëø]?~s9œŒŸ_oS?ÿæóä,ýÇώåîT§c™ìþùÒnÉÉɐÿ AŸ¯>ËIò˜û+66òƓ ‡ågyƒ)((Hýë9SXÃ2.SЌÚύ (@ P€ (@ ܍ƒâ»Ñˁseð—á%d*ÇÆD"æúÄÝžŒžè«HMއ|Uª8G$r*ÌÓBX+L"`KNISAžbjÁៃ§PïÞ ¶Õ1ÕÏÕaA¢–ŠŠö϶€Sf¢P§ŠŠ>È`Ïô9²e£šO>ô/%5M‹&õ`PKãla¢ÊðM垶™£*ècp<Ï[̌L³±UÐ*^f³Y…ÖÚÌR-€5Ë2²=}Ÿ^šm*³R#L¢ïiÂI7R­ÚZ“Z6DÎúÖCCù.ÛÒ÷©ŸÚBõt«ô‚<®ú¥†©[Šw¬_/£Õò˜ü,ëÐÛÓÏÔË8†Ý7Ÿ»Ÿ£ìƒîߺĉގcŸd99ޔ”Uãyú؃~YF¯çæ>Êý2èt¬G–‘K²È`Ô±œÝN?DZÿŽN²^ÇöûàX¯üìíí­ÂXG˛Ë8^·›ÛvtÕÛÔ¯íÍÁ¶üþ矢N:¶/šœ—ì‡ì·|—3}廎¯‚ ªïê³ …õ—\ï\Ÿn÷{ºÝ5ç> P€ (@ P€ (ÅÙQËçsdð$ƒDý%C(ùÒÒôÀV5KQN޳5e˜¥\޳+å°gs:~Ïç!³y äªÀí‚ø›÷9~wü3&ÿêßågyãGÎðÕÿœÉ?cò³þg-WÂÊ)@ P€ (@ P€ @6gާQ€ (@ P€ (@ P€pÅîr%9 P€ (@ P€ (@ P€Ù`PœM8žF P€ (@ P€ (@ PÀ]»Ë•ä8(@ P€ (@ P€ (@ dS€Aq6áx(@ P€ (@ P€ (@w`Pì.W’ã (@ P€ (@ P€ (MÅلãi (@ P€ (@ P€ ÜE€A±»\IŽƒ (@ P€ (@ P€ @6þBÿãD霐 @tEXtapplication/vnd.excalidraw+json{"version":"1","encoding":"bstring","compressed":true,"encoded":"xœíZÉRãÚ\u0019Þ÷Sžœm[œy`\u0015cÌÜÝ\\à2…[”l\u001fÛ\u0002YrK2\u001eºØe—E*•T¶÷5òV¹#\u0019,ɒŒ¡ÝEÑA\u000bÏ€ÿüçûþIúö¡T*\u0007ãŸ*¯—ÊjÔ4m«å™ÃòǰýNyŸå:º\u000bE¿}wà5£‘Ý èûëkkñ\f£éöг”­zÊ\t|=î/úw©ô-ú«{¬V8·z}\"\u0019ŸT\u0010?ÜûåboŽY©ûÇÑÔhУ0žj\u0006ŠÓ±UÜ5Òí\u0010C\u000eÆÑÊZuZMå¹õÏ\u001eä…síE³ô\u0003;]Gù~jŽÛ7›V\u0010ª‚Ä\u001b\b…ëï¶¢Cøm~ù®éõ\u001f–)G›H\bŠTxH\u0014\u0003‰žäñSb,\u0010Žç[?»N„\u000b\b!ÁP\b$g#,S\u0003\"ˆVm›¶¯b\u001d†O®Ïƒ%\t˜\u0004hzçö\u0001öŸÜ~:õǟ÷ƒö¡OQ{&v\n8Šç¹Ãò¬çþã¢u;“Î\t9Àa2Ï\u0015GMöå ·‚ui\u000bìîMNœ‹\u001dÞõ~ÅÖáW»Ú_n݇»øÔ\u0006ý–9U d\u0004\u0013@\bã\f‰\u000f\t)æ(ж=çöŽS߯\u001fWª[öÖF»o\u001d,O1\u0002aŠb\b²\fÇ\u0010%Or\fRŽbŽ‘&SíWå\u0018]\u0019Ç  P\"$)Ï!\u0019\"\u0019êÍH\u0006\u0000d˜°•sì‡b\u0016ëÿœ.À¬wÑ\u001c¬†¬5\u001b·›ã¯§m—tÌg`6asж\u0010f1‹@\u0016€DŒcŽ\u0018£P\u0003M`\tó0\n%)š`D+›HŒjŒ~‡\u001fX®\n\u0006å\"»êmO¶ÏOå\u0011ðêŸv/jN‡îoNŸ\u0003£‚¿ct\u0005\u0018ER{D”‰J\"3Z\bQšç\u0000À“Ð^\u0011F¿#ŠX\u0002£\u0012\"\"\u0017`ô²:\u001e@Õ:Cµª+÷Àç\u001ds\u0013‰,F\u00035\næá‰y\nž(\u0001×…ð„€¬\u0016Ÿg:~ßô޶\u000b0Ú5›Ý§~4Jµ¯]\u0019L9’R2\fòbj\u0004Q!N¹vÚ\u0006‹•ã”\u001cù¿6:^×»DÖåî©lZ\u0017Õá”\nÉ\u0013!J\u00047œÐ\u001f¿ÿë\u001f¥/»›µÒîféDkιr,ß_/©‘ÙëÛ*L#¯\u001cÐX/™Ž£þœj6ô•Àƒë\u0004ÇÖ$”/\u0001ʰuËìYö8u€áó«¶Õ\t•]¶U;+­ïÀÒiì¬;pûItúʶœð)2\u000eq›ú)ŠnõvÃ-;\u0003ێÁãY\u001dË1퓕íx\u0001Ù­öÎÎι}~xQ=îì\\·÷Å^ —#;\u0003)²“DZýHvˆE–순sý)®sÊ€N~XndŸ`Å\u001cÕ)Öñ‡äˆŸ€é)\ffœ\u0006g\u0014à\f\u001bKüþÏ¿–\u000e\u0007\rÛj–öÕø\u0015É\u0005ÅKȕÙÀ\u0002®ôŽÝ»ƒËñkÕ\u001bÖP\u001c\u000ejÛ¢³\u0014W0£)®@’­9%ËRï\\y\u000eW\bb\b\u0002œÇ\u0015͇b·È˜Ô\u0013ÅKÒàÅd\u0012\u0000\t\nȲ5°›–[ª…žnkd\u0007ªT\u001d\u0004]\rÌà­Ògá–\u0016\u0010jûìB\u001côºØÚ®\u000fŸÚ>=ºýå('cÏs><]`\"2\u001biÂDôùNšg\u0005š˜sÆ1Èø™QB\u00142Š ¬#TÎWÏšb÷óï¿ý÷?/ÕºŠm+§£Þ\"ƒæ·°€1_èÝæÙñˆê\u0018ow|}w³u·ß»Yº~€\u0000d\u0006\u0002\u0018¢Ž;ª`lP‰yÖ)1I\f™Œ²ŒÂ‰8p5µ\u0005š\u0012ª\u0002:œµÚ‚΁¡ö3¹‘\u001cd…\\b\u0012#Nu®þŠr6&)§`\u0001~ÕE…}\"öšö\u001bä\u001a²Neˆ—²ø:ó5Ž>\u0010\u0017‚0HIú\u001d\u001e6\b`('šâ$‹Ø•¿Tx}À®Òú\u0013\u000et\u0016A)ÍA,ÊÖq\u001f\u0011K\u0018\"@²—\u0014l\u0017Û~&8À9¶z]9ø\\3†Ê¶+·Ž;tÖÜŸr¬VE\u001bâ¶Õ\u0019xf\u0010ʟç\u001b 4\u0010\u0006œÉ‡¿‰*à\u000fô\u0015‰ªâs|Å󷌀‹¢¿§ZR݌Ž÷Žê˜e›\u001bg9ïø²\\Ô\u001e„\u001bDGÎ<íF8(`a²-ŽÄÀªkÒ?\u0015\r™äB2W“f\u000bJҐ…i͋ršWt\u001b\u0014‘„aI2üÛ#دôNüò®tÏUâó‘Y­kíªü1\u001elNóIĂkåŽú®å\u0004œ\u001fÇ«Ô*AXm[bv4.5sà+ÏrÚî\u0012“\u001f‡Šæß\foýëg\u0015OKR?\u001cmÜø®–áq\tÃ0Š·÷¯\u0018\u0012£\u0004\u001fžiçÞ\u000fþû\u000f~ñ_Ìç9.§#1Æažõ×q®\u0001(„X\nÄ(\u00069Á\u0018\u0012†Î-Ž/\u0010Šz\\Nl\u0006)0€ÀŒ\n¢\u0017\u0014tÕßXýT>‚\u0010\u0018U›ò\u00025T˜Z @\u0005&øeï-Ÿ\bÕtüObq\"ü§]K|WŠO2ú1»ÿícîèbô„W%\u0003œxœŒ\u0003²M?š¹œž\u0015hé\u000fC!çwæ\u0007Š\u0017lXNËr:º/vˆ\u001f'î.ñª4²­ÍAš\u0000`0J\bæ\u0010\u0010ª\u0003M\u0019×\nB\u0014˜ýÈw?°ê¡cöyXY[’§EY\\\u0019H‰B\u0001Ç\f\t­DŒ‰Œi\u001c‹Â\f\u0006\u0004ä\u0012sF\u0018€3eÞ§\u0015T\r­CW™\u0019ƒ®%Nö%C‚‚ï\".Ûæ]¯N­I·Òå-JO&£å*œ³:÷é{Ó7W\u001cœ—\u0001ƒ>×'w­\u0013ó@Ôo\tûÄÎ÷싃ÚRÙ\u001c’¹\fª RP\u0014„0/[qaý'£Œ$”R!d^>G‹ó9ɰöw‚œ€\føTUE{lU%\u0011hŸ9¶$eŸ2åÃ×/›ýþq \u00150s ú@­ÖÞâEËw–\u001anä}š\u001f]áª\u0011ûB0ªPÇßî?Üÿ\u000f˜Œƒ."}¡žÑ/IEND®B`‚fulcio-1.6.5/docs/img/certificate-request.png000066400000000000000000002077011470150653400212020ustar00rootroot00000000000000‰PNG  IHDRp…Œ*T IDATx^ì`Tdžÿ „àîî.Š»»/PÜŠ•>€Ž¥”âТÅÝŠ»w„’#.oÎln؄ÈM²›ÝMÎôíÛdïșïÞ%÷¿ç̳0QÀ… 0&À˜`L€ 0&ÀŒž€ 8£?Gl `L€ 0&À˜`L@`Ç`L€ 0&À˜`LÀD°€3‘Åf2&À˜`L€ 0&ÀXÀñ5À˜`L€ 0&À˜0,àLäD±™L€ 0&À˜`L€ 0p| 0&À˜`L€ 0&ÀL„ 89Ql&`L€ 0&À˜`L€\2¿BBB@[ý…††Ê÷Ø~ŽîžòYLï„O9Šü¬ýÓgÚØÍÌÌd1:®úYù=ºŸ•cæææ² œ+õŽßµ?W~ŽéÝÂÂ"™_%<=&À˜`L€ 0S!ÀNëLÂÃÃCŸŒŒŒäËÇÇ‘Dжòõõŋ׏Q€h!ѓFˆ˜™™kÞé¿pqJ…Tø€âjXåsª$úmdõð6ÚB‰lH•*ÈfEüÐgڂ*Mš4ò8 mÁB‚„ìJ:5‚ƒƒ# íºÔ?IQԗfΑEïJ}úŽ+vÅô¥°ŽŽ”ãÄTšœÂ1ªXԞ;ýL}EVís¥-PÉ.íóJõ”ºQE¯••üüü"ÍM{žŠ0€yS]…iTAU@>}úŋG† `mm-Û*ïĞ^4úŒÎ%/å¥-jMå¶“ 0&À˜`L ñR”€£ø>àíÛ·x÷îàææwww£x€M›VŸlmm‘>}z)BŽœ=Šw‡>óôqÅÝQšxîp~R„ž‘m"D݁CZG$æBì‰*âw¥–‡I£ˆèpDßaâKM€Õè€øàKæ°°ÇB”ƒ²)aIǃ¿F”56X’hÇ¿DchúQ[HpHøà_ŽÉ:4ñŸ•µ‚h ñùÁ4‡41ÍŒ!D‰‚"„Ÿf2šãš^”15b8œÀ—Ï•ŸÈÓ&+B‘Î U7—ž:b«éI2ÅÊ*•x!òwåüHÆáõ5çF^ù»ÆóFuå€èŠ¢âŠÀ–ü„Ø&‚%›/^IÅãIŸ)QùùáÇȝ;·lGb’Ķò"Jméz€BuHÌ)¢®ËtéÒÉë“Þ3f̈L™2ɗÒ&¿1&À˜`L€ $#ÉZÀ999áΝ;°··—bíãǏқ‘)[zdÊjô9,‘!G*dÈd+Œ é‘:5ÝŠknî¥@R~hnø#> NA¡~ñIF—OE×Ì¥Ԉy ׈X‰RäJ­–P ¿öB…÷÷ „¯>{û o°æý³x÷t÷b1Òe‚µ¥q©3ÃÊÒF @ò’Ëœ93²gώ}œ{÷pÿþ}<{öLz0J—.‚ "sNdÈi†`«O ùlúgŽgâ —ÓÇÛîœàîê%D/̂R#{–<Èh›]ˆº,’‘³³³ôܑS^ô ƒ `L€ 0&À˜€é0yGá'Ož”¢Â!I¬•)Så*”Eºl"Ä1À^Aïhzg‡-fñ$@¢ÎÝÕS :7x~DŸŒ…;[€K“ ^>ptt”!—ô])Q¢„\WDž 0&À˜`LÀ4˜€€£õBW¯^Åùóçehd­ZµPœzu(”Þ!NÑèlg€­dz&ðÁÉ ï\åË6MF-Ty²E€(‘JŽ9€#ADž 0&À˜`LÀž ˜”€£Ä#G•Þ6 «_¿>jÔš!Ö yãƒïcžû¿Fh˜&‰&ÀŸ&ðÉÍÎ$æ]a–ߔ¯‡ŒYKàÙÓç 5£%K–”lJŒÂ… 0&À˜`LÀø˜„€£5<›7o–Þ¶:uê ^œzȒ% Œ?Háæèd|dÙ"&`äŒ<>ãÕ3Ø?sAår5P¥L=|¡—Ž~”’ŸT«VÃ+ü²yL€ 0&À˜@Ê#`ÔÎÅÅ;vìÀãǏџ}{4iÒDœ¡0ái³‡‹ßø}JygŒgÌô@àÕSŒ~þ™lr¢VÕæ0 ¶Æõë×Q¬X1)äx3s=@ç.™`L€ 0&F)àhÓä-[¶ÈŒ’7F›6mW¿pñ} JÝυ 0Ýpuñ€ýs'}¶Dã:­àe…×o B… šZµªîä™`L€ 0&ÀâEÀèÜå˗±mÛ6Ô­[­[·†yª`&ùnþ¯Äú6±Á4&ÀôNÀý£'îß~›ÔéаvKxœ7ÓÇÏЬY3d͚UïãóL€ 0&À˜`Ñ0G™%W­Z///Œ5 i€póxÇçŽ 0pzû÷oœ@Î<ÙðmÕú°»ðVd±,ÉÞ8– 0&À˜`F!à(TríÚµhÜ€1j5.ŸÃ7؍Ï`FB€ÖÈ=Ž{…oj—A«ôr¶@‡VÝ`kkk$²L€ 0&À˜H .à6mڄûï£÷ ÖKçÊëÛRÆudz4Q—NÛÁ6œ Ʌ›çŸ£yÝ.(_²º‰Î†ÍfL€ 0&À˜€é0š€›?>Rg BÝvÅD’’ Ó£Ç3HàÅãwxùÄ5–ÇËGïQ©`KTªÀ NRà¥ÀSfL€ 0&À @À`núôéšX³ WMc€ióL€ $†€·/®üwEJåEšoÈP Õ«³'.1L¹-`L€ 0&ÀÔHr÷ùógL™2{6EúB^jlä:L€ )Jpbnn†ŒËÃÌ/êׯo€–²YL€ 0&À˜H’TÀbâĉ8¢3ŒÒEžHÁžÜ·‡¯·?ªo ?ïöÄ¥àk§Î˜`L€ èŸ@’ 8Ú&`òäÉ;iÜ-ïé¢ÿÙñL€ $ ûNpyçƒ*EZÁ㓚4i’$ãò L€ 0&À˜Hi’LÀ1ÃGBPŠç HiœyŸL Ùpvtû‡~š^¶)ÈÛ^­Zµd?gž `L€ 0&À’š@’ž™3g¢Uëf°)ä‚ÀP߀ž#Ç˜@p°ÿ€Ð¹É6ræÌ‰%J$ÑÈ< `L€ 0&ÀRœ ž¥K—"|(^ÛŸAî)ƒ*ϒ €`ÞyÀ̵ ‚¥Ž„&À˜`L€ 0ÝЫ€Ûœ{7<<=P§CAø}ЍÅÜ `FOÀáÙgäHUöööhÓŠ lllŒÞf6 0&À˜`Š@@oîáÇغu+Lj w{S`Á62& CŽ÷€,6áì쌎;ê°gîŠ 0&À˜`)—€Þܐ!C0bjŠvH¹tyæL 07³€ýuÀ2,-òæÍ‹Š+Š`]ž`L€ 0&ÀôB@gnÎÂI°ÉŒú-ªêÅPî” 0Ó'pãâC8>öÃŽ ó`mmmúâ0&À˜`L ‰ èDÀ¹ºÀà±=1mþIl>ǘ€)ðñöŞÿCóúÐŒA'S2meL€ 0&À˜€QЉ€ûuáOHÍu›V2ŠI±L€ /›—ááW˜>ádK_Ðx e˘`L€ 0&`„-à\\\0núŒ›ÓͧÇ&1&`lü|°}ÍqTªV ÝZŒFKÞ/ÒØÎÛØ`L€ /D žÅ+ 0µ¶úÆxgɖ1&`Tî\{ »«OÐwD'”ËÞV6FeØ`L€ 0c%(„Ÿƒ»`ÄÏíašÓ‚ëIf»˜€± Æê…ûЀmuÔªÒyl9üÚØÎÛØ`L€ 'D žc'Žàäµmè9ž¹qΎ­bLÀh œ;~ Nï>bð°~(š±ÑÚɆ1&À˜`LÀ˜$JÀM˜2•åAÉòiN&kËÁíç±ò·]Ȕ5=~ݎÃRMöL²ájž}ôÄæ•GÑdgÔ)ÎûGªaÆu˜`L€ 0&`÷þý{L˜1ãéÎu@àã‡Oh_}üý#zë6 )ÆÏî sssŒ`š]„††â͋÷(T<iN€­Ž•ÀÆGP€D^ ë:æf–L‹ 0&À˜`L  p«×/‡³ïCŽì\‹!kp^…û.¢×–033SÍæèîK˜>l9j7©(BR[`ÃÒCžzö>Zu©Ÿ6šˆKèœTO>–гÇýƒ}›Ï¢RšÝžŠ–ʇR !K¶ ºèÞdû0ä9Ñ%ާìqòÀ5,žÿlSe×e×Ü`L€ 0&À’% žþú¢ëкȚ#“сùèü Çö^Ægo?„…†ÁÓÃ?þÚ/Iì<ºG±¡ËñǺ1hÐR}fοÿ؃UówcÏå?P H.çiáÌÍØò÷1)’ÿ·dˆÁD\Bç€ àýZýŒ{7ŸGêÊÒÒ5”Cëïê¢^³Ê°²N¥‹¡LªCž]‚ Á²¹;0røT-ÝH—]s_L€ 0&À˜H–$à=y€ù˧aäô®FåЎ ø}Ê|öñ‹°-••%ŽÞY"זé»Ðø3G®lº¡ïÈ6Ñ7ŸïB).ç ‘—.œ&}ú/×b÷¿§qåíúH‚dÉÜmX¿ø zk…w¯?|ÕNßó¡þÕÌIvžºx`øw¿¢x™ü(]±räΌ÷®xpûο-ÃMÓgL‹œ`è]*UÊ Á3Ô9ÑÇy>$Ö~fH“£ü€î¹O&À˜`L€ $+ p+×ÿ‰^ÏЊ[]£‚±cíIü6eœŒ©ï7ª-2d²Å²_v€’%PHãØÿõÔ»œû·œÅ¬±ÿ FýrhÚ®ì]@[вB#oÁhUyÈKømƒòXŽy",,Ìñã %B”ÜÂå7뿲qt¯ùž|ú.2‹°AבÚé}Bb€žæDC}”‘ÝÇåÿîbܬ^2¬T»@'»þ]vX²¬Xœ–l›Ž©õaŠÑõišs¢o_œÇ¡-×°zñ}tÏ}2&À˜`L YH€:¡;ê¶(‡å  Œ·_¢_«™H—!-Öø)"éÅÅSvÝs>ÒÚŠÁ¹ÿÄk]ššÉ………aïŠ3xñøL‰þôþžŒwÿªiº 6˜Ÿ`·©.%‰Í·^`ÆÂÈ™' Š Y†S‡®ášÃ¿_µ¥õqä…[ºc2v­?©ã['!sŠïjêϛŽ»6œ– ~^48Ú&ŸŸý1€Ó\<Œó ýF·Åˆ©ÆçV3מêË9‰Ë΄Ÿ7iVü±Y³fMh܎ 0&À˜`)‚@ŒÜGÏ·<¢/&ÿÚךBÖFõ oÍ=ü³oºHxQ2âä£a‰Á ý£vK=WæØÀ€ ü1}#n\|wo”®PUk—ëÕrb⋟ê3WŸ¬hÖá[”«R %Êý]¡0@»ëOe:uò6]²_‡Ôiâ¿):­%º~þôЕ­\…Ef¿„ Oûý‚Ï)¡ãFm·ò÷]øgÁ^P6Î^C[áà¶óš+ÖŒ•Ôzp@çuâɄ/=5—Y;Mµ<ü§^Ǎ ñò©ƒô&.Þ2I&n1–s¢/¶ŽÖ³n¥ŽhÛªœŸ†à~™`L€ 0&,Ä[Àí9ù7Nýw Æύ֓ûöèÙxšðnUÃo«Gubhمw°áÈÿ&š;QÛVÇÎõ'áéî#³kªŽ… ‰„ÿßøªïü…r"D$É[ »kEEò‘0¬]ŽÝ6ÃÄ9qïmµsý)ü:y]D¿$VÊT*‚BÅò `Ñ\ÑÚÕ‡7.ƒ·T¬ {qšs߯"qK߯<Ž^Ÿq`Û98Š6il¬‘GØÝ±wÃHõì_8a|Ÿ?ڳ, š…4RB–3GoÊ$2Õë•Åšݑ+oüŒ+KæˆõKJÏZHpš—<$í¬V§ llSÃïsß{ ÏO>R䬨9E†™j—S¯aÍÂ}xûʹóg"¯… eMH!f7.>’ûóQ˜®ÚòÈî–Íہ{7žËvMÛ‹!“:Á:µFšÓz¶"ôœw]RbšãkÇÈë0±çD­­†ªwëò#8=fN›c(x\&À˜`L€ ˜x žÐ°`üŽ`2fM‡†ñȰšoëÀÒ_¶cŸžÙ¥›ëøÚmHǹâù=(ÙIŠ,ée$yÁ¶œþEf„€ðÞÍfHÈ’m“€Àòõñ‚îº*{€š ï•WÂsÒ¥îd€šò[ô™/)ÃäáÑD¬‘£€?Xéæ]±Ÿú͑'3Ÿ©]ý…`Î#ˆÒNñÒÑxÛÏ^A)"‹—- =q>"IÊr!hª×-ã᝗%ÂI=ÜŒEFK3™A40 PžF,ewŒ®š™“Òîö•'2d•ú=Çø cð]¿&â†Øxöl¢tû›VÁú#?ːEµ…nº{ afÿÜI†é žØY¬¡³ÁâÙÛ€·GIž±hÖVùû˜Ÿ{ ·å‹Z> A”)K:ù1 €ÖUFKqöëß#£5…B0•‚ "ܯ»û£¢ŒQ»qE”ž<'wá5z/l{ÊÆØ¶{=)ŽÛ‘˜iW},Þ¿sE—~1ˆ9Ÿ÷ Š Üôý…·©¡ìÿÎÕ'ÕcŸôêLÿj6š ë8*yN„LF'JãÕ̉ê>{øýÛ̉§I¿|/Óü“pÚù&ú ›O͍þ×yš'<“»„‡²ïš69­®œœ'Ey)̢̀Љn¿œ×ãÈ®KšR³”\g˜OÔ¿pòÆôúCn=ðç¿ãåð$šÈÓGŒ„UteÁ†qšßŒ ºÖûQ í¥Û'ãÛúå#U=)Ä%¢!ÏÚÀñå1Ú¿Žö±#á6kéPT­UZŽG¶“€>÷bµäCÞN:ôY«ïê`ÀžRŒÇVԞ“žÓñõ „g¿ç”/™­1Ùȶ0&À˜`LÀÐâ%டځ?gÿƒIóúlO²è€Qú}JÃ?|ÊwøAxbÔeï5J"BBŠÒÕÂiùŒÒ ÷׊ šÓ€’L0BûÊý{l–ôŸÅVÈËÓæ›11†sR[ Ù¬U°:}ßHŠ)*{7ý‡9ã×`îŠáhÞ±f€!H‘w,j»+gîaD·ß€HY¹{jÄ9!¯­ #ω4Z¿×ŸÆ8±Þg¬?ü3Š•Î/û FÓrÀ ¢ÐŸ×Ê$0Q‹š9Q›Á"™ÈMbH!Ût­+Ã3ï‹=Üþ^ ñR»»TzåÔeoÚBaÌ̲Ù;û˜Ðg¡R•¿-‰ß׌‰ÏJ¿·.?Æ sdæÏŸ#Ú \ÕbÂs‚ KáîgrKêÏP= Á€$7 ZV•ÙCK/æoS7ȹPY-’âTsª_| ÜÆá̳¿a›N³ýƒR†túE®\±kŠñ,+™Jæ¢oڌœNÓʒñ±Éû¡íĶ…±ñøìˆöޝÛÒ¹Ûáìà&ÏuKцŒ|…ŠåŽ—Ús¢–µ1Ô;¹ç6òŠ«„ž=õŸ-ÖæË60&À˜`L !T 8ß wì;·B®k¢0/c*$lZW-ÓõÿöÏ(+®òÉÕ m«•7Õ$àÈC€]Ú÷l BÜȏȃt]$–PãáSBâj7©ˆE›&FtI¶ªµJ¡V#mu‹ ™27ýŸüý؞˘6t&ˆusÝÅú¹˜Šv»ëNâ××ǹE…5R˜eÔœéÖüµOŠU¥Ä”ÅQ͜.¶“ŸŠ"ÔÑÙÑMŸ”BBjÚüþҋŸò»QÛלžŒ:r#s¥PxæÿF¯Â)‘ðƒÂJnœ€"%¿$méÓâ'<ŸûZ ²Ó‡nH/—Rh}ãŠ]Såþ{«ÅÚž¿î”Bwá¿ã"ÖRØã_?o‘M*Õ(Õû5û“5*=D®‘<ýxe$!zxçEü4b…¬³ëâ|)ºÏފ KIoß5qíø‹kS)™Å~„‹Å–¥ÊŠ„ƒ„7­±£¬Š§ÅÚ=2› Px«vâj€æœÄ‡µ1Ô¥¬¬onšaƌÆ`ÛÀ˜`L€ 0£$ ZÀyŒÃê­⓫§ð56ºÉ€˜,֒ø¢‡Ø3ŒÖ QØ 5$Ï …G*áv2Gkš&ýÒ]û7ín]~"B-eš[…oŠG̱›ÿI·P„ÝÑú€Ø ݄×ÈÛG$B)!ÎŒœ|Ñ ø aS#‘XD³.®Ã·ã嚬‹¯×J/%ãèÕdz„w(Š1ŽÛцÖÚÍÞ 4øYœ-ªFÛLñHuîÓS~ÿA$ÿðǺúÏ}È-²cNš×W&A!OßëÆÊ}掋š9Í·Z„ žÁö³¿Ê°FZ{öüÑ[d͞$fó‰d/ñ-ÊÚFŸ«öLÿª9%8Y&Ö>Ú 1FëýH‘çŽEőhÔºšð΍–kϋ6tþˈ융‰ÐÑð ¿Éë5}èr¹NÂ$]ÅzÈ­ÿ—[<(¢oæ_ƒ"„§nª †’ßüùÓŠˆµyŠ×–Œo4æñû˄î3NЬ¯£ä4t EõDŸaŒÚÞ¶w¯±qù™p†Ê|ái¬ÓŽR5ç$ŸŒ ]ßS„o]x¯ZmhSx|&À˜`L€ -xž·˜ûÇtä+œµÃœHÆ6+ÊFI{‡Q6Fj”™Äг“›\ßTPxFv  %쒲i'c+}[ÎÄ}áÐ^S[ýv³ç*Ö:Ÿµ"7ËõPڐ ïÏØU‡ 2ô‘„g҃EX`)¹!uL%j;%̐ê—¡‚ä1ªX­„ TÖåQßkMáyäýñòü,yP(%%eÉ&’™Pêú‘b+Ê9zfw|÷CÓHIMâš­¹£µwJ¡.® ųEÙ=׋ ¢ÑJ¯?iÀ")ˆß^,6Nÿ€Nµ&Ê0NÚ0¶Bkû4ÿ ”ÅS»ø£HíH:þú™#‹„7ŽŽ-“àHB#%H¡€$äÍ$¯‰àfå†ÃG$æ °QòöÅVH¬µ¯1^ž»ñ³zË,šJ¡ëŽ®?JÖB}i—žÎ‰.ÎAR÷±ò§S˜3ëWdÏnÿVd¶li-yÍfù[6ÿgÿ ±&°@„qÍIIØQ²|A±Ÿ&cgb í‹F^I Ùí;²MŒÝ‘ˆ›9j%N=Z‰Pámí$Ī£ðnÎY1 -:ÖŠÕ õ$/žûG/ä{úі $l—ý²Cn±ZpÐÎ*ùA< ˜;a èË-2TÒÆìäñ͐)-~á¬ÏŸ•׉’D…¶,  Üc+ŽF‘2l^=w_V#1JÉfHL“@€­)(©ÉŸkFJžpÝ$ IDATØ×9I,CŽß·òš5jƒZµb?o†°ÇdL€ 0&À˜€1P-à\|^`ðA˜8÷ûm4m “jÃBáÛŽâˆôЌ˜ÚUzO(̒Ö]9s_†>¡? AEÂ-cfMŠÉž %ÚÐv–ž2+&­ýjÓ­nŒRèÇ5FÔã&úÈî%Ü/±]eÖtz÷-:Ւa¢j ­#€ð‚„X{*²už9r4]SЧ’ÒPH&=xp× m‘9kÒKb›öå‹Ï9Q{΍©ÞõCïak•œzõ2&³Ø&À˜`L€  Õîö“óXð×<â•\ ÝôSØÛºÅ"Ö]vΞl'!6VlÓðîõ‡hm qÛwT[áaìWW1ëœ$žc5tzŠ»WÞ`ÚŽi²€‡eL€ 0&À˜€qP-àžØŠÿ®Šv4ãžbÜ֑‡hÏÆ3ÒkåûÙÙseFi‘„€zœ²±†VÆÝsʬAY/iýš³£+ Žp.‘(…«Õ-#×Û%U!%V!¯à'7/J[žD^y^ËV.ãÆåŠ}KaŠUk—–¡®Jò“øØ,²e^Üvr?¿46ÖÈ/ºPæËÊ5K~åéŒOßɱ®™OV¬ûë/^œ§ÇsbL€ 0&À˜@¢ špk7/ś÷ЮGýDÊ0S!@ÞÙ=ÿ“ÛSÐÞm\ôK £u>ü>y3.\ˆ4i"‡ñêwdî 0&À˜`ŠA@µ€ûsɄںŠõ<ÕLcfl%`&G mª¬ø{Îq >… ³`6¹È3&À˜`z' ZÀý4w"ò–¶– ž0&ÀôAÀÊ"-ö¯|€  f͚ú‚ûdL€ 0&À˜€IP-àÆNŠÍ  ˜È0ȅ 0& f0ÇÕݟ;wnŽk×NCpŸL€ 0&À˜0iª܀¡œÐiH ä >ž0&ÀôEàùY3PÐþýûëkî— 0&À˜`&K@•€£=Ÿz÷ë‚á³Ú$›=àLöŒ±áL ™p}v7bÒ€IÉ|Š<=&À˜`L€ ğ€*çåå…a£ûcÜoâ?·`L€ ă@šs>ìÜ|¿ýö[ûÀñFÞz9 Ü)`‘lûóR[¥Ã¬Y³˜ `L€ 0&À˜€UnãÆð|ƒZm 3<&À˜€Þ Ü<äÛÔYУGœÅ0&À˜`LÀ”šp›7o†«ï+ÔiWÄ”æÆ¶2&`¢®tE›lèÞœ»‰Î€ÍfL€ 0&À˜€~šp[¶l‹Ï Ôm_T?Vp¯L€ 0-×|DFÛèÖ­saL€ 0&À˜Ð" JÀmݺÎ^ÏP¯C1†Ç˜Ð;«û? KúÜèÚµ«ÞÇâ˜`L€ 0&`JT žíÛ·ÃÑýêw*aJsc[™0QWö9#[ÆŒøî»ïLtl6`L€ 0&ÀôC@•€Û±cÞº>DÃÎ,àôsžW&ÀŽ \ÞûÙ3åcǗ`L€ 0&À¢P%àvíڅ×ÎwÑè»R  0& w—ö8"g–‚èÒ¥‹ÞÇâ˜`L€ 0&`JT žÝ»w㥓wegJ'—meŠJàânäÎV;w6Õ)°ÝL€ 0&À˜Ð UnϞ=xæx M»–Ñ‹Ü)`L@›À…]ï7GQtêԉÁ0&À˜`L€ hP%à8€'on°Ž/&À’„Àùo‘/g1pIB›aL€ 0&ÀL‰€*·ÿ~À˜`L€ 0S" JÀ;v ×îF›Ÿ,àLéä²­LÀT œØôe‹ƒÖ­[›êØn&À˜`L€ 腀*wüøq\±;‰¶ý*ëÅî” 0& MàøÆÇ(_²ZµjÅ`˜`L€ 0&ÀŽšp'OžÄśÇЮ†Ç˜Ð;c¡BÉoYÀé4À˜`L€ ˜UîÔ©Sžtû˜¡dœ©`¶— ˜"£ÿ>B¥Ò5ѲeKS4ŸmfL€ 0&À˜€Þšp§OŸÆ¹k‡Ñ~@UœÂ3&ÀG6<@•²uТE †Â˜`L€ 0& E@•€ûï¿ÿpæÊAtø ÃcL€ èÀ¡u÷Pœb4kÖLïcñL€ 0&À˜0%ªܙ3gpúÒ~tTÍ”æÆ¶2&`¢®œ‹•²€3ÑóÇf3&À˜`ú# JÀ={'/ìC§Á,àôw*žg&ÀÖØ¡f•ÆhÚŽ)CaL€ 0&À˜Ð" JÀ;wÇÏíAç!Õ`L@יּƒZU›¢I“&z‹`L€ ÄE ,, j^ÔOhhšìNyWÓ.º:Ô}®ŒkÿÝg1ÕÕÅçQÇSx)}kÛõ˜všõb:ŠŠ……BBBâ:u033ÓIè:Ñî›~&»•Ïè=êqícÔ_Bëªiknnab‹!ßÉŸÞ¹$ž€*wáÂùo'º ­‘ø¹&À˜@ö¯Ÿ:՚£qãÆÌŠ 0#&@"ÅËË žžž@```ÄËßßô¢Ïü?»âÚÕk(_®Tž 7¯$Pè?)Š@ ÿL|¬ùI ÿYù]Ž€ÿÂÂB*^š¶_Ď"œ"DGD;M/ãÖÖVÒFÍç4€ø?a˜ü]þJ7ä[ÍÂo@-è7úŸ¹æÝ\V S² âwqãLïòžV[ÙGxšÝà‡·Ñ|®ika¡¹ñ–7éԓCsó+Ç ×#cË1©/‰L3føM²ü<ŒAÄͳ2'åsiƒŠSÍT”Ÿi\ÍÅ'ûš#Ž+vhÌ ·• Ñú*‹±”vÉRŽ¡ªÈÇš¥†¥ŠŽœ»VçJ+Ù^ök&Îøù”¬"÷­4U®m~šeyŠÃyËß#~ŽÜw8"Í5Þ9¯}>h¬ÐPÍqꆮÏ/uCÇÑzad˜œ‹d-^$L¥š/‰| ¡ð¥ß;Åx’ƒøªÓøtÌB\ÁÔÿhŽ‘Ê<Åï²=}—"?š."þ ÿŠÒ„äƒ êOþ/Œ­üŸ„яš¢±ÅÊÊ~~ÒFÙoø¹RŸÊw‡&H?Ëãáß åš×ÔÕ€a!×Vŏtý†_Gò3ÜâˆJå ÁÌ2-`a3‹4H•&#ÒŠÏŠô™r#]ºtHŸ>=2dÈ ß---¿\ƒFö“*wñâE>µ]†}kdæ³9L€ $G{ÿŸ‰úß¶B£F’ãôxNLÀ$ ЍÛû÷ïåËÝÝ®®®ðññ‘7Ût£ãçç§kBÑ (Ýž§NZÜŒY!uª0<ÛU*•K3wyŠÈ†šÂ!\GE åÆ<üNVŽŽ"'DÜÊ*ÊM[žÐ‹ìùÐ(å&ZûÆQÚ®o…R1ü2â†YVÕò†i~×LE#õŸün•ʁÁáŸE>Мø/}EŸŽÅ!»ˆ{ÄXZB#’ _}ýžtsBB@«hÉ€ÈÆhÍ9Rýð±Hh~ÕW4EõŠEîKs‰ÝWFÅòAš4VðóŒO“˜ëÆ&–¢zü”ùi Țͣk£]ÇÚ:•x@I\+Ç# [­FÚÂRùØBŠÞ/èó/‚ý+«ä‘œˆš:ÚmŸö*†×‘)ŸÔWêÑ÷#(HˆÂpš¹Ž•o‘FJ¡JŸ‡‹=í:âiB°Œ†Ix’-ÊÍX‘=ÎÊW\#8o?xƒò¥òj}Ÿd xzûÁÇ7Ÿþ@@ˆøÎ!BÂR!CÆ,ș§òå/‚R¥J!Ož<°±±ÑÍõ•È^T žK—.áÀ‰­è:Œf"‡ÓoóÎŸðÞÁn¿úgdˑIþ« Ÿh?É ÿ]s’5ÿrЏô‘òäBó… ¿ÊÏG\ÄÚOjD=úQs‘iÿ‰Pþ>}ùL>Á /šgKš'‘Ÿ»”'ÚO4ciùä“-åËøÕ»ð¶á}ÒӘ0q¡+c~ybþ% o¯< ‰°ž:Êo¬b‹ò.>Ÿõ-ÿ‡ÿþÅM¯4ü29.=a€§TZOK"úWŸôòÉá—ؕ§2 C?ÿTâéNÜ®xêCû‰lÔ«0º?çI¶ü¯øg_k­'tJÍèÿ¥ÚwlÈ¢þ Žé\)Oâ>ó•ÈÅKüÛ*ž>E<ñ7K²žò$Mü¬yòŠŽï‘)KfT¬YÅ; óP,à*n‚"ÿ!×ï7T}ï»WÞ@ã:mÑ Aõž&`:'@‚ìùóç°zN/."œ­•k©èqq³ÿÀdÿ®dÎ$žX‹§ÖÅ+CƌȘ1³ø{ ž^›…¿ÌE›PñÞýªøG]#nž0&ÀŒ‘€¿>y}ÆûptöÀ;¡/^9~·Û©„¶È‰òåË£F–Èš=ÁÌW%à®\¹‚}G7¡ëˆZ34Ёß;yâÒ©Gxpç-‚͐Ú6›ži B¡ÂAâHf„„Š`‡ðGtÚO?ŸŽK&UA¢BÄS‹ŠŠv£zJ…r3®ý,Oʶpu÷$ž.„XDã–••û|> –_nþ•§ á¿êƒ8h\ÙòÙ9“ÅMœÆœ(Æ ÓØ.ïðeð§päy—BSó$Oiñ$â3M3Á"4܅¯y2"+|ÑògÍ+HÌ7,Ló”PcŸŠnÄèá}k‡)ÐôI Èöà`•ʘpÐý„ H²ŸD"=éUâÞ5è#‹`ÍGRJ”Ê*•ž6‚4—–ÆŽ8Zµ³ýÓܕ~¢]Oœèé(qR.ÐÅþ‰<Ïʳ\ßáá>D4œ“ŠI8ÛpÖtƒ,σf~šÐM˜&”†BdÈVê‡ÂNÌKúŒêÑÏ2Þ\Œ|}Œáíñ ~ŸŸ käÎ_…J•E‘YQŠ€«b¹QœïZyMë¶GýúõÊ.6† €ïÞœÃÇáüÞ¶p†uØ|OšéVŒY)ƒ ²eN‡,™lS ž'`)œ€óGO<{å »GxíàŽ,¹Š£n㎚[·^’¯íS-àœÜŠ.C ¿Î×OžÇ}­ðô‘+îÞxŠ·/¯X 7€Y²çLá—VòœŸ"5OãÊòEü„K¡(âHó©ümïi4®7X!ž#:Œ?Š÷5Š(T,PÖJh<”$ÄHŸi¯mg±ÅZ$â4»¹8ãÕ£p|óJˆgKT®^šgƒmzã PжsÅU4¯ß õêÕKÄl¹)`ñ%@ÂíÖ­[r=[ª0x:ÝDÞì6ȑ-=òåʄ FöoE|çÇõ™`º (€oÝ·Ç¥;ŽxýÁ šµEûöí“lݜ*wíÚ5ì>ŒÝFÔÖŜÜG@€%ìîåÄœk—€çÁ÷³7*~[©Ó×Íg‚'È ™@pŽ…Çwn }ºÏhÒª(Š•ÎŸ„£Ç>ԎeWвQñT«®ÑØÄ†0äL€Ö¯Ñ–AŽŽŽH%þŸŠ·üˆ¢Ù}Q¬`™€€ `L€ DOÀí“öž±Ç§ÞhÓ®Z¶l©wTª܍7°}ßôm؛©·ïl±gãe”©ZÏÜEµœb\ïWì Œ}ñîïþCŠP¢l£˜ï¶e—Ñ®iwÔªe|aÛFˆ`:$ðèÑ#8p@f]+U,*äý„Œit”B‡vrWL€ 0c&àé凍G^ÃÙ3FŒÜ¹sëÍ\“pK·CµFmqùÄaÔlÚ*ÉãMõvžc&``YÒÛãôþœš^¯,ÊU)f`k€­K.¢}óž,à ~&؀äN`çΝxüø1š6mвùÍ`ô0b urŸ;Ϗ 0& ÏìݱlÛ=4kÝ­[·ÑÇP%ànÞŒ‰­{V£çÃyàΟ|‚TÆû·o3o~dΞC/@žS& ؈§íÙ2=Ä¡íçÑ¢S-‘67«A1lY|ZôbgгÀƒ'wsçÎEŽ9й}sd¶C˜¿srŸ2Ϗ 0&d–mºØÂÈqÓu>Š*wûömlܹ œÇ&¡@ ØûbëÚûÈ]Ž^=G¹jÆœÎÏwÈ’€@¹Ò8üŒD,w§>†ÝmË¢óèØê{Ô¬Éßõ$8õ ;û^ù`âŒ?a–*œÎ†2 ÷ú™#îÞMw7o.UFdÌËš3Ü`Ù³y!O.Wü>uÆÏî%ˆ}› T6ýußµí‡5 ŸùÖ@xX& žžž?~<~šñ#ò¥y…0ß·z‡;eL€ 0 £gïãüõW˜»h,SYë‹*ggg‡u[—¡ÏxÃlª{㲃ˆÑ·BHk\áÛ::™8w˜@dÖVÁ(WÆKçnCsFYŽd>ƒ!ú÷Ï3èÑq ªU«f0x`&Üxxx`öì٘<º7²š‰µn!~ÉmŠ<&À˜€QžzçN\÷ÀŒ9Käȉ-ªÜÝ»w±vóRô™`wxß{Œ~á)÷z˖;obçÌ홈@ÕJö8žíŒðr§Aƒ–ߌӆÿ¡g§A,à vxàäFÀÕÕ˗/Ç÷][ ¿õÝä6=ž`LÀè ¿ð \²‹(ˆ ‰¶U•€»wïVoZŒŸ&zÀ„t°}³»Ø¯Ê­{þæÜ† 0•HÀíßrilS£i[Å/®ÿã4zw‚oŸ1œˆT‰Œ«1£'@a“6l@…òeQ§ˆ‹ðŒùœÍl `L 9XŒý ¯Ž:$jzªÜýû÷±nóôW?Qƒ%€ñ'¬^x>>žhÓ«Bºà6L€ š$P¢˜3¶®ÚŒ mѵ3•­t_mËâsèÞaªT©¢ûιG&Âüý÷ß2dç‡ö%æý8…Íž§Ë˜0Žý±ûb êÖ«Ê•+'Ø0UîáÇX¹îOô›”ô™é^¿ÉŠÍ+÷É?>M:uOðDÕ44 AêOï‘Êס––HŸAi3©iÊu˜@² @nï†Ýb.aø~xkƒÍiÍï'пǚDýãf0ãy`“#àãã[[[“³[Á'Ož„££#šÕ¯€ž¥Š ×aL€ 0=žú" ®ÜuÆÀ‘>}Â2Sªp+Ö.À“ëq:ÑwýÖ!3ﺁ@?ÔjŠ¿ʌ¯ï ۓ‹°ŒŒšûs–üp©Ðé²%ùÜy@&ÔHÀÝ»vï^9£ÛÀæI=Œ/,, ëæŸÄ,à Â?%JëÃöïߏҥK£T©RȘ1yd:~òä =z„Ž6©Ñ€Œ‡ôM‰§—ç̘0*!Hƒe{]PžHŽmÛ6A¶©pô`Ùê?ÐÿÇ€pNÎqhçx{z ^«ÄŋÆD(çÝãÈhý¢î033„YXâ]ÎðËbž¬| :»Üˆ ē žípïúsôÙ&ž­uS=44ëœÂÝÙ§¢ÜK\èšûøñ#ÞŒy{{{€K—ŊCÑ¢EãjjÔÇ×®]‹ŽiÓ¢q•tÈdédÔ¶²qL€ 0”DàÆÛl°{ìŒ&Mš páÂñžº*÷øñc,ýçw!àšÄ{€Ä6 wlÿ#ž:9¢aû.‰íî«öäyËyïäWŸ‡™™ãMÂó–ù®î‚µ·^6€P«4:·!1Ÿ|tYsæF†ÌYӍAÛ:¿{ºÊ] AíàÁÜ¹<àît NÞÆÐɺÿŸ©aŠžB¿n,àÔðâ:‰'ˆC‡Á××WŸšžžžˆµ×>([¶,*Uª$ŜµµnöïIŒÅq÷pûöm)H3€ Bý’^q7àL€ 0&d¬scÉögț7/:wîïqU ž§OŸâ¯ó0pjÓxØÞ>©±kókž8œC£öß%¶»ÈíÃBPôø*X|‘+ØÚ/š“õ³>Ÿ€¬Ï®ÀµD-ž–¬¥[Ñ[€+Ó©„ø)\ºªÖiˆÊuê#cÓ ÷ümì`Œzü9òæG•: Ä«!ò6í'߉8­mJÎóÃmœ=v Çw„¥eâ÷*‰ï„‚‚‚±yñôí:’×ÀÅ×× ???PæFòÊÑ6:/^Œ¿,X*T@žâÆÙSðóý,Da>{{¡ÇˆññêC»òƒ›Waÿä²äÈ _os"‘öÙËSÚ[¯uŽë3H¬·zŽõóçÀáõ‹ˆæE˔—sšX£Žœ“©•ŸtÇwCF£lUÃ¥âO3pÞ®wqæÈMôÓ©¬,ÒM¢ÚcËÒ³èóÝp‰"ɍuIÀÉÉ ·n݃!C5@"Ž^%J”0*1G¢“ìõwµC»:Šõ@O—çŒûbL€ 3ñX;OŒBŸ|ùТE‹x™ªJÀ=þ.›#`L€ DGÀÜ o§ƒƒ£úõë՜T 8 ùcÉl š–ôŽf²n•\ß¿Y([Á*5ÝT늀ý T¯Xߊ¶ÚfÆ+±.>eûÊEøoßÙ$µ81?Lš‰òÕkIwSˆº«KïTÍŠ­ÐgÜTYÏñõK\8º²dÅëÇq÷êEVØ¡ßá}K‡46i£õJ-˜4BÜp[ nËvžxü ØüüŠŒoÒ±»ðt ŒÑ“uöànl]ö'llÓ¡…ðrŠMŸûÖ¯¢Æ;vC—A#ã3刺Ƕo”‚ˆ„ Rò,Žû} r /\j1ëÔ_¯'<ži Níنa3‰Ê[çÏ 0À„Xý~̏°Í°ìp~â‹DîS»[xýô‘Éu¡§Ñâ`Æ",B[¢CßÁšÞHýõ?㇮HŸ)3&.X‘ v†j”1ƒ/̃nãèžË>EÇ!Ë*'àˆí+΋5p£ež&`¬hez|ûö­ü·688X&@¡ë6!‹Òu1O²éâŋðpžŠŸm‹ë¢Kîƒ 0&ÀôDà©[nœ¹fºuëÊ5×j‹*÷òåK,\>× ÛÐDÖ¬p!wr}yFtUhˀ¢Ç–Á,,úùšãxæ-÷UÔoeðVxw~Õ_ …ÊÂöƺ¢ˆX«Š]>}tÁŒÑáéîŠîÃÇ¡~›N‘Ž+âŠÄ‰ŒØẾ=„ôÁü­dµ·/žŠPŽxýä!JUþƒŠÎ–"M»˜¡5h6«Gb#Wþ‚òðýëW°ô§ Rtþµû„3áj&ðÇ ”•H0ïß=±ö°yÉ|œžÄÿý³EzIDîúg©ôÊQÈ谟Cž‚ñËÖó쟖L/… 3q£•·PQd˕[®Œzú˜ÑӖ®EŸ"Å=WƒÎEP`~‘{ª™NI—N0ò¿Š“®aÄÔ®1ÜÏ7;ÿŸˆ>]FÈä\˜€) ¥ôrss“9z’Z§Ni¢“²\Ÿ|Y®×³þ|õ«æHÊ¡y,&À˜ˆ'€P[¬>üQ®‹Ï–ªÜüÅÿ8Ãì µnÕ[ž¹ž¡FÊÒs£«bèBgÖ!•¿·ª.ßÔî®z+ œ?~((K$­…Š- Œ…“G!•8 ¶뎟d:£µpä ûñ¯¿Qšd™Xí$Ñ ßÿºioD=²ƒ<€;ÿ^"ÅÙ䅫"1\2c<ÞŒ†ñ"”±XÙ/ގñ$yl—¢?_Ñß>dʚžuÃZ×CɊUåڜ؊"àæ¬Ýl¹¿„"=aŽ+gO“a§þXŽ|…‹©:gTéÁ+X2c‚€mz÷GÙoŸ…­ð2*嗑ýåú»å‡Î©î3®ŠQÅŽRÿŃ»2aKåº ‘5G®žºIòã$àB|.ãü‰Û2)þY‘(‰ƒœ‹ô^’è7·Ð„ÓÏôÀÜ\Ÿ)?›ËÊáõÅÏþ~8žùºµáS‹µßeŸ±Œ¢¶Ir˜<`Š$@a•ŽìÀÎÎNn M{ÊuêÔ ¹sçNÛ·oGj©R&Ë+Îù]’Àƒ0&À˜@Œì»fG <VVVªÚªp¯^œÂoÍÄàéñ[`§Ê•¶o|+n ]E[s€¡mº(æÂû–ÿÊN€öpVÕݧBUð¡|#Uu©…/þ5e4JW©†ÑsÆÙnÊ÷AÞž;ŽDZkE JÎì߅?ws %ΠPAŧ=è¹Ã{±eÉ2sÐŽÙòyçŽè'œƒƒ§ÍùÊÆœkWŠM/âÇEÿDîç€Â+P2”qB 6k» k³Í‹…îÈœveòþ5e ҋ5yS—¬ÞX[µ&àƒHþ’=OŸhœk$àh+ƒÅûŸ¬SŒ©câ{lÇF‘ìå€ðšº‹0ÉL(^Ÿ² [Õö®j 8òî]=u —OÆ»—Ïe×­zôkFæÖ…38²u=>8Ÿâ.·_íŠÚÍ¿ìÅFIaò-!çOLÿž;®œdXn‘RêÝî±A#èq7/?A¿Qñß\’Ö¯=žýï^; ± 3„ˆw‡&¥BƒCÅÊBZ]&ÃÎhÍ¡Twšˆ[^âÛ* åÂ^*ô ‚Ržˆµ‹$Úèw¥P&@ ]ÓþŒŽ¥I“”M’MÐ8ʋÚ[еŽôyTšˆ>j8ŽkViœèŽ‘}Ž>*ê1ê+:ª|®Ø"ÖËÆ$HÉÞžŽGö”ñãœÑÍ;&û£›gls©~t¶i©úKn„)‹åõë×qìØ1¹FŽ2Ñ5>œúõŽñ™m°gÏù=é]/Ø Ydãc/×eL€ 0àæó`\ŒvíÚEÜ÷ÄÅE•€£MY0Cfތ«?œߺþ5ߺ£Fã:pf"YE ›‘Úóƒ*{݋T…K™ú{§ª>UR‘š }€D'bHICæo=iŒ¥?MÄ+ù§vq•iýºÈPÓÅ{¿Þ׎ÚR(âÉÝ[ÑsäDÔmÕG· ïÞºUŒM}”ÞÃ!3~Á_SÇàéÝÛ²NV :{Ív$±Ž E°÷q<Œý}F$|#ïÇ÷^ 6Bš‰ðdºq§œÝHøî²^ž`y,LŠ<úä͑>óû ®GhT» *ގچÉLþ"iŠ­Ò§æskš14ÇèEžº©¥ŸIi‹Œš‚‹X*"#ªÓŠˆS.íðb²ƒÆÑîK9®ýNvHñª%©_²S»­2ÕÕ®QûTúÒŸ€µëÐq¥ïšuȈ$‚©( •wúLi«ý®'»IžÆÔ–ž&*çL»ïèêG“ÂéŒj‹?…EtÇv$Þ±µmÔs£WøÇ$rµÛќˆ—vݘ (unÞŒ‰û÷ï˧«b9oÞ×<”Ð<ˆé3ê[û:y/qQæJqeʔAïÞœu.à®\¹"Ã6‹äK 9Þ&ôŸnǘ`IL`ÑÖ'â>°ZµŠ=ßEÄß6ñÇçK,R ÆŸyós~ŸŠ¡3Õuªë9Þû v7œ¥÷"êôøŒek¯Èmw VÞnMIŒœ­Ù!Öº Ï€Ž)ƒâz!FhŸ³–ÝûÄhПÈÒHIL\DØÜdZçeï¶±›ËÇÞ£'Ç9UE4L_Ÿ>Æ5b³†~/³\’È»xì hÍY{‘a±E·ïãì?¡þÛ·ÛWþ…ß6ï‹s“qe \lëi»ƒ3v AžHBuO*b³}jŸNÒCÕûµÍžïZÊ=ì¢óXÒ׈’ŸPè,­\øã(8Ù¿’]кÍyÿîþ* {vï({(mA[IŠí ŽïÜ,×O6éܝ —ö’Ä ‰È\ù ѶBn°J¬ Œke|Ν¯Ën|xïŽ.}›Ä§™Îêz{~kணg»azp:34™uÕ{UF­Ú¿k‹JívÑõ¡-:•°O‡Ñ ç˜úR>§S@B*jŸôw‚etí/nÔñÈ#«xkµ$yúož"©%47&‘Ju©‰6JnB¿çʕK&7¡ššóâŋuz:tî"Ž»aõ‚ÈmýL§}sgL€ 0& ?[ޅ—ei :TÕ ª8ŒEžöúñÀéÒVî+yˆIÆ$b•ÏIL:88€Bi3íׯ_KÑV¬X1d˖Mn1 xÿ(Œ’’›è²lÚŽ >"ñ*Áòó}]vÍ}1&À˜€ œ¹òמ™cÒŽ_dÔJ\E•€£=nfý:E„rÈ·ë1>ø,7òNhIÿî!rß>©¹¿ðŒœ«Õ !V_ïG–ÐqŽÛѺ/ZÿEÉ3zšˆªÈÃÞŸDB‹#8$¥¶¯"2˜üóWûŽQX…×U­×HÖñOVIԑ‹.,S UlÔá;¹ù5mðýþœØDü4.Ÿ8,œGŽ'Ûš9¢`‰RÒÊÐHÉ0…À£mêµê‘ý‘ÖæùùŠtØbëí0€ø°¡ ³3PlšýCŠÏ•ýy‹­ÌDèSµú¿¶$Tfê!÷Š›Ÿlœ m$¡ûàÆU™Ü„’‘Ð^w=FN!µº(?ê‰÷oí±hωX³œÎÞOf«œ¶„¶ø’“öô;ŒeH@²Õj÷¯B˜QÆÌÿý³UxXÀÇÓ~*¶‰è(×:ZXXÊp×{µGåÚõE‚ ¹’…Óú F…'–Ö»)×SöÊù"t” í¥WB$NQʌþ݄Í.Ğnžæ;>ÝK‹Žê¢Ù(>©‹‡»·`yœ:Œ@Ŋ“zx ċyÒHšÑëÚµkòßJZçVœzuÔ®][†Ÿ&E!;V®\)Ã2»4ʅ0ï§I1,Á˜`: pﱎ\rq¿"³XêW1 wlß}Ü¿(`Äÿi¥yP€n‡`åé +?Ïúo4ÐÇ÷ŽXþ¿#Bé2Š¹iƒheiÚ6€6É&Ñ€]v¯^†‡·®ÉvÑEžÒØs×ïD:‘ÐU¬¢Hò°Ñ:­ÓbËòÊÐÏî"‰†ÒžÚÔ¡7!yQœV”’BÉH7y I|eVLê‡öc£}ÙâS^ŠTùÇÅFÞŽE‰Îè ÙB^#J òæÙéÝ¢ñí®\À»›Rl+² £ œI E 5mQëþop/)žh8ÊòSQ5CòVfʚ]0þ Â&oHÛIT“;µw;ö¬Y.¶Mš"EyâÈ;GBæPWœoZ'Gkä(쵚ðÒŵá7q\0qxŽC×üö?Ø]>/¶ 8¬“îíïoCZ›`ŽèûÚÍÄ0­í'7oÛ~SzàXÀé‹2÷›X>|À£GððáCÆIá—5kÖDñâÅ¥×-©‹««+víÚ%7‚­UÌa~šäJ\˜`LÀø 8:¿Ÿ¢× rOžžŠ*G!!³›*Öþfžƒ;n‹Ëy\Ò~x‰|W#oŠì/’’Œ£5ozòŒiC'au|ÇfܺxF :òŒP òÆÕ™ IiºÉ§P=òÂ(…êPýÜ Êœàò.*û¡°QíÉPÈš…<7$ÄÈÓFmH\ Š­!Ïàû7öR8¥û,^J&æ(^.~žcBŒí]·2b8ò:•¯^Kη€è“ÖzQ:|*‹ŠÅ£[׿2Äek$o ¶2ßÔ@áÍÔuù}Ü)²Š,Zᙌi Z7HY2Iô‹t÷$¢KTš,ŒÃ]"’ˆÐžuKD’I V AX\vEýS†MmkÖÅПæIAGÎÕÙ ý'ÏDµMc H‹6×.$ài< ՍÏÖ 1 öüö&dÊlŽæj굪þÜ?zâø®Ûb  8UÀžR’xúô)Ο?LŽ®­|ùò(ZŽš “4d¡H™œ{÷¢^œz(ŸÓð×d²å˜`ÆOÀS$p[²ù:÷™ˆÒ¥KÇi°j7sî$ ÿ_ë8;ÔG…û¯âå‹tšÙ4þ!œÞÜE.»ãfù§â­V҈·„² ϗ—‡»/ŸÂ{•%{ÎCi[ Ó$a“UÔ'qH{ˆÑÆÛ”ÎÞP…BIäÀ±²N-ÈbÆyùÄda€Ùóä•iôi}ÍE{Ss}Íå‰Ý-éílØŸKŒ† Ә“×P T:%¡}çÒY¹¡9­c£rWxW̚"û¡ulõZwž=òèQØ$­i|*TkÐEfR”g·6"k6K4m§Ÿ5‘qÍÁMžS»ï {Ûa쁋 O2gΜÁÿý'£*Tš 3I’pS»éªŸ ¥uw$àh]]!›GóW·Ç©Ÿíâþ™`L nÁÁbÙͲóø®ï$ù7&®¢JÀ999aú¬ñ1+áûBÅeHlÇí87ïrŠõE±{(¢ë#»ò_Ü 1Q˜‚xK 'nkšhûÚ>!@ló@EÉ4©Ì†Œjý&Έs; ]ÍþѕÍÈWÐ ZƟ僮Ƌڏ«‹‡Hzc‡îmXÀé‹1÷«Že‹áÌŸ»èÆ.©N9N€28R("íÙvýúu™Ñ‘[Û¶makkkԜììì°gÏLŸ>©ÜŽ", rÆe£6žcL€ 0ü±îšÈJÞM›Æí°R%àèÙޟÇbÄlÝdý‹ï9"÷É+/ÊV3LZóøÚËõ™€)ži+ò0Gã6Õ 2 ±ÝÙC÷Э{à rRà Žù5m‚M¥Sö/äȑC>͐!ƒI¹xñ"®^œŠ & Ôi/øe¯S“˜É˜HáVl…ë£C‡ÈÉ £Ã¢JÀQ¶­É3F‹ôó†pû6Ÿ…·^”ªÜ8…ŸZž>Ð?‡Wwˆ,z¡hÚ>nŸ>¬ùàä†s‡ï³€Ó\î3ZÎÎÎr-ÛóçÏå&ÛuëÖ5H&ÉĜž“'O‚Œp'NDš£HÜô)1Ýq[&À˜Hb«wÝEŠuÑ¥KÜ9LBÀýœ`/üs¢VóîIŒ’‡c)Àùƒ«‘9‹ú7LÈŽ³£.%7\ÕBޔw†xƺ&@ž·­[·Ê€9jëz|]ôwøðaŒ|ù£Fn—pºè–û`L€ 0$"°nï=Øæ®…®]»Æ9¢*Gá$§Äè9íâìPŠÊû÷ÜÑô»±úèžûdL@‹À‰ÿ HÑ0tý!îl}€{ïàŠ‹Ç k ¡Ô_îók^^^°ûrÒËTËþýûA džŠP‡@°—©N…ífL€ €H:p?~Äø©#0f®aÜGg,™wmûNI‘'”'Í’’À¹ƒP·AV|S§LR1–Óۏžtòºµf²Þƒ€ãAS4;w‚„hÿþýæ°aÁÞ)šOž 0&`j֋n69k¡[·nqš®Êçææ†‰3FbÄφÙŽf1wònToü=2ŠýÍž0& ?Çw¬D§%P²\!ý KώBÀ]?ó›fg3Àƒš"J^B{Ô-X°@xà¶ ÜgSœÛ̘H±ÆÍÙë,eðÛo¿ÅÉ@•€suuÅž‡aÌ/íãìP_¶¯œ7ìbCcÄuék^Ü/06ÛWÌǔ_š!sÖô1Í፠®ž~,C(Mu=’AÀñ )šÀƍannŽž={"ôÝf Ä/EóàÉ3&ÀLÀV‘À-ض2úôé§éªyàÆLбp7¯8âäáwšÝŒ5hcc.L€ èžíGwrÇbÌZÜCÞ ¢Œ³ÿ€kgž ksp†àÏcš&ÿýWìi.à6 çoša«™`)”ÀîàaV Œ“€*çîîŽÑcì¯qïKçˆ ¬àä菝›_"MZT®U?œp3&Àb#ðþÍ#žŒ>þc çm÷Ú×Ï>žá(_Ÿ<Ÿ0&ÀT GIX({YèہÐ@­ž `L€  ƒÿ=…£! 6,N“T žOŸ>aÔøBÀuŒ³C}VØŒæ!`‘[xàl¿h }Å}3Iàáå5(\<3ê4©d°ù¿yù·.>Çw͆±€3ØYàMÀ† ä^vÝ»wnƒpAŠ6¶— 0&¢ ¿ðOÝra̘1qr0)gÿÜwïY!4,#|Œ¢D…Ê"îß2Ήr&Àb&`aŠÇ×× GÎ hÔºšAQœ~î»+ÏÑ¥) 8ƒžÜ€Dpk…€ 5)ûÙX&À˜@J'péÖk\xšS§N…*G{Ë ÕãÿÏÞuFQmÑCBïœwEQô"œš €)œ÷Þ¥Wé*ˆ‚4©" HïœJ $tJBú¿÷mf³ Iv²Ùl6É}ÿ¯»ÙyõŒIxgÎ-Ó¿1Û¡-*üµê •kŽÇŸÃåüY.Uù ³ÅÐ2† €Èá ²gyœ[ÿBšŽ©ñe˪ Ÿ>!p Ÿ2Dˆ@ž»Ká dʂ€ $oN]Œ‡ç0vìX³@è&p}uFŸ&‘wT«ØŸþ4|‹q+O7WzÝAþ¢Å‘§`8‘#wB–zòIùx8'áBCCÉô3ò÷tê†PC}ªÇïTרtKX_ü#]U×ù;Ã¥ðwÃgŸ†€6Cðº‘ê‡õi:Žªa3¬Ÿ6oèÌ8Nøžáã88€@0­/ýKІ÷°Ã6ùÒXGÕ[ƒñ7ÕúˆØ§V5l ˆã7:Ò|Žkç§Í™ç”"…ƒšo ŠÌÈï¡ÑðîH߅]{çuÇ®Ÿm£=²Ú–-ë+€uòÂÕs—qýâ]äΗ _µ®ž¿6Ʊ]]îãâ WÊ'>pv±!2‰D@N\¢Ø3™€ Š\žî‰MGƒ0a³Àè&pÝû’7Í>8mUW/>đƒ¯áÿ&Îé3à•÷sÐ;€;èÓ5" ÿó!Ÿ‰€ ×®>s=n뀔)S*bg åNýÈ “~™’uÑð}Y 'K†ïÔÏê:¿hè'ŒOášZZ}C‡‘ê›ôg$F†~MÇ1ômBòLÈšBßÈ2[aÀÐõÑ€^„6&}Dü^ÛW“Dv »¯‘cCœð>LçÀßkĚÈ6REºñŠWP°z æ:a߇]3~gz>‡oŠ"ô!†÷Pzçý×ö4|OÂ+°}3ìM؞h„’§«öR}P÷º·ÃîŸgOŒ¬9œ‘&µ/‚üŸâùS€Nã„ü…s⃏ˠx™&`%œŒÕ\ IDATìÇÛ׉ÀŒM>pœPŸ|ù„ŒŒ.$˜À¥J• ­[µDˆ™PJA@HT\¹áu‡‚0qâD³óÖEà^Ÿ|‰®œ;`˜PF^Õ Ÿì5w1oþ"³«×Eàø…ﺵÁà™ÍÌv(A@ˆ ×.ÞÁËîhVS|à₣ŽM^lذ1ºã·ÄäþÚäµxY­ IÏ1}•«"pæ‚çé&p]z~‹v–. ì•,A"!pí8òƒk^«/ʕ+'ø‚€Ö¯_/^ S»ŠõX¯£…TA@°'<Œžc֟w)ˆÉ<U8Š¢›À‰gO[,s’.WÏ»‚ýà„À%Ý=–•Y7âÙ³gè܁|à<6XéQA ^žOnþ†û˜{®.÷•\¹r’NnA@›6m£GÐµ#ùÀynÒÓDê‚€ ØîO1œ»õܛ7oСsK ™Õ܎–)S€ˆ€FàšÖ€4åÊ'Å%ʚ«#°eË<|øÛ7Fš×«÷/ ‚€ Ä/n÷Ÿbá_îøaò,€I“&î œžøÝ0é]žtæîÜô 2ŽëüùóØ·o|||ààà€Œ3*2—-[6äʕ 9sæDž} oooõùùóçH™2%Ò¥K‡9r(R—;wnäϟ TäΖe×®]žví8RàþcË¡e,A@+ pëî#ü¶Ã #ÇNUÿ¶ÄTtå À·šaèìV˜žt!‚@ôœ?é‚{w’ e”+#&”r¯Ø/¯^œ‚§§'ŒŒŒÔ‹‰¿3¹cå.{öìț7¯"u… B‘"EâÍ$sϞ=žxñ"úw#÷h—ý‚&3A@ˆ›töY±ó†žböß ]Ž}àĄRî6A@°çNžÀÃí!)p=Ä΀Ëñ‚“ž;wîšÀ"übrÇd/SŠLJ±+P Š+ŠL3•ºW©R%³~ÑMö¿ÿþÃÙ³g1š'™P>Ü/kŠk§¡¡ð M`DŸ öêÃŽ(šË 9îÐp¡q2^Ûß K…+öaúðŠ”³)总ñ:é\’ü7eõžÇ2b’ž$±£²A !pžœ'Ebjüy7”+-i’ÑÖ'ù¥†††âÖ­[8yò$®\¹e’ɁSZ¶l‰:˜MÞHû÷ïWýî՜ž=v‡eHš#n|¿˜ƒÂœ¿v˕FÞ /‘-à„]“ž?·žD›Ÿ¿àøæšô^»Ã\&$‰ ë·œ°nïS ñƒžÄµu2[A@8{ì:ŒˆÀ}ýy”/[A5Ož<Áƒԋƒ¢°E ûÊñ‹ +gì3§‘ºÍ›7[ŽÞƒâèÑ£Ö§Bíµšølô4(ܢB#pY2g@Ú`O»&q«7Ç·ý—áß?¢F•Òf×&,C ÷ØÕØŒëʗʇ)ßÁ{e X֑Žì«{ÝO0dädëžö…rðÌfvqËÎ÷@Š'"ÀÎóÞc4ù¢+Þ)#ÎB¥Y ÀАœL›É›DÞ¿_™Hj„ßS¥J¥êüûï¿ÊĒfÓʊ+¢jÕª(Q¢„E3?|ø0˜Ä ïÛ¡÷YÔG|6zTžÅÌaJàžr|‘ž;÷žà’Ë}xx=Ç3ï×(”/š7¬'§”fçšUXõ×1Žø+þþ­/êV{Gw;©šÍ»Ïᛮ‹Œ x–MkÖ_¬¿©)$.»x௬ÀY‰À©DÞ]Zbð !p‰äi ‰3G¯á›Pv!ž÷í:dâI—/_*²Æ*›CòϜf@#lü™0aÓ^ݒ [š4iT”1&m|ðAœÁ:~üžJ}0¬wS„>9çþ¬ÝFàBCBár×!!!Æ!R òåΉŒé™ÀY‹Ä1a;|êŠzí?îŽö¹|ßòøiJ;ÝKÿ}Ãtüöý9U+—ÔÝ.9VÜøÏäϓ•+Õò» [ekaD¯øà‚6u#n»=ÆâImѹUÕXõeíʧ/ÞçíbâoO%88­ûü ïŸØñ[?8::X<=K÷Íâ­ÐÐ^÷EÏÒ.^»-‡Ÿaàp+8•È»kk ˜ÖD8=; uAÀbN¹ŠG^ÏðUõïɄ2î[‹'" H0ùbŠ©lŽŽŽŠ¬qN8N#ÀJLÉ›Lra"Ç/www\œzUEšdâöþûÖ{@qâÄ ìÞœ£ú“÷ä Ý흩÷굂C‚M(xKZ€$Œq˜±º¿ êwøNÜÀ¯3:àÇ_÷à³J%ðãžV–BdQ»ï†ü†ßÖÁÑMÃc­,Z4 ÎFý'ü‰yË÷’y¶#ÞÜX¢³UÔÕÌí+FýƯQ~ qQúb;I&ñ/^ùaÃâîȔÑ9Bs{Ý=kdòýÏq >Å:yà„Àé]ê‚€58E‡›ÇD³–Ò‡~8€FÔXiãŸ5sH~g…¿ççzãºNNNFÂÆ×™à™ö‰câÆùÙ>ýôST¯^]™NÆGá<ÖøÁ­úôH| §>MM(/ßt ÀqDžóåEæŒéá7Ï”Dý %ˆ˜FàÓ¯Q2ësÝóp#Õ­äç#‘?wf\Ý3Ñê¡þç-߃þÖÂíèteš·üôÇôµJ°ÿùœ>ÿ$þ <}þ Ÿ}3U)ŒŸx|Ç*+%nõæpN넛&ÛD=*üéPÜó|†%“¿UŠ}H VÄ·[Ûꈓ<•"[Hùš–/ýP¶æhš{F\Œî6œ8ðkeji«Ò~À2¬ÚtýŸ«…¢²ÃÖç€gú..ʗ¥k`r›ÿãÁʯ3gö ð:5ÛÒ®T;sûvòü|Òx2Îí‹wËäÓXzó^óŒ<z£NÕrØökŸäÑ÷EïÚØüs×)2¡œf6¥Œ®Îý™Sࢀ­~Ò€vR—K§>Ž¯c5—LïôB±‚9qvǘXµÓSyÆO;•O֓ós‘%S:=MŒu¶í¹€uŸB‰Â¹0Šo£XµM察Ÿí{/*’ŽpbcÓOŸžŒ“îšv»Ô‰M—ºêr4=N³p×ã)î’ÿáÑ3·UÔUÓâ@ŠëÇïÅ¡ u-*LòW€¢Oþ³¢ÿ[ãöó‚Ñ‹Ì^^sžŒÀºEÝuÍϒJ>D<­Üö§t#?íD^^ŸzóVW…ógÃîUP¬PNK†‰SMæN˜³:›Û}»tý>*ԏßfu·M>‰ÍPqªûðñ ڋ}8qγF7ÇÖ/ØõŸè],â=g^gM×µLýÆŠ©ÞK=A@H:h®QµïðnÙ“ÎÂd% †ûq›šCògVËòæÍk$clÞh꿖6mZdΜÙHê"«kÑ-†‰áš5k”JשS'”,i›à—.]† 0n`3"pÇ ëè6Uà.Ýžý– etí‰ÀœSª(R8XLàòåÊ냬ÇÌڌI þ&3µÅ€ŠEŒ^É*Ó¿‡®R’ö |ñiYä"¥ÈÖESGjÿ¯¬R°L]`Š.ځ‘36á»ÿÃÏSõn‰ŒV9ûŽ[ƒS€°¢XéÝÂøŠÞ‡˜õË.œœìþ֒›ÖÿÕ?.…Ȍ•‰™sÚÔQÂâñà9\\¢-åÙã¡Ç(מ%å.¥€9Lþr2€E-ò{Œn<=}šŽs–þûVU&¡_Öª€ŠŽö÷H…Êž5ƒžî¬^‡©rµÆ(_ç€ÀU(['¶ŒŒÕ8•MŒÕŸq0 R€rOðFön«±ÌUÞMs§.܁óWïQ£,”k±0ºµ©Ž*D̹hÉŸ°Š÷òõRý#š_š›S|_?N„tÿ¹—è7ÌJÎÏÏÝút@¬b7ßHÿ‚€ x8yè2ž’¯Ä—Õ;¡|!p‰w'næ?iÓ±õ fªÀ…°QŒ‰Ÿ òƒss†³TcSÁ{ÇfÊêšÌø˜l°©‡ì~HªMÉ¢¹°böwxCæglÇ%õøŽ±¯ÑÏ«Ÿå×Åþ\(œû|qáq9ô}[3 ›N[òÖl9 ö[cÒW­r) ÔQU>,®æuw^€­€ô]Ø9î­`%7É€òkºÞ³] ôh÷y”}3F£gnÂѳ·•Â؂¢-ާƒz"\8 ÈÇ€äEѳDRŸh«T,®üÃØOÍŕ"¶êT+[öú ëÿ>­ÆÉDäk`çÚ(S"/Êσâ…rŒE˜#/€Õ>ö6m#©tAêr®ì±ã÷ŸDl ŸµÞÿŽ^WÁn|ýü‘#[4®óÁ[˜ýµó,þ°ËV$‚ 2·aIwUß\1‡§¹öæ®7é²[þ=Okìþü~¹‚FßA¿7ºîíÁ“×ãoRl?þ š®}cÒX€L6{wøsǶ47Eì=r Óég¢ÂA‹JÑï~VˆÓ9‡“yƶ°áy›ö³KŠ5›ÊŠû»`ÉŸðýÅ6™àš zíëOþ•sÉÌ×{WŽ9?N¿kÇ®ù£Ç€Ià‡ˆ1]&”LàŸïÞýŠ4Îìí)A .œ8xÏèPÕšjRà¬ì!.s“¶ö‰@ä`#8„ƒŒh&Z@Maãö|ýÖŽ`#qY™‹‹ Ö®]«rºµk×ùòÙ&²Ÿéœ¯]»†ß~û SGŽ&w*.ˉ—¶ Á…k·"€ˆi@>°œWª„ pb){õÚ_ö˜x˜ùé;+&5?+«„ZTItÂ~5‘KÓn‹P™Ô–Á]ëªK,a;ù“=<3ÇX•Í¿í¿”ÖªÌy VR;QŸ¿“3‘‘È—+7<”˜æÿ¶vÛI"대‰J ùˆiäˆI܂ mtŸÁXaÈ\Ÿ7™ñåÀùÆÅzOgÿ²CŠlPfìßÇD700Z|†_жWýÍúy—ªÃáý×ÌïŠ"a~`öî²=h\÷}¬œóœªÛ¢çOذã4ùdÍ"߬šÕHSL6ì8C^V«q#&Ä% ç€þ?Àڋ à`ü³ïR„Üp=Gÿ%«ö“èõª—'¬_àԅ»ø”åÁõC]2N]G¬Àòu¿Q&yrfRëÞž€ÊS€ÒèŠf®øç‚.hÖ æTzðŒõ&™4XøûèCJh×6Õ(:g[d(ÛSíˁu†µÆöÞÖº6·o¬4g{¯¯JéÀþ\˜€ žŽž”Ó¬X=¿ ÒŠqR$øþæß.ìXºXnú=ð$Ò î±u‹ºƒÁ|ùÝ|üýßEu¿MÔXù²7“î9Ÿ7ӝœU îߎèÙö¡ã¿wL‹Ð^Ë;˜šò º›nsÇiNŽ\òEÿ3ÌúKNJÀõüµz’$EøB œÀµ'g_ùuâkÍÒ¯~Ø'Û4”?“²üùó#[¶lŠŒq(VàLÍ!™Piæ\'}úôúŒ¡&sôèQ°úU¥JõJšrýúu,_ŸS‡“œ÷™„šFŽã&€ÇŽ ›ø1©bÂÆÁØäM{ŠÏי0,\A¹ô(:ä€ÁM"¬Åë‘7 ~2„±’سzºÖª÷ÏD îàÖÁ)êçk·Œð~ýñ* Æ²éŒ&»\©”ºëÿý€Er©º<Öê-'H‘úQ™Y:—î¡HŠ\tšZǪÕ(2ud•¡û·Õ‰ÓSØ7‹ ¯“™Ø”_×Fça¿«Cõï€L²É#û•ü|„!”ÿÅyª»¿žDJŠŽ“y#ciZ8@ ›šiŸZdÀËÿNP*ZTÅŸÎ}|Þr†òŸc•Ó<°ÿÙ 2­ŒNžŒ¢þ™L2hÞc‰òs|¯L#Yá Ûí«¢Žòž°¯Ž{ÇgšáùA·ÛŽëœ2%I$Ÿù¯»âŽŠ 'ª 7÷S>®tQZI)XießBV¢+zñŒÍ™Ö=qÞÕ[Ì@™byTDL~P‘±\/eκwá^íœ­õonßøÞMS²;Ú4þX©ØLžúQ`Þ;.£È¬’U[Íܘ¿ãß¡µ »)¥“Û³ê=”|Ièó™í£•RšåÝ>êýÚÞÞ Ã*éÓç¯U “9cZ Oǚ 3·/è%=ÜZôw òOÇ/šo󊢥{]»ƒYõø5?2¡ŽóõõEŸÐc|!pÖÞ-éO" püÀ%:næÝž-z.QæYꁯk‡'Y¿AjÏ &ªC#›§±™—ºßÎÁ=¯gžB) žhæf›é…F5ߋqys–îÆ 23ãà"u«œƒ\öW~7~.‹¢ŒŸj¶ž‰}Ç\”ÉWJ>®§°Ùû45üâ]üñcçh•$ÓŸ4õ%͟ #›·i…©¿—÷5ú 9ïJ~LðuYlv:œ\y)%>gò§©uœŽ˜ýÔXqd"îŽÛˆ•øeÍÁÃÔk‰«‡t«‹)C¿AîŠÀIÜY)ÔLV£š czò˜±©œf†Ç$úÝ:ã”ÉV÷nQª…šˆ?K&˜Š‘ݬzÌ sYRsnŠàÆÜŸ°ÊÍj:§ÕØŒŽ—Uí÷7Ÿ"³êÙ_öÅ<í⇁£æ*“ü˜Š8=ˆJA@°ǙÀ‘yDýÿ}+Îfš'Ì@ì_mlÄÓÓ3‚ºÆ$‰86€óªeɒ%‚ÂÆ œ­ÊþýûÁ «|œJ࣏ìçÝ;w0þ| ©M œÏ[A¢{S÷êµß[yà¢ëÈÑÁ‘ˆ‡ÁoÌR8¿7ð¥Òæ\@æ.ûW)•)@›žñ¡ž–Íz,ÆzšÄ…ƒiLÑL}n@É€Y9`3H.šJÇŸ=¬€•¥ Ñ퐩™˜±Éޅk÷pjÛšA68ÇDRÿ&SŽKVŠ~§píze&œ|(e_¢r%óÒáù+4$eщ°\ØÌ2eJ‡>@Q${œ˜©T8$âæñŒÌs)­ |‘ž°ú•ºD7õÙûÒ|³9Ï&üž ãçn5V…%a͘k~q‘1á:©‹JÕ°Õiüï£Ø¿vjµ™>3iZNxEið ’ÁJÝÅ= IDAT•=P8vµ—‡þ®ü²~ ¿+ΝǪ!«±kv}Ë×êÀ Ôh9qäùlÝs;/$Å·+ùÅUTõà©ûÉ€â"糈€›Ÿ7 äÍwÚ3öÿ;û÷åÇÛ{[ëÓÜŸ±Yrö ]&q§É’‰+Ÿï˜`í^OEa\Ÿ©÷2Ÿ4œ‡™€·í»ždŠüýÞñ}W‡ްß©m££…†Õ26©}yeñžæÊæö…çPšÊP‡Ù³ä„yÛTRvxôàôìU,ÙKÛ°ÿà_ 3_Y—ÄTt86éÚ«=úˆgéžH;A@ЉÀ±}ñŠžäÕû¬ Þ-m?dÓ—j1 À™°i€ ™fÉ>l\LÕµtéÒ)²Šaò–…sÀýõ×_š\¹2.\ž€jÕª¡@ 1•hÇtssÃܹs1{ ž‹v57µ¯A…àX ¡äçår×=V \©Â-bÂØŒìم͚2áá9çGӂYÜv{¬TŒ#š*ß6'ŒO>TLµ'ö.û&¡8Õàƒ'G°ã`Lþª\’‚f” HŒÅðÑ{E"MqЉ՛Sð“eDVS“騻ÊÿŒáђçÏd„ƒ€¯1&³KŽØ™Ž”.ŠŸ}ÑÍgù‹µ'13uØ78rú–2 å +Ú!=2&Їñ)C›QŠ:²«Šý¯RqåŸÈ„ >‘kVáØÏŠÍ(? ۇò¥òÁpvŠ +mLҏ¹äûԓrË1IåH¬pñþý>›Ò‚Pn5­hŠxŸñžd®éùÐG‘}&€¬”òØzñ4·‘¯kæºü°€MŽšÊ??|§ZKJ®Í*œŠBÆöÞÖÆ3·oÉõœºãTõ5°„ƒŠh…ï‘BU†(r|ô¯á(_{¬ŠDÊÑ1«|XŒKh°üâ9o ‡¬"î¢h õÛÏEÞ\™þŠQáà êAJÁit°hPž2†C…”ć›÷hÑ!5ÂÆ&‡LȘŽq€HSsHÎÃÆÁHL6s>¶B…£L²GšlÚŽ),I1ßsuwwǬY³(”7ž—ã{žX÷oªÀźqXK8Æñœ•$:êQ®8ÀGVümÃEÜŸªõ>ùåÔP*›ò±ÊÆŸF쇊§˜Fɰ…%Ãæ ãçn£ÄÒÁŸoZaÂÇ/™Àð!‘•µÏšNÅä!MÔ¡• G \N*ºÎ&‹Õ?.­Æ·$€)ÎLÖ8ññ‘S·pí¶‘Ž7ÊüŒýŒúvªi4¯l7`þ  ß·ü~"ÓÆ˜ “ÅÎ&†ÑúÐÚßv{€ü‹8P ÖYýc%p%èæŽ \¢Â„ÉYÝvsÐæëÑ¡Ù§ÑN§ÇšU*èÅØ~_ª:¬Ì §ü…ûÐ ó(ŸØãZQÄ<`…‰M;_ùŸQägù»™úÍqXyŽ>º›֜ššV›–¢Ÿ S~LŒµ`9Œ§¬:q‰ žz/8}›ž2qÛA&žQùjUš7—®{(%™ƒÐp‰Íœ­wßXýäà0_|ZFžÈe=8à|ƒì'É{2‘”.V™î{=WA…Ê‘JÍ{ûE›Ôð}Àé)òæÊ„íd²]au”£ZF€ÇÜŸh¿o?,Ø2] «LrõDÕ»O–Ôcòzáö"p ͚æë"p¯^œB÷ŸÑkB£X?ý±dÒF’/Gÿ»€äH_ÿmɔèãä D"[9ûJ³©#'°Ö‚ŠhdÍ ¹hIø:û¶™†ñϚUŸ_OBÁ¹ä2fŽ}2fœëeߌéÓ§«ƒiè‹+z›Ù¬Þ£ ð,§ñÊŠ>†Ôá€(NY¡1?€ØøÏYåP3Óºe_(ΟÆù¬N“"w‹ ‡Äÿ‘reµŠ«¹Â€ƒS(غðÁšVý8˜ÊʹÅQ#™Prwò²ƒLãXÉcsÅç>ŸF³JssåÀ  „Û6­_‘¢~¡+ߞ¹~cºÎÑC9Š%ïc&ÁŽoۖõy+Ï[LýpΚ’±3”sÖ«þŽŠF©rî/6xj!ÿcšÚ`ÿ-VºØwÉpT…Í{wžl ì Ííß+΀8kйŠc1[·ýÔ[9Ùߙ_Ñù3™âë–&^7·/‘ñšÖ|šº¿Ùœ×Ò1ケ֖ò\võǐñ‹Í>pg Ä¥A@°Bà¬eŒvÄf…Šùר/,Ož<Š”±B¥)p\‡‰›h„ÉfNŠõ`ÿÁ)SŠ`Þ8 bòòšõ:¶ROŸ!àâÏy)3·Å)…Ê¥9N-õf·`i¢àtl:šå c³BVÎŽÂjâ0R˜8<|l˓g/᳇À?±{tõ£ò%4­kM<Ù¬“ ©ŠZF7'ÆyÅÆc*àŽi‚lKל÷ÍÜŸhXp€Ð\PQWÑÑRˆ¬ÒŽý¯ÞõÇÐ ?™íO7ë=°3º©' œYH¥‚ ā#{Ïã%=ÑkPµ-™™R—±€­>˜Œ±€©ÂŠ™C2acÓ4MãzlúhÊ_óoÓ7šÔ²Æ}êÔ©ä”ß”ÜuKºˆ÷6>ÁÙð,(H[ŠÕX©RPêˆTn`'Å6p~.ŽZø7%È~@*“€â…sQâñR”Ç«”Ù %¶™eâEðŽßœZúçAtŸ2‚¹iBÍv')p·Œ‚Ñgø³SÐEàØ7¡gÿïÐs\C€ ‹^d¶g© ‚€³4+7áÀUŠêÚÓ§O•ß¿˜ž±i $á:|-rÞµ4i¢6ë±ò4¥;x/&L˜€ã[ ôÕ ÁFA@ðå™ÈÞ>4Ŭ٢ŽîâT…M?ï<ÆÀ1KÌö#Î,DRAl‰Àa Ãüú¥/êWmC Ü'¶:َÅ$Ì4à4͍յàà`u“is1%lš[²ÏNÎêèžqã°pž›v2+™† ö‹À•*ïßÈ^ 0aà× >Qºsïq(ú6Ÿ[Q\‚o—L@L`÷Š\ƒjDàJ ³öÝÁŸjZTHŽiɰù ®ÒÂùGV×ì1£µ1JŒý1¹;v,Žo†Ð×·ãd΂€ ØNtÏ ï9Ùy…²m:vTƒ­ßqŸ; ÏÈEf碋Àqô­þC»£óÈÚäÛsfp³#JA@b@ œÀµ&WE°Š#LÆLý×|||Œ¹×R¥J¥‚h `5SÒÇ᥹xòä‰"póÇ6|ïØhTFÄ‰û%€œØíŠÓG]á~ç2eÏ¥ò9§~‰œ¹€,Ù3ªC³vØ ?óg&YAdËmÃ9ì ¬~ÖÍtºæšl|;އî™dq’Eá™3ÌSA†~ø ¯øaÉ0ù³FS: XÕ3œGCaãQK€L•!Ô?wÁ"4Ä@ìT^Sðqô™sŒ&éÈ¡†}4^ MEä&lð°ë<¯%rÊUGJà©úŠÑu“uð<8‚qq&ÌÓÁ1%­;ÈÐSØâ™øòþðzU_Ô4Œ0©Ñ~ „ÉtW4¹Š0ç%ÓxŠDÌ0”áύ:š}PLÖÅ$Üd®Š$:TäœÛ(BN}ð| $;Œlkõš…jG÷á+äqyáä<¬oêWõ©Æ%rÏXó}€©†à‡ tP§ ó4šsE¡šÏü䀮óxa޹ñɗ/|àKD€1{åã,9r¢HéwPîϐˆ\á‚O¢Ý_[\Ð\œj¢ÀqdA°q2lþ]bSÇŽiÓª{Èßß_åfóóóSߛ*l¡³ÅžÉ €‘Àû¡~ ?!™ ‚@¬X±ñ(CÓ¢ó …fÛé bÂNï}wE·ÑöIàŒ}œqæ„vn؇LÙr¢ô{"Oá"HÚ‹(C†7”tòY0¢ªàëKÊMˆ~å&ŠAüH Šº/MqQí¡0>Ï5FûÂðÑp1ŒzI‰2Y$RAÿc’©õa$*a}ûˆÀ í5’‰Uªñ"“:mÍÆ6Šò`ØE E&©ód²kZÂÉS8^Žd”&Mª³²É?†_3 ÃwQ 'RZ=aÒ^É՜ìÎõ«ž}ý2º»áýϪ£j­2 Jâî>ŠÀµB…RÉÇŽM9؈!’ß9D?û©¥L™RýNr²l6“̐!ƒQ]ãDÚ¬¶IIÞhnáØ†À¯ä †¬^DˆÀïŽ ÔÁX‰Àñ“ßþCº£ëèºv§ÀÝqˎ£ûnàúù3šþedʒ-n™LYHx|_œÄ‘Ý;”â÷}ß/Ȭòe‚Lêà."päW¿zK"pIׄ’Œ™šC²ºÆD,]ºt wVŽY]ã€ÚLÒŽŒlü™£GJL0*pl,ôÍGA ‘!°|Ýa8€J‡Žý“8c3µ+œpíì|ݱK"Û&™® `Ÿœ=rOx ßÈjpN`óI2ó§àu>mJî6?Ÿd2æååe$md„6M]c3H&u¬›†ñçè‘Rs0ã4ó(Ýü™«.×A@ì U›Ž"¥SzŽî9ÏìÌt™PÚ«wdß#ìÙq Zw0»P© úžxâ{ÜE¿QÕÈ9ÌOQó8Õ WàÈ.‘8öM35…äÏùóçWŸkš_&ÿ]}þüy²ÆIØoWŠ [8 é˜1c°pt„ú?Žms©/‚€ À,[{ˆÎ\éÑ®Ÿ•8>d Ö]) ¥œ1ñ£ü ÓÇ@…Ok"_ᢠ¹ /$=þýëO+UMZåµitJ&p¯_SžÏ[àýRU°ŠæLÖŽ "¬®±o%ËaÎÙÙY™Ij ‡ô—"XÎÿÇ Ü‚Qµ€€§ÖèRúA@°!Ëþ<ˆ4iÓãÛŸVŠBÉnÈšÞønX-»!p÷ÜÄá}Q»ikB+C Ɂ—€m[µ }ÆvµiPÀ5šA \Iû$pŠŸkLØØ’Ãô›á55öYceß™ÀIâŸß&Nœˆ¹C«ÏãcéSA XJ.­3ž>V"pœ tðˆ^ø~Dm€N“ðæ=m΄ÿ«P”¢ˆ“RA ~`®@‘âøªy~‹#¹Ævfá \sRàè0šÀå͛7FsHþ[xïÞ=EÌ4SGþ{ĹØ4’‰ûµiÄ-§.Ã'#øAžù#>'睌V.KA i ð˚HŸ>=Úô^lvAº|àØ9zÈÈ>Dàjفóºÿ ?Í=‰Ê5ê Gž|f)AÀ2n]Ÿˆ—Σÿ˜Ú6#pv›H׫ޔ\uË&‡Vlil„ýÙØì‘óªi)'˜Ä™*kLØŽè‘qZš #À÷ì€I“0x5„úX܏4A@H~úã2e¢ &œ¬DàØ9zØè~ønxM» pGzc÷Ösš×ò[:T¥L”eTA ™ °rîTL\Ð3øÛdÅLà|_û£~fx¿dü*p¬žiæZÐ~ú¥ù®q(ãÏõ4UMó_³ 2ˆ  ̚5 3T‚&ˆÎ©J5A@(øyõAdÊèŒVœ–˜ÅG—ÇnԄAh?øsòõHøüCÖ<ŵóWˆÀµ3»@© qCà¯e‹ÐúûJx§BŽžu€³u8#®du­ôUãà"ŠÑ!ÙoˆÕ5ΫÆêasH.¢å^cÂÆ€NŠ `ϰ*¶?1Ixî¹·3–þx¯|ŒÑèÛïäxF`ÓòŸð^'4ïDŸ56(«÷ù7ø TÜÆd2fª°R~9åϑ!YU 'Ð6%kìÇ&EHlž¹¹aîܹ˜5 8ßÄ6}™¯ ɁŸþ؏¬™Ó¡EϟÌb¡Kãð×#ÇD§¡_$ž ¥çƒÌømþ„„† n³¶fhR Ò¥6„®„’ŸM†LðÀû­-ÔŠmµ9<ŒïŽ}Û6â›ïz"•äž²®¶êèß «‘7ïSŽïÙÈ&C†ž&Dàjè“ ™©ºÆäM Y]ãß=&j/_ŸDÖ¬Y‘'Oc°‘ 2èC* öŠ€««+.\ˆ}ßBÞØë4e^‚€ Ñ °xÕ~ä̚Íz°\ŠqÒMàÆN‚v«'8cnͯçLŠNŸÔªo÷7™e•Ν iSÅì«wþÚMT,WìetÑÍ3I‘ž“ûÿŲ©ã0üÇ¥(\ªŒÝï™L0"Çþ݁ÅœQ·I›@£žºŸ7Ƈ¥ŸˆvL6‡4UרR€‰p°&s¬¶ñçlÙ²EH–Ӄ›,Pâ[·naɒ%˜Þ÷=Ràlã¯ː.A@H¶ \wJäÂ1îŽIìÇ&” Èûå«4Xùó%òU D•D@ಥK‹ÂÙ2™œ5—%3«p/“‰;ñß.ü:}úO‡Ò$íƒÙ›ÁÎ*ß³“Ü3Ôil[W§zcT,Nà8„?ÿ-ÒH›¯¯¯2‡Ô|ר2SŠLÈçf“"$®_¿Žå˗cJϲ€À&‡%ËA@HRpœÙ3¢ñws‡˜cŽèRàì‰Àùú9á·E—É*q(p¹3ŠC>"eæŠ)ãºöNâ^<†ÙC{ãë]Q¡JÌɖï݉å3&¢÷³ðNEr°—’š`^šÀC4ln›€ÚGöž‡ÏóWšônuäJ_R™E2yãpþ’ a%ŒhæìÇŠ]OTËd+ põêUüñǘإ8l…¥ A@["À \®lÐŽëDàbλ­‹ÀñjÌÄ!è4ì‹Wàȅ³n „üY>©UϖžZ4–FàBCBár×]ùäh…}ãòåΉŒé™ÀŅıyéŽþ]i¬`4lûÊô‰ÕÓ-œ;rK&Ž@ón}ñÅ×ÍcÄæ(™àý>kÎXˆ’å+X„£4J8Îڃ<9=ðeËø éÿÆ/Ïûàécoú÷z>Ã{ïTBñüåÁFòæÍ‹,Y²ްÚ&E \Ÿ|ë֭Þï  ÿwFðA@H,a8EàæKã€%[4›¡¿šk÷;bªÀœzí‡`"UápvN‹”ä§sáúM|P®$²F:”²wá®bÖä‘ç}ŒîÔÂ8Ngg”zïC”ýà#”ýð#ä̛?ΞÞ¹ œ¬óˆ šX5z?%H«;rÁ¯(XŒTœÇŽM;×®€€Ð¯Ñžc·ÍøþÙžt!ÎُžãŠ#_‘b±é6YÕœvv2Šœ¯ZW·Úº_x¿Vdíé#"môzAÁ{RŠ${oòœvñ@êUkâÓêM"ٟMŠ DÀÙ³g±yófŒëTP A@H„üŽú²g¡ &]fŽÎq'p^^^;išŠB™Ð>pŒšå‹oÂÇû >«k›šxq¹L œ¿?…,7QàžßŽ©S#…C Üt»Ôè€Hþ||†Pn>zŠg¯cUlëŠ_ð÷êߢœzb%P³IKTªVŽa&i±]#£M˗èRÕöoû kÎÂø_V#wBعnNîۍG¡+Û¡u׿uùf êAäõ ˜6ߨŽÉ+‚lÚÉåëŽ]Q¯…äŒØ«§v!ƒ³'·µ<€ÿ“GÞxþäž<ô&uí)‚Hv€œü‘-gfd͑ Ùèu\0)Öuk|…KÖÒœßRQHΜ­ÓíúWcptBöÇc¿®TDž[v﯂á8ˆºí\=œ ™Ó?À—­ô™Pú¿ 0(kO êšÇÝG”>‘Tð=Š”ô "Wž¬ÂFκYè]©oaåளîßõk6!W3^î éTHj>|À°6¹’ÚÒd=‚€ $ ˜ÀeÉèŒæ]f‹9~†.çéé‰ñS†¡ãûPàÖ­tÝ[Íú^ÙÃn›S࢛#hH“ÚàÀxÅë ÞÅj9×ϟÁœa}PœÑ7hÕs@„¶oހýÒ6,]€ŽÎéÐgÒl(Z"VýÿF ‡—Ÿ»qÒÁŒ©ìZÿþZ¶³×ÿƒt2’ú€#»¶ãêٓøŽvŒ÷Éÿb5¶ÞÊkÎÆ~Ê?מSwÔmnÈøçâ9Ø·e)ÉiЗÖ]ü ¹-%F.ŸÜ‰,’ eÌÎëþœ?é¢H›fÉþ˜¹òfSʶ¬92"ö‰©Ú}/|^£^-ŠB) œÜ‚€.öïߏ“'ŽcP‹øy ŠkRIAÀb–ýy3€A‹.ӁT1ûùë&pã&SiR9ŜÏÌâYÇ¢á?›ïàÜi/ÔþŠu,Z%LUSîҍÛo™PF7+G"pï”* ‡žÿ6¯ÇÚ%sÑiðTþ¢Î[ð·î§y8°ý/ rRœ&ۏEY8n(®œ>ŽEÛ˜mµå÷_°cÍoª®“Í»7®ÁãÎmäȓO,Kóv-2§ì1F¿Ü±æwlùýg5‡c§âJŸ˜{t^¿|¡Èhr(—ï@–LÌúÀy?{‰+ç\• °FÖ²fš®éÁËHàj~Š¥jëi"udÀž={péâyôm’9Ùc!‚€ øuÝa€O넖ݩËãt8L˜:œ|àìƒÀíúûNºK~KßÚýþ˜*p!dŸ§; ‚9 8K80ÂÁCj6n¡‡€trÂc/<ŒïŽ÷ÜÀ&––=uZgt3eÞ¯ˆ'<ÁÊÝûŸV3KN&÷ù==0gƒÁ,в–Ì'íØŒ[÷ÅX/þ\4G){Z)ZæE.-!K¬@òzŠ¯Þ‚ÛW/ãçI£T·Fåo“ZmL紐±mÕ¯8ô s A™*á›ïz kÎܪʁ훰zÁÌ(#p®^0 —OEû#QêÝÌA“(®ß<·Ò¿ 4ñ£”F!œÀ}E.ú}JàÉ$!°cÇܟ邞_™O[c£)É0‚€ ±@`98g"p­ºNœ²ÅØR»ÿ>&N©‚˜Øƒwd¯öíq%³žÄCàB(¬ó…k·"€ˆig8ÀÃ{¥Jš'–ž)};ã®ËÕ(‡`߯Â%J£XîÎþ IDATÙwQ©zMä/Jyƒš,›>'ÿÛ­ÈJífm"Žõã‡zvTŸdÅʖGŸÆ5IsD¿És(8ÅcŒ~ᣔ-R€‹“+kå÷ٓqñÄÌZû·ñ»+§O {žŒFÿ9&os†ö«oiȬ³Ü‡•éóU<}øõ[µÇWí»ÄâWÀPuÌ÷­ðÈã†Îù‰ÌIû‚×`®¯—ÎcÁ˜Áð§ù0idŸ9ßW/•¿àžŸV)_9ö¡ã(Ã\ŠÂ¥ÊçõŠ0Ô²¡"}=ÇOÇ»•?õœí±Á­ [àœÆ‡ÒØ&\8û’œýGšµÇ=“9%?¶lÙOz@×µAÚä·xY± Iåë‰À¥!×e:GÜ Üœ{÷0}îxŽé_Nv`ByüþÙ| (Ǚœ—„Pà8Êb߯µÈ×Ìy U„+‘âD® "¥Ȓ=g‚¥a8ŸÛ·ðŒëJŸasTºÓrúà^ü2y }û=ê¹ëõeô ó*‚~S惓pВ».×0é·õÆ.y,NgÀêŸ)y,Vî]tùµÍНŒêØþ¯Ÿ:6V[Íy{}UìƒÅĒßÙ×®ÛèÉњd²*9c`U·eþø€f=Eàæ ï‹ÛW.bä‚å*jæôÝà~ûæmÚ¡/öë[1g 8Ê'×5%±±šŒUv9ó2€{©;ˆI\§Ïyà^P"ﺵŸD¥RöŸë1®ë•ö‚€5ذaŒŸ=F§Ú©¬Ñô!‚€ `c~ßp”x–#Zwù)ÒĐJ—çîîŽÉ3ÇP“v¡À<ìŽíÝÀ—D&ìœhŽžK.®º8öû*o¡›6ŽêÔ|V]G‹×Yú7­«rŠÍY¿““D 4¡™#ö›ò#ŠÉÒ+n5ŸnŠT·”)S©ÔŽ"eª,)T¿š‘Ù_î)i£ÿnœ +„~¯_aÂÒ5ôþƒ[5TæœcIåʘ9Üî÷Îõ+dº˜+֑*™ü ÿ6èë)q‰Bérñ,fé­rœ5ëÒ[ÏpªÎÀ ”)ä¬u;"øœ±¹ › rá\nœv€ «S‘Ó0±éÛ€6œÕOúŒ™0wD?<üHµÕ “ºË§ŽYü‡”6ºÖµ­òÕãdßÖ(Z8ÓŸ˜ žµ(ʈ›<—ù£ÀgÒ|›²‚×¶ÏT¡ˆ™\8IúKoåÿ§©l풣^ZÆëÏ>®žÜ€Ì™|mfByxÏyR^ nÍFøšŽs)‚€ 3$ë@ÌèýC*ÁPAÀ~0q­Ê =m! Ž©cœš.ÎÍÍ Sf¥àö¡À]>{ëVÝAÃ6,ŽPh«í35¡|õÚï­þ¢® Ø¡·,"RuáøaÔøªZt栗ýG!÷×SŽÊ`õ3a’2}`weV؄ü娀R+€„S °ŸÝìµ;à”& æVÒLž¬üqÿ³ý§ÎC‘Òe1€õWÊïŒ÷Ž~ëqÞWà\ž0Éb"É€‹#[›û3ÒgŠ©M ú2fÉJå—wöÈ~Üwœ¥L9yœlî©-ºe5ÊCX·yœ;r~Yš00m%ÿP/䉢ލ3«)¬m¶°œFàêÕjD&”BàÅM"“LpÖ¯_OŠÇѱvšŸ‹L@A ö¬üëÅZH‰oûþd¶±~7‹ÜP"pÄ º\:s›ÖÞCíŠßRR`û¶÷7M#àr×=V \©Â- b¢©AEK—ÃP"+z‹—û]°á‹çϐŽ#aëMJ²åʃÏê6R!øß¯R ÝÆ‚’,ž0\ìàPÿÎé3ÀçÙS8… SÛŸCU.?O3‡þÃÄ_׉ÐvJ°œmœ±%ËWPyé˜D±ïZN"P¥‰±)c±råã”h<™crÊ6õœ9ž§JOPˆžt2F}™”é1d3É©ýº(•ÑŽd̒ ÓþØgò©w¿lUïÆ™Ȟ=jmyڅØÌUžØ %u[·n…‡ûMtmsî ÁKAÀ>Xœù8‚œÑŸÏ<³ÔEàîÞœ‹©³ÇÙ »Hn×¶ûøŽN+¥ðØs1Uà,glžK'ªHŠSŽŽƒ ¡óõ6u\5o®;­ˆÛ‡ÿû\¥"p&߯5 g)UŠ£:rá0ûœkŽMµRžd4hÓ1BFM 3néAÁR–>o©"\ØôsóòŸÈïìr„é2 +A$±#åŽs"eOOÙ»i­Êsgª&rDË)}¿ÇKïç*š$GÅÔÆÖæÈfœì+—†Ì-c*·iŽk)偧›+™§V‘*«5lŒÖœé™^¢ªsõøräʝuۆÀÛOz£~mQàՍ’„&{õêUdΜY²dAÚŽ‰#ªãΝ;qýÊ9ôù&æÈeIh›d)‚€ $)Öl9‰@‡ŒèÐ{ŠÙué&pì×aÈçv¡À;~{w>D•º-uèÍ"OrfL‡™ã–—ç²çcøLõ–³‡÷«H’戈Þþ¢«Çzž#à?)eyÞ2Mävì÷wŽæS°D)eÂh®pž:&qw®_Åý;·T*l¹r£?ÑKØy̛—Ï+µÍŽ4ùû¬Éd™=ÇMWDN›ãŽþ]•‚ÈiŸùŸ'ŠSšŸþÈóŸRÙTò)åÊOWŽŒtìžuÅR•š|ÐÌEŠh&µrýÄoș' jõ±M–vdïy<}üõë4ÄG¥ÚdLD0EàØ±cxúô)ÞŒyd̘Q‘¹Ôô)xJŸ>=ÒÐÃCgggãËùïÇíÛ·QŽhQ¥Üóß-~·€ìß¿§OĀy-i.mA@µÛNÂÙÑ©÷d³3ÑEàîܹƒés& ã°iÐpàMÈròÐþï>ª~Ù5!§¡klg§T(;Å0ެŒ!‚tÕó‰îüߖ"­ކ¹tê ®r\Š |À2-ïTú„R©nZ™Ô«“Rà~XŸ.É€0]óÍ3+‘9«ê5±M^»£ÿ]P \œº Q¹”Á WŠ ` üüüðÇ(RÆÊ›öÎD.ˆþR&~ç¿ ¯éïïïïo$_ÜF#y©ÈÝÉÉÉøJIÁ˜œñ‹s«Þºu œ¢'{öì(Y²$=z„+W®`ɒ%-õ̙3ضùOŒù®”Eí¥‘ ‚@Â"°vëI€.€ö]ÍǯÐEàØ„rƏÑ~pu» pì#séœ7*Õ쐰Hë=SÚÔÈæœŽ””[oaÚHþ`^ŒŽµúŠw ©5œÌûEÞäT|PcSRVÖ85@ЬÙ#4zH‰ÂÇ|× ÛvJy -Ùs÷Ë«àœÎu›T±€y¬Û0{ö”£PÖ'N\¬”qB€U0___0™ãw€(Çïüwß¹n0ýæ‡=\W«Ãõ˜Ø™Ÿ‡âñãÇJÙ˗/ *„ܹs+"øàÁEèúõë‡O>±ÌT™£EϚ>sUŽÓú¥± ‚@ °lí!dÊSÍۙ ¯‹À¹ºº*ÇALìAÛ»ý$Üï¢ü§áÑj5¹#ðׯ‹±kÝ*üðë:J’nÞ<41âõàæJL§òÀÛw³8GÙ™Ä¢ÂŸNS2æWÈ[Z\,`“ªVFàØ¿;àå~MŸëaåží§»7¯ÜpëüVòû 9rۆ€j®A}RàJ‰g?wCòœ GœdrƊ#a• G d"Ç/Ž*©™MF—Ǎ£PN:5kÖDƒ âLNC°béLék›œñ²éTdˆ€Ûý§˜»òæ.Y¯+%•.wãÆ üžhªÊgi’Qkîŕs·pdÏTkÜ/_бf×җ ˜ àåºÏŒ®¡m÷ú6SßOºŒûnÀî“ҍe?A€ 7΃ª™Gr.7þžÿMäümLäøÅ9ßb*»wï«cÆ 3úÀÅÇ¢8EÁŒéÓ0žMAdÉ(ÿ6ÆÆÒ§ ñÀÑ3·ðßoŒ™¬/š.ǎÖó–L§4ŸÛ{äõ ìתgoxzeŽ¥OA Ù#àÿw/mF®<ø¢¡íL²Nº‚{w’JAALJ7Iöû ØVؘ ñ¿y[úôéJ›µðwlÉ »ÍÎ÷Ë/¿(¹þýû›«n•ë£GÆ×ŸÄûEõçµÊÀ҉ ‚€Å¬¥iNEПËp]}è"pœ¯fÁO3ÈÎ>¯löØUhF~9ÞŸ•ààšk±RIô#pãâ9dJEŠeBÙ QûóèïMMÀÕoPUJ£¿¡Ô,@€“kkþkY³fE‰%Tøÿ{÷î©%%RSÚø³ÞÂé–.]ª"LÖªUKo³8×[¿~=ž?Ÿ‹ïëÛÆä9ΖA@0~ÎÔoÒ•«éË›h Ü¿[Ã÷µ?j4ª—›¶ ® ÷— \ð}õ 7.žEžœîJ}K“Öv‰OŸŠ{®P¯A]|ZŠir\ÖiC8 “3&n¬€±ªÆäM ûïäädTÚX‹Máè”Û·oÇùóçѳgOågËÂ&ŸóçÏÇô~•àòږCËX‚€  àML&/øƒÇÌG®ü%uõ ‹À]»v ž©|àR€°³ŒiÃCGÊMõ·Œ}ô?ՅŒT’1‡wnC©òe;û-Œÿ±åɅ-ðô‘«p»í…úŠÀ5³€ i#Œ…+Mi Vªû±±ǁHØ¿[SÚX³€\Œx»víBŽ9T”I&‚¶.\eÔšQøŸå§(œÑËÖÃËx‚€ ±Dà²Ë}¬ÚtÓmG ‡”ºZë"plB¹ð—™è@‰Œí‰Àœôyy× ÿ„p¹UÁÁ Ÿâ@êRI°S8âމœ;ñÞǟÁõÊ¿hßí›ÏôÜñëpœáA \|VйÍǗ“AAAF¥U7VÚ8t¿···"müïGdâ–9³åþÔ¯_¿ÆŸ}û”Ùe™2ePœzõqõêÕ ðC[5Ð‹ .‚€ 3n= PGŽë«/€ ÷Š‹À±-?§è4ü »ÛƒçO_`þ¢bÕÈYžŠÝÍO&$$<îºâŸëMT®^·/îA“¶•)ºžŸ'AÖ\㙣×pç&%#nÈ®…5»–Ÿ’ LÎXm{öì™ F’;wn0ÉruuçrӔ66›ŒkáÐýǏ§ˆÁšV­J•*×.ãÜþÑ£G˜4iЬÔ!¢ÂÅPé@xB 00#glB׎MP⓮ºGÑEàøšÅËæ ™PÚcaÕàÏ¥»qöäS.S¹óBÞÂE*ÌW4|،…Kh(œÓPž#¿øÃœ«Ïô 1|fãÔðz†Ï!t(àBýšvÔ/悃Cè ²¡?ãxÆMAœr;Ã<@hØunÄ_æ>5W5¯°ù«·°ù…Ìg×Ô„Ž¢ªš††>#<ü¥§Ý<¶Â5`AS2üV-Ì<—Þh²Œ&ŸÎ5µz)ÈÌIÃ1…BL¡F’³A}5*ÄÔÎÑÑÑ8N„k†šjª>œÔ8ڜTŸô5%­gŒŽ>ùÝÁ!¬OnŠú —· ېjÃпַÁò˜ë:ÀAG+€vª=}æzÜÎðsØuƒÆsPõš·¥5Y³Œñ}÷ÜñôÑdϑ  úãÙÃ;šÑ œRÇݚó0íëì±ëžMæ È¿U\|¡œôúuww7šH2A˛7¯Šþš‘6VÚ8z$›MZ«üûï¿`²Ä¿›œÛÍRÓKkÍÇŽŸiÓŠá£w ¡Z™WñÑœô)‚€ `Œæ“Óf EŠòº{ÔEà._ŸŒŸ~«|àì¹<|€«Ýè@ê†ÞϐÆ9ÒÒ+8(©Ó8#™È0) V„†?3Qïê3!"L!¡|îŽ #@"ćöàà 0ÒEm‰Dq1ôe >F2 ˜GˆÑ÷Ž”Oˆç¥J؁]ÍÁÀ‚è î@}211tÀ‡~)' ŠÀ„c~Ÿ0EGǔjZ}Ñ!a$…¯É÷©ÍƒÇâkaN‘ &HŠàæ¥È aÚê?ò©‘ž·t†-î­7‰ [~rM7"Bß30UCÑ 4+Z)BÁ`Èqó5|eJ ÜОÎpRj €ªs5®_ړ ž»bc†}Qä2ŒÐ©¯˜@öܰ‡4w†alÃõ02nd¯lÔX§kt…„М€-T¬eÀ•pfDëåïù~à}VûFøøgǔ©Lˆ_ €€\G>&…ÔãÍ{Î?¿ôyŽ ož2•'q†sº4ȝ'©Sy£X©ü(ó^ãþ˜l€Í>ž;á‚[WÝÑà˺Bàl†zâèÁƒ*O‡ýg•Õ6.LÚ^Ÿ|©”6&m9sæŽêœŒŒð÷ß«• Àÿþ÷?«öoÎØoㆠû=9ćŒ±F—Ò‡ ‚€•XŒj?òäȈ&gÓaTþÎ$EàL1 ð„—Çø<{…ëïÀïMòäÍF‡Y&2UƒÉˆAÕ C0ý옒Uþ̇^ÃwÚuÃaØ@`Œcºž’ Hš=éMCך~eÅ@¶ Ä빖wΟ€ çÏÅÌ~ïYމŽA@ˆ~ßx”„ Ží<)ÒÅ.ß®.ÇŠËV.DûÁÕâeÒ© Oßĵ‹®hH&”ÿ+ÛJ€IŠø“™¯ŠŽ±/çScÒÆ„ýÎØ4’Õ6[åYcò¶bÅ Ô®][%ûN,eÁ‚(žíj’7±LYæ)‚@’Gà™÷kü0;Æöo‚,å(x‰rYÒ_t8NHºbíÏhÛÿ3ý=KMA@,@àҙ›žzžÜ×Dàʁ³ÂDۄM~5ÒÆùي)‚”äkúâÅ eÉ>nLÚ4_7[.”ƒ€ðžö®ºEƄͬ»~× GÖHš²¶Ü#KÄ‚À›!µS*4kÑ)²Åž_é"pçΝÃok– ý Qàˍ!ó+—ÎÜ•s·Ñš1ûÀµN¬ËyÇ777e"y÷î]¥¬qlûÿþ}£O[Á‚cÑ£T5Eàø±#ØœqFõª/À‚€ $0.®°ìÏC˜>ª5Rän„N±Oi£‹À={+þü í„À%ð–Ëð‚@ÒGàòÙÛ`÷e“ÚDàÚ$ý'ÓzzzÕ6¢Eïå’šy€ $™BdÕe/ž? 2õٟï©Ï.¶§þE€ J•Þ»tB‡H…éíϝÍ@7!Ùl6ßà:³3÷ž{îooÏœçÊü53‰DÚDŽÉ°IYT[ÒýËŒ6Š6Œq—qiüøñžpá}àVŠorÓʇãô’H€\˜À…œÊøá·“°xûaÜžq%î©Cnݺu˜ù돞ýñ®%î ’ €=pë—ïБýÑ·Åœ„ã"âããm¢M†AZ,dff"<<ܖˆDÖoãVþ¬\¹ÓŠMÃm#oF·Š9ÈO;Vþ:AI€HÀȚn[{aʜUj„õžá†ÒYÓ!·víZÌþí'ÜFç] ÷&ppï ¬]ú‡pýZÞçޝuñޝ={Ö&ÚdŽ›DÚ222l¢M"mŸŸŸ.Þ ºçI0óõ×_C–z1øޝ«²Tæç:R•eH€H€|Bq(1 Vì„üà)Q7™JPZ›ÃSqë#KËÚ% Màðþ¬\Œ ÃG]§"ppÎ~,RSSm¢Íœ×–““ƒˆˆ4lØõêÕÓKpsO»wïÆÔ©Sáïë‰^­|Ñ©EšŠ¶zºggÙ+ žº,× IDATZ>á8˜Xó—ýÄÄDtïÞƒ ºZ«Yß!·zõjÌ]4 £¥€ûK¢,@$pUŽDŸÄŠ…[0L ž~-Ç\•-VvŒ€€ú—d$ÑÑÑ8qℎª‰h«^œºmxd@@€cÆXÊ-Höé… "!v?ºŽkˆŸÝš¡z˜ZÃOæÈ债EÙ  (.Ød ¢ãü°zÓÈôæÍ›£OŸ>š\¹rqM©žCnÕªUøuÉtFàŠ„–…I€ŠCàèÁX,ûm³pýпÕÅ1Á:8t萎¶íß¿Š@³_§-00ÐAK,æ®bcc±hÑ"ìÝ»²ü@˖-Ñ¡C4m\d©uäҕ S¢Nö¹æ' ùrNÄ^^Š»¢a¿H€* ©8•”ƒãq8çÄ”Ýûž={¢E‹ u* ‡œLpþ}õ< »¿­Scc$@À±C§°ô׍:ª?®£€+ñ@"l"Ú¶mÛŠ#mòR^»vmÛâڒU’ & Yü[¶lÁΝ;uøòìDEEéH­ ³5³’Ú×ÏW;xzÑð|œš»lzwu¬¿«cãkŸ>o+cÔÐåÌ:æ5¹¢ÏYëYô.7/W?Ûùê“'mÈÞîcû®lä©ùùyj/-I³ŒÕ7}Nʙ×ò¥ŒêŽÔ“2ÒŸÕ¶á¿dΚ\1lÉÞjWwÅ<¶^×>äéŸèœê@žòßè¯Õ–î¿”·²1¹IeϊBÛÖvÄ+£=9kð²]Sß ÊŸÈwù—fl¶e­g˜È‡¯²³U²{öÚWëý³µdŽ©Û°¿WÖzÞÞddfmêÍî~š²Ú5lí{xzÜsuÊWÙÉÊQstM3ÖçJÊéò†cºžµ{¶öŒg0O—ñVC…sÔœÒ玏êy¬Ž«?ÆŸà»áÔڗæ¹KëJq³œ>¶ÚŒž ㌗ò%Oûbر/«­í_öºÕo£ž§­Ÿé›§]»…íÊ5³—ض¶i³#÷ÁŽ‹‰¿ÜîœááU 9ù~8—îäsY8{>'ãÎ!éÌĞNÔý•$^mÚŽAÓŠMõ÷ÊjsXÀ-X: #ŸŠ¬üd»$@„À‰#§±xÎ »œŸpV^—n7ãââpäÈlÞŒÙx±T/3’î_Öh“ÿ•®Žîv$ÁÍÑ£GõsuìØ1œà©S§ô³%ÏS•*Uô^–“áE²F Ì¯k×®f!bÈ~¯…Î>öeÍ2ò%¢ÒünÚ2ŝ\·ÿHÖTyù’œ™EUêˆò]~Ì0õ®+ßÍºæ œœ-óœi[lŠÏ/Ç/ºW:g.p_x/6MQx±h°ÿY9ûkæCY D €Ta…Ë–ô] Ê/µ\øÚåʚçì¯>çhûrW:/ ‘kñVál<òÁõ‡ -ðM!oü`Ô+xÞE€_,¶í~°ûñÀŸŽØ0þ^vDìiñnµ+6Ef)¡­Ï©?¹êÇiG~0ëÈ5ãkynUù» ¶Å®·—Ê8œ•mó[~1~$1ê™?˜Ï¶xÒG«éï냌,±·žÖÂÞ*Ímtq-N !oü‚ Ÿ«)žÂÓK õœiÓø»e”0Xš"Ø|zl?‰+ÆÍÒ.mÛ±m[5Q'”Q‹?<-~ð°ø*¡–¡—SIKKÓ}7ÿ.‹‰¬EFF"**J'%©V­ZI?þŲ琀“!”"àn×±X°  8J æX<ÎZ‡a·õŀÖ9Zå ì`ûöí ƒòb(ÿ’ˆ6gÓ獩XäH2YÊd~YÐ]æWf©7ùlÜžQÿrm !c/h쿛Dz7Eý¯ýWR¶ðK÷•„¡Ø6Å០HÓ^QÊ^Iš]®?/ŸÉb ÷ïÏú^øÚåê^ŽmI—³¿g¥á“ŒTÛ߃ËýÍ*Š,ü²¥¿©&]­Ž0’¿sæó\5.ˆ _îœ)ÿ¬Þ_•14ÄßÅ·¥®ù÷Øþ9±ÿûPøŒù|:zÞŒöõ ×ݱcÚ¶5Fš}•˜$1—ŒL'ü%{¿]é¿æ žå˗cñÊ_pËX 8Wºyô…ܑ@ìñü6c5†ßÖڌuÇ.–ZŸäåÙ)s—ä<ò‹¡ŒÏ—h[ÕªUK­m&( p5¢Ñ|¹,Œÿ³ˆÒ_FŠì^Xí_^iËÑvÿÌ_GmüY9ù8žÜóVøåÝŸÌ•®ýYÂàJ"¡°/—³éŒv ÿØaFí#Ǘ;gœ$Žù߂Ò'à€[ºt)–®ù7?Ô¡ô=b $@šÀ©‰øuÚ*5„²/¶W¡Y8ÒyF&¢M†§I¢ ùŸo5ô¯ŒmŽd  (_pË×ÎÇð±ëÜH€H Žœ>™„_ЬÀp%àµ}žŽš)÷v%í¿ üã?ôx}I ѹsg=V?88žÜ÷   ž< 8>$@.E .V žŸVšܵJÀ=âRŸ•µ3111:{€Ì%’H›)Ú$ÒRÖî±}   'pHÀ-Y²«6,°žŒ€î ›  M áô̜žÃF_‹Ú=Z¡YHçãããu€M„›Ìq“èZ·nÝаaCж ÿt  @E$à€[¶lV®_€!cÚTDFì3 € $ƟÅôï–àŠ;úâú¶SÀII¹nÝ:œ9sáááèÒ¥ š5kæôÅBxëÙ   €p‹-ÂÚ-¿c(œHY„Hàj$%Š`æ÷Kq㚞Üþñ«1U®êJtMR¯]»’AR†DvíÚ­ZµBXXX¹ê %  (= žu[—bÈ}­KÏZ& EàLÒyüôõ»ÖíœdѶfÍœ(²µöíÛëDÝž‘   @a ž… böež‘ŽO @)H9s“Ÿü 7ßÙ7Ž ꏻm’òõêÕØµk—^›M²GvêÔ ÕªUs·®²?$@$@$@%LÀ!·`ÁlücnŒ·U 7Os$@$p1ó)©øá³yJÀõSîQ•mÑÓ-ÉZm"Ú6oތJ•*iÁÖœ{wI’    8JÀa·yÇJÜpOKGí²  ‹À…ói˜ðñ\Œž»®oÿ<=,Ų㠕Ž?Ž•+WjÑæåå¥#m=zôÐ ms#   âpHÀýúë¯Ø¶gnž»yqÚ` p˜@ZjŸùp6FÜ¥"pDÀy9\× ž>}Z‹¶M›6!++ ;vDϞ=å îÑ   rNÀa·}ï:\\9¿ßtŸ\ž@zZ&Ÿ~ЊÀõÇõ†ÅÃÛå}NNNƊ+°sçNÄÅÅé$$œzõB£F\Þw:H$@$@$PŸ8$àæÍ›‡û×cНpåëöÒ[(23²ðÅ;Óqëœ×)7N 8—ìDjj*–/_Ž 6èŶ۵k§‡G¶hÑÂ%ý¥S$@$@$@îAÀ!7wî\ìŒÞš\3÷è5{A$ಲ³rðÙ~ÆÈ{%7^žŸ.ãkffй~ýzö_D[·nÝtč    8ƒ€CnΜ9Øsh ÞÑÔ>±   L ''Ÿüë'Ü6f pcU®lœÌc“ŵEŽEGG£uëÖèÒ¥‹þp#   gpHÀInïá-è{cgûÇöH€*ŒŒ<|ôڏžu̕Āl"p"Ú$säºuë°oß>=—­k×®:í¿§§{,kPÁ+v—H€H€܆€CnÖ¬Y8pür%àÎ$ÇÙ€È>z÷q€§g"šj5cI`ý&/ŠÈ—ïúu(K«êºl^^H4ÀZEœ“-çTYõ—ŸŸ©™­Õ?ªº‡¶-ßµ}±åmAVf¶íÁ‘KŸþ>ÈLÏ2ÊY7ã\Šþfžöó÷E†õœÕ5øúù({9=ˆ/O«o§Åi[|6ëÊU?i'#[ûjtÐðÛä"Çæ%Ýgá`+*×<àãëîfð1/zÀWÏ²;o^?rµ£~Aς¥šmfŒoñ]Õ±Ù7ÛR—=•}û¬†d§}6n²Õ/k÷le …¶ñ°«o±(s/nÏ€y±öè ›žŠ~nÁœ4ž”óŽšëy_··mZm!(È*ÀD iAiŠk9ñA|‘6m"EüÑŠ ±£E†!_ D)‚Œ2º×"˜Ô¿Œœs”`ͱ ^ãÁÖe mG[ýŽ1¶S%†Š¡[ n äVQb-k¯c€¬Ÿo,£Œ.¢•²ÜC4nËŒWyVÁdo?O|•6­bË(c áªïµâ¹ðõQ¢[çåmçjѯÊÚÕ5~0úkRZÌ+»rMÚ3„[Ÿ°ÖïVD`érªžüÑå­õŒúÆ9Ouoµ(VfDkAf-+¢Îx^”xVÂ\\•[¡Ï+Q){ŠòœÉqbÂYeššxÌÑ8øøy£vdº÷k‹ˆš!Ð2Ü>xu’^np§‡áíé_jžäää`Ϟ=X³f vïލ°°0-Úd^[åʕK­]&   âpHÀ͜9‡bv¢ßm®™ûȁ“Øžr—ŽŽµïÚ šÔAhõPõÂZq •‘–^zYìt€M¿H·‚ã‚ïFdN>ÆË¹ì áa-c^·ÚÑG^ÜåM\tŽ®gw¬Å!€róԛžÔ·Ö1Û±‰kTП-y™ÏÑÂÔ°aˆ)ÆùÝ8.Z^ÞÞJ@‘A£¬u3ËèÓvÂXûøú©(aFÁ³i޲fÙ?ŒÒŽD”ÝŒÅ/•X¢À+óD¡È›ÓOÙ²™QYŽFð 1ª¢—Öֈœ\·Šn-Ð¥®Ušëf€ŒZ¬Ù³†P×"^×3D޹ׂËâeµ!‘Oõ#€úøä(¡lØ6ʙM‰0ëw-ÈôñÕ-rmñÌCZÉH»Œ-k÷bû†ýhÔ"Ãnïíè-(•rœ6Ãïž7vy>ž%چˆ¶C‡éd$»víB`` :uê€#m"àž‘   €+pXÀ>¹}G5p©ŸHô`ùüÍÈTCƒCƒtôàlJ€þ$&Ur)_éŒ]ÄÓNì]ÄE„=fDÍ1f‘C-ƬÃ3«ËR&°Ð šqV ÍÁ¢Ykq(ú$Æýcd™ú䍟pãmœ0Ž›žÀ«öCDÛáÇu2éëë«3Hʜ¶š5k^µ}    gpHÀɞñ»píH×pé©X2w#Z_ÓGÆ¡^‹ŸHQÂ-3ËËYìØ žæMcàŸ…­k÷`Õïà‰—o/“>~òæ ÑC»?_Kñ~Œ‘H®DÚ6n܈;vèÈhÛ¶mµh‹ŠŠ*“~±Q   žZ ž3fàè©=žöV×pò"6æ\;š#–/؂6Ý#öTÕ«eÁú$Pá ˆx'ÛÎÍÑØ¶~?îztˆÓ¹ÈBÞýnŒ7õzT ž ‡ÛÑ&‘¶­[·jÑ&CZE¬‰hkذ!3H:L’I€H€H€\•€Cnúôé8·}FÖw‰~=‹€øÕ±A³:ˆKjÅțKÜ:ádN\Dµsº+_Œ3 }®ïˆf­ë9µkŸ¿= }wÄÍœƒŸ×Ÿ'‘ù¡"ÚD°IIÙj×®­‘ˆhcI§Þ:6F$@$@$PÊp‹IˆFϛ#KÙÇ̯[ŸC§@ßûÇQtîÛ‡ŽTs¬"K‘ ü%/¯<Žl£žä!zÏq,·cŸñ—õJ²À—*×kP{ŒžV\•KL›¢mïÞœ:{€¬Û¢×jÑV¥Ê¥uJÒ?Ú"   ²"à€›6mšpœG8÷Wø+AYŠ—ø©ŽçaÁÈóé„óç¹FSY=@l×= „†\@œÈDݹ7ÿþ5žxõoª\²Ù ÿŒÜWïÍ@·Ÿm0²ÿð· 8SŽÄ [ï@Xõš¶.͟ò"5EóÜ¡›.ßSÀ}óálT Àm÷žjŸí#mmóõóA^~žJFâ‹:õ"P§~u,eҗ¿¡aÓ:žçæg”€ œêvi€H€H€H€܅€Ã.Y žn."à~Wi͏ËC«n·¹Ë}(v?V̙<µxqÕàPD6oˆêŶå*S’ñÜèažeÌÃ0òo6·^¹ÿv„ך…Çþõž«žêÖ~e IÃӘþÝ5œ1œ¶/Vsrrá‘*Úw2 ÞÞ^ÈUóÜ,‹muëUGpØÅkœýôõÔmP÷Ýò,œÃŠÕ.+‘   €;pHÀÉž3i'ÐùF×Èø¶jñ6ìÝuíûÜéŽ÷Äá>-›5 û·oÑsƒµlÊUCQ¯e«r/âÎ$&àù;†cðè{0ô®l<^Ÿoª„„â™÷>w˜ Ÿ€)à&}¡¢aÍë¢Kï–³‰6%ÜNŸŸ¿/$9‰dŒšª…›ˆÂ+mS¿YˆZ‘Õpß­Ï¡’7—p< ’   ž=‡Üäɓq6=]‡º†€Û°r6¯‹Gç÷¹ý ºR—ÍúY‰·­¶Ëö"®Aë6š^~7ONˆÃ wތjåÍ÷³õñŸ÷ŽDP•`<ÿÑWöŸ;³ãŠ€“!”’Ò¿uÇFÙüia;ŽïãΪ{ ’WzàBJ*ªÕ Q¢­:j+QæÈ6mÂbm Áƒ·ÿC 8Çê8b—eH€H€H€H ŒpXÀ¥dÄ¢Ë×pÛ7FcùÂÃèqãØòοXþ¯[øþX»ò’ºŠˆ ¯Y-»v/–mWš”w ÿŒ{†Üy?nüÛœ6—^Œû='îéwÆ»‚›nOZµˆÁgoýŒÃÕºkÍþ:‰Qôîcˆ?uçÎ^PsÙ՜¶ԎŠ€——¥HŒfüð;‚Cƒ0öŽ)àŠDŽ…I€H€H€ܝ@¹p{wÆŒé{píMºûý¹€/ÀÑý{p&!þ²}×±OŽïÝ·XlÎ&%`Óò%HOKE~^>RϟÃèGÿ^,[Å­.9âÁÇpÝÍóÿ¡†UÖm؏ŒöNqM³^ tlwï¿2 · ‡4:²ÞƒuÂáàëHñ˖™5y™Nf2îÎäQl;¬H$@$@$@îFÀ!7iÒ$œÏ<ÎC 2–%ˆƒ{O`ΔÍè=ü©²tÃém¯]ø+ÿii¶ºÒÖÛg!šj°íܲ_ŠãlR"nº·t" ±ÇŽàõ‡îÀß{œ·µûÌšÁhÚ¶#îáõ"÷ŠG@Ü{/Mʧ‡#8$šxFŠQkÎO+àïïù'*û”ÿÄ<Å@À*$@$@$@$pY ž_|éygpçÓ=]£ž_ŠnD¯a΍ •eçEŒíX»J¥]÷GÓ6íáåãƒÃ{wA~˜[Xu%ÞîyP%Œð/²«ËçÎÀOŸ}€€JAž~ԝ¬\³¿ûΝIF©¢aæ¶pÚd,˜:N_Päv©pâðŒùð=žïÙWйß@[•§F B»îœq×S/8b†eJ€€ž=õ5žþ׬Tô窞.Œs ,*[åo}Š\âša=   p; ž & !å8úþë$Î $Iæü€ÜðŠ!àÖ.˜‡ëVÛÐ^$âö(§†=FÔ®ƒëXâM¢yï<õ+áÙ÷¿@ºQº­×áÓWž_@>š±H­5§›SÛÒ9Ó1U­ÓöÖ3R­ä£#âÏÛO<€±/ÿG 6s{tX_ô4£Æ=éŒÇŒm(MÇàƒ—>dzÿŸûª†DŠ,#P¥j à ž¢Âcy   ·&à€›={6ŽÆD£×­µ]Æáý'ÕÊ è9ôi—ð§4X;_‰·õâÍlËqÞjˆcʹ³èsÓHX<‹–(ÂŽ5þå¿c÷æ øû»Ÿ©åÚØº“›“ƒ§F^Ìô4Œ=i¶Z«ËHçŸzÁ\Lüèm<«Òù7Ž+_Rönی^xOŸõšµ»F›•µîÆ î…n¿Ãî~°€š¢¿ Ð *_Œõžyó.øø8o¡ø)jI~rψ'•€s¡Û|XH€H€H€HÀ8$àæÏŸ}**Ò{Žk e:ƒ™“Ö)Ñò¬+0,5®”mÒ^Ä5n՝ޠæÅùˏã£ñïGïEûž×⡟y‰Yß~‰Vãù¿ÖÃ7eÛžlþï×/‰ý™ûÔzu{¶l@Vf*©¥$²V+ªþe«lW6¿xãœ\@œŠ-t™Ž ç!C(oRË RË Þ$ùÊÜIßBêæ«õƚµ¿F/nFØo5ìŽfd}œ™D·©²2\ŽÏ[.kïàîjݹ04hÞJ¯µw¹-+3SE$§aÅŒ™H=wu5ÑÓ^ëÆžH¥zuOà³}ßSäL’WӅï?‹íbÔ cQÅÇ5²ß^MX—H€H€H€JŠ€Cî÷ßÇÖ­[1àžzÈÍÏ*©¶‹mGÜ,%àz»±€;Ÿr“?xûOE5mŽ·þ ž–âEÞÄøü©?`ö„ÿᡗÿöÝû8tOL5æù×ЩÏuºÎâ™S°zþ/Z˜ ¿ç!›‰œMúä¿X³pž>'"Pã5P«^ƒKڔd*ßœ÷&^ýßD-ždKŽ?îº·?òô%‚+zçv5ÔóY) ª¬m‹à‹š]¯ýo’æóÁ?ñûññÌEøeâ7øuòm×âå¥Ú™„ˆZuô÷œìl%ÿ¿ÏšŠì,ãY¿ŠwÿË&NIINÄûÏ=†ž˜ã:±L¥*UqVÍIôöõÅ˟}§Û/ï[­ê'ðõ¿ÄK¢ˆ->~ýþLtéÓÃûݧœkDþK£ŸŽI$@$@$@E%à€[œz5V¬X[é‚óYqEm£Äˉ>‰Y?®wë$&ééøQ ž¬¬ÌËò‹TâmàUŠ71<í«ñX¢Ä×?>üê7kéМڳu#>~ñ)ÜùäóèzÝõøá÷±^‰.s{ò­ÕÐǎÈS‘°¯Þ|IEºV Ç !jøã=š3ê'™-ߜ𳚷pQ»+~…Ç¿wÑ»Ó'ŽáÕFãžg^B×þ×ÛÊK“wÿþ0džçm?¥¯‰€ûP Á<€"hÿüt‚Zz 1>{õ9ìÜŽw<þ&}ü*‡¢zºØÿÇV-8¯¿í.m㓗ž†D E¶îÒU‚Л›£3nþúã4nÝ^eÂì€ÌŒtüç±1¿®ŠÖ¬»cŒN3óÿ>Ç¢é?ª€/«ä/£âéʅ‚«œÂÏ_~‰þ[°Ÿ3üýì??cÀM]0°ËßPÕ××ÜH€ŠÖ‰ IDATH€H€H€‡܆  Ã(ÇüýF$€G—9·ƒ*‰É¯Ó7£û`7]F 'Èž€“Gbþìé:*d¿•”x›+Éãßµ‰Gn®DŒÞö-Ríف­«—ë!‹‘šêì”QMšã5äÒÌlÙ¹ï@Ü÷Ü+6ӋTËJèÈVx±n9'ÑŒéJX~0mŸR²?ž_ õŒï’a›YÖ°Ek%&o@xš*;çn̛ü­ªåÿþ8GÛxçÉqxßnˆÅÇ×ÏŒ÷™šÓW ώŠ6]zèh d×VœN$žøÏ‡ /X̜÷׌C'<ñï1O הH]°*ÓïŠ[Q»^C}‹Çìï¿ÒQžGßx­:us§K—©Ré$Šó?<ÿöœ¶$6ÎpøÃW'aÄ=סwÛ[”€+ÿ‘Lg0c$@$@$@ƒ€CnûöíøùçŸñôË÷áøùeN&z÷q̛¶É=#p*▟‘¡€GŸæ«†çý6SDœ1œ/ªI3 uÇU ›Ž¿2‡ëÅ»nV¥ <šæÀµêÔõ/ï¯$<‘H•Dœd𢧻Ÿ~Q¿àË܉§O©%æãóןGÌáƒ:ŠV(ۅs)j·;ÕòIú»džü÷„izø¡¹ÍŸ¢†uª% Þýi®Š”…èӇöìÄŸ‹^x{÷Óçv©ˆÚø—ŸA%ޒããÔâæÑa)Ѷnë²/Þ=Iq§Ô0@ ÆœúZwî®Ï‹(”ùm/|ò ŸúÏËØ²r)úyQŠKY4ýƒçGüÉz×èuÃ0üóÞ[uÿCªEèHŸý&ÑF‰NºÃRõŽ;ÞéC(ßyá;Ü÷Ä0tj2Ápîð(±$@$@$@%DÀ!·k×.-àžùç#8˜ò{ 5]|3ûvÁ¢9[Ðmð3Å7âb5Õš?uKƒ‡UšÙ»w[6¬CUíéÔo€ž·U’›¡¯þý²®ÙÿŠQè=ø&„×4GȶôŽT-VÌe¶­Y/ÿõ¢Ÿ.Q·ç>øRÏ“mú7Ÿa±Bøø›`Áϓpdß.ŒöõƏšØŸYš[†-Ɲ<Žu‹çëH•ˆGSäIœYß~—?ÿµë7Ôv¥îÛ*Š6jì“è;|€>'™0%2öʗõ¶­k–kÁ(sìÄfµšÆÜ)RùȐ>zˆ€ uŒQ-·`nÕpÊ ¿/ÐË$ìÞŒ^‹NÙ$*®êËpOYoOŽDîޞ4K Çoÿû†²yíА¬™vnӉdšš5ú$鉻lAÉ*áË{xñ]ç&1yûðð‹·¢Mö‹tœì    \5‡ÜŸ}û0uêT<þÄ£8’µðªœZ»·ƺe;жû¬–¯Ä“‡šW¥Ô™Hš‰W†øT‚G ‹¶Â÷@„Š ¥<ª²ŠP«ÕJPJôI„ +|] 1ٖý2S>ÿŸjîš$ë0Ş\;œo=~?®1áÕkâÇOßÓÂF"mTbí5ö -|dnÙç¯ýC ¢õzØå}ÏŸ¬,Ÿ;S-*þŸŽbI4K6}¯?t:õ€1ÏœªÏ}óÖ«ØŽb‰ZnÀ˜sw¥-[±•å*U®Š7ŸùÉ&¥ü*•xEæÄýý¿Ÿªùmí°vño˜¬’®¶*e{ªÈ›DõÌa§2§oØÝ\íãìÒõýý/`æWo«!”÷š,ž%ûÃÁ•:ž››‡×Ÿü oŒ‹šÊÝâåҌè    8“€C‹5yòdÜu×]H ؊¬ÜTgúxI[lŠÆ†•»ÐŸ¯­'â-GÍu«€æ|©äj¬¡îwŸÊÚèác ?tƶwÛ&-bN;ŠøØU­ŠšÆÍÐûƛўU[í‚,ð-Âë¶GžÒѺ›, è‘×ÞÑsÑV͟«“~DªûƒGß«“€˜›œ—hޞ-ÑE% ¹W%)‘Ä ¯œÍÛwÂcÿzO•HàK÷݊ÔóçðáŽz©9/­nÃ&j »O/I†bïWôŽmzsYóZ–:úöSÙ{BEÏ ¿dXh’Êz™~᪄†©(áoaã^}m»öŽù'ÉWdáóš‘õœqkÊ€ÀÀ4LûâM§.ä}úd"&}ñ›^{.²rW„ú¹/ß2¹©l”H€H€H \pHÀÅÅÅa„ 2d|k%à\Vl™vzۆýضaZ÷|¢Lý(ÑÆÕ0Å|5óÍÃ×ù*âå¡ÖKË÷ò†G@`‰6SRÆÎ=ƒÊ*‹äå6‰ÚIĬEÇÎ7wîL²mŸ›TÚ¿c«ZwÌû¢áˆ"ìÄnû} Q§„î;O=€£†2Ôò–ûAÃæ­µžñ¹cÃÈpÏ€Ó±x]EÞ̄(;e-8A-i°qé"•Tå7øVÒg§ý)Ïø AjîÞp•¡R–Ok)I‰Ø­Ö»“Ä.’xEæ–çd&AAZÀ=ñêíªìœgqŠ°¯\Œ cŸœªöEOõ¢Þ2–'   ·%à€;§(þR¥ïÙ³'ê¶òG\ڞ2²yíìÚr-{<^Š~”dãùJ°©›µÒµaV 5Ì,˜wV’m¹“­ôÔT|óö+zŠl2üSæŒÙo-¯éª²Wþ[EàŠɔä)’ìå¥ÏŒµãd“6暌“’uÓlO†‡Ê"âæ&ÃAyý¿¶5æÊ+÷å3ÞÀœEhµ‚D3¥Ù—ÕK¶!æh¹çQ4ïöh™úQ’‹ðP‘7nJ…{n¥ $I²ÊD),CUҔF-Ûè¹qUB¶s¹‚ÏŒŒJÊðΛDúVý6§U¶ÐŒŽ4µ4A8"7Uí^ã6C+×Ìý†îƒš†5¯Š££•çM] ‹·nRó›‡YD¹‘    pRð“O>ADD†Ü2û’ m. ’ÀäèÁShÔñ¡²hžmº1™ÿv@‰A‰ÚI¶OùþԈAžeÌÃ0òonÜó+wmÛÒÐ¥OkŽê`d-ímò—¿¡A³:žqÐpÔ r|niûEû$@$@$@$à p'NÄùóç1îá±Ø?Uù~ñ05gvfÅ­H8•Œš6÷;³Y¶U˜ ƒwé7HÏ_“¹xœð€-I@pI÷¬û ›F [ß6NéþçoÿŒ~C:ãº.#æïÑ蔎±   ( ž3f %%·ß~;Ž€/EFNJ 4_<?}œPe#LCÛkŸ*žÖ"+˜ö¿O°d–ü@ÔiÐHÏ}‹SÃ#ßüö狖KšH×/øaÕüpۘNéöû¯LÂ=ÜˆÍFÃßË9óîœÒ16B$@$@$@%@Àa·dÉœ>}Z'2É­zg3—@óÅ3ñÍG³P)ÐM:?šÖã\±âQd­ËùskÎÃÏJÈeЧé"[·Wë蝰À¶-û~Ÿ¹žó‘ÒŸ–ž–÷^ž„W?xH%0¹Õ¶x|……ÏŽ“   @! žõë×ãøñ㈊ŠBþ8•º³Ì`NüüW4n‰ª5û«a~eæv_’œD– HINÂ/Ÿ0•¥¢n§ÌDnv †ÿíÚRG°wÇ,Ÿ¿ÏœüšZB _©·ÇH€H€H€H ŒpXÀEGGcǎðóóC÷þ­qäÜê2ëë×ÌD÷~ma ìFWfw WqG#íÜQŒŒçºRïò¢9둞š‡Ôš~5+9gÎ]©wŠ    @ pXÀ%&&bÙ²e:‘Éè»F`OòŒt£hŠŸýxÚvjŒÀðk)àŠ†Ž¥I ÈmŸŠÊ•spý-݋\·š~ølš·©[EUßÚE­Îò$@$@$@$àöp¹¹¹øî»ïP¥JôíÛÇr©<”‹;“ÔôïGxDUTo8˜ΙàÙV…$°mÙÇžŠGSõ£I“Rïÿ»ÿüw©&×µ~^žÅ[xœÔd$@$@$@$P†pâã”)SŽ€«W¯ò«AzΙ2q}Ýrµ܁Sè~ýíˆOš\&>°Qš‚‚20ï‡w1æ©ášTª]NœŽ÷_žˆò4Z„-Õ¶hœH€H€H€Ê+" žE‹ÁK-nl±XÙÎÉGË€ßçRRñÕ»30öyµ€Á±úÈ̲”‰l”ܝÀ¡?~G^nœ¯ôç¿íýã0V-ކç_ú;¢*wswŽì    ‹@‘ÜæÍ›‘‘‘˜˜ôÒ §Sw«Ñ’š4ç§ð÷÷Aœ±g_͒0I$@vÒÏíÁñ}«Ñçú¶šU·Z©³™?c d‡‡î}áþKœ=6@$@$@$@å‘@‘ܱcÇ Ù(eAï6]#qÞû@™öùÃW'cÈíœPµ%bOqÁß2œlÜ-øú䪄%ÉH>¥†)GCT£Zh×¹ôçŸ ŒñoNÁ #»ã†.÷#Ð;Ô-x²$@$@$@$PÒŠ$àÌD&mÚŽAZn*ÕK*iŠl~Àµƒ¯ÕþHËð.r}V d®›gN ÒÎÆñC§T5@Ež}ѹw+§à9¯†EüÆOjïqh>Ò)m²   (Š$à€ƒ¿üò 4h€]{·£Q/2ïs^^&}1gÎd"žF4lÞ>j­:n$@NÀbÉCNæ1äeÁ…”Dxy[P­Fòóòqþ\:÷jé4„ë–íÀ‘è“xì‰GY¹‹ÓÚeC$@$@$@$PÞYÀmݺ"šöîݍú=óà੟ì>†Å¿ÂÁ}Éðõ÷VË TAH˜9œI:£¯„U‡§§§õã}ì¡¿{šœ‡‡|Ô±ÚËy¹ž›“ 51G-™ þäË¡þ—ŸÏrlÊÞ<ՖQÏvÎúT˜ßíëvo/dgåØl[­^òAõÇYÙÆ}³•·Ú7Ú³óA_å¢>È5£·Š©‚²ÆóQ˜™§Ÿÿ—l…aÚñ»ŽðΈ/êïšþš/ïlǹ9б<.ê\nž^Ð#?7yr¬Îå©e?„Q^^®®'{ã{.œƒ—å¬*™‡:õÂT%•‚v!ɉ)hÜ¢.6«ë°›%Qð»ñsѲCŒü8*y—þ|»’ð™6H€H€H€H ,YÀÅÇÇcíÚµ CŒÇ&5G&¢,üŸb›éyHŠKÄé˜Dœ?{9ê…6þÔýb€öùÈUǹò2¬÷ê¥Öö²k\“—äšåZÉLJŒ ‘ ”_ÿÃG÷ÅÐnÂâÁ¡Ø¥š†I€H€H€܆@±\\\–¯^ˆà&°{Û!ôØÁm °#$@¥Oà°Z÷mîԕxíßÿ@œÊ=J¿A¶@$@$@$@n@ ØNúþ㔉šÕ!VîÂ5=Z J0žÁ3Á.€SL‘ä%uÃp÷ˆ'QÕ·¶SÚd#$@$@$@$PÞ \•€Û±c¶œƒÊU”‚ö]š–wôŸHÀ ’Õ/Ÿût.~î6t­w§m1u'4Í&H€H€H€H \ž*—™™‰ñß¿„ŸÃÛaÉÜ ŒÂ•ëGÎ“€óÌžŽ A~žãö{P»‡_;<["  (ï®JÀIçç/‰TäCûN {¿¶å ý'(E§b1ý»%ž÷‰¡èy3ŒBJ±5š&   ÷"pÕ.++ ÿßkèwKK¬ZŒ MZF¢Z Ÿ¹×cÂސ@Éøñ«ùš­²ÖžŸš‡ÞXr†i‰H€H€H€*«pÂhíºU8™¹ !Ø¶~úŸŠ cI€ŠJàđӘ5qÆ=?Q!ÐŒš&XžH€H€H€*4pyyyøì«ÐýæšØŽj7ª×EzÕ+4XvžHàR?|6ÍÛÕGÇnÍÑ:ìxyú    @”ˆ€“ö¶lÙ‚Ø  zcÌSk; ݧn°( €»عåÖüþÆ>7u‚®Až#wï2ûG$@$@$@%N ÄœxöÝ÷ߢíõ•qüX N‹Gç^-KÜa$(âÎ`îO+ÑoH'ôh;”â­üÝBzL$@$@$à"JTÀ>|;÷oB¹Jé"7˜n€+˜øÙ¯š×ž&n»i ªpœHWž'ôH€H€H |(Q'–.] ϐ$T®™_~ZëGt‡··Wù€C¯I€®šÀæ5{°mÃ~ŒþÊ¿(Þ®š&    Tt%.àè7ÿ÷: A||öí8ŠžÚUtÎì? TH±'°`æZÜsçýèØôº ɀ&   ’$P*.&&¶®@œ.سý°ŽÀ5jQ·$ýŠ- '–šéß/A¯.×áæA÷ºž·tH€H€H€ÊRpÒõÕ«W#Ó7Á‘yØŽz"j† n}.-P> zIWO`ê7 Ñ NKA»Uáíㅅ³Ö¡{ÿ6šàÜ^²5 §k.$XðÔC¯ 00Ðií²!   šJ]ÀeggããoÞ@ß[šiž³&-S‹|÷†§§gEàË>’@…"°ô×MðÈÂ7?‚ˆˆˆ Õwv–H€H€H€œA Ôœt"éL&Íþ=7×}šþÝÜ0²ýœÑG¶A$à«mCÆ_Œžá^4hÐÀ -²    šxœ"à«dМ6ÿKôfˆžù3× Sϖ ¯Rñš³Ç$àfÍ^‡KuÜyóÃæŸ??Îý ×ôÔ–/؂†Íê vd5BBWH€%•™Å³6£zåŠp퍈Œ4þns#   (Np҅øøxü8çKt\^^lX¹ ¡Õª¢aÓÚ¥ÓCZ%(q±IØœ6¡þ‘2dÂÂÂJ¥%   ( àt'M§§§ãß¿¶}#P¹j vn=ˆ çÒеOkÞ r@`ϖÈIA^Š£G†Ÿ糖ƒÛFI€H€H€܀@™8“Û·“?EDó|ÔšŠØã :×­okµèwš eHÀýœOIÅ®Õ  ¬¿ :Ôý:É‘   € (S'\~Y0 YûЮKcäååaíÒª€6×4valt*#{ã‘|È þ>UÑŽiStìØ±âA`I€H€H€H Œ ”¹€“þoݹó–OF§^ÍQ­Fî=¡?{4G˜šǍH ì$ĝÁéýÙðÎC~žÈùnew;Ø2   @'àNîAJZ<&Îùþ•ŒÐ®s€^HÇæ5{àããV¢RP@¿Uì> 8—Ày5/uß¶x§G È? 5kÖD÷îݝë[#   žˆ€Ë8ñ*3÷Œ&Mš qãÆ°X,زc=vîۄð(„ךŒêj]9n$@HKÍÐë-žҒ=à¿K²,€$)áF$@$@$@$àÚʕ€3QÊzqû÷ïGtt4dŸœŒ€Ö¯_11'°ûÀf8¶Á5}P³Nª×ƒ··—kßzG¥DàlòyèÌ©lœOÌCp šPšï‰jÕª¡Q£FZžy{{—Rë4K$@$@$@$PÒÊ¥€³‡’’¢ÅÜñãǑ››‹Zµj¡zõêHË<‡}G·bÿ¡?P%Ì¡j=¹°ÊêSÞ>t%ý Ñ^ÙÈÏÏGrâ9$'€èý¹ÄLdóF_8òs=õ’I²nݺšZ•ë+–ý£$@$@$@$Ptå^Às'OžDll¬þêaaéùI8•|IçbqFœØúúy#X ¹àÐ -ê‚ÕÇÃãèôXƒœHÀâá ‹§7Œ<}Ž ËHÍÁù³éJ°C̱8ЈSë&úÁÛËžðFÝZõ©[:uøŒ;ñ^±)   (-n%à CJJJÒB.>> 8{.–€ €#Ù¹ÈÍÉEff6rÔÞG ³ ¬ä€J~ òW ‡Ë±¿>ççïSZü‹mW¢-òÉËS{õ‘a¥úX“ÍŒ®¿ê²…ÎÉiUG—µ+/_ìëj{öç¬eµAµI›í™mŽgßAS$›ZÙ&šíÄsák…ëh{ÖB¶kÖFìExm㢭¬'àéá O‹ú(;žj¥§Þ{YŒU9O%’ä»Ú«ó2ÇRΉŒ—žªúø .=§qëö.*gN®(›"Ä,òQ‚K}Œ<•@Ó{U ٙyÈLÏFêyõÄ&$ëçX>ò\§ŠŠÚ†>Ê=’*dqhhšþ„……ÁÏϯØÏ+’    ž&·p…‘‹È9{ö,Μ9ƒqшI؏ØÄ#HOã<—IDATÍDzZ†Mååæ+q—§„]žJò£^®å…\œp{yéõç,ÞåPÇJôåšë qgQ¯Q-ã…]¿Ü«ŽèQ{UÙQV!aÈ ˆî1c~†žÒ2H‰*ãºÞDxÉî‘dJ$XÄ‹— ^Jpøª—öœ,å³ÅðE„Š)J<=EŒšsª/bW„ŠnM:(eEØšc-XD$YËj¡sÑ9£¬Ÿnڐºv厀ÿÔu£¯ªÏê@Êä©~ilbÓŒSÂ*ßhÛЍÖòIÿÛÊQ,jŸê\®º¯Š}©$Õss€!$²bÐØËP[ÉÂ(σ›ó{áóŠOº?ZÐ÷Çì£f*¢ÏîŒùœð9³žìeèoDD„®'s9ÓÓÓÕ ™ú8++Ë&ÐäzåʕmÂ,<<!!!šT©’ )‚MüâF$@$@$@$àþ*”€û³Û)/íæËsᜌLK¶>y闏›„GŽÑó‹ oòâmŠóšŒh‹`0_äÍëfYó…_ÎûúújŸì_úímDáòôËŸøY=+‰3¢sHKK³‰{!b|¹¶Í>˜>ڗ)|Íüîãã£ý’Íž…}€PÒ׋x±/Sž¬"“›ÙGû6ņ{Qe/ž$%~Ÿn~~bÿr×EžËµÂíšþÊuyÌÍþˆßòlÙ×5÷ìÙ£Ÿ‰–‰ÿ2äWü”œÜ'±k~·.ºÿ–ØC    + €« ÏÆå…)H ‹Î+}¿œ@-\Öïå†8®ö¢Ë^ ®KASA\v›H€H€H€*8 ž þ°û$@$@$@$@$@å‡\ù¹Wô”H€H€H€H€H ‚ €«à»O$@$@$@$@$P~PÀ•Ÿ{EOI€H€H€H€H€*8 ž þ°û$@$@$@$@$@å‡\ù¹Wô”H€H€H€H€H ‚ €«à»O$@$@$@$@$P~ü?±³ ­PR þtEXtapplication/vnd.excalidraw+json{"version":"1","encoding":"bstring","compressed":true,"encoded":"xœíZÉrÛF\u0010œë+XÌÕbf_|£©]²ÍHò\"§R.\b\u001c’(\u0000\u0005€–(—o¹åJ%•«#•|B\u001aD€ØÄÈ€+r\t\u0007‰À,è™yïuO\u000f>®5\u001aÍh:6ͧŠ¹Ž-×é\u0005ÖEóIüüƒ\tBÇ÷ ˆ$÷¡?\tì€æ0ŠÆáÓï¿O[ŽltÝÊžfdŒ(„z?Â}£ñ1ù\u000b%N/i;=âçô¢}±~\u0011luwÖ¯¶Gm”4M*Ý\u001a\u0013\u0018;²ŒkÒ¢Kx®˜žÝOá\u001ecÑBÙK̊/œ^4ŒW|ölhœÁ0‚‡Tè–Î^lVçú­O\u001bhö$Œ\u0002ÿÌt|×\u000fbÓŸ»~SjØ©eŸ\r\u0002âõÒ:ŠØ\u001agŒï;®{\u0014M“ža&a֚¹þßÜØ‹sÏ«ZÁ\u000b\u0007Cτá\\\u001blÙN\u0014O\rK\u0007\u0010\u001b7Þí%kòSŸû¡\u0015Œoºi&ƒÈ\u0018fLŒfŒ\u0013®5ÊÌc\n\r¬pþé\u000bßK`‚)aTk‚鬆\u0013n\u0000>¢€×Ÿå†&ÃøÍ›yìdñ“ÁÐè­{@ƒ—gÏ_‡Ó\u0017ûQ¿\u001brҟ™=‡#+\bü‹æ¬äӓº~y\u000fíî]\u001d{';r\u0018Œ¢N÷Üm\u0017ë÷æW:»“qϺ\u001e(\u0016Œ2D9L\u0004¥k\u0019+rÌh¿?ÖB^­\u0013ÙÝûádïrc}3\u001bXÿ\u0001¢|\u000e¢ V\u0010ýrˆbʄ¢\u001a—B”¢*ˆÂJC\u001b!ä²!ú\u0005ª¿\u0000D…ÔœÕAtûjûík}ˆ‚Íç»'\u001doÀ÷7®î\u000fQÍ\u001f!º\u0004ˆ\u0012\r\u000bGh\u0019B\u0015©Bšà‚0(_:B¿ ~X\u0004¡D0^ƒÐwíé\u0004›Þ\u001bÒiûz\u000fœØ±6ˆ*\"42—Q\u000eœz\u001eœ„š\u00028±ÒEp\u0012±\\pFå…c+€¹®\u0000è⇓À¬\u001a¢\u0018-\u000f£’ÀÖZPT\u00161a6\u000bõ02 ecžŠÊڍ|5­ñø(‚ò\u0019ýa}ÞÍØÒΛ\u001f\u001csñ¬ì\u001bÄäŠ{Mè\u0017cÓÄsþñÓÚ§\u0001ßf!¢"}bÁºIEND®B`‚fulcio-1.6.5/docs/img/create-certificate.png000066400000000000000000003144671470150653400207650ustar00rootroot00000000000000‰PNG  IHDRšߎЬ IDATx^ì`”ÅÇÿ酄„PBZèœ)Uš(EEñ)(ö‚ˆ‚¢‚)¢   Å*œ÷ÞkRHƒô^ïÍìåÂ¥‘»ä’\¬ïÉݖÙß~w¹ÿ7³³*"„€B@! „€B ‚ Xˆ@­àá…€B@! „€B@*‚B@! „€B@˜šf± b„B@! „€B@ˆ@•k@! „€B@! ̂€T³X1B! „€B@! D Ê5 „€B@! „€fA@ªY,ƒ!„€B@! „€"På4YЀÝÒoBC‹ìTXxô£Ï6BG! „€B@!PnD –êŠ(==ÉÉÉHLˆCBt’b¯#%1ÉQHOEFF23³‘‘•‰žÌºž…Í|¡Éc¶ö7þ œçu¿ëžÓocaAÏj4Ô&§m΋\W÷ÜíÈÐ9œêåœnnUÕ=oiMv^+µ• {NûŠvlþ×ٚìB‡×ŸŸ¶·[s/Ѐláy65VŽ)–TG7žz.?D5œ@õòŒ¯ë gà[,ó­NŸzúÜ WÄŒµ&h`ccM×DŠ–€^¿ŒúhùµÜ×óA+ĜŒèÔ¥A–éU,Ø&ß:Ò©••]»Z[ +Ú&¯ýyåoÇóÌÎ?–þ\ H±õ†Óomm¥ÞgEÛyë}’¿N¡¶æŽQüu ëOPÈ[#ÿºÚØX!=gýó£ËcK7ŠþÄóR×è_sºµ/tÁò=©ýÑ®a>ãílm‘š––§A±×¿õ, çPäâä{AË ïgBŸ·Fžöô~JMϹFõ¯í,ŸýºIúL1d2¹‹«×OaÆP û°Õ[î/Ï þ°Ì÷GJ+ú [Ä¢¿±èúÕ¶Í/€nAøCEÕÙFþ”•U„ØÕûã’+Š‹ø‚Âý[[å뫈/E}øëÏ@÷E€`ÝÛ|ËÐ}ÓÎýcr«Ç_ yþE +Œ•~UŸÞ2ó1»í÷6źàh¹ÏèìÎoOQün3ۖ•]ð‹[~ކ||°Í–Vt­q}ÜêCûE©°’ÿùŒ_ˆò¶žwÕ}!chû¿õ‚ö§Â)nT˜/Àú=ä·ë6W`VôùÄ_š ,m!2ÄŸBßûjƆYUØgW¡_ s Îó¯ÐëXW5·ïœ/‡†\cE×É;ŸÂ„”Z¯œAµ_ԍ±0ARTÅ}&èß Q¶gJ¡µõçC­ô9]ØudغkYŠðµ/êfŸ˜¹ý­ès£0{u­ å“_ØåöË÷|nC¹ð?­ÅZPHw£°kN7ŠîšÔý-ËsC³|ùÇ*llýñøõüŸ¿rkEïóHËðօ¡?&÷Åz-ϘùnØëO£°z¹ë­oFî2í ¢<6çÔ»e‡ÖÂlr:Îm›¯neÉ7òõnlæ±OﮌŸiºïUØëìÒëï T¯Ú5”8åïP|3"ƒœ%YÊa’¥n”§€fЍHíC‰èœÏ¬êNêýèìdêÎàß]\ªÁÕ­&\]k¡†»'œkÔBu׺°Ž­Ø8ùwÍ5҅‰ ˆ@51PSwÇÂóêÕ« Cdd$nÞŒ‰šš(%F³èÍëáá[ò"8;WC 'TwÔ Ý@rqȀ»SœíàTÍv¶ÖÚ»xR„€B@! „@%#N‘(iꡬÑqIˆKFL\ âSŸLÿŠ*aŸ”–{s€¬›«®”©ˆœ¢mšÕC¥Žrњµt#„€B@! ʝ'jâ“.‚B¢pþr˜ÚϪ¡|1uj¹¢K—»Q¿Ù]š]¿“$]*åʈ@-@Mv¶o\£v࢟ Қh× ];4¢œ€Ÿ^ ŽÒT! „€B@˜5ÔÔt\»…³~¡8u!XyWùdN»¡UÇ{Q§~+³¶ß\Z‚•9ºöìø'NG‡ÞhגDiÇÆt0·M z“&B@! „€B@TvA$V/]À‰sAH ð`—îèqÏ}hÖ®ÜjÖ©ìÓ+7ûE ˆúZÀylß°‡íG-w{tïè‹þ=ZÀŠOþ–"„€B@! „€È!ÀÙÏø…àà‰+ôŒ|6CÞ¢e‡{„Q1D Þ& »6¯Ä¶Íÿ!%1 wµk„>ݚÁû•"„€B@! „€(ŽÀ:Vòԅ ;€’)õë?z>WwñªÆNj!Tn^Æ?.Åî={ЀÎAЫ%:¶®_ܵ'¯ ! „€B@!  %––s—B±eÏy:Â& ›ŽÀœƒ‡£~Ó»…˜šz0¯Åêe?â‚_în×ôo·â-•wŒB@! „€Š#H™€÷ñÇ%:sÕÕÍ C†&m‡ÕÁtƒTҞD ÒÂ]»ž®ø×0šO éß¶’.§˜-„€B@! „@e!˜‚݇.aß±Ëpuqă F ÊláèCS°š,Ó0©wŽ@ ö߇¿-@HÈu &azß=’ Ú€W—t&„€B@! „@±RèȚ}G/cëÞ ”=Ѝ[÷‚…S3ÀúΊèŒ#j|øi,]ø=._Ÿ†‡¶Gï®Í‹œh€‚B@! „€B , dffáðÉ+ø{Ó øÔsÇctFï°pŠGµ†e9ŽÙô}çTéq~øcù|ìÞƒz·ÆCڛÍBˆ!B@! „€B@&ÀBuÃÎ3Ø}Øm›{ãÑAáT³),jö,mª4€ª/PI˜j’°kã2üµnÚ·òÆSÝ [[ë*œ°29! „€B@! *7„ÄT¬Ù|/‡b 9Øîéѵhª­{åžØm¬¯ºU ÓË»Ž?ÿ¶66ÖxqDOÉÊ[e/e™˜B@! „€šš"oÆcáÊœÐh²ñ¿'û v©Õ[WÉÉVAJÂ4ñ4±'±zív8€á÷wF÷N«äÊ€„€B@! „€ž3ì;z «×CÏ.Ÿ>l(,=úRȯm•š|š$Lü¡‰;‰+W®àÇe;áÛ 6žÚöUkѪÔ(“B@! „€BÀ`©iøõ¯ý ‰Æ;/…{ÓGۚ·7÷ŠU@ ²0õâNA“™€ÿ¶ÂAòš>ûhw4m\ÇÜù‹}B@! „€B@£ \ }©³o§J0àÁQ°piktæØ r ÔÔ0dߨd%ƒã²^±NÕl1úñ^ô¯œ9ò›„€B@! „€&!••ï~Ù M¶ïŸñ?m–_+;“ô]QT^š•†ì뫁ìTœ8„µ›O¢O·fèӕ³•"„€B@! „€žClÛwAeû}ÜPøŽ{°«Uig^iª&r 4ɁX³é8Îú…â¹ÇºÃ«®[¥]1\! „€B@!PRqñɘüíZ Ü œ=E!¿íKÚU…¶«”U“x‰A›(Õò@Œ4²7ìíªöµz•ÈàB@! „€B@T _ÍÛÏ:5ð̓R–ßþò[¹¶>V>JûM¯šåkö¢yãº:°C¥žPÄH! „€B@! „@yX¶æ ®‡Ç`üžGaA"ÕŸò$­tõôŽ9غmºuöÅÝí•ÇúÊB@! „€B@JE`ÿ±Ë”§çŸšø8…ûvPXX˜ý*•@=Žcì\ƒ{{¶DË&žfW B@! „€B@T«A70}Á&Ìùl€ò¢ZÖº—B~*ʃƭ4u×öõ8±k)†ôo‡F>MN* ! „€B@! îd7£ðÞÔ՘ýéSprvEûaaën¶H*…@Ýža.ùö€gíf S B@! „€B@˜ÌÌ,Œöñr̚<vN°ô|”Â}-ÍÍLeÙ ÔàØŸµx°»+Œ=ÍWé›åêŠQB@! „€B@£ß[L"õ žxu……k³äbÖuyNƒ¯^Ä#Ý,QÓµšY£„€B@! „€•@zz&ޘò;ŠSâ€êŸvæ·uÒlêæÍ›:guÝÌ?ÛTež ÅF! „€B@! îlIÉiŽ'uŸò"?I1µVfÄ,ê¶mÛHâŽgwxW¿aVÀÄ! „€B@! „@e&—„g®Å7_} ÛÚ=Íj*f'P÷íۇ+W®àîŸðu:gV°Ä! „€B@! „@U pùZæ/ۅof/UGИK1+zúôiœ:u M›4F¯ 3Ñ\8‰B@! „€B@*E`ûþ 8v.ïŸÔlB}ÍF rHï®]»P»vmÜ×Ùš¿*µø2! „€B@! „€¹Xúç~XUóÆ3c§˜…if!Pccc±víZØÙÙaÄÃ=‘±Ñ,àˆB@! „€B@ªNà›Ÿ6¡cÏáè?ø‰ ŸªYÔe˖)O=1 šÐ?€ìÔ SZ4K$kœ›"»:á€FµmQËò*ÕєvÈ2mï%s–îÀ× § EÏ©LÎ…€B@! „€09>~fÒÌu7~4llòþé°Âê?ÿüƒ„„ÜÓ«'êٜÒ"±ß,ëfk¬àŸÞ )ÙN·µïä…Kèܪ9<àž~ȬEêŠcä?áàš‰èÒ®¡Yr£„€B@! „€(«Á71oÅ)L›¹¶¶¶%ëÄ­*T =z—/_FÆ Ð¥Al‚)U|Q™u”Ñ¢XCtÕµ†3²BÍZ€._sÏŒµ[–œƒ~ݛ;7©P2¯}Œk6@›fõðńah×»dI+! „€B@!`$ÿ¶ÂÕXŒñÎd#[š®z… Ôëׯc÷îÝjßéÐ^®Ð$˜nVÜSDf}„fïךlrY‰TŸrÆ/×Ãb›„úõÜñø.tgÄÚ`R¿ýu£ÞY„u‹ßÀ Þ­ n' '°fó 37·¯Ï¯Fá©GºމÔB@! „€¥ 0}Á6tê; ÷TŠ^JÞŽBjVVxß©……žè ëäªuÞ©N j²5ð»„ìììܲ€êÕ©…êNŽÈ/PM%RYî=rI=vôÃåkÊÿ7¢~üâYƒ¯œ%ìÃè÷cNJ÷pÏÝM nw'VüsÃ1xÕuÅÝí5ý—&,Å•{0ñÕбµ&|ù'o`ÞÔ§ñâ“÷՗©+=} W‚nšæT²²²ñÔë ŸŒõ‹ß„••e‰Í+麕x@44×u1ÁÔ€ ! „€B ‚Ä'€`Ö¯Ç0úÕOáããSîVTˆ@ݰaƒÚwÚηšž…•û€Ëz@}jbR ²²³ô*àèèk++œºx [5…›‹K“JâIœ•€Éß®ÁæÝçp-$*·?wW'ÜÛ³Ú6÷‚§,--á5î5ªaÜš~£Xžb^ú`)Žüû‰§ú·«ˆŠÿRxÂÉsÁ°·³&¡~ÓÆ?ŠÖ6[¥y¿à@‰€NløØšáú?9—#quï—jb⒔Gu÷áK˜ûùHŒôTo£ú3eå1ŽöKɋζÕñÈ{œšrcû:~6]ü\5‹=3ÎNöÆv‘[¿€ëVâMÐÐ\×ÅS“.„€B@ $pèÄl<’Œ)Óf•»å.PýýýqòäI8Y'`PGóÎ\[ÒÕКiié$PoyP¹O k¶°ŽÀ¥ÀØÙX£¡W=ò&çÍÇê4\¬" 6áão×âóÙÿ©ú>õÜðÜðž¿otjS_‰Ò–y¿îÀ«“—ãü¶ÏЬQƒ»Ûº÷<^ÿøwLxe0žÖÝàv%­~#£ßý›Hšë—7Fߋo'•OÚlß{>@Xd’.Þ ×Õ·¥(&-ûO‚Ý8Øûç„Üêiižÿ¹ï°ë?Mß-ڊž]šà»Ož,)¢µ{aüb,^œûÿþÀhÏp‰4°Ñ[Ÿ®À÷¿lƒRýçتðjÅ­Ûé !xsÊïjvi<µÆÉ7)âSðÇŒ—áRÝ1Oss]cç(õ…€B@ó#0sáŽìößÿP¹W®•C{/^ «¬XŒèãD{ ­Êu²å5˜~ˆïÙKWòxPنõ‚C£1Ú3*ô4’ŒÛ™™YJ؏}ºŠbR·ËÛäQ¯¯öùê³hyï$²œ:N_ŒkýìGT(py•Qo/Äoě/ @#ù¥Q:rÔoÑs¥ñ\–t,ÞœºŸ§öUת錰#ߖŽ+Õ®žu;|ò*º †ë?FÛ^¥ËÐÆŒÖlWhD,ÞÓ ÿ.z=86Çu1tnRO! „€0o‘7ã1{Ù1Œ{o:<==ËÍØrš›6mBBt0š× GË&†{áʍ†‰*΃ZÔ0ì鎷ӊtnnw–IFYäÒúU4ö©…ãëMŸukú՞ț'gÁÕ¥šQvý»õV­;‚& jcòÕ֘Êÿo6þÛvZ‰À9ŸÌmÚí‘i8|êª:Ãõ—Ó¥AuÏ_ Ãsíz®ÑþßýÇÀaÆúŒ<æ];4ž?ŽÞјxÝý®ÊÞ»aé[Æ}uò2€§gáU Ë^ðû.ðƪ¹/d_I*ő°žûëNð~æÀë7qˆÄYBbÁó‰x¹cóoo£qýZ%ŠTmt^}î„Å?{÷)Ʈۙ‹!h?x 3Ï<Ú͘¡JU7âF<­ÅpšÍ7“Ç?[(»ž¯K©&+…€B@³"°mß»b “Ÿ*7»ÊM àÌñý°K>…œË΋Vnän3ŸõŒ@ߢšZ‘@mݬ,-,K,PëÕv5ú‹º!Ì&³SXGa”óÈš7û/{ ·ì9ŒŒLôïѵÉÓWÞEçݺ¯WKåÔkþrîz|8ýoŒðD/,øÒðÄPùçÀ^ê7>ùG(a{„»Žm€aƒ;ᛟ6áøÙ S~'ôéÚ )̚…§£ƒ]¡X®‡ÇÀïJžŠsf9Ãò:k¶$åZ%Ç¢ýªÎÎ@ûŽ‹ϐŸßº 3ÞR *‹ì‡ŽGgš{;ò"Öts6€;“×ab«“Õ^ß(ò ¶oéCk?4jœ.~fÔºq²±f¥ðéÛãÃ׆5Vq•7ï9‡/ç¬ÇÉóÁ”D͕În€±#ûà®öyÏ.ɺ°6!)•¢6ò†g“Œ.„€B@&ðÙwë1èñ7qw·òIÚYnuɒ%°I:ûºûš°Àª\ô=šÙìI3t«-íCµÌٌZR*‡²˜kk+fÊbŠ3}žõ»Žòº5mTK¿}©É!›œ‘א=¥Œ×oÁòÝöUò~ÊçèøÞsɅÇå£Qž.ÆÃÄa«_Í߀ß×ïeQÛûîf”ètïäkôå1ôÅðyjOmü€@2€Kòûœ>îÙ~xåÙŸ…ö͌&Íøû(ñ”­v {@\8aQWòÄ–¹ICòÒwïì«ögò>Q¿+á{›GŒú#V¯;ªÆq!qù΋÷¡EOŽð­ ßúnäŸ{ky愯þ$/kŠz¹vÍêX¿ä n3¯mßQ%ÓJNIƒ‡»3†ìX€Ù_ãÏW¢s›J$ñ ~îù/«úŕâxןž×}iÖn9Is|üs‡V>¹{wSRÓ º¶ß›¶ëÈãÞµc#ƒÖE±7…¿ö\ÌúxDq&‚ï8~M×øAò|rRŽfôÞãìá¯æxëf³íG ²ØnýÂû\?Ј忌ç\J².|}q†bðú Β’Óhó, COÁ¶åïTØÍ†bAJ! „€B B šš³þ˜øÙJöZö7ŒËE =zAà†3wÄ%:š­ÉÆ© —ó3s»«‹¿¶kÖD%P*©@MLJS_fYXéáeï {ŒîíÙR}áÕeååDJŒ¯->v.î&oÙ{cŽçq2>ž7âØÌܪÖúÌ[?Óü4*|•Ç`O­ BÏ@u[\Îù_Wû0uûOWþ{˜ÄϪ\QËB,ƒöhêÄ‹Ô>ip"öÕhó…™zàä†OŒ~ûÓfŒÿâ–ËûkYÈgddaô=ñӗ£Tß,Ø€êðñ/¿Ïƒ†9û0ùX˜Y ·bè øuæÿTÝ'Æýˆ?Ö¥=‘ßÐÞÈœÉúLþXŒI-Wãæ/,ø›4šEýwÄxZ‹LÚÇœaǙâ‡û×/†¬ ïaåςkûŸÊÓ^w·tàkü}œ IDATš¥¹(¥­B@*Nà‡%ÛàÓj0^òhDC•¹@MMMŪU«s£†40Xt:s¬W‘Tš\8•E# RN®Â!™:/ ¿Î‚hÎÒ*»îÔ÷̓1,2>ÝÆ“G³)¶.Wœöäk Hô\ÅåÝ_šß/\C‡û§š„= ¿~.7CïËþª<­·Ž& k«º<Öòµ‡È£ø vlþеüÅxÅªó¶²×ñ# Åe/ÑËÏôQ"ՐÂ{#Y ò<Ù£fLYŽr/^œ°D‰†%äYæ\Þó׎ïDíQ/§¿WÝu}d*y¢qÂo™¥~áHB©Û›«Ë¬zvË§Ê ZXÑg¯s}GLWûWÙËËÇñ>C ýœH\©Ë,veŸÚgÜ®…w®ã$Aÿ-zCemæ5ᜒ,š‚NWÃóYŒÜîïM'Tšó‡t“¢>í=q.‡|Š’ ]Ú9 NÕ ?ŠåW:b†=匷—=€ECy³FúuŒ‚>OLG‹ÆuUFaŸSœÕ«*ÜzÛïÚkÕØk[×qëÆ×®}ӗ1rhW…ÀâðMJÆkÇå# ûe¯».žŸã÷ÐÊ9c•§šÛsÔÂûŽ—;~>öß$åévmûºú÷Â¶Ï $›b/wTL’J”4sòxýù{ó +n]8‘” øô9ÿœ¡K°ôúóý©ïâ=Â%]3i'„€B@T~™¹ðÏÓx圚S§ls •¹@ݶmb¢£á[Ým›iKU/úÔ3~W ö ² jSÊ=šYY°—‹ÅéíöòÑìAùgákx _Û¥l±\ùß”,'*÷lω_ÿ…¯æmÈýR®ë€Cwž D¿î·ösr%N²tŒª|†f­ŽoїîD¬Šc3%Ï ~aoރ£¿ÇVòLQÆà¢<ùÛpèe& 3?Æùâ(êzã°ÝŠ}>TY`Ÿ&Ñ1„2ÿºº8beý]úç~%Duû9QÍ-áüœb/ßçé˜nzÓ'hÕŽð³Wó3áNŸ~óg y>„CÓɳY#Ï8,‚Ø›ºaç yþ{,ÿþE<ñà]èñè*„”>Ñg~%è‰ÚŽÜl³séfÄkt£@'®t³—î}ò sù䭇0éõ“X-ùcF¿·³§R7@øzaÑØ¡•7v¬xOyœ¶uC²n֍^¢k¶ƒ Cg/)Ûð2 ö(<œo ð5ÎY£ÙÃË×ÏîUã dÔf‘Ý}è*TøºӂŽ**’mcï§S‹q*ü}ÞT­çVWŠ[þcÂâ–3Zë<üܖ÷=󹝶ޟÜçTðyÉR„€B@!p;–dÓ/ŸlœCÈXªe*P#""°o…Іã‘îyCӌ5Ž2Õ×÷ ŠÒ9šìœ2€˜"‹/‡×F¿†[ÔžOŒ›¯ÂÿüñDö³ æðK]aâº_ÞÈݳgë;†öZ"Ùo^±öŒù`)~^±G‰[·õäù µO”=Æ,4ó3áNÇNü?ýŸû¶Ç˜?ˆ.~Žñcá‹÷‡¡Nç·qƒÂ§ÙÓ« ©.Ì@fzŠÎñäPN]˜(ß$h;ð’Ê…œ³—é(žÂnl°pf­Ÿ ™œºc?üM% jä㡲<óCx 1_~q(솝g•§œ#BHd€=Üa˜ {S­›€n®smë†*nÝX€²÷Ÿ÷ óÍ NÌŽ•ön²çü¥ KÁáÞ.ϙœùf@Q‚7iËÞòçï¡Î+îýø×Åzÿ9B %yã÷ÿ7VqëÂQ  ÁÇ.­ùùÕ\ªº÷oYe¶6v}¥ŸB@!`þnF'`þÊSxêŏàëk|ÎCgXŠuýúõHJJB[ÏX4©§Mòq'}š˜”RàÔ¢XYZ‘°ÒîÛ,éÔ”Ô $_œ«DÐíʬ…[”ènJ€Ã¡‘,Zø‹óc¯ÌÃÍèDՔ“õ|=ñ1õóÏ}GBàŠ Óå¢ó²òÞ:ö„¶€€>Eݗh]$‡”žºŒ#ÿ~”'‰'øùŒŒ·Ó([0{ú–ÐqúaÉ·› jþÒÍ{ùZ5õ$qð0†gؖŸ sá0`kkË<{ð8#k|b ®š¡Œšœš(ðz4…åÖ!ÑÝ>7™{/회UýĞ™]왟Ÿ~÷/ŠÌú'W+–Äš™ëö¥ægÂut¢µ0¯¶nîºD=œîj‚+ÇcÀÈoÀIXþBŒŠÊÔڟ’ð°§õÜÖOÑÀ«ŠZËß_¢öE~NûùìXöú²7}åœ1ö:î:ä‡~#fä c¶çŸ­'1ôÅ9ä±CûR;« ·†ð,ÉgÀxºùð ݄Ð/|mx{º"ˆÖŒ÷ß_7Yí£5öÚÖõYܺqØ|ÍöÚ;†,RRˆ. s.|ݱ€~ÿåÁ*és6ž£ ïÕ¿†ùÃÓoüŒP £ßNï;ŸîÒÍÞC{äßIE¢ao'‡|'œû!÷šæÊÅ­ ÛP¿ûûžI7#fN¢ƒ¶iò§ßÿ‹Å«÷©³Ã~›'aSIÖFÚ! „€w?6ÇÌÆ÷Ú;e6é2šì=ݹs'²Ò“0¢—aÄ2›e9w¬̌ߵ £<šÍø”8I'páðÇèSßæÊ‚ŽŸªK–xCy¡ŠO®öÖqžkíad±«óžøí˜ _JÚÃ_¬9('ãaqÛ§kSJÊӄ2Ù6Æ]íæ8:‘ΣŽ|ÍAJ®ŽÄž…6¶Uû?YdpF`¶ŸÅ'‘ÉœMqËÈ.†ßý²U…·Öts»Ãž6ö²ˆáœƒO>|·êªÞ]ï*AÅsŒ]X0g<®Fž3.ú{k‹²ç7Ú¯9Šökr‚©/' ߣ—UØ2'q҉üLôÅÆï?JBpp¡ÝëŒxœºøªýÁ,xìEå}ŽæÛ3gÚ4óÊÝóÍI”8™{ÔØSÊ7!˜Ç,Ú{8ŽÎVeɎÙCÉë·äÛєñùÖþ]šhO—‰C#âÔÍ žìéæ± åYÜ:æ]NÎ7CØ#ÍY§9cr§ÖõÕ\ºŠŒš:/²±×¶nŒâ֍3a·ô‰ªþ;%Dâ€EºÂ×Hýîã•øßÿ×hsßÇ*“3gîÞ©1Ý€ÒšlÚü`›ÿ ›:ìÞDٔï5 žµkäî.Œ{ÀwÓB|̓þJ†¬‹níó÷Ë7øæ‚! „€B@J ’’zÎ_}ώ¡õÚÌšze&Psœ§ ,ÑÄ#Æ(£*{e}jIçR*'û‰aO }ù5ÄóÈ T83íbÚ_ÈÂôáh_\?å…âPSö’ò^?ÞªK~óÕÃñîKÕŽ8Ë”YÿbÕ圧ºÂ‚–3³@ã/Áìí9üKLÿšúR΅3­þB^Xiô:‡ÔöéÚ\_’cfô9³K lö¹Œ a$BSUx$ïó{côœ¹á¿ÏŸœË(iÍÿFôz{»Â⎏êàØ¢ éÚFªý}œŠÅ{oٓ»ié[¹Y¬ cÂâsг31ò‘®xî±EšóÊG¿©€:¿ùªÃžµèˆN.Å}è ßxž‹ÎÓüî“')‹l]°‡C“S•žûˆö›êï[åcG8{óf:Óö:&h1ydõK£žÔ>dŸ± KÆÅkÊ^C.Æð4ô}ÁÇqh4 Óõ"^Ø^Éöƒ?Á™‹×U$'¹âb̵m躱÷š“OõïÑB Ôüå{º1Âçíò>e^“ÏÈSÉY~CÂbTÒ²VeÀkûeëÕÝá뀏/ò¬í‚ÿ(€ŒšÂÞmÞ÷QX°âÖE÷~ûü‡ÿG¡õ锡šEŒ!™ ]'©'„€B@Ü9VþwñV­0æå×ÊdÒe"Psœ§™™q…öf%—‰ñæÚidŠ7®g4)•y-íÀÎò–è+Ug&hÌ{ÿ$—>g‰Õ…5êºåœˆ|~(Ÿçx”<ª—I ñ‘)ßÑY‘OÑò⠋*>b§Œ öˆ±×–“5MŠ3'9ë. f>惓H­§ÐMöÄr8mL\²Ágørâ!N@Äm‡ßߙ²¯ö7èŒÙÒ0à옘ׁ…?‹€,Z·Ÿ^àœÓۍÃYŒù\Úü…yp6g>«wpŸÖ*›¯î†×5†§îH˜ÛÙÁ‰|xÿ${*yï.‹ý ‡ŸoÜu67qTi·n|­8RĀ.t\,›«þ;Rà `NäÄ}ϧ~;‹üº£Ã­³Q™Cq뒿¯Þ¥®o7/阯Ø'u…€B@ªE€ó—,øó<ž; 40ùäÊD nÞŒ hÓĝ²÷^6¹ÑæÞar¶3üÒ:“™%Ûwkk‘‚Vö©œÆÜ§Zéíããr8ŽUw+‡œ²çSWØ<<„||ˆ±…7’ó™–E cû3‡ú…íåշ˔<9ì˜÷=tTËí s^úç•ЋœÆ¥-•q݊[ÎŽ\»ÓÛ*kõ¢éϗ•ŽB@! îPٕår7žõ‚É ˜\ ÆÄĀÃ{³²²ðÌ ºÐ$šÜèÊÐa\–;¢3ë‚|ƒF™kc‘†:6`‘*¥|ðù”œõuݎ3'/$‹ßµÑ·[3:DzY±I‘ÊÇÊÊ3Šð4ßµúyÅnŒùà×<áÐæk­X&„€B@˜+vî¬Ø„1oLAíÚŠ=JÔäuϞ=Gã^hïqž˜ŠÐ\/,±K;‹'” §î€=_ŽOý΢#³B@! Œ!0}ÁfŽïõ,bL³bëšT ò>ÅE‹QÖWk<ù@+Ø$*Ö© „€eOàœÿuuî퇯>€Oßy€ì”„€B@*M€O'Øpà&&|òììJ¿ÍJË€õôéÓžxñ"jÕª…{‡Sr$íyšR„€B b ŒGgÉ~KgÉ[7)ÏùÃk•Œ.„€B@TV|ÌÞ×?nƃO}€Nï2Ù4L*P—/_®²QÞ×»Ü39ɏ! „€šhŒ/؇ÎiMJNGÜÙÙÞ[Ñ "ãM !ËáéÖž˜b‹Ë©¶È€ÝCV”‡–Ž•H=(Œ%=oi¡Ñ>Ϗœßu?sÂx®kAmۜú9ÿZÐ+VÔ^û<õOÿr]ÕgÎsܞû¡/P*«9×§ÿÑsܯ…^ݜ~rúVírÇ̱›Ú랷æN€! *M»ÏÂ?ÔoLøÊd–›L cߟ}š^œ:uq’Lf€t$„€%'Àgܺ·MÖÆéMSJޑŽeL ž„è՘4„ÄŠãz\:ÂâÓŸFç7§!=9×BMGعxž+iaAJ‘„¢:û›Å)GŸQ΅3šóÏüšîlpKÊ̞MÂ-XÍæÔãºԗ†2ž[ZÑë”ä‘ûÒж¥ü…ÛeÑøy ÇIûuúR%ð§öÜ¿ƒl õËEöj++ûtÿن,­xfq¬æÅ-sê*AÌ/dg)aœ3Šœ:®M!Ðöª¶z=§îSõ¥Æ ùçe: 6Čç̯+Í©­µv®dª…ÎúŖfÒóªo5&ý—SŸŸçÚŸŽ¶ØZSÿ™·XòZèÖÈÎΚέÎÇ3Çv>?:ƒÎmVóà9æðåŸóŸŠ;1Aû¯á#Öt\Uۜ>ù[Õ/Ù£kŠc•ó» _#t-hmäk'‡%7àthû×®€¶ÜªËG®± ^uÝò¬¯nÞܟœ­ ªÑ™â5ª;•.ŽêX:g'u.œ!P™]Â¯Ś׊ç~“˜n2º}ûvðù§íÛ¶B3§cüii¥! „€(=w§®BÇV>M\úÑ€!P807p>8—Ââq5"¡7NÏEÇ&"-%]}Ù·€\6¶¶°¶£s‡éìaúׯÞ)‰I°&áÄU HšM¶V\²x#Àù0”H"¥Åb”E˜ŸžÉ#DsÌŽ¢ñXŒªJƒh®Vì²°¥þ•PŒ¥˜Žít"̒„î­ß•@&QÃãjíR’N‰ %~”¶¡grD²NŒéDuŽBTbˆ‡×é!­ðfÿë-ù•«¹rXšñôêÝÒd,YµBRÇP+èŽì•`͝s^%—ûŒn‰sÇʙŒNÑ匞ïW%ˆYP+wÎdŽ^mþO+®ub['ԙ'©ÂáËl­bUBXy°u?kûÔ d­ØWÂ\«-µý«›ÜWþ6ZŽV9^ñ,ŸY Ú鄾ÖS®|ÎZ²Yú…¯³ðhÅѳ–«2$÷>ÿ³žVÔɍ˜:’1UÝ|Q:S>“ÆÔPZ5]àèäˆ:žnšëéz>uP³®l‘AÝ4wÈ@ kùž]ø§Œ<[füžm»Ü‡AŸd’áM"PùCûçŸVoúQúÀ2ö°IŒ“N„€B@ÊI€=÷!á18ëwÇ.ÝÀ™k7›‚t’,6«Õš'×pvsAuœ.µÜQ£vM%L¥ÊF@?äœfáÌ!æÚpsmºz>G0óüÒ²-Fõ ú7•™HK&чšà0D‡G .â&ânDSA*ݰ±¡÷ˆjúxb@§†x¬+Üíuw-*1±·*Øì2¶ì»Œg¬$=hÜ›…q0‰@õóóÃñãÇááá~-ã€ô˜ªÄ\æ"„€B@Cà:‰Qÿ+8rú*ü¯F"4:IKØÖªƒêžuQ»¡j7òcuga)„€‘ÒSÓyQ×éœåáW‘•žŽf <0šœ'ú`màå®B¥ò&p3:ó~ۉ'Ÿ‡Šî+õð&šÿý÷âââÐ뮖ð²¡ð^)B@! „@•&Ÿ‚€ òŒ^ Á‘Sא”šŽ„LKž7nûFŸš^ÏÎîæ(E2!3güH° #ô:ê»X£cK/ éߟ j•ɘҩ(ŠÀËvÂÕÍ#^žYjH¥šIIIX³fÚ›1rph.–Ú(é@! „€0?1qI8y>§èq90é”N7ËŸ®Y§ I 0zpi „€B@”åkÁÃ͍›Ô̕GQ­}'ÔòmT~ÈHB@˜5€Øxþ± ݚÔÄKO•< «YORŒ+s3ڌfŸuðÀ ~°šûˆÑã•X Î™3ÎÎÎxöÙg¡ Y Mf‚уK! „€B |ÌŠóéîïÛ'í°æPZôî [{»ò\FB Ò°Š(ÿˆßÃÅÞŒ»¿ÒØ-†š»Îâ,å5x÷¥A°¬7°©a”q%šaaaø÷ßáëë‹~}ºS‚€ßŒT* ! „€åC :6 ,N_{®?V^Hž‹‘èpŸxFʇŸŒ"*'OÛLÜü÷/„„Ecú‡WÎIˆÕFÀÿJ8–QÄÎÛŽµ†OXÔèd”-%šŒÿôèÑ£èÝ»7šzÛC¹ÅšA¥²B@!Pö"oÆcåGðêšþøf{ÎÝÌ@˞]Ê~`AJO —s2¶ïÄÉóA˜>QDj¥_Ðrœ@bR*Ÿûe†îˆæm{£¯Q£—H ®_¿AAA9r$œ2ý ‰;iÔ RY! „€([á7âð׆ãxùÙŸøt]B³ìáÛ©MÙ*œ !Peðy©ÏxÄáϕÛƒOß1~/a•!1šÀôù)#Ž7Ü7–µï3ª}‰ê… ¡Ñhð¿ÿýÙáë€Ô0£•ÊB@! „@Ùž•€ÕëŽbì3}ñíŸHœ I@«^â9-;âÒ³ššܬ³ð\­8Ì¥mÉiéxìàª9Q™•É ¬¢¿A1ŽÅdÌ O²Žq{™š XŒx1š4i‚AÒþÓ%  I&Ÿ”t(„€B@O --ƒRüoÁ{/ߏi[C’b!žSã1J ! rtqJE—dLøòŽi慑C» !P,ãgñç†c˜öÑXÊäûP±õõ+-P¯\¹‚7¢k×®èØº²Cÿ2j@©,„€B@”/ç®Ç«ÏÀŒ“ 8{õ&ZS¶^)B@ÒxÊ#õ(qÒóï.ÂèÇ{¢×]MKÓŽœ„„Å`þ²xkìcðhýœQ36Z >|üxä‘GPÏ%šš}F (•…€B@²!°pÅ Ÿ·=V‡Ùaßþsè2€Ù $œ !pGšn•çkÅ"91¯ŒŸŒõ0ùxÜQ d²ÆàhžÏŸÿ#»­úŒmTc£êºuëàïïqãÆÁ&þ 4‰þF (•…€B@ÓØ°ó œ«;á\ _løwz 7nϏé-’…€šJZ8Šcˆk"ŽŸ¹Š2Ž.ùö…ª4=™K˜ùófŽhÚ÷?ûµQœ-P-Z 6 Ù×ÿ2bP* ! „€Š%p5ø&¶Œ«Þƒð×oëÑå~°wªfÚA€7! îxƒH ¶!¡:í‡upwu˜‘œïx& ho:Ž›1É3a±Q˜Œš)))˜;w.Úµk‡þýî&h©QƒIe! „€BÀô>Ÿ³>Š#G.ÀÁÙ >­d˜é)KB@X[hTVßê™xì•y˜5y|ê¹ !P(ƒÇ¯`Ó2ë£%PÃÂÂðûï¿£OŸ>èТ4L* ! „€Š%°rÓ)œsðAŠ£3®œ8‡N÷w ºi­‘Þ„€šêÜéè™gI€>~?ýŸ¿Ì]Õ§,ó+!+A7Ô5òñŒÕp¬ædp/F Ô .`Æ :t(žÆ@{Üà€¢B@!`Z~a˜s4Þ=»cço¡ÇcC`cgkÚA*Yo°€‹µ¬,¬‹ŽÜ6ÉŽ5q5% Ùt®»! Œ#жZÖH§äkèSÏ<ÚÝž€öA &. _ÏK6äU IDAT߈7>œO¯ÏÙ(zàÀìÝ»/œôª§Q‚€ä`ƒ’ŠB@! „€i |¹pÒºÆÕ“çàZ·<›44핬7+X¢‹KS8YÙßÖò“.¡s«æHŽNÃþˆs"R+Ù:‹¹æAàA·D4°H¯ÎÇó^†MÑ7…ÌÃb±¢"ŒÿÅxþÕ©hÙŠ“ÁÃ%P9ƒï¹sç0~üxdóþÓìtƒ’ŠB@! „€éœ<„þ ˆ÷jŠ+'Ï£Ó` í­kë†VN>ÅBÖ T×ÎNŒY©DjZr 슝£TeMÀ†ö£Ž¢Pß_o„µµ^N޵*k敱ÿoڌÖÝG`ЏlŸQuÁ‚šV­F>>„2ø®6x©(„€B@˜–À¬…[`Óg0vn9Œfww€K-ITÒÀ¡|<‹­/P¹re©‡ÖnÆ?³ⵅÓaç`ä„DÔnè k›bç,„@Yàýš»ÜÄc/ý€µ?¿[[ñ¢–çÊÜçïÿBºC[<ÿâkOÃ(úõ×_£k×®èÕÉšÛ D* ! „€Š#pìL .…Åᘓ/Â.]C»{{š®óJܓN j²5ð»„ìììÜÙðÞÔzuj¡º“#ò Ts©™DgLX$ŠxÙYY°¶µEfº6ŠÍÆÞƒ_~Ý ‹Û®^VfÒSRaaiûjŽ•x¥µŠŸÙy.º‚W²­c*Îý±†®YKò¢Þ[ÁÖÈðæF`ûŸ 8zÍ>üÌ`Ó š‰‰‰øî»ï0pà@tjb MÌQƒ‘ŠB@! „€é|³`Ú>4sW@»œPÍÅÙtWâžô=š‰I)ÈÊÎÒš€#…ÆZ[YáÔÅKèHGñžÑ¹îú…=©ûÂÏ¢¬Ó&q¶åß>šŽê5ÝàäêÇêN*l7%1 1a7pÝ/@ ·ß~1׌µ3Ɓ?7šß=|êÁ»eUÿò‘SÈHKÇ ±#ÑçéÂCèXÜîøõ/œ%A—ŸšúšÕÀÃ?x¥TâNC Š.ì;ŠPÿ«$šmpíô²ãiÔiT|˜µ).³OŸªÄú›KŸ5EwÒG) pŒÆoÎÄڟċZ ŒU²éY¿ëX¶9_}3Çàù,PÃÃñhÑ" 6 MÝ# Iô7x©(„€B@˜†Àñ³ž€œšº E˞]LÓqèE_ Š‘hËÒó òôìì”÷ðR`ì(¡KC¯zäuÌ;ñSñW–SŠ4þžñ#­Ù|Û1šti‡fNVuxßé眀LšSS ç~núÄ\oiÐ9üòîç$R30~Õ\œ®yú=ºn;xŒ¬ŒLuF®wK_„_ BühÔk֘…¿.Ñ\¢b°zÚð?t2OûžŽ lÈëϗšOc}ýøËˆ¿‹Ï·ÿnlS©obŒ5ñߕšédƒ±#e?Œ‰ñVêîBÂb0k…?Š}5öö·O`§›šÁ5 +V¬ÀóÏ?:ÇèÓ2¢RÃㅀB@TF‹VîEÇ®­1å?t~ lItIÑÐñ={éJªzœž'j·2-=¡áH¡pWM>i†›q6)eŠôÇW'QæåóxfÚx8¹Õ@ôõpÄFF©ð[ ‰jÎÈܶ_”Õ”Ç7îĪÏg+ïdÇAœ•çU¿ìYñÖý°Ÿÿ2îzðVˆåŸÕÿá¿ï«1î{ñIŽГŽ!²ÃÉ-{°bÊ,T«Q“þûÅè¹&Å%`ÞØ‰žŠ=:£ý}÷(OêÉÍ»UÈñø•sàìžW(=ˆ Ÿxt â"obè{c‘JÞäĘ8Íæ®CЃT1%«˜˜»«çŽ5e·ÒW%'ŸŒ© OãƒI_¢f͚ÍÆ`zúôiüý÷ßxçwà³ÈJ5h©$„€B@˜†@tl–­9—6í°õbÚôéfšŽ«H/ÅyP‹šŠ¥¥%ìsΏ=wIeø‡÷—Nu7zvib➥»ÊJ ++ïÏڏ×ßù 40h Ô}ûöa˖-ødò‡tÄ̃:—JB@! „€élß‘öPZ◳‰šÛŸ\ëx˜®ó*ГŸõŒ@ߢŠhE¢Šu³F°Ž°DY Ô+'ÎbÁkç“·CŸ’„φ<Æ[ç†üæ¯Ï^Ãû<fÝ:ṯ?'Cš2øYå‘}séÌÜ=¡Ç6ìÀš (ÁR¬(ęÿ}ëי” Øð=£,@Yˆ6¹«žŸñXÜë ïsÝôã2t!/î0òæ–Žø>‰ÔW襫ä-vWaÉ]ˆ5ß, ý¹W tÛŠo74êКB–¡Nãú°%/®”Š!p’n T¿~ ó&šþEÅÌHF5OæÃÃF£Kö€,P׬Yƒàà`ŒöÒd‡­5…­Ò‡B@!`™?oFÏŸñÅúK”Dg°-úÔlö¬šíˆö¡ZælF-©@Ý0ïWµ/”Ãpó?=B{A¯:¯’ ±ðzðÑ*46„<š7‚®«=¢:ŽRɏô gª]öÑ ô}vŸôT¡ É!·Ÿ=ðšwg:Q ÏÉFªp×^#Rv]

C—ïÇŸ{œ:%ʜ»û÷°aîR–Ëçö&FÇ)]†ôǰ ¯([ŸFáÃÇÔsnjT"6ìòUbžgvÀÐñcs÷Ù.›ô =·ý»HeC–bÖÏYŠVmá»'ZÂêö'™‡ÁbE™Xò%ŠskЧž*ü&[~ š|ÄLÆ ñà=^ÐÄ/ó‰ÈB@! „À-붝F}/7|øçtæ±<¡•ÂIK "=š‡ÿق¿ŸžO"×£Ÿš ÓÊϟǍÀëBë~£†£M¿îøë«yj¥yü<›4B³®í•g0ð̬Ÿû«šÇ‹¿A­ú^êçm¿¬Â–…+I Ž'zw¡Kœôƒ¯p~ÏaŒ[ðe,‡Ã†_ Tɐ8+0‹b]ù~ô»Äԝ«Š=?U׆³ |ßӔIž=F3ÉšËîÈÛðç—s•0}bÒë*$7ýô'Æ)fS6ýª²2èYÅîÝßg«£wôKzjyÅ5°uÐfýã‹9à,ÅoÿöÿR̃ï—>»ë æNym«ÑšI¹ã üœë&nŠºb̘1±0X N:=zô@ïV”ï.)À Î¥’B@!`ßþŽŸ­aíu+4§œ†R Ð÷ ž!qfš•=ŠmL°uËÂ$(W+!š!/®íiôòÓèñØÝPÐeãÕ÷„Z»OŸ~Ï=†ûþ7¢À€C.`΋ï«ð࿟bðe1õá(8Ûš,Ÿìùœöȋ*tøœ?ÀÞI›ežžÂg¯Î1NÁÚa`o•ù—=£'7ï± ;áÕŒ1^ýùk × Å7OœF{i;âùé×-VO­ÚŠ\lÇR¡Tø}÷+Ý4ùúë1žß³T]Iã*B`ëÑœ ÌVÉv ) ԉ'âñÇGÛZWô(Cú–:B@! „€ ܈JÀêuGj킌ƭPÓ«® z­z]è{PSi£1ÕY|“ã”GÃy¹<9åmŽëßÃ`ÐI±ñ*!‡òrH/>çtî˜TB¬·—}Ÿ»W“_c"‹SÎnû¿ï>o§6õQ¿”œ·yg܆+r˜îú9Kh¿kg<ùɛŒœ…uÆûsw-[ƒtfï壧‘ÁžÐœÂÞRN¶Ä Ž®Ÿ€ù¯|d°‡ö¯¯çáð?[IÜ~E"×WõÈû{÷­^‡GÇ¿L7 ¬Œš›T65ßü„ýÚaòíºH¹³ ñÏĆýáøä“O a@MOOÇäɓ1zôhøÚ ðŠ ƒ:—JB@! „@é >y‘QñøéÐ ô¥Ýc(¥ }š˜”RàÔ¢˜YYZÁ©š6œŽ€{P9QÑÚ?ɂ’“±·‘œšœŽH’Êýs={K?ÜVg—.Ão÷áà¡7Gçš;kÔÛ*WÿX—žQ*y×{ä#üò3_,Ü?ìýžÑ^W #- Œ÷“÷‰rèòòêrr&k5>‡érB#>oUWŠxiIɘHÇ䀐õôöýˆž¡Â˜[ôìœ{tÎ¥#§±ð­)J¬Ÿ¶pz±óÙºh¶.Z©n³®Týÿf/ÆÞ•ÿÊŸÔbé•möü[%Æ`åø[çò–íˆÒ»9ð³ÆÂ¿Îaúôâß×<ƒj||<8Ä÷µW^„§f§9Ï_låF€¿|dgSÈ;…q©d‘ê¡MÉÿæO©žÓ{RÕÍÉ™Çhzž¿ÜèŠú‘«RòõŠ¥'ø'mm]~XÒëºŸË ‚ $„@¹XùïadÚ9bCž•Q¹r1ΌÑ?fÆïZQÔf |Jœ$éeÃÝ@ûG9ùÑ=O=¬Î]=õø<®ö\rˆ¯î\ÐoŸ~“²ìŠã±‰¯¢aû–¹ô®Ÿˆ_'~EYjð¬óxCùØ>»”Ký6ÍáB Îï=ªúiwoOŒøøMƒ÷‘êä߆íZâ©O ¹Ó_fñeqžwÕê(ÞãZœŠX4³ýŒ§”÷™¶ÐK5ã±Ré†Á‡k~ºmX°ÿ!š'ùÊ}M€ºÅ•ãwaÕçßç tfžxüT•ÄɁ[\ÿòzÉ °'{ÿïãЏϕŒiYe„'8bڏû1{ölƒ>« š7nÜ 8ò¯1á­ç᚟¿ÊÀ’‰Téé™È 3ÝÒ)FF–ú™™™ÙÈ€?’éé9¿ÓÏ|°îµ,ºCÌuø9®ÇÿòƒE¥ú™^çŸ3sžççlm­œ’¡ŸÔðkÕ헐’#D5°¢tti4‹K(¬áìˆøÄ”qšejgkCvÜÊÎÈ"¹?}áÉ}Ñ0Š­q«-å\Í^ÁE'„ù_ªË|”XÎÀ6֖Ä*ë–`¥6<.×å9jE,©@_ tB×ÞΚìÍVmøšõ/œîè`K¶dš³µmrÄ0ýâ@¯ñØÚºüŒeîÏöv6Ğm°$fô|nŸt†£6äŠçÏ¯ë¿Æýðd±¶ž=º~tÏó¹…ü:ÿž÷gm¿üŒ>ïÊqµ‹•B p_Î]ŽZވq÷FœŠSô=š%…d¬õÀ_°ö۟ÕpìÅdo&qæý†ý®WG»p#.Ë'£<ˆ,âØÃÊáÚIttÊœÜæ>:JŠï30ŸÏ0ý{úê.Ž.ÎxàÕQè4žo‰ŠÊá±lÃÐw KZRØ ì >Hóga¢DhmJVÄUåº$G+?û'6íÆ]Ý«Bo‹*œõx΋”@}~Fñ{P£®‡cƓ¯ACLy,öÞòù®ÿ›ùqñ_"@ÒšÔ~¡› {獂›«Tj˜•Œƒžtg|ôÝn̘1ƒŸ?æM~VØÔ š!!!˜?>>|c8쒎VrDb~YˆŠIT‚.9% Q±IˆŠÖþž’šAŸ>­1èz ¥,xž»8d!fTzý–ð$1™#.ím­‘NB‡E—5í%qа(>Öô» Bì”dQÃÏÙRþƒ«D ª£ÄŠ5 ú—ë±hÑŸ®ý]œ®·D3ÊG9+WÔå<}ñÃuó P}çhhΚ6†žÑ—caPÉqÕfe‘WŠ–ÂÍš!ÿN2™ø’ Í¢/P9Çj=Át$ zúWœžó ±öwnŸ©õ ³°fÏqõ›¥Úp9"9Gt³àœÕO΍ՎÆÉ¹A aûÔ9íëÊ:º,еãóól'ß\`é&…⥒×@Ýhȹ‘Àÿjž>gwޱE2}IÉbՓš×\»îjègª“I7,©/šè*PÞl®Ç×#ÿgie­úã:깜×UzDGEÒ xy5Dmwk4©—V -à]§:\ª;ŽLRIB 4"ë¶ŸÆÆëtz?lío…NÒþNªãcŽõJ5åý±ç‘œ÷ ÎÛušKbԇDå :%ÑÝÐÔ=Ï"ìàߛphíf•á— ŸðٞÜ^ß«š¿¯šë$ÏSÆZo%zK³Ç2‹þ–ŠRØm5ºe]â"£0kÔ[jo.ï¯å£p<(Œ7‹X„^º†s»©sZ«¹TÇ 3'©¿†^çëéØ>‚†œžmúvSÂØÃ§t×@YóžSúÿgÖ"Œ> »¯í2e™g2-]1aÖ>|üñÇpq)þH(ƒj`` f͚…é>ËÄs_(áp-$ !7~#þW#­{+SÓ2”˜t©îW—j°#ï]bšSío÷døÖw§?®6JHZ‘ЊFúWyÆrŽ’×¿Aâu|õæýæc”XR1èìîqŸoÁçŸww÷bm0H ^Ÿ|sçÎŌ ƒäÀb;• U“@Bb*|ŒK$FÉ jKa42—„f j¡qÃÚð€/àõêÔP¢4:Ñ‘qÕ‘à„ˆx'ª+§5WÍ+Cf¥O == ‰‰qˆœ«Œ@DG^DhXžÔÎNöhìS =ºøªk{TxB Xk·œÄ‰ÐÜšÝ hÿ¡”ÛšiSumÝ`m„XáûSi”òZJRŒðžÊZG ‹nšžÙq@%XJˆŠœ=jz×E㎭UžsþsOë]j› óþˆÜŒ+§?mnЉ=åLÀ‚>“_ÿb&L˜€zõŠp0H ž9s˗/ÇÔWéܵŒØrž’ WÑN"a‚›®ëíéŠöB²‡ŽŽ‡ š7®CºÊû™ša…Иê‹­ŽpŠé™’Þœ¢×NÆ7µ]áj{éÁØuÐÇΩðsÏÚ.èß³%ÚµðR7u€Â,\±Ç£h/z—®*ù‹! „@e À{”·~1»—Œ"Þíʰ`ei£+ÆÏ<€±cÇÂ×·ø£‡ šGŽÁºuë0ù9o2ÝÀ=pe9Ié»\;ˆÝ‡üÐÜ·.\œp%ø“ÒpWû†èغŸ œ™XÄš“Š1Iöåb— "*+'û44«…†µbp50§Îcãîs@™Y[xã^«Ÿ EèàI'mÐnø#yŽîJB@s'ðןáï#QG¶ž˜ûR•­}65ðќãxòÉ'ÑŠMñç5$P÷î݋Ý;¶`Â3,P¥Tu»i÷YÔ¯WÛÖÇŸ£ˆ§DGýz4GíZuJÒÐg%L3³d¿GU¿d~Š'`c•…Æ$R›Ô¹ ›4=s {]¢Ðù›hèã!ýÛ¡)…ÌKüÙ;{ñ6ÏvGW:SŠB 2Ø2c6&=ÙœîjZ™Ì[MMÀÆŸý|÷ß?ºtéRlï Ô-[¶àô±ÝxkDýb;” •—'zàœNÉÉixh@{œõŞ×йóÝšáÞ¡qΈO–ì‘•w…Års#À9 ŒÜâѬîMx8'áb@þÞx7¢”Gõñ!]à`oknf‹=åH 0K×ÅU÷ÆhÓ§[9Ž,C ! JOàÀâåxž™3F ïQú΀‡JKÀ‚ê—K/£gϞèÕK{>òíŠA•Ã{¯^܏W†5,®?yœ’àãa–þµ}»5W_Œç­8‰ÄL/ÔoÚ77+l%š˜-*Ž)hîIá¿18ëGÙ.ÿدÎþý?{WeÓE‚Ø *vwwww¶b Š˜šØÝÝ¢”ØÝÝØÝ "ҍÿœÃ¿|¢è.ºà.Ì}awޙ;g^pÏ{ntk]™ÂêeßK­8ÄxpòÊí—Øvú1ŠWDÎbRˆˆå”‰@<"pçÐ  ü€‰ÃZÄã*rjG€Š×-ßùEŠAƒ ”º«AݳgÜ_\€vò?G¥ˆjá~BøÌ} ìV €ž.¶¿Št9[ÃÄ$§îFº,Ðn õÃP9ß{dIçý'îàҍg(["7:4+¯Ý“ÞÿGÎÜÎ+o¹aS€ËœéæI$…ÀËÛyñ8ÖÌêñ¯\ëjº©±b·òåË'Â|•™Ju×®]ð|yýÛËF»ÊÕ¶÷=œüpôì}˜µ­n¿i§+•{D}uµm+Ò_‰@¢A€CKçpGálŸñê­'۝@ެ0r@£D³G¹ÕØŒç öÞóBÙ^ÝdLÕ “£$ BÀËí#^8Øcû²þä•t%ÁÐM…U{œ3gNŽh¡\MW‰ îرÞ¯Ž£oåI­ Ÿa¹à#ð𙵌xŠAÝk‹"H›vÝF¶¢ý©=Œ,|ôÇ Ê %jD W&TÊ÷ŽšÙ‡cîê#ôàè&X6Wã r*MG`)=œ8åjœ»hº«Ò?‰€D@"ðŸþ8?g!¯==)~$Ù[DÇk|…©©)Zµj¥•ê¶m[áûêútRžÔªtE9@#xïî-”ÓŸkåÔqÏm,g!z™J“H4ôFÁšYø5RRè/Wsu÷ðÁÌÑm5ÇAéIŒ"0aÁ<Ò7E嶍ãu9¹D@" ˆÂCÃpdÒLì_ÑiRÆÇrN-@ ™®ÖòCŠL™Ð¶­òÏ0*T§ úxœd.-ž”»ÈjéÖý×Ñ¿kMøùc…ãE®8A¡òɖrôä‰@Â#B/5 œFŠÔXn_Œ1ÑJyˆLÂ{*WT7}Æ;#¢h¯]YÝSËù$‰@‚ °ütžÌê‚lYÓ'Èzr D@'%ìŽ"]ºthߟœRU"š›7-Cš×môhWUé„r€æ#°~Ë94©]Ù²€ÇÜ5'I9€ 0ùTKóONz˜”HžìÊæv§Þ©^˜±üŒ3€†y×ZI’D¿÷ÐÐptµqqúÈ[ŠX¢ß¯Ü D@"884m>–oˆ…²'Î Ê])G@Ç›Ž‡ UªTèØ±£Òñ*ÔµËg!Âç!P•WiڍÀÅÏŠ5ŠÂ~×5„ÔFêôùvS‘Ð÷sƒn°Ÿéè"Ì(3 åSµ„=¹š¶"Çø+Jf{ [ î^JÉö_Úz–Êüöö @·I»QžMKd͟[ÙpùŸD@" ÐHŽÍ_ÛÎåQ³’좑”N%7ÀêŸÐ××G¿~ý”®šA7Ú:!o0exk¥Êš‹ÀWß@ì8tý(ïôòí·8v3% «“ ¹ÝDº·<,0ƺÁisâkþ†Kiœ þÈÅ$ڈ@†TA0Ö¹€uÎÇ1}ddLŸJ·!}V‚× è>ãªöé&[ÌÈ»E" ÐZN¬°ÃàÚ¹àzŠQ IDATЪa­Ýƒtü/HžV?‚®®.ŠNªt2•ªã†E€ßÑ0^šö"°÷ž+ršf@þ\Ƙžê*V›Iÿì0R}tuÍoH&ÔTÏ❚&G‚ú%“h#záøðÈ>_=0^VöÕÆ#Têó“ÑcÁ ŽÞ)RÊ4 ¥€É‰€F"pnãt(’JŠ jäé$S:)à|¢]Z·nݔ.* ªRˆÇRO7n¿«Ÿ °~û=|Ed˞p¡¬œfxqì'0¿!9Œ=}z&&Ù(¹;£ÖÞnn¯©]É·=w­KK×IˆŽ£DUß|¹LŽÄk銪\¹÷–+Ϣㄡª^"ÇI$Cà’óN4͑ý»ÈTA;œ„r(¹>œÏ&S/Au²[ŒHŸû0k#Ԅ:Gu¯sèÔ=*Š”N„.ßæ†R;«{‰_Ï÷-ŠWWB'Ìÿ§1z©àVÙRŒžöÍY€y{ >9«Ã7—æŽ4 €þõ‰J RåúšX©Ò§×®pä)“úãÙ³{Ȓ5'*Uª+ö‘3gþ„»äJñ‚@°ûVª¥™™™ÒÙTñýæû@*šJáÔÌwœÇó7([<'~Dþ’]Ôєž‘ññn•× ×O÷JQªªªI•W­˜ŒË—G_’"…ÂÂÂHùŒ„²]{s4oÑ]<œaÛ¹cvïÚðË%RŠL…' òÆŒ×Ïàä‰]à_…•$rÔœ»²šæRêîùó‡`¿i>‚ƒþ+Åäxéò}H“&CCƒIÝmDû ùåڅ —Á„‰«Äûߟ}Ãû×Á~\Œp$úSÓÜ0£=”,¥Þ( öŒ~õހÏDFD П#ÁëÓ9±_Y²ä@§Nƒ`”*Rl‚²ek Ÿù8•¯Ilõu#àýb Ü=ŸÂvšìš˜ÎwÊþ§8væ>Z[+¯x˜˜ö-÷"$..oމY“a$š‰ë`㲛d:p>§«nu1ŸùÞ#‚štUŠžœŠuÞ}•Êäō»oð)¢L²$l[ƒ//`ü`›Ê°„fÀÇòTÏá葭âÔl1eÊTGxx©ŸÇá侄ÔE_Ô¬Õæ&ˆqïHIÆ]×gh6äÏ"J’$hrÓ‰€Æ!peó.ÔËòMŽF“–DH–œª}äKŠ>•sP#ŸÞC÷¶’ jÛm†ÕNgѳ}UÌßx E+Jð-$ ‚é•¥T§7v¢ò£C&Åð¥PK•ý|ýú lÇ÷Dš"åVrÈjÁ‚%c\ÿÅËmûàë×ÏèÙk$4lã}yìO䵑ØßÙ葝è‡å+Ša¯^=ÆŠóD˜mña9t† žß¿7™r@ŒR 2•-[T*W×K˜?×ZêuëOŠ_Ü¿±A ErÉÒ=¿f£Ý\¡ϛ¿U(¿L’7;/ªª1…4[˜‡9âö ãñ£Û˜7wž ºlÉèQ®\Ä|(_÷ü…Ã$"=mÆ&äÎ]è¯÷ÊkðY„††`ñRÕú¿ÁWS¯Ím썃»—¡T±ìèÐŽ‚Šº)ýŠßhl÷÷ññÕ{4Ð5WÊ¡‰€D@³53Ô’ jÖÉ$€7ɰùB ± C|¥‚šGšÎµž¿öÀÕÛ/aJ’\ßåE–åÔ9œJs% F–[ë¡ê§ÒøOTÕWÕV3:uÊ<£[3ÊElÜø×­s˜@͜1„š§ÀÊՇſ ãŒÍíÛVcòÔ È¯$§”IQpp ËUûÁ ®³ÓA>'MY'ÔK…Í›3wï^ÁxÛU(\žtôëáááhÞ0zŸ þ®kÏîÕQ¬xŒŠÜÙߙ‚ .XŽ™3gúðÁM,^Yd8Lî89ý€ÒŽ~Ù*àkžºUÄHS:R%4—UÁ«GE‰V¬:cúùóFâv_TefmÕNTó]ow*Ö¡*{èàfôé;†UQ)˜sM‡YÍB…ŠñÞò’*OœÐ[S&©¿³ukgàì™ý˜6}òä-üÓP&Ì æD•* `a9M$*œÏù¢\YxͺŸûá~?W8f%šÃ±ÙL³åF)͟>œ?3Šœz¹ŸLP?v¹³7nœÅ¢ôôô)§·+j×n“ÌÙ¢§ŽˆÇòe¶ž~-Š ³²êéé.Ÿ4x²È}åVBœ{Öê¯Õð٘=s(wº)ÆpÜù ·GÙRiÓ 8(GƯ؞n*úu©‰*e㞝€nÊ¥TDà‚Ÿ!ÆÍØ" Œ5ÜCÅ«ä0‰€D@" y_n‡²iÃ1[TÍ;œôHí•sPÜï¢G;IPðÕ²ÔüµGP€@n\}•—š„ ï5ð~%ÔÓï-,¥1ü²•‡Á——Ð Š–-Ô)$ud.…°Tqo}³mëj"€›`=ržšæú;S®êÔrfࠉ1†ŽÕEäNœŒV)îQ*¬œ.ƪrø¯Å Š€ÀeÄÂÅ;Ù:|È“§¬GþŕÎÿ§®^9‰e€öµY*rag«WM%µñ…¯Êdl6mê@<}rWìAa²C‡Ž“Ä|¿6‡<÷îYSä3ÑìÛÏÕk4CÜI}e¢ÏE˜ê7h'Zó0Aus{-Þçœ×ªÕŠjÍÜèG[µr²È±åýr!(mŸ}û"ÐɲåjˆŒ[¶~}ê"OžÂÈDöü¹ƒ(@ùÌ_©5“YŸ?~ÌoþÓóR÷uºÉ¿áýýEH¡—œò|ê©{z9_#pÚÇ Öƒ^ }Tmõ; M" h#7¶íEõt¡°ì-ÿoÒÆóS—Ïâ˅1ÕŠ :o\JÕU*šê:¡š' 0«œÎ <32ål„ ÿ.¿QU·“E„B/Àž‚^ WôeaFÆð(Ñ‘zT¹UMÆh×Ùâê¹­Z÷þ嬁ÔÖd’m_ª*ûVÅ{—èߐBpëB€Ì€hÆ,Ç_æhڌé†wï^{æô>pH-÷"mÕº—²éÿøý£G¶Q5ã…X¶b?U&6þí<ŠÔßåíÚoZ€ãǶÃfÜ2‘×ú·f5ŽP8GPy SæpåØgÎõå¢R÷)Ž›s€9Œû=áÌÆ9¿‹©8ԏªøœGn«/ëèè¢EËîô  „hw³¿£È_nÚ¬ºv³$ÿBAf²Ë$™ó‰™”rUâ%‹m”æ9ÿ-F{}À‡xôØ &È<Ô¿Åò__ŽêìU‡a˜Ú•[7ú×îÈõ%‰À#pcëTÏË^’ þ1ˆ‰àBçóÜe@ÕÉn Ô;RAÕ²›ãœ»7Sœ“·õЪMÿñžsNMî9AõŒ±^|S^€‹îŒk&òFgÍq-c~4 ]¹|¢h{[~&“Wó~õ©õKOÑæD™1Qá0QË×|o\Q–[ž ⓝªàΚí$H“3nÿbI9š¥)|4>ÌÉq1Žނöç„úø;ã|[λ-w—I çi²âÈDmþÂmȘ1îêöësˆï—/žäßÙßúƕˆ¹JòFûó±†ÓΜn!Ân—,Û+Bv™`²ªÉœi[¶êEç2ð§ù'QçWԋµ|…Zâìx cµÔfür‘kû™TR«amÄ[œƒÊyÁ¬sN¬yÿú‚Èvé:$>ŽO-sFøÝÃÁ}kà²2>Ý“Ž™ÀS(§?÷ãTǺÜ>æ%‘O.ÎÓ§ïX-ÊÌy¢\0g÷® ¢õI¥Êõ`1dêO}J9ì“ÉXå*õEq#n¹ÂwräÌkذ"”–Û٘u·s»}xËÔo•×cõ{’޳yóŸp…Û¥KƋ–(Mš(Oœúm£«çrn, î ú§mfBCƒ…Büþý+ >‹Š8À—ö‘Œú³V©Òð'âÎDlôšÎȚ5fÌr¡·Ÿ>ˆ¶7'©xâÏÞ}F£NÝÿ ýÍyñzŒÓº 'cT8þqN.(õæÍ3LŸ± ¹rŒ~›{ÚòYrÅeÎmѲ'í¹È7‹h#äç÷:ŠàöDÒõ„búå‹8Œ˜óY•ý@Ý¢[Æ(ç›êêêŠužúï4ª ÍÆœd‹ý/üy€uŠBȌqDf5Ւ%‹ÄšÅœqr³µÆæÊj*všæ×e_LYv©3ŠGÅõ5Í=éD@" P£FŠ éIuF€%Y˜ &§Ïe]»*oŠAåÔ0ÊAí)sPµêŠºtó¶÷CšLEP¬Xùxõ=yx2<Ý=Oè†øD¯Ïä”bbµpáèèPOoMa`ˆOߋ0Mn'ÓÍl˜ …ß›ËæåžK[ß¿CQSŒI‘‹–ìÕl9ÿðÝ»ç‚`rÁž#ÔR&ˆ”W&vŸ?ŒŸž¯©U»9š57ûIuäjŸ)ԗ•\&¢Üg488^TU˜ç15͍¹DŽâbÏš•Êþ}à:¬Çfì «~Lœ_œ|,È7¯óæ9QوÈ4cÅ>°ñ{e©èP˖=~ …Ž‹o?Ž;º«Àš+³jù+S<000H‰Òeª‚[ïx}þ„{÷¯‰>ªœ/:tØ,R‹]°Åe=(/H#+š¬®2‘å=ðysž*箎Ù … •=hgŒãôiƒb­žŒrÅ$ÜŒq–ZA ê5«©¶oËHLڅóýœ‡«©>K¿~F຿&,ޏŽ&ÆšÐL~š“÷ˆD@" œH‚ªœg§NϝÎéÒç3õå  ‚ú…jûø MTçæå\ÿ!púòcØðDÑRŠO3øòƶÇX"Ô(3)§]âM9ý~1&ŽV{Â7=(€—•³L™²òRŸˆJVÓ\1|cာ¢)Œ "«¯œw˜?qä̕_Ìà ]ßÞuDšîÆï³Òš/_1ñU¶\u¥mjîß»†sT|‡Õďß œ7_ò³ )§cbrÊmjŠKŠË”­Nd7òæ-*Š2qš*ۜÙÃpïî՟æg2Çj9/—÷Pªt¡F«ÛŠL6ážS§ÙE+Ë¿Zãôéœ8wæ€hÑÃy¡ŒŸMÃF£‹qÏÖùó¬EŽ(·…ac’º~íLQ8©\ùZn=GV&šÜ*f°Å*€ôû|>&Ȍ֏yŒï(œœ«=s(y\ZïšGeóÚ6ƒÌª j¹üʆÊ÷5[þ)0fÁ>d̞å×Ö`O¥k‰€Dà÷DÔpRPejRŸWœÎèPqTõ…øJU;o§cçÀn¯jÖíknŠ:weôѕŠ"Žž2ŒÈ©G‰Îj-ˆ€Ny.®ÄËáŒÜŠ„ÕG&Ž¿ ±å¶1/_rqNAæ8/‘¿žð‡Âþ+cÕó5åVrŸPVŠu‰0³"›q˜ñ¹³…ÏL@¹J-ï!SЬâÚø¶Thèý»—hÔžcœ–âè_aÌUṊI™Ðrž)vRó[7Ïc©ì̧îD®âQŒvöU:'H~‡ԚƑ2Ä7‰ß&Ng€äújVP?“‚ÚA*šÚto­s9‡k“¡nãÁÚä¶ôU" ø $Aý ð4èÒAºè;mr— *ì5+igÒ‰€D@"7nº‚j" jÜPK|£Ï|£ö‡)ÔGPe_íŒIV9žÆœ×)P£~T_Gi‰@âGàÅ­%Hkô –2×G«ûU°.zN܉|劣hõ ZœéŒD@"ŽžÉ!ŸRAMÚ7íÞñô7¡ öìÙS)*õAumfîÈT¥pjրѳ¶ãÝ甔ƒ:V³“ÞH$ñ†À¹ƒ¶DPu0ÛŠ]Œ­!'Žކè¢ûä]È_¶ W-ÿ Ê$‰@~|‡‘ÖÐÕl(š6•E²Ô©ÖLñùÙøú|ÁxËæZã³tôg‚"“¡Ö'TlչДI$­Eà֖DP! ªÖž zßt<˜j*5TÊA þ슟$AUÏ%Ì,œGÚ¡AƒÖH–ŠVŒ/žŸ#.]<‚ƒ&"wîBñŸž\à÷|xÿ cFwAŸŸcP·žÌANJ÷‹÷Ëuøâõ†J‚ªÍç T³pB嶍‘³š$šÚ|–Òw‰@RGà6Ô*¿ÁRIJÒ·ÂÆcAÐM‘F}9šâ+T­»©Ì¬Ö£MË5Œÿ ˗MÀ•Ë'1cfLžºéÓÓ£2iÿ 7ožaŒMw <ÕªËïvÿ`aßWëáîñ “­ZþƒÕå’êB âPi°3ª¶kŠEò©kZ9D@" HpîQÔJéÃe›™G^³t:†oÉSª— †ÉTÍ:eŒél±fÝÌà—¬² £ÿnHXX(Ξُ{w¯¢Ví([®ÆßM(¯þ+^<€IûÂjøl”¯Pû¯æ’kŸo6ÀÍÍ S¬[k—ãÒ۟(gnš]ZÃŽ`‰ŽD@" ÐZn»‚J9šRAÕÚ#T‹ãvGHAM«Þß/™ƒª–ÓIÀIÚ\‰}úàsD…\õç¥Þœ}Žk×NãÁýëxÿá RbԘEȑ#Š*Go‰±L°ÜÝߊ1cÇ-ƒaôÄA˜4©¯h¡Rµªl¥Ûá2Ö³fZb¬ÍR/QQíçÏE˜ž•«ø ‚*sPµæN‰ˆˆDG‹Õ°ØîAeÿ‰ßçÏÂÁÎxÿîEôúzzúD6Sb){… —¯31ݱ}-Ν=€¯_œ¢Ç2éI“6fÎt„aJ£è×9”˜CЇ›‰Š•êþÑÞBCƒqôÈvœ8±þ~>ȓ§0Úwí“bÒ-.ˑ,Yrtê<ø§uý…jü˜ˆš‰‰)º™ €úÒÅ£ðóûŠT©Ò @(UZœí™˜Ä;;-B*SŠêÕo‹ÂEÊÄðïÆ³XŒpŒ·ÎŸ¿ØOŸ_»z {ölÄGòר؍›vF:­”bùíÛ7Âm+¶ž¬@xx˜Ÿ–Îhô˜Åȕû¿<¹ÈÈHœ9œOàëîö)éü87¹Z&šR¥ašLéZrÀŸ!ðÎoÞŸÇŽ‘2÷øÏԜ«ÊöµCÝޝ9OÍqJz"H∀$šq,‘g‚ªkN} ªÃºEÔf掬â«E7LHHº [‡áæx듌Ä×6îÞ¹“Ìِ%Kx Ÿ¿× IDAT{{ÂÒ"ªÿªž^ Žï`.Â~³fÍùÓò—.ÃÊåÅëÆDôڵ돒¥*#Mšô±ºúôé]8:,ÂÈQ 9Š«y{ÆÌéD&ß@WW©Ó€ƒ÷Oèë§ÀŒYŽ1|ŽÔ>Tµk7ª†Û,ª.³C7ãÀ'øÁ4[nôèa ÏÏîØža® ܆Ýú÷‘ø9}zcq–ïèAcS€Æ·ž#^ãÐp&ú|Ž!!Á8rØɓëDï…ýt°_ˆŸýmPZÍD?®÷¶Œqۄç/ß`úš¶Úâ²ôóT@!Ÿ=; s®ì#‰€D@" µžR‘€Ê²H’ÖžŸº·;ì"šœ{÷V:¥J}Pí×-D˜÷]IP•©9ƒan㈡æœñÒ7aêØ1ݐ9svA>Xi[Žp4nÝ$’¢Ce› y 3˜šæŽá‡ÜØï$”Éàà@¥!’Ú v@êÔiÕæ¿‚ø±ºÙšI'äÊY_Ÿx`Û¶ÕBEAª,‡Í~o;w¬Ãî]Éb’Èᩝ»XÍ$”+æÚŽï…,Ys"Ê$›•ʼn„ [Ñ¢å0nŠó2YŒqý )¬ã±b¹­x/]ºŒÔ»t˜P”&~ŠŠ¹0gž ŒŒ>a˜eT.«’ ï$uZŸ>œÇ„q=Y\±ê¡>th36;-ڵÇ`D¡ÆlÝŒiƒÅ>ZŽìŽüDŠ#‰üíßïˆg€J7m֍”bË_b=yb?<~6㗣X±òÑã<>}@pHræÌ/^[²ØF(Žü GÏ?ÍÇ-‰¶nY! 8ùûûbýº™8h’ §AAbŒ=ä`ÔB©^¹úð/UuµÝ ‰`¢°xðø9æØtH»IÚ[(Ûk-ZôBFÓÿ2%mDäî%mDÀ•rP+Ë"IÚxtjõÙî°)šÔ« †Sˆo2«ZO*'óö ÀŒ1=JÆãJÿMœ`þHÜœs«‰)H¿ËùˆÜ+p×®rhé7”&Ø®}ÿŸzŠr˜'“¶ãÇv2Äá¯5k5ê«"œ—‹$98,D¡B¥P»Žê­48ÕÚª¿Ô"ü–C…¿7ž‹Ãq4Vþ¬I¹d’Ä6Är:*W©=ŒÉ+“Øïó=yÏóHýãªÆ c¥ŽDÉJÑ?+ÔL&ŒL4™ì²ÂËDžsoÇdôñ£ÛØhNü;czT.,çÞr®ÂÖ­!òagÍvB"Š{÷lÂv"ÝLXžñ„W¯žPUßZ‚@2ÙVçà2ñüj=x`Ò»nýÉ9Á?â¥Pƒ'Ø®ú)7–Ç*ðbRÊáÒLP?f™ð¹3†ŒGV‡y/'­AA:si¿G ò³#nßyŠù:JšŽ²=×¢‘edÈj¢å;‘îK$I© &åÓÿoïëùP‘$5TçKìyST-º¿>ñÃà N˜4jî~,‘ žs(,‡Ä~¯°q(ì÷j)‡ñ²JÊ‘؆YÍB™²ÕEþ!çd~ŽÊ„lß>AzY1œD9Ž™(gòÈá-pr\LÅŠ)Œ ƒUÅ8Ž•I!«z¬îq¥ÛGކžžАÂÉy”?šPâðW&ˬœ2©ãðXVZ•…ª¬‚ž²ÒÉa«LŽ9o²l¹š°Û0[„ÓŽ¡ªº\P‰MAPùû>}ÇП¶ŠÐaV@§LۀlÙòPþå;ºK—í£|Ô«`"ÊÆaɌa㊜ŒIVš”3‰°²²É€o萖",˜1ÿðþnݺ Ë|ùŠŠBNººº1¶Ïù¡œ«8“™3†ˆ  <` +Œ©c…ÝÙq S.i KnHáÉßžZ¿~&͙¶W ¢Ì•‹'ñŸ8<™M‘ËcX•U%GV•û ±Ñù²·î=Álâ«õG]¶Çj4¶êô™µ~/r‰@ÒEà)𕀂što€ÿï|ý¡¯DP3ªOAÝD9šá2U«n¬OžŸ°œäŒi6žõþç*®ñ±…2ŠPȌŽŽî€BT­×ÌÌJä,*ì9µ‘™L}:™xrî¢"דULVVùu…)ÈVÕj0Øb å{n#žfݭОIg•·rêän"ŠsHíME›(œŽ -çŠržh³æf"¿“ Ý!ÂÌJ‡øòkÜFg<…Ø2yM›6œ uü=ûk>ÀV¿œT1wû¶5"D••C.¥ šÅ‹W­t8‡×íÃkX](I‘Ê!¯Œ+µåˆðÞŒyN„3YüLřž²/àYsœE±'.žŽiãLÌÇײz[¿A;tï1\™ëIþýä^Ξ|ë!OTýw#ɃС”íŸ MG BZ㞃ÓÐ-I·$$ˆ€ëfÊA¥u25 þw[ÞpțB|3¢µÀTf*IÚžv"¿Þ#µº²ùäû‚€Û§¯°šâ‚Y¶CpíuÑñŠ«Žrk“©Ó7 u8ûœO•hٞ튁‘·HRô<Å¿&&ÙDAO*ˆ3kæèвéÒe•pÃÂBác«Y³Ìڊ1sf €î{ÅUÙ&YŽ!˜‚ÊI“H}$âô+ãcEÁÎ7mÞ¢»ÊyžLZYÕÌE…{ŠL³¯s£­[VŠ}eΒ ˆLÕ­×&F;~ŸÛîpåÜ9ó¶ÑÞ" q± ÞWì €Saááá‚È3qgbÈŽóQ>ž‰m”ÛË (‡Çr•`3"oŠp^&€cÇtqähzÀD¡ŽLPg&ùLžgW¯œÄ²¥ã£p§kóÄ÷\žˆóG¯_;#°PX êmËJ,ˆââQœïzrŠ9ŒšóhYΛ·ˆÀ€BÅÚÂg¶gÏXË¡3P®|MAnïž^ ÷÷­hø,|}Œa9,JA–öktŒ7ãÂÕ{X:%ªêŽ6X`ýžSÞ|šT†0J™â¯]~ôÜMz.†ýÂ>šU©Ð_Ï÷/&à‡\•z¯C#ëH“1öŠæÿÂ/¹ŠD@" ˆ+®›·AM& j\KdãíE2ýôèÛ·¯Ò©DPí©ÍÌ7ßûèÑ®ŠÒ åÍ@àœûŒœŸ s&ZàÒ˄!š¿Ú9·Ÿ9vt>Aí\ž¿))p\8š5UÁe%I‡þ^8X!ùåœHÎ-_¡6ñé"Ú²ümv^*BŒyýŽ‰|̔)Sã+µž¹{÷ ®Q8ékR ¹2/“Ô–­zŠq?š¢XR\}  ¢@) ùf‹Ë<ŠPâù ·‹V>¡Df™ 2ñWŸïýaUU‡Ô[Eè2WTæÊʬt²òËýSY ðÅÓ'wÉfbY¥jCT#»xÑX¡Æ²âû}S^ƒ[õ0¹|AJ8+«žžn"g”[ÿäȑ/,ü:“Í_õ> qÅ;)Ž×õvÁÙ+w°|jTEgM1ŸvŸIî$ƒA =|øè 7žãüµ§xïî-ÜÔÑIŽªåòaëòÈlUÜëOl.Ô²™³ {×Aóz “·|éæs”-žKìMÆxUè¹ÍF[ u†tê˜RÎ!Hþ ‚ f"‚Ú»Þ?Y_.ª¬?ø©ÒgG׮ʠ«DP¥‚ª/Þ~ðšÛ±hº%Î>ù/Ž6.s$ƱL†8Ôvÿ>ûè"AÜB†Õ\…e͚ Ö#©Ý ÍJt5Åuáâ]Ñy¬qõóbWS˜2WJfûqïü@`ààI([VD‹+¶š2^ßg3.^ˆ…¶4Å%áÇœÇïQºÉ”>è£@nä0¥>ž¡axõî3^ŒñÄ*ðdÕ·Áûßk„w]Æ« ³‘3[Æ?žGÕ /Ñ®Õq.FlŒ™£ÕÓ6<<Uz¯EÓ1Cè?tõU2WuOrœD@" Pw¶lCÍ,z0ïVK]SÊyŽ&šâ«6ÕnÍ|¡ öî C|µå~xóÞ ÖÓ·bÕìa8ùHÔύCI9ï•Ã~™¬±’˜‡BPK¯øÛÐßyþŠÖ13š(‡ÿ©±Š{æÌ>*üô~Ÿ_©bpz–˹°Ü«565öOג×%<)|·àØÙ›X=³GÂ/þ›ï}kg÷Ô ‡Ÿó"e! «/™綏‰Wßҕ°D©"Ùqv[ü®£ØDý®óqúò ï×óÇ«§œOhh8jô[‹&c‡Á(mì³ãÄ$<ù뻏pÆi7ºN}ƒ¿Ï‰NÂPÊ­K®DP+›Aí%C|“ò-±þÀgè«OAÝžf"|,’€5÷Ջ7=k6.ŽÂÁ;ÚY$DkÀN G9ßsLâ‚M\žIšD 6˜ ;wKä rN§ŠBJ]tútªŽu?ggýH•ǃCÂ`’15Ò€6üc·9Ÿ5WÕÑ@¡d+§›ýñ<ª^ÈJg†RÊýb^úÛqŒEíþëÑÄf(RŠ‘•Õu/€HiHx€RŠqdD\&/B_ú,˜€äÔ_ZUۂj·úÿ!Ÿ’ þÝÉ$àÕO^žcÒ¢}X7Ï\%AM@èãm)þ€ÆœL¹zîÒåû¢ -Åۂrb­D@ÏÇ×o?ÆŽ­©ÈUÌÞ¶ÿrCW]_¢j›Y(’?+ªP!€TT­×Ý÷§‘‘ߢÝ+Q8Û[!«I܋?ÿ{,ÂÒÉ]`ѳnŒoùÊ헹Öv–XgÅŽnhV[-k‡¢þàh8ÊR%BŠ–E5p÷ç¯qóÐižžžÿ/_¡oh€áÔ;}–ß÷†ýðä%–õ%v4嘓 ¶?ZxXt©ö¶r€ Þ>x ›]k‘Ö$þs˜5vé’D@­HU­pjídk‰ ê©“ nX5Éü¢W‡jZ JRsüáS7L]²X`ßí"Imû‰v¿ö D‹›i36!O™[œhú/6–‚êÙ«w1{L{p"M±%v'`=mk w85?I*W"rQ1#V ýBpñÆ3l˜×åŠç„óž«èÙŸªÈ]]çrNTüµ±h*ªå²òÊó6«W…óesÏ[scgïÄŸ –"—5ŸmµÓXØ:‹eÎïCUˆó«eɀÀ4d‡Æ6V0Lm€–9µe’à€@\Ûw®ÇÎÁíÙ+ávºÌ™·Lqøø¢=õ÷VVÙxÿ;\Ü~PT2Ÿq&æ}ÇóÝ!…tǬè=o<ͳWøœƒ¢ˆ°Ã"mLú)Ðh\· Š‰†È_>§øvníþO”ƒšE} ª$šñ}dêŸÿþ“˜±ü6Ì·ÀÞ[’ ªá3#tâö1eÊʂeÿæ4Uo'\œùS¬[!•ÑßµeRçnOpÂç³¢øQšT‚tÖ¯^Óÿ:\“ÕÕ -ŠãԖ‘Ôœ&êtŠêÚd[–›‹ö1­û/lj PŽ€)ܢµ’:}ëçôDÁŒYD˜sZ æjÁºº±‡y>|憥OâÈÙû‚ø¶nX,›©„ßž¹»0gÕaKŠðõHišžœEÿ€`4l‡&ã­a`”RG¡±s}~ç×ãçqiÇ!úú ?s•(„jš¡x­Ê*‡é†SE虭û‰9žò„ýQýª¿·}‹íhƒ(߬® Œ ãkŠ5녲k¡ÃxKÅJ:&Ð&\ˆ f–U›Î,>|]»ª‘ êzVPý · ñóŠ—9ï>zÙ«aã‚AØuãßöA— ÊI%* °wÏ&äåêÌ%+©0:q Iæåˆ›wžÂvh‹¿ÊåT7[N§s?zš·—ç"[–ôÔÊf2µŽùðÓôœ×: k-jӆzÿ—›»~Ë9R@7 565g.NB_ kÅa‡á1æáðáGÏÝ`œ!5:4+/¯™ÕzžìœªöœW?ÿ`4¶ ‚:aD¬á©ªà§Mc>Ÿ|‹ýÇ ,$zT˜štƒšÜвÌçm\Þu{®×ç̆›®æŒ}ær:Ìê©ù²©Ñk<Ÿt›FÏD‹aœ‰7óÚò‰€Dàgî8¹ Rf]Y$)‰ßëHAÕ1̌~ýú)EB¥>š’ *ÅQãž>|‡ùêf·` v^—UãH:” ŒÑY2gÇÈÑ d=XÄÓO^ŒÅ°Þõ‘>f„†2éKS|ˆãåâM†z"ü˜¢v‰FR«]RU E$#ÊMU˜õ2íI=M9Œ—{g1N+HnŸ\Æ¢_j RQS§6Àf Ÿ¶o‚ÎVq€“;{FtiU …IE #ò9cùA‘ë:¬Oýè±ö;.¢ÏšMȔ!VÍèNó•„××ÑÓôùk"ÓQ€—óAۚ¯À1"š +KáÇWöŒG=ªà{þÚ3ÜÞ=:Å f‹^óÃGoä­a#Hñ—;KàKcŠÕŸˆ¯Ÿš[µ0õù®†’EràÊí1}åÆãÓͅH—&%º]‹­û¯£‘]Û¡ÍÑ埮“¬Z¢Z»Ù`2ôd•Z‹Rù_Í-7¡±íH‘™ì6åœî[Ž^TÞÕÑÓEéúÕQ­cs"™yTÞŸƒÍ<<*÷ڂ¿7-˜ƒWόq=‡ÏŒÔôé§\D®*Û¢îVòÀžÝQ ¬4‰€Dàïp%µJf=ÊAÿÂuﭜ!ŸX³×B|³ª :¬[Œð¯w$A¯‹‡yoÜ}%>žm˜Û[¯j7A}ðàìÖφ͞eÈdUEšD@¬­Ú!ušt˜2uƒ*ÃŘÈO›ðìÕ{ 2«ƒÌÆi4bOL9ô֟ ÿ|þâO!¶ÉHáÌDŠjÊAeÕ4ª˜T&j£Ú Päw–)–vŽE»+Ež(‡×n^Ú_„êî<|¯Ž.ŠT—òTÏ^}JŠšÌ)€Wa®ߊ|V®ì}w)†SÁŠMÛ/bp:‚ôúÉüÞ8‡w‚esRj=PšÎT+ŸÇ­I퍪úʊn“‹qüB”ªúâü,±'uç–C7¡‘íš$Ջ“s@o<‰+»â‹Û'gŸr%P§{[ä/ÿû¢W—v·Rë†h3rlëw!ÂWNq,'7nÃñ [£•ù‘.ôKSpÅà%œF L£šèd;L]G)ç‘$y$AMò·€`Í^7"šŠê#šëV̅nà#ô”U|µæ»yïµ(H²–ú º\.¡5~Çæš£ýB=º 3f9"W®Zœé|Â"`5Ž LLL1nŠ„]ø®öѯߺ …ñOÚŽÄ§ë¬ ºQiž™D1"e¶ãÐMªÈ»ǝGˆk6﹂ëw_cõUœêÊOP¿o'Ôë{ŸYn ³fˆ­ËŒf–ÀlbƒnÈ^8_ŒSÆq¡Ù0„¡Tœê8ç²-­ú¢jûŠ8ŒÊg÷ ×Œq(\¥\Rƒ\îW"oÜ¡"I•e‘€xÃW&懺ë|Drƒ,èß¿¿R—UËA]9Éý —,’€PMÀ•«RÚ/ì‹-WŠÓÿí$Kh©­\1 —.Å *ú”6m-݅tû_ `9€rç.„#çÿ‹åÿɚ!nàæî‰íª"{Öôÿć„^t¹ý)‘—ª •\øhäŒí"ÔWaL$ûvªŽùã;åU?ÿdΔï¯ÒÿoßMúÑ÷E돉¹èoi·6•Áí_&/Þ'‹Ê§ÅýPŠéTtk]IüœU—}¡\Ø6VLPÇBW_9™W׺š8Ï»GÏá4~|<>£“ÔÞcžèëGÊçHSh®å†¹B åCãkw!Ÿ–O%•۬PIktnrMê`qOkä(Z€HéxÌï<„°ÖýO“ëÄ^ñYñ‘>I4.’T™Š$É63š~Rñç_ŒTVPu¹ªlmG§Þ™oÜy þжialœR ‘ßþ«Z©Þ•â¶¹³­pÿþulr8ÿÛ’ñï‰æ®À¿øÎ±c;àïïƒ Ú£QãŽÔb#*¯*©ÚàMP¬XyXXNK2Xï¯>h߀rRQ¢€jLð®Ü~ Vm¹:o͊cT5nÔ}¡hQ³hb' ¥‚R¿²£ç iÏÅâm.ŒôŽú°²Ëßs¯UV©kv˜ƒÇ/>âãjûååívÃíÑh2TœÄOPŸ^s¹ŠÜ&6ûðô%–õ% ' ÛŽ z+­ö£gáɕ[(X©4…—‚¯§ÞÜ‚wŸ‰qºúúºqžPWY!e¥Žß’ÉÈO¡Ã ºR±€·>« ŒÝ=P³K+4µè‘TmäŸ%ñ‚€«ãfTɪ!=ejŒ¬“òßꍇ<ðMßæææJ=VQA ƒ°gèJ¥ißÔ׊",B{ŸÛN药ޟ±lÅ~íÿx¹aý,œ>µW¬Ì€4"" –Ä›¥”3—4 ¬Ä»yÿšX¡ú™û§òo– §ߏ^"U9‘ÿf7ñ·êUחšÓi"('u">Þ¯AtÓ*Æôè¹»(†T¡dnL§žÒk7Ÿ£ß«H˜dJÁÝë`ô€ÆÑùš'(µQ÷Eѕ„Õáõç/~è`í€FSl¢ øšc^Mœƒ‰ä ó±0J—Ì»¢pÕòH“)Jý ƧWïpëèY\ŠӒõª¡ëëèmZá Ât¿7ÎeNk’_?}E†mœ,ùr‰!\8‰C‡§žØ,&œßº—mŠŸÜÊa²äU_5fMÄ[ú$HhîA­, jBîQë1AÝt˜ jfõ…ø®]>zÁ©Šb5Ú¬tæ×p‘€UŽg±a^/j3S¡áÚ«€ Ö)SŠŠTyä± °Åe9ìwBáÂeбÓ@dϑGoÁî]P«V‹$EÎ~„§O¯ZšS§ºS_R±À·k©ª¬Z5,ƒŒ9“ʶN\s÷ IDATÿhŸÇÎ?@g‹5¢@çŽæ§0a&7¯ß{‰ŒR¶¹6í1ÂŒƒBDeß4€Æ*ò_¿_”sUÛ6.‹ŽTõWÆ*mGk{4ž6>ч›†…„AµÁGj5ó#Ñäè…1É䞥)Ó€/)ZÂçÊF¹Šù©ç©)r—,Œl…ò‰Ö꣔ˆnjVý1°ßN̆¥€ÌzŒ~‡ZÝÚ É 3uŸœC" øWgT5M © &Ùû‚ðÚñ@€žTIPµï~ºyÿ5V؟†ÝŒÞØ}£0‚Ã&D,88®·/áÆ3xýú)Œ¿x zŠèÝgôƒØ¯o]äÏW c©Š¯2;zdΞݏ™TP))Øþ}ŽØºe*U®‡Aƒ§ÐçÿDìßç@ï­ÄËéš\å×!Œ‰§ÈÈô0«†V­{¡Cǁjßf@€îß»F}<ÃPŒDEÉx»þhF==óç6QûŸۄ ŒxÃqœ¹òDôVMA9ˆ9LÓS~ivT,•fmªPTB§Hx|öA×QNh0•êordËy„…„âá…ëxtñ><~ÐàDFDrnBŽP•²šÒ¶qޚŒ‰.n?(Š õŠ–2Fin©Äù¥Lz͗MAÞ2ÅÁkLjØ yJC ñUW~K!Á+—IX'–{FîC{žãD jj3Ó³žö8-=U+áԏÜñØgAP¹*? þ©â»zÙl„t9,ê‡=7 !(,~«@úø|³ÓÜŒq!!Q…I’%KC)ZÖ#æÅØî•+'Äú"EÊþ†àà ôëSå+ԆÕðÙJ!=²³ø€1{îf¥ccàçÀÓÃM„Æš˜dCº­cýEzõò1ô(·){öŒ¢ ‡UfbÞ²eO4hØ^LŠ{w¯ £¯Ÿ¯^=Æê•S``˜#G-@êÔé~rãÚÕSسg#>º¿…±±)7í,TÀíΝ˘7g8ræÌÉÔF…çÿޘ8ÝU„û.\Œ+Ö=š²Öµk§qñüa ²˜LçSbxåò Ü#¢æõù£š–Ëë]Ÿt\ì59ÝiÓe@í:-‘*Uì¹erPAAصs=NŸÞ‹ L„RÌký÷!• ä ñíÔÙ-Zvÿi™—/aû¶Õxöôžž®r•hןÿO8ÆæÓÕ«Šâë×ÏâmúÝß|=Œicøʝæϟ?޳f͉Šë¢^ý¶âw#>ÌÿÍj„Ó}W¿zQ  ¶ÒŽ®,Üe”O·Uú¹vîðÏœö¡ÓYmÌEžo»1ƒ„Z›Ù˜.Ây»LŽRÔS•I0^.€$M" HZE*𠶆®"êQODRˆ¯$šzH á·Kà*“ŽTarÿ­Bð‰_‚ºú”ž>µGl­Xñ hÜ€3Š-kþãǏï0ÒºƒxoÃÆ3?Áqø >Œ)*¯>{vS&õGQ*tÃJá@"††Fț·²šFå)lÕÊÉ05Í-ÆÆÕ^Ÿxˆys­áç÷Uëté3",4uëµ!âÒ蓼C3§[¶nÃIìܱN„Ô²qèœy.Ȓ%?ºéÓ¡µ5šRµ!ÆÛt{`«Y³ÌÚF»ÉÄnù2[\'BÈfL=_==ÝÅ÷ƒOFµê£Ç217¶;ÜÜÞ`Ö'dË{#û‹Ž€1á> ùòû£µ–/› HhÙr5è!Áœh…É-+ޟ>œä³MÛŸŽÇÃWDþØøu&Î9(ìx í!uê˜$• |` ¿xXÁ6Žv¡ùuˆPF)a,˜ø÷íoƒÒ¥«Š×øaßϟߏqÄ|î£Ç,Šî•û™³ÕÐÖèIÕ= :ž.›—‰¹˜àò™0þµk·T}éÒ1¬Z1™®Dþüő’È-?„УB6+V‚aJ#"®^âÍeËÆ$Ø¿ï_Š}òšC­fÑõQgŸfʔE|öìŒ{ûíÚõs¹Óϟ7BœÛvýbì9¶ü_¯Fhhê×(ŠBy£æ”Š}|ôôAϱΚ?u‚ö9ÏGÐV<ó”.úەŸúâæá3šL}Qõ “n.~<‡œ^" ÎAå"I2ÄW)T‰v@XX8œF„ž$š‰öUÙØjJ¿`í18A=p» ü‚cªkªÌ—1Ý‚yTæŸB|YulÓ®/ªUk$ÈÆÆŠÜÒÅ6(P &MY÷Óû£GuƧï±Ñþ,…P^ÇÜ9V¿t…C[[Lùëjµ»b>+Vûôƒ’¥*Sž¬.…[7Ï£K×!hÖ°ßœs%š r˜l] ·ÍA!­L(6)`ÂÐŒ…:wòÇÃ*““€_"ÌëEÈ,‡ÈZ j&^72JCa²;c„NžØOšxLjôõ 0aâ*d̘Y\ÄržõœhÿY‘eō %“"G‡…8vt;~rD."_Lð™Ü1 ápÔüDÞ9ÿjÿ~G AœûVk×LÇ9RÚ:v„ãÇwP®¯'Ò§7ŠëŠÃ—°aìØ˜äY[µ%؜Î>ⵞ®Å×°BÈ*=œº"àî=¬…ÊǶtÉ8°ªÊĊÃmÆÄŸ‰<ÛÛU(\€Lô{ ²8pÐ$AN9t—ÍŠ°ã= ÊÄ{åêÂä­[;ƒÈlTEç=G a£â{Ÿþ8µÙa%—CuYݶßK„†óC6áaݞZñø¢zõ&(S¶º8ӋÔg—‰oRå§M"–±+ƲۺMŽïð_™ô ÀŒ|õHŽŽaã³u°_ æ›Hg¡x¡˜“C~'Oì‹F:¢!µâûÕÑ[·Îãõ«'bXW³¡¢ÿ/ÿÌ¡à¬ì[!òg>/VÒÛ€W)ŒÂù²þv¬|Ssxïþý&ž ÞTí šÏ®ßEžRE’|ÏVÍœ£€g‡À—­(o¬#ÛÌü»#øç+³‚ºëŒ"ÓK‚úÏOã:pïñ{Ì]}D„øŸ“_ã'ß-¶-rx#°>zt›ÈKL—.…üv¢¯.¢ˆ“&¬Äuï1xáá37ìxù«§õÁïöäMœJ™X(ˆ«m¬Š²âôžrï8”rÌØ%xG”•-&“§®Jë/,\8*Z=R(Y2p&Ï˄«Wâ5VŸŸÏ 䞀ΡPÑ¢ý ‡{ò^ç-؝ƒÉ!›–-‘¬U»9†i‰ ë`å%~xÿŠì¡&æËWT“ï«óòž,‡Žª)‡ϙ·EšÖœÛˏsR9v5§?q|'Fæyøœž®ÅóÚoZ€“'¢ -ñÞùDâ¢?lL&VŸ'N^+H8ÂÚd7W(ѬsQ#>ûïÕ\Aå9ªP‘"ÎçäuØy·LؗPHžâg&¡LFÙŸ'ÊOžÜÁ4 E.YªŠ É •’UÞF€R²1d\—¯<(”ñ«WNRþ§;…fç!Õ»z¬58gšÃÖ¹øÖî]v”oŒVä“òYeË{î¯"›Ï”Iö÷$•Ý•Ë'Áû«'ÆOX)~_Ø/ÅYr5‡ ³)rbýü|è÷ ‘J9²ÞÏéa†.*•ÉMPÏ^}›Ù;áåí/ªZB!Ƒ¢bmV“Žðö ‚A ]„ÒÎHê ‰0zèBmUR€Ðƒ×lYҋ³ç6*éÓŠD&"ž™2€"b›Fü̯3¡ßG|ÿE\U~ï5}Ì«wž2u;jOÖ®ÔÓ;qŠŸ²æÏƒls£B‹ú0-ûŸôO" PwìP%;‡øÖUτr­C Š zAÍ* ªÖž~ôÜ “îö•qœêç š+WLU|™¬ÕoÐ>º@œ… FSû™‹èÛφªâ¶áÉÕOéÃÿgR"™È4mÖÜ€5O0s¶“ <6|€B]9ԓ‹ÒRžè›7Ï(|õƒøpÏê¢BõhސPLF᠇b͍ b.(3jd'¡ö²ŠÆÕ_™xòÚ£ˆèŠOŸ ¬DrÅ\ÓíÒÕRäWZ j*B/ç-Ø*B|vúÔ^0IeÒÌJPŠ­PÔ,YsÐ/걟"¬Y•Û` õeô÷÷CS¥J#* ß»w5šà3® )|ô©ØF"w‘pÁž¬õ‚BQí鬞€Tɒ•ÑÀ"Œ;°wÏ&‘¯Ë¬?å˲bŒl)©‹DøøL˜°òÍAj#+ŸLʧL2„Ãƒ¹pÔõëgã"I³çº{üØv4!µœ[÷ab|ƒ69ެžwïVUœ?L>³KŠÜ_&…«1f¢?ftVÍyÊlC7uي1é_aÎ÷4Gð=Ë÷.c>—îƃ‹?ñÃÞ[ÁB%ÅÃÅ}À÷ü˜Q]…ʝ;w!á#¿Æ•ƒ¹€ßËVV³Eug.2¥ÈeÂêK{àmŸ×ùR„ÛNè-îKe-”^¯¢íD jù(ZàוJ¹¢ž¯0üüƒð•ú€úúÓÏAôsÔ¿üž/œîíˆO^Ÿðñ ÀW"²ŸÁ‚à†R_Ð0„PI&ïºÔŠÅ€È,÷:còõoœ®C÷ž.‘f}¥LÔFHMœD3Š7""›’ˆo:€¢×M2¥AãŽÈŽ_ÿOÙåk’¢q˛á3v Æ€ñZ·}owì_ºaÔ*† %£û£Z‡Š(Ûž¶ÖíE:,ü=wíQ9;õA•õïÁÔÒ5RßœzõŸÿg*ç Š€T© jÏ]ñø…;f¯Š¢«bAËäüBV0a­[¯õO…œžE çlrµb&Üچ‰*eÆaº/ˆ$ýh¬œ² Éy« cEŽ‹±ñCU×b¥ÃJ9G—Cb‡›­är%[Vg9O– 1Ád•Ï~Ó<Ü¥|U"¬ÅŠ—§<ÍB!W.ââRœËÅ¥8<—Cv9·²\ùš`µòŽëe‘WúœêÈ!áŸ>ޢؐY×Ê"Ó¬»•šzü„ˆÙXIæpZE«&„ÖV”oàƒµëŽG¥ú!*áüΟŸÞ‚³›˜bµêaãóe"ÍE‘9³ü:ßó9s œèîÂ?ÞãÿØ» €(³-ü ‚š ¢vwww>»»»cm×îîîwµ»ÅVP$DTRß9wDWÀ'ÎÝ7nœûÝ_ï~'vÒs{“\‰Y¹f^Þ/gãåg]ëiÀó±»8ÛÍÏ-»ºsb©Š•|E¢¹t'›š;ïOW÷f“2j‰3†*šºž§_ýýûDléEäUKn™è2ùõ|õž€Üzœö#²ûN^~ßÊÊÏ^xžAxïHD7˜ž5ª{I*} M}ŽO€æò1cɵ"’KJ.»"3f’ËD–I®RtÚÁ!‘-œHÑuJɒÄGR"Œ¬ìc{ðÄý&lCñáÆGPµx[»'7îAÉÆ5©iþYœÅêWEqzÙ'•œÆø\ŠÍ‚@džN jQP#ÉŒ‰‚ºbñtXŒœ)Ո“;Ü0fö¬˜Ò§f‚û›š'š “þp}ýú"\nêÃ6'¡Iš4µúP¶TJDád2À&&}ÐgÂðmMΈÎ™þL&˜øp¶U}6&÷3ŠP$ªZõfÊu•ã1™ŒßsŸ®ˆ,»"s©šÆMºË€0gÇju©À3åTø²}+–OQ%zX•mÕºïW ox×âKƒãÇ÷š€Fì2ým¢E Èå3¢1ЬŸ§€Bڒ3ƒ jXU”US&actµgʱ ¹—"¥—»’ÔL%]âXUŸàH–< £ <£ ËÉàê•Óʶƒga҄^ð ¬Ä©–ê·Ï._–p Uv%~ôè¶RB9A_L|ۗ÷È/V¿×"ŠÁϞ=&š6DP‹G#AÕ矅DV¹%²Ë/Vm_zœ§×[xûŸ‡çk_"»€æÒ÷¬ðrŸwD?|ú¬èÓELBHÅ'ÈU³&<ÈùA‘bk"º±m¬èe­”[&ºñlc+’›^‰Èm™Én2§D†mÉ:%°Uý"ú¬ÿ .÷œÄ );Qt蟿2ÍoË êŸ¹+áþØU:7‡Û£g8œõ/d*œy*–€ÄJ?/óÛ7Åx>{3Û÷£jז’`*б6ŽéƒéߝÝ3–¡Ló:H˜ÌŽkV_§,Ÿ…“YS êϓüÚ‰=úC€/£7ý텏±’£eKúûŽrÒü¬…KA?k‹/»š3Ùu}é 77p£dQLt=•šë‡×>ï5D—úø}v]þà¯q[frËãß} =J&šìÊÌD—ãwÙ¥™U]­ër|J,•‚buc“KsB"µ€æ²â˄7ž¹6³{3œâÙåØÞŸ5gºd1{/òø»%œ®ûÜù‘ŠM}ÿÆå[7 ôóV„PÜs©&µ³¬y&Uºzø$6Žš‰nK&!eVMyi恀¯—7Æ×n*][ tÓÚ&œéë«IAMF1š­$Õ€ú'›ÓTO"š)ôGPçÍ»ˆ šç? Æø0ݺ÷S©êŒápýEV<÷‚j çÈePŽÛ­T¹·Ÿ>ˆß^¹…æÈQé3dÿŠ(r©vÁe¢eŸÐA¹CsÜ"×+åžMV_}iΪìM.Šüa›ØÚu4Y`#²–!aמ²gÏ^PeNŽlã¬Ãç)/—¿ñQÉœb+WälÙó+ÅXß ydíŒÌ8&švq­Q$_z©ƒ¿3†U]&²/‰äŸ —;]v]~ý¯œÉm™~÷Ɨãv?(—É­»—¯úžSëü¬ž+–Ÿ!×eú†ˆ.‘\&º€èŠNžHõW–\—ÙËùÞc€.[¶öñ+Nlz±U_¿Œ¬©¬ØÔÿꌞ ÐÛ4¯ÞÆÑ•›U2®RMj"nüxøwË>žÜr&%©. լ𷵌a¢+‡N`ÓèYh?k$2äÿ’Ðl 7ž¯0¡NG”£ ›JíÿÚd>Z¹ørT!š~RQgž† ÒgÑX)… F̆?3Ô¹«þƘŸµq×+;\^Å7|£ÅÂ#À.Õ{v¯¢ÄBÛTmÒï5V¹>+'dªFµgsæ*áu i—؉×£F/3$³ ƖWΚÔRE2 A5Sa’ú†Ü‘}ˆÄjŸŸ'õ֏ˆ®¯J@õŠ\–9>7bpYíeÕW¯û‰ˆg0)º–‡kAê>'ÒfÓf×p&¯œ”È‚~oËV6±a—_q'¿ì`7Ž"žÖDnã&ˆ‡˜DŽ5DWóŸúþsŸ˜V?WwõëÓw•¢êóғÊÒÔAš\YÀ1«7EåNÍPž'Œ3ývùÀql;mŠEæ"_jD›þÎe‡>î^˜X¯“zþ«tinҀÜÛ²yì!Õ€Oùç›ÓTëøѰaC}¹øŽC¢˜.hPMS„^šá#ÀuöŠ£ùGM<ôÉI5á-FVS>Œ…—n.ªüŒ}"¥òËÁ!Y„Ü#mD4 älÊ·o_ÆÜy{—2Kû/çY”PÈeŠfFŠtI#EàŠósŒŸ»y R;ð÷{‡~ïÕWúúA}%R˙rœßàÝòš xÏ÷Ÿoñá­æwþï> ðƒ¿ÊŠË–‰§%ӘÖV*•–è²w'ÅN…æÍ›Óçҟ_„†+U\|uÁnx¿¿}ÿ9®=Žþþ×÷¹ðē®®€ &€g^AõU9‹ïÿª˜¶[TdŽ‹ ªUL T(‘ ÒHŠÔÈ`hcnÜ}Ž T¯7?Tåü‹-à=¹‡["žoýŸ"œü³†ØŸW$÷œ¯ö÷ïðޟꚊ&ù VÖ֊ä2áe·bmâ(VsÉ¥ULL¹/“g~É,“Ü/äVC`ù}­ŠËٚŸÝŒ‡û篪r4YŠç§ï¯áåçÊõµb‡&FãÆ‘£:¿ç¶OZ€ËŠ yæt*}/W7LmÜÕº·R™®M¹Ý$‚ZPª)±ÎœiÔO6z$šsŠ…œÅ4­]D§ÒÁ0àÛ÷Å돣w»Šð̃Ǟ Ã0±BøEX-îÙœ&rå.¢JôHûEP-c b©ìHŸZª±>7îžbâ‚ý(8h‚>iÊîüÎÆj¬¿ß«Upê¹Z‚kcnž(Ìï±ò+6»Ӌ”YVUY͍ߖÊÏ*·e⧪Î4'OòõzE÷µêç&Üî?Vê®%e}Œ“À±?“Ý*]Z ]Þì¿–p¯}ÿÂuÊØºeZÔAþ*š¬âÜÎl?€]ӗ ïúÙpH•<Üó[GwO^ºÎg¯;wVR Ð¥Gcۆ^íåÌÖ3袵NÿN&ïÒ. ª^£œL£ º“‚šZ ªTã{ØÅw醓èÒ¢ |>åÃCDÆ· ±Xø÷šÎ+—áá ÃÒŸ!šwgRÉk”+šiS9Œ)AV÷¥“à˜:Etšd0k¹ÜŸy¡ùžÈQÚŽ?_ß\C.ŸIˆ ¶–Tƒy£ÙÎR¿åow|ŽÑ£‚*5šOQËÝŠ:𫷟A“š…»œÝ䃪`•)ƒGÀËyŠ*eR«R^€¢Ò%Ҍ+·žbú’Ã(1š|CŒ_Aè);èUžÜ¹‡‹{ÿŠGú“Š‹M“33:ÏÑé ¶ÿ¡%ð÷ª­wl“"ÞÜüßœÇüNƒQ®U}ä©XÒ`m×e×ùdrÊÉ»8K1gjÖ6>Ë-zQêè¶x¢RTÍ­= ‹—¥œG¡ÝŒÈX0—Þ·ïz÷¹Ú?E¢äI&wÖßÃ-UïÇkt*‚zô%>ÆN£?_!šF÷ày_¹åV/ »Âžë&®~ÆwŠb± q^ߛ… JTS¿j€Hjîߥé`‚:céa”"‚êlÕåÎpTV]éûÄ)“ÁŸ’;q6ábu«DºF*P?žx=žÞpFl;[ä®Pœ2§6֙a8pŒjàÎQ8ó³Šmœ {ÃÈéª&07ž—KÒpÓ¯ÊÏë’^#Õ×5ÎT(}_¹S—mY•;6UóðÅ?»ü•[ŒÄ ÕEÆËGOÕóÌ--ÆTïñŸGVõù{ŸùwÓ:k‹ÐœÜ<~–€-£çŸ3²Íÿݳf‚Z0©žø~óxS£ º‘‚šV ê¬i£á`劯ä.*Í8žÇuëiT-›ñ“ÇMW'ã0\¬_BàÍÃ9ðõû€VõŠÃÉAêÄþ˜¿q𥛔@eÙTÜîAŠCP9›-`Ÿzø€úÐË ùñ‘ۀʱڔ—ÊÌd/Yð—Ñ¿°÷šŠudbÊìÓǻ·¯}0¥Q7•9˜I·É » `ŠTê£}ßU!V‘êîŽýƂ]1¹… º Qd¯fïvÈGœy™ÉêË©L©oÚ6»m?å^ÊĕUÛÓ[ÿÂ ÊÆœÀ)1šŽî«lâÆûDk ݳë†M«šütg¥§¬qÝÓ['Ï+·EŽOÌE]µq˜¿Š>»„NmÜM¹†²û'_vïœzèž"kLܺ/¬–™P·#©œ '/â²/ÜØ.gsn×!¥Þ±’V€ÎÿP»oEÖæŽë¯”C&¢ZbÈ.Êó: Tã9KoRôÂ6&XœiÈ®¥¡Ù‡W œ Ô­Þ«ŠÿpËg¶ïW€€Is£aœBû_O –ækHvÅvšt‹&ñ7Vœ†–k¬ˆ8»â:ŠI©H)+ˆk‡LA^mPŒAuëÊî¯ìÎÉJa§¹cW«=²•( T4n¬f2iå1ù«–U*,»ïY±Yeò'žæï.)3±^gE€™äœß}XÙÁ˜0٫ٻ}hÌ%+ˆWˆ\N8¡Qn¹1écòŸé «)âÃãØM›/ØU5K±/J+âL’ø9‹IuzƒŸ þ쮔Sn‘=3&‹7ŸC}"Ьs³K”€j—¶ÆÆQ3Õ3Å-\"ˆÉ8“Á‰õ4É»øâeÀæù*Ÿ–]gÓe¹¡»—©gæäÆÝ€À®ú*AÖ£+·°žÇpõç t³ÚJ­eEóøºÊEÉ-“Üï5¶clvÊ%þ53a×6>cvÎGžÜ֝¢ZŸà ‡oTV ùR†³/óEOá=Á—,Ž7Vî™À³jËûá Ÿh»®vÞ[«V£`ò8BP¿{ræñІ Ÿ 5~T!šÆùàž /_õAÀ>~܍•Άƒ€– VÒ.ƕ@†•²Û'/(×U.#꟭}TŸA2rõäÄ=üޓ’ÄÜù÷‚"|ŸÆê)«pQÝŠ4ž?I­ü@*êõ¿O+eKšd%eP«ö±LP™”2iE±„ËûŒQæ1‰à68³UEXÙ­Q«ð5ÕGÕñdÒÆ.ì‚Ë1ŸÙJ"—Î…Ê5³ÝŒá¡D‰]%Yu+׺*µo¬ÖXÞw,»°n¿ÿnދœ³W(·T^Ÿµg·î‰¥H«aL˜°.'ÑaU˜UÅfcú*Ëî›ìÆÉ­ãœQÊœYÛŠ6é®ÔI&Û§Ê„Ýhµ¥ožßöÉ (~óF\­ÔÛ oÛ{5Ç€&UĉÝwã%N@ûͯ”簍cs·Oúâ²ÌnªLŽOoÛ¯\o¹±›/'jšÜš+’eL«”hn¬Šn"—Ýšä6]¬^u¹ðˆb_cÒÙ°«1 »ÞsŠ¡åË&·¬æ2©+Ք”F"àÚÙ3ÓTž‡‰8Ÿ »s 0“wVÞ9!»0³Û/ÇNóÙpc·ä. Æ«>ܖöIû¹z±¡U)Ù-V«OšÓQ¹7Û_/_ò°B™2kõl}ëaÀLù€‰óžÚHýYM/׺þ/8ǒ²zÊ*jØÆ1Ø|~ È »óŒ±€ Ÿ Ý'OâdJçvRCŽ1±Ü‡•ùÅÈ Aý b³üAï•oç͏ÄVÏЈ’nH3ž¿ôÆüÕÿ xÁŒÈ¥4.=In†‹•‚€ i˜ Ÿ{²žybhÏêˆmcé¹dàïEàâµ'˜»êoÔü³'î9ògVêX ãÖLü<žžšÌŽ©²gTdIL¢äÑf2®V;R ?`¹žþHqҞ°– r†ØÂ”muLµÖê—…ôÙç3ùúkÞjå’9lßJr3}Eîšý8?‘R†Y}eR”§R)r+íŠHg_å2LÒY…bWSN2Žšû°¯Üq× ›Fq§UÒ"íZ§¶ìS„·zÏ6äâZ]%æÙ9m±re¥”ݍYݬѫ­"qì.͉œXéäžW^Ϗbmy­oU<Þ3“dv­Ž}&!Š?úm˜ªÎrvËå€LçŒVn܊2¡ÍP@w9”°D”çb;¹Ü^Úÿr=æÆd38(H¹­†MÄkqŒ&ÇÙòyü¬ñø¿WnUçBÌutVq°«‹W®ntQ’VxÎªÌ _dÎLKPyߌÿ-ÿ ‚ꪶ6Q’6>”]^yV×Ù3à6aÌJ0»J³¢ÍŒTVyٝ|×ô%*©»¹sBšiM{ª œÎóÇêü è)¹Xó¹Œ÷W‰–øB„3÷n#rÉ®Ä|™>_N¥h2±«({>3[öAa˜±PnåŠÍ.ºìÆÍŠ:ÛÉI§X-ÕÆr³ÏÊ4»_Ÿ¡Ë†\â¹ñر5ڒ|eõ\~ۘ L[\|užªévÐÔçäâ›^?.ŸBPóayéñ‹7GŸ©‘%GY\x$Õ8OR¬Ô÷OÂù¡Æö¯+R€'®>ÆŒ5ÿ 6Ôûþ†KP™˜q\ Oê “‚Õʒklžÿ$í‰Î“ЋB5+qù¯KhX[83í{r™e÷DNÃ$‰?Ї-ßÂe8tŒNóÆšŒ«œ,çÀ¢uJyM”" eýý תôUiŽá;±a%rDR?«‡!kƒ©ýð_…Jµ”nZ[™ÅaYŸÑŠqÜ “#”]÷žÊŒpü,«°òç Ý«gk†LV.Æù(ÉTá=”ÉD/Â6&Q+(Ëì«§Sâ¢'Šø~[愳µr|*“ N„ê »Ž2aý6Ó·çªu þö}vÍU®žRÚC‚‚Õ¯YYLDY«hsV^&NGÉçÁÄéGMëŠÊd³kUbNôÃ$œ±`%µJ—jŠÈœ+ŠÇÖì ä?SÕYÜ¿p \Ú&‘nmcš]s V¯@—o”ÂÞgí,ï{`Ñz¥äó¥_àð¥ƒÖ— éŒ(‚ØfÊEا7멒Jýš4OX,vN[¢JÄpãóæsçÆ%nx]ŽÛø²„롲ÊÉ*;fŽcf7jNìŪ0+µ…è9fò­ÍXÍD˜UüfDʙx3¹åxrV^Ö¢a²ÍYªYÅÿ¶ÝV.ŸBP£óï@C[KÔ#®ø'ƒTC;œèŽÇëõ[L]rEó¥GŽÜeqþ¡ÆÅDš ˜.LPŸ-Äœ'îß¿®^ëØ™.j†¹³‹×+µî^p6`‚=m²C@”‰ãÌV(e‡?l³ûª¹÷²bÄ€ŒÝq¹H\RãVEvOì‚i;¹š~?Ž˜Ev™åøB}šÌœ¥XK€"kó·ãØÆTӔ]‘Ù•“ô0gÂùÊõ¥rCe<™Èö]ÏJ¬µJ’ÄJ/_§ÏîÞ\§”Çs}V&ïLŒù\Ÿ­ˉƒXe›É|öR…” þ–2³ -Í”Á؁² ³ÛrÂÀ¯’&iíç ÈÔòüöÌ"26³¯Vg2Ë.XI [¢Hk#“I&¯Z×åÛä¿fð$ãÊqÂ\?•/8QѓëwÕޙXrù§Ž)ÀÊ~rº°hB¥|Ÿõ`²Ï‰ÈøÜÜèR‚/>ØEœ/>Øm=lã3f¬~„WD0øÞs'U_w-AµIœ õêÕCLzîÖbÐC÷%û;=ù¡?k‚rñmXý×ÓŸ/ŽÆe¹ï{L˜÷Jʈì9KãìÃßB×ÎÄZA@øLPƒÜ–âÊ­g˜6ôKFOAÌøž@uɆš=°+nœÿúÀñíæ÷XìñÄ5Ôݓ-ÐfŽÕZÃ$ L‹º¡ñ ¿ÇJãX•“+m1C¹+,?Çz†µžc$9v’ *ÇÛr,)Çar²šY2„{£ü±”Ý£­Ùš$è۳㬹MÇôMÜž¡%kœ@vÔTNXÖ¥6"KrÖàÍcg«˜Òï=·Ê*hÖâÆó™üöjÎâ][–ÒׄÐT„Ä΀–-[ꇠJ ªñ=!~ïü1rÆn+ù ”Åéû_Š@ßnÄbA@1>â»ø>rÇ€ÁõÃ3Dú(®=µ'Аb¯ Aô)±û%«N'È…­ll>ÇæåP%ot¹«FzaÈqŽ—W §žª}RŠqÌŠbSµ%LŽ[×f-֖˜á$NqâÙ*5UJ~qü®¯×+õ•cÙµU[#•]I9–“± ÉJ"»7g( ‰™4Ċݳ6ñQdmdl.ì=¢ÔOV¢Ù=—÷Ì{ç8ã况‘]+:ÆÝ[¿y¬‰ JÔèÀÛ×øàˆmG]¬o‚ê`í" ª!žøl  ›ŠA“¶¢DÁL(Xš,NÝKmD֋©‚€ ŽõþcwL$52ÊVPçQ¢»fúãê;ÉÆl(ç"vD V\¹üȋ{8/ 8Ž7-•ÕáÄHÆ|i -±¶”PÄ3ÍÞw8•ê Š‚jšçž]iª ԌúQPC(8Álvñ‚ž0”>ìšÝsÄ”¥:š… —ÁIç4†bšØ!Q„Ô·”Å÷ ÕAK1šÒŒ-Am9Œ;.ù A5ޓËÙe—•@VBYåÆf9k1g‹euÐTï“&•nV‡’357•mýò>î¬Ñžøvi!.Ÿ¿ Š‘N ÕH.*Ìî5’jÑ,(X°$N8§Š%þ3ç;?_|üôvv ŸúÝ˗.ptLþUM®ˆôãeAÀÈ°Ž ‚úx!žžŸÂ˜~šŒ ÒŒ-Am3ŒÎûÅ6ÎMˆÕ‚€™!Àâ×2åÌ˃wPi $Ç23XpgÍgUª¹}è~£„ r’$ÇX.hPÍx²Íö ³ñaÓv k†d(Wº<þ¹õõþý˜>µ?üý?`âäuprÒdž?oNŸ:ˆ²åj¡]ûÁ꜈ô•³ð!`I ª/)š\yDïZá$œ ‹×5Y|;ŒèŽÓo… ä!‰Q‚ÀwØ=sNoý =–MQ¥y€w‰ æg_!šfû8hê3rñÍ€?_!šÆù< œž92%G¥òåñ÷íôQŸ‰•+ŠàÈámjN]†£dɪðõõF×ÎUÔ{ŽÉ0cævõ}DúF¹á²€ `"Ä$ÕçÑžQäáœj˜È®Ìs¯?QµÓˆnøWªy>²k£D€:q)˜¬Å ¥ýQaŽ3Ô|BP£Z£™Sï5˜2à-˜3 ŽÖÏDA5šÇ@c(+šéR9 zåJ8r+ê êɓaú9H—.+ºv8qlèIzÁÃó7î†â%þ§l‹H_#ƒ]Ì~LP_?˜‡WÞïðg÷j¿ÍYø×žtã f¯8Šn£ºâžoÜ_ŸPfAà7!p—“$¥ˆ#1š¿ CXVCPŸ’‚šY? ªTC8ÖÈÙ0fö€NžÕ*•á›#7‰Œ£A€ ªçœ¹xë珁]4ž ҌK7S™™ãè<¬þ~#Õ8OQ¬F@ª<>`ÏÉx3œ ê쉃êJ ªž+Ó#6nî^8$ŽCƒZ•qàºTc:;±Uˆ V–!xyg.>¢G·‚4ãDà2)š ÖC·¡pXªq¢X- qñ•A£ >!5‹Ts&-؏x¶±Ñ€ne쿞ÉÜáý &@L‹žÝ™ƒààôi_Éä÷kÊŒ|ã)f.?‚þãºà€·­)oUö&&ŽÀýuë7©žøšø9ÿl{Š !‚Gu>ÕAMbóõ«æ7choëœGm@l+ îÙû®f6Ÿ ˆÅ‚€ !XA={x$>ÑšiCFh¬t6,.ß$‚ºì0ëŠ}BP ëpÄA@ˆÎT5r["še"4N:›‚úA€ ¶nÝ–––?Ý\ * ÌŸe~Ø8u٢鰏ñXª‘='ƒ&mC@@Æ h=W²™õb® D&šÇö Ab{[Œì#ef"ŠŸ!õ¿rëŠ/9„¡º`÷k;C2MlA BÜ[KY|“I’€fbý‰l9ôÔ¬ú!šAAAX8wœb=‚jdËòÍÿÂÕÍý:×Á®ËYÌz1W"Š@l« œ=2ùsŠ–œÏÀú_%‚:mÉAŒ˜Ð;„ Øéˆ9‚€ „ F-Óì%uÑÜÉ*I’žø×C³a÷9\¿ëŠáœbç¥lÆeŒX+F ~ìØ·mjŨJ¥²GxŒ 0®ÝvÁ”Å0šê6!š†s0b‰ Dû€ æ5ž™Ò A}ëÄКQ#XXXüt{:]|•‚JuP“Ä~ŽzU$՘–¯àø9gLü³¶_‚jLg'¶ ‘AÀÁî֮ЮçS(OºÈL!c ëw\1iá~L˜Ü›ŒâˆUb† GàÁڵȓ,¶$IŠ8t&3BCPov=ºøAMßÕËç6 Ìa#ÿœ¹‹®`ê°ŠØz!‡9lYö(˜5)ìß`ÑüaÛ¿6Ò€t0k,Œ}ó7]1uÑAŒ›Ð 녠ûqŠý‚€Y# Õ¬_m^KPƒbgCÛ¶mEA5çG‚“lÌYy3ˆ þuKjؚó³ {7ãºbö¬ÑX7»lãژNJMt—·ï=ÇD*6yR'¬ñŒo¢»”m ‚€9 ð€\|󈋯9õ÷ÈI[7pFpÜú#š fOB²ž/P÷ùÌ\cی󣗘µìúuªŒsÏË›ùb¯—èG- IDAT DžŸ®cÕêض°kGJwCCàöý=kfOïŠUBP íxÄA@ˆBP#–‰v‚j¢™m¹ŒxMY ¡YíÂxðŸfdА1‚€ `Dø{ÆÙ3‡°hBK#²ZLýwžaČ]˜?³+–{$A@0Z®[ƒ\IãP~„²F»1ü×ÐÔ»€ æÔ‚ˆEs§ iœç¢ þÚÙDûèWÞ~˜œüJÎßXõ3ÚmA úxáŒÞ<ÁÐ^r!}šGÍJ÷ÈfèԝX<» –žÛGÍ"2« р€ËæÈ’ØJj4`mšKcÃ_wb«W‚:Y¹øÖ©,.Ÿ†zð?²kÀø-HŸÚir¶Ãëw±Í|±W"€ÀÙ£“‘/K|Žª_,£€«!"ðà‰;Oڎsºa»(š†xFb“ „GëIAMG²ø†.“ì¥!š·‰ æÒ§‚*ÕXŸ–EëŽã‰«*Wï7ßDƺ ±[À¶5}1šsȕ&œ¥‹!#ðð©N܊Õs»bÞ˄†lªØ&‚ÀOxŒ~r$±ՌŸ AœE.Ÿ¹ÐŸ}{Ĉã§h謃Ê.Ÿ çLF ;7Ô®”׌¡5έo?p˔3oUøYä2ÎMˆÕ‚€  ?¿7Ø·e(–Lh‡Dv:ûKÃFà‰‹'úŽÝŒõó»a¶TÃ>,±N~ŠÀ“ ëÍ1ºµ”„æúšA5דÿÁŸO_z€Ë7ž"Q’ì@üŠ‚Ž ˜(;ãö…ÅX;£µ‰îÐŒ¶õÔÕNىU3:`†›(šæuú²[AÀŽx²q²;‚ÚR’$™ÖɆ7Š î»‰`ÛÜúTP'!e+šââkn'ÿe¿ÁÁ!X³ë*Bìòꇠrßù€ ŠÕšŸªñs÷Áý}jdÎQööFœ1^ŸF`ù҉ø_ùbèÛÔ^ 1Œ^Aí·;—tÇ"„x'ÕDNV¶!˜nÛ6"ƒœ•”™1¿£ݱ† ^µcqŽhÑB'árñ?k"ÒÚ{¢FqՉšvØìÎ܎…w!‰Q @iµŔˆ"ðúµV,›Œ¥3 Oj÷ˆ—þŠÀ+o?"šË±maW,{•oC, ÔR1KŸ#àB j–Ä’ÅלŸ-A ±Ë§GUªÑ?Sî^ŸXŒín=òGµê-3fL£ß“l@€û7 10¶wa€LøV 1^ûŒ£,Ÿk±rZ[¬öv€w°žøšÈÑÊ6³CÀe3ÔDBPÍîàÃl8Êjf§×š\*‡9ckô{Ÿ³îîžÄ…ƒcrdÉ* ¯Œþ@e‚!0~\w 8 ‹<@,«`ÁÄDðñ}–,Ãæù±Á'Œ‚åRÑDŽV¶!˜®”$)³C,qñ5»“ÿ²a&š«w^§øÑ¡ƒî²—árñ7kÒ'ôBõòââkÌÏ֝gŸ0qÙø µ©šVÆŒ±]0{žöi`PÕkˆšùœÍSà Ô}–a㜎ØúÖîABPMé|e/‚€9!ð|ózd¢,Ÿ][H_s:÷°{ ùˆ•Û.ö…„ šëCð£}¿ý`1Ë=ñîœâƵCÞŒÅ"A@0R>}ú„É“z£_ÿéHãø%2¹éNÄìï!ðÖÏÍ{-ÁºÙ°ó#܄ Êƒ"FŠ€T#=8=š­!šç‰ Ö#A9¿Bµr¹ôhªLÝp¡÷Mgsb×ΕT+1> .;»øÑm†¬'z@`ۖ%pJ’%JVAÞ4/%é+=Ì*S ~ïüьêší±Ïß®âñb(g#v‚@ÄxNI’2;Ø ‹(š΄z3A]±å,EûöíuîL§‹/×A=}2;z£jٜ:'”†Àý— qàŒ.^:˜–1Q¡b=Ã6X¬ÿ à|÷*NœØ‡‡šßý/×}ØÇõ€L÷ЀÇb¬šÞ‡ð$@ª ¯lE0+XAÍB1š›‹‹¯Y|˜Í~üøË6Ÿ…eâbBPÍõ!еo—×ñ±x‡ž?‚äÉÒ"[öüº†ÈïAÀ@ÂÜ9ÃѪu_89ؓkï38Å÷3ëÄ }!à„œ—bñ„–ø'Ä ý­õ5µÌþYœ ɳ€GŠB’X0°IWAà+^lـL‰¬EA5ãçBª~D¶îæc‹ékžÀÅõ)J•ªû„.}Aà7!°tÉ-Z% ç$rú¶6A¿ÉY6* ‚ÚŽçb,"‚ú/’â>åýLmÒ‰R$A›)oi‚€ qܶ¬GÆD±„ F:“Eu,²8ù Jqñ5™'…6òÊ/F-tÆýwаQWØØÄ6¥íÉ^“C`ݚ™H&3ZÔ-Š‚é\aiAåÒLNÉ_¯ó|,™Ø gc$ƒ³(š¿åœ§4î»D ÐyÞØß²Ÿ,*˜^;7#m|Kqñ5…ÃŒä4õ4b:”D»vítήÔYÓÆ"[Ò7ø_i©ƒªQ#ëàóΓV¹âüųhßa°‘Y/æ æƒÀæM ‘&MFto’é©.µ4ÓF€ÿ1¯ÓqŽoË1“áöÓÞp4îŽÝvŒ. Æé\ur º-žš³¯tï# ÔĔ$©yÈŒX»ý‚â‚jÆÏ@„¶þ.Àã–?ÃÙsçюHª……E„ÆKgA@ˆ:ý±sûr89&Æø^ùÐöCÔ-&3µÚÏÁŒ1ÍpÓ&nŒ7‚zùÀq웻y+•B‰FՑÀIÿá'3[õÁ/ŒØ¿ZçyOªß “9¡ÃìQ:ûJA@ø>/·n@ŽA•$IfûˆpiŒÅëO"VÒ2hÛ¶­NDAÕ ‘ytð§{Ó7xcû®íhÕª/;$5Ë.FÀÅå!þÚ·Å åÀðŽ™Ë*Ā­Óô@]RP§k„ûv©p•Œ]Ì¡m= WݪSºT” (72̃Žy²Â*V¬_†a|°‰}ÖÎÒ9÷Mž)ZMŠ^£;§.€Ézãœa3æWv^9x­CåŽM‘ïetîA:¿EPJ’€ß}¿{ý…kOÀ&™ êÌ©c‘#¹/*—Êþ»÷&ëG!Á–Øö¯-f/Z„\¹Š L™QžšL-?B 88/üƒë×΢]“²hV9>bÄŒÌ &=atŸZpI˜—ü̃ z¹ŒÀòŸcðú…ÇŽÛÊ&òW)ƒâ ªÃ!U²H?CË5Fê™Ã¥ŠŽ©Þ äB“‘À×Ë+ûCšÜYQ³·îªÈèï÷“uCÀû}x=TËЩÎí:ŒSÕˆŒDÜÛMÙedœ mxlۀŽöÖè*uP£ sC\háÚãDPËêGAåJ³§§ToT*)Õ\Ÿ6‡ÄÀ çŽXŽbÜܞ¡Jµ&÷–YŸKÈ\‚€ ðnÞ8“'ÿB§€Ñ£8²§–DHæúÀ4î¶#z׀‡czœ÷3Ÿ$vkþœ„['ΣJ×(Pµ^Ÿ‰ûç¯âþ…kðq÷¢ËššØŸ1ʵªáG#ðƒ?†Wl†<K*uRWU¥%r”.‚zƒºâå£g˜ÝŠ/>RÁùJšDj}]ëñïy¿KzŽP®Å6Ïÿ.9-Ñš*Žmš”`i‚€¡#ౝj!š†~NQmßµÇ'EŽnÝZçR:]|™ NŸ< ¹Rú AÕ §étžýܧ.?ÃÖ]ûÈ¥*Š«BD5ŧ~¹É5ÝÊNß‹@PP nߟŒ«WNácð{ŽnT5K'„m,)!ó{Oæ÷®ÞŽÇb îVo’eÀ™·æCDvŠ'×î`èžå°µÿÕ!ž?~†]ӗâѕ[(\»êôë¡Cò~é Ž+-Ѱ:ª÷l£sì°òMP°FERL51Snž€UL?o4Û_çøÈtžñϬ6™ çEÛiCÕ×ÿ> #gà%Ϫ֜J6®™©eŒ ð[ðܶiì­DAý-è΢LPc'/6mtÿÝ+ÕpÎÍ -a7¢/cϑ›°ˆiƒÂù)(mØ&HŽ·bÁ,Püª4A@ˆ8žž/qåÒ Ü¿NT#®IŒšW1Rˆ€ ­û,C϶åáŸ* N™AU¥âijEÿMóŸû°’¹°ëøûœG÷¥“"K†p?,ϝaN»þáR@?†„àÏÒ Q¶e=ï©«y»yà1k›ž±‘¡`nX“KrdÚ¹]‡°cÊ"”nVUº4WŠ*»=‡+ՖÕÛȶoß!Ù'É#‹ Œ‹ ^äâ›Z\|#IYŽî%I*§?ßi“F!OªwšX2›I%› ?~ïüqüÜ=ìûû:ìâØPLŒòfO… i‘:…>Y&göóEÄÕ olàék>7þáGRzš3þxöôîÝ»ŽÇï"¶u0 çJŽÖu²"cZ's†FöþÚô]ŽÎ-Ê Fú¬8î×,0zãù êt€Óä”Å·âÄ·“*¯g/àIñ©îž†Æ§f+YMGõALk+RO‘Úšéòþ<éîéKX9`T&šÒ}@Ù¢YL<ÙàÏàˆ/ÝxŠëw\qçÁ Ä€ä ––1(»š•"«I 9œâÙÆ†­mŒ H7¶xéco3)“ ϐù `e‚˜–aE¯˜ôâ¯ôЁ@øúxáÕ+Œp{×çÏéëKŒõóƒcâøÈž9%*—H¯«Ÿ§1ÜÔ{ܝþËºÆˆAsQ®þaaAcé? ó¹Vcø}ž—Ç)/KmŸO ‘j.Äë}µF˜µBÇðp^“VSñ„Œ¶æ_Ü8ùûÏïñoyoü%ŽÆ^ÍžKûœö«fmÓ®÷6õ«Ÿ;h=GUíTažî§Yû{c跟mûb?õ§÷Ÿì-ŒMŸí׎ Ýã'M Úœñ÷ññã'|ü€ùÊã>ñ÷ôúÄï«÷è{~_ýLßÓê}«ÞSc4/z!ô^õ ù‚OÁŸL.{ܟV_)ÙIpH°f]ê¬ý™ÆÑÏ?…š~êÅ}>ÿôù+Á>^\|ðçç=P©«›7ޒǁmÜXH˜ÀÉèÂ&S'd˔™Ó%¡÷Í#k˜ÇJŸ$]‡®%·ïB°Ëž‡Í„ [»®El»žH“++’gN§Ž)‘8eR•4(Vœÿ&‹ºqŒb6‡NE*ÊÌÛuáøÿ =œy/Œr}‰1G×ãВ à5Ÿ×øß*][¢$)·Ü<žºbz³^h8ŽGh9íZœVNCÒ ip~ÏlŸŽ@ÛÖS†»qzJ¢‚™T®³ñþ¹sI„OI¯‘xxé†*/BŸÁxß]MøO^øÒþµœ’××®õ…(jš'7~ϒÔ&BÚ6ñ3­ûRnD±H ¡eªöùêg¶ã3Uvò<1‰x3Î[?ÛÉc¹/ ³wÆØŸû~&ŠŠ ’YZò§ýʗt†|>|ÆZ6ŸI%ï†ï w nVVt‰ñ!Hƒ!ýž³b2éגæ°Z¢­ÁHsžL(¿×ŽñÅHÍLϔzÔe=Gê‚BsÑÀ_CŸ+ú>&]¢š>d,ÿ.–uLEZyŒê§žÅ/ß¿t÷Mlkd"×\Û8±7Ž5ìlmȃÀ^‘RQFÃù‡tû!LPëVÎÇ|ypÐÇÖ,Ò­Þ«g Õ@ O;µe/öÌZRMj¡j·–_ y|õ6uŠÈnçùcùe‚ÊÊkþªe‘«\1EæžÞtÆîK•;që)"KÑüÐÆ«67€2ùVój^.;“»B Ìï4ÏnÝCûY#‘!Îе_=wGà‡ŠÄFŽMnؕܘÝC‡ý¯s3r1®ûÃi8aÔâá-ݬ6õLêïÔãëvàé çP\¶N˜‡‹ûþF¿s‘8ŗZç»g.Çé­û~9Ÿ5¢û”þæƒÀ띑ÂÎ ÝZ–5ŸMËNÿƒÀ¢uTf&iýÔ©“F"š(_<«À-DD‚ˆLòKû=“Ø &µô«]LŽXÑÒ(_š÷ø«Fӌϗ]~ ‘F-û¢Ô©÷éç8D6˜P‡’,­Š§ˆ›V™ÓbžûgMÛ?nlJ$EJs(¹T,‹' ûUCQmbń?)qŠÈ†Qv¿PXÊ«eފ„1±cõW0Vœ5œU›ƒÞbM˜Hœ…Rÿ”‚Ì4ù3aS}ÕzZÕX³vLêR:µ„PCô5JtØ ƖWà¯ZJ©¯†ìi”m^WC‰ YÖôcRÈĜŸc‡vÿ¡_C•ì°ë|VÍ?Ϻþg«™_³i‚€1"ÐcÄzT-›© æÇ_fBP™h1áuhíwÕÒïã™íûUf_Ž)åØRm À܃(nõr•/®âUµ*â÷Ḛ̂;íáe›PŽ^Ôú£=‘»»XÐešÐžÜ4ž›–ŽjqÔw>Ÿyp^JŸð¥gÖÆ²j÷ª(»4¯Íë8ˆìzˆì¥ +_åAò¹±ÝaÖØØÆÅ6Rz/âÛcÙRŠÓ©/î?Æ<Â(6'¥"âú=…ÚÿìˆÍ†…€† Æ$‚*.Ÿ†u2Ñk† –&‚Ú^çÂáRP§NA1š(WLbPu"*A@ŒŸk7pT-€rÿ¶œü1z#ý»›™(©Íî×v¿ÍŽè\xzóÞðxâB®ŠóIÙ _â0-iŒßN¹¯²:øÆãVžš%7vœíŸt2ÕRœŽeŒ‚}t[2)Ôm–ë£Î#5”É,׭ж‘RFY! ›PÉ×ë5Æ×î€4ÛyÞXhÝqٍ¶áÊ5ùWš6žV;'[ò{í£Au˜= ©É9lÓ&•ÊQЈ*{ÃñªwN]Tqµ)³f@æ¢ù”²ÊM›˜Ý€k÷¡’;¬ªrÌlù6 P±]ã_1]Æ ?DÀ{ç&$·µD·VBPÍù1YL5–Ts~d ‘EÀÍÃ) ÷W®Ú.g§Dvš_7pâVɛ9ÉœtÇ«Èԓw«Ä@Ëø‘î^šjìË^–ä­Á“îĊG©lì~Dq×¶ ã+’Ç/»D U «XVª +‹ì:[©}cz/|%WފdÛiÚhžpcž{æ2rSýKÙÌ1›Þ/=” ÉI^Ÿ÷ƒãF9žuQ÷áJï˜XýÌä]9Sn’ô©ÑqÎhUæ†Éތœ‘‡"5ÞKÙÂñ¥CË5QIš˜02æ0ŒWNŽ”¡@.r'΢$1FlODš6n”ÇÔÜ ùª”ÁÖñópùž'›“kqŠB_pñ|öӚö uaþÙZ¬(ó€6yRØŸ}Ö΂cš1Uú áFÀg×&$kî­Ÿï£Q# j2RPۈ‚jÔ)Æ ‚€ D?R;³ŠœÇ忆#w֔Ño­8xÒV*ç•*öHTçsWTFYVöâØÙ)‚ÉIÒ,(~܂ˆg ‘– R(Æ>$8H)L¶˜˜²’ÉYn?PæÚD©’àÉÕ;J³€øìDîÞxŸ&ÒL¡”tŒÈ/»‘Œ¯âÏ9Œ€y.×ýsçÒpםÛ~€r;í³nöWq’á9€³;âï•[ÑÌH$Ž]b¹€ +¡[ÆÍ¥r1͔,tΔ{ýïÓd«&\Ã:¶ •q©ˆ²-ê*¢©%£œ<ˆ3÷ŽØ¿*”lv€l²ÊʍãE9¶õæñ³ŠìkÏÉ*fÍ?Ú_<íó{0·Ý8¹íœjºš*8(K{Â“ëwÔϜ˜÷¥ýÝôf=Ué.KîË?kŸ^Þ`ûª.ø¬™˜2A•&D‚jIUÔšÂØæ]²þ¬J¢M»:Í —‹ï” #P(C€”™Ñ §tA@0œòÿ¡’Ÿ é^ £û~]’#ºö7têd˘Å+—ÀæWÒô»«ŠÁ”-(P“µšÕU&­L*†»g.©Œ¹ü{&e=–MVŠlx•D®ßÉ€‰ÈšnoÉu–ÕDV&Ë/g’ÿ¶±BÉõCs–)ªÓ&OoޅËíûJYõvsW„•³û†7á/âB ñQ6]ûÐ59y'ò¥KfäÊÖýùö¿°fð$…qÉ&5Q€ve¥†3Qrý.ž6*Çõ2y­Ò¥¹š“sÎŒŽ÷(T$…»|ë:÷'È"à»{3cÇ@Ö¢ FCS·x=Å &)…ÖmõDP'OŽ"ƒPŠÈױЖìAA@øŒUFáú]W*¯–×ôù-œ¹iS$Fùê%±áUüßbÏå˜M&£wN]‚3}M‘5£JŒ£L–1RP;bÿjUÂDZÔ!póø9l;›2û«EXתÃü³ Õ%çzšY‹ 5bßܕøwÓ^UZ†Ý¢¥ Q…€ÔšBÖžæ]²á8¬YAíšÓp *»îL7E2 AÕ §tA@0ª·™…ýÇnþÖ8ÔqsöÂÉ!>ª×-ƒ5ž¿Ÿ r]PŽ‘ä—ë݇TŠ%²+@‰xòªøÏ“›öà)†Öä:ÊeY2ÎKq€yUŒ§ŽšG€]‘/ì=¢\V¡9.˜cl3ȍ”Ù2*µ[Û8[ð€ú]”Ë1·ÒšD@jT¢k§yïÜUõâ>œm–IQˉUi†€óÙ+XÑo¬JÄL⊠IDATT šÄöi¿uoÉÅ×Á†\|ۈ‹¯ñŸfäw qñ-I.Ÿz"šÇE±,Á(]X\|#,2RAàW`ÕG[ã÷Wæ ÏØ-û.¢q÷E*Î2è¡ækt7.3ËÚýû6ÂrѲ<—a7]¥”’ënº<ىæGºŒ9Àñ˜œ\‡/ÅŠ„Héóç€Ûý§°£XIŽåì¶xbŽØ(‹ü:ë†M¥óœŒ¡»—IíÓ_‡SfЁÀý%‹€Œü'ÿ)±Îæü°,Ù@I’‹“‹o'0ètñå3ЌFþ4ïQªp&JA@A@ß AÕ §tA@ˆ Î]}„bu& O‡J˜·ðÁT&åÐÉÛžÿØEò¥Cá<鐪hxŒz‹WWg!nœðÕñÔçޗn< wÏ7èÙ¥ꑠrWVIùõö•œŒ)yN~ªušœÙV¹î’RêDåG4„4/ReÿrA}vÇA\9t‚ʯŒE¹Võ5$UšÑ pjË^왵‚2ú¶@éfBŒæàŒØÐçkW @&G4¯£;¶oSLׁTkÇbhÝ®³N¬tTVPǏŒY? AÕ §tA@ˆ Þœ@ü=P¥LìYÞ3ÂK„Pò77ˆgkƒx€Š†m>ŸïQ¡é4\¹õLœmA5jÚs16í¹€ÿ•΁]ªµAkd-?L­“ÈÞwŽŽQ_£³mÞ{A‘æ‘ýêaö˄^šëiªxRzùùŒQ„4Y†Ž P±€¬”f,”ÙKFÚÜYUÝҟµÙmú!¶]\$Lžõv‰°=2À0`—îãëv¢ÁŸÝÔ…4A ªž=ošTɅJ%‰LH3[ô® Ž#‚Z6—ŠåOo¶ ÊÆA@~/u;ÎÞ£×à{k.b O›¿úô¹––(Y0î>|©”Ô™#«¢ñžä›¢H€I‘v UW9Û`—!kUyµcgUÜëöÅݳ€Þúì:t'Î9cҐF˜áŠ› ~€&€ÏnÝÇ¥¿þF‚$€ˆæF¬žqáE*)ÒXql”Ë.+¥¬’†§qy™Ícç€UØò­ HíÊá&}A@P\™>ݛG±3F@CP‹’‹¯î Îp¹øŽ9erÆ@‰‚¢ šñs%[Aà·"0|ÚNŒ›»ö EŸ©uÚÂî±9+€}ü8Ø·¢—³ûÈUÔé0mÇÒI­¡mݧ†ôš®ædwà¥5ZÕ/Nï=Cþjc0”Èé("©Ü†Lَ‰ó÷£w»Š˜6Ž!ƒÑ⏥Ø÷÷ x_Ÿ+«è©‰zìì]lØu‹(vês{|ât¹ÔžÞž‹;*ëî%PÜhºŒÙacg _Ï×*¹‘cêäÈUŸ%6ʈÔ9"_îèÊ-øwó^ªQA%ԑ&‚@d8>jf©t©"3\Ƙ‚Z„Ô®:w€SAe‚:Šjùܖ(.ÒŒN@¥ƒ ‚ÀYq×l?ƒkáòMMò¡±ýjcPת‘†çúWä­: š”R€óÚlýë.]‚w-c2Œè]Iâ«5œòÿ¯×~ÿY¯.%êØ4¯“ª©Êj©CÞÞ*µMƒâJ5åxԌipyß0ĉ­ÉÞË O_z­µg¯<Âҍ'0ÔÎ[àæ¿—•Zê@4qÊdøH¶?w~„€÷º“EôY­ûª€IGôþ%’Ñu¥¿ ˜U[ÂÑ!žémNvn–Ñ¿gV…‰ ê—‚nX¥£ ‚@x8sù!ÚX©â=¹¥§[óààªTˍC£Â3EhÎÞ«-ñâæáƒ…û«dEɜâãÆÝç”Q6Ó€xâú Ü7qB[•÷í;äš8õ«Pù.Þx«˜–šW%?ª•Ëõ• SÀ ª9ªm™ˆœ\óR%O![õÙùÑ3Or+>‰å›OÁÚÊqR¥V*éÛ×ÞxtùÖWn»Niõç6çýÒӚöTªlÛiš$QÒA@ˆ,|¹wtèhüµ¬bÒßÁÒÌœT†qĐ~š˜/&ý#/ÁÍæûXÉÎA@ø1ü!äÖœ˜¹üˆRNcÛX¡SÓÒ*f3]*¥TzŒòERÇᆑãC‹×ˆÆ5 aíÌöj\²‚}áî嫟¯Q>7&ýY™Ó%QäŽ%Q:zê†÷ª¡<~*·˜¡jŠríԟµç/œñï…û€Èº¢`î4šV6Wh†ßp«‡ŽlÃÞ£×ɕø:¹D±wÄ5rKf‚š Cz$J•<4–TËýgŠÝ3—áÒþP»oG©m˜‚€"àíî…; `Çݪ™ÂcV[æKWËDÑŠ}wûÖ© *‚:”j^!š:є‚€ ˜!ŸŸ«j†ŸõóW»g…rф"£<îŸ3w±bË) &7଒¢dý‰Ê­–ÛªimÑŒnQhãJK΄£ú)UۆN݁ óþRÙy;7/ì†+W]ÎÎkGõO¿m;^ÆàIÛñÊÛžWfFûÉ}ðTI˜”ò+e2{$&u؃2 sŠá %²*z͌v8/Þ}ވƒƒ0œy/„cðöÅQ²†L*所׭Ûxuä–NnmžÈ®CX¶ñ$¬ ¢U;!šòX‚€ D1;]AœNóÕ*Ý[•S%\ÂG~ÿäyV¯áŠós€M•sF5U}nß¡JŒp¬gîÿT¿oR«0:7+Ò '“+oEزaœ²Vo;6ýVhÊÂìšx‰³ó¶ê³\)©WþŽì™’£BÓ©DzI׿ÊËNØôï…XH±±\>&ŞN\_‘ÚèhŸzàÙŽ‰>ºø@qPú#VŸ‹äMJ¥²£bÉl(+2§q÷EJ>i— Ÿ!ú'š¬˜î³Ù(ûoƒ!=¢YCÌ÷“€š=ŸMÏ60£]ËV¿‡Àš§xùôHPÉÅ·R~+Í'uPå‘A@øvG-P},œœÄ“S“H üR…UÊñTF›()AŒ8ŠtžÚ6HÕÍ_mފQL®žJý NÌç”8òçLýÇnâôöÁ‡ù/–Pö¿s»† •)(\kœÊÈë˜ØrŠÁ•[ϔâȵNgoŒ®-Ë*ý(µaׅ8xâÖŽŒÉqýªù1qP="»+œÑó׺î2‰~ãû)’Ú+rîýæ}(!­LìcŲúÏԝ‡¬AŠ£}”¡|‚õ¿µ°ÛPžPÍÔNóÇ"U6)#Ñs•þ‚€  g{v#µÅ;ôë(õ“u£eÚ=ô¯  A5í'Fv'‚À/"0õ?è1b=v-íŽ*er‚3Ў˜ŸS)˜œäš]£š]9/JÈšˆ€¶u¶Ë(.¥Nå|ªŒ X"qÜÕ(ˆõ³;‚³÷æ¯>ZÅ¢®™Ñ®nÞè3f#¶í¿¬úYXÄ@%"xœ!žd¡ÿ­Ó—`ÇÁ+žCjmÜ86ș%9š’J˱±QÑX¥Ýs„]w¯aס«°ODH_zú69H!ÍNeo²#u8ˆñŸ“·+{ߪ„×!ú#šËþ@tY0>* 9A@PÜ[µ e²9 Yí"‚ˆ™#À1š1@ëöºœuƒ*ÕÌ)ÙŸ ?G€]sÙE7{Šdð|ý^oÕvםD*eò$öߝ`ËŸ‹Ê•›mÜXݧ6‘ÏMêç“[†&çë;v3æ¬<Ї'&„*ޝ}ÞQö^/¥€þjÕ_=ßÇ.^АrٛsDΝšœÂkïwȒ! ªRÒ%vۍL-ñéKÁ’xüêõá€?‚úú…&süÕmËxA@~ŠÀµÙsЮV>”-–U2sAM˜­;ôԉ„TIA@]0Yäz¢ÚÆî·«Š·SÊæÏš'ŗ&¥ÌŒìÚË éš?j!sÙ!*^ô𺟡Cƒ‚‚)þô ê‘[.«¬†ÐX™=yþ­?¡Üuc’2Ìjn ¹QYŒfÿe[7ì:§%¥oÞîA1 aÛbƒ áFàâÄÉÝ»2§çx{i指ëX%€Ôöz"š#‡öWef$՜+Ù» ?G I>Ê=·uýâØ¥ ÒŠüÛÉk9)Ññ³÷ðà‰»ŠÁÜ8·“r÷ÍSe€ªiºmQWÔ®”»_ERb¹ÌŠ!µrÝÝK%`Öî8‹#ÿÞVuUߌý€úUò¡(•aãGÙ2&Ó«Égˆ¯Ür%úvÃËÀÿÆšêu1™L="ð)ˆ’ҍm »ÀÊJ.Øô­QNÅág.?Ă5Çpˆ²ÿŸñû®ŽZ$_:ŽªWL©€ID—)j] x‡rJ­ëÊb‚€ ü /ŽA<¯gE¹€ LP-æ¥$I_~„JžêpJ’ô¿üÖêhi‚€ ‚À÷˜Ž`?8ëlØÆ™r¹Œ+МÍ×Ç·.Ûô¯Rr¹dMPPR%Oˆêås+» æNû[Íæ€Q–Ysñh±ßj‡,.‚@Džµr*f— ŸÁ̔ûªTû2&À˜@, œ¿úH „¢ïwËêLZlÙÆcXN‘€Ï]~ˆZ+‚8‰=[{Ž­lv™¢wüßc70iëeTêe8°„IqeL€ 0X Æ¡Qãð÷Ü4hž³gbÙ5.KB Ú’µ•©<šÃ(ŠoUŽâËˑxŠí>þ×ãÊõ;HáðhoB±ŸµÊŠžUrûÝ6 âµ­6¢›ž‰ù¬ÄykÚŠAŒ+ñLåéž|/¶pÇôu*ÇD•('óQ~Ê#겊ãò˜öœx­<è<]QNyè^+Ï¢\ôã⠊÷Êsô×Ê1NŸð °Ghžq{6FDDÈ-F"""éÚ× £òµÕE`•sºŒ"$åeÄ1ú'^+uAž‹”õE"\#Ž)yBT QkÏ+íŠs:' F¯S¡ÑÚCe©Y·l‡^S™ +„„ª ¡×t@)+ÛÏZ»èÙûõ38»$AŸ|ő1Svž9[!KJäHý¶j |âÀ#¯7ä%݋]¯ÈýRÅMÒ2¢UÃÒøíçã°eÓVýì¥؈zž}å÷'&À˜€¹x~ë|vmÃÒI¿›»©l_<PŠø€)Ÿ= ¶hÔÔáCh›™ÂŒÍŒAš‰,ƒž¹_²õ6ö¹…Û÷_ EÊŽ$:íàj©"åFõòƞòi4ʍœFÜŒÓÍŒB†ÒÚ/yÃ/oðé>_£ÑŸåÄq!:CBE>qÓ/ò)DžØkÅ1@ùÔT_šŠÐ‘Çu¢†®N‰é†¢Ÿ/ÉK*"rÓŽDhÂ5ÒÖðpkLJ Q§V¯Òå˜Þ¢o:!+Ë3BìjŸåý‹€šDS€RVþGbÚ “uéë ×61TôñK)L£"ºÆÈ5ÕþAv¥?¢.„iÛýDžxv+BNŒÖöQžÕvVW›èž°""š ÁVÉ€ýO\lmû:þÚ\6jÑÇm }a¥v-í e€@LJŽYdÂé35` LCúrºÁQ…šÚŸ1ý€„È')”Á ñ?1ša­RIº|Ê@ šˆò$xïGv‡ãÝ;$Ož ¹óAɒ•‘ÅÝ%³y}ñúò‰˜Xœímsg.=”{“е€5ÊçC¯öՐ-“ym[“Þ•ë°¥Úü‚éx/Á˜pãŒL€ |·÷ìGÆÀçܵö÷1€[5;KI ªM)P…U¬A-Y˜ƒ$™ÝÕþ=y늝‡aùº,y.ü#²fË{{i»kR¹Ÿ•e>%ÑeŠ$ŒxBÀ}.)"VÈ+åYÑ^º×:§×mÚŒ¢ ,ÿQ=J]×I¢Yšp™ŽÒNg‡TœŠˆÖê@%O€Pnº2Ÿ§"D”"7á¬è(1­+¥eåN„E‰m­Ԟ—b,z~)£$œ<¯÷&G‰D%Kô÷ŠxÓµ©x”ó:a÷ù^YîÑkWÏàÚµ³xòø.ʔ­‰fuH¬²Hõ¿zë)­;JÛØ\ÂýÇÞŽMeŠeG£Eñ­µ”ÔrÜ^„$uG±Ú•,¥KÜ&À,˜ÀÑésÑ¥v>ùœZ€<šœ 1ڃZ•<š%‹ðTƒD-<é»é±i÷eœ? ¶Gò©,ŒÇÜ=&7üý}±kç饝2š2»ûÄMCV«ï»@ì9t•¢îÅ©ó÷B³0R&s‘û‘е€…òXf0ŽÑ»ïcçŸóhÐç »¢Ü&À,@XHv‹ý‹:™ÝÞ֖Æ:!õg)ŁP»å'ÚÛ Ù,P "â :bMá€ÙOqáâiŽÿcƒaLÀځgObùøêHêl‚-¯ŠgïbÃÎ3ØŸÿžÒzLMx„Œ Ù¢^ ¹ Œ{ WËëôG=ÚñÒu›ŠVcûÃÆÎ|" [{ìC™ò -¯'0ß+Ŗ%TëÖÎFÜÙ0€}úDÝ78$Œ‚­]ß#W±mßE„È`Xi=’¢}ó²R˜ZêÔ]c?¯ÿú:`á†ð}ù•Û41¶çcL€ Ä;ÇbãèFÈH»9pb:Ë6‡*I^šâkØÑeÔ_$©:I*ÁA’í§lé–ëØzðš·èšhpǙ@\ðõñƒ%ã1sÜÀD4éÌ¥ÒKºãÀ%ˆœS“»9ãÕüT:šÖ.†Ú• ÊHàœÿósÄþÛï°{î ü2Òð;scL€ |/î?Áõ›°{FëïÑ<·iÆ–nyöFná$¶¢jHw… MŒSwœ^¯ÂTXõ: 6Œƒbu« CžìÆå|L€ 0x#plÃ?(äÏv–E=ÞàYxCR º‘@5•u8yP«¥(Ÿ…9Н…v>Ûœ›ߡ뚣šV­)ÒŠËœpŸ™@Œžxñ.]<‰åZ„@Ò}B”ŸŠç/ý<™ÞÓô]”IP¿ZaÔú© S°#NÆžðÞ“6ŸÇ‹»Pœã¯Æâ\L€ 0x$°¬ïlŸÔYS'‰ÇV¹©„@` Tµ[š4×(* Tƒ-:Ãê=>X±å~ùµ'll”`%œ˜ˆ“&öÁŽE‘&YPÜ4‡µ^¿óŒÖ‘е€Š§4WV¹çíÍ{/P§Ré%­S¹`¢ˆºW˜·ŸuA¿?F᷉ƒacËßÇqřëeL æn:{§ÎáàÄF1/Ì%,žÀrZƒj—,?ZŽ1Ñ>šcFB…|‘äAÍbñ𞃟<ßç.œG«Ö†÷-b~L€ |¹s<1žST-íþmÅCi?ړTxH/^‚U[OÁF­’âÓû­?Dà#!H…—T<8™†@H„~³©ÜñC͟LS)ט0mS¢rÅBð¬Í3.M€ÓâªA’ÔIr“µ¯ÁŸçAÒU‹ˆ)Ÿ,P µ° ^o]Ñcô>øùœE›¶ý,¬wÜ&`~,… …í1¬[5ó3Ž,:N{’ꌀ7ï=§ÈÃé &azíö3dL›œD©â)å©»qwù_}†^Ó÷£Ùðžq××̘ˆw¯ß`ËÄùX<¯JºðžÞ1@—h².ßt*לhõ‡a=ªâ5š‰æ#ÕÑ«OÜ1`ü:¿tOĔB{G¬UÖ_Ž7 AHâDžžA ,)=þû÷m”—mll-©k‰¢/k×ÌB®Ô¯0aàÏfÑßOŒ¥ Õ8ʛ= <ܓà­ONœ¿'·)š?£¥bm)§ø!Р×J€¯Y éik"NL€ 0ïMàØú`E·]Ó;•GFÞÏû{_³l_YƒjBꈡýQ­š Å r€³Œâqh”ð ™þíIŽšµZÄaKŠ©ÚÚÚ ³»ÁÎAýÕ /Þžƒòæ‚&”ÖÇ]{aQ"õĉ}˜3k(FŒ\Baó˜,×ovþ³%sx£Këï3}344\®=zú6þÞв+Œ¡jµ5nß)·‚ÑyIyênŒ},>ih÷ÿ.cÞÿî¡L§¶ßÏn™ 0& %°ž÷HôÛí3‡ÃŠ©0ÏkPjƒ|Œò zÒßʅU(U„ç”$ja^ú9£ÿ”3ӄ¡V­_ÌŸwI’Ù#uƒvêjR7x¿zoQ"õø±=˜;g8 š…Œy0Ȃ3˜]»Ö DÖWèò[¥x3ìµÇúi»Â+Z­l^€O“oÈKz„„jšTnÒC*„i‘|ãÍ.nèë~í¹ëփ[ŽŒŠ 0&ðݜޟÁŸŸXÓ· \TßÍnØŒ ª[.Žlo¢)Ÿ,PÍû‚Ç¥u>öè9áyP†@MžÊ)S;D] ŠÌæ.RÅàÑ£þD“ŠðÃ_ß[ìØÑݘ7×õ›Š‚KdÁ̋ÀžÝëP0ÃSôjW5Î AŒöŠH»àHLßMç‘¥‹f…­­wŒ„ÿû`ž8ÛëEijw·8³…+Ž=Ã§ncEX/Ü£4–µR!öPž$`ñJ@®ÁrÚZfãÜNȗìËK«âÕ(nÌ, (kPs˜Ðƒ:Ž/ª•÷A5ËëçFý6캜æW³Vó8oë[Ð ÔȈHÜzøQ#yV4é$­‡;\ñ±@ý‘Ïaíd[ µC¡Â¥¡R}}ŠqLûyöÌ!L›Ú¿¶ê‰ê՛žóǐ IDAT~µø‘Ã;±`þH 2¹rŽiSœÿ;øß¿‘#ÕCüõGu“Zrø¿[Êö/$Lݓ» =rdr‡?íKú¿7ðü•Ÿ^ o)§„A ãÀ(TéGøç*–0 f+™°(G×ï@Zs:«s‹êwÆôD_šâÛÒdS|Y šþ*% ÛxÞBxxjÔL8Uà}M„FOZ¬‰ptt€Z¥Â¥›wP$o$KòaPœúœÖ€^Œx‚>œ¢ÚØ;8"ož¿@ äË_鍯ì 9ü‹ŽE—n£P²då¯Ö§Ë;rô2dΜë›ÛŽI;¶¯@PP€ôôFOBŒ¯]3gNBï>‘>vù׳'7"•ÃCôíômõ¡—·â%=|U®)-Q(3ª”Í[\¿ý;i cºÔIå0(Œ£Gv’ÈœAÓ+Ð·ÿtd̘ݘjõy„òÕ±`Ñ¿4MÙù«eÿÙ±ëÖÎÆüûàä슰°P>ŽC f!‹-£¶ÍŒ|Ù$Úuš6ëŒ:u[Êb+–OÆŸœagg/û3'¯m4ÄóÔÑ5Hãâ…~jʊՆI/iÅR9†c§ï`Íöÿ5CJœ—Ž`îoŸbnÐÎðÝ ì>x;\B›þípÐÏñ»ÛÃ0&`ÙvyNÀœŸµ;[jËî(÷ÎdÄ63j×lŠš#†õG¥V(EQ9%>ÓVÝŁSOÐâ—nfßùèÔ+·ï}2Å÷KP‘@͗3 ¬i—éØÔœ{6`åŠ)èôçpüXæÓµƒÂƒºjå4ˆé·… ÿˆ>MŽËɓúàò¥SXŸò˜Ár›6ΧéÆK±lÅ1£Šß¿O߅{ªŽ$ ‘w3vSgÏ‚“'÷ë£ÿœm)6n˜/Fõê= •6hû—2Œïgç× Çº23/xòÈjéAík@ Þ{ôJ®#£$LÅ:ÒúՊ *­3M‘ÌðVKfŽÍ‹A· WÖÔp(WBx=X,r&ÀŒ pnÝü˜<]û>ûua"g1C+h ªð ¶ê`"êÈá f†‰m8%>³Ö=Ä®Cwвu/³ï|tj„ˆtdl°#Z‡j­]Œºhá:ž5j4GŠÌ9acc‹—/ŸâùóGxþì=ºÐÐØÛ;¢g¯ñț¯^œz†ëäy-V¬‚ôt~- ü;^Q}óî3x VÒôÞÿ؆¥Ë5opp V,›,=³º”={~)ž Ùó¹ŠÇYôgæìpçÎ̜®,‚ïØiØgE»®Ÿ×زyΞ9LS‚#d`©fÍ» E ™E·ŠösŒÅZۋN CÇ!ȝ§ˆA6 !ÃÕS‹‘ÂÅ=ÛUù¢¹sVÄŽ%ûåŽ]ñš\&OBèÛÇÄö@­Ä€îõqÔ1;üy=jçê™@â#ðâÖ<ÛŸ k§ñÔÞÄwõ¿­Ç"H’ÚńS|Y ~ÛIè¥Wl„ {ïã—_Ž5‚„Î¥w?Øfæk×A¥²FÁœÙe¥ØÔaCÚàÞœëŸmB¬œÌœ%7rä(€R¥«"ƒ6‚íœÙÃ(xÑ^4oѵjÿúAÙàà Ø íhžŸ(×®ME¹n³ÿ€xûö„GQx&E$!*­¢EzZ0.œ?†¹ó÷èëÞWá!ÕEâTÊûd³˜v\ @Ii¿·÷sÔ«ÿ~nóéÜ}hýÛKŠh<Ìs‘œîd°®›7.`ÒÄÞö8“Hƒ þrœî„‰keŸçÍñ”–FŒ\‚,Y£„˜¿¿þìXCŠÚÞ}&¡p‘2 ýOMÚíÌR$±óÆ_ŸÅWìcÊ^R‹žÜ&ïÄé‹÷±pÝQŒÙ«œ]ñQ8“·È2&Xк@1ó‡5A†ŽÉK·¹Ÿ&"°bóIŠâ›-; 6X£QkPY ähÑÖ…›o¢mÛþfßÏïáAÑSÛ·ýIzHӥ˂ŽÎ2}ú¬H“&Ry€C²dîHÄþý~×“{èGk3Ŗ4ÑÓ©Sÿb֌ÁhÔž=j×i‰ß[—û"{Ñf?®ºàG"(’›S§mїm¥J•NzoE҉c!~»õ 7·äxóæ%zõh„%+áÏΞ1ºÖŽÏï­ËÓ~¹áR8‹ç¢EË¡{Ïq_œ2,K‰š¿"¯žT¶\MTIˆÛÛ·/cԘå2ê°çð?ðèá-,ZrðƒºÄºÚ… FÓzÞ2ot‘#ãÍ,óÅ㠐ÜÙ}I|sb±!°zÛ)ŹK¯fXÿš~bS —aL€ D# †ºî._Šª…Ó¡a¢Ì† ʀ"P3‘@b°¬Qu”ç”Ï‰àœ µÀ ÷>ÀŒõWÑ®œá}‹Ÿw÷uUxP¯ÜºoŽU¬»ÌË5š/_z¡wÏÆ(VŒ"º“Ø36ýÑŸ ‚°`á~88:}PL7]vÀÀ™Rðꪜժ7A6òšŠ-k6¬›‹sçŽ +y=ÉÃ(’X¯ú†¢·J_§ððR['¯—mþÙ©&M7vÀž k$I2}Ÿ»w¯Éh¿1ô+Äm÷®õôõÏçà!s€í_JcFuÆõëçdà€²åjQtãŽrj°ˆ,ÄæÌÙ;äºS!šÃÂC1sÖ}UbP`È ßäÔiÁHL™¶”táè|€MˆîmŸŸß­¥ô—û7&/ÜKƒ?šÛºvŒýz`µž±€keLÀ’xo߄4vúmúòòKê/÷ÅôVP_•“ð šH *ÔHZƒÊÕô—ËükmA#Ö¹ *¶s™0Ÿ'î‘'4z@¥Å‹ÆâàÿþƀA³Èۚ];זë>4l‹ú Ú|óu=xðo,^šx…÷ÓÅÅ ïÞùÈiÅÃG,’ï£']P©±ãW#5­7=}ú Ӕ_7Ú£µEûÕ­•etс+Wi$û~öÌ!¹/¬`4pÐläÉkYS.Ÿ†ä.aèó•5šFÈ8c¢'ðGÿåø±X6€­\ÞÛ%z € 0˜°Š™N·ÿwóǶŠYAÎÍ>" ¢ø*S|‡dcÔ_éAÍGTšZb†œG®aꪇhþKO)„Ì9EßfæÖÃÇ1ò æÌ”!VA’tÞŒlÙòI1flzú”F#iš«Ÿß[žº&…ŠŠìúŒ}”)S£Bźr‹–(ÂoZÇ)‚M›ÚOöGlãää__o¹ÖTBáq¬XQ™b;sú ü÷߁Œ­bÚìæM iÚí\äÊ]GïÄâEch  FŠÁ¯ÑœÁÞ¯Ÿc(­}žT•J…9óöèÛÖÙ(Š Ñ,Š- Ŗ8^^`ck+#ýVªÜ¿·ék”} )әƒã‘9í/W)!™Í¶š1ÐÐpôð\‹|¹Òíz]< U›±µl`æ@à݅³x~ô(omæ° @Àäu”ç@ ’ÁA’,àÛ.üsà–ïx.ª!!›úMY&©»R¥ù¶€ ÷oŒEhˆ2ÅÖØ$Šš HŒqÍ'<</^<&û‚‘’<Oö /ë²Gx.ÅÖ2†Ò³gI€^•Ó‚Ÿ<Ÿ‹×$,…XîOÁ‡Ä”ac’hóÖÍ‹ŽN®ˆHœ iÛˆ©÷_“ä¶1:=É+*<À2f'1ÝU®GBöå /œ'ñÙ3¥-b-­n®X‡»yÓlÛºƒ‡ÎC.Җ–Ξ@՞=š–vaÍ ?çþ ¬©EKŒ Wþ91&À>&ðøàA„^¿Œùc¢–1%&ð­X ~+A.ÿ-»ÏaýŸ'šßÄpÔ­ïÎÎAL9’ÒŽ×ØY"„郛o) QìÊs)㠈hÂbKœKŒI$1UYÐèI¬GÛàDŸZ>xPkuÊÔͳµLô>_>>ɬ8Нñ%ÎsWą[ϐ£õïˆtü¶ÁŒ4ËY™H .mچô!o0¶oƒb1›™Pˆ I6ŽõWS­AMS|ËæG™bÙ ¶Ó„Öü} ÿûÏ•ê$Œé”N®¶lÇÖ*ãUªEáaŒy„°Ð˜yOMˆ:QVuóÆ;¶[FòUxoÅ:[±uÌÇÛÝŒxñ}zýŒ†Úɇ%ŠûŠÀÍYÎŒÕ/¯YôiÛŸ Ø~è:Ü~ª†Ô¹s˜…Ml`ߟÀþYKP5«3úŽãmΟÿÕ°< €Õ)Zvn°sFIbj£EgXžö®ÞCɟzXt?¹sæO`ÝÚÙøgÇJLžºIF¶Äôüêdš m…my¯9KŒŸæÒ§ ×aÜâƒL¥®µ¹˜Æv0&Ï]œ‰ k7£g³Rh\Ýò–ÎÄ3Nnî Vn9 +‡thÕIÙJñkÉ(:fÄ`ü˜+ e‹³ÕPKEvª¥^aóéWEø¶äþœô å[ԇG֌æc[˜@Œ8»zT/œ0}`C€Lî/mr#‰“€šö$Pÿ4•@I5' ÔÄùq¢œ8G­Gp˜ÊT7ÿ5š‰õ%†~‹­v&Oêƒ_[ö@õÍ,¶Ë—GHhеÜ>ZìÅK [ýßsLYò/2æË‰‚•„£«é›`–KÀûö=œ[œ?W̅¿T°ÜŽrÏ̆À š*Çt4Å×Duìš!(•=åJðZ³¹ÊñhH¿±I Z¡dÚx4‹›JdŠÒ69çh«Ï‹‘5[^‹íý­œ3KjüÕ±ºÅö‘;f~ž¿ÇÐ¥ÇqöÒd-’Eª—‡yï{m~Ù"&`þÞy¿Åƒ;aåýúÕF¶Lîæo4[hVn%ª]ò Ž4Ø£ŠøŽ=%³³@5ˆÓ23Ì[u~þAÈP(aI²Ì«ÀœòÖ^îÙ:gÞnˆœZ-19مa͒žع ä¶Ì5¶–xÝ,©OWœÞaÜêSžrÓ yÊGáªe-2Z¶%]3î 0†€ÿ\ûg/ïÝÁoõ‹¡iâÆãš&ô N ê™xT?ž. ¹6ÓðÙ˜2Ž)žü¯·ŒOž¹^'¶+áضu Šý¹R^F­Ÿ &Œ°ÅL€Œ|í‡Cÿݹ+ep¥0M$Ry$‡GúTH!5ÒÐÖd©Ýi…pzÈg*ª¡×ô¬;zOÇHsb‰™€£oŸœ„÷“gxãõþoýü>vNH›3 Šͅ‚YݑÊVƒtváð gNLÀ\ (kPM(P§L‚éýP±Tnsí3ÛŒßú£]¿åX>¥ößÈO7Ä%°sL 22»v®A¹òupýÜZLPڂ{Ë]Klž¿òÃÕÛ^žq÷î=z…'ÏÞ"$4™Ó&‡³³=R$s{rWx€tEÚTnHëá·$âûœh¢6œDl‰Xá'Š ¡KoéY9AW‘4·Q§c€“•ã”;R#ݫі—e(/Qò~P§ŒQuèêWòGåTÚ¢Œ¢~¥=Å®0*,þÎEñD/ŽïÅ!q@{\žWŒ^ÑóG9©Ï§û<éÊEµ¡Ž£¯+ê­ŸMyú3ú_k‚qՏ2ë«$žQSKÅkmCô€­m\žÒž:§Í§;.¬‘uÒÃ:ª>+ŠD«d‰~<êuôúŒëPüç Fp@ Þ¿õ…¿Ÿœ¢øî=|ž¿„ß«7䍀£=’¥JÌR"OÊî,Fãÿrq‹ßH`õÖSˆŽM‰VÇ¬Éš5š“Æy¢HFö ÄiùÄ GÛ¿–¢Z•êpÏú³åw˜{ÈâˆÀÝ»×p÷öÔªZ—ÏlÆÐ.`k«Ž£ÖžZ&`ÞøŒ'ÁúÏÉÛúòÕ;ÚÂÌÞtÌÇ7Ÿï¥°r%ïJm ;;ØÑ߄œ-=ÛÑ3œKùıŽb}]€^ðèĈNs !£KŸ“BJˆEÚ‰(…ŽÐ[ºŒBô‰G„˜Â*ÝëhÏRGì‚T+Dl¢Ï/l°ÖŠ*)­ŽÛ{(ÊLgZ‘%Äðç¥(³Ö nErRy­­¢¬ÂÂf!ÀE¢ž(ñVèbj[êc­˜Ï¢œJ­FhxžÔJÿè!êՉ~Ý1ñ^{NnAC'ò…!²ïÚv­TÖÐÐȁŽŽ¿A­ªã²:£DÉVMXšb‡–·ö:ñÿÁk]¥Ry=uâö“×T7Ù,ú!¶]Q/œŠcжÖ׉ãš<²d‹˜^+®œ|–).ÃÃ4pIæJ<”ãâ}ñçÅ%öDÐû÷’•hËÎÉpÌÁÅ É©\ŠtÉP0[*äJ›™ÝÔpSix?bý_4¿HšVm9EA’R¢åŸ&šÇ Gá þø©4{Pê‡Â”v‹/Ô!“·âßSo+odȘ Y³æ¡›ëïŸ<êÇP¹™ÐPGF*7ʳü…Šzúq?,ÚQký9퍆žÙ?·òfCþŠ‘qzŠ×šeêŒò#©ŒÖÕ§‘í*íEµÿñˆxŽóòŠG{^܈¶dÝQökÀ£FÓu#âòFD;V-lӥ듌ï‰þƒ¯¿ó¿ÓÖ²-ýð¶øqõɛy«£üšk?02¿<®ÕÕ-nDDÚû*å†G¥–7kʀžöƋ^[koÄô7 tLäÕh£¬Syk•R>Úh»5LdڛŒOŽéFϵ7^òƒìŽmW^«TÂ㯜ÑÞø‰›yc¢}/ú+ދŒÊ9•Io üýýðøñŒ|áw7ÌDÛÊÜD»æåà`okÊ?S®‹ $HþïƒñÊہÁa APPé90(A!ažuŸŠÓÍ~òžê¿3å×»â‰T~tÏQßû☊Ÿ·B©¬È Œ¬ºß éMߋ”G#¿ïé;‡ŸÅ÷€šÊX«¬à`g«|Ñq5u‰‡8/QïE9å»ÃÑކꋀï6ñ^{\~ißæžØ^J|‡ŠüÊwø>‹*#^돋:uyŽù¢Ÿû \<î{)X“œRËç(/µô.kE­rîSï·Î£-òŠ_š(Ïž"¢?ö~ËvŽõ„ÓIq>”扇Ñït}fÂÃ#¥#±FZ|Â(uyóCÅ3œ Chš’a2_(•ÇÂBÄyzŠŒ² œÖг•š‚EŠÏ” ýV€–¿tíijð†ªll,»|–Ÿ ñlCùD*ëàìçänðHbŒn6p·Ñ ¥:©lÂyýh‚üæb£! <š6)кË8ƒÙö Jÿ?ýÈÕ ÑD”á®W(F/¢…útÃíëóŽÎprr–ÂÃÁÁ .®I•Ñe1ÊH?âµx?þRØÑ·»]ŒTÎ *Fž)ŸŒyb…Fd5aÚQjåÆA9¯{M7 bԖF(uÂJ«ÍA¥rjúA ÕJ;å^Ø¢K¢m!@•Quí¢h£®Šp‘ÃËÚAoe[›júñ£€:á'Ž‹jÑFô×ÚBQmPuÂ6a¿Ð`Â.ÑGa‡ø!–¢Ož‹òh¥"õ›nd(¿†~x¡šx€ÆÕ+L倎„­ä R—e€÷€Få!ªS¶ ò\„†R~™tSԔ:•œÊ  â"W¹nºA‘Cñ,(ÇŽ%d^;ºqu+vËk"mUú¢<)uŠdkk+m‘,tYÛa™Ok¥RNŒŠG° ×ò‹k€ PFÿ•AÅK¡¡kA|B‚õŸAq³!ÊèD¬žéޱµÓã1)l IDATïm‰©è³ž:Q«ˆ\µŒ>ï|Ŏƹ¯©““+…û·GÖ48ªŒQ¬`&T ý¥ÂTŽhxù%°xâoZ#Ŏòõš~·äqe ók¯Åw‹LôßmòY”‰VöããBTŠiÐ:¬ôÎÉRåYy%°Õäi"1ÿé¹(ûtbè‹E?Ä`Ÿà!݀‚L ÷"šW|'ۈ‰Lù¬}m+ŸÕô›#ŸßÕÒc/žm)Ÿðê‹gñ¯Kbztá-E5”Bšé¹ìy R µªÆâÿŠžƒL@n3cçn:ª˜âË•?X_# ~TîG 4<~Å·9 ,8م!_úpŠgNL€ 0&À˜HlšŒêƒ]7J Nž8ù<|P¥, TƒD9`L€ 0&À˜`L€ è ¬Ùv u2ZƒÊ•?L€ 0&À˜`L€ 0&ð ¬&¡NJu¢A+Œò N™8 yRœAÕry VȘ`L€ 0&À˜`L€ èIµ•©êÔI£‘ËÝÕX ò§Œ 0&À˜`L€ 0&Àb@@FñµM†–MäAeúœ• 0&À˜`L€ 0&ÀôL.P§Mœ)^£Zù|Œ™ 0&À˜`L€ 0&À˜€Ñä_•Zud°ŒQkP§O‹ìÉ^¢zš‰r&À˜`L€ 0&À˜øÐƒj“-»°@å`L€ 0&À˜`L€ |GbŠ/lȃÚe²A+Œò Î˜2Y“>GŠù VȘ`L€ 0&À˜`L€ è¬Úz P'¡)Ÿ&š3§ŽCf·çšÉ•?eL€ 0&À˜`L€ 0&B ZÙ$¡)Ÿ,Pc€³2&À˜`L€ 0&À˜€© ˆ IÖ$Pél":{úDdpy‚Z?0µ­\`L€ 0&À˜`L€ X0eН Mñj°—F­A5œóÔ®ÄÕ QÎÀ˜`L€ 0&À˜`z2H’šÓ R1J ÎT§Çš]¹ Á 9`L€ 0&À˜`L€ 0“ Ô¹³&ÃÃöêU-Ĕ™`L€ 0&À˜`L€ M`%yPUjWüjª)Ÿ,PfÏ™`L€ 0&À˜`L ÅW턖]§äbÔ_!PSÙÜGýj… VȘ`L€ 0&À˜`L€ èÈ I*GŽê6à £êü9S‘Bu ª1X!g`L€ 0&À˜`L€ 0& #°rËIÚfFxPM$P̝†dV·Ð°zQŠÌ˜`L€ 0&À˜`LÀh&š çMG’ˆh\ó£àŒL€ 0&À˜`L€ 0&À„@U‘õWSyP͟W Tþh1&À˜`L€ 0&À˜@Ì(TGšâ;Ó`A£Ö .^0Îá×ñ3{P å L€ 0&À˜`L€ 0&E@zPÕøµÛ,ƒXŒšK΄cÈU4©]Ì`…œ 0&À˜`L€ 0&À˜€ŽÀ*Ú*{Šâ;Û £êÒE³`tMë°@5H”30&À˜`L€ 0&À˜€ž€œâ«¶GKS ÔåKæ@ýþš×-Á˜™`L€ 0&À˜`L€ M@ T•ZvŸc°ŒQT)PýI Öcj(g`L€ 0&À˜`L€ 0<š*µ­A5‘@]±t>¬ßA‹z%3`L€ 0&À˜`L€ 0£ (A’L(P«w—1²O£àŒL€ 0&À˜`L€ 0&ÀNØ µFMßf†QS|.\ˆð7'Ñ¡Yiƒr&À˜`L€ 0&À˜`:óW‚­­ÚþµØ £êêÕ«I žA˺ù VȘ`L€ 0&À˜`L€ è,ßtvööhÑÅDkP×®]‹`ï h]'SfL€ 0&À˜`L€ 0&`4E Ú‘@k°ŒQT!PC|n UÍ +ä L€ 0&À˜`L€ 0&Àt–m<47•uýúõx{¿ÕHŔ™`L€ 0&À˜`L€ M@TGG4ël¢)ŸB úz¡uµ$FÁ™`L€ 0&À˜`L€ (՞ª‰Šønذïý^á·*öL— 0&À˜`L€ 0&À˜€Ñ–n8gg{4ýsžÁ2F­Aݲe ^¿~‰öÕl VÈ'g/}ñì¥^Œ~‡Óà}P0’&M ++ 2Ҋ6æµF„FƒÈðˆó€ÈØØš._‹C"ÙÛÙ"84Vt̊2GÒ³£=ý/"XŸŽ€ÿ©TÖTŽêŠ×ºcNvx"‰$ž]]ðÎ?Hoƒ8–ÄÙ~ï阶.‘7‰+{$ˉ6….NðþÀz;[5BBÃd]¯ìímu\œw¡?È÷Úòº:ųZ…pM„®»².{êsõY¶­Ž/’3:‡*vim¯mDíE·WŒõHûÄ?m=âÙZÁ­¯_WŸ,ã@eB¢êŠ^§5œt×,ªN¥:»•²€5Ó]÷óØÚX#4Œú…PßkkºÌŠººŽ-É÷ ;>¿BII¢ŒZeE畖?W¿¬Wûùˆ^6úkµ¡¡Ï–.‰ÏŒ†®—† ÓPÝ¢}achXžŒŽáôùUžÅùù¹|ôì lU*dɘnôÙʟ3R»'¡Ï£ã—šåãL€ 0&À˜°(Ë6“÷>;šhŠïΝ;qÿþ}t®—T NL@ðñ Àêm§pþêcyÉ€nN ‚ÂRÀÚ!"LèŠ^ˆˆHº“× Añ‚>NtL–‘$PmH Q©=FDú÷tÜÚJk€ÖÖjzXS[YÖښŽ“€RžIQ{*V”_yMj‡€’È#Ž«©\ÙleEDŽhӖSÊ҃ò)ÂŽÊ ‘EÏ)\u¢Q©'J”‰òJ^)ÎDKԆH¢>E EYÚ×Zå€G/”ÒŠ ¯ìÂàlK‚Q/äK­®Ò£Q&%¿ðÄ+Ú0@ñüå?-{h—×B›7JÈ+bÞÅ1jkE˜ÉsZ…©»Vâ­þµyÚ¶éµrMµEDÛdƒþ˜žž”;‚Ä›øGäèœ"òD{NöâúCŠ?QƒF”yEœ”IôGå+Ë'OêŒÐÐpÜžûœ,l‘5c*4¯[Y2žó `L€ 0&À,šÀœ•‘>u2Ôk7Ó`?ò îß¿—/_FÏـ×+å –MàüÕGغ÷Î]yˆ*eòà‡™. в̈́›Ï“Ã7Ð!ÎDD1#„„ò¬4­(RŽ q€\ùZïuÏÚãRü®PºüT§ˊØÏòœ¶NÑ) µû¡h֊¯„ô‡eÕj&€Ú¥HT" û”cZ¡ší‡Ppvvä… Ð{…?,«ó kÅ£¶^ ø€}tï®Þ-­Í!Ή “ÄmÆ%{{GêڈòNG/Õ&y1Õjy­1¯<Äë(/U¹ÞËkCöh…÷YûúQ–ÄŸLÐhí×Qž“çÅàBÔ ƒR R€T«hˆv°AH€eÜÃ@Žzý …ÀÇå@†J-Ÿ£?Œ#õù\¶* g~†w>¯ñÏÿ.aÿ±ë(F?};Öø–j¹,`L€ 0&À̚Àô%ÿ"WVÔh=Í F Ô£Gâرcèß®"3X&1õsѺ£r:c74­]OÞºâ)=Œ&ï:'³  ÷ ùûÁVÝD[ÅLåÜGskèAÔtYWX'<(ÌY$Ì)}/ýK8“‡|Ίƒžtã æmÅt˜`L€ 0&`‘&Ì߃â4(ÿSóIûg”@=}ú4vïލ¡Ýj"Òï’ÁJ9ƒåk7ç­>„jåòáâgÈ_€>Œ|\B®'NL€ Ċ@õwÔ);þœˆ;ÏbÅÔv±ª‡ 1&À˜`LÀœ ŒžµKåD™FcÉ̯;HŒšbzïºuë0ºÿ¯ˆ|{œûζÅái›±ì~oü#¯?Š*Õ~Å/Þ7Ps•‰Œ€›cjŒ+{œïè5ì?| 7Idž»L€ 0&À˜€¥>m;êT*€bµG>UbŽ|)%Poߟ `âÈîˆ|¹×Òùqÿ>"páÚc<~ö¡4Å·XÁÌžüúGöœò§„ ˜ˆ@‘Lϑ3µ·¬­}¿åhÕ°ʖÈa¢Ú¹&À˜`L€ |ƒ&n¡à%P ê`šJ0Ñoš^^^˜1c&Œˆˆ§›Ÿقx%°þŸÓșÅGþ»†õâ譌ñÚ>7Æ,™€ Nª[älÕœ8{Ë7Ÿäõš–|Á¹oL€ 0&À!Á“¶¢5ÍÆÌYa ÁÞåA}ýú5F…ñãÆÀöåZƒ•rË"°˜#¹ºØ#Cšäxo[¯Þ9YV¹7Là;ȜÒ%³=‘VÔþ}:–MnƒÉ\Ÿ³UÜ<`L€ 0&ÀLC ËÐ5Òûw€.ØÒ`…F T <žžžHâ¿‘š ƒsË!0—ö- EÝêepÆ«€åtŒ{Â̈€.`R—!«Q·J!T-—׌¬cS˜`L€ 0&;"žÍý—cúä1pNWÎ`%F ÔÐÐPôíÛýúõCªÈÓ@(ï…j¬e˜³âxñÊ5ëw£ídÜ,šgÜ&`>JfõBfwˆ¬Å^»[ÿd>Ʊ%L€ 0&À˜ˆ%À ôð\‡ù —Cå’Å`-F TQK¯^œÐ¹sgdq}Ä{¡ÄjYf-??ÿPä,Þaš¯/j¶¬žso˜@üȟî%íú “셝 º°@?øÜ`L€ 0&g^y¿ƒçô혳lÅG²7؎ÑULñmÔš e çœP bµ¬ Þ¿ {T¬5Ȳ:ÆœafD@'P{x®…œ-ÆõodFÖ±)L€ 0&À˜ˆ»_bþړ˜<ÿ£*0Z Ž;¥K—Fù"îˆxsÜšÊ9“eè7n#^ù9¡jÝ~–Ñ¡oìExx8¬ha•Jý5™Gñðð0,_6u궂»{œQo[†,Yr#æaš…[¡šÃ×"‰‹<{×·ðs÷˜`L€ 0Ä@àܕGØqä1FL\nTwšbÔtéÒ¡F…üˆ|Å{¡E×B2-\{Wï%êb!=Š}7ö؈0U8’&MŽìòÃ=iêØWf&%}|ŒÑµsm4oѵjÿª·ªOï&ðH•}úN1K-Û w×TÊ{#h#ëLéS U£Ò–Ýaî`L€ 0&(:u gnG ßÐÉFõ×hºfÍ„„„à÷_ð^šF¡µœL«¶žÄ±‹ïQŸz/ËéT,z²{ÿz\¿~ÖÖÖȞ¯\ݒ#WŠ‚ ^€Ÿ}û ݺÔEýmÐøç?ôdz÷l ·€)0dèŒXÐâ"1% š}ÇnD‰BYКFјVÁù™`L€ 0&`vþÞw¯Â² CçÞFÙfŽ@Ý·o._ŸŒ>}z#âáb£*çL–A`˞sØqøMñíoŠE/vï_GâôœŸdt‘š'Ka€H’*µšG‘7o^¢{×zš]§%š5ï¬7ªWFpquƒçþ{+¥šŒÍL|Ðæ6˜`L€ 0ø"°xýqže®Ÿ›41ªI£ê… °iÓ&Œ=OVŒªQ€-!ӞCW°rÇ=Ôn<ĺã>>ºgÏú€œN€º§Jây ïéã†ã©Àë×Ïѳ{4jÜ ¶Õ·Ú£[¹&uààÙñdIânÆÉŽö.r íú-CûŠåP¢ˆá0쉛÷ž 0&À˜H&.:•[¡B… F™kŽ@œÿ>æÏŸOOOØùìCdÈ+£àL ŸÀ‘ÿnaÖêËhÐ|DÂïL {p违žï:|^þó.Dj‰+£t‘*1¬YÉîãó'OìGPP"##ðþý;üöû_±ª+¶…^Œx‚>œ~F‹_»¡fÍújºv©ƒL™r¢wŸI±­šËŐ@óRWЬË| í^y²G¬Ša5œ 0&À˜`fC`Ðôãø¥moä˗Ï(›Œš¯^œÂ”)Sлwo€ÀUÚ õžQ pŠ„OàÔù{˜¶üê5—ð;ƒ<¶µj<žuo?#RSž§F“†á`烚•¬Gî¢è¹“š/«VÛ`ƬípuMª?¶oïFøúz£IÓN1nØOœ _ßæhÓ¶~ªÔ@_äώ57ïèÜu€1Õpµë|Lô3Òz$3A\`L€ 0&ÀŸ/Î£cĘ)H™2¥Q†-P1bÄtèЙ܌y/T£ðZFŠÿ.ÜÇÔeÇI N°ŒыCGwàÜù#°³w@®‚E ¶µÅýWáãýZ_:E*§ b'N÷ïÛ$Å©““+êÖkgç$ذ~.üüÞ¢FÍæøå×îúvþÙ±;¶¯Äü…ûŒ°<æY=ºƒAZ¢ÓŸÃñc™êú þh_ŋUD»?ÆŒR.+B ÖümVOo€IœbUbL€ 0&À˜€¹ Aß—1eê4888e–ÑUÔ&jœzõP ‹-"y/T£[BŠÓïcʚ͇@=td;Î]8ª¿tˆÔë$Rߌ†Gš hX·m¬<§÷î^ÃðaíIœ:cȰùH›6³lëâŘ4¡ì±pÑÚk•6[¥Žoï¬X>ÓflCŠ&ÿH {† m‹=Çá‡bôõ·ù­<*V¬‡–­wôf“ÿJ…UòÞBË.ã±qn'8;ÙÇgÓÜ`L€ 0&ÀLNàÙ Æ-œ‚Y³f]wŒêŽiӐ-[6Ô®T/÷ÝgLØÎ]~ˆ©KO V“± »#FXè0yN/ù$§N€ÚÐtß÷o|Qœr3š¬UFÔøi–‰ã{RDìS4d.rå*€ÏŽŽTEpp œæ›,™»}ÖÏ9{ö0ŠMé'Û̖-¯Ìà4Å·i³ÎšS·å'åDp§-›áì™Ã2ž“¶ÍšwÑ{xÜ¿ š.]:)=ÀgÏBݺ­Q¥jãÏÖwëÖ%ž¹¥@Žä^³ŸK¡¡ÁØ»g#þýw3Þûû!sæ\hÜ€ÃB?!ÿµ•Êr þí‹»ÒgL»Â¶3&À˜`LÛO†à¹¯5:u2>–JŒêɓ'±wï^RÀÃx/ÔDô;w…ê<š¿Z®@}çKFõªf͒uj¶„J;Ï©š|ûßËåZÓî=Æ¢XñŠF}ŠtòÏ.#PºtUYf×®58ô¿íRx6iåážÏŋÆáð¡2Ÿ‰Ÿäòµ˜Â›>C¶OÚÁšæÏqÖHA)’·÷ ôèV­ëó‰ Œyã&Mì-=œÎވ H‚Ö#uL˜ž–Ä¥ cFuƃ7±pñlÞŽ[·({©ªTjŒ§<éåûðð0)twïZ‡°°y¬T©*Ÿ Ìäãã-ë}þüD0)±G«ÏÛ×°µµÃè±+‘šÚOè©Hú[è1hþYҍX}^€'ô>²ýL€ 0&À˜@â!0o‡/ÒfÈ.—‰›b$Pïܹƒå˗£_¿~pòû‡î.Œm‡ó%`gI N^tu-8HRPH‘@ UDÒÇÉâTÔ¹zÕtck1Üs²e7.Ôö•+§1~l7Žk?eËÕÄÂcpŒD¥. 8yó£i¹˜1} y5¡Bźš_ÿw€H™:¯­ˆ {ö}û4C‡NCQ¶lM}[" ÒHÏÐhÂѪuoiðŽÝ·o_Æš1ËåÖ4“'ö‘kjÛŽë‡%$˜“$IŽ4i2âúõsrʰ˜:,Š4Oß×ÉÛ+„ná"e¥˜u7iú'¶m]‚ÜyŠÈHÂÁÁA:øw»ªVûµ‡£“ Ö­ÿ¬’A¥Dp©„ž2¹ÝDŽ©°uAç„Þ¶Ÿ 0&À˜Hì¬là¹ä>Í «‹¢E‹M#Fõõëט9s&Úµk‡ô¶—üÂè†8cÂ%pæâÌZy Õ:%5áö*Êò„#Xí¯Ç°{ë&éՋžL%NEÿ;°K×‹4cø åš‘€"ðÌéƒrJm–,¹¥G6kÖ<ð¹ºÈÀ"¯ˆÈ«KBÀ­]£,LoÔž=4lûA³Â»fÕ Ì_°N$EÞÏ!ƒ~ûdZ±ð` ‘)Ö–-W îîiqçÎé!AfÎÞ!#Úwï^•Çlmí1xè\$Ož ;ÕB‘¢eѳ×xˆèÄB`ŠI“ ýL—çuéÐÁíXŽp ò(~ý§K/«xˆ<Õj4EF‰{ûö6l˜'œšœÿšŒÂ…4§YçÉèz§MÄæù~qš³Yw€cL€ 0&À˜€–@„mjô³C† AªTQ÷y†ÅH  ‡§§'š6mŠŒoùþŽ¡úùŒ8Iû NÛÌ4Ÿhœù° áÖÁ±ûFÊÏŒcשa¡ò}Ö,yhZo«ošÖœE±†²G·Ž64]i j¡B¥ 2œ|é”ô4 ¡˜J[Ž„aûƒ¥øëݳ1^¿~.· ™:¹/?Ÿ#, Q(’?­ÓЯí£úFŸ‚§NÛ7}»o[†$ôfÏÝEžNeïM!„G ÿ]ºŽBÉR•å±KäHQ†ÅÑ7o^ʇ.‰©»mÚõGùòµå¡žÝH»Ät_!F )#ÔZA‚zæŒAøïÔT«ÖäƒHÁoߌ˜ѝñâÅ4þ¹íÍZœz4¢šÇ.R  Û¢'á-ÞeKH™“>Àˆq£°c1Oñµ„ëÉ}`L€ 0&˜ øDfŰɛ1yòdZvfg4Š TQëìÙ³‘1cFÔ*“‘Ÿçnˆ3&\Gþ»EN¢FcËYƒI‚4Ä:ëO§ôŸ~þNœ¢(º(Sºš\7iÊ$„ÞŒéƒätâ5›¡Rå†4ª”N6!֐H1ªÛfFLٝ6µ¿Z/bÅ«ë×ÍÆ˜q«A»FU”N[ÏŽlÕ ÕªÚ IDAT7‘m ŠðlŽ¿Z®÷ÿÆš1Μ0 ì=|Ûö^@¹:f>cušðžZ…ÁAãFŸÔª}d.›GØF(Û»ÄGºJŽWóÙӇÒÃ)eɚ•+7B®Ü…¥ "ؐ–­ë-œ­§©ŽEŒ†ÖÍöê3‘Öi.&/çßRì oký†md!]ǧOëO[Ðü‡2üš#AzþìúÓ4àüùK Oß)2«ðäöêÑïü°`á~9-W·.4SæœL{ž~l)º]7nœ'¡l§ß¶Fw.$$Xï™Í“WY,/¶ŽQƒý‘4iJ)Z·ÿœŒŠO@ÑÊÉÀHúý;ÝÆ-@Út™ããÒ|—6R8ûcÊÄØ0§#\œ•iڜ˜`L€ 0&àØ$ŬÍOÉ)’µjՊ‘ù1š^^^XŒx1ÚŽnŠŽ8£Æ8sÂ$°ëàeì=| %«YN€kŠV°‰Ž‡aS o*y#\Ìò"ùùœÕ¯ýØ@±fSLã-P°€Ñ¶\ߍëç¡R«?˜.+„몷žv;%ØsX;éõ͐1;š·è*ó‹mw^ŸðÂyÚ¿õ왃rí©ðþŠ`I±Ióh˱÷ëŒ{áèè,«X³zMe^#|“Šh{òtΟŽõÌeÚïUL7~HÄÚ܄,ÉÝ5€jw¬˜Úɓ*}çĘ`L€ 0„FÀÊ%úŒÙŠŽ;"{öì12?Æ5$$cƌ¡-,ê£`R±U .ÃÉr l߇NÝB±Ê1›?nÎDB­‚äg7L%žëHì5IH²Z™³ÙßÝ6±>vÖÌÁrš°Hbz²Xs=‰õšÝhŸW±?il’'g £iÂbË]mlÜ0;¶/×·'Š/GFFèó€N‘¢ùNÒ¯…MÛæPf۪Θ8ðgdH«ì_ˉ 0&À˜` €¯uxN^-ן:;ÇlÐ=ÆUÀ[Í€K—õŠQ€Ópÿ„Æ‹í!Í»Ïáä¹{(Zid Kšoö1±—ŠøZEZCü³¢'㠈­oŽÛ-×Ì ñ(‚2åÌYHîǚ”‚&}Kú³c ò—’ӏ?NbŽXÇ*ŠýR +wdŠívòç+n1SwoèŽm« HŸŒß‚‘Ë2&À˜`Lໞæ“k6lÃØ±1a+ºgÏÜŒyݚ‘»6øùwë87?Öí8«·Ÿ"oéOCüXÀ­X*±þôÖ͋Rªiбxß¡}š>ܵjÿj©Ýþj¿Žíì‡Ջ r™<‰²ÿÜi&À˜`L °Mm§"hÙ×ktè󗱚׮]“’:5-„€6/8A6߁›ŽãáÓ7È^|¡¬|ž ĈÀ˜Qqýú9”)StŒë×ÎaÜØnúI1ªÌB2Ÿ;8Åò§AÓ:Å-€GÜ &À˜`L 1°JZ 3–Bh‡ˆŠ1îz¬ªÜµÞO97Í»7ʁ!“·Á÷] J[Ð63 ë X®µ«WNÇîÝke3f́Ð`Œxþ“§nú`;Ë%ðiÏþý{ÒºÛbD¯ú‰©ÛÜW&À˜`LÀB„»7D߁#зo_Ú:1MŒ{+*Z™Ž.¯–«HD%2rSóôro–±L3«”þGT’#ËÉ4³-£œQÐúØ­–…ÃqÓ¬Ëèòò¬¬Ô/&tõêŸ^Õ÷ž +_l¹qõ÷ÙG¬_í©ñÝ$R³M³ïFðÓj=鳋ðM¶`ûðØF+~èÔ:)ýŒF"ˆDû°ú‹ªñˆÄŠE”[DÖ=5-,ÍyýÏUY=Í(V÷íþ3ð:. Œ4ŒÅó§¢ÂW‚ò‰Eð·ÐxƏëVÌÅ5WÖ çQ€ (@ì((Þû‡—_ÆÁƒño|cÔqŠ%A=yh'~óôp‹ºnߢyÕ£ŠäŽ@GW §Ïâð‰shºÐ¡ŸGÑÐxÁP•“}úKz(d|Q«ûP8ª“#Iû§«i’ÈÆ —Ë WJVÕãâ"OlºJjÕ4™. œ[-£Ýز…jY‡$À*aÑÓbɰ”)ÇUÖ('َ‘4«{µŒS%ËFâ cÙX=’@óäPŠKò€žê›$Ô:AÔɵ9ÝLR.kri&_ÖD؞ëä\§åFf$×±$]O³&êF;ýÉŒ%±×Ó­Ë«r56ÆtõX™ËØHÝ:“{5߬K’0ã¹ey˜IòfŽi$jÆœ,«ÿbt¢×_‡_ݶŒóÀ2²Œ˜ƒ!«$Ù²œY·<—bFœ’øEµµ¬[FŒ2ߌÓÒŸŽ%¢h#.)+­÷²ôôõ“Þj$ÀñuYïÍr†G P€ (+e áœt¶lÙ¢Žˆ âÞ{ïMKäiKP›››±åñ¿ÇªË§bå³Ó+¡(@ P€ (@ìpLߌÞp!ŸûÝïâŸûîÃŒyóÒdÚT‰æ¹_þNx wߍi Ž•P€ (@ P€ @v 8ŠgÂQyöìك^xAޛ®[ZÔC‡á÷Ïü3nŸ®—ÕU¥+FÖC P€ (@ P€Y"à˜z3E3ðœï}+W®ÄúõëÓYZT‰êÑý*Ý'±ùÖ«Ó$+¢(@ P€ (@,pO„sú8vìžzê)<üðÃðù|i ,í ê®]»ðÖK?Å]ŸZ„©S&€-PVD P€ (@ P€ã+à˜ô 8ÊàÉ'Ÿ„×ëÅÝwߝրҞ üäÑïãªÚN|rÕei –•Q€ (@ P€ À8 8=êÒ2w¡©¹=öŸò•¯ ŠŠ&­Á€=A•èÞzë-|°ý—øâm‹ÕõG-œŽö˜•Q€ (@ P€ À°Ÿ+à(_­[·âÀxðÁ‡]ÇP2’ úý~üìÉãòj?Ö­^0T œO P€ (@ P€Ù,àpÂ9ã hï â‡?ü!îŒóN,\ž0íg$A•(_}õU|ôγž÷³—£¬Ô›öÀY!(@ P€ (@ Œ‘@É8§¬ÃË/¿Œ}ûöá›ßüfFÎX‚ÚÚڊ§Ÿü7,›Ù†O^ÃߢfdôX)(@ P€ (@1pVoB{[ï=ÝŒy3-Z”‘V3– JŽÛ¶mÃÁ]¿Å—?³ÅŞŒt€•R€ (@ P€ @·9+úš5 ªhlݺU]u'Ö,)DíŒñ;î9+F†AP€ (@ P€È ÀÿöŽE§á‡þ!ƒ­ ¯ê¬JP%ôgžy=çÞÅ­Ÿ¬E¹¯dxœáÒ (@ P€ (0€ÀK¯íAýÙn|ùÁEiiِˏÕY— JÇñó§àð¿‡ÏÜž%ޱ²`; (@ P€ ò^àõ£át+6~öo0}î5YÕ߬LPƒÁ ¶üìqDü»qÏŠUp¹ ² ÁP€ (@ P€ÈE7ß9ˆcõMX¿ö:Ô­üjÖu!+TQêîîÆ³¿øúZá¯?¿&ëà(@ P€ (@\øã»‡p¬¡ŸX1ó¯ýP89ëÂÏÚU€ä©¯üæho9…û6_§Ó™u€ ˆ (@ P€ @¶ Œžm7ZÕ%eV]9—-YgåYrV'š"ÖÓ݁gžø{ôõtâ¯Ô៏;+!(@ P€ (@lx}Ç4žmÁ†5‹Q5e"36Ãáʞ#YͲ>A•`Û.4à¥gE0p›nº e¥ÞlwÆD P€ (@ P «älœÍ­ž~å|ÔÕLcÂåpTd׉‘r.A•€;;;ñÌ/~Oš7¬š©S|Y5ð † (@ P€ @6 <ûû]èìîź՗aVí 8ÊWÁQ:7›BŒ(–œØƒjF …ð³ÿz \~,© cAݔ¬Æep (@ P€ ÆZ K%¥¿ýCttõàÖõËP5{…JNÕ^ӂ쿄gN%šæÀ>÷Üsˆ†{0Ã׎kŽõx³= P€ (@ P€Y)pâT3¶ýiÜžýÓk1aÖF8ŒÕYk¢ r2A•ŽŒòÊ+hooG©7Œ›Wš-}-9ƒÎ@)@ P€ (@ €[`ׇ'°÷à)”áö;¿×€«GAº›Éh}9› ŠÊΝ;qôèQžÝnÜpM-&âÚ³È(+§(@ P€ (m[ßúgšÚ0kVÖú~uÓŠl 1¥xr:A•J‚úÞ{ï¡··˯Z†…Õ=ˆ¶D#)p! P€ (@ P€¹*Ðx¶/¿¹W]ŽÓƒ+W݂¥«ÿ2W»¢ãÎùU:á÷ûñÒK/¡@g=yòdlX· і·í®ÏéÁað (@ P€ ’ ŒýþQì?|QW9nÛü·˜6sNÎcåE‚jŽÂ›oŸ‰ÆÆF8¬]»ÓÊ£*QÝÛr~ Ø P€ (@ P€z]{7äÞî> æ²5Øpë=y“W ªŒÊ‘#GðÆo šš555žþú5úßhëûê°ß`Þ ;B P€ (@ \zï~p ŽœAŸc2ÖþŗpÙÂ%y…w ªŒŽüuÛ¶mhkkӏׯ_Y3«õïBŽã@^ ;C P€ (@ ä¿@}ãŒõî!£…šª»7Ü|‡Þ)—o·ŒLPÍAÚ¿?vìØ¡0,{S¯ŸújFmۃhçAžH)ßÖfö‡ (@ P€y&Ð×T‰éa4œnAoAnøÔ±`á¢<ëå@wò:A•nƒAŒþúë8þ<Âá0-Z„•+Wán#Qmߗ·ƒËŽQ€ (@ P€¹+°óƒãøH]×Ôáö¡îò X{ã­ú|;ù|ËûÕŒcǎaûöíúL¿rØïµ×^‹ uYš¶U¢º_íQ åóX³o (@ P€ @ì=p ÞuîâJøŠ.Ä'Ö} ÕÕÕ9ùèCŒdT“êý÷ß××Mõzœðù|X²d êêêT¢Ú§’Ôœ*Y•kšòdJ£_µX(@ P€ (0£'ÏãÝ'ЃržËfãÚ5ë1þüáT‘óË^r ªŒX(ÂÛo¿Ã‡ëß§bùòå‰jÇ>#Qôæü³ (@ P€ @v ȵLßßw}•èqLš5k±lÙ²ì:CÑ]’ ªié÷û±k×.444Àét¢žž+V¬ÀìÙ³õáŸú÷©r‰šp Cü¬– (@ P€žTö|܀ÿÛ{QÏ4„ &ášU«u>r)ß.éÕøÖÖVìÞœò;Uٛêr¹ô¡¿òçtDÕ¥i>Ö¿S•+ñF P€ (@ P`€þönÈÓ'»vWÁU\¥¯6²téґV™W嘠Z†³œœòUÙ£‰DúՉŸ €º4MDù¡ÎŒZ Ø P€ (@ P ³Çê›tbZp–ÌDeu/^Œ… f¶á« j‚ëîV[5Ô5T÷íÛ§/M#¿Y­­­Õ‡þΟ?OíQ=€/QƒP{Ž 7Ã¥(@ P€ ÆJ ÅßIL?<Ј>õÛRÙczÙ¢¥úҗ3fÌ«0rª&šC ב#Gt²ÚÔÔ€¯9${Ue…š7w.Š—÷ªDõu±UN :ƒ¥(@ P€ 2#ÐèÅáçqøø9œmh|Sæcђe:óÞð–\€ jŠkGKK <šÏü+×Q•[QQæÌ™ƒÚJŠŸCŽ·)ÅÚž(@ P€ (/]=8Ùx gZññ‘³(ôúr•㊕7a®Ú±5sæÌ|éjÆûÁuħNÒ‰ª\ZZŠ`0ˆ‚‚ÔÍ,GmEj'õŒ V¡(@ P€ rEàŒ?Œ“g{qŽÞ3Í](p—Àí-ÃüâD¹¡ iIDATKôN¬ººº\éJVÅÉu”ÃqôèQ?~rFumÁÞ̝æDµ¯Ó§N@ÅĒQ¶Ââ (@ P€ ÀžžËá(¬@{ §›{pŠ© '[!W‘Ÿzœ^}讜³Fþäò•Œ\€ êÈí.*yúôiœL¯šˆêJÊJ‹ÒØ*«¢(@ P€ Ò"à(BRÎ;SXXšïåjrÈîŽiÓôŸLç-3LP3ãzQ­~¿²‡õ\ý‡8yô#\h: gT8B0ÆÌê L./Շ—ûJPá+†oÏð5FÃÃf(@ P€ .£þžRŽt¹ÐÚíÂ)uR£ææf}ÅóÐ\ŸÏ§ÒêêjœwTR9ß oc#Àulœ/jE¶ÄÈ ¡ùl=šÏÀñcÐ῀úý*"}è€ü€µzêDÔªœ­%Å^L(õªÃƒÕ_‰¥ê7 P€ (@ P ^ ¯/„öÎ:ºƒh xÐÔîDS[ÚBhnñëDT~;‰DPUU¥Ï°+Éè”)S0yòd^fœW(&šã<ÖæålÀ²§Uÿ5×£å|=NÕGóyuaß@‡JX{QIkTýQÙk…ÚÓZ5y‚ºÜʊàS%E«¿"¯ÅÞBu8q\®anñ)ðúÇà“§z,™²Ã;!”1Õ89ÔÀÍòܺœY‡ušœnsžZÖ<éT|ÓuÇÍOPwTÅWv˜u«÷­þ›={ÝýóíqÇêù!ªÇIê–zåfÛږَ^&IÝfa™(.kýƒÕmmË>ÆÖºu{–1íï§uœ°Œs\YÛúc5²€ ÄpÖ¡„ëŠÄ΢W=C¡(@ P :â°/RauÈ­J<;ð·wÃßP»ÑŠÒöÎ aÔd–©Jt"ZQ¡ŽTT‰§$£²7tâĉý©ŽÍeÆV€ êØzžµîîntuøÑÕv­§Ñé?‹óçÐÖr­þvtvõª¿µç5¢ÓI`œêw­Ý=AùF®ãêQ¿}Õ÷ýÕ±óêtØNW)œrï.…C=ô†õïgåld²…Iþä°yËœ9͜n}.].ã÷މ–·/+˘˚÷2m ±ŠŸoŽ—5çI:!Žf±x¬mÙÛ5Ë[Ë%«Ã^O²zí>X}ɖ5=†ËHãIÔ¯dæö1JŽrÛcNæ6X]‰êH4VCŞʋo°¶tùX"îpÆma°TmßX£ õϏÛ`bKìû“üØB:KboÝÈaTßVÜ|[݉6|€Z·u#‡Ù‘ž .‰6ªè×_,JËÆÙè`ÝØ“JÝö5zœõPÄ÷ßàØÀÓ?_MOŽq(ncÖLPVÚ²ôc` /S]_‚ (:VûƚX'â6ÈôW¿ÏÚë† {[z9ËFžê¬NƒoLŒk+¶Ÿ[ߏã̓Ž50,oLŽ¿’õ-ªöhè[ÜàøÚ7øÙ_ƒœä³ñ¢ª¥œDë«åu&u|® ôÍZ_¢×™ìIž1Q֊žõ5ÖeKŸuÙØ@Ú7&ÚÛ²oŒŒÈÖlÛkÅ^Gâu;ñkÁèûÀk:ÑkÁ\ÍÍ×BÜ:iÆbéwÿò–Éf?Œ{ëkÁò:²Œ¿Å¯C–÷Ûúi%ÞKŸs뜱œ¥wŽØÛûíéEïGf RŸSöÒÅ ØËY—hõâ÷7sýÓ*:Dcý‘õ_XÅ/Óe܍6ŒùæzÐß~lŸ”—ÕÞê­ËêrƎX5ˆ*ƒH؜g̏ˆ—~Ë1–3ËHËáØëw ã;©1€Æ£?P× =£O *ßKåçnò6¬Ú ©£åÖèCJD{ûŒ„TÊÊǯŒ/y<껊ª£Žl"&”WbÂÄ*ø&ÍÀÄÉÕ(//× ©\ RþJJx5 ëú• ™ æÂ( cš Ñ`+ЧînF óz;Ï«tP]£5¢^ô!ô„‹Ññ¢'äAOă>µu)uÇ%–7ªˆþ“›œXÎD“ÍÏÁDqŠ:Í\÷ÌXÍþ€ZÞÞkŒÖyVIìÖu#ŽkW>%ëêOÜâ7î˜.R$£æ–‚Bõ9,õžÔFùØ 㻐¡®¿«Ä.u"Irÿ4y(ß¹Ʋz9=I=]EKHz§‚z, ©SM°~ç1ª˜V æKä:³ýX»qeÍvÕòÁìY5ê(À2uğ[—•£þÜêOîå=ŸH}v”xÕс%Åj'‹ÒoY䱫X9WŽôã-æÝt(Ú§®Í$oêºMÙ|,±µ'»òܞè&{nNOt/fÒl~P˜u[?8’M“7GùÒ6XÙ¡ê•7âD’Öö“=–ø%6ó‹©=Áµ'ÑöDÝú\ˇ©±¥ßú!6ðÁ“¬üÀžQNŸY¿€Xã°/knm[æY7^˜ë¯}³ë}¢i恡–I}ö:í±&{ž,–d¯ÕT¿ø[Ëõåy$ËZ-ÓùŸ’,!êKm¢†S—µüpʙ V²/õöž†³œ›ï=É⬟Á̬_œKR¬u€ºœY÷HÊŠÒ†|5ßwM{Â`¯'Yœöå¹¹Á#QCÕkŸšn‰WÞ¯eƒ—9ßþ~fß¶¿%ڐifÝ(šèý5YùáL—1¶Æ?XÙDŸCCÅe֟Êgšµ®T?󀌵¡>S­×þ™šÊgéPm'úÌLç{.ë¢@6 0AÍæÑalHAÀúeʞÐJñáN³—ì¹užýñpŸÛ¿š[ÒÓñe׺U>õ™×@³~IIBbÅcªIW²„j°ž’­RCÕe–“ ֍)¬¢£Zdމ¹™ìY¿ì' (YBŸhº™ Úç¥ZÇ`˙1V÷pæYûžhcµ®‘n²¶‘©ú’Å6X{©–±×‘친ŸDϓ•Möó“Qœ@X˜ @ 0AÍÃAe—(@ P€ (@ ä¢Ô\5ÆL P€ (@ P ˜ æá ²K (@ P€ rQ€ j.ŽcŠ(@ P€ (‡LPópPÙ% P€ (@ P€¹(À5G1S€ (@ P€ÈC&šy8šì(@ P€ (@\øu)¬jQ˪ ùtEXtapplication/vnd.excalidraw+json{"version":"1","encoding":"bstring","compressed":true,"encoded":"xœí›ËrâH\u0016†÷~\n‚Ù–éŒ_Œ\u001a\fø\u0002ØÆÆ7jª£B€\u0000µ…$KÂ\\*j×»YttÌÄlû5æ­Š\u001faR*\u0017\u0012Hš)·ÜÕ®¶ÂaC*•:™ú¿<'Ò\u001fv\n…¢?wôâ^¡šÏzšiô]mZ|\u0013”?è®gؖ:…Âïž=q{a͑ï;ÞÞwßEW”zöøÓUº©uË÷Tœšï…‡ð·:côƒkËï/%ã‹]Ä[õóN}VÝ­yíðÒ°Ògc\\œçkÖÐÔ£S3U\u000e1€Ë‚yP\u0000ØòûÔèû#U&!-Éø±¬1ҍáÈWUˆäËÂO·Ù+€e‰ç»ö^±MÛ\rlù\u001b\bÈ’®Ö»\u001bºöÄêGu\u0006Z\u0017\u0000\u001aÕ\u0019\u0018ŠÙöçaËjèÔ0\u0015×Ú¿y4\u0017®•oºJÝp8²tÏ[¹ÆvŽžá\u0007CA¢\u000e\u0004Æ9Çýð!|¿ÞüHsÇfŠa'b†ézð(\u0006\u0012qÉ£»DZ \\¬—žÚVš\u000b\u0002(\u0012\u0010IŒ¬`xU¥\u0007?lt ™ž\u001e\rapãÚºVâz‰if|k6±{vwríÍO\u001bþ åQ4XZœ¢\u001bÍuíiqyæã›¬v‡‹ýá%¹Á€«1×\u0016\u0017=vÖ\u001cçÐ.íƒãúâÒê\u001cñ‘{…ÖœYv¶k÷ñSôÐ&N_û4€\u0011L\u0000c€ ÀwbV¬\u0011Š\u001fºÖÝõ°ÖšµwË\u0007æÁþÀ1šÛ\u0013Fà*a\b&\tC””@ü`IÄ E9#FzL\u001f|UÄhnˆAA¡DHRžÂ\u0018\"t\u0013cjT©à\fJš7dÏ*Z¢l&$CŽn§7Ÿ\u0019]YéuïªóûëM†Ú\u0017ˆ\u0016É\u0015ђ˜›XŠ\u0016€J‰x\u0015éf‘BL˜À\u0012Љ\u0014ÊDéR€\\y\u000fÊ\u0011…y‹ô¹ò äç›?+ümȇ!ßš>ӎ3Œ0È~*hɇú[^kï 0I¹v3š:µ^ïyK'7Öê†ß|Óoþ­ƒ“Î :'ô¿ ?ÓÉ>0%+eI@àä„óÉ©òWeI™Ržùµv|‘òÕqRŠ|Ší§ æ6©›ö‚¶š_›÷ÏÈȂ·gA°a’„Cõ³ ÃÚ+æpãBt"ûšM.¿]wÌ~&äæàꪇ ŸÉ/õ²ð‚â þ.ˆÔ_ûA…NæÝ.„Cæ ÊüžŽÉ£2Щßr.åÇ(Ř̟©÷‹Zrž ŽTØVð™v¬ …åM€ikû]|Œ 1g΢VhLF©« l©[ÊVUm2ZÛP𹹝²¯¹B û9¶ÈkÙ× Sp:é œÌvš°™© î‚­W׍ùÚ*v=ëtÐëÍ×€yœôækO»ÞõrŒzOöœpŒÚ_o>Ní#íQ׋&œ t:8ÉoœôzW8»žÃÙÕ.nžps÷‚››Üœ|àáå//_žººþHˆ(?Ò^n (@ P€ €í0±s¡Z’­–ÔÔTÄÇÇ#)) çϟGrr²z/--  E»©öððP7\îîî7a.puv‚‹³ÎNèuùÐ#NȃΔ ˜r 3æÀÙÉ€n ]œõê·³úÑÃÙÙ zg=\äQ¯‡‹ú[ö+ø[¯/ø[o>ÆÙü»0Ì(ž5#怃lQàBУ…@æËü1*ü¹: æÑY£ü.'圂‘aêsõÚ£z]t_ó1F9ÎTt)G+Ï£Á`ü ¿;æ°É`„å•o0‡Šyyò“œ<rs󐝓œ\àä 'õ#!ŽÐ9ÃËË>Ÿ~€@‚ƒCàëoŸxûÖPŸÉKžQ€ (@ P€•#À@Šrœ‹Õ"7s²ÈÏéÓ§qæÌÄÅÅálb<²2Ó`2äÊ¿ÛÃß×~žðõ@€Ÿü}Üàë ?oWxy8ÁÝÅ7†Up Y%lZ '7Ù9Ðä!+;YYy8Ÿš‰äÔLœKÎP¯Ï§dšGFìÈ86“Þîž­ðºáTG…7òS£F ›î/G P€ (@{` Sg-ë4LÆÀ˜‹ìÌT$&& 11'ND!:&ñ gå9 yðuGX°/BCüP+ÄA5|àëãoÏ s•TDY&(@Œ¬\€¥g!%Íü“t. §ãS”ŠæÕÑ»úzo˜ô^ˆhØ !¡u$£k‚B@ P€ (@ P   dʀwÉ¡¹g‘õ/âNîCô©$‰J@ÂÙT5ˆ<ŠP',õƒQ'Þšáç—â“¶–gsX(@ÒÈ#Wç“3‘”œŽ€óHHJUÿMÓé= wÓBoԏl…š5k"44aaa*ÄáF P€ (@ X&À@Æ2§Ëî%óºÈcGQûWcÿÎÿ–ž¡æ›ðpwE£ˆ`4ªW!A>ôQ“ur£(`¯gÏ¥«p&þl*ÎÄ'#9-.î~jMÜQ¯~SÔªÓááá* áF P€ (@ \^€L)® `bbb°ÿ~ÄÆ²Ïù©hÖ( #BÔ£G2†(@GHMÏFlB² gNÇ%#3+Îj'\1®n²d·3òà…ˆ&P¿I'4hЀKp;æég¯(@ P€ ¬` s0Yýèøñã*„‘åš%„‘ùš7 A݀óôH·’›»S€š™9ˆ>„šSIj»» t.ÈÕ¡Q³Žhذ!j×®]=0ØK P€ (@ ” À@æ"”ŒŒ >|DBB‚šÆ××-[¶DýPgy$Ôqœ(@ X( «98™ˆc'‘œ’ 7Ÿš0ž„ÂÍ; 7F“&Màááaai܍ (@ P€Ž!À@Šà<ÊŒ0ÂìÝ»WÍu››‹Ö­[#²A-Ô©‘ d‡)7É1Î:{A P ŠdÕŠ£Qñj:œG0ôžµ‘–㪂™f͚q9í*:/¬– (@ P òª} sèÐ!8p±±±ÐétðööF‹-О®7ÎhÛØáþé@~/ P€°QôÌìÚƒcgòáÔé¹îjEŠ:ÀÅÅÅF[ÍfQ€ (@ PÀ2‡ dRRR°uëVÈêIzœô†$\ÓØ C9A¯e—÷¢(`IÉر7gÓÝàâ×9tìØQ­Ìč (@ P€ö*àŒ<šŽyóføzé‘zöÚ7ñAûЁözŽØn P€}: [÷DÃäÑ×Zê1ŠÎ;Ã×ח> (@ P€°;‡ dâãã±qãFdgg#?ý$‚\cqm›øûzÚ݉aƒ)@ P dûNbûáLø‡µBjF>ºvíŠf͚‘‹ (@ P€v%à0ŒÌ#«'yyy!óì~tjâŒÆ jÚÕÉ`c)@ PÀ2sÉØŽ+)ŠÚ0¹#,, ݺuƒ›››ep/ P€ (@ T±€Ý2ÉÉÉX·n²²²`ÈÏG k,:7wƒ§»kÓ²z P€šhYióÁøÔltèÑ£j×®]ÑÕ²| P€ (@ ”YÀ®™#GŽà¿ÿþC5ƒ®-ÜЬŽS™QX(@ ؏ÀÙóéX¿ã2õõ‘côTËc·iÓÆ~:À–R€ (@ TK» dd®˜“'Oª¥Ouù)èÖ$ Ÿ\µZ^Åì4(@·Çáx8yÕCœzõгgOºP€ (@ PÀfì.‘ {W¯^­&î5 ñÍG·È4›fÃ(@ P òŽDÅãßm§áØAµÑ»woxzrb÷Ê;¬‰ (@ PÀR» d±jÕ*õÿ\'%%ášf~hQ3ÉÒŸr? P€šIçÓ±zã!d8Ճ‡}ôéÓAAAÕ çì"(@ P€ €= ØM ¿ÿþ!!!*Œ¹Ÿ­jû¥Ú“5ÛJ P€•$—oÀê qú¬N~-qc¿þ¯€ÚY (@ P€ ®.`Ì¡C‡°~ýzÆde€âú–Ùð4\œw܃ ªµÀúmG±ÿH,r]`àÐûÔÜ2Ü(@ P€ (` 6ÈìÝ»»wŸLy©èÝ,înœŒ×.¶ €=lß{›w@ŸÎGŽCýúõí¡Ùl#(@ P€ €ƒ Øt ³k×.Èè™3ÆÅx7ŽÎ‡ÎÁO»G P€å/°ïði¬Þxƒƒî|M®-ÿJX"(@ P€ ¬°Ù@F˜ÇÃÃÃù'Ԝ1Ü(@ P€¥8x,þ·ù#†yu"•¶(G P€ (@2 Ød ³gÏ8p^^^ðÈދ^×–¹£,€ (pèxV®Þ “#þ5kÖ$ (@ P€ ªDÀ晃bǎjÎ×üSèÝÚ©J`X)(@ 8Š€Œ”YñÏxûú㎇ÞWÿ{Í (@ P€•-`SLTTV¯^­þÅÒɐ‚[ŠW¶ë£(@j sʬ\³áubØè‰pqádñÕàŽ³‹ (@ PÀŠl&IHHÀÒ¥KŽüü|ÜÜ"NNœÂ׊®6† € ìØw¯=€Ví»áæaO9PÏØ P€ (@{°‰@&33S…12l<-- :ááÄÑ1öp± ìY`ý¶cX»åzöœ]zßaÏ]aÛ)@ P€ ìLÀ&™å˗+¶øøx ì‚.±vÆÈæR€ €œ üŸf/¶ïÆQO¡Y›žöÚ ¶› (@ PÀΪ<Y¿~=’’’pþüy\ס.êzµ3B6— ìYÀ`0böâ 8yú<7Áaöܶ (@ PÀNª49tèd‰kœ^†µÐ2`°±™ (àHç’30cî„Ô¬‰±Ï}áH]c_(@ P€ lT Ê™sçÎaÑ¢E ¿¿?º7: 䞳Q&6‹ ]àøÉDÌZŽœztCï¡/8zwÙ? P€ (@*š²@F&ñÕétjE¥A=`Jç£JU|-°z P€Õ^`ÓÎãXŸjî¹g";Œšö (@ P€š8* d¶lق˜˜5wÌ š PwžâzȒ)@ P€VÌ^ާbÏáég_„gh'+Žä® (@ P€°\ Ò™3gÎ௿þ‚‡‡š5 BóÇ,o-÷€(@ T°@rj&>úòŽoUCF=W£ ®‘ÅS€ (@ TGJddÞÙ|}}лy獩ŽWûL PÀƍŬ…ëñÀœyí݀{š·˜Í£(@ P€°7J d¶mۆcǎ!++ ·÷…‡!ÆÞŒØ^ P€š&?.݌1‰÷ĝp »pö®&=g7)@ P€ *C ÒYUiñâÅðôôDû&>ˆ¬Wýc (@R €gäà©¿¢g—&žéŠ›¡ éWªrx(@ P€ JšŽ@æ?þ@rr2ŒŒèÓ"gƒ (`ó;öžÄœ%ñÒ#ýÜô6è<ëÛ|›Ù@ P€ (@ûš”@æøñãX·n²³21Œ§7|ܲìC‡­€(@j/0mÖ?psuÆØ1÷BÜ»Ú{€ (@ P |*%ùù矑““ƒæuuhS'³|ZÎR(@ P€• —˜‚w?_ÇîëÆ]\ü+¡VVA P€ (àèÈìÝ»;v쀇s.†t`29º)ûG P€&ðÓo[q"æ,^xéèüÚ9XïØ P€ (@ªšÐ@Æh4bÞŒyÈËËCÏVΈÊ©Š>²N P€ @™2³rñÊû‹p×ðŸèxóž2•Ń)@ P€ ( ÈÈȘ]»v¡Š_úµÓQœ (`·+×ìÃÆíÇðƀϠó¬g·ý`Ã)@ P€ lC Â™üü|̙3¹ÙiØÉ 5œl£Çl(@ P F“ /œ·· ŒÝž8ûÚ}Ø P€ (@ªš@Æd2aÖ¬YHO>…=œQÃß«êzȚ)@ P€å(ð€Ÿ1dØ]èrÃÝåX*‹¢(@ P€šnÈÈÊJk×®EӐóž®}pu3e)@ PÀþøw6í‰ÃëüàÀœd×(@ P€ *Z B™  .jFÞŠÀŽŽ©è“Èò)@ P òdèÓçcì£/ U‡+¯bÖD P€ (àPåȜ8q¿-ý MB’ЧK€Ca±3 (@XžbbÎêñÌkS B P€ (@R ”{ ³bÅ Þ±ÃnŒ@h°_©Ń(@ P€¶,•‡ÇÆÿ€w?ù5ÃÚrSÙ6 P€ (@(×@æÜ¹søîˏÐ8$ z·¶Ñ.³Y (@² |9÷_x7ÃÝŸTöÂX(@ P€ @µ(×@fãúµXÿç·Ø+ ëq2ßjw5±Ã ª‘À‘šL™¹ÓŸû­õš]¥(@ P€(/r dŠ}øÜ ñ=¢{yµåP€ lV`Â'KqÃ-÷⺇ÚlÙ0 P€ (@Û(·@æøÁÍX8ë\ßµ)Ú·¬g›œe«(@ P€å(ðûš}Øy4/œ9£KeQ (@ P€ÕA Ü™•ó'aû¶-xìÞ>ðör«vì#(@ TsŒ|þ÷ò\ŒÿÙ׬[Í5Ø} P€ (@kÊ%ÉJ܉Þ{íZÕÅÍ=[YS?÷¥(@ صÀ”ïþFÆ1ô®'íºl<(@ P€ @å ”=1æaߚ)øeÅz ¿¥ÔådŸ•{ Y(@ T¥À–]'ð˪#xçÓUÙ ÖM P€ (`ged²Nã§ïßBÔ©³xvl?;ë>›K P€(»À£¯ÍŋãßGœÈkË^K (@ P€šed2ã6àý÷ÞÅõ]š¢GÇÈjÆNR€ Š LŸ³¡‘ñÀxÂP€ (@ PÀ"22Ö} —aôðõ·šRîD P€p$­{¢°ø÷ݘ4å'À‰Û;Ò¹e_(@ P€ @E ”-1åcáWO#êdž~àÆŠj#Ë¥(@ ØŒÀC/ÏÆÄ7ßGXÃN6ßV6 (@ P êÊÈ3OcÂË£Wç&ê‡(@ P º LþæO4jÚ·Þõbu%`¿)@ P€ ¬(S œw%Ÿúr*ٵìš–»R€ KàŸõ±q×IŒòî€NïXco(@ P€ Ê] LÌß ßÃÚuðÚ·”{ÃX (@ PÀžRÓ³ñÌÄñŗßÃÍ¿‘=5m¥(@ P€šÒ2&#&O…:µü1ž_û*h:«€(@ ؖÀk-Á AƒqmŸ1¶Õ0¶† (@ PÀæJÈ€=Š·_{÷ ï†ÆõkÚ\ÇØ P€ @e ÌYŒ£3îvFeWÍú(@ P€ ìL ÔÌ¡mKðÍW3ðړáåájgÝfs)@ P€å/°sßIüŽ|+Þùð+è<ÂË¿–H P€ (à0¥d÷¢£Žâ‰ûû8 ;B P€(‹@Nn>}.>y|êðËbÉc)@ P€ €£ ”:™ôâPŽkQ}{4wt#ö (`±À„O~ÁÍ}: Ë­¯[| w€(@ P€š~¥ d2ғ1þéxìŸÞšXýÔØc P€ Àef-Ú€{y p£(@ P€ J(U sâèLy÷IL7®®Î€¥(@ P @`ãöcøýß}˜0þEèjt¥ (@ P€ Ê/YñëBìÛ0όíKV P€ Š€€eaÜ€Ÿ0íÝÇàZw8m(@ P€ (P~ÌgŸŸ‡Úî'q[¿vd¥(@ Pà"§'þˆÇᅪzŒH P€ (@ ”_ óü3àޛCÑ<²Y¯"cpATJMèõnpr’Y.l9¹yHI9”sñõ7¡eCoèuFšR€ € |ôÕhÝ4ýîxpñ·óÞ°ù (@ P€!`õ2çϟÇë¯<‹7n?Šh“C•™™ïŽýI ¡wv…“““ê›^¯‡N§ƒÑhDzz:öïߏM7``¥{MèLyvcpÛSѹ]Œôh»i3J P ¢~^Ÿ çS2ðГψŠ®ŽåS€ (@ Ø¡€ÕÌž={0û»ix÷‰vØÝÊorVŸ;Ž€FÂ`2O~,AŒ‡‡‡ e$1™LkõêÕ8}*î‹ÆÁ)€)¿ò[ŠõõǪ‘R{þx£Gó P€Ž)°uw–ýœ 'Ÿ _[Çì${E P€ (P&«™¥K—"êÈ<6Ž^™*®.K s4­1ô.ž…#c$„ÑFȈƒÁ`ÀÁƒ±uëVôë×][ùÃ5s/`#e$©€è ïW—SZéýüþ§ux{êopÖ;áÅGúãî!].yü­ÒÅ )@+ $%gà•÷á‹Éã¡éC- P€ (@ \"`u 3mÚ4Ô4a`gwrZ Ì±ô&ÈÍשG–$ˆ‘@F~d“ß2Z&66Û·oG—.]pMû¶Ðg„WÞAÙÂZ¬ß%7/G£p:î<Î%gšv èÝ^žnV&LH b·~lÕqÜÙ2}‡Ï u¿×‹íÔl}Ÿ-4‡m (@ P€°1«™—_~ÃŽAëð4ëŠm6G dŽG–Ž F hä±%Ùä±¥}ûö¡qãÆhߟ=`2ÂÇx ®9Õë²nÀì܃Í;OàŸ ±ä÷—Ù n0¯~[…3–nÈÈqGÖŒcé!6±ŸÁ`DŸÁ7Wó£dœÍ[² ¿®ÚÙŸŒ^ožKȒíƒ+ñâ» Õ(€±w^‡güŽŽŒlÜÔ«%~þâxžW](³mO4&~º SÞ‰zၖt§RöQçµÑCª®Ïß…‡îêYêzK{ÞJ]a9h«ç¥ºfwELøäÜrC{tÈG:íîä±Á (@ P ¬ drssñä“OâíqÃà¯;^ ͳÿ*² j„LŸQ_l„ŒÖ3- IMMő#Gàëë‹ÈÈHõÛÕE_œ€·1ªTsÊȍ©<î"#~ý{×%˜2²¥IƒPÔ®U'O'aÝÖ£È>2.Îz‹à%ÔpmôZ7­+ŠâžZF£©Ò»Yµîü¶IÉé8w>g⓱ÿï7­  ®Ö¯Ë}>øÁiXúçNüóãóž®SãË£=ΊíðÄë?`Ú¬UXòÕcxCœŠ=ÁNÅöœ'‹…2WÚvZsÜԙ«ðä„ðÆ3·áÕÇo±æÐ Ý÷÷5{ÑÿŸOU³>ƒ»u.u}–œ·#QñˆŒšfݞ IDATYê:J{àåŸC¶z^JÛO{>î‹Ù«VÓCFOœ9R˞Ï%ÛN P€ *BÀª@&..'NÄŽ·î†)u_EŽÇáʔ@æxFS5©¯Œ†Ñ[’ŽÊMŽö^ffŠ dŽ;†ŒŒ<žººÂÅÅþ>èÑÚ-ê­)#AÌ ±S M}ŒÜ1ì–p}k\ßµé%«d¥ŠgÃ×ÛòGѲsòàÕôôž6«Œ³øÜÉ lÿ{?EÝZ5°ìÛ'àéájñ±¥Ù1+;OL˜‡o篜äðæ?ë:^> )M}%#«QI(öócðMí/ÙE,eŸÝbðïÏ/ÞàkÀÖ__C»uÕqé™9èïd Ý> ’S2/9®ŒÚ}¥r&ó'ž}k¿¯&¿~GeTiQ#Ÿ—oUûþöݓ*ž*ívµóv>%AmŸÄ²oGÿë[—¶«{ýã_ðÖg¿–x=Ùêy±º“p€ŒDŒKLÁÃÏŸ‡ùûˍ (@ P€š€UÌæÍ›±|ùrŒþXo˜ÒSÑ dNd6S#d$€‘@FæŒÑæ‘)ÈH³sçN€€€š’eDRNNŒ<ÝñäškÐYª§êÛ³ŽG'ªùˆ|ŒÝ•sŸnͬ-²ÌûŸAVZªŒÀÎèØ P€ (P-¬ d–,Y‚3gÎàáaM`Ê8Q-€ÊÚI d¢²š2ÎÎæ‘2²I8£…48|ø0öïßŽŽŽÂÉóóóU0sݵÙ·6ô:ë–ÃÖnÜdYjYžº<7¹ùn÷d’Ù§šçì°t“ ßýŽÛ÷DãØïVØ(™ï¬Å/ÌTÍZ³àt¿¶‘z={ÑÜ÷ì·êõ©M",ÄÏÒŠ[ޟL*+ó¿Ä%€@^_n“ÇÆ~ûþ)ŽoYWÝ`>ëÈ£UsЌUaÑ w}„ÖŒäŠ[Ê{còR5‡ËŠ™Oᇥ›‹gQ#­ÜIþ¥ÿ…I q*öö9ƒ„€’ç‘’‘Xœ6cFô°²†²ï®(ÒJÚýûhÑØòëÞÚóÖŽa(|š?Z)Á^QytMMúåqëµ8q2ÉŠÏKÙϬ}–sæ>üêwLù`{ÏVS€ (@ \MÀª@fúôé Áàn^0eÅ\­l~@™èìê‘%mžm2_mò\ù;==ǏÇ¡C‡Ôk nÜÝÝáãã£]ª쉟ítðt5Xåª2ÿ+ºU…\fçèÓIhÐýEŒÑ_œ{o±œdþš5açþ“šVý{·†·…+8ÉÈy¬ÉÕÅujÕPË=—fËË7 Q—p*î<æM‹;“x. ¡×<£þ^¿øetj[¿Ä*dŠôÃÕÕ=;5Aí°€bûÉdÉï}±ë·Só»DÔ ÂàŸí°è÷íXñϞKʔàEÚqMËzhÙ4\Ö)iKNÍÄúmG1qò2ԔtþdŸÓñÉêѯËm2°ŽCÚÖŠyôì܀ԞŸ|ý'ž{{Á%UIšôà=qm›ŽhŽˆÚ——çjž¥9ÏÚ1‹Vnǰ‡¿P«~ÉcjÒw™#HæI²t8æ3,_µÛâó&ßiçZœô»<¢v,:~žšUÓ¿ÄæŽKÆûÓW`ëî(ÈuY?cFt¿däQi΋„k2R­ïu-.©_F_É÷O®Qk& ¶Ôž:헙‹gߜßz ^õ‡U§®³¯ (@ P€XÈŒù曞á†й~LÙqÏ]Ž@ÆÕÝG=ª$[ÑUŒŽ&++ ‰‰‰ˆW#b$„ñôô„¿¿?ŒœœaÈMGcÿcðtɵ U dŽÉd%(9x4;öÄ®1êF]‚I/ …Ÿ¯}u.‚jx㜗n¿äÆ]nÔrrólM¢-É,B}ôêðÂvIP3HæC9xªð=y¬åïžC£ˆË¶_nÖߘŒLý«¿ÜLË&7×£GôÀ#w_ðВo\/Wà‚_·`äã_âÚÖê ‹·ÑϧŠ­¿Ž¿€l¹a~åƒÅù8Šn¯=1žŸµð­QO}~ÙtIّ!8“‚[úŽAÿë[bö¢økí~LçnŒyÝUÏáÛSÃø–îwÏЮèÓ­)š4 ƒ”íïëyÕ2Vo8ˆAc§ZÊrŸpú#—ŒH:t<ß-X§¥’Çpä±*9¯Eç’‰„Ü7­›ÕÁm7¶Å±“‰ÊG& Œ®ŽYêyÕN]f¹Žåñ<¹n~ùú15zHÚ{蟷 ¯9™w%&ö&<}Û%!–|/NÄ$býÖcj¢b -=o²Ò˜Œ JÞûYaë2³ra4™. !ÿÝt§,S£žŽMF®ýﮞê:×V͒ïZ×Áïàð‰øKz,«F}ðò°Â%êKs^þ÷òl|õÿêýîJðS¯Ë85ú酇oÆ;㆔ö”ðžÇ_Ÿ‡—»á×>E P€ (@ °*yê©§ ?u]w¹I€Ž@@™“9-¡Ó›'ËÕS’PF c䵄0òؒÌ#)Ixãáá¡FÉȊKy9隥ß7§, jœ°‹ÈÈ cp O±9GŽœä³¥ß>ŽôŒl mŸ©ŒÛöñ%£7†=òþüw?ÎîúT…52?‚Ü4Ê ;²ÒŽlrÃÛ}È»jTŠlr³)·È6jpÌüxŽz-7г®ÇÓôU7¡²‰6¯‹|.m’Ñ1Ú±ÌüúݓžŠU=‹û/åI¹Ÿœq'¹çz‹“›ÒaO/\™J&@6Mj.Ùþó–štw햣è9ü=õÞœ·K`Ò é9˜»d£špWúpfËG*àй‘~flßÛ"£:Ÿ˜ýnœ±-$Ôê;êã˶YWj»%‰Ém#\ 玑Šè(iÌ+#?ÚÊKò¹››› e$œÉÏMGšn;\u™Vµ¿èäŸÚr3? OÜÜ«%Ú6¯‹úu‚ÔÔ~ù;^˜ôs‰_HXàÝìUÄÑ'©cäQžÞ#?Ä»/ÅóÝ€>»nØ{êÆXêXðÅÃjn m?¹áü÷'ó„«ò¯óò¯ôÚÍqdϗ Ã"™“FB/O7Ä&€šG‚>ûþouœÌ7#ÄX²ÉÜ12‡ŒŒÔ¯ø ø•Ž×V°‘@EB ™w®{IÐÚüÈ«s0cîÕGY­I;§rÿøwŸ!$#dqmå›ñOTޖŽIøÔªï녣$DõÔWêѹyoݬ¶Zž\FDh›-rñqÚÁb>ë“”™6Ù«Ô/íM£{žþFœ~ìÞÞxøîëÕè‘Þw| •’Ñ<2ª§€M¥étÛÛj¢bíŒ–ŽŸ¥ž–œÓ’öyæÍùøôÛ¿Ô<<2‰¯»› ®øŠrŠÙøz$Gæ†é6dÒe¯!- žx™lKˌ(‘$çè ŒûùrHµM®!ùŸdåä"¢ë…Ɇßùv<ó@_uÍÈHµqïü¬FPI€)KÈ7ëýªú>Èh, dŽMŸ‡‹VnSE?>~ž -e~š¢›%çEksâŽÉÅ7$sÓÈõ&{ɵ˭lýZ7­ŸCŸr3.€„Uê«ÑEÓ&,–ÇĶ/ÀoUŸ¬Š5gÑ èÓZ‘ãkwzN}VŽgâ“Q§óó…mÜûçD4kvI›µCγœï’6k<-:©íôãÒÍžëIóhYé+ÀßKMýÒ{ Õš¹–God®–þ÷}ª‚ÂØ­ÅGÉü?=nW•œþýbóYrÞ$<‘ÑG2òéã¯þPåüoT/,Z±M]3ŸªFjq+»€< èåéŠ÷<oé—`/{KX(@ P€ €­ XÈìÛ·sæÌÁ€I“`<90æÙZ_l²=ȜÎkƒ<ƒyE%m•%y-[Ñ F{¯è£LÆÈH™œ¬”22ÌyæªË¿3õ7Èðú‹—±–‘2â@¶¢ËDÿ¶j7nó™šoæ¹ûA{ÜAF$íúôŠ‚jaŽ6ÿˆÈ\.ÜÐæj±&9sVj‘Mn–ežœ«M,7ÔÏ¿ózun¢nvµGŠ€ 8Ÿxgú_o^ŸVF¥Èç–ÜŒN›¹ OLø¡Øœrl×Á“0çÓÔ#(Ú2ââw~ÏumX2Bãâãä1¥qµÕ¯ŽGk$<˜öæ]ªOríÝ÷ìw˜³xCá÷IFIHvñ&óužåM5ªC¥!ÁBó>¯aÈMíÕua§µ_`Ôîæâ£C..CÄïÜ WgÈ(±=œùÃÂùWdrçÞw|Xxž³¡æTÒ6KÎ[ÑÑ]rܲoW׈Œ4‘'rnåºöjj6,)dÉÉÍGDWóÜ-ËŸ}GOQûÆoûDÍéTÒv¹Ô,9/ÚcVÚdÑRÿ ±SUÀXKÁ[{®íyÿ%¿ï@ÂÙT<ô¿‡  ìnÏ]aÛ)@ P€ ÊYÀâ@f͚5Øžq#^xᣟ.çf8nqZ ãìê¥n°µ9dŠŽŽ‘ÞksÊ•÷\]]Õg¹Y©2n.õ™ŸÿOÍcp¥­èür3-s_ÈãFÚòÐÚ±2y©ÜØjŒ„2ÒE±›SÙFÞÖ _Œ=JíWÒ¶mO4:ÞúVህ;›Ÿ~ۊû‡wǗ“î)üÿø³©*”xúJµï†%¯XüȒÔ+ÁœϘ—·–É}edÂÀÚ 7Ï æ»9ŸœðЀ‰_µe“ÿœó zuiе[ŽšÉ‹kû⊞-‹M†«Ýˆ[2׆¶Œ€‘›sÙ>úêwõšÊ” #ñ蜜Õ{2A¬l‡W¿ƒ†õ‚±ôϝ6]mâÜ¢ÇmÜq¬ð1$ñô˜Ÿ—Œ8’:Ÿÿiƌû^݀ϝò ²²s1aòÒÂIŠ¿¯Oá£b¿6OŽŸ¡Ø©”•zÂ;>§Î± ió i!Ž5žÖüW@&!–€¥èÒÛ2š©{ÇHވ¬…oæ¯U!‹¶º–¬Z% Éš ªÞzn0Î$$ãî'¿.œÃEê_œ`œòÐ6KΛnÈ1Ÿ¿5 2é®lڈ'ñ‰ßþ j¶ZÕ_ôz‘ÿ:¯B@YÝIF²ÍxçžÂ‘fE'%ŸØç¶ŠªyŽŸÿh4îÒ¥ðcK΋¶š”„Œòý• °µåÙ- ­9WÕ}_™{jË®xþÉ{ázáñ³êîÂþS€ (@ 2‹/FBBzp4ŒÑ3ig¡€2gòÛB cސE]’9c®¶É>Z lÚd\íbŸkÿŠnéê>òQщGµÂŠ>‚!óÊcM2WŒŒl):BB›HWŽ“Ñ!7·W7ž-›ÖF«&áj~ÙŽÇbä†0zƒy‚Q¹Á–MF5H™;÷,ŒY–²Ö.|-›„[ÕÙyù?»ñä„KœÐX+,ußT5jB›KäÍgáåÇ\±.mKV£Ñ‹QAÖ÷Oª›u=!7èÚ$ÁR™òh“Ñj7õEKjTÑãdRX™lX›kF $‰5ŽS#dd+:wŒÌ #%[^v ›¬d$<8 שˆM“cQ xcÛbó³ÈÍäê æ¡úë·Ã?ëªê%‘‰fՒ¿yùÈÎɇ¯wñÇšäØŽôl5âB–Œ®ˆMš’æ“‘9Pz }W­0$Û=Ce9ëŠðpwU!Îoï.üì¯yÏbÏÁS*0ºÜ£YEÛ^tE# ºÆÞq]‰£$Ð&â•ã%ø’ÕuŽ‘)—óžø8Ùït\2Vo<šBšu[Žš‘Ñòø—ˆÅéžój¹åËyËã]©iÙjB袛œÿënO…¶Iž!Ïhó°Xã©Ígr¥ó-׌¬–tÿ°îjâ܋'֎ÕF¶ŒôhõxRY¶«79?¢=gEëûyùVtœŠ‘ZíIÛä\Écs²luI×áÞC§±içqŒÑãŠM?{.œÄ9f®v^..TB9éçÒoÇ€Þæ9’ž•€<.÷â» ÕjeN¡ý÷âß¡ò©…¥P€ (@ Ø£€ÅÌĉѯ_?tjׯ3‹í±¯UÒæl£'N嵃§—šÐ·èfÉÈmÿŒÜ,„˜6ÃéUҏ²V*}•pÀÏ×âð¢¬õ•åx¹¹~äÕ¹Å&¶œžo¥ióÕ΋VffV.|š?ªŸ— ;>)6©qiêå1ÅdÂdY¢ü³‰wÂ=ì:è|š“ˆ (@ P€JÀâ@fÜžq3f šDøÁû+ù,È5º!!¯>ô.îÐ;é-<ªønF“:SjèŽÀE—Sª2xõŽÆbÙ_»ÔÜ32£~ õøH§v J|LÆúª×ôŽÍó­-nÍòð¶ÙÛmՃ/·¯ ‡_®Ðù··Ý†²e (@ P€•*`q ó裏büøññͅ)þ÷Jm$+£(@Šè3òCÈJ@›—ŸŠkZÕ«˜Jªy©²äý‹ߌðŠ} ókWÍ5Ø} P€ (@MÀâ@fôèÑøüóÏáfˆ…)ño R€ € ‹NTKlËäÙVœeçœ±Ýæ›ô3ÆÞэۀί­í6”-£(@ P€šT‹™œœ<ôÐCøþûïaJ? ÓÙ+µ‘¬Œ Ê_àÍ)Ë0ᓥÿä@ŒþÔ­å_KTã?Z‚¡ý¯AÛ®C ókC P€ (@ (‹™³gÏâÕW_ÅôéÓaJÝÓ¹ ä£(@;š×eœZ‚{Ù·£ÿõ\]©¢Nç[ŸýŠ»7GçÞ#ÈT2Ë¥(@ P€v(`Q  Yöú“O>)e'Lç·ÚaWÙd P€(*Ь÷«8|";WN@«&áÄ© НDǶ Ыÿ(è||U3‹¥(@ P€v'`Q ³ÿ~̞=“&MRaŒ„2Ü(@ PÀŸæ/یƒÇâ ËžËJbÜ*F`ò7¡ydú  o«Š©„¥R€ (@ ؝€EÌ¶mÛ°lÙ2L˜0A=®$-q£(@ PàêÓfýƒzµ1ðö¡ómyõž(@ P€ @µ°(Y·nÖ¬Yƒ—_~2¡¯Lìˍ (@« |9ï_„ù`ð3¹:÷ (@ P€ÕFÀ¢@fÕªUØŸ};ž{î9µäµ)ãDµbG)@ P€eøvþZøúx`ؚǠómQ–¢x,(@ P€ € XȬ\¹‡ÆO<Süï0eÅ8»B P€š8™?¯‡»» îž÷Iè|šW\E,™ (@ PÀ®, d–.]ŠÓ§Oãᇆ)îW˜²ã쪓l,(@ P ªf/Úgg=îŒÿ)2UuX/(@ P€°A‹™E‹!)) cǎ…ñÌb 7É»Â&Q€ lO`î⍀5æYè|šÙ^Ù" P€ (@*°(™?>233qÿý÷Ãxz—Z%e¥ (@{˜·dŒ&î~à9è|šÚ[óÙ^ P€ (@ °(™7oòóóqÏ=÷À30dVPsX,(@ PÀ±æ.Ù˜€QcŸ‡Î»‰cuŽœ¡(@ P€(µ€EÌœ9sT£F‚ñäLÀ˜Wê y (@ P : ÌYŒ:ydé2Õ錳¯ (@ Pàj2:wÝuŒQ__­L~N P€ @€Lê«wrÂ]*iL P€ (@ (‹™Y³fA¯×ã®»î„1êÒQ€ (`¡€ZeIï„;njƒÎ;Ò£ž(@ P€ €£ XÈ8;;ãÎ;ï€1ê[G7aÿ(@ P€å&0kázžº:cäýÈ4*·rY(@ P€ €} XÈžžž`ä#`Œf cß§œ­§(@Ê˜¹p=Ü]qÇèqÐy1©L{ÖE P€ lYÀ¢@fæÌ™puuÅÈ;†Ãý-÷‡m«b˜g8é'@ýÖÁtáÕ>>ÓöÓUqûY=(@òøþçõðpwÁ2BÆ«ayÏò(@ P€ ìTÀÊ@fŒÑßÛiWÙìÊ؟éŠåçœËT•¬FbtLæß2ّöú¢ §è~æãŠ@Úßáö™„>z-,ºè³båmÃÅm*Rö%íÕö…I­¬R¬/W8®Lh<˜°YïZOOWŒžïèŒØl;Ù0 P€ (@Ê°(ùþûïáááÇÀ=³r[ÈÚªÀ_#Ê IDAT\Àh4á\r:bR‘”ª^ŸOÉDZz6R3r–•‡Œìš‹2·É(ÁŒ® /ÞŽó`þ]ʙŸc3‡o…Á˜“9T*ø‘÷õzsp§s.IøfÞj aíoœ$ŸIP"Ç©÷ôz$şEXíõ¹”é\ðŸ”#¯³³ràççUð™ìã€VÃq–}õNðtw…««ÎrŒjùš6搛›‡¬ì\€fæ %=çS³œš‰ä” €€ÈïtUŸ|_|àÿÚaª_·6õEßìrûþ² ÛøvÁZøz»c˜Œñ¬oۍeë(@ P€ *MÀâ@ÆËË ÃoÄ@ŠÒNMùV”kÒ!%ß )œú}<.G¢ÎâàáÄDÇá\ÜYuS-‹oH üC‚ÿšò 7OòmP9–fxÌA6*C6DŸoEÔߌÖÂõ· M öÓB‘‹Ã‚`ܕhaJñ׺VðyáE‚Ÿ‚—Z8$»˜GÙŒ¢Ñ~Žž)2ÌCz. –ŽÑ9%[,€ºÂ~EFi£}ŽÑC…m+µ£6’FHž£w1ˆ’CTާ׮‹ÊÏÍùØx$ŽCÒ©8œ‹M@r\" ‚Ãk¢GóPÜÞ¹6ZD†«ˆ›c |3-ü}=pûœÈD8f'Ù+ P€ (@«, dŸýö[x{{cøí·Áxr¶Õ•ð€ÊXŸæQÀ€œp*.çÎÄ#æÀQÄ;‰üŒ<5J!žNB"j#ŽA]ø…ÂÕÝœòË)PÍRÎ"æà1Ä>³Ñ§à¯ËA÷–µÐœC$:·o/~é’øúÇÿàçUÈÔs€®±/ (@ P€e°(ùæ›oàëë‹aCÂxrNªã¡-›ëŒµiˆÎvAâÉ38{ò4Nì>ˆ¬Žt5š!0< µ›5DHœÚjô 7 P ê£OãÌ®=H?|N™éhÓŒ6úõl…NmùxK՟²·@™þ^zŒa SvQ–@ P€ CÀâ@ÆÏÏ·cÌ\Çè¹öbkº;LGüñ“ˆÚ}y¹yjܰÈÔnÚÁukÙô£GxJØ% X-w ç·nÁñ]ûáåᆟ׵ÀM=[ªznö)ðÕÿ"š††H ãQ×>;ÁVS€ (@ ”»€EÌ×_ 2åÎ_>žÎ0bÎæ8lÚƒ”³IjB\Ÿ ÔmÞ¡ ë2„)f–BJ0e"gßNì_» gϧ£W—&Ô·Bƒý*µ¬¬ì_Îû!A>|÷‹ÐyÔ){, (@ PÀ!¬ dúÃ3Ï!:î8—œù›NañÆ(8靑›:Í!ŒqÔšUÓºÈ>P Ú Ôt͇ˉØúÇ:œIHFŸîÍ0ôŠkÔÛÜìC`ÆŒ5 òS ¶+–®Åù” Ü;Ž+úõlé€=uŒ.͘»a!~4ЁŒã]öˆ (@ ”^Àâ@&00Cní ã©K_,“@ŸÁˆ5ᗍ'ã\ÙéoÒ@…1îޜ_¢Lž<˜ö  :xfâÜŠXŽb+êÖªîèuƒí¡õÕ¶Óç¬Fxhn“@Æ=ŒÚ:°ã (@ P€Å, dŸüòKcðÀ`<5Ÿ†U °ëÀ)ü±öŽ˜|Ÿž¿àhжŒkøWAkX%(P•.DdÆbý²pèx,†ßÒ·ôi]•MbÝWøbÎjÔ À­wœž×¢(@ P€ ”¿ÒÒ³±òߜ؟ƒý¹žÈËÎF£­Q3‚CÚø©có(Pá=r‘»k3–.݀ká£zÁÏÇ£ÂëeÖ |>ûÔ ÄÀ;e„ ëôž7(@ P€p\‹™3f $$ƒöñÔÇÕ°±ží;|¿ý³Qa8s.Áuj¡qÇ6Ð99ÙXKÙ P ªœt@ä(ü;ÿW˜L&<;¶ê× ªªæ°Þ>ŸõêՖ@FFȄш (@ P€JÀ¢@fúôé Ãmý{Áxú'ÒU‚Àßë`û¡Xì҇"5ñšvœ!õ8÷@%г Ø¥€On:Ž-[†3ÇbðÂÃ7¡US®æc+'rÚÌUš_7·Œ”@&ÔVšÅvP€ (@ T±€•LOOÿ\ÅMvìê #­ÜŽÜŒ|ü‘ì…|“Í»_ 7O>†àØgžœ£@ùœZ¹ñ»÷àéÑ}бMýò)”¥”I`êÌUhX/FŸ žÕ,SY<˜ (@ PÀq, dŸøâ ÔªU ·õ¿ÆÓ §÷6֓ôŒl,øm+ŒœÜ±.6Y5j¡q§¶6ÖJ6‡°u=ý‡ÄÍ1~L/tnßÐ֛ëðíûìû¿Y¿&úßñ‡?Ûì (@ P€°\Àâ@&<<·Þ܃Œå¶V활š‰–nFH ì8™ŒÔmP·Ec«ÊàΠ4Ý«Ö#}Óxíá~h×¢.aªP`Êw£q dd„LH¶„US€ (@ ؒ€EÌ矎:uê``¿n0žYdKíwˆ¶ÈJJsoDH ŸˆGr«îná}c'(@ª8»úoD­ßŒ·žŒF ªêLLùö/4i†›GH \UÍ`œ (@ P€6&`Q 3mÚ4Ô«W·ôíã™Å6ÖûnN~Ÿ3®‡—;ŽD%À»SwäÕâŒö}VÙz ؎€áÏ%8°ç>|e‚jxÛNêQK>ýö/4 C¿¯®\«zv• (@ \QÀÊ@Š3Œg–Žæÿº2‘ïÉÓçа[GDE–cé,Ššî­œr°þ»••ƒ÷^VÝ9ª€ÿ“¿ù -×B_!Ã@ŠJÎ+¥(@ P€¶(`q 7v„ñÌ/¶Ø»lÓ_k÷#&öùúOŽnŽ‡Ë™@Çì${E P€ (`µ€EÌÔ©SQ¿~} žáZc—Z] žT`ßáÓXµþ Ü\Ñ<²bŽGt¶ ©(@ ”»€Œ’i˜…çÞZ€çì‡n•{,ðòý'Ú4«‡I SƒT (@ P€P2Ÿ}ö6lˆþ}:0)‡ '-#Ó笆¿¯'BCüܱ3ÖŠz”CÉ,‚ @Éw‡€âß?7bÉÊøêœ{áéáJªJøø«?жy]Ü #d\*©VVC P€ (`ë25ÂÍœÛûÌÖûdóí[žb’Òàê¢G¿Á×cþY_˜øš’ÍŸ76ö, £dúúgà¥÷"Àß ãºÉž»cWmýã%hÙ$#|—Œ]96– (@ T¬€EÌ”)S‰›{·ƒ1ö׊m‘ƒ—.*-_œYYyx讞XƒpœÌá£J~ÚÙ= ؄€Œ’Ñ¥œÃèç¿ÇÏ܆kZÕ³‰v9z#>œñ;:މ@ï¡2BÆßÑ»ËþQ€ (@ X(`] s}[ã~³°hîV’Àԙ«™•‹^]š ¿As¬ç£JŒP(@JÐFÉ|ÿó:lÙuÓÞUI5Wïj>˜±Û6ÀõC$ñ«Þì=(@ P€ @¡€EÌ§Ÿ~ŠŠM›¢_ÏÖ dÊpñ¬Ýrÿn>ŒúµƒÐ»7ÌNð-Ci<” €õCÓÐÀ=÷>ó †ö¿·ÞÐÖúBx„UïO_‰Îí ×`2VÁqg P€ (àà2“'OF³fÍЯg+ã–;8IÅt/'7“Š-GNnž~ /vëC±3íb*c© .#àëlÄÐÀ4lþo'æ-݄ٟ<@« xï‹èÚ¡zJ ãÌ Ÿ‚¹Y<(@ P€°‹™æÍ›£ïu-`Œ[a7³¥†®Ùx­;€ë»4Eëk[`V¢ŒœÈזNÛBj#PÇ-CÓñèK3Ñ·g œùšjÓ÷ªèè€Ï—£GÇÆžn2>UÑÖI P€ (`ƒV27öhSüJì†m7É`4büG¿ÀÍÕ¯<6kÒœ±=Ýݶm­sƒõáwWèœtÅZœ—›‹óÉɈ;›ˆ\Ogž†À&`vpZÙÄJhé•Ý®M˜÷Ë&ÌüxL%ÕZ=«ygÚrôìÜ=n{pö®žì5(@ P€ À%2ü1Zµj…º7…)þw2Z)°y× Ì_ºÃoé€ÈV‘˜è‹í(@nŸY˜þúTŒÜžs«·§þ†ë»6E÷[e„ ™ŠQf© (@ PÀþ,dZ·nº5‘ŒÕgùÝÏW 3+Ÿ„5©žØ’ÆÑ1V#–p€2í]kÂU§WŸJãáá¡B dL&Ο?Õ«W#æÔ)\7| bÝr‘o4”Gõ,ƒŽ!°î/Äì?ŒO'Üáý±Á^Lød)zwmŠ^·¿èœl°…l(@ P€ @UXÈôéÖŠø?ª¢v[gTÌYŒ7}îÚÍÛDbV‚r8:Š\Χ2ÜBáåfa$‘F!#• åZx …íøã_X¿ wŒ²Òê¬è>Uuù1û`ûOKðߗœÜ·"ÎÅ“—b@ïÖè8à2Ì2)@ P€ € XÈ|øá‡êFöúÎ ÈXq¢‹Ã[ŸýŠ_†ãî¡XŸÊµ‚請z;¹ª2Îp*6BF;P hRSSqäÈøúú"22Rý–á@ZŠÅ#¯’&ú=ŒyŸyfâUûõÜŒÏ MZ9c.þ™œHãà‡Š]ÚÃÅÍ {Vo@úùžyz`܏Sá]Ãÿ’rÏ>õ —cËo«Š}ÖŸ_O {å±R‡Fƒ;ÿZ‹CwÀ˜oÀ™£Qhܱ n{ú«ö­Þ0äåãÿ³w`Qf]ÿ£ vw÷b¬íÚb€‰ŠÝ­kw‹Ýí®®~溫kwv`!e€€ Ò!]ó=çï8 È 3 çîãÃðΜçÞû»ïžŸÿ9Ñi("BÃĘg÷ wœðòÕ×»'[ÂÓÅíGöEÛ¡ñìÞýïÎoÛ¯žV±ž±°ãîð^\›Œw=JT)¯ö–<}ă»›ÝÛxcIšwj—ðøIí¶ö*8Ü·Æ 3ñKËÆ©=]бçß3A†ÿŠ·BNŠäŠ5–›Î k»:šO‚LC­ÙeCL€ 0&À˜`›€š‚L9ÈŒã۞±·Ÿº«1s?úvm€h3ž'Œ|è勰¯Á"l)wŒ(Yµ¢ðz¡öæÑs읱êքùŒ1(R¶d<†”è÷¯‰‹E.™‘›)Þ»Ÿï(®íùOüNó4îÞÞdwç1Î[+®[;՚ÖSëLB¿â±óàóñ“ðÖ1Þ_ŒAB5ڗɰÞjÙT·³,V†]“‹ð. ÕÊ_¢ü?y ±)G#ô[ 2Ú˶˜`L€ 0&Á š)Ȕ…ÌûVßòÏYŸÇ—L\ô/v®Ž3áÅ͹cŽMž™Æ¹J)}}}EÞg$‘&$$oߟ…œœ=Ÿ~ýªHþ-„™ƕ‘¿A5DÉR¯6yëXv,„ƒI{Ö á%¹öß²­x~Å ó& ŸYëïºÓþæ4ï%®¯²:Š,Y³ÂÖêþž¿N\°l:jµn*^' —JÌ«FÕõ(Qãw®Txë[¹Öo¡Pé˜yx[rfÔ~ŸŒq(±q¯ÿwž9ÊÆH$ŸaÈ“Ã-eöÏZ‰íKú¡U¥Œ)3À£%°pÃiô4­‡_;’ “)1&À˜`L€ 0A@%Afݺuš_¿>Z5, ™÷mF§c¬ñð™úM«ÀÔãPaI:ׅ™&F¥EȒTîZJæK‰}©ÑïÁÁÁpvvƛ7oÄkn²gώܹs‹Ð%Ã|F.›QYÔ¯ºDQ‘Ȗ=éŒÔçœõ+üoÚ2±&I:ŒáZ…Ê”@ƒÎmqïèy8>xö]^j›4C©ªP¬bYäʗ'9€ü~2.þù7LjÇŒ>¿2+-X°þ4zwª‡:(dÉ@‹–Ù`L€ 0&À˜@F& ² Ó Aެ_ 2dT9ðykO¢jňiÞ~QYUÂ}Ô$ 2yr‰P%j’C¯%‘&,, ÞÞÞðôô1$Âä̙ùò僑‘Ÿ†‡âE”ÂôÔ÷9³éxpâ&í]÷g†ÿg/<:sO^Vä!ï’æ}º€ÂC<Þ8!$ð+ŠV(³qƒPªÚ7¯ eZÙcŽ-æÜ•$m ³ цš$Ȑ· …cQu%je:n‚Œ}qóà š+Ȝڰ N]!PF÷·h^ƒì†øý¯Uß­•ª0‘ Dym”›É0 ŽÑW\¢°­í£çŠpš„­â¯¿ÀÝñ=ª5­/’?¿l…wO_¡Ç¬±hÔµšw wÿ×î®ïñÏân J‹¬;…Þ]È=}-ZfSL€ 0&À˜`™€J‚ÌܹsQ»vmôé\2«ŒŒßŸ¶öžcÿÄÀ ýà”?ùДŸ¶(›ˆ™Š¹Ë ‡†®™+Þ¿qà8®î>ŒN† Eß®*¯…;&OÀûã'ÜÛu÷÷ŽNŸ3÷P™Àüµ'Ñ·[#Ôn?Ÿ•©qG&À˜`L€ è>•™µk×¢aÆhY¿d>wtŸŠ†;tq÷ÅdËÃ0_9>ì£!Í€‡“ ó[ž²È–å[î`”œdh4åo¡?R¢_zßÐÐPˆ2$Î| Åm¿÷ø®öZ]_¿ÁŸãæ‰q”d¶IOSœ\»SxĐÈÒvH/4êÞï­mDè~¶l(R¶*þZ~ýA>~Ø?k•(ß å}¡&å‚Q".îèŠmxvé6Zè. S²cÛۏ+‹EœŽ­ÄR) ¹"OnÚ#@Ÿ‘#sVàôº~(]<¿ö grKó֜DóFšÕŽ”†Â€HÈ ü0tM¹‘WyçP›}ôOP(”*íS—ŠpŸQ[,Q©ž±*CDŸ¿/À‡W E•T"{UÏoŸ £*Yµ‚ð("1†ÚŒS»‘»`>Ìm!/Û=ÿôîd«$Yý{ÿ<(Ä®ö£ú©²î£‹›vaF§ª0k­úý¡†ùLÙuîšØ£ ŒMHáï™ò&àM3&À˜`L ê 2õŠAæ{A&C`͎Kx#ˇÝ:1«T$@‚Ló|å‘U&Q’ª,ÑkjÊBŒtM9”‰Äò” þª‘ óÕ/ëúNP䉡„µ£6/UTiŽŠÅ‰ñ˯ÿ+r±Íå]Gˆá «,Q¿­#f‰|+¿vh‰> '©2è³yÈ4|vr…º¡G/¯ßÃaËMÂFßE“Q·}‹dçŒsä,.l? ø†øÂÓÅ]1†BŒzÌ#Jo‡ai§aâœEö!WÞ'祜=zE!WzEÍÓå#þ=W”œ&¯"n)'p÷ÈYŽÎ†)#8?OÊ)Æ9{õq éõ~!Aò„ãܘ`L€ 0&À˜€š‚LQÈ|ï3µdŒ÷7r6m…uk3«T$ 2FÙs ñEÊ!£ìCÓK9e”—BײeË&Þ#™ë^Ž)òñuÿ‚œ3W|—Œ¶ûŽQ"TIòl!wG'4îÖúH # IDATÙâWYqzn‹]“ /òv‘ÚßóÖÂöÎcñëäœëQ¢JyPßÿ–oyUšÿ„Ý«“0”÷-…©â‰¢<Ž˜žX³OÏß—©ºQ£.&(W»Bƒàå JÞ[žL …WЁ¹k`÷‰ðÆ©X÷|°±‡§óGȇjë ቚ”À˜^Ï:ò –*öûæõíG8Ž`]Œ¯;‡ÏàÂÑmêH4íišŠwî›¶»û9­ñ§%‡ƒiëŽg¯:Ž¡œCͶ,Èh‹)ÛaL€ 0&À˜€.PIY³f 7nŒ¿aAF…Sï2r;êNœlè… ŠžË Ó" C‡$²PèåOI®QI¹áýAQaÉ QŒO¥¬o<ʑB­|íêè³`ˆ»GäՄ(܈„€ä¿E˕‚ù̱(]œ’š,ôôüM\Ù-Of›0Ê'Wl2M1'%Ó%ïÉö„]«Q€\)•×L¥u¬žuúê•ߍ‰Áœcp}ïQ…7PÂÉËÔ¬¢šŽ$…9uÕm†ôLrRrbê@yfª6þqÉe)oÈK³a|>~ÆÙÍ{Ě–äV wŒ\ÜápèoœÛÁ!—Úº%f­<†}›£zdž1&À˜`L€ 09•™&Mš yÝBù>`v? àã÷ý§îEû•K˜S*Ê!C¹aH”¡ÊI$ÈHÞ/RšÒ–"ŽQýZ¡* 2™ðà-3&À˜`L i* 2«W¯FÓŠMÑŒ 2ÉÝLÛÜÄ»¯@ió^Éuå÷5$CO¿ä*†ÙT÷†I8% 7‘1Ñx䁰Ø( WÄÓ"@yIìï?…Ÿ‡'ô²dBVé•PŠfÕ ZL:u ŒÚ{jEß® Sw¢L`=&6ó֜ÄH!ÈÌÉ;æ-2&À˜`L€ šJ@MA&?d~òª/Ü'°xãD)…B­¹d,ß#L€ dLÎ'£zn&m›17ŽV‹ùëNÉ™–³ÓÑÊx)L€ 0&À˜`iM@eAæ·ß~C³Zy!ó’ÖkN×óOZü/ò7h„Üu€ëuòâ˜`Iðºv¹ƒ<±pR†€!šè,\#XÑ$gL€ 0&À˜€îPSÉ™ÿSÝ£ Å ™¶»wEΊUŽh•M1&À~ÐÇwñÕÁëæ[üŒIutŠÈšhçäðŸ­Qµå,Ý%o‹ 0&À˜`L %ÔdrCæo’y2͘^cÿD­Ñ£³hÑL³gÞ(`ºE@f÷ÎV÷°cÅ@ÝÚXì&(8«þž€á}Û j˙i°ž’ 0&À˜`L œ`AFË'ÓqÈü6w&rä6Ò²e6ǘø9²»8Àúäìß0üçLšÃ³„…GaÙÖsB©Òb†Ƙ`L€ 0& .•™U«V¡Y³fhflYÀ3uçÈ4ý##£a6â˜,]À•c2Í©óF™€îÈë錛{âðöѺ·¹ŸŒ£ÐðH¬ØzÃúµF•æ,Èüdü<`L€ 0&ÀÒ5•™æÍ›ã·_rBð<]o(-Ncv¢ójKèéé¥åRxn&À˜@Š  ðÀ¹­ûpâ¯ñ)¶ÁåBÂ"°rûE #™æÓ `L€ 0&À˜PPIY¹r%Z¶l‰Š5³Cð‚ñ%AÀÛï+zM9€.«1#&À˜@†%P4Ô Ç×ìÀ™ÿM̰{H/ Àê?/bhŸ¶šÒ|ZzY¯ƒ 0&À˜`L PS1„,àe:Xvú\‚û—ôŸ{]—ÏOŸ äU1&ÀT P<Ò‡—nÃù}“TèÍ]~DàkH8Ö!œI™Ê°˜`L€ 0&À˜€‚€z‚L CÈYIêþqq÷ÅÀEÇÑ}Ù\ŸÅ˜`–@±h^ŒöOΰ{H/ §*KëÿºŒÁä!ӌ™ôr.Œ&À˜`L€ €j 2Ù |•֝.×àìæþ–§ÑkÙìt¹>^`L@E£pÄr 2ªÀJŠOà×0lØ}UxÈTn6E Ù`L€ 0&À˜€®PS1€,ÐFWö®õ} ÓgñôY>Kë¶Ù `Làg(€cK7áÂ>öÑ”y@P(6í¹†Á&šÜŒyjʓÇ3&À˜`L@—š,ÈŽjÕ Mªg…,ðµ.í_«{ùðÑݞƠ,Èh,cLà§Èê‹Ó«·ãÜNê«)xÿÀPlÙ{ ƒXÑ%gL€ 0&À˜€ÎPIY±bZ·n&Õ²@d«s޵!‡÷Ÿ1çœ3š÷î¢-“l‡ 0&ðÓ ä ðDģۘ:¢ÝOŸ[×&ô Á¶ý70™ß8I²®/ï‡ 0&À˜`š`AFz ƺ|ôA7öÑ"Q6Ř@ZÈè…+›þÂéÝ¿§Åô:5§¯0¶ž…œMP¹){éÔáòf˜`L€ 0& !5=Ȃì4œRw‡¿wñB¯¥ç1pÙ ÝÝ$ïŒ 0'+È W6ìÄéÿMÐùœŠö}ü‚ñçÁ›л=*7ež©Í›í3&À˜`L #PSdAöi?u­ŽN_Ðå%ô_:ý§Î˓1&ÀŽIÀ(È—6ü‰3ÿcM¹zû~ŎC·1Т*± £)NϘ`L€ 0" ’ 3þ|4mÚfóAöÕA§hs3¶o<0týuôµœªM³l‹ 0&ðS }õÆ¥õ;„‡ŒÞOY÷&óò Â_ÿÞÁ€^$Èp˜î0ïˆ 0&À˜`)' ’ ³|ùr˜˜˜ QåhÈŸ:Š|6ùÒÞ £·ÜFïESt|§Œ=&Àt™@®O\ÛºGÿ}ý¬ºŒÕTߛ§wÖ.ŠÍъעTŸ'`L€ 0&À˜È8XÑâYYÛžà÷÷`±€+ih+›bLà'Èá÷V;öáàŠÈnhð“g×­éŸxâGšÔdœnmŽwØ`L€ 0& •™e˖¡]»vhT9 ²¯o4šP—?zጩ{¡ç\NÜšËçÌ{cºNÀÐçîù»V †Q.C]ßnªîï³WöþwýzµgA&UI³q&À˜`L€ d<ê 2•"! ~›ñvù“V|ßúfކùlÎð“ó4L€ €/w<;x[—ôCŸ<9Sa†Ìcò“gö»Ÿ=ÉCflæÙ8ï” 0&À˜`L Yj 2¿KÖhfí°ïØ}l»äˆþËffVŒo&Àt€@Ö/nx}øÖÍ·@ÁüF:°£ŽÛ‚û<ñP.È4“v ᙙ`L€ 0&ÀÒ5™pȂߧ»M€—Ý~ô ŒB·™ü-hz9^`êÈòÉŽ'NaÙ s-”G}ó'tBÉbù3ðFÒ~énŸüðÏéGè׳#*° “öÂ+`L€ 0&À˜@:" ž S!²§tŽüôµ”[±˜™ôu(Œ&ÀÔ&àqç.Œ>ÀÊÙ=P¶dAµÇó€o\=|qøìôíA‚Ì(FØ`L€ 0&ÀTd–.]Š: a…ÈBœ_H±ŒrÀ›GÏàå‹zŠ­PµQÝdÏnÿìUpžoZmšbÀÒéÉö—:|vrÅæ!ÓP±ž1Fo±TywdL õ DŸwDÀ}+ŒîςŒŠŽ\œqòÒ3Xô0C…†Ã55Çã™`L€ 0&Àtˆ€J‚ yȘ™™¡~ÙÈB]uhûÚÝÊÍûŽXv2 ãëþ/®ÝÁӗìšRŽ\)L;Žå‡€Bƒ‚±ÄlˆèÓ s[ôš3^e 6·àŸ…„w̔UÇ™H}ïôð.FõkÁ2â~ïâ…ÓW^ÀÂÜ åÓÐgL€ 0&À˜Ð%j 2þ…ºéÒþµº—›°ü„-ÌŠÑªÝÔ0öÑþ®ì>ŒwO_)Ìåϋß,:A?›Š”)‰jMëýpjqNoÜ-úŽ`Óqãõ—ÅÊðÏ¢õÈWŽ0:M===ÅûN^™ÿKt\jì—m2& :ð7ö~r#û5G¥²²€:¹ï{Ÿûà‰3×^Ê™,Èh’Ç2&À˜`L@ך)ÈøAúQ×hm?7î;` 2ÓÓ¯ ãüÒþ8w‡÷Š}“—J‹þÝDؑŸJ<(ĉBŽ<]ÜEÿŽc¢õ@óxcÉûfmßßŵ©6¢˜R®˜Óvãá©Ëºv.ª7­¯ÒœÜ‰ 0ŸC ÌÑ!Ö0ªosTdAF#èž9áê[ ÔåëÕÈfL€ 0&À˜Ð-ê 2eü cA&©[@2'_ÃlZúÍ!³Š÷xø}ò[šÒšÚ î…rµªÅó^Qå§DŸç¶ìUtí1s ukoš”'†.^9 5[4RŒ¿®ßDø|ü„YGþ@ÁRÅT™’û0&ð“„8Ø"âù#Œèӌ ™¿qþ‚ 7lÐÓŒÊח‡xrcL€ 0&À˜`D@eAŠS§NšWÚ²0¹G·ï  ³ò€-LÓqÈÒßóÖÂöÎc±øB¥K ÇŒÑ"±®:Íÿ³V[ŒSØ a…òÇPåöâêY*ÏCÓyÂP4ïÛEŒ–rÏPˆÔ‚³{ÔƒÔY+÷eL@}Áv¯õò †÷ùõñÅáèôoœFÏî,Èhˆ’‡3&À˜`L@çš$ÈXZZ¢sçΚWÚ²0ƒ ­ ]µ²Ãê3v0KÇI}#BÃ@áBϯX)¶]ªz%Žìß ¿Žh„,Y³þGLt vO^,*2µèÛUô¿ýÏ)X̛€úf­ãýoÙVʼnŸ‹&£nû [‘ááXh2@ñ;%¶vžøýЂux}ûúYNE“fZãφ˜Ð ›—Ù=ÇP òaAFªöï>ንzšwF¹zƒ41Åc™`L€ 0&ÀtŒ€Ê‚L—.]ðkÉ/…Ö1ÚÛÎõûöX}Ê.C2ҮßÃúÂ-Ü=z^Ÿârç‰CÑŒ<ŒH¹ÙÝyŒƒó֊KRî—K; ™ËŠ£V멊îRYké‚aÎX|a?Hš±4•çQXxn/(l‰`鋀Ù Èâús7C…2,Èhr:vo?áê];ôìÞåêůD§‰]˘`L€ 0&ñ š$È,^Œ]»veA&™óŸ~Ï«OÛ£ãÔÑîΈŽŠÂ¹­ûðèÔ±öq;V œq5Å>Œ\=°aÀ$ñ{Ç1„͗÷®°ú÷4(y/ +õ;µéXù‡”«†„šã«þ…JØžžÎn8¿}?j4oˆ!«fg8NŒ`&Œ|Ž,Ž/…‡ 2šžÝ[\»ë€ÝÉC†Íhòh&À˜`L€ è•™nݺ¡n‰O…Ñ-ZÜ 2kÎØ¡Ã”ô²ôúÖCx¹y ‰yGäÌc”èÎwŒ›—׎è6m$šö0}ÂCB±mälQ)©F0$ÔP®˜šˆH,hÛOt]vý̓—Daɉ1$ÊpcL ýðþ úïl0€WSd4<Û7 „ïæä!óë·0N Íòp&À˜`L€ 0  Š ãYžŒd2·ï \»gµéXÙ8p2<]ÜA¹bv1A•Fu‘=gÄDGã«_ >ŒŽÃ̓'ÄÆFm±D¥zÆÂ³…ðŸ{úJ±aò†©P§&JT­7»·°¿û»w€ù ¹g]ûcÌ\‘$xÐÊYp~i‡¿&,RŒ'ñfх}Ð70àۈ 0tHÀï™5²9ÙbpÏ&,Èhx>¯Ýqó¡#Ì»wE¹ºý5ŽÆÃ™`L€ 0&Àt‰€z‚LqwÈ"ŒtiÿZÝ˵»vXwÖíÓ©‡ÌÝÿÎáü¶ýÉîÙdxoŽÞG”§Þ3}ÜÞ gÀ’éÈ[Ž ò)€°A՚šš%ùŽwž~ïèyþÔzPá5Cm×dK8={-^w;­š'»îÀ˜@Úðµ~Špkôèø+š7šœ6‹Ð‘YmÜqû¡#º›wC¹ºrÏAnL€ 0&À˜`L€š%ÈÔ)þˆðfrIžv×>NI¿9d>Ú¿Ãk«Gxÿԁޟ"ŒˆZv£œ(W«:šöè(~R;µa—È)C¡F£¶,Ž'ÄHšÂÒå¿þyœ,œzH\>¶r;¬/Þe®)„‰Z€§N®Û)l˜Ïœ,z|1&N ø<}‚œ®hޘ=d4<£Waõè-º d4ÄÉÙ`L€ 0& STd-Z„îÝ»ƒ™Ÿ=yȬ?kvéÔCFÝ;÷Ôú]ÐÓӃéøA0̑=Ñá!AØ2|ȑ‰»×ˆ>¬qå¯1tí<ä+ú͛FÝù¹?`iCÀûñc¹¿Á€îXÑð^ÚÄÝ'oÑœ[7”­ÛWCk<œ 0&À˜`L@—š,Ș››£N1WÈ"|tiÿZÝ 2Î:ÀdJúõÑê†ãŒÉbe€„xÍ 0ŒOÀóÑCäõx‡þ,Èh|˜/ìÜpïé;ñ¥FÙ:}4¶Ç˜`L€ 0&Àt‡€Z‚Lí¢.@€¯îì^Ë;¹zÇÏ;Àdrædތ‘Í1&ÆŸ<|€üŸ„ SŸ4{¹irÏmÝpߚMòX&À˜`L€ è*5™@€Ÿ®²Ðx_,ÈhŒ 0&|ŸœœÑ¯ 2šdz׮xøÜ ݺ‘‡LoMÍñx&À˜`L€ 0" ² Ó£GÔ*âDúëÐöµ»d6·GÛÉcŽk˜­1&À~"O÷î¡°ÏôíʂŒŠØIyôÜ ]»™£l MÍ¥Éø   £D‰i2?Oʘ`L€ 0]%À‚ŒOV.È8 -‡,i‘*›bLàgðž{Eý\ѧKCYÒŸµ ¿ü dj÷ÒÐZÚ 0`®_¿777ŠÍ"xV&À˜`L€ è •™… ¢W¯^0.ôˆ ÐA ÚÙҁ°ÿ–:͝¬ƒl… 0&œ¯^G±  êф ù?}õOm\Ѕ™ZS©]»6lll¬Y³jH„‡3&À˜`L€ HÔdÞQL/ WîØbËGŽ™ÄI}ù&aL ãøxÛ %‚ÜÑ»sd4<Æ'/?Àúµ ºvë‰2µzhhíûá$’,X°¹sçÆüùóµnŸ R=²O¡Kܘ`L€ 0&ÀŽG@%A†þ±gaaãBo€(þYRø¯Ü±Ã– öh3‰sÈhïՎ¥ý³W¡LÍ*h3ž§v ²• CÀêß3øðʃWÎBþv_¥s“™> WYR‰YR¿tÆó×nèÒ­Gª27n܀‰‰ Š)OOÏ$׺téRn4cÆ µŒ\|||PžpaÔªU ¯^œÒˆfL€ 0&À˜ˆO@%AfΜ9èÒ¥ š”ó`Aæw\q`™tø)›Ý¬'Š–+…i‡¶€ÃÕñ’R“À¡ëðúö#,:¿¹òåIÍ©tƶBéÒåJqÙkMöÑ gŒŽsCgò16×ÄT¢c»wïŽ3gÎ`öìÙXœzu’öÉ˅š••ZŽh¡ò:¬­­Ñ A 4TywdL€ 0&À˜Hž€J‚ŒÂCŠ #ý5y«™ŽÇ+;lœ`Ö\e)ÝÝ$Èä-RóNîJwkã¥.¿ç­…íÇ˜}l /’º“éˆudŽwTòú•ýGtîÖ eŒ»kÏ0[[[ ›ŸŸŸ(P @’ö+V¬gggœ?:uRyǎCïÞœ…ØC¢7&À˜`L€ 0íPSq¢ƒµ7»ŽY‚ÌE{Žæ¥tw²$Èåϋ…çöŠ»µñ‚R—À¹k`÷ fَB¥Š§îd:bíäÃgNxå@‚ŒÊwӞa䜺fÍL:7nLÒ6•¬Š0Ô>|ˆÆ«ŒŽ•+WŠÜ4gϞž²iÝ"""ð믿¢I“&øßÿþ—ÖËáù™`L€ 0& 5{ :D£ uy0•œŠ2,È€¿S&AŠ@‰¢˜}ôÏô·8^QªØ7k%<ÃŒS»‘·pÒ©ºˆ fœ£OïaÚÊÍTÊ`«O_Ë}ðì=^;z SWdºjuq$J©¢”§‹»x=pùL·R=gDª.4 ŒK÷Ě{'Ò`öŒ9% 2ŃÜ1°{c”fAF£CŒûäœ>¡S×>(]³³F¶”‡‡‡#GŽâåˆÉ•+W¢¶§M›†M›6‰÷<<(<éܹsèÚµ«š9sŠ~(Êl'ÖH$9t萰‘X EΜ9UÙZ¢}Ž9‚~ýú‰÷(¡ñªU«Ô¶EùvÈ;ÈÜÜ'OžT{<`L€ 0&À˜€6 š)ÈŒb"Ž9¿NÙºùÀëOŸD›©ãuj_ªn†Â@ٚUPŽBèé}Ë墪m÷óÿâÕœÆ¢Aç¶è5çÛÙÜ:t ·žÀüÓ»a˜SþM³6ZXp ³ý0<&*ý[(BB;ÉÍEyy¢"#-{ö$QŸ°¯ÁșW^ÍågŽØ˜x¹ž‹Ü0TÖ<±¶²Çhq9©’ç~Ÿ<áôÂúúšP·f’v³M÷:ÝóÞŸ(^©*Ö­™dÞbäã<…ò§û\6n7å‚̐^MQ² 2šÜËVßâ­sê2$ЈBmǎB,!¯i¶lÙ"ŒXš‘PB" œgmm (¶$åŸ!¡†ò~‘Jc¯[·³fÍRü~ïÞ=4oÞ\1–{ _œ\E²^*_Ýž{•K{~øˆƒŠ yŸ.蟝\±ôÚ?0Ì_PQu®3›þ‡'.aÒÞu(Y¥BŒ5§Gg®âáÉËâü-/‰3šœ™*÷†¯ûY¶tÔÊWC‡ÑýP¡î/ñÖ·šý@!jM;Ž%ÞuÊ-tù¯p÷¿sñ®› ³@»}“ýÈ:=·Å9«xϓèöìÒ-Ü?zAœÔè³Ñšk;Ež£Ä&KȀöY x?èŠf#AŠhàG ³ø %ŠŠþ|©¹—޶mõè Þ¹xÁ”}ú#£ä“tSHՕ+W`hhˆ°°0±š—BŸh¿TF»`Á‚šX±¢x~”Y«‡ÇƘ`L€ 0&@MAæÅà’ @߄®þÏm§OÈTŒÈÓäòNy8 %*•ƒÍ­âw‹¹¿£~§6ˆ ǝÃgñ[/3èeɂÝS–ˆ\/#7/FåúµÄƒñ­¿OŠDŽ3þ݆¬úYÅxO—Ø5q±N”Í3pùŒDÃp^^¿‡\ùò»ÔÜìßáÑsÐvšڏüöAž%*—ÇÐ5sŠ_ßzˆC ×w~Õ«Þó' E¹‘pBb Ù µ^Úñ-,ŠÍàžè0º?^ÝžoD‹Ÿ]Q³e#P’Y©•ª^ w¯Qüè퇝¿/ymP«Õº)>œwÏÇOBˆZpf¢‚=àS8µ9Çw ¯7Û7 E…:5‘¿Xañžä%Ógá$üÚ¡eŠæ’*‘ʔ}„L°_€8·§n ›äíCbFÕ&¿ªuf)¹7ˆÏšÞ‰{¢I÷œŽQ*y^Šf!I-&*/X‡ûÖâ Z²ØX8¿' ydû¿wÖ6øß”% {t?Ò)ßót–‡¬SFô…Qø””ë§±yt›2Bi$x•¯SCô9ŸúO<=í†÷ÉðÞñÂÏŠڌ¢åŸ¯†óÝM«Áכ·P4À#úü†âEXÑ%n?|'7/tì¢}A†Öåçç‡ åÖ¡C!Œ˜˜˜Ä»Þ«W/œ8ñ-ŸyŒÐXò”éÑ£‡È%C՗LMMÑŸ}{\»vM\+\ž°m¢jL¿ýöÈ[&a£µžA”x—ÆÒZ6nÜ(j­[·ÆíÛ·…àC¡RʍòÊùóÏ?—'L˜€mÛ¶AJèKû]¶l™JÇBâyçšÒÈ£hðàÁªtÕjŸ˜˜dÍ*ÿ^ZµÀÀ@á9ŽhÑ¢tQÞ<­8ðŒL€ 0&À~6dŽHüΓwXuø)ÚÎÈ<‚Œòƒi·i#ÑŽ‡© z`îØß}‚fœ;£Ë€a  @Ž›‡nSG"&:ç·ÉDÒ'=äÓšÔ†¯Ÿª$^ÐÃ+yPßÂeJàö¡ÓžýÏ)!þL?Žù;¯„Î/lñ×ÄÅ07-tWÌC^2Ê!U/®ÜÔH8jlÞù‹ÂΉ‹„xD =fÅOØL ­…*8}xå Æ’ÈBý¥ªNo=ÇÞ+â=Œ“—‰Ç[gÑùÃBL¡õì¿@T¢‡òá O¡ „œ[†Ë¿Ñ^xn¯fšI"‰,…˔ĕÝÿ*öF∔3…D‡ý³W‰œjêÎ%%O”&=MqríNq64WÛ!œÐš{{Px˜ºg–’{ƒîeϖ~–SñéÝXýsZìo֑?P°T1ð2¯uqÿŒØ°PÁGªÆEk§û­\­êB4\c1^ˆƒWÍFÍ$ªSQ葥éa‹Xô]4ù‹Áõ}GqmÏ åÕõ{ø×RžL•æŽr– É{ÈñÑ3œÝŒWo”÷§ë”˜ÓŒ—(UÞzpO‘H²O¡f›‡~Ë}Ôj 9LÇÔâß\ߛ’ 21²Os+’t9åT]„Ž?sõ\Ü}ѫ!ÿû15}Š¿|ù">ÛE‹Mò_*cM^#$ÎH¹d€5µiÓF„‘÷‰$€]²ùßÿ ¯˜*UªÀÖÖVT`Rn›7oÆÔ©S…÷ åx!!…„ÊÕBž1Ô?~/ùo’Ý;v-Ô(ŽÊÑÑQ¬‘**ÑzšÑµªU«ª„qèСŠÐ-åŽOúCB‰HùóçëÒ$Ǎ* ¢ó!RöòåK‘4Ù××”|9±<@ªØÔFŸ»wï¢E‹ °0KKKm˜dL€ 0&À˜€ Ôdž±Ñ*˜Íœ]îY¿ÃŠCOÐvŠ<Š_×…Ї†T͇„•ÒÕ*‰‡rIll¥‡n”C7聖jôÐJøäUBÞ%d›úÒ+ 9Ôè³›MQÌI9a(7Œr[Öežxš^}çžð&‘‘îÓF¡IŽ‰ËW_,ï&ŸcÀ²éÂ3……­èþ-÷ÊôC[P€œŒÊµã«þPxˆÐï$ztÝ_<°Ó^(êåµ»øoÙVÅÚóš-–âyMÚ³%«VDBïv(DÅæŠÜۈ*')‡Ýl8YpžQòô q‡Â€DŸ ¶gÚÒxydԝ‹lÛÝyŒƒóÖÆãGóõ·œª‰Rrf)¹7þ7u)Þ=}%Ö¢ìùtxÉfÁ»ŸYkX̛ š°EçIçJÂŽVõ£Ø {%«V€Ó³× O¬y§v#oáÄË=?»|G—oB¢ä-DÆ(‡Òó+VšÞŽŸðNzÿì5vO–?Ø$š&å6¢÷—ß<Œmú‰³$ï.ÉCŠ<ÆHÀ€AÒ9óÑ[R÷ÉöäYð÷À¬qŠ(V8O¢ŸŸš›àòÑ„‡Lê 2ª­ȓ'8È+ƒB‘(O %K–ž+”FªÞÔ°aCE9aHŒ<`h. •"o3H,±²²R)$萚B^.ºD^*âï;;àâî.¯Gú'N¬Ý'g¯ÇÛ¿ºsÑ<_ý°®ïź(îšÍ‹J$€äÌÔœ7ÈK‰æ¡ùš)—õ–Ä')LòfQ.y~çÈY\Ø~@$ð ñTˆ{d‹D–3Æ|—«G™óýÇ@6‰UíRîG…zIçðŸ§·å>+ný‡ù­û$ù÷yøP(‰ƒŽÆ€kë/ò)âï†Ñý[¢h!d4áJÕ÷Ü<|ÑŸK_”®žž ¬‰}uƉ):DâHrmçΝ7nœÈÛBÞ4Ô.\ž –€2ÙÊ6(/ =Гx£œp˜“— Ù¡Fž/$ŽP'Z ‰>ä™Bsќ”˜:}WvÉÃršj %$Z€Ñ{ÞE2` Ï¡0ZêulI¡.&ÈCM(¡ëü6ò|2ݧ†A6[õ‡˜»Ÿå4DGDâêž#ÂۂÚoœ:áþñ â5…`Q(µuý&ŠÜ!äe1eßz…0tïèyœÛºO!öøCITñxㄭ#f oeæ¶ì-ú,¿.ß#…ƒ‘èPšL Tªg/ŒŠÄ" q‘qšæ‹EÙ‡rËP…)jR(y6©3¥º{g®PäI‘æ%¯# U"ÊÇýsŠÎLÝ{ƒòÍoý-‰vc¶/ž%wŸÁ…?*Œ‰$A†<³ÈcˆšNG^Jëþ‚6öðtþ(’åVk\÷»$Ôt–VžlI’§ÚÖé÷ÁhÞ§«"¯òŸ>›ËÅÙ©7¡X…2âuLt \mqbÍNÁ“ŒÁšT¹òyÒ=yzÃ.џÉû֋€Ò’÷Ý#I%ËV^CJ_»Þž…Âþn;°ŠüyU³RºÞô<îú={|üä‡ö]ú¡tõiºÔϟ?‹$º”ÓåòåË*­…SÓç[¹‘×ʃ„‡”˜Ä˜úõë+ú’x@^4RB_i<•ߊJI”+†ÂuHØ!aâÔ©SèÖ­›HžK‚I£FàããƒÉ“'ãßå'’(B‚%)–ªK©Ž ¥NzEs’šQŸ|ùï†_œzUðIªÑ>É»ŠP¡BjMœpáB,_Ÿ\&4GõêÕÅxâDeÈ©I‰’ׯ_/òúÐS҈;y)‘7”ª2ïß¿>ŒRŠêxîǘ`L€ €Œ€Ê‚ ¹Ùþ’ך™p~ü‹öÝG»Ù“Svl””3C• å‡î¡kçŠò¿”ƒ„ŠßµZQþYò|Xeu ›‡Lçœ áé1s ukªr³kÒbq™«ŽZxòò칋ös2Güµ»£“"ù(å}¡à„ÿŒ @€—¯ššD¶”€–ªý B^$ô@*%©¥ÛâÅÕ;8µ~æÚ…@o_^ŒI‘s†•Γ†£JÃڊ;HJXK€\3”L˜Œ ŠØ(dI€ œ!”W†ôZjŠC!TTUŠ’ºiô‡<*|=Ÿ`˰Š÷VÌQ²Z!ÀxŒq†ÝÝ'Šd¯kî ÿYžA˜Š°§Ê 뀪7‘€D‚Ðk«‡pzf+֒@!±¡þêÌEý)' å‹!oŸäZJΌX©zo°F¹T(̘mKÅrH@É¢¯/„š„6;¿ŽG¥úÆâž ï"òÈ¡ŒAÔꙶB¥úµ`-›(]îðà™â=òüqw|»{OQ³Y4ìÚ.žyºWœŸÛâ£Ã{žØ8(Œfè&ì^ýí>Ž•!$ ÐÓ¡U‰}èÌd²Øïª†ýèó‘ÜY€ô}düÜ0qHdA&¥Åž«wìðÙ+&$ÈT‹ÿhd8ƒé³I9dHððððáKé­Q]<È»†ª*µlÙ2Þç…òºP` g¢„Âê4))±² óþý{T®\Y䜡P€>}úàèÑ£"Ù1• OØNŸ> sssño"òþQ¥IeŸ)ñ1%N¬ÑÚTñL¡y JsþÈ£ŸÞ“öõ#æ±q÷!ý ;RxCЃ ±q·(õ/é=rô—‰—ÂkšzÒ}™%+U÷“Ñ‹ë+·Y,Y“O@?åSÊK³Ä*ÏE×äöå]ä^ú4§|]òÉåsÈï%ñžè'Ÿƒlӗš~þþ(V¢8š±Pxáëeý'"ô„g8ý”~×ӓ li\Üïò®Yäýé:(¢‚V#¬)®‹±Ž/©ŸX£| ÒG>nûqtä§M…"«,ù³Å Ÿ¡ô³ê‰Ï 哣j…iÙTd,zɓúrK’ÀK{7ÌÜ~æOgJLà§ ¿Díî>Æ¥ÿ|W‰A‰a©BP‘2%Q€\)Ô1i&³ŒÜ(¯ íkéÕCyéví$ÈðqÁŽQí‘/OÚþO*ÝBRqa—n¿†_0ژ‘‡LÚ 2*.[g»?^x¹P#/SSS‘“EùaƒB‹,--qûöíxŠ)"ÊoSuDòÌ¡ÛRE) uRUÌQ^€ÞJ×(…^i£QhyÆ$¬°DoÞŒ“““«[·nšÿ£UûeßPBhªŸFI¡?|øÊ3E‰éœÂIL ‡}%Iš Ÿ,ދ IDATŠ)z,ÏIò‡!ùÃUÜÃWÜuñè$®€÷œ˜¢ŸxžRê+VŠäȑáaaŠ~âV‘.ï x)žØâ]’?Æ]’Ö£Ü?nRzà”ŒÒC'Yͪo€˜èè$oùÃaÜìŽñ ø!O>©ä|Ü2}}DGE‰> ‰(î…øÏ RŸž‡Èø‹‰{h–ö,ž@õKaßä•÷0.ždeˆŒ‡avùƒ·X€üáUúÐCœxøÿ}{Ozj×庀âI^Èq ƒ|+ßD€oŊ§þo…Ò8*º ҕÅ$ùz£##‘•2‰‘ŽÅ|q{R°*·œJðâ®I ÓBwîQâ¡=66ZÎRé°$Ciyߝ›œÒœwÞò;†ÞŠ;Ž÷ë·÷¿¿íä#ã„ñA‘‹òŠdHé³J6¿}€âM$͑`éßö¢tÊMÈGDE„A?¥ ø&)^+D( b"ç"úH÷t€ Î.±ŒµqgùmYÊŠoBŽIéÈ0æ0BVƒlÐ ‘+G6äΑ ¹ õÅÏ eK¡\™R(^Œž("@•V™üþ”ŽsEeAÆÂ¢'ŒóÊópKœ€ƒ;Šmœ†Ž Xá{$mP>òö ð€<… áE•Œ/i³Ú”ϺuøL‘¯eüŽ•(k¬o‰SŸÝI‚L¯˜:¢ à€ŸšœðÅ[¯áëO‚ yÈŽÑďÕJLÿH“ŸQNÊ,};Kª”s‡þqF’ˁ–”- ‹"ñ‡l‘°³dÉP(=ä’ðA¶“û†N¹DvJ¿qNl}”̘B €o†é!}ߟ}"$‹K Jd”"Bƒ„Ð Jëà¿Ï®0Ì"C^£șMÙõbñkíšhøk-T«V-U² £EŒ¯ßx`êæ+èžàûD€Zœ†M1LO@*AÞ SQv ž\¿|>®˜5ºòäΡ]ã™Ìڅ›6ð dZg²Ýóv• ž1aœ9s&Q0%yï$ց”ªW¯.|ýû÷×VÈ…­—yîlÛ¶MؖS^ªŒ€Ü(ŒŠ’“C=$ ‘˜£ÚDýI”±³³Ë|‡”NvLçD%â/_Ÿ,„±~ýú‰`î„N0Êù}uˆ”¬æ© úŒß‰˜ØXd3W±‹ˆB@`( ³é qŠbÙ"bŸzÆeâ 69±ð¹ë¯̂LJ,µlÙ+V¬Àȑ#µ‚çêÕ«â–3gÎÄÚµk…MÊB¹n=z$Êa'lƒÆßÿ-[¶cÈkç?þb %&¯J|ŒhÑ"áùÓŽiS­¬—$O€D¶­[·ŠÜ/tŸÔ©Scàè%Ä©êKò–ž`L€ (pµ·†×‹+(_À@xŠvíÚU+€ÔdºÃ8ßK­Lª«FÞ8}Áž5ç`¶˜]=cÞÈ HÉëõó'vYèµÕ<}‚àæá·OŸŠŸ®~pv󆛇/""£‘Ç(ôõ³À@?«øŒKô³fAéP©\”+ç]S² ÊÅyØȗK[KÔº³×^âkHDœ‡LK­ÛgƒL@ZÔ«W/ôíÛäC­sçΞpáÌÍÍE)l©,å˜!¯ ª4ErátëÖMŒ&;=zôP,… ‹¡ŸT±jñâŚ,“ǪH€„2 QêÓ§H8{ã-„—€€+©hš»1&À˜€_||v†.hÑŽaŒÿ÷¥‚L7ç{•Òy2Åžw<1få˜YÎÉûåM2& ›ޜ¿„<^.X6Ã9µ(È$G+(8\3®îŸpÿâ·OrñÆÙÕ®ŸøâˆŒ¹sŠ5eÑÓCdt ‚C…ْÅò£bÙšT¶Š̃j•Š)Œl ÐNyàä֟Øûg®œDHhZv€%dRǀ +úå—_DbWª(EÊ}S©QHyÁPÙn©QžRǎÅ8ºN!J .DŊñòåKìܹS䓡fmmj‰SLƳŒ~ýzÁzêŒ90(QCxÃx‡p2ތw’Œb&À2;«³ˆt} ‹.íDè®&MuAŠgWç·Ñd.ûÞÅ £–ŸB§%su~¯ŒA&Àt—•œ6úì„ÅSº"Gvƒt³Q s’‹4~ø(yÚ|òƒ“«7>|ôÆ'Ï@ªrˆìÙ DTLL,BÂ"+C‰¢ù„wMµŠÅ¹k€œ6E åIµ=žŸúaáQhс™©6f)%@ž1”sdРA $ԐšrñâE8;;‹ë$ºPšI“&‰òÈÔȓ†| k¢²Ê’ˆãëë›hyìŽÚ‹.λcÇÜŸ÷õ†­aN#]Ü"ï‰ 0&n 8\އ(WXºt©ÕMISCéãü¯S2GŠC‚Ìø5çÐvÎ4è%ñ—Lƒ7ʘ@†%àzó²|‹å3̅§‰.µššy›8OÊiãìæ…wŒÄ5/ß drç΁˜˜‘džÆ.˜[‘ÇŠz¥â(W² ÊÄU*U,’ˆN]~.l47ŒÒ•›éJÞ H”%^°`† ‚ýû÷3¥T$pýúulÞŒ&¬Glž”=€âòØ4`L@ç D„ãíÉÕš\¶fÏNYY•™ùóç£WÎš]Kþè®úðÑׇ™å\èéééü ÈdL@7 žÝŒl®ŽX9»‡ð$ÉlÍË'WîØ!WNCáaCbû[gOžxøà‹W BÂ"‘#{6dÍ¢'̈šhÌo„’Eó¡B™ÂšQ¹„H@L!Qï?#oîìh֑™ÌveÖý¶hÑB”ÅŠp'SSÓ̊!Õ÷%ÊY×7„ÕÚ€ú|<`L€ $N gà;<8º ŠK՗Ôm* 2ôM‡EÎ0.`«®ýLÕ߅Ëã0]‚LŠ:xÞ,Ð1n·nÃÀÅ«çôՎžÅ'%„ɈÄx‡÷ŸðÁÍŸ<à댬úYa Ÿ‘‘1ˆŠŽAŸŒy`˜=êׯªU«ŠDªe˖ʕ+—d8³g‰UU¢²ÙTÛÇÇÙ²i¯J[Fâð3ÖJ%ǝ>û£z/“ÿŒy&À˜ÀøÝ?ÿo±uëVµA©!Èt‚qöùaw_¹ ³x6‡,©}+ò&ÀÒ ·­ÅÉëæõ‚> 2):Qâû“Žž z¥Wvo\ooo„‡‡‹‡UÊÍA¯óæÍ‹¢E‹¢L™2šR¥ ŒQ¹re…hc`±rù€ÊpîÝ»'BûZ¶”W»téÌÌÌÄ·„œÌ7õŽóÓ§O0`/ڍ â©7[fL€ 0•d ñÁƒý 1iÂïhÒ€‰Jc€N,Èš…ëǝ©,ë°EÇÐÑrÛ©E®lŠ 0ŸKÀÝêðÎôFÖ¬‰'òü¹+Êž³»h ™ ø­ý”®üíÐ$ž¹¹‰?®®®°±±ÁÛ·oÅï”5 Y³fᯑ‘‘022B¡B…D™a*-\³fMÔªU ±±±¢D±¡¡aƅÄ+ϐîß¿fÍäy‘®]»QiÛ¶m°²²….qKTâ:($ …ÛOÉɹ1&À˜@Úpœ±YƒÜ@Œê453°WÇvŠëëF‚Ìâcÿgï, ¢êº0üŠ€`'˜Xšˆ (X(`b¶`¢¢"‚-vw‹­ØÝ~6v`‹]Hš *‚ý¯}øï8 1È3°ÏZ.•9÷Ü}žsñûîËÞï†Í˜Ðà—˜twþŒa&VŒ>sº/`°\²”ÄCÝvàªX¡F AF‘ee¢Í͛7ñàÁ<þ Áׯ_¡££#2lè÷ܹs‹vÄŋ‡‘‘LLLD¶ •DeΜY‘[ò& 07nÀÌÌĻ¥qãÆaèСâïäo¢©™þü§†—ĉ͚5Co·‰xœ¡xWâ˙`L@YB^ÂwóD̙> %J”PxYÅ™v0Îs_á…ÓãDJOï6zlLJFFö]HÏï™ €þgÎâ烛˜;¶44Ø <)gJ%KİzÃn(\Ò")Kýuí—/_pæÌ‘IC6÷îÝÓ'Oàïï/Ê¢Èσ2lš,ŠJžræÌ‰ ˆ2(©,ÊÔÔT6ôB̓ $–€···0–•={öÄʕ+»ÏWe#mÞŒíÝãþÛï ^ÅӘ`L %_>öV&èÙ£»Â·K„ c ã<^8=N$“Çnc¶ÂfŽ4Øw!=>Œg&&Œ9{ßïùbþøÜ1.‰'ºeßdÌH‚Lw.Y-‰«%þrʲyõê(ÃæÎ;xôè‘ø;•E………‰r(mHÔ!3Ö|ùò¡páÂ(Y²€(‹"±ŠFȕ+îÖމŠ¯HKnߟ-|c^¿~ ===\»vM”ÖñH&L@Þ|z€©Ÿÿâr¥ä¡Ì«2&ÀþÀ]ŸCŸq»7)þƒ‰D260Îã÷o‘¥“«^„¢ëè-h8ÚMtØàÁ˜PGoΝ÷»ŸX0¡#8?&i'èœï²(ûªÞ  RAI(zɈ^ªIŽñóó“•E…††ŠÒm444„MžŒo& î¢™ëXäÙIÝ·’êñoÞs ™2iÁš2dÔSI"™ ßœ{W”ªÐïRYTpp°(‹¢ÏiP'(jïMeQÔޛʢ(³ÆÜܶ¶¶ ݆?géžÀùóç±|ùrTï·‘?ž\)Ý? € 0•$pjË"üúñc<ÜPY_;Á!È4€qÞG .˜ž'Œ ú€.#œa=ÊšZZéï 05&pÞ‘7¯cÑDd’zŒ›v_‚Ž 2”!cžÔåÔöúgϞáʕ+Â|˜Ê¢šÕ7ùÛP·šˆˆÑŸ›Œ‡¥öÞúúúÑÊ¢(ˆ 8 =6Ãz€+4µ9C&¹yóúL€ $À çá{3d”€wãî‹È¬› Õ(CưŠVLŸKO yØHeQ?Ý¢š,êãǏ²²(‘ICÝ~š[T©R¥ ­­Ö­[ ñ†Zó`êJ`âĉÐÌ®Ý*Ñ[«ë~8n&À˜@Z$ðãÛW¬ÝíÜæ£K­b(’Si‚L]ç{š™)mOÁap‚Ì0hj'\/ŠŽóBL€ 0%ºp_nR† —,%ëAŠ +'u9Ÿ>TòDeQ”eCeQ>”•EQ jíM^6R·(ò®‘ºE•+WNt‹"ñ†Dj΃ š"‘#G"_1#d(¯˜Q€*îcbL€ €ëÇõDàÜ¢&в “rGþðY zß†cÜ •‰™Äæ{{æ¬D·È©ÇíSÎç2exzäŸÜœ‰5³z({ét·ÞAŠ' ÍÒÝþUiÔQ#u‹zðà¬,ŠêE¢Íϟ?!•EQ·(*ƒ*[¶,ŒE† 6Ôú›H nnn0(c†_e¥ÆíùžL€ 0&  s\Q¶j}xôjb¹âoö“ˆ’%ΐIˆàۏèìŸ õ<†± “¬ŸŸßy{f¯D—)n(o™6;‘$ Og©F€3d”‡~㮋Ȝ™J–XQÕäY‰Zy?þׯ_Ý¢b–E‘`óû÷o!ÜP·(ù²šÈÈH888Á†:H‘A1& l$È*c° £lŽŒ`L@©­œ„<úÅáéÒ%r+Aqvv†]} ØVŠPj im± wÑyÄ&Ôu -Lim{ÿޟÏ! ™I:Y2Ç{ýù‡D†Lûу`jcõO÷⋘P ‹ðŗK–”Asî‹ÐÒʈªõºÃ°œ…2–ä5R‰ùÕPw(2ŽYEÝ¢šCԗ/_„1eÙP& u‹244Y6T% 6$æð`‰%0jÔ(ä0(íŠö‰œ”ç3&À˜@ 8¹y2jiaú(*CŠŸMkÃXïy nCýn% 2u܇B[ ™Ï¡aøõó'²ç͝,°#ÿ`r '*U }MŒ÷>ÛbïÜUhãÞU×K–xxQ&À#|ñ"Â}¯°‡ŒbžâE‚LVʐiàý•”°"/¡ª=z„OŸ> ÑææÍ›Bž!_ÊŒ¡²š?~ˆÌ*‹"Ïê%•E•.]Z6”]#‰6ºººªºÕ4WýúõqðàAdÊ€?D›4iŸëæE.‹Žiæ x#L€ 0ŽHàün/|ùôs&ŽDÉ} QE>6TEÿ'G[[[”E‘PC]¢b 6T"•žÇ‘#G0eÊY‹ôuëÖ¡M›6*‹d÷îÝØ~è4Ì»NPÙ90&À˜Îí\o_>cúx”ɧ4AŠ*æÅ|ã!ð6äÜ6Âjž 2eVýÚïGWoaåàñbGî;—!òS8ü.ùâŸÏ<»y_¶Ó–®œQ­yÃDŸý£gà=aôlëîmãœþÐÒ 8µaú/ŸŠ"åJa£^ß,®ä5…JOôý¹`×ÌåžžûŒjVA·iQC¡o±ÐÑM&ÆŽ=Š ¬’=[G‘xyH o/_BøõË\²€ز’¥†} _\µú®„íò©H€Dù êõðáCQE¥9dJœ%K–heQ$òä˗OøÖ”*UJŽù–÷±¡¯“×MZžžžðòòÂÛ·oÑ€Ix{{«ä–I@Zåœ5§ªd|`L€ D8Ÿ~6t³åÀx×þ0ÊçE…Û^·jRó¿fÆñxòn`©&‚ÌՃ'±mòBáÓÉshŽ}ˆÄ•}DZoþjñuû¡NšÞÂ&QçvË>ì_°-†9ÁÂ>þkÉ?†|d\ÖÍAED™ÏŽƒž{æ2ª5³†U‡æ‰º·¢“×{Lǝ3—d0á>bqߑx÷êX¢÷ (Q©Œ¢Ëñ<&& óùúe6õUÂinØuY3ë  2J ÉK$• 3’hC‚ ý¢²(ú*Äê%•EQ‰ù§QYTñâÅQ¢D ™é°d>L¿§•6ß³fÍÂ… A]³šÅއ‡GR‘+õúÓ§OcΊ šÛo¶R×åŘ`L@¹,Ō0¢”ÓcAF¹tãdB?ÃaøXºº SÕϐٿp ÎzïC“Ý`ÙŸiŽ}ÿú o>Í!/˜zyà±sy¢XJY/]a\'þ²£ӗàòÞãpÛ¶¹ Æß” xŸÜž‹€GϐC/¯ðŒù×±%}Gâùí¢Ýv…ÚÕ°ÔyŒ,3GÞÏ&¶‡Œ “w ©©…Šå#i| ù¿ ×QºZ¥¿ºXE|úŒw¯ _Ö‰bʓ™@J`AFy”ÿ2}¡_Œ‚ò敘@2/‰’„*¢_TEÿÍ¢²(*…¢Œœˆˆ|øðyóæ™5$ÚH6$옚š 'þüÉmò,Iݰœœœ°víZ!D;œzõJž›%rU÷ IDATՋ/bâì¥h0øO‰u"—àéL€ 0&vÎsC)³ÚpéÖåó+M©ŠùýS |õœÅûÐÏèDŠŸ®ƒ¡“%³Êodù qxrí¶è‚DeBÔaé ŸŒ‰ òCUn<Û'/ˆŒòz‰9‚_ø#_‘Bâ'j›ÆÍÁÍãç¢õÆeã˜Yžuâ<Æì_,9³ÇɎʉֺMAÀ“?Ó$„ôž?y $šù޶ýÄ^)3çÔÆ]žqäŒX£ÇTiT7Öõ~|ûŽÃË6‚2€ä‡u÷6hгœøÒÎéKqiï1X¶kŠ&ÎÝdÓ~~ÿÉ-D9T‡°ëãè˜ù&ÜÞ]ŸŒÏ×/qɒ@¯ßyÙ²P†L?èçl;% å%R‘À»wEI¢ ™âŸ|ùR˜ çȑCtˆ"ÓaúÊ6¡VßÑ›˜¥QTN¥jƒÊ—š-vɒ%1}útØÛÛ§jˆ×¯_‡ûÄÙh4lIªÆÁ7gL€ 0ø l™6ŠÖ­Ð·­ *(KiÙž:L D•qðˆÀûÐp8ž­GÍaê!Ȍi耯_"â<Îâ&F¢\Çš–9 •óæ÷p…ÿç ô‰$s»AӁÝE+íœE鏩rêåEħp  _ºô˔¿KÃkØDø]Œ‰Ç7AK'“ø²ïñsBœ)U%ÊóCð;,îã!ʙhä/f€ çQetf6µA^/‰”iã^;Ê󮀼–hP¶e Å6HPY?jîû\V6Æï_¿ðôÆ]ñwWï…ÈkPKû><=gAéª:«<õœ‹eƈ¹ñ‰>‰ÙÏeÊ&ðîÊe|ºv‰K–”V2YIéýb唰"/ÁT—€|koI¬¡¬jéMåQ?~Dîܹ…— •E‘PCeQT.E™7d:,_ %/ڐ “ƒ|vlmmAû E‹ÁÆ&q%Üʊ›Z¥9 MÝ—±¬¬ûó:L€ 0& žNšÕÒݚZ¢b%eÈŽll“ŠENg…|G'WdA'«êý€GþX>Ÿ Á${Gñ%6ŠW*‚%‹"ñ"¢d({ÞÜ™ØÊ TâCB‹ü8Ÿz+Ž­Úó&õÑzD?‘ "‰'±=5ZÙ¡¹KT°$`L=»]üD F9õòÈÚQKåEÔRœ2vH0zzã–9E1ã²è»dR¢žŒÐ€`LmÓ7Ú5e,L…¹¯Fƌ±®%u"Óæ3G¢XE#|‹ŒÄŽ6ýDÖK—)n¢ežŽ÷±×"sö¬²µöÎ]Ÿí‘»P~ ÛŽ5c¿O¢6“™€’ ° £< ,È(%¯€þb¶ö–7!ŠnQAAAÂd˜Z|SYÔïß¿ñõëWQE¿H ‘ülHž‘o’Û€˜Ì‘Û¶m+üvôôôàîîGGÇ-=Š{÷: ö^êÿ0ð˜`i•ÀïßX3Š;vsEGëÊ0)ȂLеd†¯G¡ƒ «â‚ •*QÉR‘ò¥ÑÙ…Q6 ‰$4HL Ò$i/ʔV}DÆMÇq."ãD^iУÊT7‰)Wü‡ã«·‰Kû,ôDñJåDæÍ»×˜ptƒlMÏŠ=„È1õÌv„az»þâ3Š—â–ÆµÃ§W¿ Š—QhÒ$òŽ!‘G~P›oê%‰BòŸ}z‡)­zËŸD­²)ӇXJí±=v­@öŒ¹0²µ˜7åôV™ž#}×)n(gY5Qñòd&RÞ_œŒOW¹dIŒYQE^#œ ’'y‘&f×(ú; 6”M“-[6!†Ð5”ÅBm¿é¿Ý1K¡bŠ6$ô$eøøøêÈD:ôgfʖ-›”eº–Œ|ºŽV£×(4Ÿ'1&À˜@Êøùý6x:Á¶‡;ÚÖ5A%¥ 2,`R3dâ;Òаptt]CA7›jgÈ\?r[<ç£bœè4!z‡¥žöøóÇOxԉ*ñ‘E(sfÛäE 5iô^0%L+@òg¡ò%*c’’Ø"•7Q©•<ÉgÈH­¯‡l˜ ê~D¥>”™2îð:¥üDJjËs¿v}P§S‹¿0P(êEŸá¡a²r)šH>6-‡õÃ4€r0©e÷ïß±vÄT<Œä+2{ú,š˜òÿ:𙀂Þ_œ‚W/rɒ‚Œâ›öGýbFJX‘—`雉2‚ŒŒ`C6TEbMžd t³ý)SQÅIâBb2dh˜Ç¿Êq˜8LԀï[°Z Ò°qìˆz][a÷¬ž°ë°ÈŠžj†-ȃ…Ÿ&µÓвŸ2fÂ{†ùŸ5nS„WKÛQÎ(^ÑH<4*5°DK×ÞBœIÊ8¶Ê[–©CëÐz’§Nש#P®–yŽå׺Oܳ—á8o M+àÙ­{zú YsçDY S™÷ ]Žzød<8MìÙª}3ÜüÏGt«¢ÁÙ1I95Ÿ6%° £<Ê,È(%¯Ä!³S 5’pC&†º>Ñÿ¿Pw(ʲ¡²šOŸ>L‹Éç&¶r(ù̃€1gÎQŸT»vmQVEëôî݃ R$ÜDÍ¡øÛ÷ˆvã×'ê:žÌ˜`)Gàë—ÏØ2} 9ŽB‹šF0S† 3bÄØÕ3eéð”Û‰ÞéÃÇ/è8l,\Fó QÅ­óڂã^[…!_&”P¬dèK™*1̀It¡l›ó; Â}Ç2?EœÝesiµÓ–®¥l'ȯe¥Ë<ºrSæÁBqH‚Nû1ƒ`ÚÐJöwI<¡VÚÅLŒP DQ4, MíøëóbîÍÛsž¬«Ò@¯Â;‡J˜$£à†œÚ£n疲’#ÉçFœâcõêþc,tt‹uÊÄÿ6C+SÒRŠ:'þœ $… 2Ÿ®^ä.KIøÿke‚Œ3ô‹&IƒBæ%˜@š&@¥M$llݺ –ÏŽ¡ò'ʒ‘̇555£™S6 µó–nHÀ9}ú4.]º„êÕ«CWW7nÜÀ°aÃЯ_Ô“”1^¿~ÖÝú¡Ã„ÊXŽ×`L€ 0d þÛfžÀ®×HØ×4Be}%dȌ3övUP©`p2„œv–$AŠÓ°ušŠ‚ µw&Ašfab›˜ñÞ?$èÜ;{EtA2³­ ‹æ ‘9Gv왜®Þ݆è§Nþ~OD9“|›jšEtõ–v2aâҞ£Ø9cª6³F«áQF»”BY).kg£€aQüþõ>Û€ŒucëEÙ>'¹ CbEÆÉõ;Eûjòr!aˆím^÷a²õåœrÎmÝ/Ëìq¢,™ÊÆ݆Œt>…„A¯šŸØû‘›áï÷TÌ#ŸÊîé0v°"áñ&jB®]Eؕ \²€„ø#È „~ÑÄù\)áöŒ`‰$@‚LL‘FþCÆÂ$搇 eÎР,ʰyøð¡è*E%S††† #cfÈg&©ã͛7hѹ7:znJêR|=`L€ $Áo°{;šô‹f5Œ`n ,Aƶ *bA&Ÿs ûŽÃÖ¢š‹32gÿ“ΚLg€eIÜžyÂ¥ÍM9GòÆJ]BÞ!<ìrä˃ìyrýÕÁ‰}:ʗ/íW–,YÔbKçϟ‡ë”%hëŸX-âU÷ ŸÝŸ„œ‹Gãí«'šÞŽ+¬» E&]õxVԝ=ÇÏԙÀo_±qRØõô€Mµò°*®,AŠ~˜ Sg6É{”©ïTuˆÌÙS7­5Ù7Ë7PˆÀÍãçüÒÖÝÚ"ƒF…®áIL µ „ß» ÿÿþÃò©,È$õ,Öî8œÔeÉnô Kêr|=`é˜ Jcæ­EëáìI—܏ÁÏß1ÖŸ,>‡Ÿ•ݪ@±²è3grêé'÷íy}&ÀԘÀ¯Ÿ?°n\O4r…ÕÊ£Žò™ò0-òQÑ$èBqYjC] ›ôä'Îw`L 9|¹/ÁÊéÜŠ=©|×n?œÙYI*GŸž 0`ïÞœ˜±zZ»ÎU[¿~ýœ¬hjÅÿcemð•Ÿ/¯š‚ÖCf"WÅížßœ‚¹NõE º ÃýKÇñÚÏWˆ1Aî‚E”b¢×  Áι®šbÓF }=_ÀRšÀ›Çwö.FÖ)}ëÔ¹ßïßX=º+;ŽŽdJ()CŠiýò0cA&ÞC%AŠýàÕš1|t²dN€ïʘH"¿{x~è0VÍ`A&‰(Á‚LR òõL€ Hšõöœ‡Ñbðtµ‚òðê)øžØèWØ»xlŸ† ’?søÌö¥Ø9g8ìz„Mw·8¹Qùx(Þ5£»¢Nû°wžŒï_#±mÆ`\>Ž)š(óû×/dÐÐHÑóxýð&fv·DISK Xx Eï×ÍŸ|ú øE~þˆÏaïù9L0“ž-oŽ,9r«D¬DÊ ï÷±ÍË S欘vìMÊÞ<ï¶fTØõ k cÔ3Tš SfE>¥â¶TÿÖB䅚#†!Sf]Õ˜#dL€ ÄB òÑ}<=p^3º3Ÿ$ 2\¡oÀ>RIÄɗ3tM`͚5ðÚ­†ÌT ôBŸcö0\Ü¿î¯x‚a¥šÉŸS[a÷|wXµéƒ–±Y?ŸEbÅðvð|ƒ–EŸÂ†"ŠÓ[—`×<7Žt™«Ö}Ä×H\سp$Ny/DžBÅP©®=þÛ8=&o@ÅÚ͒}/Ò ^=žY=k#_á’é}=Åî+݈ KŸÝGÀ“{ðt®ŸÁû7Ïã#k®|˜°Ç5S<^ŸaêxrÓºT‡±ecôœº9uƒIÁ»¯Ó »Cƒ•PßP'Þ;+ÔözÜžqhR·,̊~NÁmšß­D—¥«`9r8Žuâ¯~»ãˆ™H/Ÿ=~€GûösÛk%ždrPÉÒpè€^Š»¶ÂK0&Ê6nܯƒ—Ѭ¿g*G’ðí)sdÝØžqb§˜lÛÓYsæÁöYCÅßK˜ÔÀÀŇ^(‰3ެžŠC+'‹¬–²Uëãÿ3|ùŠLY²Â®‡ ÊV‚‡mÔ¿Í$p ]y :Y³ãÈêi8ŽrR4A†æÐŸÖï…ëÇ·#¯~q±a«Ï ŽI£UìòÇ7Îbá€ÆbrMûž |‰°·ÐÔÖF¥z-P¯ã ÅJĬ ç~";èÖé}xûêqŒWk`Ž2ýyʐA}fÿÀ:ØÓÄÔ󻜰uÆ`4ï?u;L{RdëÇõDœNƒÐ°feX—Tš SfEùº# 2V£F@+“vºåÀgL@œ |⇻÷aíì꜈~•÷9äÌ¡‹MÝYQóà˜€:Xµz ŒOÞF“>ãT~—ö¯Çæ)ýEœ—A‰ŠÕş¯ڌ{‹?OØûÙóPê^>ŸŸţäÀ碙òÊ߈Ê'Z œ‹Š]ñòþuœÛ±¯F—q«„XtlÝLX6á/A†Ö ¬Åƒš¡ãÈ% ¡â֙ýšÑ¬[²œl’Á0‰C”CP|Ù(Mº œûB¥2¥,¢auõ¢­IB¥Ì¬„(õúÑ-Q’V±vStŸŽ!EJє±A*Ÿóx Ùó6óHK7‡ß•“pßxù‹•Iž›šàª&8¢vÛ~°±ªŠÊdJìèÜ®ê„D‚L[畹3ÆšÚZªG˜HÏáގÝX7§g"®â©±ø“!ã}Å %™&`L &%K—c÷ÅÇhä4Z¥á€àÙŠ">û£ËøÕ0³n%‹—Ê]F5.!þî²âŠ–«ë^ȋäޅ£ˆüò Å+TEåþzÑ¿zØ·Ï¢ed”ªl‰ qpùßDôyMû(bd†ÅË SÞØÞø¥¿|Ê& x -]ä.XuÚõ‡N–l²šÄj鐸ñíLê6C¶ÜùÅÞ5IU„gB`è,ˆ«|\Ò5R6µømØmxŒKÅun$˜u°ZdÝР=Ó܀§wAåNQ‚ZO™ÇüMÈ4Ög×*TmÔIdìHͲâ$Š”«,Œ€gt«õWÆ YsåE¯©›‘%Gžh±?Œr ëÆ÷”]CÏ™Žæ5ˆåeMÝ<µáaï…p£_Ê5[ÄþÿPÔùkVš}ÆÔ ¬fKG™X˜ÐÙ)²wé =—¡A¯1Ÿe91}⁧Ț3¯,<Ÿ]+±mæñ÷ɇ_*,NQæÙöÙÃ`Ó}ìzy$ô˜ ¡óðªÉ"ëLúþ§³·hÚ–-cý÷‚%Y²ç‚жêX†l˜Ð U¶Gó&v°-­AÆÍÍ k¢nŔuOðÔTlÂÇOhãŒõ'Œ…FFf¥bÇÃá0&  ß/Ÿàæ–íØ0×QÁ+xZ\Öl÷A®YP•~H˜H"i³æâ¬_tsMâJÉ{9ùĜ۹Bޚ®ÕÊ)Q7;Ÿ~6ö/*É¢—ez±¥r<£Zcñ¢æÖ JÈ!Á€ŠM;hëdÆœóG„· éE\Xè'þN3¶Å ™SŒ$à‘£KõxKÈŒØºóQ†uýØvñâZÚ<*ƒ…^âþcðK{ 3v³eÌëŠç&¶!uيù]K†Ô’_erì]<'7/øk!lzžAC#cŽÏ lŠG×N _#*iɕßÔfÌ¢iØœ"D9EÎN‘œ+ú\’`³È¹ Š•7ÇàåÿE‹™ÎƒŒ‹(æ±;î*ÜYlj§ª"ÉmýE,%öÄ5è{Pò˜’Î)—ž,“‰„™Þ³v p™Jb b~ïjœÝ¶L̡ϻŒ]%û^LêsÔë©ËRùZÐÉ¡3ì”!Ȑ©oãÚ%Q¹xdRcKÓד ÓjÀr4œ4Nmê'Óôðæ˜ø7¯ŸâúŠmØ4™øç*drçÈóFîÐ××Oêr|=`é˜À„ÉÓqåU„Tyw eMô˜ŒQøŠ(:äÅ y1gՈ¢4‰ÊeZ œŠëÇw`ÝØîâÅzô¶[Ñ~’ïÿø¶(K!q…JŠ€ŽDÅ+Zˆ.J± z™£Gz Š—a*¹:ºfè%žîA/îŸBßâÍã;Ѳ^ÈgR{3ÐK㈍—A­Ÿ%ƒ`º_ç1+Ei”$±±m"„«G¶€<&hPÙeEPYÌÂvÂÓŠFóîh;|^œè×Ì.>›q"8šy®üŠòTô|âšGŠö-ƒÆœÇ A—aq.§È¹QÉÎÚ1Ýgʊ"fôµÿ6Ì¿H”qßx9Z •Ù,Ú … +à}Àsq-•œöó•1¢ÒêL%‰<$ä‘96‰± IH ÏH„èè±'œ€îEϵm§ò°-ÓŠÒ#zNhÿƖMD×ÈFÅŲ]ÆyÁ¬AkÙ-šŒo\ #ñ÷þ öË2‚èïßâö™ýÂgå׏Ÿ2a/ŸïEöþý[€BÏ¥ôL’°Õ|À$YÌRÛjú Y$€*2€R;:—áëÎ'x •9JþHŠõZ¢ÃÈÅB0#.$NÙ¶T¬1fûaŒMÿ<ž]8¢o:^Ž—Ž£TåÚ gò$Ü?L ,6Óú-Ñš¡5•QB†ÌøñãÑȪ8*ÿöဟK„ ÓlŠLH?›æ2&ædðŽ«ëœ±yAâ~²™æ@(aCk¶ù wά02,È()/ÁÒ-1àûæ+lþÿR¯ª $B8‰“²>Šw©!ûi8œSvCHà+ًuÏ)›`lÕDŒ˜ï[2Vø3Ž:+Þå)ó`®SýXê/]øîõSLlWIøfHY4Oo]ÀüŸ6BP"aIôbOåE”CbËš&†â%ÎÙBd!ߊÝu²>9 IDATäˆÊb‰ ÿ„«‡7ƒ2_r(,^0Ç4+->ëæ¹VtF¢!ÿâKÏUdŠÿk–Gbx*r>ñÍ¡Ì*1³éî»^#㜪ȹÑ3ðæÉX¶r’µw—÷°¡ÅÉŽ˜Ì‹¥Až4<ÿüÿ ‰aýçíÅÏÞ"»jš×‘Uñ9LŽ3§’iÐùR™•|‡,ù $š×oî^‘uABÏô®5„hÐiÔ2‘ÁŽbx[!Æ ó:++§ºyjVì,nAÏš­ŸÐÔÊ$þNÞ1óú4¢‰‰±Äœ"{|z_¡çòäŠùسh;Fƒ®²ðšuýÙ˅à5lÍÙ¿2~â:ðs‡ EÊøIè9£ÌŠg·. 1•Ÿç2hD¯6Ù6ÃEø:Q&µ[—:žµu ³mðû÷/QVGR”m“˜Ší_>ß1k(Ê[6B;[4V– cgY UJ|ÿ—xÒÍ5>~A;çh09aC«t…7ʘ€ÚÐxó—×n‚÷šN<þ@” “ æÜXùwŒ|%`FŒ¿ÚšÓ~€Jóxÿæ<Û‹é§ídôª‘1~oŗ÷®a¶c]QvP¢¢…h¯,?šö›€ú‹/ížï.|ayázýð&fv·]t(‹…eÀLîP&uš‹, LF4Ô/ÖSú‹,wE2kh-2Û¥LZûæÉ=¢ýt¿«çš8ÏHÊ!‘6Ãf‹yô"¹ibo\9ì-».Š$¿ $ÈÈ{}xO : ]u¯ÈXAžI}˜$Ÿy%¶5:7){„ÎÊuÍ9dԊêX{qßZxOu–-IÏeIH-Ž¥ š@Bù‘vqÿ:“ö#ˆnZÒ Q„‚Ó[Ë2žH,£®[äC‚Û„Ö ~'ì}„ìyò‹Ë®˜ˆ£kŠ‹Ò¬ˆ„@@Þ7Šõ£Œ«éY¢LùÖàò.”éE_òÏcLV‰ù^Pdïaïz.¥’!ùçN>Ë*fFOBύ$® Zz ō«%4]”š‘ #/RÊ_Ž~|O\;º v==pèÿ¢ZL±GþߞV.3`Ù:õþ?vç\7”­ZMš4FÓ²ñ·{Ïð›þH`P†Œ]­bšbȂL|šB>|FÇÁ^°ž€úí:sþœ 0ôK@3ð%.xmĖE©÷²ŽB_2¹²Á܎™ŽrŠŒ&Z\GŽÅ“ð,šÝ¶oj… ð}årO™.uÚ @ËFøñý>œÆ—O¡È™O_fJ™ »æ¹Á¶‡»0-ŠŽ./î]…ŠŠ6JU¶Šfæ)ý€œL\©õt|ƒÚ`iV*šØBëÎq¬-ûE8Fmœ)Œaɜ•ÊN2Î]1Œîúô}© ©yÿ‰B8‹ùS~Šõҁ Ø<¹Ÿð¿é:Þ äashÕ$ñ²IƒºíHåT¢E¥Z1•JÑK¿Ûº (hX^¬1ªI”Ùì”#¯pvûr…y*|šqL<¿Û [g @ŽÓ·Ä¹\BçööÕLjo*˜;/<( ŽIð öã4(#êÊáÍBD!“æŽ# W)ƒƒæžoºŠüE£²$ó\é9¡nE?~—™÷RÆ ‰TCkÒ}©¬žMòL‘†¹m{á_„ °jDGqÞ$Ò3B™ýÒ3»cŽ«Èè"ašHY3‘ÅAë:Nߊ’еdåv$*MÜÿ$VV‰ù^Pd參ÔQ蹔„ Š2²ç- Ä'ñ H±m‚ü]\,£ºfÑ÷t ûîBl%?j£þ1áދ.j¥+ qmíèn‚Wµ&ÑÞmì{çSH°`)ÃŠÖ š%.öâù§ $ÊÊ"³is.ì[+ÙÆïñKTGš€~ÄŒž²Æ ©4®¹=š)A™0alj¹áeǚŠÖ{ú ‡¬Fý‰,È€©ƒåÍ0tF@+ø5|V¬ÃÖÅ}ÒÙΕ¿]d”Ï”Wd镀cÿAü•[å=d€ó!“]zA•|!b;7©äF*s"߇þó£gÇÄŒŽ²(û!®.NòóåËOÈÏC7[ìY0R”F9Œ^Ž*¶íÅtÉ¿‚ K©¬ˆ†TŽD/Îô"ې Œ;] c«Š˜ßÏFVbE/åTbUŽ\eQHIñB*ï#"¿&œž÷»G”W[7S&DPw¡Æ}ÆFóÃX2ž¹hÏM€I]{‘íAå9ô2ÛÁ}‘Ì·FžIý~"фĖøÊpè [ÌÒ$ùžš,¥†}HƳô•&Ñ^OoY,„ÊZ¡riHåZOOœùýœö^$JrÈçÆ²µ“¬cyÿ¬×SøÃ”4µD­–œ°ftWáW#eºHí³¥Î?ÆçïáåÑé/|tÖ}æìY:Ôm‹Ö¥A$lœõÿVSŒ^(1GbŸ$‘+Ÿœ“Èžp@£ŸKŠƒJ­šä*æ ,7jkž˜A^9ô¬'4ˆmï™QfÜóûيßéY*PÜþnÉÖ yƒ—æÀd0,/šÅŒGU»Žè8*Ês&µù*62ƒ}ËÖh®4AŠFa˜—ü™Z{R‹û¿ÿ„n®kPÏóÏ?j8ɘ# ýÖg—­Á¶%ªÿSXU?8!ÈäÎsÛá\²€ê‡Åñ1'à<ÌAôâl§«Šá“ B%:Ô˜~OBœXы/µ²%¿R‰ý™ÌQ­;ý«AÆ·È|~-ʙšS|“äYPËè˜æŸt~€ úi6™³N>ôB˜µÒ ò£#«§‰®2’H“±T‚"eªPÆþeãEæElƒÊ™šýöŸC"kAzÁ§œØ;O¶ÒîOYÆ!_ª"Í'®£¶ø"[nœDñÌ©g +ÿù—g(¡6çҚԉhÏ‘ñž=ëÆô>24(3£Å ©(Sµž,4ÊP¡Ì$T&eç8JdOÙµnÖѶpx՜۵öøÁ÷äa+ ôȆΌŒ†h°µƒ‹dšKR± æ8°ÜS&fP9U›Ÿ"ۅ€£kŠáÐÊ?ž4dÐÜÈqŽLh¡gvõH™(C>H«Ü;ŠïIŸÉŒeäƒNÌ÷B&Ýl8³}I‚{ÿñE¡ç’|XH Œ|pŽŽudžNò™GŠ>#Ät£gïhå[q]+™XS×2ÊX’Οæ“0fÑ€³è°&/ŒR9"ù6…Ÿý;Cݪ.Ü(Ÿ§(S‹2¶RsPf‰G-ÚŽ‡}9eeÈÔ0€yÉ_©¹/•¿wàۏèå¶u<Çš|¬ `L .™Þ¿ÁéÅ^ØŸôï4iŠ–8,È$ŽÏfL n}¹"T·ª7늶˜èÅ).?Éc„6Gå<•¶Y !o^ÀïêIÑ֚FËAÓ ©ItQÉWØ0AÔ‰ü)èE²OH2·í ó(‘ ‘ñJ_#£Ýy Æ{*]ɒ#OŽ9aoßàÑõ³xyÿžÞº({¡§þ!+NÄ"ìm²ä̧ B‘áE¶€üøŽyœˆWÊ& ²œšö=¢œ°*Ê3©^RÛp2'Š—âží÷âŸu ž ß@K'sœ]rÈ«…Ä›¢F•ãmÁLk‘È µžŸñ8­œ(|bÊž¡g‹2ºH¡R2*ŠAÆÍ”Í"™óÊ_û-ò‹(¿É‘¯`œÏ6=ƒYræÏ=ÇŽŽÔ*=6^Ê8»˜{§û(ò\Jñ¿|$Œ–è™æu&Áﳞ&PÙà—!¢¬NCS™t²@[7 9'ásè;PIR¡’„( ú^¥r&ݬ9%J¥‡©]®Dû A5¯!Zµs@‹òÊdªëÃŒT‚v3ÿ|XiáÂ7Áaèí±µÇ³ “Γ÷ÀÒ+ݐœXž ;–± “Ôg`õ6äɝæ¶®œ!“T˜|=Hçž <{)Q–’œ@ž¢,ŠE£âÜy‡/yG$füüþ $bPFDj 2þü9õ É2p’ùtA­ü‹¬üšÉÉ3©±§æõą|ŒÈ³†^ú3gÏ Ê"ï TúE‚LÌnC)sJ]|Ï¥ÔKޔ8%$ö^$šQ™!ýÛ0n×ýÄ^®ôù”]G±ŽêØ ­”!Ȍ=ÖU ÂÒ8ÊíšGì^~@¿Ña5n4#bL€ š-ÌqlÞ ìZÞ_m÷ *“ “9³.̬¡L™2ªÇÁ˜€èÞg Ÿç«s»jœâ!“Èpóän=÷Cä—ÏÈSššð`14­gƄ⫧¿™Ì3qgNY4ˆ¶ŠÌTF–š#µÎŽÄ>jOÙBžûÇ)ú¥&›˜÷–̺)³®óØU©Ú±u³DVT‡^h]A 2žžžhhQæÊS}“ªÀ› è3r¬8CF‡cbL@A:ÿϐÙÉ2 ‹{ 2yóäD›aœ!“dšŒH¿è'æ]œ}STnØ6ý‚à3d&àÿø6ft­™`ûòd#U—âëƒýí윕šARv•óIå‚ä?³n\šJFωs¡­›m»öFãÌñ¢Rší5 2 ,  j© ©É]åïý6äº]z*Øeé珟øñý;2éê üÃG왻 åk™Ãĺ–ÊsUv€Ÿ>C7[V±ì#gpÏç Zºö–}MÙ÷ãõ˜€ºÐ z Ÿ•ÜeIçÆ‚Œ2(òL€ üüùÝû F†Â•af݊0&Lšë’‡maŒKÙ!Ú:ñ¿L'S©ºìæ)ýqiÿztŸŽ&uš§j,±Ýœ<„Š:T˜zÏÚ#‹ÂŽøøºYŒü?á•Úã”÷Bá)Ô®GŽU† 3qâDÔ¯ª‡j¥5R{o*}ÿ°OhïŒu=ÇBCCµX홳.\Çð-‹àwá:VŸ ã:p˜èªÒL•ܧ˜Ø¬':ŒsA%ëZ˜ßÃþŸbðÚÙ(hXTÙ·ãõ˜€Zøýê)|7oÃÆyŽj¿*œz«òæÍ…*6C9CF•†cajF 22œ …V±j óTL€ $E›âѵÓÑZ£'ßÝTke;F4Œòhšv<™„¯j QJÕŠ¢,š†Ý†ãüžÕÂ|yÂÞGȞ'ªŒ}ÖPa\<`ì<Ž«š„ !ȘçCµ2S}sªÀ§ðHtžÕÝÝ ­«£R¡n?ŸÇÎbÜ¡µžsú¶O]Œ†ŽP¿kk•Š3¹ƒ ~áY¢v'{4êÛc:àë—L:é M­š6‡<˜@z'ðõÑ<9p^3þއLïLþuÿ«·žCÞ|yP¥ádþ"_ǘŸ~ýŠ®}C«heTiÕò—`ÉCàâþuðž2G^öÓÓžvt+֏ï•äîJÉÍìün/l18Úm’ÚJ™1ŸÙŸ?¿G;ÇÁèÀ‚Œ2ÑÆ¿VDä7!Ș ˆ¬¹r€Üž“$Ȍܜ>ÛâÔÆ]è6ÍF5«àsh~ýü‰ìys+°’zO‘™ê-laÛ§ÆÚt™1”!à 0(oùâÏ,žèÀH’H JÉ‹* ]XI"KŸœ €g”!Ós€+tKր±U“ôŒ‚÷Î’À¯_?á{b7ÊY4í®ÓÓžyjVì,2ñºy®Ué­SïsÝ@1Óè7woŒíÄSr3g·/Ïo_ÑÖÑM”•!S%/ª•ÕLÉ}šÝœŸÿø‰ÎËQº§#rüÓK]6r|õV[µC6Ì҇qa×a Ý0š™Ž1­M_b­¶MP±n è—-‘f³E"ÿ†Œsš èŠIöŽšÔÀÆFWXUáÌ(†GÏàþùkh?fÊ•Á© #ŽCù‚.\Ào¿›˜9’#“J—™€äë™ èÞ²ÕF›<˜`ÉAàËÇP^5f Ûª„‹"{€ÎX9ò@¡’™ž"sÎîXï‘_ÐÖq:UR– S9ªqIGB'Ø~À2è·íšr~$dêûðÒ ”±0ÅœsW°~ä QŸôöå,êíþ×¶J™› lÊ(oY¹ äKhÛñ~þû×odÐPCè€'/QSùŠœ΃Q±~MXwÿ÷Ï/?ãÁ…kxzýžŸÄ—°OÈ[ž ,Û5Céª&Ib·Ö}ŒÞ ' D¥òIZ+¹.ŠÎ2šÎù&×>ÓÓº¯þ;Ž\ï_aœ‹ê¹©Û9xm=‡|zùPÙz Ô-|Ž— 0!@2]úž —±5ÊUoš"QqL€ 0&Ÿ+ñm‡ÂA‚Ì€I“P×,',Œ21ñôŸÚV ahª: ]l!K†~ýú…}óŒp~Ç¡8wFY3Ö=Ú"ñ‰>ÿw¯°jˆ'ræÏ‹3FBKGµž¡¯‘ÐÒւFFÅý‘n<—wB#£^û=œk·cå’)³.&ݐhfò¬q›‚û>WÑy’+*Ô¶HÒZÊŸøÇ·ï ø?Gß%“×  ²oÁ륁—{÷ ˜f†8òÿô'õHÑÓӃ™õ@d’ “¯gé˜yÈtì5zfv([­~:&Á[gL€ š>ŸÝ«ñù#Ú:CgS%dȐ SÇ,ª©–Q­*ÅOoŒ/a ã:ÕU1ŒXcztõV/>sß¹ ‘ŸÂáwÉ÷}®àÙÍû²kš5tµæ‰{Aó»x^Ã&‰5T¹4(1‡5¹¥‚ßË.!áÅÔÆJVyô s¶¬ðÙq/nûÁmëâÄ,m.e-4OoÜE1ã²ÈUH¡o‚… ±nö¬¢Ì*5}HÔg×UĜ·p!8¯œ,é¯5à?° _øxó&T-’=ÚÖRá(Õ#Ž(A&?̬YQ#ã(™€JøöíÚtïƒjÍQºJ•Œ‘ƒbL€ 0(ç÷xáKX(Z;¹¢«Yüª2üŠzƒ 2 úóù„y{qK³ ,ìm¿(•g^=xÛ&/þ1<©EןA$WöÇŸù«Åí‡:¡z‹Äí2J®8¿§±mÉ_Y2”¥ôô%ÂÃ>¡p¹RÈ€bªbόÎx÷ê0nnâÜ &õkƚaó/¥Ä鍻ññ}(èÏq ºwY£ _ºDŠ<=!Áx÷*JŽ&œºÿvÂãk·Ña¬ Š›¥H<|“ä%pwÅrØ×,‰æ *%ïÒÁê,È€ƒCæ-2 ðóçO4ïÐÅ­Ú¢€™e ܑoÁ˜`ÿJàüž5{‡ÖNÃÑM‚ÌäɓQÛ$ª—×ýטÒÍu‹×ÀÞW¿aÝ­ÚìyÿÂ58ëœMtƒeûŠÑâþþõÞ<|šCAœ<ðع<Úʔøø.Ùóæ‚n¶¬ í›2L$^ä©ä‡²>hT¬W&D…€)c„J 2ji"§^…ÊŒ">‡C+“¶RMŠ,߄ëv Å0§D oÄ3£fÆ8c_=|2œ¿öC^ȈؠL 0,Š,9ãv|y„'7î@SS %Lˋ3‹o„øˆÌÙ³Eóù!óc*•ztå&ü.ޝžhP6y)Zâ•Øgƒº}E†G svŞ#…6ž”hWfÍÆÎVšfš2‚_¢T£ „ “??Ìês†Œ‡ÊT’€m+”¶î C“*Ř`Q.ì]‹Ï¡Áhåä†î••!%ÈdEõò\ސÐC¶ýà5Ì;ñÍ]z%4Ue>_>hœE ŒJ¢H¹RBŒxçˆÀ'/@/÷òÃa¢+ŒëX€²Z®: Ÿ­@&¹Ò(]­ª5k¯ß‰ÔñI~]ÊøÈ–;'ª4®'º=ÉЁ:DÝ={Y&ÜÐ|ó&õQœ¥rä‹j×M‚Ñã«·Q³M#hëè`÷œžžëˆ(§é¿lŠÒ^òO¬Ý#+6¡Ã8T²®2L~yÇTúõêþ#!`I#;L*²‚ˆÙÜ.."ÖŸK'C7kôoNŠÿ‚5xqÇO[Í÷Àõç…(ÒrxÁ5ŸAž.‡—mÄÙ-û¢M³îÞ z¶_»qä Ÿû†ªM­Ab •“Ñ}Ië8~ˆ0ç}xù&V ™m bH+TŠڏoŠ>4ïÄÚí(nR†f·UC=;û!ŽšÞÒVeŸGÒ[ §ÆzbɄ(\(ê{‹Ç¿ðÚrù €iý\²ôïùJ&ÀضêŒÒÖ,ÈðÓÀ˜PqGVOEø‡t1=”%ÈX™dE d<úÓýàî}Sd›h«x鍎™1 dBGl€2êðcTË…J"ìm6Œš­€Š aQPY‹”ébÑÂÍ÷™” síÐ)‘}C/ü#ëE‰4HT±jß zÅbï>raça잜B6_‚ž¿_¥;3GB¿Œ!vÍZ.˜nÓÜôü-ùcš[¯K+Ø8uLðü™ ݇b¡!íYþZŠ‹²aè³!ëç ™ŸßÀ£n;1­‚U5žEݧÈw÷¬x~ûøŒ€ŠÎÝD—«ÿÖnÇÑ›Ñx@WÁ)®Ak¯5CdµÐ0¬lŒß¿~ ÿ®Þ …éý„È6zŸ¶MY-§çì1¢+ÔÒþ£dÞAEʗ÷&¡.¶¬Ú#µP/_«*òHÔ³ñ)$ “[8ŠŽdŽóÆavçÁ2!‹bŠLE3®97ž£_?à˜ûXY?*ÔM±èUoV” SŠõû³ £zÇÃ1µ"`Ûº J×ïÌZË˜@z$pqÿ:„œ @+'wô¬¢€ +“,šQ>þÅÒ#ì˜{öœ÷ V]AíŽÍ“Ü.:%x~|‚IöŽâVù‹ x¥ò(X²(ò/‚Üõ„_H̖Õ7ŸÃŠqsÄ5$Jtž<¥ªT•=žx {çz‰—þ­ìDŠÐ¥œÇ°súRt™â&Úh“À@Bƒt}‡šÙŠq¬Þ1’€@s)‹£G‘ýòé}(N®ßŸíÄ:äMsq÷QœÚžKø˜HfĔõóúþcñµ>‹&*)eq<Œäm-ºOÅ:ÕE[qT4µµâ+_2D¥aTþE£fëÆÈ’3Ž®ô§ëöj/2$ñƒ²](k†º\5è%æÄ6hÿÖlçAU±ŠFø‰imú ‘Cb?¿‡+ü>‚ÔŠÎ®=ۉößòFÌt/óÆõ`Ý£è”sð5Ûa0,Û5~:‰y6H kÓYÄLÏeZå.”TBEBVïãQBÅ»•)åR±E"ü_ãöšuغžŠEŠžá¬Úr „i=dÔó9j& :¬[tDq‹fš`ÙXu‚âH˜`Là/—¬Ç‡à7héäŽ^æJdŠL™Kc]ÔšÀŸ =o/üßÃaîT¶­ ƒ²%šžêŸÓK9•,Q&•õ(2È÷eÅ qbê€åS…¯ü |‹©­£^æ&ô†ï±sÂ4X>Ëã©ï]Y¶I–B%õ»·y£zÑL—ô)攳¬Š.“†ÿ%횹wmïNxÿ:Wœ…R»“=l:ŠN@ô‚?åÌ6hhh(²ÅxçH¢‰0…JCŽ-Dvˆ¢ƒ–˜eE”=d×§³ð—‘§7íÁÁÅëP¿kk4tìë->œÃ”VœeŸ‘°£_Š„\€Ò)]+Di—gÓѲPºMwG®üù0§ëÕ¬"²‹hŒ*-»~äŽl]ÊС8å;;ÑŒéíû‹lžîÓ=„'¢ÏÆÐMó1«ã@Ùú$Ì ^;[xÖ잵Mvÿ«|MQÆ<ïß Œ¿~Ÿ¯\Ă ÊÉ(û÷HÒÆ•Q‚L!˜ÖëÇ2iãHyL Õ4éÔ…«Ø¢l5ëT‹o̘` ž|`#Bƒ^ÁŸ·œ”!Ȍ?5Êë ~•øÍA-íÏø »±‡PÆ¢ÊV¯¬òŠî-žóã5Ӎ¹ IÄ¡l†ØÚ:KYtÝäS[ñøêMáUBŠŽÇEyšHƒ²1N®ß)Ëh¡—rÛ>Pœ…­(o’êþD] bŽÍãçÂ÷ØY!ȐÈ#e®ÐÜã]„ãí9Ox§ Ý8zEõ“|&R‰×Ô³ÛEŒ‰OoÜÁ2ç±²ËâË~9¿ãöÌY)Ë@¡‹ˆï"'wÑöšD”3Þ{q`áZaà&²]€AÙ9-‡õ‚ y¶ž[ý1›Šì%Êb¢AB •M8ú§ÌKÜëÙ+œÚ°+š0C™=¶}:ŠL%2ÿ•²\ÆY§×ïO‘g£ïâIXÒo€,Öþ˧ŠÒš·/ß`fGç4Ó&=±ÏGjÏ~à ~„`D¿F©Jšžÿª-gQ°LêôAá…ÓĞxL€ €û®ÎÈ[®&Œ9C&u€ïʘPÀåƒø öNîè]5þ€…Ú^S†L­ :šiœMÁÒ÷Žú£"WŒ°°W}SRée>12O_bÎÿÍi]ÖÍAE⓹í‹;°cÚRÑZòmñ÷{‚ù=‡ ¿ò.¡A™òY%TbtÌk‹¬Œ†_Ã#ð-ò+Ÿ„}BH`0"?AäçpÑ *GŽ IDATGŸ< “cùR£˜å@މPÝgŒŒµeôíS…_|Kò3›÷àÀ¢u¢Œ•µîÓpïìeáÃbhZÏnÝCÐÓWȚ;'ÊZ˜Ê8ȗ§UiTm<ÈX¬q›"üg†oY„<ú„ïO–\ÙeÝ©Þû ֗÷×ÐóBm·É˜Ø­V+ñ5º–DEŸ‚¥ŠaãèYâZŠ…b¢! GòÏK’/N^kÐÔ€Ú7«ššëxrìXá'ƒ 0ehÕk(²1†™uÔwy0&À˜€jž|hBÞH9îµUˆ1³#â‹]êÌDsȟ%ƒ††Ì@–Ÿfaoû¡Ž"ƒD€–ÙÔÚØœv[ñRO€JW5• -~—nÀkh”×KŸ…ž@† Âd–e]9î›Gτ`@ƒâî·t²…$¿ ÊT3•…ÿÌ÷–­”Œ ºïä–N «ä]Cí·ÉG‡Ä%5[7‚UÇæ";I2Þ%/—õs£eÝŒží‡Å}=¢ŒafÂ»WØ;w•(Á’Œz%^ǎš×5îÿI“/mœw•l€!™·rë+:0y ›Þêwk³†V2Q‡ÚŽSÖ•BQ •RIÜGl_*|“}6nýç#Œˆè9 3”Ï6Zæ8 u;·Œ¶ºß2çÑÈY _‚-›Úû÷ȯ˜ÚŠo4*¢ÌœâÈS(?²ä́,9²Eó‘Œnh}21¶ë•eCYE‡–¬ž2ާ¡æFëfDlÉt9f''ɀ—֐2€èÏN”%SÙø¯mP‹kêjøô…(ãªPÛ"ÚÊ8šÞ~€0æ%AF>^ƒš’vf„œ“•D‘GO£Ÿ…I1eΌ=žVxà(úlйP֍QÊ(`X4Z<ÔB|åàñpY;û¯Ï:#þüß üüñ{†Ãé ƒ ¥ÝÏèßWMßW² “ŸÏŸwÏ”IÀÁÅߎ²¡Š}Oe.Ëk1&À˜€’ \9ìw¯Ÿ ™Ó(ô³PB†L” £…Z&Q/Ÿ<â'0äÔG!"T¬[e Uœß<áƒÒæ&Ȝ#ñ%it}ø‡0‘É’%gö8=Uš-ó÷oß “%³àög6ïþ$1 ä!C^2òY$JÐ/*“ÑÒɔ(®”•[ÛæD-òÿÉ$Êüøþ”q’¯šŸ¬¬'Ÿµ€nIޝæCz%Ê{FÍh}Œª6³F 3ÙíHÔ¡,ê&E£²]”¬RZÚÚÂoæþùk²ÏyÍD¡ÒÅc Už×Ճ'D(I “¿ˆ:^QT–Q"-•lÅ|~}6ââŠÌ3û—sN×Œºÿûö`ëŒéqûɲçUÞgQÈ (*Övä ™d!̋2ôC ›Û „EüDöýÓÏŠy§L€ 05$põÈ¿|„ŠN£1 ºÒ™Œše’K q€|ÈãïjâôÆÝ(b\FŒ@óˆ›À׈Háûò!ð­h­›-«ÈÆH¬à¢êŒÉ… r©Žê_Œ€É }ƒbšX»gȚˡqœL@E Ž0Ÿ¿þ€Mw7ÃbL€ 0"píèV„œFƒÎC1°†2dŠM›†êe€Z•žíµ"ØŠ œ8{ô"^?x‚ڝšËÊ:¹–ç0&ÀR‹ÀÆ“°gj;Ñgñ]Yg°a÷EäΫd”…”×aé–@÷‘óñ>äêwvI· xãL€ 0u píØV>}€öÎãУJ–xCVší5 2ÕÊV,È(tþ"ޱÄ'wÏ\By«ª(lTJ¡ëx`L µ¡ö¥ Ûpn›E*ó „©¯Aq[ö@‘"ܹJ™ly-&Þt2_kÀªMßô¶uÞ/`L@­PÛëw¯žbڔ‰šT0þ*řҿaešW­@€f°{_þœ¥¡_ºžh·Ìƒ 0& Ê.î>‚¬á!X3ÜF•ÃT»ØŒ¶žCÁBÅ`lłŒÚÌTŒ@끞ÐȔ 5[°p®bGÃá0&À¢ðÙµ ÞbߊI ’QH™>}:ª–ú +Ó| .È¢üüœ–œÃ³WïEk`euøaŸL€ 0ä °cÚŽol†A6œÑ§LŸ«·žCþBÅP‘eb嵘@º$Ðj€'43gG {.Þ4`jCà¿ sP8§MvO0fÅ™’?`eŠ—à‚<ၭgaÅñÇšÔÐ ù‹f4L€ 0•$þá#6›ïU.š”ý‡JÆš®A­Ù朂$Ètç’%u=DŽ› šÖ'!ƒ–jµrR‘ˆ8 &À˜ˆÀþÅcÐŽz) ìß/A@ 2SŠLAåßa]­P‚ ò„?þÇÞyÀGUtmüIo„œ7éœwB•ÒÔWÅ.(ššØ@Q°PTDA*œ÷ÞDz)„’PÒ럿3›Ý$ÈMÝÝä™÷ãËîœ3gÎüç"܇3çÝŸ‡wÚ T«‹žmˆ†H€̒ÀÙäå‹_?x •ÌÒGKuê×ՇQ²L4¢ c©[H¿IÀl {cbccÑå™)fã! HO òîøì^Šõ+c„ÇG4jdäÈR‹ê èÔ¬4yg‘Àw¿îÁŸûh=i,llm³8šÝI€H ï ¬ýê'tïØª÷“²–®>Ò•КsȲ­çr šš(|÷Ýwê×å˗QŽhÑ\'0fÆB„\G¯IÓsÝ6 ’  ä@¯Qêî”/]Ï<óÌcjdŸüòK4¯‡NÍÊ<Ö ;€'päŽVm?×öžp«^ƒxH€HÀ¬Üœ}ë¿ø;~圭ÌÊ·‚àÌokŽ D©ÊhԉG– Â~r $ð0L™2kÖ¬A‡ðÕW_¡iÓŠyê…9kqéèv ~í«<±O£$@$@9'pïßíšæ777ôïßÿ±5 2M«Ä³EÙÇd‡ô"£â0ý˵(Yœ »ô! 0+GVoAñžp,~«·YùUPœY¶ö(ŠyTBãÎd ʞrY#””„3gΠaÆpppÈÚ`3î}ãÆ ŒôÒKغu+J–,‰×_oœõVžz<ÿïSXòílŒûè×<‡ÆI€H€²OàþÁÅšW£<<<ЩS§ÇÒ$ȈÚ߀r4<[0‡Ìc‰fÐaýö³Øü*Ú?3ŸNµ²ÃcH€ò†Àª_bÞä®hÓžJÞLPÈ­þŸî(Ü<*¡ #d ù“Px—?pà@lذ®®®X¿~=ºtébÑ0.^Œˆ_|D… 0cÆ Lœ81_ÖtÁ?ÃFŒÄ˜–ÀÑÅ5_æä$$@$@Ú x$‡!üìF”*U õë×Gœzõ;8 ‚L<[”¬Avx”@@P8æ,ڎ®íë#²Q;܌c.>'$@Š'pùÈiÜ;zkæŽ6œ3ԃ?ÖCÑÑžÓ8T®\¹€®’Ë"Œ ܺu åÊ¥þcžˆ2’_¥|yËûûäÑ£G1iÒ$å͚5!/ ”ï[ߺ×0Žü?TªÛ,ßçæ„$@$@ÿM tØqwHÆ¥K—0zôh”(Qâ±È4 2+G¡ ™ÇͬÃÏ+á俟xþõQØóøÉöDH$@ ìšû=&v­‰!œù{È²ÜíõÇàZŒ"šPÉ2;°Lþþþ6l˜Ê«ââₚœ*5jÔÀªU«Ð¹sgìܹ¶Rè`ãÆxûí·qõêU%.ýñÇèØ±£É6ç¹7fâ.ÜÐþ©I&ó“  |žšÿ‰'žÀ®]»P±¢>B:11QEìÛ·O}—cG-[¶D±bÅpìØ1ŒüòËêú‰'зo_„„„ OŸ>ØŽiSºõܹsG‰1"ܘ²ét:uÆñâÅHHHP‘ž?ŸÊ}cÎMøÏ^Œz<ƒò5LŒÊœYÑ7 ÈVÖ }ó†ê ³TQP³ S¿\8ºµfYԜnhdTŠÎúµÖ:õΩ9Ž' ,?r·ŽŸÄ’/ÆÁښQzY‚—Î+7„C‘òhæÉ2ÙÀÇ!&" +&æÍ›‡W_}Uy%"ƳÏ>›ÎÃñãÇCr¯¬X±B‰2rügÜžqøå—_LŽ’Œ§ŒŒTëøý÷ßUrá &š<7Ö֖‘OK¢xž›ú¢<ÐyøË°±e€£Y=`t†H PHžy%"¯¢_¿~(Sú53Ð.Ȕ C·6æs†Vó Ͱã‰sŸ˜·dZN…„’–WúÑ ‘Ò%  œ£ïaÛó1uBx¶1ÏP| ˰š.«6„ky4g„ŒEí}”@XX<<<Ô 9Î$Q.Ǝ"àŽmÛVEÊHôKRRfΜ‰:<"ܘŠïíÛ·Õq«5kÖš5ŒôÒKøøãMåNŽæ]µ~+–n9‚rÕë¡~‡>9²ÅÁ$@$@Ù#q·öÿŠ7þ7VýùWºté,Wâ˂ ŠnmªeÏSŽz„ÀW?mÇù[Qh0i"é @Ÿžœê8%Çá£×µe}ϧ ø$m>[—òhÖy4ªTa”ißn‹\ž$ñ=xð P€*RÚ&Š”ª–£H’F^¿~=ÃcH_~ù%Þzë-ôêÕ [¶l1+â³Ty’ãWîîîêlÿ›oŸiV>fՙ˜˜Œøþ\„Ç$£jÃ6šÚ€GP³ÊýI€H §.î^‰§Û?ânEpúôiLš4)Ë&5 2’Э†G8& i™å 8 c"bð⌰oÔu»w&& ÈSǎc÷šX0kʔd•·<…Æøê-§`ãLA&¿xäyîÞœ‹3gΠS§Nê˜Mn4\äHў={”9É“6¯äS!ãœ÷ÞSIn¥„µ¡Œ§ä‡)Y²$äøÏóÏ?¯ª&I_IÚ[©R¥Üp/Ç6€Ò…ø/‚SùòåÕgKbÒBY¿÷4~]»M]ªÙŽ#*Ôjœcf4@$@$ À¥#ÛQ¯x2žêÑK–,Áĉ՟5Ymš9\¯Tºµ«žUûìÿNŸ÷Ã+s¶ Õ„Q([ “ù° ä RQ!Ø0w!Æ i‡~ÝåÍ$ޚ!5[OÃʱ,š{Ža„ Ÿ‘Ü,’£E*‰°ÓváÂUíH„iÓŠMÃG}”NšråʈˆˆÀáÇѪU+4lØ—.]RG~äˆÒöíÛÕø *`Û¶mšW¯^N]Ëñx FgϞU%«?ýôS :4ÇvÍÑÀ+6cïYoÄÅF£Zƒ6š\¯¹9ºIŸH€H @ð:µ®ñ·ñÆž*YçΝўqöDq͂LÝR·Ñœ]Ò3oå1,Ûë!oÿ¶ööæà} (`‚~ù îΘö2ó ä÷֊ ‡rhхG–ò›}A›/44TE€ˆâï﯎Þd·;wNåv¡E*)mݺÕªe|,]Ê[?÷Üs*úåâŋˆWQ2 #Müyýõ×U’\)emÊ&âørõêUU²ZþA±[·nŠt)_æþiÙjõºƒ˜žx+SuZwϗy9  FWNìFtØ-Œ?¡7¶lÜ ª ¶nÝ:Û(4 2’yŸvÉ[èÑ®f¶'âÀÌ Œ˜œ ·#ÑûÅ1ÄD$@¹J vÛZøyûáë÷‡£ˆKjÎ\„Æ2%°vÛèÊ¢…'>&9'0uêTU 諯ŸRÂCvZPP+DŒ‘E"eDèɬÉ1&‰Œ‘ãRsç΅ø |œŒŒTR_‰ ‘ü2Šlþù'ŠOŸ???4kÖLE‰Ï…©ý±úožxQ‰ÖHNJB6=PŽDé„€k% <%”˜€ 7#11cz4Ç©ý[”èߌyÎ"³ È¡G»'òt‘…Õø¥{<7}Ü˔Dç‘L¶YXŸ®›r›@ü‰ƒ8»ã>wªUÊü…+·ç¥œT붟E’}Ž€ ÃÇ"øúúªH9$Ÿ³“KF¢az÷îÎfÒFÜ8::ª¿`Ž3Få¬9uêZŽh‘a2ß\XV¶MüðêJRpp°Šøùî»ïРAƒlÛ³ô{Ưëw#Ùµ,‚üP£I{ToÜÎҗEÿI€HÀäBoúâòÑ(Y±:j–.‚ä s0`jÖÌyÀŠvAÆã&zޝerсd?úÚãçϖ rƒZh3èɂžL®‰H  Ü>~ÿ)㻢}‹œÿa‘®š©Öo?‹{ñnhÚáélŸ-.P@ž˜9r€J »iÓ&%hm"ÂHÿgžy/Œð‚ªž€¥I?É¿" r%Š~ýúZ†åiŸÙ³gcΜ9Rܲ®yóæ¡F «è’šyѪ-ð M@Rr2’“QœQ[”­núÜ>yúPÐ8  䁸Øhøœ9ˆo”«^wC1 a UQ°hÑÜ)’‘A&=Ú×΃eÒ€8á„->QØüݯšÙ¢Zöçù_>$@Ù#xÅ«WaÌ VУIöŒpT®ذã$ؔFË®<²”+@i'NœPÇq²Z^Úp¬(00PUcGáááHHHP¹_$*FJ_KŽ9ÎÔ¯_?•'f„ ªz„©›’jO ,@tt4† ¢rĔ+WÎÔ®™åü›÷ÁªÍû­³GBB]Q¹ns”«azAÍ,Ñ) HC@„¿K§à{þ8JU¬ kkk„ݺICz O§¹ÊJ“ #ÿòðD±ôìHA&Wé?dL`í¥øø«ÕšÖŽ>#eò6m“@%xåŒW­ÄèŸM1Œ_˺JËYÖß;ÿAœuiŽ¢ c9›fž¶oß^U=’<.iÃ¥ïß¿Ë—/g˜\P’ŠÀ²sçÎÿLt+%°g̘¡ìK;zôhŽ’æçƒðÎ;ïà—_~Qe¹åÕûï¿ÏªeÀŠÀ¶äïCØ~à8âb¢‘œœ[[{T¬Ýe«Õ…kñR¬°  á·ütíœÎ¡X© °¶±Åœ;AšÞ %Š ëŠê¹ŸQ“ #ÉÑjºû¡gÇ:…g7LžÒáxñ³ °«T íŸhòdy&DÁ©I€²@àúًØž£ú6Ã0Š1Y —w]ÿÞõb­J¡U—Ѫü. äõë×cРAxóÍ7ñÅ_MV¬X“‘è"Én%1¯[Úžq£ú»…···ª˜T¬X1•àWDCl©žŽzõjôèÑ#7\β[·n©õ­\¹R%ž4i>ûì3õ™-küï%áqþüø_9 ]²‰ ±p-^•ë4E‰rUTu&yñ(lM"Å ÓA§KVQcú_ÉêZ\t$윌×ÒõMN?Æñ)v’Ånz›imË€Î©ï—Ώ”ûríŠ÷ù "›äŸq³Ö2¡ýbŠ“ÅFEÀÑÅ5kÎz˺SZÖWô_Sê­E†ßA‘â¥ÔïT”`ÊOýgkXÉÿÒ\Ow?å^úqÖFÈð~š9`øœ:&-ã}œ±Ñp*â–âuÊûŸþÞ£Ÿ+ύ׳Ÿ£„@b|ƒývÓ!>Hˆ‹…œ£3’““`gï€ò5¢g‡x²NîOʈºfAŠ†Û <Ù©.w.ŸÜ ‹ÀŒ¯ÿF€­ê  Û¢Š-%™OËæ4$@Ù$pyÿÜÙ·“žn‡~ÝeÓ ‡å6»Î!F 2£(Èä6ÜBlO"EäØQLLŒJhëìì¬h™Y³f©ã=†&ǐ<<<ÔQ$i"nHBÜ»wï>RaI„˜_|o¿ý¶jò»ùøøà7ÞÀ† T¢áW^y|ðA~»QàæKLŽúÇáT` B¯#,ènúœÇ?o$ëtHJˆƒ{©ò(Vº¢úéæQ®%J¡ˆ[ Ø9êŸ/iº”Œ4ò²"ùi€¢“Dâè’õ?Õwýu‰ÈQ?ßÓ|–kÊFúk÷CƒQÄœ„QÑ,t$ëE”dƒ’œ”â°AdI@”ð‘œ"‚€yA·’tÃ˹µŒ¬Ë;»Mšbý}õKî^ê6Rî[§}O3ÆÊpÝVֆí4×±-}¬|ýRseRMô‚l?é©#EH#qšZ–'L? Kí€dŠ•4ŠczÑKùŸñ³Q Óß3 c™ôÉÜFª§ú§øš‘Ÿª¯zÖe˜.cQé!ÁG/6¥yÆUuŒÿ|€¿²‘~Œ<÷1‘÷áRŽžþ÷µµ:ÎceeóÐw¹g£¿gì'¿ŸÒŒ1ܳzšŸê£·go%ŸSç;ú{iúm믥m"ŽÄF=PŸËsq/$P 1÷ïÃÁÙ6¶vê¿ ÅJW€G…j(U©&תŒv•àá’Þ–Šg= 4 2Rb±†›/z{ÞÌõY`šk]cbãñåOÛqÉ'œFõETå:ˆNÊÛ"ל§! |#pò¯¿wù_Œó|OŽnZ=ßæåD'°i÷¿ˆÒ•Dë®dO‹=²B@ª ÉÑ9Ê3nÜ85ô­·Þ—_~‰.]º`÷îÝFs¿ýöƎ«ª3I4Ã8t€Š’ˆ6r¿Q£F&‰B9wîœ*åœoß>”(QB B¯œöZV°¯÷“ŸŒšx"ãux›·‚qëV0ü}}€ÈðDÝW//’GA„§"ˆJyKyÁJ#L^² /|zÁA^ÒÒôM$ô/o©â…Qà€bc¢àäRTE!HÓ¿3Z:±§®€FŽ#€‹ÜqCþ¿¬mm•8€3ؑ¡â“ÜU i# võ?õ*…zMãGŠ ^Rê—Ò_ß=µŸÑŠÑï”qZû)Wµ'/úz~©ö2ò9?)ëzÄ÷4kÔÞ?ƒu€ØÉØ~úþ‘`kŸA€›]Êsœ*ŸdŠ¥éñˆR“t“–çÿWš;Çÿ¡ZéçHŒQ‘Tú–ñŒ~kŠÆ’IK#5š(MtÑ#¢RŠ8ô_¢’u2Š€ÜLª‰‘(mYÔý08¹ºJØLÖ ¡òY۔kª¿ºŠ@¿Â¹\ IDAT“uIz*íwC€XÊXe+E,M¯ŸCÿÝ ŠŠÎ£„X܍Õÿ~Ž‚”«¶sp„œ^áâVE=Ê xÙ*J–ˆÁÒeÊÃÝÍÎvVšWÚuJÚiÚºœvÒ$Èȑ%džìÄ í9žñ¬?† ;ÿg»zhØ»ÎÇ:!’ÂLvPr (÷ï„áÄò5šé‡é“û l)÷µŸ‚°˜Í{þEd2™‚°—涆›7o*¥iÓŠ8}úŽrï… ƲÏRZª)Iu€þýû+!fïÞœ*ïñãÇáéé‰ZµL_=óȑ#Jˆ‘5”)S~ø!Əonž ?"Ò›8buHHˆGRb"¬ml`-BFÚ&ï;êœP/€|LÓ#Ýkuº÷U]º—Wù–bAæ0ŸuZé# 3h‘ÈìŽ>bA,ÉËŠþ§œ,RÕÿ¥ÿ™rÅè‹D©ÞßäåPü‘Ÿúúû†—ÙÓiç3ŽU©¶ÒÍ-ïÃVòâ™ÞWÃÜòò)/šéçL?¿áåÞà³>úÂèqýi×cŒÌ}Pe‰<ÒÓWÑJ†Šáed—ÂÀÈ?eúh‘ÔµÄˑǔg$¥wú©Œ ORºM5Ø3ngz[ižŸtŒ²aìfx,Ò\0<éöÔyâ‰JDtpJE–æYH?þ?4—‡€Ã¯ŸêžQðKgøaÁJÿÝ(ŽÉðtâ^Ê~€ŠêÒC¢¢^M霯Ž>z&õžü^0^ÓJùn°©S¥ŸŠ?3Fè€ô5 ¯éÅWU•h›fŸÿ:úeì¯ìÉIrD3öŽŽp²³«“Š8ÚÂÅÞ NvVJ|1üŽ·Ñð˜‡75Ÿkdª»]G¯NÌ̞ ̳eâ¢WæýŒ ¶¶6xvtĕ«†£r®5[æ8ˆHÀ œÛ}—wìÅè.Oà• Ý,|5×ý-{Ï#"Ƀ2w‹óte"V|ôÑGŸ-ZŽPŸÛµkgœsĈøóÏ?•À"I{¥=ûì³øùçŸñK®/^Œ8Oý͊ñ;vš1W®\Aåʕñù矫Œ8l$@$@$P˜hdä_Yª¹ú WgY2å×€¥«`ϑËhÕ€:º÷뀫¶%q#6©L¹vÎM$ 'pÇ?G×oƒ}Ô}|4®Ú6¯A4fL`ëÞóžŸTmºŽd3Þ'stMr©€­ dðQ’ÝJ$‰4IÂ+—ºwï8€ÅÅÅ)qC’á^ºt ’æÕW_UyX䚈©ÛºuëÔq$???Ô®]_}õ•òŸH€H€ # 2žë×üB°hÅAøø…`@÷FšÒ¡Î&º#>Ù4aVˆ.“€ÅˆŽÁñuÛá}ê_ôêÞs'¶e6 ØÅ­û.à^‚Úv£ cÛe6.ʑ„®]»ª|*r$I"I$FÝJ®•† }mÓŠ Ž;†U«VaèСéÖ '''ØØØ˜|mµ#¢ä¬‘5‰#b   fš™ùó¿E—kLêkfOÊáS>XŸþ8î„G £gxŽn‹@kVc2³m¢;$#q118œy.=‹: ªá#: {5—Ùäàü#°mÿ܍§ “Ä ÆLDǎÕb$’€R¥Jª‚MXX˜*O¶IdLϞ=Õ%ÉÓ¹sg³‚0wî\U®Z*:ɚ$é°2l$@$@$@’2ʘ]*só¿ûU\ŒÑ»Kê¿ÈžùØÌ k¶žF@Pj6«÷¶`_¢€ù8HOH€²L ,0ÿî=ŠkgÎã‰zÕ0~PK jè‘e;`ZÛ÷_DX| Žc„Œi7³GEEáâŋhÖ¬YŠ*Á"•’îÝ»‡)SŠ I“&ÊÓwß}W‰R=Iª!=®ÉÑrÿôÓO«£JŠn *ZG"|€ÔvŸ>}ðÅ_š#Jl$@$@$@©Ž 2ó¿Cegoô¡ cÖÏιKX¿ã,Žÿë‡2eQŒqcÔhÑvööfí7#ÐHNJÂå#gàsêD©ÓŒ.&ôkŠ>µŠ‘…Øqà"BãJ m×gP­Z5 ]Ý΁aÆ©cDO<ñ>ùä 2ä3 ,ÀË/¿lŒþÏ?ÿš²ÓÓŠMÃìÙ³UÅ¡3f<2.11Q‰=Ò€¿4ooo•×ބ拰4sæL,Zޱ±±>|žZ‡øÅF$@$@$ð(‚Ì·šììCAÆBž {¢!‰$wõÆõ›á(_³ ÊÕ¯ƒâÃÞÑÁBVA7I pHˆ‹Çõ.Á÷Ü%]œ÷2šÓŒ>^êßM‹&x•;^˜âhۍ‚LÞæ —öÒK/áûï¿W÷äHѶmÛÔg___©jIRŽzãÆÆñ"ÞHùgÉ3iÒ$•Wčƍãúõë8yò€Ê³uëV5Fî?xðÀäh¥·Dú,[¶ %J”PëªdIFëš|sè  €YÐ$È,Xð-*9Q1ëÌĹÀ[áØuè2Nœó…—ß”*W ekTF‰š5àòDm$èL_qÁ¹ÒgÈ.‰‚ ¹ÿË>žåí«"aÜJ•@ź5Q«e# xÂ͋Äf×<Ǚ]‡.ávT1Žë>’2f¶7ùáŽבˆ‡Ô éÑ£vî܉ýû÷£oߟêH¿¿¿Š†Y²d Fùóç£^œz ÌÔMc€ß˜1còc)Îáåå…éÓ§c͚5*yð /Œ ª@™Ì1NL$@$@B@› 3?EéÊ2²¯º'Œqæ‚®\»…[·ïÁ£ŒÜ˗kùòp,WÎ+À֎eŽ-yŸé{î°·ÖÁÉZGë䔟ò=ŽrÍ*ó{‘qI𠟇Ë>·põÚmøøÝF@`P¹jYÔª[šÖ³› tVhë“ûÎÓ¢I ˆ ] í!cÒ}ÈÊäÑÑѪ&µjÕBóæÍU4‹|΍¶páB<ÿüó*ºEÄ©˜$•“$ïŠ$œ•ZˆyóæaóæÍPÑ&âG‡кukÔ©S¶¶¶¹áR–mœ={V«ÚµkœñÚk¯)aÆTþdy@$@$@fB@“ óýüoQÁÉ})Șɶ厑Qq8sÑ—œoáºÿÞº‹›¡°wqƒ»;lÜÜaã^ ®ÅÜQ€˜\Ü]áìVŽE\`ckúš¹CÁ¬XRÐ<õ—NÿùáëªêyÊ=CcŸLÆíèãšÆ¥ŸKÏÆ8ÃýüÿåçCkK3Ÿqݏ°ŸÃ$eáiÛX‰ø’*ŽdG–˜˜„èØÈÁÐðH„„=@Hèßy€Û¡ú_"¢akcƒòeŠ¡j%Ô®^MêUBÙR¬†f¿órÅÅU›N"$Ú}‡<Ï™\!š÷FäèÍÇüÈDRhüøñ*qîՎçՁÔ1%É©ƒÒ¥K+1FšrŒGڍ7”@#÷:€sjâ“ø{âÄ %(‰óꫯš“‹ô…H€H€,Š€&AfÞŒ¹(ï胧z²L¡Eín6œMNÖášÿø†"0ø.‚îDàFh‚ïÆ","±1qHŒO€µ5ììí`gg«þEL+XYY«—rkk+X?ë¯Y©kVHLH„ƒ£ƒú¬ú¥ü²2~·No…€„$88ÚÃÚʞŸ¯5¬­œ]õ=庵lRìÝ»’%ÝUë”ñ6âö¥JS€ØCòÒ-/ïÖ"KÈ÷”—{±¢Eœ•b¡ï'kµÒ7ô“yRîëÄ'œ 6€EEÇ!ü^ª”÷P¶ÒŠ,AÄ`:ZŸ±é¬ ³JNt"Aè”ØØ8:<Õ$w­Ä„цT ‹@©®êºN,H7ú€·§’’S]r2’¥‹Ny.’åf2¬KVãÕ5ÃgePŸëà/y‹J»K×TÉ:%\žq„.Yæ›2$9å§~¬Ìe˜Oo2Å5WÊœŸ"£ãàìhÐð”(VD?.ÅWýXéŸÉødý cÄ'ýZÅ”pwÁ»‘F’’’‘˜„ø„DÄÇ'BŸ \{[žº8­šŠ»Q|˕vC¥ò%P¥‚‡²ÃVx ì9rAîhߝ9d,å)xê©§°nÝ:%Œ|þùçžvíš:bŽaÃã6mÚ€*im›Û·o‡YJ›_ÆpÍ`ë̙3JärѝcM|!æòåË(^Œž¬€   @ÎhdŸ_ð-Ê;x£_7}&¶ÂM@^D£b⋚˜8%ÈKªD $©býK¶þgšÏ)/Ë÷#bàâh€”zyVŸÕ/ýÃw0ímSìŠôIyiÖ÷O3N^š•ˆ ¿z7îE•œtB2p?"EÐëFqB/Jè/êE ý‡˜ž8ÚÛéû»è_ÜõßÓ\·2˜ÈèŸ÷Ä(¿”“f>% ˆH“Ö§”š}숟É'Ãgù.kU¢RfM¯Íš&<]œÕ$ê’(>iîË%;[k$%‰’£±”˜Šš‡ê6ãõ¡*ì^”%”Ød"\YY!.>A (âkªœTOä-}œôŸ•eðC‰j©ö""õ%2¥ŒÞô" ïD„K'øY+{FñÎFÿYüOýŽÑ }JðKþ plm¬`gk;89ÚÃÅÉÎÎöJ³µ2!°÷èÞwG‡d,å!yñÅñÃ?`ñâÅxöÙgn‡‡‡ã·ß~ÃÔ©SUäŠD‹hmÒWŽUšPrÜçʕ+ê»4©–T·n]­ŠòµßÚµkñÞ{ïÁÏÏe˖U‘úè#ˆo±±±hÕªf͚e(e«ßÿ}&›¶€M€¯$@$@Ž€&Aæ§ï¿E)[/ 2nû¹   Œ$pè€|SOæÉKιmû믿VQ#Ò$¹¯DÉHÔLVòÅä¶OÙµwêÔ)•fÛ¶mJˆ‘²ÞïŒóŽ*cÍF$@$@$`Zڙ桀öhbZo9;   XÃ§|àu»:?É2æžmr|çï¿ÿVùaŽ9‚:uê }ûöèÒ¥‹ú)In+W®¬¢e€_¿~ýÌqúŽÿ~•¬÷رcêþk¯œŠ »»»[Ìè(   tš™…?|ƒÖ^Ô³iAçÁõ‘  @®8rú®Š Ù\cš[†víڅ§žzJEÀdÔ$ϊD’,ZŽÏ=÷œŠ’‘c?...¹åBžØ‘DÃRºúÒ¥K°µµÅ»ïŸ‹)SŠÀÑÑ1Oæ£Q   ìÐ(ÈÌC ë«d²Ï™#I€H€ !£g®árpxR1«Ý?~ü8Z·n­|êÓ§ŸüòKÔ¬YS}ߎi“Jt+íþýûJ€ñôôÄÁƒÕq)mŽí¯¿þR1þþþpuuU ‡'OžlŽ®Ò'   FÈð‰!  ¬8væ:.ÝrAçžÃP£F¬gÿ< ‡ŠM›ªi¡¡¡(Q¢Dº™*V¬š*+ÉQ¥’%KÂÏÏ-[¶Tߥ\Ž”Á6—öË/¿šdœâWÑ¢EU¢Þ‰'š‹{ôƒH€H€Hà?hdýø ŠÃ ƒžä‘%>M$@$@$ •À±³×qñŠ <Ÿ€ £•Y^÷[œz5†ªŠÉ(âåâŋš_¿>:w{÷Ý ÂéÓ§Í&Ìüùóñ駟"&&R†{ƌ9rd^ã£}   \$ Iùìã™p³ºŽçGvÊÅ©iŠH€H€ 6ãÿ\Çù@t¡ c6-1õêÕSÑ.Y2}út£oW¯^Eÿþýáåå…U«V…sq>::ß}÷>ÿüsèt:•pX„ɅÃF$@$@$`y4 2!S ^xŠ2–·Ãô˜H€HÀdNü㋝)Șl2žø›oŸÁÔ©SU¢^©®$G–Ö®]‹Ñ£G«’å³Ï>3¯ïܹƒW^yëׯ‡”ähR¯^œÌÆG:B$@$@$uš™Å?~ 77÷⑥¬#æ  ÂJàä9_œ pB—'‡3‡Œ=RY©nݺ*OÌÃmÖ¬Y*jÆÊÊÊäßžq"ITŒ$!Fª?Éq*6   Ë'@AÆò÷+  0S§þœ³~Nèڋ9dr{‹$)ï™3gTþ”öíÛÃÙÙ9KSȑ¥—_~Û¶mƒ$ñíÑ£^xáÔªU+Kvò¢ó… 0wî\,[¶ öööèÞœ»*_ݪU«Œ˜Ž6I€H€H€LD ‚Œ÷jf"79-   X 2¹¿g 5j”Êñbh-ZŽÀ®]»T•!KnRŽ[JpoÙ²ÉÉÉ2dÞ|óM4jÔȒ—EßI€H€H€2! IYòã×(ª£ çˆH€H€²Bàôy?œöuD·ÞŒÉ ·ÿê+‘"†ü.O?ý4öíÛ§ôJ4‰5–ØöìÙ£õ;v ‘‘‘xî¹çTŽ›'žx—CŸI€H€H€4Ð,Èž&_ŐÞÍ5še7   3üpêº#ºöz5kÖ$ž~ý:ªW¯®¬:tíÚµƒˆ2ýõ—4Þzë­ΐ¿Ã7nܚĥ˗/ãÁƒJ„™2eŠ:BÅF$@$@$Pð hd~úE’®b(™‚ÿDp…$@$@¹FàìEœžæ€nd41ŠŠÂîÝ»•xU§NGÆÌ™3oŒñ†Êõ"Gy.\š„irܧe˖šæ1u§+V(!&((²fY“1Švó“   ä#‚Ì\Iò¢ “éH€H€,ŸÀ?ýqÜÇÝz3Bæq»yøða >\U>’$¶;vìxdˆ”¥þý÷ß¹.Uˆ$A¯¹·Å‹+!Fª<ÅÇÇ+QIÊYK%6   ÂG@“ óóO_Ã%ñ*†öᑥÂ÷ˆpÅ$@$@Ù%ðÏ¥ó¶G÷B.Èȑ:uê€ò£ž¹¹¥CºråJ%ÆH“ªIóæÍ3~OÛ±ÿþc>"ØHr_)]Ý·o_ôêÕËØM’á._Ÿ\U]zê©§²»u¹6N§ÓáÛo¿Å_|€€$e÷í·ßVBŒµµu®ÍCC$@$@$@–G@“ ³`Þ§pNôÁØÁm-o…ô˜H€H€LDàÜåñ²GB.È|üñÇxÿý÷Õ.žººâʕ+(W®œúþÛo¿aìØ±êó AƒTrÞÌ"F<==U_c.™Ž[‹gŸ}V 2;wÆÞœ{MŽóPQ0¹#U“áàà€wÞyG·b#   ! Iùå§¹pNôb„ Ÿ  ȁ/âðU;ôèSž,I®É÷"Ñ+7VQ-öööغu+z÷öéÓëׯ‡­­mŠ„%ºfÑ¢E£KbO„C»qãƌƒƒª(IúkŠDÊÁÁÁJˆ™;w®Š*V¬˜b ¢Sv%  (à4 2?/œ—o 2üaàòH€H€r—Àù+8t…‚LfTEš0$å5ô©P¡‚:ndh"jHŽËóÏ?;Ú·o¯nÉq¥Áƒ£L™2ü3#MJE‹ÐS­ZµÜÝÌÇX»ví&Nœš"xJ–,©"€ŠM›Šª@±‘   @F4 2ÎñÞxº/sÈð1"  ­.\œ‰ƒ—mУÏ0“Dkhõ3¿ûÅÅÅ©#<çΝÃK/œ€•Ç59êtòäI=zãǏϰ»T*š5kŠ-ú8s¹vÿßÿU9b乕Ì+Q9ïŸû.úõë—ksÐ   @Á$ Iùeá8Æ{c™‚ùpU$@$@yB@™—mÑ£÷P¹Á%\ˆ³gÏ4o®ÿ‡žÄÄD„……©$·îîî°±±Q p%q¯Dž4lØPõ“|3r\éöíÛjüéÓ§áää„víÚ¡uëÖjl~µ#GŽš£I›6mRǯ€äök¯œŠ³‘   €YdŒ0¬o -6هH€H€HÀE¯ ì¿(2…Wùä“OT.a¬¬¬TŽ—Ž;ª#GgΜQ‘25) -ǐ$°”–#HǎSǁLÙvî܉oŸùFù"¢Q·nÝðꫯR™Ò7ÎM$@$@$`YŽ 2?́cËÚZzK$@$`j—Œƒ°jÏ]Ž÷ì…=z˜Ú|Ÿ_Ž$I_i3gÎÄ| >ÊWK’ÞŸ~úI]û믿ðÞ{ï¡råÊ*RfûöíFEŒÙ²e‹ºgª& ‡%QïÕ«W¥JjË)C”©üâŒ$@$@$@–K@“ óë¯àç…aýZZîJé9   ä3Ë>·°çŒ5z¢™Ý»wãΝ;6lfϞéÓ§©ÿþûï9r€*[mš€$ý»té‚;v gϞévH¢bÞzë-UÊú¿ª/å嶊Ï"ÄÈ1©ÐÐPU-é•W^AœzõòrZÚ&  ((È‚MæI€H€LCàŠÏ-ìú×Oö-G–Nœ8V­Z)Ø«V­R%ªåˆÏ‹/Ÿˆï¿ÿ^]¿yóŠª@ôᇪˆ[/^¬î]¹r/^Tå¬%FD9ædŠ&‘;sæÌAll,T4Œ1ù]œÉkçœ$@$@$@ùC€‚Lþpæ,$@$@…À•kÁØuÎ =û A­Zµ ,)3ݬY3HÅ!CR[9ftéÒ%Hu$IØ+•‡Dà0DÃHÂ^c*V¬ˆÏ>ûÌ,؈O’šW"b$"çÖ­[*?Œ1""±‘   @nÐ,ÈØÇya8,å&{Ú" (à®^Ǝ¬ðddt:Š)SЌª,$MJXKDKÓŠM•À"É{Ó6©Š$ՑDì9PŸšH€H€HàñŒo„`ëizYh„ŒT’#GÒ€lµü2$Ù•è’ *š{ÁÁÁ*ªDùJ B`` >¬DS%æ}x‡–/_®’ ¯\¹R»²³³SBŒ”ßf#   ü& IYºð %È0B&¿·‡ó‘  X2“çn`ç?I2llºs[ÓÙ³g±wï^?~\  6D:uԑ$9úwÌÆ IDATÆSªT)•;Ɛ7ÆàéÒ¥UŒô‘šIì+-99ÙlDñçàÁƒ*"F’ÇÇÇ«Œ0’¬w̘1æ¶ô‡H€H€H Ð&È,ú¶Ñ>1€G– ѳÁ¥’  äÀuÿ;Øx"œú6KA&::/Œð–-[öÈJÝÜÜpÿþ}u}ƌªLuÚ&yeúöí‹gžyüñ‡ºµpáBØØØšäŸæÐ¶mÛŠ„˜3gÎ(1IJiK$ÏСCÍÁ=ú@$@$@$PÈ hd~[ôl¢œ1b,òç…Ë' È߀Pl8šˆÞý‡˜¥ óÓO?)AFZϞ=1yòdu )22ÕªUS2U"‰{¥dµ¡ýùçŸ*GŒ4IÞÛŒyó,PÉû®«W¯VÉz}}}‘””)Á-G§D@b#   s! MYø9¬c|ð sÙ7úA$@$`ün†aíáxôé?Ô,™Þœ{cëÖ­*‡Ê?þøÈ1£5kÖ`Ȑ!ŠôŠ+ G”$fɒ%êÚÚµk!I}Í¥-]ºT 1ááሊŠRɄ%"Š[·næâ"ý    #m‚Ì¢ÏaMA†Ï   d…@@P8VˆEßCUNskžžžØ·oŸ[†þˆ{]2xð`lذ!Ý=‰¢‘„¿:u2‹%Iµ€yóæA§Ó!44².‰êi×®YøG'H€H€H€H #š™e‹>‡>A$@$@$%7ƒïbÅŸhôðŽIÉ3wî\9rD ’t·K—.èÓ§œñôÓO㯿þÂüùóñÒK/ež6eäh“7å˗GǎÕÑ©PdÊ«òÈSŽhQHÕ'‰Ö‘£IM›65¥kœ›H€H€H€4Ð$È|õɛ@Œ?^›Ø]“Qv"  n…ÜÇï»"ѐi™ñãÇã×_}d+€Š’”~>zô(&L˜ òÆ\»ví‘*J枇aaaF!Füööö†¬SŽ&I®6   °š™e‹>¢|0r`kKYý$  “ž}ç~Ýù Ë÷™Ó§O§K¶+ÉwoߟiÓŠ©Dœ"fœ:uJ•¹–&‘4S§N59³ÌðóóSùa$*ŠvíÚ8þŒŠ†‘_U«V5[¿é    dF@» 郑ƒ(ÈðQ"  ­BÂ"ðóÖ{øÔ°|ÞÈ‰‘&ǔvïÞ­>ÇÄÄ J•* ÁâŋñÏ?ÿš#KÒüýýQ±bE­Ë˗~—.]RBŒ$–<<^^^xõÕWUDLÙ²eóÅNB$@$@$@yA@³ £‹ôÁ( 2y±ŽI$@$P@ „ލĢMá4xxŸ 2iKZKrÛC‡)KU¥E‹aÖ¬Y:4µÔÞœ{ѹsg³Ø ‰è!fýúõ*& Àãîîn>Ò    È m‚ÌâÏ ‹  “ÐK$@$Pø„ߋÂðÔÐüd®_¿ŽêÕ«¡¿õÖ[9r€Šˆ;v¬º~îÜ9H>ù)å¯_xá˜ZìäÁr,I$9N%Ɉ%"FŽ&988Ÿ‡ˆ+&  (°4 2¿/šäÈkŒ)°F$@$î=ˆÆüµw0äéù!#ëiÔš‘Ê“Q[¶lF•ËΖÍ͛7ã³Ï>ƒäŠqssSG«D„™\  @žˆŽ‰ÇË1løH“2²(©Ž$—~øácêf(]íììŒèèhU)I*& 2ÄÔ®q~   ÈW™O‘øàF?EA&_w‡“‘  X4ØžÌþÍße2AFÊFËq© *š’Ñr$(¿[TT”І‘£I"À„‡‡£f͚*"ŠOŸ>ùíç#   ³  Qù ®c ³Ø4:A$@$`ââñÉÒ>bêׯo2§¥ºÒòåËññÇ«œ2ùÕBBB”#bLíÚµqóæM4kÖL 1]ºtÉ/78    ˜% 2f¹-tŠH€H  HHLÂGK®cÄÈÑ&dD‘iÛ·oG=ò¯¯¯¯bäW«V­àããOOO%ÄŽmÛ6OçŠq   °š™å‹?Aüýë3˜G–,ecÿËO]‚I¡I°-k[–Ã5 €ÙHJNÆÌ…>xfÔ“ 2hɒ%˜8q¢bõ÷ߣ_¿~¹ÎMª8I4Œ”Ô–Hù>hÐ %ĘKU§\_4 ’   @6 hdV,þqd²‰ØtÃt±:ćÄ#Ì/‘Á±H O€Í+8ÅÚ ˆ`oÛ2v€UŠ)?­Ò}·‚NýÿÔéTu œœŒšø8;اŒ€ºŽ”ûê£Le°/ߍŸõsHSŸTg+À*底B""QÚµ”ilè/ õºú*cõöä¶UšïƏÖ)]¬¬¬l¬ RlÉXk52 #ƒÑÿ`&óY‘±qpqt0ú’ÞNêøGì?ŽF K2®+c_ÞOãzÓr2<–Íg'X‚t S8聊À}ˆ­µyš=‘KFÖi`Z¥°M“~¿ŒgÜ ãs™ŠÚ}•ûò Y[§wÚ8Ît¿9s!& ÓÓŒŠQ£Çš\‘m˜={6ŠM›†ŠM›âôéÓ¹¶3ǎSÑ0Û¶mSùjNž<‰qãÆ)!ŠN:¹6 ‘   @A" Qùq÷}!cÆ;//‰A ž~5›ŸÇ‘«×àsçBc¢`me¥D“$]2““ÕÏØÄD8Úê#dä…ÁÐRe‘ñDuxH|ȀCÊ«5ìmlŸ”€zdþ"l”fŒ†Óê+™av°±E\Rb–v!ÍÒ2—É]]šµg2›Ñßÿp\¬žÌ8€á“•…d:M:5Go1³ŸSÏh~{[Äg‘qVÖñp_á“ö™{œ-=ÓŽÏkúN6vˆIJxœ™Ljy 3˜ÅÎÚ Éúç?íoÇ:”ɈLŸßŽ7òU~?Ë%ù=îêà'g{žwFéREQ£R)4mPMëWBeáäh¯Ý5öÌ6i?zaäÈÑhРA¶mäæ@‰Žqtt̕cK»wïVBŒˆ;U«V…Š„!FÊm³‘    dN@› ³äcÄݓ#K<÷mŽSòÝ$|3}þ<}~wáîà„zÅK£aÉòhP¢,J9»¢˜ƒ\ì ¢†•îÆDÁÞÎ^”h AV°†>H$åVúëiecމ9‚ÈcŸôïÀzµ&íû°ñú‰[)â“`g“"„)séåˆÌçH1U@Ë`lÊÍÔh£TŸïÆÅšg#mËH I+Ð¥öÍ\6Qs¥SÒytSŒ]u:„ÄD¢”S‘ôÃS†<2c&BY†kxŒOihŠÎœjéfä}”wuO#Ü€HAi‚ƒ á]©YVHLN‚ˆ2ª¥D‰Õ”x!£H™ö»QžKqJoO/U¥6«t§Aè3D¿§QO#âã”øz3ê|ï‡ãºý]øD„ÂûVˆ2›””Œ–«¢WçðlS •Ê—ÈãßA…×ü{ }0lØ4jÔšÀ@ذaƒ:šäçç‡2eÊà̙3J„yöÙgQœzõ³N.„H€H€H€ò’™Œ€›¶\²s؉ĄDô­Zãë¶Bå¢ÅóafNA$`‰l+ÛÃË1‡C|ñ×ÎÓÐ%럐ˆN­kaXßhÑšª%.ˬ}ž±è:Z ršH¥&9ö$Q—îîîž|ù²b䗛››Yï#   s# Iùú“W€·^èenþZŸòÁŒ¯Öãò¥ Œ«Õ o4ó,Ž,žp ¬°r±†C}G싞†•ûN!ônâѺY5Œ2ŸJ+’u£‘!™Kn`àÀA*É­¥¶… ªˆ{{{DGG#""B‰0SŠLƒƒäÊb#   È*M‚̊ų{ßcyd)«|ó€ÿü¥{°lõQ$„'`NëhT²\žÌC£$@…€€µ•f6…]Â÷÷£J„†G`æÔþhÉh™\y>üÙ}ûõC‹-rÅ^~IJJRùaDˆ)]ºŽŠŠ UBÌäɓóË ÎC$@$@$@– ÛÚé_¬…o@(ü.ÜÁœ–ðD±R¶ºK$`®BKÅâ›sûeË>·ðÍÌáhÛ¬†¹ºk1~ÍZˆ^œz£e˖áóýû÷•#bLíÚµƒØØX%ÄÊf[ÄBè$    ˜9‚ÌGˆœƒ2&ÞÌé_®CRb2Ní»Ž×jwB벬`aâ-áô$P |í³WãCq'.?9U+•,ë̯E}ü[ªhÔºuëüš2[ó#bÄ×ððpØÚÚ*!fÔšQÙ²ÉA$@$@$@$@™Ð$Èü<bïûㅑÉÒD~úc?Œ|oAIšUcêXV軉°qZ løúÌ>œœwe«ºcÑOã³i…ÄÀ'Ën¡k×®hÛÖ<+z{{+!fÁ‚èÞœ;nÞŒ‰âŋ+!fðàÁÜD    <" IY±èÄ>ðg„LmÂã̞»€7?ù Ïvk‡uËOáû.C7„÷I€H ÇÞ?²Ã1¢~3ŒßŽ­œsl³Ð°²Âì߃ѩS'ŽoßÞ¬–öìYu4iõêÕÊ7T©RE 1}úô1+_é    Dš™žþÀŸ&yŠÌ\Ï6µðǂ#x¶z+Ž*SÙ$~pR ÂEà^\ Ælÿ‘ qØÐo\íPüÍR€Má␣ÕZYãó巕àÑ¡C‡™Ê­Á‡R1T•Ÿ.\ž€F)!ŠK—.¹5 í    <†3DÎ\ðÃgßoÅÓuš`王˜Ý®¯™{L÷H€ œÞøèØvŒ«Ûcë¶D±W<`åd]–˜·k±²Æ—ÞQùc$JƔmûöíJˆ¹rå êÕ«‡“'O*Ÿ€tµ¹§2%/ÎM$@$@$@yM@› ³p&â"1fp›Œö‡ö"ðñw›PÉ¥¶®:‡1µ[0:†O @ŸxuÿZœ ¹‰ýC'Ãý…°vgˆŒæM°²ÁW+מžžš‡åfÇ5kÖš£IaaašZµ*8€ªˆ˜&MšäæTŽE$@$@$@$™ˆ‹žIA& `s«k·‘sðJœŽøeÏQ,î6<·ÌÒ  h&p1,c·ÿŽÏ;ôÇS3[ʔ­æ±…Ÿ£µ-æ® U‡$öÍÏöÛo¿©ˆ+++”+W!3~üxS§Nüt…s‘    d@@“ ³|áûˆ ˜§!“ŸOÑ¿—ñÙìÍx"ŸJ:ÁˆZMószÎE$@F£¶-ƒ­µ5Öþö2l+ؑŒVÖ¶øfu84h *åGûì³Ï°téRxxx X±bØŒy³a$"F’ö²‘    ˜ 2æ±zñÇGá³-‡ü®anÇA(_Ä͌œ¥k$@™ÀNÿ«˜²o-|Ö| ×:.y©¹»6k;|»ö.êÖ­‹=zä®í4ÖbccÕ±$‰ˆ©U«|}}¬Dcʔ)“gsÓ0    @öhd~z Q·0š2Ù£œÍQ3_^ »pàßÐ üØåélZá0 È ~ÿßL}CŸm•; ƒk{|·î®Iž|òÉ\_±ä…FĘ6mÚ@§Óáĉ1b>þøcž¹QÈÏuè4H$@$@$@¹D@£ 3 QÁdr º3qçcñÒ;¿£šƒ#J;»bR}Ӎ}H€òŽÀèí¿Ã£ZQ,]21ï&)h–­0ý]ÔšQœ{÷εÕùùù)F~õêÕ ÑÑÑžté’1"ÆÁÁ!׿¢!    Œ!@A&ožæØj̱hŒ|o±ÊÙ0¡nkŽ,S)Ç6i€H€rB`ñ…£ø=à4þÝÿQNÌ®±6ø~Ã}UÝšOŸ>9^»ˆ."ÂüüóÏèß¿?ÂÃÃáï﯎%Mž<9Çöi€H€H€H€H ÿhdþøq£o3B&ÿö±gb0`ê„ÇFcmß p±³ÏÇÙ9  :®û¡æÁÚʊˆŽ°qď bŊèׯŸ–ö9yò€:š$ z{ö쉛7oâîÝ»*"fâDF,e,’   € P1!üÿšZŽ,y>÷Š9:cYÏQfê%Ý"(lêÿù9þ\ø<:¶|¢°-={ëµqÂÂÍ([¶, e{÷îU1§NBǎqíÚ5$%%©ˆ˜Q£øgC–r    ˜m‚Ìï"1&„2ùžqñWãÐjÔ§h[¶ fµÍy˜{>ºÎ©H€ 0Û~Äð‘­ðÆ€žx•¹ž4g,ځR¥JaРAš oÚŽIEÄ e˖8þ<Š)¢"b¬Ù;’    ˜/M‚Ìï?ŒƒäØPŒÔÚ|WRÀÎÌ©rJàx°ž?‚©M;£~‰²95gQã“tÉXrávø_E…"n˜X¿M¡c`Q– gçûÂö;Wqxí»Ù]‡Øºâ·]1prr°aÀÈÈH•F"bZµj¥¢bÖ¯_ªˆ˜&MøßüBø€pÉ$@$@$@…€&AfÙ÷oANA&äÈd4è4ÿkÐÏÔn–3sªœ˜sf/¶ÞžŒ!5ᅆírj΢Æoöœ„¯ÏîKç³<Ãk2ÊË¢6ò?œsu?Eùbÿª· ʒòvv®X¶+öööðôôT"Œˆ1’F¢b$gÌøñãUDL:uòÖZ'   0+™7¡‹»KA&·N§CÃv3ðlœÖS§E>ÎlS…ÅFáp/Œîށ³ÆÕmg[;ópî1^LÞ·—Ão£µú˜Òžc®øŸ”[kkX[Y劜ÇÙà…c·nàÝݳ4ç;‡7âÔíÔ/QFEÆüéuVM5¶N Œ6ñsœÝ5=ŽUa»ÿم=8•ˆ=+Þ(lKÏÞzíŠâë?°sçNìØ±ÃXªú?þP"ŒDÄT©R%{¶9ŠH€H€H€HÀ¢ hd~ÿþM$ņ³ìu~nu2Кå %ƌ¯×*?g6Ù\ ÉI8ìm~Wpä–o:?>lÝ íÊU…@þHÙÇÐÿïEˆNL@§òÕñ~«ì•–£?{Œqò¶?’’“qí~(š—®„—uÈŸcY9ãèVµs;DCrŽLÖékÆíø‘÷±ºÏxž;8á|è-L?²IñgY~e4. ®e»«–5eÛx!øñٝž`w;~­­:{Ký÷r Ÿ[v¬=Œ6mÚÀÙÙûöíS"Œˆ1eʔɞaŽ"   (4 2.|ÑnbܐÂuüÂÔ;Ü€ÅLUaIòp䛘€õ×Ïcù•ÓêÅÝÐڗ«ŠÖeª $&}«ÕÃç'wáÚý0ÌëôÊq3K$÷ãb0xó/Ê·åªafë'³ìgHtfØ¡¢lÒ6‰ZÑk,\ìì³l3«Þ?²Gƒo`f«'Ñ¡|µG†ßŒŒ‰†)åTŸ¶ë [Õ§ÛÚïÕÏ]Oœhq/íýË(Êìô¿úÈž¬ú—þ[SvlÆ1žÚŽ«ÎaØöÛ«…qùšÖ|äô5Ì_º{Ž\ÁSœÛà¯ûžxñ"ºv튥K—ªŠKl$@$@$@$@$ IYœôS„_ÅÄaùó¯óÜ=f­?Àêð|ƒ‚)„Å%%bñ…£Øîw%#G}Vo€J®ÅŒBd|nZ¢ŸK²ØžCóE˜Èê³("ŠY’Ö¯Z=ŒÒžS–L<ˆÅ”}kT”‰D˜ÈQŸÛÑùzôG"XÞ<žçBƒÔÑ£2ÎEýÑ pµwÀŽ–Ýqí^ŠÙ€ÖÖ¥bMLkщÉÉxrýêZZAFŸûÜ»ƒöü;kk$$'§—%@Ùì¬eM%]²iœp {ÿØVÜp¿‡Í¿ŸRž®aµ;^RBÌE¯ ôölˆ[!÷püÜ ŽïØ]åŒ=zŽ+ìB$@$@$@$PXhd6¬˜‡›×Ná…QY{¹,,ójušMGÛ2Uðe‡y5…Iíî ôÆ''v}ä¯=*ׂ«œc†~]œ‚ ×Îãì@LkÑ <̯‚‘äO‘Èiãë¶ÄÈÚÍ³ÄøóS»°Óß e]ŠªH âŽÎjü—§÷(áJÄš_{ŒÌ’M-EHZéua±ÑDæ€/"Ñìv}QÓœ$öߌ†í7.ÃëÞüñähØY۠ǺT÷‡¹öêþµJÔY§yºq†è-~f¥Ov֔û…µï{G6# D6þ2Å"ì>|žmjÃÚ:ï;®ß~ß-ݍÐðHtmWÞŸ·áå{“ÇuÅ˓céöêž’¡Ê’E€£“$@$@$@$@yN@“ ³eÝ/ð>·Cýå’-ÿŽn? OVš“k‰aóÏsm3IÂÞ÷þeì<ü‰&ªÄwf‚Œ6«ÚzItN’N÷Ÿ‰‚å…^";<œŠ(ñ§ˆÃcKÞÉU"M„‹¥+=vŒ¡ƒí¿s¹úºŽÇÈtDzÒÚÍHì0ØxœÏ¡1QøÓë DÜJLNB…"îèU¥.Öøœƒ”ë~žÕt÷€g…ššY¬$ª-7§ ×#G˜$’ç­C«ûù(ÇÑ$O[&‚›ŒÿŽß@\R—,jn%4ó{žãô#›sŽ&±÷8žÙv΂N;Œ AQøû—Éf¿Š#§}ÐkÌ7øeÎ<õdÓ\÷÷÷uÇ0é%öŽmVÿ\ À°LßÏ"Jí‹ãç-᪎õ!CrÝ$   °\š™ÝÛ×à́•x}RË]©zÞ¶ã'èZŠ&Š6ílÞksYD‰þžc0žF# ªÑeœ]µIé k+ëGŽ2IÅŠ¿¯_@ÏʵQÎÅMEšÈœÒæ{Fíb¥ÓÍ#9\æýsà‘—ùOÚöA«2•}¥ß¡ _EÝG“’кleõ}ÖñíªÏæÏs«hYÈŒöcãõ‹xŠV3Lx(‘³ˆ¯î[ [[|×yð#æŽø,ÇŸ^Þ·Z‡zžÕ.V 7„£MÙ*hYŠ2vù_Åé@LmÒ }ªÖ{¬û¯X¯Ž8š$ï­ZŽ8*žC9—¢š8ˆ(ôÿ‡ÓÍ5ªvsŒ«Ûò‘ùφâ@Ð5<ˆ‹E{Ôpó@¿jõÓõ“}^pî Ú³¬®I ÏÇB) Þ=Œ Á%¢°áWódÎ\ðC¯±ßàëÃñ̀ÜMŒþÓû•S¶”šÔ«„ç|˜”„ÉãºaäÀ‡æ²/Ž…‡šŸ, O—E$@$@$@$š™CvcÿÆx÷¥Þٙƒc²I a›hâ^_w*؉—h•7¯á/¯pýA˜‘–(/5lç”$¶ÒO„•¶e«Š‹9šŽÛˆ€ í…m1€fc£}>øøÄ ­ÙXU‘•>g IDATjzuÿ:ãœZÅJagê¿ZK„ÆÔëp+êê#•’€Â‘!§ËªÞãTe!©~$ÂKÚ$ÄÏ7h‹¢öŽJì@œ¬ŽÑÛWó.ì:,K‘!Z}^~õ4~Ÿx\¹4ºvsT.Z·¢î+Šwb¢ÐŠLÌjûÿöÎ>ªjëâkÒ!…¡÷ÐKèMzUš‚ "‚*úlß³óTÐgçˆ Ššˆ‚Ò{ïœwBB€„ôžÌ÷Ûgr‡IHÂ&ÉÌdߌ™¹÷ÜsöþŸ›è]ÙgoÃÏø¯gàçSû > ·ÜÚÍ€x¬»|Ãê4U6ÚØ¹õ•-X}«7P¥À“Òӌ×iەœ9€¹§ö©K%y±‹£“Q€3’\0³OìÆŸçÜ5ø$¥µó* nŽO2š¹< ²¶öÔ÷ÍËe¿X¯ sê|˜cõh†o>xÜ"øSÓÒñÍÜM˜1w#ª”APӚ؞óŒ<ÝTDLž8.þ˜¹äjÔš¡òȰ‘    €FÀ,AæàÁƒX6ÿŒÿò@’+BºMC·²µðJ‹nE8kñNu"2_8Šò“H«VÊWmý)çQ —c£ð̆…š‰M:šؒøs‡ï2zÝà‰Øwý2ªzû"4.F% •-7*9mzd+Îùè[ê:-’EÆû×Ö%8y]õýžãH¢W-!­ô•rÎ²íæ™õ¿«q$§ËÚMq%î6|]=°?ⲺŸyÙÊÎý3låÏJ„ÐJF›³æÚ,¹_4ÁG‹p¡5º¶_ †zô¬ZO^|þ(Ÿ;ŸÓXª:7[V^:‰é‡·B+I.ۖ^ÚºDùÐÀ¯<|\Üq5þv¶ˆIÖ,‘3Š×IŽËëY[$òøFíáîäŒ×²¢n>ë4HE IûòЬ 9¥D›±mÑŸbuž:9cèŠ9êŒ$–$ù5s|*OsÖÇûü{Çr\÷MÀ²ù֙Cfݶ“xáÝ_1žw ̘· ÿÌ~=;5Œï¥ˆŠIÀŒ,!Šw—FšRÁË6EÕÊ~˜<Š;úvkœÿØ®e𿅗ˆ^œezß Á I€H€H€HÀ ˜%Ȝ:u ¿|û>~}€"°^—‚º|ˆ~Õñn›ÞÖkd!Yv2ò:Þß³Z=Ü·,Wÿí8òÀÿÔº_Ñ'+.ÄW‡·* äA_òψð“’Œ“Q×U‹:#êµÀl4Z*•ƒ>íø0$®?3» G]ß²*J烬íFÒY¢gd۔©8ôSϑТ9dœO: „›“³;g’â¥ÇšÔ¿¶þã‘áFÃŽæÚ,‘%ZÂÝ?ú=¥„ŠüÚ¢s‡1ëÄnMiÛÇá"ë} âŠÊqãâèˆ=á!xg÷*%Æ|÷УÆ(©í×.â?YëVÖÝóz?© çlæød.OsÖÆ^ûHÒêpï,ÿÕú™-»ÏbÄ ?`ԐvX²æ Þ{ižÖþŸ–âjXŸùÅ3jH{øúxàÏûÑ€A€Šˆ‘DÁæ4kY|6ÿ,ÚŽiƒ.]˜ßfìC$@$@$@%…€Y‚LHHŸšö2Ÿ|‹‚LQÞºOÃCejã_Íí/‡Œä{‘È–Še+ç™øV¶"™&‰MLKÅ å?ªò¥ƒÆ£YL·ÚÈúHćTô‘˜Ž•j _µÍEšl‘-J²µhuÈi|qh3^iÑýª7„–¶[•Ú*Œév$_$RIJqË©TSz¿Mtª\S+Ñ;¯n_š-Λ­{ {@]³o™MWÏcÚ~CÕ)s¯5׿˜ÔdcÉâcóM¬+óÿsñ8fÝnŒFÒ|”’Þo¶î©rÍì»~EE ¯·ƒ ùw×*쟂Ï:Bór†š–œ-çuZþ™—›wÁ€|òÕüïðV,¿tïõB×*µÕ°rOHbhÓŒ8/6턇kݵ`ŽOæò4{Qí°ã›;—#Ô3+ZWÙë?VìÇ“gãçϟVù]†õk…×'\Ì>s!\ 1?.܎çžè7WgÌ_²]ÛÕÃä1=ж…ágÞÜ&‚ÌG?CϞ=Ѷm[s/c?    @À,A&""Ÿ=ÓßêG‡€Å:\lßc*zø×ÁËv(Èì »„÷öªuªTÝê  ”/€0­ä‘-@’ÛDª‰òU—!ªo%3ÕûŒÞO`ɅcJ8öl£vêzÙ^Žñê9㺈&Go]3ö›Ós€U€iUž$Wˆ2œÿþ^—-LÒÞžªò‰H%"Ž¢¹š £%ù•-7Í#ŽDyȶI|ÚØ¿"ŠwlöÍ$ÛeŸ<ŽY EÒDèèW£!ûWBlj2$gKjFJùšH  }ŠÙ6˵#WÏSãæ¬à”›ZԉäÐÑ"Ž;‚Y'vᅩTD’ÆOl‘mVÒ$)¯ä“É/pÎëDŸEh{¯MŽ*+3­$øÚM0ŠA.ÅFaÆÑmJx¡­nV)nç£öýÑ€L¥lãÜË'Y7sï³Õ;J•¥+î1Xµè_VãÝ7s7ⓙ«ñûŒgñÑ×+ЪIuL{Ãð;ÃÜvàXˆr–o8ªóºº:㧅ÛñHïæ˜üt4k˜û}y¯ñu®åðî·û0|øp4mÚô^ÝyžH€H€H€H 0K‰ŠŠÂ”7'aÚ˝ááîR‚ð¯«í{NE?ûd€âϘõ¿e‹(ɍ¶lA™Þy0*xz«ÓZ”_ûŒRÛRžÝøGžcȵ úŒÂŒ#ÛUdÅÈz-ðLà¿PK$Mÿ¥³”ž± ÷( X6KÍ!óI™ëŒÚϧöâ×3ÕiÉ5£%"–Œ)²…IòŸŒß°—ãnã瞏+ÅÜ&"‹MóOïÏ¡czœÌ#•–Dœé·ô³lŸž‹'×.P}§µ€  ù—ã–-c’FčišíbR±HD'MБêU­úÂù÷ŸO©±µmL"šLjÒ1W·s^'ÑEy£E$‰’¹ŽOY•Üž¬»—gGX0ŠìYsט²Ÿtš¢žÞÛœ û"®š>"‰Èâš3ˆÈ÷òIæ1—§¹ëiýÞÙµ£°vñ«Váޔé˰y÷iüðñSxëÓ%šTŸ4f|ð„Ù¶mÝsVEÄì;r £‡¶CRR*ŸºŠµ*ª­IõjU0{¬Ü:êÜÊã/¶aüøñš[×üˆ¹š”“    س™øøxŒýÆ$ŒûlKøùäŸ{Â&Œ¶#ÛõšŠžŸu![9ì±Év“maÁØy-!qQˆÉ*}-vÊ{”RÑ&Ck71æhßÛ©’º.ð œÔ5%s-!"ò”õðÂéÈ%’Hu ÉS"Çž;€rÉx9»fC9ïô~‰#yUŠì^£¶ÛˆÀðuסF!Àô.DßRۛL›<ø?מƒ±Œóéš%2ä,•mî:ŠÍ«/ŸÆ©Èë8s;BUA»Z” €ˆZ~m‹ÐœlŽOKŋ›ÿR¢Gn¥ŸsÚ%ýF¬š{—(dšX"z&løC NZMTr"ƬûÝ«ÖÅKÍr¿os»îj\ފvÑ*e™Ú#‚Ù£ušcxÝfXpz?~9œßxZ"u$Ǎ§I%®ÿìYceDÓʧ›ã“¹<Ó23 \–Ýܵ·ö~ïî^…3ž‰K_/vS_šò;Ž ş3'bò”ßÔö¢9Ÿ¢µîÕVn:Š"bBB#1b`kDF'à»ù›U4̘áО^å{ aÖy[Œ4mÞxã T©’û6>³b'    »#`– “––†×_™ˆWŸšÊÌÿk¿ÝÑ*b‡ì]¹_œ²}G¢!òjSö¬ÆŽ°KJ$-7ù5ôzœJ$–ƒç6.2Š#ê6GßrHÏÌPÛsv…_2–Ãþ³ÿœŠŒPQ:RÉI{è7KÄ©Œ”Wæ‚ø/‘3Z€‡éu±yv8u]åË1§mžrŸØ ºJ.ž~Õ‘„œiÆÒäÒWòÕx:¹(Á,¯–ÛuÒ78&'#Ãqæö õ®å†V»)žkÒA —œžŠæ(ãî™+mœÒ®nw%/Ÿ—Oá¹aÈ$s0Ú]dŽ¥†cûê7‹Õ·‡F|ŸÒX4ó9Œ}ígõs<ÿ«q÷Žé‹Ùk±tÝ$%§©íH—C#±pÙ>LÛ]UM*Wƍg©–é\“§®Á‡~K ËqH€H€H€H€쀀Y‚ŒøùÚ+/`üÀŠšS£Œžm.Ží=œ|ì7BаVAJRËv¡œŸ4nu2w®ð„X|ŽoÊ]“[“h ‰ºÑÊC›;naö+L›%ŠI%­’Taú‘Ûؚø"S–j÷ò©0yZʇâçãýë±#6»×¿]lf Ÿø<=\1÷‹±ý¯Ÿ‘‘‰_¿Ÿ¯=síPå«K—rG•ŠŸ€Pk·žTے$*ÆÛ+o‘÷AMÌôÅ¿¿ÜŒ?þ¥JYî>~›x-    €u0[yÿýwѯe&Z7©a–—+Úôþ}|êá%;ݲTKš•w–Ü'Ëåÿ€–×ü5säf(Žß GDbœÊ£"‰}•©šÊ6["âÅҟ͖ۢf`ÉñÈ3oš* ó38Žå}K"7k¬”Ôt yö[T­ì‡ïŠŽÂã“gÁÁÁ òˆŒÑ끿lÄ7s7¡nÍòèÚ¶öVùbTDÌÓ=àìtw‰t³Œ1³STŠŠ|³_|ñ\]³o™4sv#   °Sf 2Ÿþ9šTº‰íëØ) ës«Y÷)hïYµïg}ÆY‘E²5Èß͐ÛèFb_3_m±™Ò¶¯YISHÀ>Ì8º‹®Ɖ©C!W#1öõ9hX_Ÿû†N˜‰ÒÞî¹æŒ‰OHT^’1‚ê M³ØŽë Î]ŠP"Ìó£»™ía±¥ñßÙÛðÍ7ßٜœˆH€H€H€HÀ6˜-È̚5 >8aœêنgv`eë>¢¿O}LÎ#9ªžøÀ.hùbž¬ß caÄUrz|£vx¬nóŸ d'0ûÄnÌ9¿g÷N+24aÑ2á[T,룶&ÉçZÕÊáÛ³WSº~3F‰03¬_K4ªW+7íÛqJˆûh ӑS×\±`ùI|òÉ'…9 Ç&   °Af 2‹-BôÕÝ74ÐÝŽM“[õù|`r³Î¶é@X=rõ/ª‘ŽÞÕê#,>Ç#Ãñ~›Þèt„ŸE`§ »# •ÉŸ9¹Àpñò ~vŠª„4zh{ ›øºŽ­‹ÿþ{˜‘­ôFĘI£»¡VÕ²XŽò€Ê-#9bžM±­Ã®3™ØràÞyçb³“    X'³™õë×ãðÎðÚFÕR¶ìóú4€ “ð‘ᘺoQ”Ѻ.0¥ó©ÄTTkÈyHÀÞüzæ>?ºöRèùW€ÒkS)‘¥sP]<öü÷?²3þo¢a;âÑÓ¡˜1w#.߇ÇtGù2ޘ·xŒœÜUŽ˜Áœ[;þUû|˜;º §vM…»›³å'Èñ|È ôxüsŒÔm›×Ä/ÍÆŒžÀӏvÀ®ƒTŀͻÏà…1Ýáéî‚Ù¿oCÕÊþjkRß® Í®‚üۆ[Èp®ˆ§žzª —²?    €0[9þ<~ž5o>šÊ²>fœ§`O ^f•%³`‡ÄFáFb9ž‡¶MAéRî7?)9œžœŽžâjxÎ^ŒŽƒð×ꃈŠNÀø‘›„¯çnD«ÆÕñÎä*‚Š -=#‡O^ÁžC±uÏ9¬ß~1'gd³ûNs Ýz AǎEŸPØl#ّH€H€H€H X˜-ÈÄÆÆâ³ÿNÃ=J¡nòÅblI›Žq¯÷ñšS<ߔÿ!_ÒÖÞÞü KˆÁŒ#Û±/â ^kÑ }ª7°?=°;‚ñZˇЙ‰¢ñÏÅã˜z`n}>Þ_Çþcþ‡2~¥pæb8Œ<\— g'•Ð÷jXŸž»Ãû·VÉz›Ô¯‚ä”4€€ŠãJX<Ü\˜¢^1qIˆŽMÄ­šxHčŒÂoDãÒÕ[8}!M M³šª,v P®Œ·Å}‘ßøj?ÆO|õêY_ôN¡8ÌAI€H€H€H€Ì&`¶ “™™‰÷Þ{ƒÚ8 UãªfOÀŽ÷O °Ç{xŒbsL ìpÿƒðJ(f×bñìÆ?˜ž†Ž•jàÕÝPʆ.ÿxb7ž;¬(Nï<ËT,f¢Å;ýòàøÏŸµ8žõ=ø–öŽš1›¡¢bŽžº ïRî(_ŠªW)£„˜³Áð+í*•üp94R 1òruq‚›«3jV+‹Û1‰pwuVß]\œàìì_o€§g R_”òtSßËú—‚ü;--=éèÑ¡!š4šbQ_d0“>úé^~õmT®\Ùâãs@    Û&`¶ £FŠOG-¿ëÐ¥Žm{m#Ö7xèŒ®Ú ê··‹iæýØxõö„‡àÍÖ=á ³¿ì7ÿÚú·*EÞ·zŒÒ¢›Ùù}’ÒÓTD͑›¡HIOÇÈz-PÊ'OIJµ(CŸ gÇûY†<¯IÏÌħ7bÓÕó(ëî‰ùœGÁÉÁÁ¢sØÒ`«.Â{{VãÀ¶÷àgAAæfd*¶~€^Eºøûy!99 7£âU$NíêeUU§€ä4UÎZ¶6%&§"!15Êàä¹0xzžÀÃÝUœ{ªwÃKė2Ÿ^prr„““œÕXÚç‘¡E£j_†°ˆh|œè Þ~ïC”.Í­ŸÌI€H€H€HÀÆ HY°`’#öaìÐ&6î¶m˜_¯ÛÛ[« Æ×fe«œ+–š‘ÔŒtõ“šŒØÔd$§ŸgdfÂÏÝõ}ËCÒ­]äxo÷jì ¿„/;?‚&e*ÙÆÍiŠ•"®âß;—+!cn¯'àêè”ï•zg¢"°îÊ,>™­ïÐÚM1±Iöh±Ã7B±åÚÄŠîÈäüÜë ³D¹7ÒR ƒÎx‰”–™¡î#7Gg #OLJF­] ¢|Þê‰nUJ®(œöòŒµsm{Ÿ>–©ÐòÖ­„ˆÈ8_¹Ž­ê wç@\ ¿.mêw£Ð¢}vvrR"Œµ5Ùv5wõ-|üß/áèhY¡ÐÚ|¥=$@$@$@$@'P AfÓŠMØœñ7Œ9žAÁQüŠÚ]ÞĄíñLõ6¿ØŽ®…ÐøhH¥K±‘8{ûäAÿ^í©†­±îòY”s÷ÂŽî)ÜkŒÂ:ÿî®UØ}=ï·éƒN• –œŽ°l²Ôžî]‹­×.ªmJ!“Wqd{X0~>¹¡ñ1Ænu|Ê _õ@D§$ªü-ÕŒýÔ9)u>ãèv¬9}א¹ ["ôD$ÄârÜm\ЉÄùè›ØqE ,ùµ‡êà­Ö=U—_ÏÀϧö¡Š·?~èñ˜Y¢¥8ZÓ8¿œÚ‡Ïn‰­·Œe™~݊Ÿ^ŽÉcº«1înÖ'²d-¶ì>‹œÁ¥ðæÛïä2ö%   (! $È9rË}—o„R^n%Qñ¹YœÃÿal`ŒP³ä%õ•n‰ÙtåŒ+òkNÎðsó€köŠ/5Jû£,L¬‹oEïžY„ˆ×·/ÅÑ[ahä_<Œq=1‰ii(å⊷‚zÂßͲœEåBZ*^þ#d}›çV¢eÁ'ðûكž™”`4­]…êR§ š—œ;¯‡0›ºoz€nÐZ­ý×G¶©ïý+bz—ÁæèÍkXå,ö^¿Œè”€<]K»º«qM¶ÕðöÇKYeçãSSðøšyJÄù¬Ó \m+*¶Å9lÝzeÛ?8ºa |ËÛæœYTü~_¶I­0nܳE5%ç!   °!dBBB°`ÎWx²w%T­løK5[á$”-|ˆÑõZã銭 g+õs‡1ûÄîl•¯ Y$â団ÛÕ¹ïŽÚ>eóôDÚ׆œÆ¹è›øµÏš"’aI¢1€úWTQ§£"ðǹCˆLNTŸój"|ÜaêäãŸ/!v†]Âû{VCÖM"”rk7“â1rõ<ã©!µ›àᚍQÙ+ï|kBNãóC›Õ5_uŒFþ†$»"Œü÷ÀFõyQ¿1±ŸßüW¶iëù–C¿òšèáU!§TÄÌ M;á‘ZÍB©%øíV¥6ÞêeÖ5öÖiK茎e N®ûޕ,_eɞx}5gêµ…þýûۓ[ô…H€H€H€HÀB $ÈDGGcÆWÓÐ/ÈÍXÈ“Úß„–íñLù IÊ OÙ³ÕJùb\£vhQ®J61eØÊŸUÄÃ?Ÿ—³k‘òåBôM”q÷R9FrÎ/çv…‡@ò›H2[­œÔ¬ Ö ÄÛ»VªˆœM¶çHn’:ŸeÕ¶‰Ø(®&9T®Äކ—‹+ʺ{ݗ®œÃ'6 Uù|Òa`®cˆ`õĚùÆè•6ªá¹ÆòLÞ+Û×F­¯¢irær‘;ž ’ejûþyÍiRŸ{ôÚ_Uו?[äŸ96vŸí×.bÒŠ¿pfõ‡(U•‚L^Œ%’ë/–aÄžѬY³Â^ŽO$@$@$@$`ƒ $ȈS?|­k$ Gdž6è®m™¬’ú6o‡ñåJž #+u+)eÜsß¡ 2k?GÝýWŒ‘m-’X«š“œžŠ¢Vš•«rWސ‰qøß‘mw‰)Úœˆ"¶äÌoSÑÓ^Î.˜Ø€£JÚ+"À·G·+ šB5lžro„â_Í» À|oÒžÔd¬Œt Á±‘p€N‰ k6Ê7¢Ät@IXkZ…Hl›\LŽ^‹QBŠœ#[©žnØMˬlïŸëWðÖ®júüÖéj\ޚOri­S¥šxŽnsÍbÚ$:ã£}ë ‘.ßvv+YDìúþ¡GÕœs;%Þ.n¹Þ#ÿ=°믜+p2eÙbvøæ5|ж/ÚWªa[¿T,`íΰ`<»q.®œ êÅ'ZÀ•B"2:_Íقñ¯LGõêÕ u.N$@$@$@$`› ,ÈÌýù'dÜ܎§-yyMŠz‰v£šaBْÔ77î=–ÌT‡× ž˜o%Ù¶"‰}‡Õiª¢äáÏõHŞsÑ7ðŸ=k ¹N€§³ ÞÙµR=l÷©Ö¯µìfœZÄ¡mûá ±êX—ʵp1æ–J@+¢ˆl‘9~+ ¯n_jŒF¶ÂH"ZÉo“_ӒÅNhÜÃëäý—ô˱Qjüœ¹Pªx•Æ{mú fiÿlӈžôçù#\«‰bôúŽeJôøŽã qôÓÉ=øýì!ˆ`ôsÏǕ(%þI5¡ÜÚk-BŸjõÍþ1ªGCVÌQýÿݪzT­›çµ"ŒIDÑߎeË$bЫ-2FÌHžÉ9óbÓNxØÌmFyMª%S6ÝödŽsóOïÇ/§÷ã‰ú-•PUÒÚîð<³þw\^ñ \kmtš-±Ÿr¿üs¯Où>>y—k·%Ÿh+    €e XÙŒy3v®þoLè'ÇûL°¬ö9Z£žïad³–˜èßÎ>|¯ÌdV^:‰é‡·â?mû¢C¥Xxö~<¹GåžùåÔ~ãÃÿg©RË1¡µ<£¶ìˆXð¯­Kp"òºÚJôqÇ*Ñ®lMznӟªû_ýŸVIx_Û¶ÔžMI„IÊÜ¥rí|E£Åçâ»ã;UrZyåւc"ñòÖ%*¡¬lzªAŒ|°ðÜ!,†K 2y-𮃰nW>øb¡ÝÝtˆH€H€H€HÀ2 ,È;v «~ŽÑƒ›¢BÙŒoZÆŒ’=JÓ>S0¬Is<ïGA&睠 2÷Êã!ۃd‹}¢ 2²åÅt‹Ló²•UdŒ4DøÐÔ·]»ˆö®5š ×Vð(e¬ò#ynD ‘&ۖ€ ͜“{ŒUƒDÄ„¶ªç*Ì,:w³NìÎ7ââÙ šmJ’|Vi"“H…žÛê{ÎÒҚ #ó˵Z“š—L}áèñz-ñ;–©íSÒ$ïʘ††írÓö¯W~õ®V¯·|Èì̈Ä8Œß°Pñl_±ÞkÓÛž=ì^ƒD&'@Êfk¶ÊZ +‰N‘§‰M:Ükˆ|Ïk¹|ވ!s“‰Ôy¬nsŒoTò~6¥úل‹piÑTž4Œ·Àf.W{ë'–RÝðìk_ۛkô‡H€H€H€HÀB ,È\»v ~˜‚Ÿª Qœ‚å”°Í%f˜†=ÞEŸ ñNåî%ÆgsÕ™?ú=•oYh-‰VGdòšG"EŽÝºŠ¢N$:DÊekî2†ä'qÁTÜx¥E7T-å›mHÉÕ"bD–hۜDžyŸi'µ]ÈŽýsñ8fݞMdíI/nYŒ7[÷DmŸ2ª‘\ÿ}÷G9`€JЗ‡¶‡’­SŠ•€4A&/_GÕo…ú~å•ýk4Ä¿šwÅÈÕ¿…€÷ÛôF§ÊµÔåI"%yånÉoÝöG\Á›; ¹d:Vª·Z÷R9k$éé¢ó‡URäŸÕäšç%)= —ÍV×Îêþ˜˞ÌÚR%Û»Æ5j{ß9„ŠìYa—ðn›Þj š¹í‡·bù¥“Ù6eîœÖÔo{X0^Øô.üú\›RÉkm>ý~5šµh>þۚ–¶    X 2)))ørê˪ï‰níÍÏ'aE>ی)-ú€¡Í›a¢W[›±¹š Žl¶FfvŽºŸy—œ>wû&&mþSåy‘mEŠ‚Œ$ÕuvpPåÒŽ€ºZYå§ŽÆãõ[¢÷ßß«ó¡!íà«*áp/4ϑüW¢VÂbPÉÓ=&3²Åeî©}FaFz4VRµæ?{×*Q@Äi‹ÎÁ¬»T4LëòUñÔº_•ñEçGTtŽsNîU}Õl€ ^oÙ] Š‚ŒøÿpÍF*ºDšMb‡äÔyzýohì_Ÿv„Ÿÿü`\B€Ÿìüˆªö€Ùc Tµ6-I-¢ŽDÙH€¡Y9fä˜ä§‘ÒàŽ:R33p=!Ž9ô‚ò}^ï'Õ:æK¢eÚW¬©Àt#)’øX*`åW:[l—è)‹.‘62†9íЍPŒ±c™êú[ŸQ(çQʜË쪏D‰è·Ô RLïŸ;[ßŒØæ,M-‘JU€Eåv݊Aãá–åcnç5Af`@ŒÔŒKŸëz"2?bï̹Æ&°Ì0Zr-œµsN~7îíYö:7d/ßįÿìÁ„gÇ¡bƒÜKŸ›š]H€H€H€H€ìœÀ} 2›Vÿ†}’,ô©‡àáîb爊Ϝf}ÿƒ§»µÃšÌŒ+ïŸuÅ;³T’‡ñ; P$y5‰X™°áU¥G¢O€BÌ»»WáµÝЧzÈÖ œ×¯`h&Ù¶ŸÈ¶”+q·UDŠVG„‰¯»U qs6;Ò23Uò\‰fњˆR~Y¢7ÎGß4nwZÜÿiy"M„«æfÛ %Ç%BgTV’_±sêŸõÆ\02®”Ñ–¿ZÓ|“ï’kFrÂ<ºj.zV­‹ÿkÕ‰i©*a¯”É–H­mŒzâï·Ý†«ht$Êæûc;b‰DÐHþaö M‹Òl”è”ýׯ@¶ÁœŒ GTr¢qxá,H²5©|.‘("rmŸz‡o†âLT„Ê¥#BOÓ2•Õš{•€þߑ­X|#ëµÀ3yG¡IÄÍà¬H1N„ºw‚zµáa‹×JÂe)=~ôï£KîeémÑ/KÚŒçp0Öl9ŽwßyÎeáhI¶‹H€H€H€ì‰À} 2'îÁêE_â‘ÞÍQ³jÞÛEì Tqø"I}'öë‚G‹cz«žS"®'Äå[JYs@ò¹€edÀÃÙ Š8"%žók"ädê3•H–ƒç6.2 &#ê6GßrHÏ̀l‰’$§Z€Æ†!“”È3ïô~cÒ_Óy€ò’$Ê퐜ô†+çðɁ ª«äYéW=PU=2mbSdRܝTõ§Üšˆ."LÈ )u-¢…ƒÎº{¬Šô“rÚMÔŽL%%DI‹OM£ƒƒEźfہ@¿ FÁÉ7›ø ëen“Hšׂ1 f *‰žW“\7ŸØšxö¬VÍÊV¹'Osm°Å~)4ýÐüì-xôž[œŽEŸ,móü%»‘š–Žñ/MܘkÍÒ|9    Ø ûdnݺ…¹ßŒ†vM*¢]Kó“aÚ Ž¢ò£q¯÷ñòÐî|›¹zŠŠy^óˆà"QŠ•™LûJĉTrêYµžñpLJ®ÆGãvr<]PÚÕ 5Œýó,-bŠ<ôç·ÍŠ09hÛ»€âÔg.Ì©8¶ øõÌüp|ö~ôðì[òrèÜké$JW k§Öè6ôÝ{uçy    LàŸáõõ§o¢Œ{F l]‚ñ®ë=ßÃÿ=Ñ®×)܉8ºY$BåÈÍP¿‰®í1’Ø·Q™Šù -f ndë”äæ‘2Ù³zžýÜÝ ÉAÙ,K eÿ0v`GŒŒndف9 äA@ʉ‹ÐŽlÐx2"\ Ì<ºKƒcÓ/£ÔPC51¶;¿ŒÕÛÎà¥w~DéÒäÃ{ƒH€H€H€H o÷-È;v –~‹«£V5æ‘)Œ›¬ç_ UýêxݹSa Ï1Ià.7-Âùè[ø_—!ô¯@B$pɧ³3ìVŸ8 Þ#}H(E+öãF’?&¿>lH€H€H€H€H _÷-ÈÜŒy󜎖µ2Ð)ˆ[j ã>óê€$§ãÛC‚U6(l¿=ˆ9'÷f+^Øsr|Û"ðïˍ¿¿}®n¶e|![›ž‘‰g®BÇŸ“МG¯BžÃ“    Ø:ûdÄñ￟ çžýxzx[ç`•öO±«6Ãò6ÏX¥}4ÊþH€±ëÏViÉþŒ€GBà™õ¿ÃÛÛ¿üýìƒ c—×^Ÿ‰ß×\ÁÐ''£^œ; ŸíÒY:E$@$@$@$ðÀHÙŒy3ïø £ԁ¿/˟>ðjä`íÖxöÍy8>éM€‡ŠYzxŽG¹8t#eÝœPŠÛQx‹ÜM ß?? OŸÆ˜2…‘{9éì:x[O¹`ò˯£T)V âÏ    @þH9þgŸxúé§íÜSºG$@$@$@$` $È$''cƌšã{ »ZÂŽ‘ƒ@Ãïâµg{ch\CdÜL' (6Ñ)Ih³d:Ž®›‚JåAeºQÑ ˜œüºõˆ¶mÛÛqb    Û!ð@‚Œž¹bÅ œ=²Ï©OWÛñÜF,}bòlddfbÞ€§¿,ÖF¬Š™$@öH`]úyü{ÕR„ìúÔÝ{ ŸŽ§aÝþX<ù䓹\¹òÅ‹I€H€H€H€Jd€üõ–õKñP=Ö©T2š¡— —íÃ[Ÿ-AðöO=3™±E8;§" ;^[‰°˜¬þåebÉA`Ѷ\JÃË/“ o    ó<° ‹üuËÜD¿ÎµÌ›•œ D b«Wðû7Ï¢­k5$®‹+еìL$@– àÖÊͧ~Œ wÁ+ãYÒٔi\šfþu íÚµC×®]-›c    ”,È£¥K—â‰-xvHmxºsے¥ï›á¿ƒ££¿9ÑßFBŸ’ié)8  äI@çဝ5BñúW‹±pÆ4mP…ŽL¿^k·ÁðáÃQ£F ²!    ³XDQۖ6®@׆ihT{çÍ"_€N[vŸÁðIßãæá¯Ž3IÛ p5»’ ÀƒðèY £~œ‹ð1رøß6˜œ]íä…?wèq-,¯ŒòŠœyGH€H€H€H€ ‘€E™øøx̚5 5ý"1š+ÿ:XëÕ~ð4ŽnVÓ_~ÑßEÆ“H€î"àÒÈ »J_ŔéË0rP^ӝ”LÜFüøÇŽiӆەxg    ˆ€E™qõêÕ8sd3žìS þŸ^2‚ïM`ɚC˜øÖ|\Üñ v¥!ù@âœ/b x>Žð~Ÿñ=.‡FaÑÌçP# ÌŒhg—:8á`X lÙŸ#FŒ@@@€9HwH€H€H€H€ “€Å™óçÏcõŠ%h]#mšÕ,L›KìØ}FO‡‡› }0±s£J,:N$P4Œ†”Æw;¶cÛÞs¬[ ŒúHÑLl#³èŒñãâÈÌÌĄ lÄjšI$@$@$@$`-,&ȈCß}÷Ï`ÜÐÆÖâŸ]ٍæýþƒ÷_~£}Z õd²]ùGgH€¬‡€[v8]Æÿ~ހ˜Ø$Ìýb,jW/g=Z%WÓ[bÑßÐ¥KYE4H€H€H€HÀ–XTÙµköïXŸmŒP»ÿÜ0n„¯ވ¿^Ž¿?šˆ†Ç} c ŽI$P 8–wFpP&Ÿœ@%joÙš&Žb9gÓÛBçYfâСC?~<|}ùûž„ÿØÐ}   (0‹ 2‘‘‘øeîlÔõ G¿nŒ’)ðj˜yÁsoÍÇÊMÇ0çÙQhy£‚™W±  ܛ€ƒŸ.ՋÅë?,FËÆÕ›ˆ>}ï KXxÏønÎ2bÀ€%Ì{ºK$@$@$@$` dÄ U«VáìÁxŒ”õ+e 9F.ÆŒ:»\À‹}»á 4%# žoŽeœà\ÓEœv„ãÝ/þAç6uqò\Ÿ›ú$*•÷¹ï±íñB]©ú8슭[·bðàÁšU«–=ºIŸH€H€H€H€ ™€Å™K—.aéŸ?¡yõ4t ªSÈæ—ìáßþt Öl=?WO„U•ruò„C…øö‡ypuuÅžqãÌfΎ$@$@$@$@$`JÀ₌ þۂ_zv#&=Þî.$^ˆ­<€i3VÂ×Í™‘™èP+ÕD ?·2"vM6I@D—ú®*Æ©’A„‘¶lýÌýk'œ—¢ÄôWÇ÷†«‹“MúY˜FëüÛãôU`õêÕèÞœ;š5kV˜Óql    ;&P(‚Ìɓ'±aÍbŽ­›ÖìŸuž&ɞ¿x7~ýkü2ݑ’–ŽôŒ Ž(€ºÞeQ£”*{ù ŒG)ž;Ýy»_ëõz=2¡GŠŒëõ0ý®>«ó0—óY}µ~z=Ôõò]œc¿ìß cšôÈñnžÎôœ0ô–ëÄ»;} çŽ#Úù;ßUï¬k WÞݲ3tt:cÇ;Ÿî\›ó¬IwΙô0@gz\.ëŒé¹l#貟¹kn“Î9ç>wûêù•ƒŒ çtYc©oê:åªéyÃp&dzΰdcú9ËùÜÆRö˜Ì™Û\ñi©ðvq…C6›î¶×x­ÑîœÄî÷ηÍë4Æ¥Ž+Ë–Žô =uUå¢Zµù8t:€€Š£w—@<: 5šVµMg ÙjGtåzcþüùˆˆˆÀäɓáâÂ?:2vO$@$@$@vK P¡5kÖ,$džbÂ#•áìäh·­É±€äTlØq»]Äþc!ˆŒ'G€§e"19‰I)ÈHτƒƒâ“Ràáêl:²Dí]E\Îe)F-ÂôaZ{ÏŠ!ÄïèÙ‡œBƒñ;àèà€ŒLƒøa*fÜÑL:g“7r®L.åŠ ŠŠ¶äTUô€»« ’RR ¶ÔYPnҎQØÉ®ðd?穌lž[8Ê:’›¢”5Cn§222kiò󚚞~Ç£/rèÎ՚&ejžáι3Q®Â–‰ð%ñŸ3o2‡ÉàÒOVÑp6GŸlÓŸ8萩ÏT]åˆá>5ÞœwF6hNƓÆ[ÀD`2¹T‰MNHÏÌT׉˜!Âc¶–C»ûnŒûv2Œ“Í,SœÎxÂQ§CFÖ|ùɁq©ÉšèÏR®pqvT6&'§!6> ·c’àììˆ eŒÑ¶EMôèØZ×A¹2Þ»ÏKXoÙªtñZþþûotìØmÛ¶-aè.    €% š sôèQlÞŒ[TD³ªq–Ž™c™I *&á1ž“ˆä”TCäJ†Ä®èàîî g'%Î8:èà ^ê]øÔgGzØTçt†ïÚC»öüjú@x—`bòlú0lˆ«È®žh¢N¶Ã:(Q©Œo.É¡³E“äÄ\¡Æ`G~¶ReÆ·ŽGŸÔµH’ü:eÓzLŸúM.º+Ê&ë@|B Œ<]Í\y“nù3y —ŒRžnêtޗçr&Îù™Ÿo/÷»çɊvÊiãÝ"P–”cù“ŸÒž†!ŽH.õž%Bf}6DyeËÌq^]š™ vçº[‘ñðóñTbҍÈ8”1M`®Ï̊èÊaœšCc*?‡YŠeŽž‡rþ†{ÝÛu§›q=®ßŒEyNŒÂV6Ì(@í?/wÈïbägº”—*–/À:•P¹ŒïýÝS¿ íâ ]éŠÐù¶Æ¢E‹Œ^x^^^vᝠ   (…&Èdffª(™ôôtLxŽ)Ϗ‡œ•H€H€„€‹ŸJäŠÅ‹£C‡hߟýƒŒÈkI€H€H€H€H…&È[-JŠS§Nh}âe"'  ›" +Û :ÏZXžp!€’à‹/ŸÈè›ZAK$@$@$@ÖI PqùÇD\\&>;.±[”[ÖI‚V‘  @:¯ÚЕéŠsçÎaéÒ¥?00w o    K(tAæôéÓªj!¥+$@$@¶J@WŠt^õpàÀlذýúõC“&MlÕÚM$@$@$@$`ÅŠ\‰ˆˆÀO?ý€öâ1B¡ÑGî„>îŽc¢i$@$@öN@çQºr= ÿžš={64h€¡C‡Ú»ÛôH€H€H€H ˜¹ #~Jr_)!Úœ{wŽjÕ Ðg@±úäðbÂÀiI€H€J4£a«’kYµU)$$/ŒðüüüJ4:O$@$@$@$PxŠEw/^Œ³gÏbôèÑšR¥ iÈ'“‘TxÞrd  ȅ€Î§äµgÏUð‘GA`` Y‘    @¡(6A&::ßÿ=|}}U>gggè‚¡¿¹©ÐœåÀ$@$@$“€®T}èü;âÒ¥KªªR›6mXU‰·    @¡(6AF<;wîþúë/¡GÊY}ô!õb#  Â& ó€®\oÄÅÅ©?xzzbüøñêl$@$@$@$@$P˜ŠUÇvíڅ-[¶ ÿþhÚŽ©A”¹¹IE˰‘  @aйøCWi°~á…8}ú4&Nœˆ *֔—H€H€H€H€ŒŠ]K$JFþCXòÉT«VMå‘QùdR#¹T$@$@$`yŽnpš2Ð9bÛ¶mØŽi{ì1UY‰H€H€H€H€Š‚€U2 ˜3g’““1nÜ8•WÉáQFŸQ8  @ "à0pôĉ'ð矢wïÞhߟ} "@WI€H€H€H€Š›€U2!<<³fÍB@@FeHòwúȝÅÍˆó“  ؇JC?UÚzöìÙ*ÙÃ?lGÒ    [ `5‚ŒÀ:þ<~ÿýw4jÔC† QüôQ{ =a ,i#  €•pšÐp«„7n`ƌšQ£ƌNgå–Ó<    {#`U‚ŒÀ=vì–.]š­ìš>b ôI¡öƞþ  !]Ù®ÐyÖFLLŒªšäîî®**É;     5«dÀþýû±zõjtíڝ;wÒnòÉ€'5ÎG$@$`t~AÐy7Abb¢Ú›ššŠçž{ÞÞÞvà]    °EV)ÈH)‡œ~ýzôêÕ íÚµSe°¥6   „€Î»t~mUâxɧÄ??¿‚ ß$@$@$@$@$`QV+Ȉ—RŠtóæÍèÙ³§ª~¡>}ôa‹à`$@$@öK@çY º²Ý”#‘1±±±˜4iÅû]rzF$@$@$@6CÀª¡ž}ûvlÜž=ôÚŸ€¿±úÄ›LCI€H€Ї€Î­"tú#>>>Û6%Ÿâ1ˆ³’    € «dÄÖ={öšœ2²u©OŸ>ÈŒö'Å$  Ü 8—†CåሊŠÂwß}•À×ËˋÄH€H€H€H€HÀ*؄ #€Ž9‚Å‹£qãÆòÈ@8„ýji  €•pp†C•»‰oŸùF•¶;v,œœœ¬ÌPšC$@$@$@$P’ ، #‹tæÌ̟?U«VňGº TҎ’ŒvôH€H •‡áð‰Køé§ŸÐ©S'<öØcäD$@$@$@$@VGÀŠ¡ŠyóæA¯×cÔà TñžluPi  @ñpšÐ+6TÛ\‡ †nݺ!œ•H€H€H€H€îAÀæñGªd,ZŽÁÁÁxlh_4. dŠq±I€H€J04Ÿ¿Š‹ €IDATÎøyá&\žpA勩W¯^ ŠA×I€H€H€H€¬€M 2Ôµk×b˖-hݺ5tª §„ãÖΛö‘   ѕ1wÑv”+WãÆcòÞB`Ì!I€H€H€H€,KÀŠAqöìYµ…©téÒxüчQÉù+0Yöáh$@$`Õ–íŒÁª­gÑ¿<üðÃVm+#    €Í 2âHttŽªÀ$⌔ÅîÖº"ô‘;¹Ê$@$@vL ,"óVœG²®}U«VE³fÍжm[”-[ÖpUFejôYb ôú¢X;ÎA$@ÖI@çkY„ßÖaßñP=Š+W¯!00AAA*"F§ÓY§íފH€H€H€H€Šˆ3@'''cϞ=8tèN:¥ò4lØ͛7WïٛH„g²"jô)×A‘Æ ÐìB$`›ݔ“æà‡oãØ©Pœ>s111*F~WŠ˜íâªv¶¹ÀޚH€H€H€H 0P) ՌŒ >|Gř3g‹Zµj¡~ýúJœ©]»vî#ŠD@Ÿ$_‡h2Ó 83»“ @1pt= stWïptGªÞgCbpú|(Ο?”+WNý>lÚŽ)š4iÂH˜b\2NM$@$@$@$`Ý(È<àúH.gΞ=‹‹/"11ÕªUC5”8S·n]øøøÜ=Kê-蓯Éá&#å-áå$@$P@:£ž¢ËY4±%»øâL= ɳ¬Ä—ëׯ«\[š(-LéÒ¥ h»“    @É$@AÆÂë~óæM•sFę˗/ãÚµkpuuE¥J•P¹reš—䀑ãÆ&‰‚•@#4á@z¢…-ãp$@%†@.Ñ,šÐ’Mxq0ù”'33·nÝRâËÕ«WÕï°°°0%Ÿž»»£J•*š^œºœe;’‡‡G‰ÁJGI€H€H€H€HÀ’(ÈX’fcɃͥK—påÊõpsãÆ õÀ#å^å¯Ëòò÷÷W¡þÚ÷2>.pÑߟ#Ѐ±¢S,•ÝN¡×ëU#=ÔÿÉÿ Ç ŸõHNI‡«‹“:fÈI­œúÞ³NC¡¯Îð›„ÒޞŠ¡^¯3ôÓúÈ»ºVg˜SºfÙ“Ÿr,6!Þ^ò¯$ñ«Ný£Ÿ«D°:Ã6˜¬Ï†ãžreüÔqCƒmÆk²úÇÉꗘ˜O/888ÀÁÁ:èï|׎;d—šÓñsÚ&ŸjvšØlž&§ÝYDz7pËî_nýò/ï[955ÑÑшŒŒT¿‡Ž—|—×íÛ·áì쬒—KŸ,’%ê¯f͚Œ~±ÛßtŒH€H€H€H 8P)êYsÊ_å%۞$²F†äAIaÆÅÅÁÉÉ žžž†—‡ <\Òáéœ 7§ž;¥ÂÝÕY=D»º:ÃÙÉÎΎprt„££N=Lš1ÉÔ둙©GfF&ÒÓ3‘ž™©²XÕs¯ƒò(ëõø+¬ê¹P—ÕÏÐ_Ÿ«GAu‘–¯ØðømZ`J{ø7<Þg5íá>«ïõ1šPÎÛ d]l ²Æ6>Ðæ ] ïژ†ÏwlÑ>ø³„=p5< •+úg wŽ›ö1Žoâ‹Áƒýƹ4QCÔă£ÒõvtKÔ0Šwü2ÎaœçÎxš RýËÑÑÉ(Š˜Š+w]¯Ù¬I†E6¬Ÿz9Ä ÓïYëoÚÏ(pdëgž/ŽJ9òž’’77·lÇ šHö~Ú±ŒÎÅÇÇ«š ¹D<ŸƒP$÷pŠñ³vL{—|N"ræ<.ßTt‡ñËOŸ‹Ý’lVòCiãkŸå»ü\Ê6ù¬œÄO±MýlšŸµì>jßÃÃÃUDœleôõõUŸˆØ‘ۻؠ×úÈ÷œã›Ú(÷CZZšz‰=â‹$!——Ì™””€Þå% ä%×Htž···òËÏÏO Â"ÀTšPA 0‘H€H€H€H€H p P)\Ÿ4ºˆ2ò×jiä³<šÊK®’“␩‰ÑHMÏ@zZÒ3ä¥=4f $YãòP-vŽ"Ø8ÂÁÑðW~ÃC®A2‘znŒÂƒIT…:¬ÏŠªœ±F" ²JջỊ4qGEާ$§ÀÝÃ#KÔÑ!&6>ŸŸFaH»ÖôaýŽ``*äþYüQþ9ˆYöe}–È€Š+ªãŠ¹ÚøÚ5¹3í#‚™–ÈT¹µïQQQ*ÚI;fZâ×ôí‘*‰@žW?y薇éŒú™Ú õÍM Èí˜aÝ Â‡ö¡PÖÍ#·~"nˆœù‰*šÈ`ºÖ†ˆ•;ë˜Sü0]“œ÷HÎ5”Ÿ LÙç%¢äŒ÷DT‘-‡ŠýÅ'Í6±]c'ïÚwù,‰n%Ÿ”ˆ:"rhJÎwOD9®œä˜& ™Ž¯Ù¡Ýç"ÚÈKyÉý!‚‘P"æÊŒòñEîÛR¥J©þl$@$@$@$@$@ÅK€‚Lñò·ùÙµšíÚô=·Ï".ɃqÎHS1àA>ËC­Q‘×8:·ˆd퐳™Š$Ú9sŽII”jZ¡Ëœë4á /;L#V "j™ ’7ÄTŒ(È8Z_E0G@±ù:@$@$@$@$@$@f  c&(v#       K  c)’‡H€H€H€H€H€H€H€Ì$@AÆLPìF$@$@$@$@$@$@$@–"@AÆR$9        ˜I€‚Œ™ ØH€H€H€H€H€H€H€,E€‚Œ¥Hr       0“3A±        XŠK‘ä8$@$@$@$@$@$@$@$`&ÿ{·#Ÿ˜8tEXtapplication/vnd.excalidraw+json{"version":"1","encoding":"bstring","compressed":true,"encoded":"xœí›Ûr›H\u001a€ïó\u0014”æf·*fú|ÈÕȧز\"Ë#ىœ™ra„%l\u0004\n Kr*wû\u0006û\u0000ûŠû\bóƒ\u001d\u0001:Y>)JjûÂ\u001144?Ýÿ÷Ÿè|}c\u0018¥xÔsJ3Ž-Ïm…Ö ô69ㄑ\u001bøÐEÒã(è‡vze'Ž{Ñ»ßÏî0í {w—ã9]Ǐ#žî_pl\u0018_Ó¿¹ç„Ž\u001d[~ÛsÒ\u001bÒ®ìQ\u001aÓɳµÀO\u001f‹…€RQMõø\n7چçÅN\u000bº/-/r²žäT©|ÞÔBÞn\u0010Y¯\u001cV†Û\u001b;Q#{ì¥ëyxä¥bE\u0001ŒJÖ\u0017Åapí|t[q'yöÄùyw…A¿Ýñ(*Ü\u0013ô,ۍGpŽ¡ñÉ»)xgdg†ÉMD\u0011\u0013#I\u0010S\u0002cŒ²—Mï—&Rœ#Ê$†å„\\[\u0017„‰\\¿¡Že’]Xöu\u001bÄó[Ù5—Ö\u0005B<»fpÿ¶L0SçÛøŠŽã¶;1\\Â¥6I®e«\u00169érpŠ4‘Zf³<œ·ßJ5ã¯ÉùìXaï~ÞJ©”9ɓÝIµÊ«VnÅ»ŸŒ*\r\u000f¯?œD£ÚA|Y8¹\u001cUÐC+\fƒAiÜóíí¢qÛ·›í&ûHم%Â@ýi‹Ãj÷\u0005Æå-Ž_¹mú§{²\u0013\u001eS·þÅ+÷–\u001b÷þW6•ý^˺c\u0001\u000b®8!R!IÉžßsýkèôûž—\u000bìë\fŸ79\u001fÇ­¢x\u001e·\u0012Ó\u0004ÝÜ\u0005\u000fa‹«\u0003}ú¥±{Ž>T\u001bávkÉ\u0003÷GbË\u001fĖra2Í(—‚*¥ŠÔb‰LE€ÐHßa;)×ã°Åܲ..§±¥\b¬C®å¬Ã˜[Âù$©\fcA1£ò× u»¿wàŽ£ÊI÷ºy28ýS|ž\u0019ÝŸÀž7µ“Û(šëÊ\u0011:\t>\f|õv[/Fª\u0004?%^ŠÔØ\u0019Ƴ •ŒÍu®˜JP^\"–§ŽiõΎ«\u0007v0Ž¯ë•¡Ú@Ç\u0002Í¡Žcٝ~èŒ6§\u0018=\b*£Â€¹Æ\u000b€\u0012„LžkôY\u000e6\u000e-?êY!à0M+Î-F†§˜€\u0013SFšb˜Ÿ‚#}I…ÌÖ=ðã†{뀳Y8»ku]oTXºTSARãÿýÏ¿!GÚØrÂ8?«‘\u0003\u000fOUT\u0015n+{n;Qê’ç\\\u0016µ=v!,\u001dwÇAæOK6ˆaÁpá~kòu‚Ðm»Ÿå5çˆô$â\u0018šë\u00165'J1—\u0007®Û\bnªgõQàî\\ž\u0003UïoœWíµ\u0007Ž2m²\\£\u0005à Þ-à˜\u0007à…£¹Ôb\u0001p’\u0011A0z\rwžnŒíö=Û\rRõv/\u0001šØ1Êýž\u0003$Àâ®\r‚\u000b¥|\u001a•BÎ¥\u0012aÍ0ÁËç˜W(Úkñª\u0015QÔÞ\u001f}:Ÿ²v\u000fæQ¹’`u\u0019&57\u0011cò>ÉÄ\u0005$\t㊖‚\u000bÂÒäOÑç 97Z…ÇÌH+É$Ž\u0010;\u0013¬\u0004átµ<*)s±ÐkóØ(×>û†át-×{gùŸó‡3Žº=Ï\u0019\u0017VîçwŒb.zX\u0005Š‹\u0005|\u001a…|A©G(®\u0004Ë©ÈC\u0018ÖŒÍã‹Æ§míÝž›üÃû!¿¬®=†ÊĜ+ÌïòBVàbYàP³WáP«i\fg„¡\u001c+ý\u0003²ÄÃcïæFÆå³ÊÆàSÙ\u0016§\u0003ÿÒz¹úÈJ!¯÷/<×6\u000eœµp®9i\u0016â»°ì#r•‘\t†\u0019\u0007ˆ\u0011’™Â<„pûô}õL¶«ü°?\u001a:_ΩœyÅÖºìC\u0010!&Á\u001cÂ·Ž©bpK45\u0005…€â{{Vpû\u001b!êÂ\u00113\u0002[Á\nu\u001f”=fL4Ωé8³ä\u00181N2\u001b»\u0012¢ŸQGy»hÜò^µï}\u001cج\u0016Ö¬~óèŠÖ­lÿ\\õ\u0019–ûŽ1I“b”#̖§)Þí7¹œ¿#ëûVõ¶\\i†Ÿºõõvˆ\u0004\tº\u0000'ÊÐ*p\"šLó3Ã#*‰ 8Õì—N\u0014óYWsœ]Û#£\u001aŽ×Á‹-”ïI\u0010*<79d\u0018\u0000\u0004óº|ÉŠµU>=ºÖ|cØ8riu_’µƒÐÄ\u0010Ü\tšÆšRÿf”Æ©R\b\u0013”\u000fs\u0001\u000eLE\u0001K\"¹\tá«Öœh\u0004Qª|^Ÿ8\u000fK,—ª—\u0012ªžæJœ‚W[\u001f*{^`µŒ80¶š†·\u001e$NÉô$ú„ž\u001fP\u0012®•\u0010ËWf6k×êËàÌ=öG78fº‰xwÝàãŠb˜1Jž`TQ,ŠÑ“\u001a)BÒIœŠ€\u001e#Ȕˆ\"L‘†û¹|\u001dˆÕŒˆ’L}H\u0014R\u0012€/W;[\tzZàÜŽŒ6zœ0躑c\u0004—†ëÛ^?ÕÛ5ÀoŠ\\\u000b\u0011Œ‹‚g0(ÑÜ0\u0014CP\u0006ʊÔò…™ÅñþšP8Q˜\u0011ŠšLÉä«[\u001am\u0016©#Z™À+RB+‰±x^]fnV‡µ\tî\u0014+*\u0004ÃI!hšA*M)\u0011gœƒÇCœãI$5’Zqðì?‰7Œb+Œ7]¿åúmèÌÒŒïûÊö—Ø ’Bl÷\u0013)7 ¶aÉ6*ð\u001d\f\u0011L²rD2\u0017V/\u0011Z›ZS4þæËèý\u0015ã|³äø­‡…Z\\Ÿ(\n…€\u0014$\u0001\t¢&Œ\u0004Á³€\u0012D\t…ÀžBЮЅò¬(Þ\nº]7†É¯\u0007®\u001fONr:›å\u0004óŽcMY\u0010x©|߀=è%#\u0016³ù엑\u0011“\u001eŒÿõvæÕó•9íTãlž7ù\u001fmÉ8[`É ÛÆ”ÊGì&\\XaXOKŠ\u0013[Å5M7`a€'2jMŽÁšc&Ê…ý/jÈ\u0010d\u000fÀ—ä\b'‰Æ\f;†\u00197!€\u0014D+X\u0011>lK\u0001¡\u001f“bÅÉ6ÀGžT ^Ґ-m3ÉÂT8Þh©§í\u0018¡Šâ\u0010~!Ƅ\u0010\nbå§Ù1±Wó+_Îk{Ý†Ó=oôNwêåÙ2I®\u0005Ø0˜,Xٜ—Éd\u0002ý¢TpÊ(†8•ÿÜVlc®*'mJ‰\u001fiÅ\u0016ﯜ[”\u0010ˆ!\u0006AÈò\u0011Ùâ\u0005þ\u0001vL=ü¥LBžÄ‘ÐS•¿4\rR/Zgw\u0004Ó\nM\u001b2¢Ya'\u000bŸ±¿\u0012\f*Î54eÉ4AD2%V\\uÿ\u0005ªã¹­ä“Ÿ\u001c\u0012\u0012ÉÁä=bׯù±~ßxr{xûñl‡\u000e6‡\rýC}ùÃ\f@ޘ„„w;ÿ“V`€#¶ŠâøÌRÀŒ]\u001b\\@hÅ4Yq-`µež\u0006äìN«°3é³ßt»\u000ež¬nÏøGc«ùÏGmÞ°á\u001dð5¶o,#铹Ì;ž\t,\u0015xDPWŽü7«àʱ[W§×\u0017·}7ö(>\u000feÅ_ó\b›Š\u001fy5Ø\u001f=Ã5QAÍä³\u0001$pwíYTÎÛÁår\u0005:\fK‚µúÿ\u001e\u000eã©È.AŒ\u001a\u0005þ璱3Œ\u001d]Ê3åzó}\u000eÓù+Yœ^#†Ù\u001bÇþ°ünë~\n²ÑK7®3؜õßÅҖŒš\u001a‰\u0004G'Yü¯ßÞ|û\u001b¥ û‰"}„ôñIEND®B`‚fulcio-1.6.5/docs/img/return-cert.png000066400000000000000000002362671470150653400175150ustar00rootroot00000000000000‰PNG  IHDR…W$Qñ0sRGB®Îé IDATx^ìÝxU¿ðwwÓ;$B¯¡÷Ž MQD ¢ (œ‰¢bAE°¡ØPDýôªˆ ¢*ˆ Jïœ×ÐBzï»÷ùŸÍ„%² Iv6yçÞ|IvgNùÁ'3‹Åb7 P€ (@ P€(“†Â29îì4(@ P€ (@%ÀPȁ (@ P€ @`(,ÃϮS€ (@ P€`(ä9@ P€ (@ P  0–áÁg×)@ P€ (@ 0ò (@ P€ (P† Ëðà³ë (@ P€  yP€ (àÔòÈe³ÙŒ¬¬¬œï±±±ðññÉùÝö=۟µãŽ×r—#¿ÛŸŠý®}Ï]m[ޟe_۟sÿ®œ—{ÿܯkƒ”ûÓy=rZ^+죚ÅÂd2ýçxƒÁðŸó$÷k¶¿ËÏZr¿®$¯§ŠŠÂÃÃF£Q}ÉkÚ׍~·}/÷±Ú{ö|¿páªW¯®êÔʱ-/¯Ÿm˵=&w☻LÛvËù˜gÝyµÅ©ÿ¡²ñº`(Ôõð°q (@ý ddd --Mý1Ÿ””€ŸRRRÔïòzzzºúÊÌÌT_ZšRA%í,à2³™%ï[Ü|ÉŸYYfdfÿnÝGÞ3#˜³ü.ßå÷ì×ä»ÙlÁ _Ù¡Eˆ٠£A`Paà~Wßµ/yßh€)û»õpÛý¬¿Ë>F-0šïÖ𠯧$§Â××&Ù/{ùn2i¿[Ë»¶Œì6e—¥Ž3Y밖‘}Œü,¯­áÊ€“œÈòòóµË"OSïX7Ù÷ÚWŽ—¯î$Ç\Ý?33 ®.ŠìݲߓoêG‹õ[NéÚûÚëÀœ]¯ì›ó¶õµWö‹‹ŽÒŒÄäTxyºÃb¶Yu~HÐ϶9¯[Ìjõº)a;ûõš ߀Ùb='ä»ü®ÂuVv0×ÊÔÊ7›qùJ‚ƒ|¯–œ”‘S_N=f˜U™R‡õ»*_Õo³¿mûՇÙ}Ëþي)8®Ù$ÿõRbÊÞ:æÖsãê9šËrþiç¥|·þnŽîk’sÜú»É$¯Áú]ö“ÐjŒ&yÏúoA^·@Ÿ\“ WM®0˜Üarqƒ‹«\]=áêá wwž{xÃÓÛžÞþðöñ‡««+ÜÜÜԗ»»»úÊëýý—­l·ˆ¡°l?{O P€È`—™œˆˆˆ@TT¢££‡øøx$&&ª(áMþ–?2e†Gþè“ïêAW“úr5&c&\ Y0"C},i€9 K:\Œ€‹‹ .êQÙß“‹.òe²Ÿ®ÞÏÞÇúºõ5W—ìc²¿Ëë*Œ]óG³6ãÄŠ€þ¬9O ŠÙ?KpÌ~ýjˆŒº_–Ù‚,5#ný’}¬Žd©×m÷‘÷³T`ՎQeÈ-šUYÙïeï£>p1›sfjµ ¯Â±Ùåd!C>ÄÉ0#=#éYHKÏ@jZRÓÍ0š\`4ʗI`p/üýýáPåƒ\>~åáãWŸ~ðõóWÿáæ8†BÇÙ³f P€ @‰ È ^LLŒ ~aaažxñ"ÂÃÃŽŽÔ$XÌØÌð÷F9?O”ó÷B9?ȗ¯|\àía€»+à&Ɏ(@³¿RR3œ’ŽØž$DÇ'#6.ѱIˆ‰KV³ÞÖKi˜<àí„JUj¢rµPUC@@ʕ+§Ÿs+~†Ââ7f  (@’0§Ã’˜ÓՌ\Rbœ {—ïàôés;Q±0Xä2ÍL—óDH…Tªà*üQŸœü|<áåéV2íe- @™HLJE|b*âRÔWDT<.†Ç!:. ..n0¹ùÂbò†‹‡?jÔnŒ +#(HfƒÕ}˜ÜŠV€¡°h=Y(@ PÀ!–äsžrò/„_<‹Óa‘8qæŠúãJÛªW.UÕWùrÞ( ÷ÁqŠÏ!ƒÅJ)@ë ddf©ÙDùŠŠIÄåˆxœ= W¿œ èêQ5ê4DŊQ©R%„„„šYGn…`(,Œ€(@ 8T@î÷»pþNø‡÷mFZZŠºÈ×ÇõjV@íêÁšè‡à@_‡¶“•S€žùïZDT®DÆ#<2ç/G#)Å7O5›˜eðBͺQ¥j-T©REÍ&r+˜CaÁŒž7(@ PÀa²0ŹsçÔœ€@TøiXR.À͘†Fõ*£Vµ „TðG€Ÿ—ÃÚȊ)@ ”„€Ü—xéJ,.†ÇâÜÅhµxŽ‹»Ìoxù£z­š^» jÔšQÍqú: ~Ù P€(ͲBàéÓ§qæÌìÙ³'çñ •ÒÑ Jª…”C¥`ÿÒLÀŸQ€ÈWàҕ8œ¿°K1êÒS7WXŒn€k9ԪߵB[0 Þ@‘¡0ßSŒ;P€ J^@fOž<‰Ý»w«Êå1µjÕBhòš ·„’ok€(à±ñÉ8{!Z݋wXÜ*ž•Q'Ž9êÖ­«îGävU€¡g(@ P@'ò˜ˆcǎáàÁƒê¹€2KX¡B4lصB\à KÒ)Ž–Í ( YÙôÔ¹õ•”’wßjÈt †O@e„††¢~ýúpqqÑGй… …Å Ìâ)@ P€ù Èå¡GUPä.—nÑ¢êÕ A%¿d é,éQùÃ÷)@ Pà—#âÔÊÌÇO‡Ã«\M<« 9݄ šß么euc(,«#Ï~S€ €CdðСCê+** ²ˆŒ\Î$ŸZ‡V÷kú9X’OæL‡¶“•S€(mYYf=uGO…#Ap󫎔 WµriãÆÕc.ÊÚÆPXÖFœý¥(@‡ €§§cÿþýjõPùY»W°aýÚš˜aœq á‰Þð,W éYî BÓŠMQ¹råb¯_/0êe$Ø P€(ÕØ»w/öíÛ§ú)PîgiR7Á>ñ°$²RKµ;G P@¯‘1‰8xì"ÎDžÀ7šÒÍÖp(—ò˜ݥ}c(,í#ÌþQ€ €Ã$ Êã$dKKKCœ:5ÑŽ®=bÔs¹Q€ €>dåÒ}GÎãL„+|ë"5ÓÕªUC«V­àë뫏FC+ ‹•ER€ DàøñãØ¹s'd–P.­RÁÍC}ìd&‰ t* Ï:Ü{( —Œáá_1 ™hݺµ ‡¥qc(,£Ê>Q€ €C®\¹‚;všd |\“ЪŸ/ª•ãå¡VN P €—®ÄbׁsH2ÂèS“Úµk‡5j°$}ïÎPšïñaë(@ PÀ‰dÑmÛ¶áðáÃðpÍBjÜyŽnà‹Æµýœšl*(@ ä8v:;^[@(2 ê’Ò:ÀÍÍ­T`1–Šad'(@ PÀÑgϞÅÖ­[Õ£%ÒãÏ šÚ5¯wWG7õS€ @È£,¶ï=žð,ßééèÔ©jÕªU¥;¶†BÇú³v P€(›6m‚<€^>1ÎJ8ŽöõMšQ%°ôŒ] (@Ü—®ÄaëdžUGºÅuêÔQáЙ7†Bg=¶ *pùòelÜžQµ!-5 ÕâС¡ŒFƒCÛÅÊ)@ P ø¶ï=ƒÃ—<áPîîîèÒ¥‹zŒ…3n …Î8jl3(@ 8\@@¿}ûv”+W‰q—Ñ© jUbtøÀ° JPàÂålÜ‹gm$Šd¡k×®êŽÎ¶1:ۈ±œ (àP¹gðï¿ÿFdd$ŒF#Œ\’qKœxx{–ŽÅŠËÊ)@ 8¡@ffþÝ~ç“B`v D£FÔ ¥ÎŽ1:Óh±­ (àP˜˜¬_¿^…ÁäädÔ­â‚ÖÕãÚ&VN P€úØä<¶I†[¹Fš\¥*zöì ƒÁ9® a(ÔÇ9ÄVP€ €ÎΝ;‡uëÖ¡|ùòçvm€Ú1:o5›G P€%)pþR Öo9 ‹_3” ®©‚¡··wI6¡Pu1ŠQ€ @Y8rä6oތàà`$'Å£{3œù ú²t°¯ ìHHLźÍG“æ¯àfžýöÛÕŠzÞ õ<:l(@ 8\`Ϟ=P(ŸôÍIèÞ †Ïtøš° ô- ÷ŸÿµéÎ^ˆ{…öèÝw *Tš ÛF3êvhØ0 P€pŽ€¬.zþüy˜L&x›МqŠ£›Äú)@ PÀ‰6î8CÇ/Âä]w J•*é²õ …º6Š -°eË„‡‡«EeLqK#“£›Äú)@ PÀ äy†;÷ŸÉÕy +VÔ]/ u7$l(@ 8Z@ˆPÍ2A‡&úŸÄÑ^¬Ÿ n,°ûà9Ȭ¡‡—˜ƒÀÀ@]‘1êj8Ø P€pŽÀÖ­[Õê¢r?HpÖŽoYÛÑMbý (P ö Ã?ێÁ¿|=: ŸŸŸºéC¡n†‚ ¡(@G ìÚµ aaaê’Ñ@Ã1thâïè&±~ P€(E»œÃ†mÇPµfc 6®®®ºèC¡.† (@G BÜÖ$Hvd“X7(@ P¿­Û‡M»Naü€é©ÛµDE K”›•Q€ €£d†066rÙèÀ[ƒà‘æè&±~ P€ 23³ðáWëàææ‚±Ó^ƒÁ³z‰©0–5+¢(@G ?~r/¡ÙlFÇŠåQ݇ÐÑcÂú)@ PàªÀ…Ë1*öéÙÝúMÜʗCa‰0³ P€pŽ€¬2úý÷ß«•ݪ¹¡] >ÐÑcÂú)@ Pà¿ò`ûîŔ±÷#€éƒ€ÁTìL …ÅNÌ (@ P@6lÀ•+W`€;¹ð>B= Û@ P€y |ôÕ:ŒŒ}|$ Á݋]‰¡°Ø‰Y(@ 8Z@Výûï¿a±XУ¥'B|bÝ$ÖO P€ž®Àåˆ8Œœp5†öo‡6ûÃP®m±j1+/ §(@=,[¶ š˜uSõÐ$¶ (pCÕaýæ#x~Ê@x× žø›Ca±Ñ²` P€ЃÀþýû±oß>³â1ž³ ŒFƒšÅ6P€ n( W·ŒöÁJ4 ­‚{†Ž†Á¿y±‰1- Š(@G Èâ2‹/†ÉdB‡ÐLÔ©˜åè&±~ P€ €ÝGO^‚oþÆsS‡¡b“ávWÐ *Æý)@ PÀi¶lق'N È;œZr†ÐiŽ ¥(@¿ù.&#FM|¯Å"ÃPX,¬,” -¯f È@ÿnö7:ºI¬Ÿ (P`+Q x團>y4j¶Zàãí9€¡Ð%îC P€N'ðÏ?ÿàäɓšS!·4ruºö³Á (@Mà›å[“„É3®EÃPXä€, -«f ™1xð¶x{º9ºI¬Ÿ (PhøÄT̘û#ŠN™ŒÐÖ ]Îõd(,rRH P€ŽY£G¢YÕxŽiàçèæ°~ P€ ÀM ,ùu;.FŠaÚKÿ»é²rÀPXä€, )€/¿üîæ+vGež¹º8²9¬› (P$IÉi˜úêÌxöeÔiÒ­HÊÔ a(,RNF P€ŽG÷î܄V5кqG7‡õS€ ŠLàÛå[›êñ3Þ/²2¥ †Â"åda (àHŒŒ ,\žH:Ž‘À͍³„ŽÖM P€E+—‚'_ýsç-Bp•Ð"+œ¡°È(Y(@ 8Z`ߟ}ذvÚÔÊ@»µÝÖO P€(rOŸý^åêbø˜‹¬l†Â"£dA (àho¿ù —Žÿ…QCÚÂÇËÝÑÍaý (@"8‰7®ÅG_¬„É¥hV×f(,òab (à³gÏâ§oç£ymtm_t—Ô8¢/¬“ (p#×>\…ַ܉;Œ,(†Â"ad! (àh5+—`ßæexp@{Tâc(=¬Ÿ ŠO`ãŽøcÓ9Œ:ïÛ"©„¡°HY(@ 8R )) ̝ˆúÕœÐÿöæŽl ëŠ(@ ”ˆÀ€—cüÔWQ¿YǛ®¡ðŠ Y(@ 8Z`ÏŠŸ°æ×oÑÿöšW«¢£›Ãú)@ P€Å.ðõO[jš€Ñ“_»éº ošP€ €C2ðÕGO#:*íéЊ°r P€ @I „]ŠÆk®Æ'_­Œ7·à CaIë¡(@bžrìW,ZôºvEÇVuŠ¥J P€УÀKïüŒÛïŠ.œŒ©æ1ÞŠ(@‡ €œÇ–?àύ‡1jhú:Ž9¬œ (P’¿þµÇÏ¥`ÚKŸÞTµ …7Åǃ)@ PÀ‘–Ø]Xðá™;>^nž¿{=4‡m (@ 8\àÂåXÌùp%>œ?†ò Ô†Âqqg P€pŽ€%å"žš2ÜÝÍòQŽÖO P€ú˜øâ·˜6Š?ju˜\ F1ˆ‹;S€ €£.Ù‰·^{ώë‹rþގnë§(@ èF`Þ¢5hT/}ï{ð±»] …vSqG P€ЃÀŠuKñûò/y?¡ƒm (@] ü²fÂ.Ecüøñº„”¡PWÃÈÆP€ @~ÿ[8H8†‡ì~‰üÊåû (@g8râ>ÿá_Œñâh+²»; …vSqG P€ЃÀ‹ÏŒE¯¶þèØªŽšÃ6P€ t#š–É³ŸÃ[3ïƒ_£±v·‹¡Ðn*îH P€ŽHNNƌiá™‘mP1ÈÏÑÍÑ}ýiY®8W&“;ŒFÃ5íMKÏ@\\ â¢ÃQ)À‚&u|`2˜uß'6 n,ðìË0Ž[Žè9p °‹‹¡Ð.&îD P€z8}ú4ޙ;ïÌž õ!GíÓ[’3=p(ªL.n0ªy&“IٙÍf$&&âСCغe3úõh€»:W„Á’¡·näٞ·þ¶ÇÒOÆÂÅdí7 P€üßz„TðÇ=Ê^5í"a(Ž‹‰;Q€ €Ö¬YƒÝ—ãÉGZê¡9ºoCJŠŽÇ×C–ÅEµU §§§ † - bbb°~ýz\8† #z!48°dêŸoƒÇ.À²ßváòÎy.ï«ûö² JJ`åÚ}8‰Sž†Á¿…]Õ2ÚÅĝ(@ P@‹-‚% Cn¯Š‡æèŸ  O$„Âäê•3C(AP›)”deeáȑ#رcz÷î…NMà–|ÐùŒá '>Âò?vãĆ9šU-H÷cጠ”aO{u ~_wÝÖ¯>95«:cWØf ”)ƒG/àëå[0÷•§`ênWß íbâN ( Y³f¡W»òhßÐSÍÑ}$žL¬ôLƒº|T „Bù’MŸË¬á¥K—°k×.tìØ­[µ€)ùŒ3ŽÈÅÒÇðÈxœ8sQ1‰ˆOLA£zUЪIõÕ5pô‡¥×¬{õjV,бÜÙ>‡&/Â⟷æììëí_>›€[ۇÚW@ÜKù˜÷éjÔ¯S ƒîh]Øe=Ä'Šâ©9?àœÙãáQs°]Mb(Ž‹‰;Q€ €£ärGyîҋãnE°w¢£›ãõk¡P»|T ƒ%$Š©lr éÁƒŠV­Z3|Í'á–vDý|³ÛÅðXlÝ} ›vÄ¯îűÓáÿ)ò›ù£0Ž;»«ê7ò}¬úkÎm~U*Ù·‚Ý…óŽÉ)éðòt+æZ¬ÅKðž4ë;<4 útkbw™Yðš÷„Úøœš–‰%+¶©ßÿj2nïÒØî²Šcǧçüˆrþ^˜1¶oq_è2çþ'ŠŸ² cŒ_èr ;n…®°ˆÔëžQ÷œª˜‰/~‹§ÆÜ…êŠÚÕn†B»˜ž(@ 8Z ** 3gÎÄüçzÃ%3ÒÑÍqŠúS³<ÕLaŠÙtÍL¡Öx-$ÆÇÇãøñãðóóCœzõÔw7Wüp>æ3…ºÇðÐñ‹XôÝ?ømÝþÕ+—ÇŠÏ'þgÆ[ãRÐ>––ýˆŽÚè IDAT?ývʗ÷Ɯ߁Á3ÿËó KËȳ J¹ÀŠ+pöìYŒ d^ûv)ïz¡»'¡ðtrC5S(!PB¡ÜCšÝWh %îÙ³qqqªŸôôt€¥¥ÁÛË“jF5å>Nû/%}ìé/ñÅ÷ÿªÙ@ùã±AJ…îG^j32Y§?-P¹ÚqrЎ_ŸGËÆùÿ±T  lv–#©O6 Å£ž?¬Ü‰_×îU¯­ývºulPØâí:îï-GÑãþ·ÔŸ?Øg/DáâåX€ïœ³ žÝ[µQÚjk"a¶ûÐ7ÿ eŸ¿^qσªaÏ¡0uÜ'sÆcC»ØÕŠ›ÝIîÛón`}(·Ì¶ffeá܅(õ{ðݏßl…:~ü ßšGÈv[çFøãÿŠª9Ȟq{æõ¥xããßQ’ÁXºóÑùª_÷ßÝ_¿ûXNõ:.…'?P®H89ã&Ê €Íòí CaŸD܁ ô °páB”/_÷ŽO²RõÐ$Ý·ABᙔF9¡ÐÅÅ:c(›D-(&%%áØ±cꙅ 9 Òdffªpxkۚž¿WU˜ ö?ªbÍ?Ñçáwq_¿vøö=ë¥~E¹ÉŒÌé°Èß·uþR >øò/üŒz7»¿K.Y-HûÓ32QïÖgÕe2ÛöÂ1j&TîÕkÔóyœ:q÷À{³î/H±ùî+åËÌßÎýgUòuœmÄ}ñéÜáÈËäßí'ÐuÈëy†ÂèØ$·œŒI#nS3Fßý² !®™QÌ·¡Üá?lÄÒßwáüÅèkf s#3t}7]ÝÓW’›6³§Õ9øÎ6 §…·—Þù¯Œ·-~];Ô/±îþžjŸøa#ví?‹YSïÆŠµût;.%†¢Ãжí=­V~ñ¹©0uÍ·… …ùq P€ЃÀìٳѭ[7t¬zŒP÷žé¡%Ý …gS«ËGµGQh ÌÈb3Z8”‡ØŸ:u GUŽ—ðèáá___uiå`/ôji€—[–Ý]ÐBá€Þ-±ôcë¬NQn5:>¥ŠËëŸ-y”ªuû’š®fâäŸ8{·˜ždÈýt•+ÜÔœZbF>õ?U÷ÆeÏ\s™Ý“³¿Ç;‹Öš…_V~1)ÏŠef™±zÜ ‹B³†ÕЮEMž¹^{™ìŠ'±è» Ø}àœ*¿e“꪿÷ý8Ï2Ç­ê Iý*juLWSžûI¹{žS÷æŸ|T;àҕ8øy]÷~>i¿Ìví9tÕBÊ£ofðñr·w®ÙOîas­3:Ïc¥}wtk‚捪£qhåëÖag¡š ß®ß«*¬Êeº²Òƒ:à«wFÚ]€í¬r7no-ü²°KAiK¹TÎ¥j•Ë_÷’í¯ڌŸeuß—Q!ÐÝ:ÖÇøá=¯ù7QØq‘ b¶˜Ñ·ûµ³WRށcTÎGýûãvsa£ñÖ§`þka ¹;ß ó%â ( )SŠ`âÄ šaøKÍqŠ6h¡ÐÍÃW]6*›åg-(Š€€ ""ááájfP‚ ——àãレôD„œ„—kºÝýÖB¡íœs‘щØ{8 2«râìȌSï[cô]!³?®Ú‰'ìšç%•GN^FýÚsÚÐd‚ú£vÿjë=\ÚŠ­þhûÚÌ w©ëmYYf|µtÞûbí5³Pœ€m÷ßZš{ëu}VÍÒåµRçÖ=§1dÌ ÔQ=û/÷öÏöãûÜאÅzŽM.‘°:5‚ÕK2Ø®Þ÷Öš?_O º£*ûã‰gÿÏîÕ0e†Ó3tÌ5õʌ , Z»"ªW Ì÷ÞO¹DuÀc\c)헅nêÖ¬pMwåøtñì?zFƒ‚|Õe®¹32jƗXý÷Aȇ òHŒ‘Óÿ‡„€T5þÒ¶möxÚ}bç±ãÌ·~œW¡m³šxvüÇ¥ÈŠ­Ÿ¿ùšÚ۞s;žŒî|d>ÒÒ3qãŠ-üóÁËb̰nª.ù7“ˆàòŸ×ŽTÎÅYï®P3äâ&›„œ÷uÁØaݯYÁWÆCÎ™Ü›ì¿øýÑ×üû,èžœ»Z·<­ŠŸŒsÞ5íÔ.K–÷ ³€Ô͌aiuÉ¢l² E‡–µÕ,œ¶É2ré€lrù ¬J©Õiû•SŽÌîÉ¥©ÚÏO<Ô ó_º?ß0€ ­Ü)mˆÜ;ßîãäøõ› çoçôA/«³J[Ø_ΡÞÓV_•°¥.ã¬R^õAf eC±”2÷ºÖ{ì2O-ŒæC[d[“ÞÃÞÁŸÿºîXKø™øèmÒ¯­ ø{…© '[Ø¥htŸg®ºlV6 lZžµm¿Œ'¯÷Œÿ­ÿœ2Û¶ä£'n8Ã+Ç­ßr›—?‹vÍk]·­özÚ}bçÚQf€û°>zâèºÙ8yö ú>2_Ý_)÷YÊVÐs[•ãöْ0zÆWxóÙÁ˜:ª—úeÈžÕªŒ]ÚÖê/'«d¹ÏQîwÔ69/åm\$ìýúÅ$ŽnZCgò‹lRƃ;š2Vþµ?ç‘$?6û…aÊcœþ3Sœßžhã‘û߮ԧ+çô鍯—è Á…œ'÷þŸ0±BZ=˜ŒoØ\†Bœ&ÛG P€jK\ÿÑûo¶˜"v H( Ko 3\sî%Ԃ mrŸ¡|i+’Ê>îîî*J@ÌLOD%Ã.ž’í¬° …¶ɂ+wõl®f{$0øùx\ó°\r'—ÞÙnrߔÜ?¥Ý§ÍfÉLÞo_NV»þµñ0nhžúYBÜ܃ԥ„·=ð¶ ~3 Ý;Yu±e”gï=0ѺXü±Œô“±*,Ê¥l¿­ßÉ³Ÿ+ðý2+#3…Ò¿Ü3™7ŒˆNP÷!jpá܇Ղ0ï}ñ'ŠŒŒ$§< ^5;Yg[r/V#—uÊlPú!9÷™Ùó˜€Ü3¯¶ ŠÈxÉ""û‡]àä>I™ÝÃK;橙'mUXùùûcT°ÐM‘±ßðƒµÝôoœ÷uÕWÇ'÷GýڕðÆÇ¿©ÅS$î_óòuõݏ} ìYóõTôž¥až¬özÚ}RçÚñäÙŽŸóeՇ%>®œÑB¢ÌÜÉ žmž³çܶ­"¿qûfù<<å3Œ²P‡Gœ'Ô˶aBfYäÞ1YôB6m•E ŠA-&]³P‹véقÙ©{oŽi`YŒðˆxu)æõ–\b׎—õáíòöõgÉ]ŸÜ“%÷fI¹ßôDŸŸ°Q’ ôù’¯)RîQ{煡*TËRórߚœ3‘Zž°œ‡Kî“Åd¶ý2S<[íœüfª€ÏŸ±LÍ6}üÚ0æå1h£öοîö²ÚiNO©öï\ù|Î:ÚåZÇe¶Qf¯äòÅÜÛ '>Âò?v_3[%Ás ßbßêYj¡í²Ùü< óïuøÔÏsÎËë/ÁJî ln]LȞsÛ¶¬üÆí‡•;pÿ„…9‡Èb>òˆñ n1Y}"ã;ååïT(Ôf3s·÷¡É‹°øç­*FD'âÝÏÖäy·vœ6‹œ×ÊÂùËʵûÔ¥¬¶ P­ÝxXÍrÊVi)Ìx;ë1 ¿Ý¹_õžÁÀ˜÷,Zß u”Ùn P€eHàûï¿WJù`_˜/¯,C=¿¹®j¡ÐÅÍ[ýá¯ÝSh;K(5h÷ÚÖ&¯ÉCìÕ=‡)ñ2o+ÔLፚn[ŸêŽûÉ$|É" 2˧mÚì‚ eVa÷oÖÀ&!G‚”’<Û»4Ÿ.žv‰ÛÿÞ¡ÂZó>/©}÷þþ’Z™S6 ª2ûòø3_©Õ$Ÿ×7ÏEa®W‰ÌfvòFÎb+ÓvP‹µ\ Ã…Ë1*45­_EÍÞi‹×.±”ËéäYò‡œ|ÒߌaµœªŽK^%4Ée›ùm {ÌT}ØóûKªŸ”Ô 5[*›ÞlM†ÝÓQœ'aXBñsÑö‘Ð* úÈ¥Š²É,™ôŒ !«_6è>Sœ'‹çÔ¬šfªdÁÙ$L}œl‹ê»Ïß|$g–Wë뀗«G‹|øÊƒêraÙŽY*™i²X¬÷òÙ㙟ŸíûòoG.ɓ l»É%°r¯¥,#«‚Ú~ÈPsÛ¶ÌüÆM !ç§lRßΕ/šË±eÓfpßyá>È̲ÈG‡tÆÂ9çÌ¢‡GÆ«(³Ir.m^þœº|WÆÂv¡œÜ>Ú"Gyù‹ü»ê8À:»-a=$س?°þ7ÝÞ9 2^e}ßïݎ€”4<:lŒ•úݐƒ¡°¬Ÿ-ì?(@'øä“OŒwށ%|µŽXM”Px1³$J Ԃž\Fª=¯ðF-•}ŽPlÙW$ÙÝ1ížBùÃ?ö€u!ŽmŠz }3gqm_ùÃsðmÕe•²Å™M¯«ûýŽKµwKxé4pNÎñ2CyG÷АçÖ5kPíšK8µ‡Œÿß;áísm‘:å8 kr¢¶É"*>lWnͯ?òŸ„×çÞ\ŠþÈŸÞöÜø;Õ=a¶ ¢Äì?çûŒŽÓî˒÷¢÷œ—ç%¹¶Çi ÇÈ姃îh rr‰£„„E¯W»æ6‘×}ò µ*«\Ž+3;ymRÎ}ã>ÉYXÅöî2ö²’Š˜6iPUR¹„7÷e¢¶åj3œ¶ì>}}ø5—K(“YJYÝvî3÷ªKl_ž¿B…£ÃœŠ·ËY°'?O{ÆRö‘Kjå1ÚxÊÌ[óFÕP«Zp̏Úý€²¿nylGAÎmÛs,¿qÓ^/uɌ ,£mü}@-x#—ŒÊý{ò…lâ#áKf‰µÅ€dœþ]:C} ¢}ž"wËÏÏåI£Ýÿ'ÿs?&¿q‘gu»Ë~ÛõŸ²ç<=O=ÑÇÞáà~vü±á€z¬È€QwÂXmØ `(Ž”»P€ €cÞxã Žk×]ÛV‡%‚€°w4ŽP(÷Êœ‚ eEQ …Ú, vÙèÊÌHK@PÖ¶…BYœ³î­ÖûÊlWœQ=²pǬwQ—GÊê 2³&—‚•÷Q—ÊefGþzU…¶¡ã?Q³Z°“ržº ¹,¯•3%\>ùxoõ°zíòKmæLܐð&šj+ŽJy„Æ ë®š)h Ží§Üךö}ଚ}”:d–SžS(+8JÛäµÐ®Ïª{åµï>xü?+;Ê%Šòì±c§/£ïðùjŠ-|×;j1šmo~ò;fÌ]zÍ.rìÑõ³Q1ÈOœžÛD^ӂœ<†`È]moŽ; ì²p‰¬kk©,çƒ,PŸŒ'~š3“*AeÞóC®™á•…ddS6Û{åwYiUîéËœi ÏÄÓÇÛý?pÈ«³¶‹ï\ï2G¹LSۑÍvæ¹ ç¶Vw~ãŠÍË"=/Lúï,Ž#"*A…dY]V›Ü©m2+/ <2øuÊ6ïÓ՘þÚ깒+>³®Bš{“ÿfŽêû2BkWʹ§WÛ'¿q‘ýä<žóáJ|µt³ú@[õàŸ¯ A«÷ßð€æ›v Èxüùïa̜ ¡ðAÀôß{ºµ‚ í"åN (àH™3gbðàÁhVÇ–ÈÙ§ª[Bᥬ–jŠP6Û{ å^A ‰öl© ÌÚZ P(åʹëÖšpS¿^û$Èý³íztjšB£í&ønÚqÛöžV!L.”mÊc·ã­ç¬»g&æ>N¬X)Pîù™ x#Wù£XfLrorœÜ“%›ÌÂLxŽ'êÕ¬ ž;÷ïöøéwkh•°:òŸÎpwsU+¥æ·Éâ0]ÍU@fŠäÒ@ ÛZЎÏËDf…ò{x|bª °¶÷[J;×o>Ší{OcÓ®“jÕJÙ$ŒîZõ‚j‡œr)­ÜWÎß+ÏnHÙä±ÚâAڎÚ}›RŠ<:aÌCÝr.ÿ•} â)³¡ùmryò«và£WB­jAyî.³‰÷ŽY ú+A‘çDv³gÜä߁Œc^ ³H=ròîìqõ!ñ2. ‰©j3¯{5åÜü|É?ꃐÜϊŽí‡¬œš–™çŒv~ãb[Ž|ÓšçójFûŠç KÅã®#pèÄ%Èœ¶sžºÆJ}ë?ӓ¡§(@ è^`òäɘ:u*ªÄÜE÷íÕKSÍ^8ŸÑ^ÞŸj‘Û͞BmÿŒôT°lƒõÒµµ#)9M+yš»Þ7™“Ç äõLGi»\Ö÷îK÷_³²§=}Ò¯63hÏ1E¹œoòLH?Ï<ï3,l]âËù{_÷ÑÅå™_{%Å šŽ·üúyœ÷óí8¹ŸQ.ƒ}Öûp÷ÂVÇã®# ÿæä>QyΪ!° Ÿ®kÅPÈӈ t/0jÔ(̛7>æ°ÄìÔ}{õÒÀt³;®dԂÉÕ&£©PÍ2[Ì0X2PÞp®†ŽB•Áƒ & Ï”g î9†Ëñšì§îëÒ.T-Ê­`ô,˜WIí-·~÷çÔ3µ{ƒKªî²RÌ O{õ{È3O ­Ô×õ6†Â²rV°Ÿ œT 33#GŽÄ—_~ KÌ6Xâ¬ÏlãF P€Î+°aÛ1t¿ïMuíϋÆ;oGtÜòôôLŒ{áµP–{…ö0øçœ`”t¡PÇÉŠQ€ ¹§pÁ‚°Do‚%þY(@ PÀÉ{úK|ñý¿já¡{ú\ËÉ»éðæËвïŸ0>UnÁ¿ÅuÛÃPèð¡b(@ PàFgΜÁ{.µDþ Kâq‚Q€ € ÈBåšZW7;ø|ŒÜž7únúžç¿¬P[±nü›3ê{žØ: P€žžÀþýûñÝwßaöìÙ°Dü KÒbQ€ € |»|+†MYÄUGK` §Ÿ²“F܆šMú0–€7« (@bزe Ö¬YƒçŸ–ðßaI¹úœ­bª’ÅR€ @1 ,û}Y€{û¶ùϳ‹±Ú2YôÓsĈÁÑ mü®>ž$7/-“§;M PÀyÖ­[‡;v`úôé0_^€ZŸ9Ǎ œS :6 ³Þý÷ßÝŸÀWqÎ;®ÕÏ¿œƒû¶Aó[Áà×ôº a(tܱf P€°C`ÕªU8yò$&L˜ËÅe°€GÛqw¡(@ Pàåù+з{SŽí6¿& …<%(@ PÀ9–-[†ÈÈHŒ=æóK€Ìçì[M P€(a×>X‰î Óí2–°=«£(@"XŒx1ÒÓÓ1|øp˜ÃŸ²R‹°tE P€(œ¯/ø[×F×>Ãaðk̙ÂÒ;Ôì(@Ò- ­wssÃý÷ßóÙÿ–ÌÒÝaöŽ (PDo-ümšÕ@÷;GÀàۈ¡°ˆ\Y (@ ”°À¢E‹P®\9 tÌg>+áÚY(@ PÀyÞYŽÍVÃmýG2:ï0²å (ðñÇ#$$w÷»æs_„ (@;Þýl š„VÁíFÁàې3…vºq7 P€ЙÀ|€ZµjáÎ>Ý`[¬³Ö±9 (@ý Œûù4®Wœ<ƒo†Bý[F P€7˜?>êׯ>=;À|áGbQ€ (`§ÀüÏÿD# …‡Á§>C¡n܍ t&ðÎ;ï I“&žœkK˜/.×YëØ P€ €~ÞýìO4©_·ËL!C¡~Š-£(@ ̛7͚5ÃmÃ|y%¹(@ P€°SàÏÖ YýªžM…ÂPÎÚéÆÝ(@ P@gWCa#˜/¯ÒYëØ P€ €~æ-Zƒ «¢çÝOÀàS¡P¿CŖQ€ À$6oÞ=oióå߈E P€ €oº-WGÏþ ë2ÚéÆÝ(@ P@goœõZµj…ëÃÎPš³áas(@ P@ÇoúZ5© œ u …ŽÖM P€N'ðÂŒŸqOŸVhÕSBaÎ:ݲÁ ( rBaoX¢7S… (@;ž{9îíÛ-{H( f(ŽÓ»Q€²Å׋ IDAT €Î$ÞqÇhSß–è-:k›C P€ЯÀÌ·–cÈ]mТÇxÀ-ˆ¡P¿CŖQ€ Àf͚…;CÝa‰ÞJ, P€ ì˜ùÖOžï®vh.3… …vªq7 P€НÀK/œ„~ýú¡U=WX¢·é®}l(@ P@¯ÏœùîïßͺËLa g õ:Pl(@ ÜX 'Öu…%†¡ç (@ PÀ^çÞX†v@Ó® Ë3Ú Çý(@ P@_WC¡ ,1ÛõÕ8¶† ( cgßX†‡v@“n×r …:+6 n ðâ‹/bÀ€hQÛKÌZQ€ (`§ÀS¯ý€ÁwµEû;Š1ÚiÆÝ(@ P@‡/ŒðˆµKÌN¶M¢(@ èS`ÆÜ¥xtp'4ŒUf 8SšÏab«(@ P ? …÷Üsš×4û+¿Ýù>(@ P€ÙOÏù#ïëŒ]$ú3òÌ (@ç`(tÎqc«)@ PÀñOÍù£†ÞŠúÇ3:~8Ø P€(¬À̙31xð`4«‘ KìîÂÃã(@ P€eN`úk?àñº"TB¡‹g ËÜÀS€(% ‡ ‚ŠÕÓa‰ÝSJzÅnP€ Š_àÉÙßcÌCÝQï …Ÿ …ÅOÎ(@ P 8rBaµ4XâöG,“ (P*Šœú=Æ=Üu;I(ôa(,•£ÌNQ€(Ï=÷†Š&US`‰ÛWzÌ.R€ ŠF`ê+K0ñÑÛP»Ã8†Â¢!e) (à†BGš³N P€( _\ŒñtGƒ[§&oΖ†Ae(@ ”EgŸ}>ø UN„%nY$`Ÿ)@ P€…˜üòw˜öX/Ôh?0y1J‘Q€ €ÃŠOŸ®žSØ¡Ÿ–øo@ P€pÉ³ãÉÑ}Pœ„BO†Bg8¶“ ®xæ™gðÐC¡QH<,ñÉC P€ €“^ZŒ§žèƒjm í$ãn ( G …Æ CÃJ±°ÄÒcÙ& P€ €.&Ÿø-fŒí‹ªm$zpŠP—£ÄFQ€ @Ÿ3fÌÀðáÃÑ b CaŸZ܁ (`°X,˜<ë;<=æTm;0º3òä (@çÈ …¢aI8윝`«)@ P€%,`6[0åe†Âfgu (PWCa, GŠ£ –I P€(uYYfÈÃëåžÂªm'F7ΖºQf‡(@ ”«¡0–„£e€×ì&(@ Pàæ23³ðäk?àé'ú J›I€Ñ•¡ðæHy4(@ 8Jà駟Æ#<‚"`I8æšf°^ P€ €S €gdáé9?š™Â*m'†B§A6– rƏ!C† K#À’ÈPÈSƒ (`@Zz&žy})Š?.¡pC¡=h܇ ô) 3…#FŒ@hàeXë³‘l(@ P@g©ixö͟0}tïì™Bg u6Fl(@ Ø)p5^‚%ñ„Gq7 P€ @ÙHIÍÀÌ·–áÉÑ2S80 Ëö)ÁÞS€p^§žz #GŽDhàEXO:oGØr P€ @ $§€ã…yË1mToTi7€¡°ýY(@ ¡@N(,–$†Â"€eQ (PŠ’’ÓðÒ;¿`êš^ …¥xœÙ5 P€eB@Bác=†zåÎÒtªLô™€(@ ܬ@bRfœû Šî…Êm§Ý°8ƒÅb±Ül…<ž (P\WCa,I§‹«–K P€(U ‰©x團:º7*·‘ËG¯¿1–ª¡gg(@ ”>«¡ð,IgJ_Ù# P€ @1Ä'€àÕVbê( …S ‹Á˜ER€ @ ä„€³°$Ÿ-¡ZY (@ PÀ¹bã“1çÃU˜ÂPèÜÉÖS€ 0}útŒ=uýÏ0ò„ (@ Ø)—Œ×¬ÂäÇú r›Éœ)ŽÓ»Q€ €®†ÂÓ°$ŸÓa Ù$ P€ €þ¢c“ðÆÇ¿còš>šÜzC¡þ†ˆ-¢(@{$>þøãšãw–ä0{ã~ (@2-“ˆ·®Æ€Çz3–é3§(P ž|òI<ñÄšã{–”ó¥ Gì(@ P ø"£1oÑjLÙ!­'rаøÉY(@ —Caqɲ\ P€(ÍGO^ƂoÖã™qw#€õ†ÂÒ<Øì(@Ò.p5‡%åBiï.ûG P€(+‘ñ˜ÿÅZLyBZg(,UB P€ž Á’rÑ!m`¥ (@gŒÇû_¬Å„Çî@HK†Bg?¶— l$Ž3µœÀ’z‰6 (@ Ø!p9"|ù&Œì‹–ã8Sh‡w¡(@ \ …‡aIœ¬ÓV²Y (@} \º‡ŸZ‡ñ*Že(Ô×ð°5 (P«¡ð,©á9”ûR€ ʬÀÅðX,øz=&Œž •Z>ÁPXfÏvœ @)˜6mƎ‹Zއ†ÂR0¢ì(@ ”„À…Ë1øäÛ ?âNTjÁPX欃 ŠI@BážqãPËó,iWŠ©K P€(]ç/ÅàÓÅ0Nf [<ΙÂÒ5Œì (@²%0uêTL˜05=öÁ’Q¶:ÏÞR€  )v1‹–üƒqöC¥£ éÈÃ(@ P@WCá^XÒ"uÐ"6 ( s¢ðù÷1Vf ›3êÄØB P€ž®€ kžïÒ£(E P€ €gÎGáË7b̈~šÔlg í0ã. ( S†B ›E P€º8‰ÿ[º cFôGÅf1êzŽØ8 P€ž¡@Îå£î»aIŠ(@ P€vœ:¯ڂ1J(ÉPh‡w¡(@ \)Ü€Ç莕l(@ P@_'ÏFà۟·à‰G õ52l (@ X@BáèÑ£ê{Ȉ-ðñ<€ (PNœ¹‚Å?oŏލŠÍFpа,žì3(@Ò"0eÊLš4 Õ]w0––Ae?(@ P ØŽŸ Ǘ?lÂC÷õF£['2»8+ (@bž ·qÅV Š(@ ”&c§Ãñý¯ÛñÄ£P¡É# …¥ipÙ P€eMàj(Üdėµî³¿ (@B =u?®Ü‰Çœ›¡°P‚<ˆ t#0yòdÈ}…U›ÌÝŽ‹ џÀŠO ä»úYŸ[²¿[ßS¯gï'ß j›÷ŽcrŽ·)3÷ ÙeêO„-¢ʲÀ‘“—°ô·]xü™)Ι²|2°ï œ]àj(Üd&:{wØþbHIÍ@|b þNðƑTO$ Êf±À’ý‹üjý]{ݺ“A…Bùu”úEŸä-y×úÝ`@Jb<}}®Ÿ–ý^αFLÙÓd4Àœ‘ww7HåwPµŸÿB­áõºU ®¶¡7wàÍ#Øæ”wM0Ÿ”­áÙ64ç~/°l%É9.[»F¶li6[ Ÿ,fdfš‘™eFTtŒÍ0g™a6›Õyíb4ÂÕÍîî.ðñt‡—§›õ\åF<Ÿž„Ÿ~߅яD…Æ3ò,¡(@ç`(tÞ±»™–ÇÆ'ãì…(\Œ‹ËñˆŒI@dl bRŸ˜ŠÄät$¥f 5=ƒFR-&$gYßzÍh„Á$ß 0êlõšÑ”ý]ž £|7ZC¡ì+?Éw ŠÖ€š~–råx-$æ*-Zž„&Wdedšã­IS©úk›€NU‡µ>£ü,íSß³_Ï~_ûÃ?gížìÀj ±Z›¯YëqZYÖp›"Žl†¯þx5[T£¥ÌìÆÿg`-ÖºÅÇ&0ª&YßRﹺš`ÎÊʙÅ k묳·9¿Ëø)%ë{R†y™‘UßÕ®$Ä%Â×Ï 0›Õ±0g‡~õ=ëêï3,fë±fùPÀl†ÅbÎyßb6[_— äœìrdõ³ú]‚YvêxëëÖ@g}OÊÈyÍbFVö±òºöŸmTåfŸ 2örNXÏââSP!ÈÏúaBö¹ š.åfšUXLÏÈDV–îî®ðötƒ¯üýŒTÎýP%€ªU BH•`]ݐf1 Ý TsÏŒ™š<։¿ˆŸWïÁèG"žñ0†B';6• r \ …Ì$ú”"Ä,#N„'àÀé(9ްóALT2ÍxøxÃÓÏž~ðð÷ƒ‡ŸŒü|áåçO_oxúxÃÝÛF“é?*jv%++û+×Ïfy]{Í: cÉ‚%{VF~Wa!û=ígkh°Ÿn Ößµàóš0²ƒ‚5Dd‡‰kÂGvØÈ"êþŒL>Õ¬Š5e³F%m^Hý,e©W²÷…˜lõ]û]›5µ-mkà³ikÖýÄTÚa-ÝfÖ4§=Z`¶™]Í.­¿ÚÌbÉÏÙ«µ°šSÇÕ®õÛ6 gOåæÌìŠ'§ÂÃÇ+'è^š%üg‡ä\AÛú¡€Œ³÷“ ŽýLÖ`nýÁúŸ1çíƒë‡ F#Lä4™Œ0­?ˌ^FZ||œar1ªß]ä}“A}w1™`2Ù3ÉÖ˘³/mŸÁ%ʶ—C›-€d˜Õ%Q1‰ˆŠIBtt<¢£ä+qQqˆŽCZr <ý|P®b«UFË•1€Eêøÿ÷ßM)úÏ »àà± øåÏœ=œ¡'(@ 8¹@N(4ü d%;yoÊVó3,Äf—eB\Š—âÓpêB  é“çq>æÌ,žzz \¥ ”©„À*Xµ|ÊùçöʖàÕ°f oÖŽ—UŽËN€ZŽî‘m2¥MœÔ~Ô.™µîuuVô¿—Ó–5÷ÒÔßôÔ4D†]ĕ3qî<"/\Fjb2ª‡ [“ÊèÝ®&šÖ¯ªB-·Ò%pàèüºv/F ¿Áºaç –œÿ²”.ö† J‡€„ÂiÓŠ¡ 6Y)¥£S¥ž&lLðDd† b3 ˆ »„+g/ ìðqĆG©Ù2 |kWGåº5Q.€‚šùãF ”œ@r\@ؑH:sþŠLtjZ Ý;5DÛf5àâÂYĒâ«iÿ‘óX¹n?F¿Ad(,>j–L P€Å- ®òÉ'QY©Å]Ë¿ ÝIØㆰSpùTÎî?¬.¯”Ë«4šƒj 멙@Y¬…( Ë'Ï iÿ\>tn0ãÖö¡ž³GSÔ¬€ŸF²%Øwø<~[¿£„ †0XP€ €n u3×mHtŠ Ë'`ãÁ‹8œ÷°ºÌ13=Õ‡¢rœZ®Q&Î<è ÙÂ2/ 3ùn§áìÖžpöjW >­ÐŠy­2oãŒ{…á÷ 0jøœjx?C¡3"ÛL P€V1cÆ@‚aš×vÀœF Èʇßm¿ˆŸv\B\D€ZaÑ·|ª5ª‡º5àæá¡£Ö²) @A*'^BØæ-سã(*ùbhÿvèØªNAŠàŸØsðVÿs©P8”¡ÐÁãÁê)@ Pà&rf -ësúM”ÄC‹J@ž žvçi,Ýrái@Fz*Öª†ª ê šjHQUÃr(@ÔΌÀåM[ðïæCšZ)Ãïí„Æ¡UtÐ26!?]ÎaíÆÃù°„Âû óãû ( _ …Ó§OGeóZÀ,Ï|ãæ(™üwûqüŽù N™œ‘ž’ŠJµª£z“Pø•wT³X/(PÌ~.fÔNœŒƒkÿŎ}gЪI <4°‚}‹¹f3;÷ŸÅºÍG0BBa†Â›±ä± (à`‰'â駟FHÖÀ̇.;j8v8‹Õ›ŽáXŠ7"’²P!5›7„p £šÄz)@šé‘òá'ñëÒužÇèŠ.íCKž¬Î^Õb㎘VÒcÁú( VÞ)ÿçüö×^5k8òŸÎðõá=Äz­Û÷Áß[ŽbäÃCØ`0C¡Þˆí¡(@û®†ÂՀ%Ëþ¹çM È'Ìk6Åß*žp)ZÍ ÖnÑøŠËe €ó ø»˜Q)â$~ûî7Ly;êÔšàü+E=ØŸ÷46l;ŽÃ3–¢qeW(@ ”I &`ƌÉü°˜Ë€AIw:1) ¿®Ý‹ƒñOqSœ¯ß¡%ï,é`}pJ™ñ8±r%N À·¡M³šNÐê²ÑÄm{NãŸíÇ1Bf ëß˙²1ìì%(@Ò)p5þ®žÇ­xN‡EâçÕ»î]G.'¡Bͪš×¶yñVÊÒ)@§HøçOœÞº h>]›8}JC¶î>¥î)|tø} ÄPX•} (PV$>óÌ3š”Ÿª¬”X¿÷ Ãʵ{Q®zU¬8Æ·¶C¥ÚÕK¬~VD 8·ÀÅ;qjí:<Ü·9îéÓÚ¹;S Z¿e÷)lÚy><¡÷0–‚1e(@ ”Y†Â’úÍ»NB.5ªR)ߞÈB“nàX®d*g- @©8œ÷¯ø ãï–`تÔôË;"ÿ]ß²ëyXf  q Ùf P€È°†Âš”þMŠI@ž=žÿÈ–÷ƺªué7ëJ£Ü(@ TàÌŸÃ8ûë ŒÜwtkZÐù lÚ)öI(ŠòõÞ°T>’¢ˆÐY (@ Cañžj¥Ê'É{†¡|€7NŠžÀµS †â­”¥S€¥^ ~Ï.ÿíµ*i»–µK}õØA¹ŸPV }äáûQŸÞ†B=ÛD P€ö Œ?Ï=÷ *ŠqŠÐ>1û÷Ú{8 ë6EÅ ?€[ŒˆhÓËþƒ¹'(@|\¶®ÅŠ5[ñæÌÁšQ%^%,ðïöرOBá(_ïn†Âögu (P„ g>÷ *0¡*pöBŸZºujÃ"«ºÞÒ —Ò]ŠŽF ”mêîžøËO8zòÞya(<Ü]Ë6H ÷^n رÿ,&3… …%ÌÏê(@ P (¬¡pþŸœ«‹²ÙÂ/K7((*Šbww'*Ø-ŠÝbwww\»»~Å,llQ@EÅ@ D:ïsfýÖqYØ]X`Î}ön|3gÎŒóù³ïžÊu^™j³µ®ˆÈl9àÆBF#£b`Û¬ EfkLøæ9Õ ÐÒü¶.ß +KSLÜ\5‹p­É"pÃݏž¿C¯žä)l-%žSÈo"ŽG€#ÀPk† †éD £/šµ™Éž£gàWh~ü C“6 p1Æ*3™Ïmåp2Öº±hðCŠîÅ ÇúŒ‡a:žÛ=<ö|‡^NŽÈQž'…éˆ=_Š#Ààp”Œ€˜ND®è‹J֜=ÕÝæjh…ÎUpK¿0yØhöŒø®9é„@ ó0Œw€-o`ےÞ031H§•³÷2×ïŸÄS¯81RèÀIaöŸøî9Ž@æF€HáŒi“`Å=…ŠždpH8ÖïŸ cC=T-WQEÊâAšž¢jù|ŽG€# Œ:±èn‚Ù«NB€!Âô‘² ‡S9\»ûÏŒÐË©Ì ÛsRšX¹ŽG€#ÀÈÄ€p",£ž§PQüÿ;ÿï?~GžÜfšÔž&N|3VT%ŸÏàpäBÀÎ< ùcÀiô6LÚµ*–k”v®ÞñÆó—àÔ³'Ì ·ä€0íPò™ŽG€#ÑpRšœxåÿOºC[[ýáld.|‰ÑTŽr®…#Àà€€@nXôŽ Á—{¬ÎæEN3#på¶7^ø|€““Ìm[pRšbŒ¹zŽG€#ÀP!bR8–Q—TžJÖWœýðM| †}ÃrˆŽ)ŽÛ!úYÓ|‡Ž€Z!PÁ(MLÃÑwÜŽjZíì*©•}Y͘˷Œàéû NN=9)Ìj‡Ë÷Ãàp²C‡ÅÌéD ]³Û֕¶ßç>pøÔ}/l…¶­kaÏ„Ɖ”ŠŸ+âp8ò"Pß4?=Ä®c·±oõy§ñqi@€H¡×«Oèٓ<…²ÛdxKŠšš(„‡‡#::qqql»"‘ÚÚÚÐÓÓc¯YS])¡÷ƒ>®'}–…†††ä2œÞ ¯“{&c¥í =œ‚=É٘Üg?~ü€™™™dž°†ôž“{MŸ}ùò¹råJ„<óh>ÀÚښí›0öK¯ã¡hˆ¿,$@„ö^ƒ=³‡†ø3:–žø$ÄÇÀÂHºZ"hjj²³ãÂàp”…‘ÂÙ3& g$'…iÅtÓŸëð{÷#û4Á;ÃŒžÅœ„i…’Ïãp”€@ë¡X>gšÖ-…Ž-++A#W‘®7=áí÷={ö‚¹­LÒ•~üøïÞœ=Q||<{äÈUhh({„……ýE“’7ÚÝ¿ܿƊDØ€¯Ók²/)1Mº®–¶6âãâ‘4@$K ‘˜\‰ˆ€ÒçDށFÑ똘èèêÞŠÿˆ=)£W¿?Ó wìÿ@ú€˜˜hhië !æÐÿh,f"lô^¬AŒŸß¯‰Ä%$ 2" ZºúH`ø' >A|l¯l¿â='ÄÇý~/~MãØuöHØM&ikiBW[ z:Z051†E3ä³Ê[k.\¶¶¶È—/ŽŽŽø¿\ŽG€# 7#GŽÄԉ£aÍI¡Ü I ôyˆÍû¯£~õâhÒš"v™àW,÷ŠKé9ºÐD!CO[Gü÷^Jb¢£ñ#8Ÿ¿!Ú@ :yÌ'þë΅#À` žwpîôìZїc¢".Ýð„Ï›ÏèáÔæ›e,) €‡‡ŒŒŒ˜'ÍÆÆ†y“"""ŒÀÀ@ˆŽõaœ#ôMsBË(4ôM¯m‚|–f0×Á\_š" æ•"Ä%$°÷qññ¿Ÿ¿ûýž‘¹¿¯ÿú cSæ {Ÿ õZÄô‹I–ÆïÏ_OЯMzÉCÆì¯™ Eœ~“ŠÄä)þ™b×iN<-ô‡|ý&aâϘI< bV'þ“"û‹˜pŠIŠ41R1iÁCø›¬2¡ø3æ=ދD‰4Ùû€Ï’»+!11Qˆ‰Š@txB~EÈ·/øô¿‚>"ì[m  N•ÒšQ£ªU«sssý3àj9¬‚óNŸ€œ<|4MGJ!Z÷ŸŸÁœ1má«iÜK˜&“N2ÔÐFE‘tµuØßLú~CCéVúqÛÓÓwîÞE¡êå`\®¢ãb•²6WÂÈ äщÅÙù+Ñ·S-4®]2+lIíöpÑíšÈX§^0Ë(Rèçç‡Û·oãû÷ï(Y¶<Ž àð ^ÞÞÐÐ1„©• r懶y^ˆtx²»ÚÝE*0(ìçw|ÿô!¯á—ÿÄD†¢|ùòhÛ¶-ʖ-«‚¹JŽG + &…ã‘3êrVØNºîáë÷PL_~Ë¡qƒòØdŠŸÜKš”3 RXI'7t4Ä\‰ êëë3b(DQDÔµk×ð> õ:·Â'ÝhÄÆ‹Sežp8À§+®Hð…Ó;s8T€À…ë/à÷–Hao˜l*s¥‡RÈçŋAÂ5jÂým®Ýy‘–6òؖBn›b00áÞ!œ{ŠR©«©람Œs†ýÁ,^Œ8z÷î2eÊdª}pc9Õ# &…ã3êŠêËb+\ŸåC§îaþøöx£k ·ŸYl‡·"…Ut­`š+&‚D )ÒGð’eT+ÁÛÛ<@3»fÐ+d…û~™Êc ¿GÏQŠ^õ¿Âd3}ŸrVA 6&Ç'Ïñ•N°¶âü@ÙçzþúsŒyǞ}`V°Iú‘B___œ…’Pé‹/P¬X1TªT q ñxþó#žœeõÒK"BÃàuërÙXÃÀÔúƆ¬ð[XÈ/|~õ¿Ÿ£LýêÐ76’˜tzíNÜ8t*Yk޳C«}@…öþ%TC᜗/Â~†@ßÈÊ—ä_*kß1‘QÐÖÓU–:™zÂþ‚˪mšdWÅkðþzÊýÍOžŸŒ„#kú¢ nŒ²Ôr=Î^õ`9…í;uC2­UO Ÿ˜#ÀÈzˆIáXäŒâžÂԜî>—{žÿä –Îè†Ý_Lð#VœûÆE9‰t˜§P T„M\€-¹¶P!!! H*-Z”=“·Íë×gxÿ DL:ŸY?h2Þœð‘¹ùJvõÑeú6†ˆÜû>’ñ…+—EÞ¢øæ=|î=aŸ7éÛMûvùKgtd$_Œ·'ñõýGÉuÓ\9ÑuúØVL{ªÈ—·ððÜU|}÷"MM<»zl@Ž<¹”s°2Ž|ôyƒÕ}ÇÁ¶bi Z;Gåëe§vO^ŒNC»bJuhjðJœÊ:û3WžáýÇïèÞ³/Ìl©–Ÿ~ý»v킱‰~ê[#g¹ŠÐñ?<Ê:ÌìŠÇÆL mKécÿþý8þ<† †êÕ«g7ø~9)ž§0m·ÃðéûКvIØÔ©…«ÜK˜6eÌ"RXM?/ÈSH^AÒ¡}F­¶ˆR>ֆJG‡õó525v¡\ˆ0×eÞCUJ|\&×O¹G‹!=ÐÀ±3åæ‘38µz;{Ý G;ŽÜCbâícçà²r+{?Ïu"O]È×ïØä¯ÑuúH”ªWÙ*-‡MÛ§^ºalÊg—Ÿ ÄÆáÓYbžÂ6h>ÈŪW`œ’לÄôå+f‹ۗŠz«wþ;+¶°yUZ6„m¥2ž²ë#Ÿºú˜tt# Lþ„ŸŠz9&Œ~üœ^’míðãó„}‡ŠŽ6Ê5¬…úÝÛÈ¡…IW=ð䢎,ï‰üºŒu‹²î’Ó—ŸâÃç`tëAžB’ÂC‡áîÝ»šÑŽ->›ñØje ×2ׂ­ .dmMŠL™+++ G€#  R8wúhäˆvˆ»Oۖ].>5-î;©®óŠ£iCQö,"…5 ­%€ˆ•GHQ ŠT•ÝÇLJõ,üõë—$Ì466–‘ÃŒe‹ÂŒj Ä$šÎ;"xØJÖ®‚Þ‹'§Ç׀OXÚu8ŒÌM1Íe[²UGO¢ÃðÞšÛµÛïʞ£è€BåK¢×âÉ,BIÌ^ Ïî’u\=Mm­íPÈèrGqX«ý0'Ôë&&_ß>cI×aìu¹ãP¶aM¹uÊ30.6·À‡—¯ñíÃgFzÿ%U£ã€¡òšåc’A 6:»&-ÂöUP3ÇHIœr}ŠO_‚ѵG?˜h Skš=…”4œråJtéÒÑêâÕ7žª€óãj~#ÐÐVº?_c˖-(]º4úôù“ÛÀAâp²œŠþ¬©7¡µŽÚã+÷Š@9f)¬i”Ÿ… ­(ˆ 1€üBzOMì)Õæå˗ì5‘G===³0R]3#„Ú˜"F”zO!…c’—L–)Û3e)|ܟÀÁ¹7êvi•âîÜO¹âØâ šÓف“IN(—oßôå,ܔÂN}<ÃÖQ³ÙÐYçw3»>xû1=䩔–ùWBKçßj’®whî<ºpyçڍ˜è2y@I¿4YL:?2,Þw±ðU›ÒŐ۶€äŒ„±€Ÿˆëÿš›¢p¥2(X®$¶Œœ•ìþkwlÉ çXÙ€e|ÐÔâÞøo¬œXŸí•ÆX‡Šªâó#pòÒ| ùM 뫆Ž=ùóç‡ãÀ‘8ø,œƒÏP ÝËâæE<|ø­Zµâù…*A™+åš7bR8 9¢oš·¡jd]ÇÁÐ}hgŒÎYT¬ÊZŠ€ÐÄÀˆ…’d^ D‘Rl‚‚‚È<ƒD `ff###üŠ Çã˜/ˆÐH§ŒV‹;‡é<Í9ÑڔCH•F©r(…x R¯kkFÆÞŸðAàëwÐ32DÙ5ЬWVŽEãË6ãî‰ ,tŽ¢]œdîÞÉKøoÉFtœ<UíÃï¡6ÿ&P%jUU”$FRŒFE–“žª·žåTjHað—¯XØ~›7ãÌšš$²çžËEœY¿Ýg­›Tšªåéu»$¶Ðu iuš?A’ )ì%é\C3˜CK[ eԀqNs¶g"Œs.îÍZ7ŽìæÎñ 0øŽíãíÔÀš¬aÂÞãwôíú ³Éÿ[vš&Oá¹sç°sçNlÜž? ðøctÖ@ŽïBíÐÔÐ@§¢ÑX±t1LMM1qâDÉ_µ3–ÄàšF §DŽ˜›*џՔú¿ÿŠ‘³ ý‚iâ^B•/‘ÂZÆ ¯-n‡ „ŒJ7±§×D)„”r)d”€ŸŸ>óR%Ґˆ0žýðCh\êŸKÙ£Œ>òæ‘Wäùõ»8¹z;Ëë#)Pº(Þœð•‰U¥J¢‚ù„”ûG9€ÉÉÑEÿÃýӗ1xý<.Jí'Ö š„¯W’á4×nPw¯^¿ŸýÀŒ6ýÙµ…nGänM!x$‰Œö˜7>Uçyuïqœß(&oT&o‘‚¬Z)I§ÉÃPÅŸ#‹3š‰‹èÐ>*ÚՇŽ®.Œî<ÄSWñs†o^„ü¥ŠBº`Ï¢Gÿò6ŠÊ8>ø/Þœx —sžºÞ‰££$N\|ÌHaÇþª!…Æ×ºuk4µo‹OãڪYJ…«É€É¡ ø]fÞÂ&Mš V-^Ð(“%7›#&8)Llÿ„·_£Ü Äav©ÓÂG§„‘ÂÚ&6ÐýÉ%$(í-$NJ¡")]×ÕÕeĐ⯈p\ûþ ¿b#SZ2ÑuÒ¹gêRI®^‡‰CàëþTBzÈÖ€wgÖFâèâ ,Î,·#7E«–‡E>+Ü8t¶ìgzGí\Ž©&…€›·o=þމp–ö)=ì\7PìÝk=ª(OŽ„túÞŠöã¡z›f‰tӜMç³°Ôj­› Ã„!r1ÙžaÈT,[C6̗k ò{ô›GÌdÕLGìX&—‡‘È)åRÑj‹‘¿DüøÄ* ’8-œÈÈÞµ}ÇqnÃ^Ôl×mÇHÑ.ÎuÝ=N\R,•ŽÎ[5ƒê Z…B©œÉ‡'‡Àñóð-8 )¬#€T“ÂáÇ£N:°kәåFÇ¥>1šG -$:U)¬kVš âŠõBõQ¡œ4>È"]#BHÃàÐ_i&…dð¥í‡àºý°Äö«g¡Hå²rï…ròþ[º MútBÓ~]ÙŒSkvàæáÓÌ«7jDzD}Œ£ ÿÇÆÛ¿–òʵ–çÍû¬ºdjÃ@É#J•PÉÓIÞÏ®3Fþ•W˜Ô€÷žŸŒìRõT"¡ÏÝî%ÒrHOÔwlË>;œv'Ëœ€ª2Ç€I“R5—æp2/ÌS8u8rÆÞÉŒ›H'Ëß|Eÿ™‡a7G\€„‹ê RXÏÜD ‰DÂH…~…²VZW)Œô!1âJòHà›÷,ÏN…€¢)ùŠÛ²°ÏÐ?™ |ù?ó†¡âû¡qïNšÙΎåÍœ}î—[X;ʧpŒs˜I–?0{ž\Wü¥ë”?'è–7ÔRz/BaœŠýº IŸ?EmäÙ/¡œD—•ÛX•ÓI¿3P¬Zyžî8ŒKÛ¡p岞:ù–‚¡`ŽuÉ"pÞ²8Es„ÐZò,–mP“yT©xMUûFè8YÜ3‘KÚxõÈ!7®bÿqñ.Š!pôìC„„)SkÙ59R>Ú¿tíÚñ6uàÄû*vL|vZxrå8¢žaŬqŒ™}Zäs8™1)†œ±w3¡õékòå[^Øàò5FŠìñH_˲Þj)€œBÊ$bHE‰ ^@!lTÖîCÂØ§05€ZQÔ{/™Œ’µª°%B¿ãÐüµð¹÷DÒӏŠw¬0Q’_—ÔÊ·£ÆïÒEahLDhÌZ‰—wKŠ9ì0a°Ä£˜šS%;–tŠFœ:JrS3_ûúñsx\»ËŒ™B.%…ˆ–k\5Ú4cÞÀo?¬í?M±Ø {¶ÿ+¬“ò1ƒ¿|cÕZÉJí,ú,™’¢Iä=»aO¢q„Ë„ƒë`$EªSTÄ$‹@p`î¬ÛŒËÛåËUå0ÊFàșø‰NÝÁÔZvH®Ü€ðǏ¬QýÆý'qʇB~f >ÏðØõfïŠÚ5ªeŒ|UŽG ]“¡È›8/(]È$‹í8r7ÞüB)GÇLbqæ5“‘Â…a¬gÀ6!KH¹‚ò†þ …k`êHáΉ YBéOYHz|éžœ*!RÔ~¡H•r,—ŽHMrBÞÌ׏_°*œÖŠúDáDù…©==ò4’Çñ_ë¥VµÁ ÿ%‡µ+H:i¯šÖ…INs|ÿôT™Ôû¶8œõÈŸ¬w#y-¬ó€h‘Û ƒ§0+U$¥°S*ÆCa­\G€ÂqÏÌZŒ³ëûÂÄ8ùûRñU²†Ãg ,,»†©u ™—›RoB8ŒZ ¿ï±ÙMŸSµB "ô'Îo[€›Á±“8Iœ G€#µ`€pÊPäŒã€0¥“^°î >é[Àйžü>Õ!@€°Ÿ™-LŒŒY‘i‘ÇC(ŒŠ„k ~Š¢%“ÐoÁ¬íCj…rI€›Õ§VGfOgpãàIÖØþ_B9”-‡ö”ä_Ê»/"£aÁ?¹gP^ÀR9îÌÌEØ4µ Š·á’vŸŸ°ˆhtìFžB%‘Âe˖ágŽ R.כvÓùLŽ@Ê\رU ™aö”Ô5±MY3Áàš#D gO‹8wu4O­l=ç ŽÊVFîjÕÕÊ®¬hŒŸ†ÊZA_G~¯`RˆžDÇÅâIÈDÄó(,UÜ'aÁ!xvõ‚Þ°B5æyr±~Œ¶JAߨHKr "à¶|-Æu©ŠzÕÿô¹TPe¶~èÔ}DDE£CWòÊþ» ·§pèС°šÐ9Ë4̶Àò«]ÿCü{wìÞ²^= âVp8*E@ì)Œœq÷UºNVPÞkìvX;ށy±¢Ya;|Ž@6DàáæíèP=?:¶¬œ w¯Ü-<鎚šŽï>Šùd§]ÉM ·hƒºÂÜ*¿r­åÚ8©DÀÿ¹;Þ^ۋ]›ÖÀØØ8•³ùpŽG ³! ö‚E܃ÌfzºÛÛvÀz”:$Õápén(_#ÀàüP=¯.t«Ç1R'݃ö݆Â4_U™Úä"…¡¡¡šmלÍò1è bϧ§ß>úãᡥ،j!òå˗+ò%8ŒD€‘ÂÉ`ÿ(#ÍPûµcãâÑ¢Ï4œ9:zºjo/7#Àà$‡À»Ó'a£†±í8@ "°ßåbcãЮ+y •@ =œŒà8l zÏûw²®‚6ó鹈ŠŅգ±aÙ+ÆãÍåŽädR8)”ïà~…F¢õMh¹pÖ_å÷åÓÀGq8ŒG èÊ%è À¬Ñm2ޘLnÁþ÷G€<…âÖ5ÿ¹<…W¯^ÃÔU»ÐeâšL 7?« à²xN‰êÕy1…¬rŠ|! &…ýaÿ§_GëoÞúŽ>S¢ù\ÞžžßŽ@æE äÎ Dùzañ䎙wjbùŸw—€v>šWvŽŠ\€ðè±cØpÌ ­‡ÏS“-r3²;ç×MÀpGØÛÛgw(øþ9Y1)ì‹ø'Y~¯ŠlÐóÕ'ŒZvÍŠ‹›vsáp8™ˆÇ÷ðõÁ¬žÕ-3š¯V6ï=~—õPmKžBeÂíÛwâÈm_4ï;I­6ʍɟ\Þ6]•‡#oМ}oŸólƒ#…“úÂ"ái¶ÙsZ6úÀÃS7_GÓI£Ó2Ïáp8j@̋ÇxwÝ æ÷T {2³{þ»  M—a0Í[IæVäò®]ÿ?žz~C#ÇQ™n{BàêŸåh^Ö ƒÎB»â[áp’C€“Bùî‹[^aÖÞ{°ï,ß>Š#Ààš!ñ/=à{Ñ[õRCë2—I»Ý†H$úM +*N —¯X‰[ï£Q¿ÓÐ̅·6Ë"plÅxŽ«]£Gó_ijì!óq~#@}rgMìÃ=…)ÜWïxcîá§h9n¿w8Ž@æEÀÏž§ÎaûÒ>™wjbù®c·¡I€°ëp˜æ© 8)\²dÜ5P·Ã@5Ù"7#»#pëÄ6TʉI“xHsv¿øþ³>ä)œ9¡ri<Ïú›U`‡®7=1÷ž'Zá«€‘Oåp2„×Þðt9ƒË8)Tô(vœ --ZwQ)\°hž|ÓEívýµÏç({gö¢„nf̘¡}\ G€# Ÿ0Oá„^°€‡ú©–sóÄ|/Ž3@ ¬á&p8Ž!ççï“g9)L|‰fí\…xxñ0 ÄŸÁŒyŒ"®àä*8j€˜:ÁÜS(렎]÷ÆÊ“/8)T뻙Çà€„@ޝ'üΞǶ%œSʯ§€ÀŽÃ· «K€ÐŠyÊ)N g͙‹—æšÑŠ'|ò»O=xrå8r‡zbÑ¢Eêa·‚#ÀPœÊíÁk>Xëò íÆñðQùã£8uD ÜË®®ØÌ Í(|<Û߄Ÿ®6:€iž²Š“Âé³fãuL.T³ï¡°q\G@ŠÏ×9)TBÉÔ­oÀЀHá˜Z•‘©R®œÂÉӊ㜚ª6ïª ûžŽ€Âx޹ݷױfÍ…uqŽ€»wïÂÛÛÝ»w‡ŽŽŽÚÀ"&…ްÐðR›Ôѐ}—<±ñÂKŽÝOÍã6q8¹}ñ Ÿ®^ÁŠ…NrçƒþÀÖ7`dš{F K+N 'NžŠOº¶šÜ¬3ǝ# xßs…Öë+X»v­ZØÃàšWWW V­ZªPÿ—Îƍãʕ+8yò$Zµj•.kʳˆ˜v‡…†·<óí˜ÝžcÛ?ŽÁ‹Âeۛ€oœ#{ñ ®\ÁæEœ*zœ[žÁÄHöFÀD€pü€)Ô+ÌI¡¢'Ãç+ —îW zu ëÖ­SšN®ˆ# Nüúõ &&&ȕ+ÓÅ4ZÖݺu+úõSo'…òÿŽ³Ï°ûÆ[ØçEáäCŒâpԁpOŒwuŖÅü¿eŠœOB@9…ÆÌS8&¹KÉT'Wøèž “dX •švTÄ6>—# 4^º_…†ï¬_¿^i:¹¢Äœ9sAAAprr‚H$âð€3ȟ??J•*…/T_`E ¡ŽM*à4vìØtÞñ¿—c€p\7Xˆ^ªMêhÈÖSO°ÿnZå¿®«ãùp›8ù÷|†w®®Øº˜·€±äGÅ'$`û¡›¿Iá(˜ä.©8)3~"Ÿ›”@ÅÆœ*r8|®òxyÿ ðòþ÷¿ÿ)O)×$AàÙ³g(_þO“S %,Q¢jÖ¬ ;;;ÒÈEµPn_ɒ%Ñ A\œzUµ‹ððð@¹râFSŠLÁüùóUŸŠŒ ˆIaWXˆ|䝒-Çm>ñ‡~AóÁY«(Ü»>ðŒyu:ÙÃ(‡™ÜgèÿŸ÷Ÿ¡f»æÐÔҔ{Èàd,ä)|{éïSšà1ÄÇ'`Ǒ[02Ѕ}g%‘ÂÑã&à‡iiTlÜ^AóøtŽ€rxé~ð¹ÈI¡ràüK !˜œ£G̃XœzuhhhšÈŠì­öÁƒšZµ*:wîŒC‡©ŒS§N¡uëÖl `òäÉ*_SÞÄ€° ,DŸòNɖã6»ÿ<ŸÁn@wµÜÈ×ïxáæŽ/ý kh€fý»B×@_Š­ñqq˜\_\πú/Öhk'÷ÞöN[ kw1xý<*/ûr¹•òŽ€Ê >…þç/bû2ž­ØÑѱ8tú>t޵”G {öêƒP³âhÐe˜"¶ñ¹¥!@…fD¯\yøšÒý£(""ƒ ž={°hÑ"”)SzzzðóócH(¬T-Z`ߟ}077W%Ù[%™iÚŽ)†ž.•¶mۆþýû3зlÙ"y­§ &…a!z¥æš­ ëßÅIï4í§>•Âccbàs÷1 ÏsZ8¥ëV“‰çË{±}ì<6Šëô‘šhWOnü—vsÆ×÷ÑkÑ$”ªSUîy| G€#±Dz?Ç«³ç±syߌ5$“¯]ÇnÃP_ö]ÌÕÅ] IDATFÃ$W ™;’+§pøš1ÏUåˆEæÂÈhš%…ö›«ŒÐŒ ÂÝݝyIˆ˜PEJi¡¢'”Ë9wî\öq±bÅ@sLMMU`z©ŒÇ»wïXñU‡Ð’w°k×®˜9s&f͚¥r 6n܈!C†$:÷ÈÈHöc@ñâÅ¡¥¥•È†ØØX|ÿþa¡ja€plgXhrR( ëékÎãÚÛ0Ž3@ÕG’¢þèÈHÜ>vWvCTx„d|™zÕQ¢veü ü†Úí¡od(SןéËñìêm6Šï²©(^£R¢ñŸžÁuÛ!ŽÕùŠNtmbìý¬s» ol”¢Í|G€# Dx{ÀïììXÖ<)íg=ÇnÃ@_ö]ÇÂIJžLer‘Â!Î#k] eê¶L»e|&G@‰Pózœ÷7yŸB%b*š ƒ‘‘ø ÔÁƒÑ¥K—dWyôè*W®œâž”LŒŽŽéºví^œz…víÚÁÞÞ>¥iévýýû÷žxñ"kÕ@!–T…ˆ§§'ræÌ™¬oÞŒÁ‰'@€ªvíÚ,W[[;U6SŸì°aðbÅ Œ=:Ź?~ü`öQþá‡P°`AŽoßMš4ù‹Ð‘2:ç?¢H‘",˜*ù:;;³uÂÃᯯ>}ú`çΝذa,±!44… Ɨ/_°cÇôî­ÚbbRØ š~)␝¬=xg^…£IŸŒk…s÷áÁÙ+‰È åõÕêØ¹lòÉ}DÁ_±°Ã Éø¡ÀŠlâ/5‡ç¯ÅÃs×P®a-8ÎýS‰BUç·€<…m0j× ¹×ä9ŒG Ìó)Þ»^Á†ù= ÍóÓ| ‰Iá8˜XSœâ Q‘(Y³Yš ã9ÊDÀãú)ºcÕªUÊTËuýF@È€pQ"C·nÝb«f͚!&&D”(lTðÞŒy“‘i ÁáÇñšX±"êÕ«'ñ&’ CÝœ{7Ž?žhžµµ5ӟT賩S§âóçÏš[·.k™7oÞ¿ÆÝŸ}›y8陌yDÈÈãF•< Ɲ;w˜”šŽÓ>‰€Ù;{ö,rçÎ "YݺuÅ þZƒÆùúú²–ÒÇŒzóæ‰ÃÝiÔš#l©ñ.Nœ8K–,ÁòåË1fÌ™÷&yùˆ°&“öGg@B{§œîß¿Ÿœ·µµÅéÓ§qþüy¶‘òÿþû]£bCTtèÒ¥KŒ\ rîÜ9Žl)þ‘ÎžS§N*ý·#&…a¡ùZ¥ëdvåD ÏŸŠ@ã>ª=Y8=uœ‰ý³VJ†88÷Få a`’zOݮɋ…œŽÙ³ ¹ ýùwL‹žÄÜ­1fïjɺϯߪ©KQ¹Etž*þ±ƒ G€#9õx‚Ïn×±jfWèéŠîÕ̱Ãô±R%€°ß ¡Ð-i‡âÕ¥Ï.ø*x|å8r|ÂŒ(\”€@ ‰·I–PÞ!i9rä#mÒ$…ˆ‘KòLM˜0K—.•L¡kTP… W!%-DBÈc™”ôH÷Ó#ò9bÄ;v,Ys‰ð,^Œ˜yÍ(ü•rõÖ¬YÃÈj… $szöìÉȪ@Êè×!BÚŠMfÒPJ“ÀÈyÕHšJk¡B…@a™$©%O„áHØXXX0¢Lû'|(Œ—H µ« BH…¡×tÂ\)7H= =™Š"!Œ©õy)—t×®]8p 6mÚÄ® } É«(Mh‰€Ñ>)t˜Úe$‡‡2ïJÊu7ž%ŠY|WŠÚ,§kíÛ8ó:Mzg)€"2kúM`ÛÀ±ê;¶M5)€1T(ÆÈÜ1QÑÌë8nÿZXHüCЂöñóË7¶Þ"·£Ð‰ _Y· nO¢Ó”ášÒ²a–;kŸ!Ž@VFàûw|»{˧u‘¡nVÞªJ÷&&…w ¥%BËN£a™¿ŒÌõä íÓ Ë·BÑÊõUj.eRH^2"5Iœy€ŒoDވ€H …œ’‡„H ‘#".jHd‚…RÈ( µ» ü9 WLNˆäɓGB‰ ÕªUKâÁsqqaU3ÉH‡„ÆlÞŒ™Í£pJúñ€…¥Òø€È_÷îÝáææÆæÑCÏäå$OЃƒƒDßšQ£X翊êNÒG"ØDᣠ6d$ŒZyiûö'ãO›6MâœÖY»v-#ËtãÆccIaN…‚(ôɓ'Œ,’çòÉv:Aß§OŸ$Zúр<‹ªæ)ÓZþª^*Së_÷›6Î@RHzß~ˆ# ×#ôÇO žu»ŽBíŽ-až'åT"yË{ŒdD°÷âÉžŽí>øŒÆ„ƒë‘ÓÚJ¢3èÝG,ëþÇ 8Íe+ŒsŠ‹^ Ef&٠ך™úà¹ñ,†@ȓ‡v¿‹±›Á&_òiYlË*ÙNll<ö¿=mØwË"2ב‹:õ³ªPžBâð0•ì€+åȁÀœ3{Q î-«ŽÉE¹P€àù¡G"Dh(|”„ŒCDD,--ÿZ˜ÈyÒHˆQ%L"#IÀ˗/ãéÓ§Œp $ŽªT©"÷a‘g”Œ‹$ÞIç ‰X8.y ;j0Od®mÛ¶Ìë÷öí[6FZh} ‡%!òL¡€ÒyŠT0†ˆ»àQ€qt>D@uuÅ¿Ð1o%Ú!2M¡§5jÔ`8§GKN å»mԅ’µäÝóžvnû]ðÉï­däµk5²/ô “ïu‹Í#fÂßõ:Ž@›Ñý±vÀDxœÂ€£anõç¿;TÄæÂq4Éð͋¿TQ¶Þª^c`š+'Šü·Y>ðø(ŽG@møùøBÝÇÌQ­`fÂû"§õ`bcã°çø]å’œû¢fw*+®Hȅ#Ñž¬›†R9âxõQ~Ȁt¡òœ‘ŒTD@èœÐì\0ÃÑÑQ’«FŸ1"O‘6i2By…{÷îeäN ‡Dð(L“:;"§äm€Š¢t6tŠDþ…^*8CžÅÕ«W³1>>>Œ4RßB ×¥3#¡Ð֎;ªàü[%‘™cÚÁRë¹H—…3Ù"ëÜ™7‘hÜ+ãÂG“ƒÌÿ™n9+©"Jù}—O‡Yn‹¿†ŸZ³7ŸFŸb¶ºqŽtޱŠïxæ)œzb L,rHæÞ@áÊ_$ä…Íûqe÷1ÔíÚ ÃU[)“Ý"Ü\Ž@Š@ øÑ}„?y€#9)TäÀ‘Ânab‘žBsRÝry »õì<õzÁŠŽü¿r+² >—#nG7¢Œq(fϞÒP~=•PnœàmZ¶lóF Bž6**"„~’׍ŒT$T±ÒÐP\^žB-“"o#‘š€ž@".DˆtQQHQ©V­Ë$FBŽ Œž/ŽA¢@²+¹Š©?Fýúõ)º~ý: €êž$ôžò IȋIÞB"D`É3Fž0ÁFzÈ;-xðÈÃH!¶ÔӑÈ$íl¥ê£d ÙK$1iAyŽDº˜ é€|F²‡ªÉ#!‚F„ÐÌ̌œ'2Mšš(æÝ$#‘:"«÷îÝc×+zŠs£ŒN"‰$D¬‰[Y‰Ãó+ ƒ•ÎW”¶›® Ujåُ"cÄ€°-,µÞ)¢&ËÏ]àN¿ŽBãÞéCÖS è[—Ø=e1 +-Zµ<ú¯œ‘HÅכ8ð»H µŸÐ71Æo?œÛž—…’R%Ñ=Û£B“:øèó«ûŽ̚ZâÄòͰ.YWÏ’.ÃØ#·/CÞb…Rk&Ïàd0”SåñÓG8pO¡g‘˜N‚‰…­Lmr‘Â.ŽNÈßž?ò—W¯ãÂÈh®X‹Š–±ÌËÄEùdKÈ”^Èy’šÙ9ÉÑ£GÑ¡CFB(̓®S êaGD„ y»È«'-Dzè3ÁÛHd”*`R˜ª@TˆXmߟ=‘G˜êáá7nHŠÏP~yÎÈ;Fä‘Z)PKAšâhŽ9˜×íå˗¬˜ yÇÈ&ÊGÔÔÔdCÉ#IsÉNò–)S†…² á±Ê8 ã¥+“ê€ðWÊÏ$/Ýx>éž^œz±O(–H si!Œˆ< ĘÈ0ý@aŠ”ïIû§ÜQé"?DP ïô*à3cTkXjÿ]•6œlÈ ë¬?p§ßD£q¯Œ!…á!¡žŸïl+•FñêÉ_ Ÿ‚[G‰Ì[|óOQ(!äSÎ9òæF‡‰CP€rY\Þu·@Ó~]P­UÖ~‚„ˆ!…š&­FšΏÛÈàˆøvÿb^<Æ4gN ¹'bbã°ïø]èSNa÷É0É)ûG2¹Ha§n=QÈn0ò+§ˆm™fnè ¬nö£– XÕ™Æîìdšëžša­ÅB ¹(ò>Qxšt%Ê€«<¡……X!$’A•2SjfO’ˆ$ "™%K–dœühnóæÍYX(y‰T9£J¡Ô¢A5ìzèQ«j‹!„ªJÛKž2 úé‰4h+8Cýü€…ÂP‰ˆRx+…PR>$ é /"yLjðR•S"Jä-$âF^M*öBm))è&/+Mj !xãR:9"†d y)ä“xð€…³ù*]º4#GIIÚ¿Ö¥Ö ”kG…U(Ž•ÂE)Œ6¹€Ž"H”ãG!žD”IÈû)ªW¯^1Oœ@V“†ä*çÄT¯…BW©š+ïϟ?Ó›V+9)”¹ÿž‰Sè)ŒøŠeÝG$"wÉYN`¯Ÿ‡yr±0Ѝç³ðP )m5¢« *Ý×ðèÂõžæ šœE‹!=@ÅhfÛ÷fsæ\Ü ]}Œyêň% µ±³w M÷•E>Š#ÀÈhŸÞœž—Ï1ÍÙŠÆÉW&Ïh3Ãú‰Iá˜äLü#xÒ=Èå)޳ob-‡¢HÅìQ}4Àç)–õ©‹Nè:y]f8÷lgãÙÍsѬlîDùnÙo˜ŒTò)Á"?rHB„©OŸ>¬)UÌ€b,×®]c×(“Æa¢PO"|”û&Ìúð‘ǐB)?‘ÆP{‡ŒòBRuRÊg$ÒH„‘<‡ 4H”#IýýƏŸ,$*…œRîaZr 3bßÒkÙŠýRqò°Š§pR(ÚD O¿‰A£^䛠‚Q‘aáx~í.ž»ÝCà›÷ a«hëêÀÌÊ¥ëTC.öÐù]HJš,Z®a-t™>‚–I*[Gρïý§(ךçŒÅ·€ÏXÒu¶èÆQIÎï­£gñèÂuV±Ž@©¢*ØWÉà€Awn!ÁçŠrRš܉IáT˜äŽ‘©O.RØŠ}g”é< ¹ dÿÈ €°jó®pœÎËY+tGª`rB|Nþoj2f­žšJÕ?)\29¡B5ä}#R%-äå£üž€-‘H"“ê.Ô÷O(ðBRù€ÞŒªnò®Jl(¿‘r…\CU®•T7#…#`©ó!=—Ítký Íd`øhj#ßúA“QÅ¡j¶m.i<ŸTšùߐ)häÔv»3OáÎI Qš\© %À©Ý/Ïàȇ@୛ùybÊpî)”±äGÅÄÄaß !§pLrPœ¶j׺Mƒ…µìRЊžs£## £÷·[úçC¬ÐµÛõG§q+ÒÝŽ“ë§ÃÀØ MœþT}Lw#ÔxÁ˜šHžî]æes³œ3.ê‡y©Ê%…Š~ûö…R1ʃ30H]Ï!¡ù:yá(ǑKú#@ᎊKÞN څ€—%bRhKéµdŠ\gêŠSpûÃ¥ûڙiÁ ûoàÔÛXæQãÂàp2+ŸožAûíKLڒç*pˆ)ÔÓӆƒãt˜äÈ/S›\á£-ZµCµÞ”.›a*`·Ê§Þ<¶GWˆ«JKËÓЬwâퟯcýˆVhÑ ìúL‹[ç°eB4î1­†šŸ/ž@ çžzã¹TŽMf[ <än»ì@“fœf¶ÃKƒœŸ>}’TЀªŸÔ,žKú"вeKVà‡*—RÕÖôN åC|ãþ8ÉI¡|`ñQŽ€Ú"ðÒåŽ?ŸÁ‰8)Tà”¢câ°ßå.ôt‰΀IkÅIas‡6šÑo!ÌsËf˜ Ø­Ò©7ÿۂ£ËÅ¡˜ÕZ:¢h¥zžžk)‚Þ¿‚®f{“?_4œî^бÐfØ<4ì>§7ε@ é2q j¶î­2{c£#1®¡˜VhÔñq±øþYܛË2Ÿ-zÍ÷eËÎü wÏìA“âЬ•—¬@ãÆY¡ªrJ}¹€/5kÖÄÝ»wY®dFäu2R8¢ré~Nߍg²ÕÈSxúm,rOa&;9n.G€# ÀÇk× ÷ñ& n^}4Í7‡JH¡}Ôì¿æ¹e3Ì4[­Â‰2º°{¶‚@òèõ׀טץûŒÏŒÝ(ß°­Ä Á3ØiüJÔnÛ”{xÛe;]:S‹<è·H¹•÷îÙ‹§×\øýžÿ ëâàŒî,#²ÙY~ýƒsûÑžž)œ35~~~˜`V»’ €ùgßÀÐ4g"0nŸØ—õÓÐkö”ªe'¹FŸ^: ýîGÙz2€pÏÓgãÚ¡õ‰ÆQ."å$’ø¿žß×P¯Óèè°ÜÆ[Ç·Â2ŒÞ|TmÔÛý2ÊÕs@á µ±ÁPD…‡bÒ>wX,‘ò©g³ÁAñäòq4)n ú²˜Ùdåʕ˜3gšuA›6m!€Fì\8ä“ÂfÈ¥Ç=…²î1)ŒCÞÜSÈÿ-q8™÷®®0 z‡ñä)4âÓz’‰Iál˜˜çQŒFFF¢s÷^(ßu ,¬÷K«‘é5ª‹îœÞ åŽAŸù{ä^öêþ5Œ,]uŪ6»ŸÏ˜ÇQž˜hlŸÚ“¢!)Z¹>«Rúêñ ö~êÁǰÌ_G–a$pÀ’CøüƧ6̔èhê4öƒf$²mÝp{Šc̖«(Pª²Üvg—?ðìúI4.j”©Há’%K°lÙ2|ýúmÛ¶ÅâŋQŽhöèý™]îMŸOÕ ÀHáðfÈÅÃGeŒqŸNœç€P5·¡L­¡?~b³ó ŽÕE«”Ë ø’…?{å#ÿîÒ%˜} ÀžAvœ*¯ÒIaxx8º9õC™Ž«@LKÿ©ÎÄÞ¹Q¿ËPޱHn.ìX„s[`ÔæË(Xº*›·{f_.ìXÌrü-?Ûr5Ž9Ë"ôGÄÓH$ðòޕ°-_ ¯ŸÞfs ”¬„w^Øg#þw>‘mT锈æÐÕ'Q¬Š˜”rùƒÀ÷Ooñüæy4.j€¡C‡ª=4cƌÁöíÛAÌ;tè€Õ«WgH^–ÚÅ äü"…Ó†7Anýo#pR˜q·Ç'¿·XÕk êvigգ˞ò•ÿ…?{åßþ/"ç7ÐÆÜS˜f€££cqàäïœÂžs`bf%SWŠ9…ÔŽžG߁(Ñz¬ e®PFßGnXï쀌…Ë`ÜΉ4åV qvÝFÞ"â¢ûçaœñïy«f·/%ÑG¡ ù‹W€ÏÃ댒Ì>á SËŒ8°pîþã©lì8Šy'7/ÀÂDWÜø‘È6ª|JP‡¬<âÕÉesvôõÃxßœ„FE 0dȵܺ——ƍÇžS³vêï¶fÍhhhš¥œÜ(Ž€:#0|øpLÖ¹õ¿«³™nÛŠý×qò}öàá£é}}Þ`ußqšêÐ'©ÿ•éOV^ŸœòO×ÿüyä ù„q8)TÝÄ€p.LÌr+F )ïÉ©ÿsŽ<¶H"FŠ×Üøø8ÌïRTŠDõÆè9së_y…ÉÙB9~Wö¯Nä)ÚRtž°µÚôÁÕká²n*ŠT¬ËHàgo‰**2Óyü*IžâÆ1íà}ï2»Nm&œfog$pïœxpá&ï€Ü6Å$ó·Oqijë§å4Þ?wGWŒÅ€œî™² ¬2Ï<èœ^Þ¿‚ÆE 0xð`eªVH×ëׯ±sçNìÚµ (TšF©B\€Oæš1)lˆÜú?TŽÂ¿ÕÆÄƁBp""cjLï…g*ù-ŒIôY’q_„B_W›Í¥9ÂsŒä}Oê3ƒ4Âw@ÞŒmKšALãDT²«.Óy«€4˜)§ñ³Wþ±œ9w–¿>c,'… ‹ƒOá<˜˜Éî}ž¢§ðׯ_è=pŠŽ"ñš)da:Oþøê9ViÆC­ÜÑÒH[ 777Ö»íȑ#øüù3âããÑ¢E VQ”·NP¯û†[“±п˜˜Pñ2z¯“ûLú:ý»¢_ ‹Ã@"!T‰ÈY¬@ÒâMkĂþ҃œ&âE¯câò+šš"öš™˜Ð‰‰]l¬ôs<{¯¥)‚––&›CŽ~m-öZS$úý¬‘H‘ˆž?4Äïiz­¥)~ÐgÚ"hkkAç÷5-úLS„°ð(ä07„ð^KKÄ^“^ñkZC<öïkš‹ˆBN3#F i]z°×¿í ×Åm­P0¿Ešîh1)ôàžÂ4(瀄øhˆ§ø?ó†¡ÓP¿{Žê$§ŠÌ9,ìgü=‡‘¹)l+”Μ›P¢ÕÙéì•›LU¯NŸAވ Œæ€P!ȉ:å"…Nóab*»Ï°\žÂŸƒG `Ó~™ÞCE=Ÿ^ua^Š7Ïî2  •«ŠÛ£v›Ÿ¬Ç ɧמXܳë58ëžûìç×O˜ÙŠžÄ{'xùèÚ°5§XåÑ€þ+¿ŸU)%b×Äil¢!T©tíð–Èa•ŸõD„ZX¬Øø/}ŒðŒ:Ÿ7wÑŽš!ú÷{RÓC(?ðÿû®\¹‚\¹r±ÑŸ}û²|Á5j€‡ Yf " ±È}ñ—&oߟEžR8d$lõFþY§—²$ü³øŒÏýkii±Fô‚D†ý7œ×ÒF\l VnÊ*ˆ’TkѝU ¥ëä™|qëŒäš¬ÏøžØd=‡—ŒÄm—¬²i»®šÓŸŠËéTà>–9•HáëgwÑŒ„1#eª–Ë—/cƌðõõe‹ * GèÖMòû/R#M ¢BÏAHJ’’™€×¿ÿCCÃD„#¹9ÿÒ#ý9Â)\žð_„KÖ^’ÓKĈD W‚'+éÞ¥I‘à5Jް‡®H‘i”ôŒ¥‰“ôkZSšlI{­ˆl~üøQBŒB”ô99‚$MŽ€_ù¡v# `Dˆˆ’@†€ }–܃Œuô9= "kÂk²ßÌ̌éÍnB^ø)ƒëÁÊ($»m=UûÝžï:Îõ¹§0Už¥fðË»°}Ü|6¥BÓºè6s{-|n?Ì õºµIÊL3öþ™Ë8ºðÌ^ò’P;]}8o]˲cgšŠÒÐìpö©„DááÞÇ]`„iÃ[ˆ‡ŠÏÄ€p!Œ“ôkOª8ERH…fÈS˜¿¡ ”ä=ó€€öG–ŽÂýóÿy`ÔÄŸqÑ‰r å=ÝÐà¯006Ëöá¢Iñ"RH9œö¥ÍYžŠ²äéÓ§hÙ²¥„tá¡ûŸHŒ@Všx ”ù‰þœ‘Áë!xg’Ÿ—©K.¬ŽöGcˆx‘ŽäÂS“#FII µû‚HyZÌ F"MTÿåœ&¶B(!Íl"¢õóçO‰×Hð%õ" )éõäÞ)޲²J€SÖŒ|IG60o¡×­Ø9q!ڍˆmí$Ë ù¢IÃMUiŸ*t?¿~{Š.eª;LŒ*öâÊè×öžÀ…-ûaš+'&\-ì÷£Õ¿Î^ç]túž<ë˜ݯ)Œ ÅÞx.©G@逐òB(§Ðº~Oؔ®’z‹²ÁŒ@ÿ—x~ó,ËÔÐ!G^ؔªÌzjéðYeߟ_{Á÷ñ Ž*g^œz)Mýû÷ïÁ¡{ÞÙÙ.\`ž[[[Ô®];‘W-$$„‘œä åùŒB‰lþ+t Þ&é1DÉ{$M~„ëÒã“Îý×5ÊG#r(œ†t8`Jº /.U#@ÿ'¬ +cN eaM9…§P? šy÷Â|ÞÀ,WN,_úF†ªŸýäÒÿø¢ÎY®ÓG¢¢]=ɜ­£ç@€)BßeÓäÒ#Ï øž8D†EÀÀÄHæðˆÐ0hëê@ëÑ‘aáðŸóQá°)] ¹m $Û6éõãçØä<“­ÕwÙT¯Q)Ѻ‡æ®Á£ ×á8w,Ê5¬•¬Mò¬E¹ŸšÉø»GÅ¡¢£¡g˜ö*œò`,=&*"ß?|f!ÃúÆcþ¯³tÐyùÜ{‚ o‘‚È_²(4µÅ… åêƒH!ª:zº(Q«2L,r$;r])Œ™tÓ¿Y8ʳnFŽñu9ëXN =ƒÄ€pŒM“¿w„uRôRnH¯Ãa]ÏËTSÔ>>Ÿ# 0žësÿ*ÚVÊÃòù”-e˖eù‚HäÌÓӓœ®[·.êÕ«Ç>#âhii™,©“•w%\#ON.Ž@ʈIa-X‡¥<8 Rx& õ² ) üŠãË7ÃûöÃD'ÜgÉöE99¡/ã”dJÿœ%ùþ1Ñ‘°*ló×ð wAá‘?>}a_ŸÍ­r¡N¹ÉÇ=—‹øoé&8-œˆÒuÅߕè úҮÙ}d§ŽŒzèkwü úƆÈSŽj¶ûãaÆR䯕]GQš|)®TÔþ`ÛØ¹,l³í˜šÙŸ9JdùÕÔîÔ:zz8±r î¿‹üy1lÓ¿€ûÉK8œn#„‚«^Nó'Hò$éóؘ,wɰûWŸäÏ/ß° ý@®\WÏú [yÖ¢}®r޲qÁ_dŸöwç¿óŒ|æ+f‹ۗB‘3“÷Þð}ð g¯bx“PÈp³~]‘ÓúOðäÎ^áÍS/_ºþ\È«:híäÌ'»‘xLdŽ-݈ÇÜdÞót6—¶‹î’ó€ð^ê™Y³} ˜Zþ›ÐùJÿhàãþ¶JežÇWL ¿ct¿fÜSšÀߎȚ>}ŸUÍnÕ{1ŒMdW¶N‘R5»ý†Âº^7*ˋi(p6|ª’øòÖžw.¢cõüpttT’Ö?j6mÚÄòÍ(—ðÁƒhÔš‘€Œ>y Äú#R~ŽG@õˆIaMX‡«~±LŒ‘³ š›ÅHáÏ ïØ8l#&$äúøÊ_ßd¹mÓ\¶±j DéË~©ºÕ@QN¯Ý‰ŒE bк¹lîÿOa_î;OsFåæ $'íqõöN_ö×ɗ¬]§:ÿEšˆ=¿ó÷ŸùfÇYØm€Lvž8Bx䮹œÀ±›‘ÇÒ;%Ï]BíÜæ}8¿y¿x«ó„šÞŠ)ÂBB0¿óp1ç܋{…7Ö}YÒ€ºN%<ÅÁßpi‡+®8!æ Ü×_¿áŸ“DµØèš(ñ¥ µæƒº‹œÐ $E„š%&œš±*xãù‘£(ùMÜSÈ¢P~Àt/01΀QHyOm;÷DŸêíP±qù-ã‘L@IÞ¿ÂýóЧqitï.ùf1­]GqìØ18p@v7œ……fΜ‰®]»Š•ŒÈPXŠìž%¢0õûtNÙ-èõ»‰£G%ž­ž®¥ü© i£°FÊÉ"a% —œwi~ýƜö’kâæÃýøˆ¹ldãw®€¹¥…ì÷»'/ÁeÞjޱí=þ¯KEÙØmK…xMšyÝž‹­ãç ;(üÑÌ"Ÿèöøò-ìœ")â" ¶ì[# é£üôÁ_Úh,­AÂäð’õBÀ‘;0 (ë×°wŽÚ 3Zõ{žïæBwÜ`y‡xB§`©bøöñ Þùø‰±qÃ_É«:»€Âw\vÕZ7ÆËÇÞÂ+;fÓ"á©<³~7.n?(ãHï¥f-©á$T®î;yd[ ï+ä¥tnøßÕ"R0±\>ÀQ1©Ç9¡³?²l#n<%cG_P®Ÿ4ü™<ÇäANšÑ!sþ,ŸÔˆëeŠŸä}ü„Šÿ~q°vÄdñ… yÇ)ô÷÷‚F®¯Ç­ÃgÐrXoq§$‰Bz>éËi³,_J払ž3}aAfu5…y٦S˜ç2U—Z¿.y ]NÜwð¶°ŠY%UƒkÉz i`‡ýP°~Ïx×3h=)ހÖúüî'v``‹JjbwîÜÑÅÅþþþƒH¡ŠŽŽŽšWï¿ozµ4Î4„‹Â”ÄÊÍçqú] š ꑲZÐkËøyâƒ4}Š¿ãæÀчÙÎGÂŒp±éÿ„¶Eb‹Œe;'/Èùàÿðêñ3잱 µ:Z££ãP1Œ>ïŸ³Jä®I…3ö7^ö»ô ²©× I…„^Ù}$ž§B"IûŽÞ³plÅñœ×LTlZWŒ£,«†Ly1鵞<Ê¥[3ÌY¶öšõ PšLq‘O÷w¯Ñ²k1(ϐŠ™P£ðڞ3íE*yAÉêžk%ÂC~aõЉ«Jìžž¹ÇCÕzD_˜”¶žÞXékä™ÌY /æw&^¢J«”ÛžšÇ(!”€žÒ7OŸ§j-éüq‹ÚÐkÍuž,i{xþš\g–Úgƒ®-[Ðu„l] ×4Í) œ;»a.l;€Æ}; ±õûٓ – JÊë»süB<Î$ªÛÙ J4_5:*“I©ÃŽåÈS€`BŽxM* +ò³gæráݍ+ ›ŒÂ—©ý›KÈCžš*xÃçðQˆ Äž¡-…—‹›|â‰ÂÃÔ4k’¥Hvê5ùkwEñªÿUԒÏ<Å'ð#à.î^þÖU•z%…"–={ö 7nD*Rcbb"âžqãDåRnL€ ÈO€òxÇô®‚Ò…Ô—ã"¿õi7rýn7œxn<…q?\Ï9¿[€€DÊé3+”Ū–W-3î w”†"Òž±[— _1KYîÛЕ3EQ—ùkDxeψ ÀÙM{e!’u»Ž‘…ßI=r4×;ïX9xŒWºJM* (§rÇšù=ðÄÿl§‰Ÿí·-¢‘Ä&yöšhË'¿7B4’H¥pD‹RE…”Œ59 ÏNÜŒ6 _$AARœt•Ù°žçh!,)Ìr얿eÅb®í?Žc+·¯Vhpˆ]” ­~¯Aâ^a›žcwM["ž™êmš ó„‘2O!y¯î;.BŠé9µ]¿@>Jãé5*RD!ÏÔ€wnJ¿lˆrœvÿûo%! #1~xK±(”÷ T" »ô óêíQ²ºä?Fܘ€: „|¢pT§úèØ±£:MIpmÊ?\³f öïߏ/^ˆ+$jÖ¬‰N:¡]»v°Žüóÿ4nlÐ cƌÁøU‘?‡ä^Mn ØžÇ Ç^E¡~ß.éQTD$&7‘x=ÉË'‰m.nˆàšuód¡“q ËH¯ ÑX¡Iñáû÷FBdȲi"7B")4’yÅZë%ŠœPx)y'Z/Þ£Tš#nX TäPˆ«ýŽå"goû€E¬Gü/›“¬ŠØ6qŸ¬žå~QeRºê‚l¹n^<ü¿ÑÓàwßSx·Œ›+n™™gv$[ÁVêý€}JœÒq_£×I«Vù‹¢Rz5åR&jôÅyß?÷‚’ÙLÏM^«Bˆ+òéKÊ1$îĖ<ÐÒýIé·„£ŠôYPŽßóÃG‘/"G¶†‘aÆ»ûRQ~ÒññEᘚ&Š›"Oa·~C‘³r+”®ÙLYvò‡¢B… (W®Z·næEsމۚ± ØÙÙÁi@%ȝ±A$³ûÍû®áȋ0Ôïÿ_ mðî#V t’ “Fœ;¢@)+!ßyû‰»Ù€Õ^;(„Dr¥ôé9•ä— "ú®~Ȓ=kŒ;úâ² úüá!¡²ü®„.Q'‘FkK…ÿõã§§Œ[„® ᚉ]0N…@2g3Mô¢òžâ"¹KÊiÒ>q ¹ç•<ˆYså@à‡Ï"4WZ…Œ”u:·¢äŠëi±\«}»`~.WYrfùûåÕ;!f€WqHmKéZåÖ“+·P»cK‘Où»PMè–ëÌRñlÐ’$ ©â)}y@DžQ“x÷úImûýì=ÝÜe^aúBƒB‘Í æ×JŒ|ä…'WÜÅ3M³í˜8¿yŸøÒžÕ°>⋅žçK[µ”_J?KïLì7o<Ê6š)ëKóÑzÞ ŒŸÆá÷g?±ÿ>Ä}fÔñß…ၘlÛ†™ôÕaBºXS%¢°·Íh˜«‡rõ[§ HŒ í'°o‘&ÛtF›6mŽv3AAA8{ö,Ν;‡ 6hí>Øp& j$ T‚‹Â$QoÝ ®ÏCQ@ÚVeVõù“èÛ5}iŒŠ¢q×$/GëQýâÝ=šj›Žu~òVÒµ t§bb èŽÙWxeÉ»ôψÉBx“X¡j˜eêVw¹9…Ó’Øùð ?ŸAßÐPäGRèkJÖj5Œ7ÂBB…w7%‚0-ØKs9­mz¡IùªpÒEðûf¯ˆw¯d\Û)”µýØÁñ®0IÉÞBŸÿ@ltŒæéµùžJDá”1mÄÅëÜä# QØož=ô UCÅF’ÒËܘ€º Xâ§~m4>|Tݜx}&OaÿŠ(3&=lGe{ØzàyÿDƒé§úš‰¿{OÄ|ß>~†¡‰ Ì åC‘ ¥‘ת°ÚrŸTv˜*ž˜DÜ£K7ñåÕ[á]ʑÏ\äªYU*#ËW“š@ÞÚ†OŠ'n(-ä{p¢‚'nnejÖRñ¶S<=…nnvœºƒÂ‰åm”K^Ã÷Ï_"8ðLsæ€y XU,#˜sK˜‰Â<á˜f×N\§ÀM>¡a‘8xê.ôõ $WR(#|t í8Äæ)‡ÊMãǪËg"bŠØ6mº5«Ž‰'*>ÏÀ˜€F¢°_ÈE™SÜ#°íà ð FÁ=P*Ê5ŒyøŒžP=¡CòÖRfž"…„ǯJˆ²Â%J5$&ûàûRÜGHň('[Ú ðÑ<¡˜nÿôõtÓvñtޚLdB»þ‹”# m윖£ªµH?y éèÌ3äVŽþ3 CÛÕâ<Œ yúŒéŒF`ìØ±pè[ÿ¥Úd4)ÚïŠÍçqÜ'Ö£§š?wbò ë(‘B>säÍ-þègJ_"CƒŠêµT‘sÊэÈdd$*#'§û 篯X8± ôXÊIˆB‘«4Q8Üi‚ò£FëÞrÆ™€2 œÜ0}š”Gߟ}•9-ÏŘ€ Qhß§, šÅ¯”šŠªÕ€]®·°÷Qé¥V;xq&¬·›Ñ}êqO!·Ž#@᣹C¿`¶cGèêò÷å%¯Qh;aŸêä@í¿ä«–wC<Ž $DàÌօè\³æoÄù a靀­­-F÷,ƒâøã€Îz÷á[Øó0 ‡HJúscL@~wŽ_Àÿˆ+CšöOwÊO#mGúž†Ù¯¯˜;®£ÆJ[ÊY-4,OÝCdŽZõš‰üùÿ»j'¡RtOáØ) ð.,êu²QŽ•< PÀ…]ËѪœFŒ¡àL<œ 0M' <…œK£`n.8ÔYí9êŽ]÷ÐȆE¡Š?ÓlŸæˆ‰‰Áã‹7P²vµÝ×§ù”Tc¡…!_0o‚|•_Uc•öÍ*…ú†hׁrr {¶Åûàt»Pûˆ°Åé’À–É}Ñ |!¬\¹2]î7ŘÀHŽíU …̹4yRÏÅŸcw°Ãã3ÙpX=ÿûaL@{ (ÌMžÂñ\àR‘ST‰(5aus V;Uäpx¬ò\=žµòÅÂÉÉIy“òLL€ h$…v=K¢pžôUÌBÙ°÷»ƒíw?¡ÑÐ~ʞšçcL€ €ïC®Èˆ9NÓlÍôžJD¡ý„šBõ–\æ:=>4ځt@Ù IDATž§«Ö£fŸŒ7NÍg›™H{{{ŒéQ‚Ea2Ì\NÜÅ6÷h4ŒEa*/îʘ€†ð>芌ß0Û©ƒ†YŠ]æü ‹€ë©{ÐËd„¶}ç!kÖ¬In E9…ƒí&!2{QTµæ+)ŽëqH¿Ö^Ù·u ÀёïJ¿§Ì;cQX…óp¡™€ž‰ƒ'ïbóÍh<Œ??:L€ 0­%ðìÀ!ä‹ ÂlG…Šâ¯Ðžž&QhŒ¶}ç*GÚ8Lů̚ъË\+r8õƒy„Œ€…gîA?“1ÚôQ’(9abMQ§Ã FÍ4‚ÀÉ sЭ^ Ÿ’B#Nƒ`ª%àààÛnV°ÌËH'EÚõÌ}lt{…Æ#ùÿ«UûDòìL€ š’ÀÓ}.(aމ#[«r™t?÷¢ÐmúÌQާÐqÖrø~ú‰&œíÒ=@Þ v8žlÆto†.]øî í81¶’ ÈO€Dáš®EP$Ÿ±ü“d€‘‡ÏÞdž˯Ðx‹Â pÜŒE&n x¹@Á؟˜aÿWºÝcZlL%¢pޚížäþm‡ÏH‹=ðL I‘á¡8±f2œ‡vE‹-˜`霋”ðÑs°î¢?šØNÙîŘÐ@^û ÎOLË¢P‘ãùOfF›>³•ã)<|ê"®ÙŠ“Ö(beJ!ðíãøžþFôuë*eNž„ 0Í% Da—Â(’?³æ©–;ÿÿ\xŠ¶C4À6 0&  µÔû…iví䛀G 2Qh˜mz+Iúøø Ïè)èäžÆY²1j& VïŸy Öû úõíråÊ©Õ^œ 0Õ¢°s!)Eõ‹iñ '.>Âê³ÏÑtŽï‚MgL £ QXDÿŠŽaQšÈ³ÃThÆ0 Úôž¥Oa@@º ‹jF!ѲŠØÇc™€Â~<:‰°70jÔ(äϟ_áùx&À4›€DD‘Кmšš­;yé1VöAÓ1, Õ|Œ<` ðܳ:?ùJ ÒАÐp>ó@ˆÂÖœf [¶€{)º§&î>`Œ‹ÖB劝4‘‡3ù è@?®­GpÀ'̝;úúúòOÆ#™Ð t鈎`e‘ôÅ»Z±yêòc¬<鍊vCUž O͘P-§{÷Ã*S8Ќn£Ú…Òùì!¿Âqäìè)[.^¹§o=Ã_¶sÒ9Bޞ&(œ)OlBþ6\“ÏŠmcÊ"À¢0e$Ï\y‚eÇœÐl찔 à^L€ 0 $ðtß~X„aÊè¶hö˜$…FYк§=…nnn˜³ÁU¬{ ŸUí!–Š9Œõ/è.îß¹…J•*qåÑts²Œ&4''' kŸE rN{R€ÎºybÉQO4·Ώ`L@k xísUŠ0L¶eO¡"‡(Dá9òš¢uÏéÊ }ÿþ=ÆÎ\ó¢šÑª—"6òX& ōàvh3Ñœ{wXYYÉ5bL@»ØÙÙapÛ<(WÜ\» OckžòÀº3>°7*Wæå˜`Ê#àµßEx Y*ÆT* õ ³¢UÏiÊ…d–óüUxäÿUšu™ Wìšxtj”23@)ÃOسgŒŒŒ0vìØÔ çŸL€ h1‰§0Š̡ŻPœé®{a‘ë#4·¡úÅx&À˜€Š<ÛV¡˜ÄžB…«T>{ÛO܀Q–¬šÙŠB†ò`&}+gÆ¥“®xõêªT©‚F¥f8÷eL@‹ HD¡9Š̩ŻPœé¯{aá¡GhîÀ¢PõŽy&ÀTE€E¡rÈJE¡a6Žì9U¹žÂ_aèå0†Ys¢DE.SM9Vó,L  ,_°iÓ&ÄÄŠNdÉÂ÷•ñCÃ2 …Cۙ£Xa…Iù¥›Ï0ßåZ8ŽÌ(ï“ 0tHà™Ë¿žÂQœSšÈñþüŽ£çÀÀ(ZöP²($Ãæl9…gþoðþêvӜœã¡ÈñØ€ éë`X,"lôõëךQ£7nÌØ˜È@$¢Ð Å ›e ]§~«—ozcÞþ{háÄ9…©§Ç#˜ÐOá/L²å꣊œÉ¢0;Zö˜¢\O!vÝÿ/[³EðóÛWÔjÛ:ººŠØÌc™@¢º–3Á§pôèQ˜™™‰ ë¹1&±Œ76mr¢˜eñTîöŠ»7æíœ‡æ, SIŽ»3& IŒ9…Î#[k’YZg ‰Âcç@ß(;¬»OFöìٓÜCŠ/¯—Îò*(›O݅ל›È‘§ ÂCò…öZ÷˜h‡Á–ÙõQÛ,˖-Cll,† †"EŠh‡ñl%`J#@¢pH›(nɑ)IAus÷ÁœœwÑÂÉViìÓÓDWvÿçè7oIù¢Œ ŠÅÒmGðâKšÈñÒP¡Ñ_ŠØÍc™ÀW2ÀúuÿàÇèÖ­ªW¯Î”˜Ȁ„(lŋäɀ»Où–¯Þ~ŽÙ»o£ÅžÑ)”z/ßÂŽã[9{Ö ŽsÞ*Ð.>¡ˆÁ/ö*xlŸŸüÀ¹ëOah’ ÖݜU# ¥6þœv+õrãS@¢"#Q©q{èêé+žÎ€J¹cp÷èFøùù¡wïÞšS§caL ƒ?~<µÊ†, “|®ÝyŽY»2–(Œ‰Eà‡OÈU o²ÿ:vLZ„'nî˜à²9ó±×9Y`܁ š‰Àóƒa© gö*t²ê£Æ$ 'ªV†‡‡cë¶1.€ç_Ãøñ Ê×oÃÅg:Œ=8Ÿ©êšcõÊåxÿþ=ìííQ©R¥Œ …wÏ28ñãÇaP«ì, “y®ßõÅÌîh1^s<…ï>"KŽl041VÉS|e×aœ\»CWÎDÑ*å’\c›óB<œzãö®†™E>•ØÃ“2& 8ç¡ˆÞ/Uå¯Ðžž¹‡L&fª…d+ CEeÂgäÆÝëçQж5 –ª¬àVxxF"ÝHu âƒç ¬]»VVV9r$ (‘0ð^™H€€…-³£„‡&õ€ÜðxéÛnÂzxŽž¿†Ý3– AØt@W”¬Uy, BG—’N”ÓöÌ\Žç®bВ)(Y3éÏ[ÆÏó˜äºÙr§íõ&1Ñщæ1~ð}‰ìysÃ8Kfå@áY˜€–ð=t…õ8|TÑc ‹ÀÁS÷`˜9D¡Ôà3gÎà‘ç3èç+‹;O| ŸÉÅ«4@Ö\üâŠjzoš§ƒJù3¡ÞW¬_¿÷îÝCŸ>}D!7&À˜ˆÂl(a•|ˆ`F&vÓãŠi(€Â.'ÿÙïHH ’x+S¿:JÕ©ª°Úì4Þ·îÃnóßÈ_"éBdëífà…ÇcÌ8µ ÆŠ’»n©ˆ™ŽŽòDjBÏßݓ—à2o5ú͟€²õkÄërnó>œßŒ_xSÇï[£2jFþwÁ{×>Ÿ‡\a©žB.4,Nޅ±©9Zt ÚðÑßmõööƅ j ¯‚õáÿüòY•e¹Ȝ-m¿•S#W1¬†º°Ì¡ìaopúˆ‹xnš5k&*ŒæÈ‘CÅ«óôL€ h'Gôo‘ eKrä@Rçv럊n¹ë vqŒ¿ŸcÛÄxùøY¢ö4êÝ zþ%wá—U6ðÖË7EÞ¿µ#& [æ^Ú Ä['ÌyéF¬«²pRª·0«Í@„ÿ EŸÙN(ßž¶ŒÅ™õ»qqûAÙïêð`jăÂF0ßøºþ+ ùJ …ž°ðHžœ Q˜-ºŽO[Q(µÜÝÝ—®Þė(Œÿ‰ŸA_afa…ÅË#·EQ…6ȃµ€žŽ(WÐ<‹.Ì3ëÁ!ðžv—.]‚5j„^œz¡P¡BÚ·9¶˜ 0•˜0aœ…¥Š²§0)Øî÷ý1eó5XOÔ QH¶žÝž¶ºÀ²|) ü{2>øŸ!œ^×ïàÓË·b;ä=²|: •)žêgi^§¡øþ9ó.탞A҅î€rᵃ þ‰­ú‹õÌ æÇè a”Ù$Õë'7 èóWÌï4Ltœq,JI>ÛŽç·žˆŸ‹W¯ˆ®Î£ÍòÖù?ôÂÞY+Dxeõ¶MÑeâÈÛò Ó­û Oßž=«’G^Ej“­O¶ï÷/xvӑᢪiŸ¢…““PÊa€\FòÒº/ÝÄΩ‹®V•ËbÐßS``˜ð£TœÆÇý?~Fþb–(Xºxú¿FælŠÈjÆÿ_+×Áñ µx²kòDc¡sµÚ¡í‹GFFc×á[Ȓ£šwvÔ Q(…êÿ- Áá±øðoßÂÇÏ_ðÒßß¿ÅÏo_ñëgÂ… 2" 1Qˆ‰Ž‘ˆ5‰˜ùCäH$êEÖGˆ¥8¯Ñûb‰ø#­(„±ôz,Y(y]ò7œ&ù[WOOˆR!Ù€ÂM¶.é²…V‘Gk‡C–l¹$ŠÆéJþÖ¥þҟÿµ9ä{ ²åÌ-^'&ÆèêŠþä]52É,«+—$ÔÄ^uu }=œ…§Ø€xMWO:bC1Lÿ†¬Y³KXx“È“ðýÄŸ%";::Zü‰ŠŠ€¿Ç}^'OŸ¡¡!LLL`jj*:sssQ9”ªˆ+VŒE ¶ÿ—…ígj$0q‚ú5φRÅØS˜Ô1Ü}ôÎë¯hŒ(ŒŽŒÂ€ÆÝ…Éä˕?¢£¢ðåõ{‘Ë÷óÛwÙvšÐʰU³`ni!Œ‡ß?EóÁ==YŒ-“P"o])ñéå,í3V¶±Û–&û„NkÑÙÍsÁaçŠ$û^ÛÇVn‰×‡ª§¶Ò#Ù5~ï ­ÀZ±Y=4îÓQæ5$›‡­™h¡Ë®‹×ÉBli^–Ĉîd úôó;KÂR§ß/'óŠë^"Ÿq‹ê€ÚxÀÔDÀïðaÔùɗ×+È?2*;]oÁTEab{‹Š‚Ãcð#óÙŒž÷ëÇL—ÙPºn5x]¿+Œ©U¬¢ûÔ1ö‰»édÿ= ~÷=…ˆt>ð?¥^¢‘î øÿ+ 9|T±£ŽŠŽÁŽƒ7`šÓBó<…ŠmG3&À˜@F$À¢0e§~ïÉ+Œ_«9¢ðÑ¥Ø5u‰0žòõ(ü1ñ"0+”9óSºHÖ?6öÚÓk†9‹×'º¬/n[7jŠ9í1Õ:zºØ3cY¢pÈûh³bòZ‚ÔkY¢f% ^2UŒ‘zëwo‡¶£ˆÜ v3Ä{µ:Z£õˆŸÈdl$‰¬¡+f hÕò);Œ{Xð,gR:pèʙ"$5¡FÂva·‘2ØyâèàšË [±y,-„§óþ7읜 zü…6¶’‚9Ô(Osnñ31ªlÝ Uörg&  ü‚¹ÐŒ‚‡ƒmn k®‚hÞÙA³ÂGÜgL€ 0 HÀy‚ú4ÏÆžÂdÎþЇŠmvƒµ†x éþ=º‡/5¡—Þî÷±ÙqŽž·oê±Íñvüê±7þ1IŒFùyþŒd¢žŽ o[þ<˜×Q*Ù|pw4(Tä!Üä8_ߌ‡Eébœa¡,Wñ÷¢4”gHmüŸ5žŽãb$û̇5*ŠÈæÄ:E†…cJ³^²·IJó)œ–ÂX Œ eï¿óñÃÊAãDþስsÅŸý<,èÇ|Å,e}ß<}ŽÕC'ŠßI@f͕¶¿KCL2ž35ðܵt~aΎjŽ"},œaræ)‚fDz§0})ï‚ 0&q Lšè„žMLQ¶]óÃ-1ŒÞÂ~åYޚ¢¢píˆÉxùøšòf¯)¿&ãp™¿æm’X22Í,„fõ6MÐÅy-Z÷£ç^ôâ°U3aU¹œ( æÜ «è7õè&dÉI•ž!ò÷HDN<°aaX3ÔYˆ0jºYªv(a%Yj/—§*«÷-nlpïôe\ŽNŒFûi;f ìnÆžfÈsIÁ€Ùy|ùÖ]ZèƒFœùÃ4ÿ—B{ Œ:vùc8|T'(…M;Ø%{€J/¯WÆfx&À˜ÈØXŠìü={ ûš# ¥EVڍˆzÝÚŠlÿö¢PHʛ£{úHš ”,*{}׎%xtñzL³Cå’,ÇWoÅí£ç1ýä6q< 9Êˋ›(€<} {µGƒžíSŽ O×qš™c6/â’Ú‰ÕÛà¶÷šø™ ÁPAjÔoQ÷Q›Hö÷žåøÇ†Žß ª`jlcÓÌžžý ò“+îB<ÆÍ%€ŸR¯$ O Ü˜€6x}ì(òÅüàB3J8ÄM{¯"‹B%ä)˜`L@í&;;¡{#S”+Éޏ€ã‰÷;Ø-;­1¢PíŽ  ÐҐ `äț[‰³&<•Ïí‡Ø7{…,ÿð÷^”'Ù~ì`Þ*mä)=µv'Ú; AN­Tn#/ÀTIàõñ£Èõƒ¯€PäÍû®ÁÔÌÍÙSšš<`L€ š•€Ýèh[ËMë–V«šŸž§Ï{ŒYr ­Ši†§PÓyi²}Q‘ ¯áûç/ø Š9sÀŒˆ¬*–ùãîFò<ÒÕ”7_R“÷Ƕ1€Œ9~yY*å!ÙŒÿLs±(T Lž„ 0&ÀÔK`²³#º5ʊòì)Lò <Ÿ¿Ç˜¿O¢Õ4ÉÜ2ÿO±ÎvªC°Ð9clšw™® Œ9~ y£¿søšNy‹ËudÉQÍ;qN¡pòL€ 0& NS&9¡kƒ,(_ÊBfhüÚ^Ï?Àvñ ŽšÎ¢PãK‰Jk4Ê7ª¥Ä™y*& oNEÞHUý­.×a’£0Z°(TNžƒ 0&ÀÔI€EaÊè?{ñ#GëéR6€{i=ªp:ݺ¯ØÇ¬s»DURnL@Û Œ=q y¢ØSšŒsÜvàŒ³bQš ˜<`L€ š—Àg'tiJ³§0©“ð~ñ#cQšÞÇ5MW¿Ö {g­×]pÕÑ4Eϋ©Àۓǐ'â;šQãíoÀ0+y m‘+W®$gä{ •œ§`L€ 0Õ˜:ɝ뛲(L±ß' _p­§OTÝaðÌE€.¯§Kì+4®ƒÞ³5Ê66† ÈKàÝÉc0gQ(/Ÿx㶺‰H]34nkƒbŊ±(T Už„ 0&ÀÔB€EaʰûøÂðyGÐz‹Â”Óþ^¿~üÄùÍûP©yýxWThÿÎx™À»“Çaąf”ðì8tŠaÝi4{ •À“§`L€ 05˜:Ù êeFÅÒÕh…æ/íûò†ÎeQšù'Å2&÷'#Wø7L¶mà$°Óõô³(äðQQòp&À˜P7òv¬Ÿ•X&yŸ/?cèWŽžÉךû™åõ™ŸÀûSÇa„I£ZË? vŸ=“‚°îÌ¢ &À˜ÐrÓ&9¢CÝÌšT¶–ïDµæ¿xõ6³±(T-fž 0øpúr…b{ &œûˆ;tŒ-ВE¡Â,y&À˜P3©“ìÑŸvT)_X͖höò~¯¿`È̃h=k’fÊÖ1&À’ ðñôIä àðQ%<%{Žž, •@’§`L€ 0µ˜>Ùíë°§0¹ƒ œB›Ù‡ÑfæD@G'¹îü>`L@# ø»B¶Ì›ÐY#íÓ&£öœX£hŞBm:6¶• 0&À"@¢°]ÌšÂá£I> ä)Ž™u-gL„‹BþÇĘ€–ø|î4L|ÆÔ1mµtšcöÞc·“©Zv33³$ ã{ 5çÜØ&À˜H€€…µ3£J9Î)Lê!Qh»ðMt€®®.?KL€ 0­$ðåüdúˆivíŽÒ~M2zß±;ˆÊDžÂ‘, 5é`Ø&À˜H=é“Ўr Y&ï)œy­8§0õ`L@c\< £€÷˜>ö/±I[ ÙU-qx IDATü" Xjëù±ÝL€ 0&‡Àô)hW33šIæ© +)†ÏuEË|%ÿbL@{ ^:ƒ/o1ÓŸœönBC,w9qázùѺ { 5äHØ &À˜—ÀŒÉhSËUË[Ê;E†÷üågŒœwÖÓ'fˆýò&™HŸ‚®œ‡îÇ7˜åÀ¢PÑv9yáº, åÈã™`L@̘âˆ65Y&sÞ~1záQŽ˜Æ¢P[6 09 üžz±o_b¶SG9gàaRNz T7Ú°§ &À˜Ðv3§8 UMTcOa’Géåûcÿ>ŽæS'hû‘³ýL€ d`Á×."úµ?æŒcQšècpð”~é°(T”#gL€ 0 0cªZW7Aµ >šÔqx>Ç¥'ÑlÊx 856 0& ë—þÒóÆw’o%#pèô=„ÄæA›®|%?L€ 0& å„§°‹ÂäŽÑÓûÆ­8&“Ç%וßgL€ h,_7®à—Ÿðåõ Ÿ‘ëé{ŽÍ‹¶]¹ÐŒÂ0y&À˜P/…-k˜ :{ “<ˆÇÏÞÂyÕ4šÄ¢PœO,¯Î˜€"BÝÝðÓçNì¢È4<ÀŽC7ñ#Ê =:!wîÜI2áËëù‘aL€ 0&0Íy šW1AÝêÅ4ÚNu÷Ðë Š¬9‡†ÎNê6…×gL€ ÈM ìöUüxæ…EÎ, 冸ïÀÃgïã{tŽí2‚E¡¢0y<`L€ š—À¬i°®jŒê‹š× _ýŸçL_w &:jž¥l`L qw®á›§'Oîʘ$päÜEš£mW… ¢äáL€ 0& n³ŠÚ£EUԚĢ0©³ðxü ³6\Bý ê>2^Ÿ 0& 7È»×ñõñc,™ÒMî9x „ÀÑsiŽv, ù‘`L€ 0m'@¢°yUcÔ¬d¥í[Q©ýwœÄÜ͗Qw‹B•‚æÉ™P)è{7ðéÁC,Ú]¥ëd„ɏˆ€…Ã9|4#8ï‘ 0&ž ̞jf, “=âÛý±`«ê8Ù'ۗ;0&À4•@Ìý›øpï>–Më¡©&j]Ç.<Ä×psüÅ¢PkΌ eL€ 0D̞ffUØS˜ÜrëŸo¿†ÚNc“ëÊï3&À4—ÀÃ[x{Ç˧÷Ô\µÄ²ãáKXnüՍ=…Zrdl&`L€ $F@ˆÂÊÆšY™ÃG“zJnÞ{¥»®£Š‹Bþ×Ę€öÐ}䎗·îbåL…Šžâ‰‹ð9”E¡¢y<`L€ h9ÓìÑŽ’1jVaQ˜ÔqÜžë‹å{o¢†œœ›À˜€Þ“Ûð»~«fõ’o%#pòÒc|üe†¿ºƒ¹¹y’døžB~p˜`L@£ (l\ɵ«Õh;ÕmܵÛϱÊÅÕǎQ·)Œ>`L@núžwà{õVÏî-÷*³§0™ƒž|Ë;Ï2^Ÿ 0& 7Ãg÷ðêÖü͗×ËÍP:ðô•'xÌ¢Pa<`L€ šŸÀÜéöhT‘ÃG“;‰«·}°Æå6ªipøhLt4üzÁûÖ=}@ÕVP²få$·#Ã䶟.Þ?ùÏv›fA㟝ÒÅ~xL@žwàsõÖpøš<øâ9sÅoƒs²§Pa’<`L€ šy V0FªœS˜Ôaž?ðÃâmWQKï) xû÷Ï¹áæ¡Óøùí»ly,-à°sEŒm}~õ§.áëë÷ÐÕÓãK70Áe-ræKºH‚t’ðÐ0ø$1ò=¡Á?Åϱ1±ˆ‰‰A˂Èe‘Wîç:àÝGxÝðÀ«GÏðåõ;DFD"1KŽÑ9óç‘{^8¡^g1~΅=00Ì€Ð\ªL utuT15ÏÉþ#ðà&ÞzÜÇrŸ§Pá§â¬›'^ωÝ9§Pa˜<`L€ š—‰ÂåP·Z1õ¢á«?ôzƒék΢žó8±ôÍÓç8³ažßy(³)KŽlšÛµ ô3ÀŒP”ªSUöލC§pdéÆ?ìoaÓMûwùãu€Ÿýßà“ÿ|ô{ ÿG^xëå›ìþí·-EÞ¢…“퍫ûŽ"ôGÂ~ýÂÏçxçã—àž Mê ÷,ÇdçLªƒTN=º YrfWh.eþúö69ÌFöùÑÜ#.sW=ñ2(':²(äƒ 0&ÀŽÀû!šQ*:ZWÑö­šÔ~_ÿÏ3ÿšLŸ€ÒuR2¹ßOœX³=ž@ËWŽ0ôjOúLC^ÄÃK7ˆ×«µn «*åpqÛA|}ó†&Ƙx`L²fžÆûgÝðèâ ŒöôIÒ Š9³‹ñq[;»A°(•Œç9ðÃg,ì:"ÞX³‚ùQ®AM˜ʇ\$Ç£Ë6¡pùRèè44%xì‰ÉMzˆ÷*4®#Œß>~¿“gSQÁ)·aÿ€ßÍNsÅo•š×GÏé|Š¢Ly|‚ÝÎÞbŠC{F€ sWŸâeP… räáL€ 0& æÍ‹úåØS˜ÜQŒýð 6Óö¢Ñ”‰ÐÓ×K®»Jß_Øm$ßk”šY Múue…RÐÑI8ôBF—ô–\¥ÑfT?4è)ù0Ha§‹zŒ?÷™í„òkc“ãløž?ÙO‚¯d­Ê0/\Q‘QžŒÓUˆÀi'¶$(>S³ñàÀ Ìùk°Ršl ޱíËò¥þ˜BÞ°Ê»'.âñ•[øþé+>Œx•šiJXaØêYˆÛÔì%¥})ÔöÝsÑœp¹’ñΌByÉæwÞ~˜è²–œ…)…ÊýREàó™Èö F¶NÕ8îü'óמÂÿy ‡ò=…ü€0&À˜€v˜?ÃõÊsøh2Çøéë ž²5íGÃ8KfµúŽI‹ðÄÍ]Ø@žµNNCQŽjùDmÚ7{%‚Z¬ÿð¶-ïï “T,[¹×öa§-wGþâV²<7©ˆ$5fób¥0Xe3Ax<í·/C^«B©š3üWh¢BŽ„äÄ ‡Ç•©_¥jUFŸâE§HA%ž.yI ~ü,ò –.=ýDm€þa!¡Âã·œ÷ñÇÓkwàëñH’6ò|ҙ€€Ñ~(ĔÖÏnžKäƒ&×B†ˆÜɄ<Çɍå÷Ó/×®QÂ4¶ý›€ßMŠÑÎ.\÷‹€ìBæÉ“tÎ3_^ŸF‡ÂË0&À˜€|$¢<…Åå› ƒŒúöýNڍòC#›y.µîšÄÐá%„Г6‹ÒÅаW{zW0}þŠù†‰näݘ-k<Ûݏœ¡šœfØ !HÅbBŸ}‡i®ìñËë÷ø»×hXU.‹a«f)…Áz»xáñÎÿ'òéÂB~ÁïÞøz<3¬RñW·KkXí%Ö%O)yL«X7D·)£ãyÜHœy]¿ ׿׃Œ‘JEã>á2˜ËaçrQ'©FâÍuñ:|zùV֍ΝöMa­Äéâ¶(R± ŠV)~äe¥ðÛ6šÝ©¥QÝ2~^<Ï+MFs苅¶cÀªRÙ$í }žÛŽžWo Û©QØnõ¶MQ»S+d˝SŒF¡ŸŸw£n×ÖÈdd„ÃË6à–ëñ¥ÁšÿÍÿCš*åðx­$à·kj́~ëh¥ýšdôÅ^ðýJá£6, 5é`Ø&À˜H=…uË¡^u…IÑ ‹@¯q;PŒGO˜[Z€Ž F|zù7žÆM×Óñ„K'§a²3’žkê”oT }æ(V$çí³X5d<ŠW¯ˆ!ËŠ)eGÒPX:‘á2áwrcß?¯à¬³;Å[$Ú֍š"~n7f êuk+~~r厮Ø,úS£ðÚv£Š3ûßèið»ï Ûõ P°LâÏû‹{O°~Ìt1žÖ,]·š™$ÊH„vŸ:ß¿b^GP.§ÍŠXÚwlŒÊ¯3NmÃߗøßhÉ<Ôþ;Xä|RfBlö8uõ{ŽŸžy R[ÈK(ªÄlÐߓ…èu]²^ˆÀ AÏÅ©µNԚôë,ÓJ94žD« xmø:Ô-ŽvÍ+iõ>4ÁøK7žÁçKvtêÁ¢P΃m`L€ 0(¬SÆõk°(L cl,ÐÕnò·m/òß4©ÑµwO\ÂÕýÇdbšíèšßœð&Rø(‰&OŠ4òF­æ,BU‡®˜¡ÈTb,yۜtýcaeÔ@±*å‘-tuu‰°Ÿ¿„—L:vÇäÅxzõ¶øœó„x~û¡žbƒ‰Áfº¡pù’²ù·N˜/ĉžb‰„Û†ýH©ì/ž }ž¿lFõš‹:\qZáœtó|>³(T$OÀ˜`ê'À¢0åg0hò˝²õ«§|Pö$áD9ä1¢6bí\DGF aB­1[þKÞöÆË«m&QL!‰Š6³3ZõÓP™’µ«ˆ»ßsò[‡Š¶lޟ…—ŸÅëÒcª*[7øcØf§9ðŸuƒ—NC‰œöȲžqð”xí•òøžÝð¯‘Ð&Á- _•NB}Çn[*æ?ŒdœÌ{I!€÷Ï]řõ»e‚Î‚®)]§ZœßŒ_¶FR^@i©'ŽyœŸ,întرYÍrÀ¹a71åìÝ9~!žít•]·a”ÙDäð‘×TÚF­_€BeŠCšwùûµ$Ø=N^Âå]‡eÞ?ò:¶;Å«UÓH¯¥šØ¬žÈñ”žcïَâß۞™ËñàÜU! éšiÕXêÛsŠœ{g¯Àý3npܵRTå–± èé§ÆOÁá ¶01Δ±a(a÷WnyÃëSVtfQšš<`L€ š•€DRøšf…DªJ"‹/Ø|—ßG¡Ù@‰pPG[ÚÇNä”Qž]vÍP¢fe™#:* ÁßáÿÀ·ŠI‰/ä1¢ðËF}:¢R³z0ÌlŒïŸøM>¡JœIUµ€Kì)wŽÚ· †@І‰·û}lvœ#Df¥fuþ+ á¡¡øñõ‚¿~Uό C&c#äÈgŽÚ¬ÅµÔ(ôôÊ®Ã8ý¿]ñ–$/܀œÝÜìSŽ.߄ëN¢ƒãPÔî(©ú)õÚmþ±ˆÅÊAã„×’Œ¬?ŸÂïÁSÁ_Ÿb–²9¥¹šôB×I¶âîG©]Kœ§ÛŒØØX!¥w.’çðá…ë8»q¯Löœa/Îã÷ ¬<^6v׎%âŸÈêmš ó„‘2Þ?ƒpußq.JëPŽäF‡ÙâÎIb9vËß²ë,š’,y©OՖRs<Ü7Ðýñ —¯À±Í’+jž)FÀÍÝž²¢KOÎ)TŒ$fL€ 0µX0ÓµK²(LÁIl;ùëÏù*t‰z –I²ËÕ}Çp|ÕÖd§i6ššê.ëGÅGŽ,Û$*}&֒ «€1ý^cY?{1|Ò¡õ Wa}xþvÏX–ì^š…gÖëÚF„]’8¥<Éw>~blWçQ(PÒJ„’RõOju:·B{û!ñ柎Ó§×íÕS[ì‡g7=„—‘rýÈóI¹Ò33ÏìÁĚÔv /¹n^Œê§Ò‚6䝣ÜÃ5C'Š éIŒ“h¥FâðÂVœßâ"~ŸunÂC~anÁ•øÆ-ŠC6’hÿÜ_†JLhmºÊCš8hÉ”¬YYf¶ÿƒ§Xg;U¬ßsºDÐsËžÂ|ŸÁ÷èql]2(ãBPâÎÝnûÀó=‹B%"婘`L@]fN†ê%ŒÐ²Qâ÷Ü©Ë6M[÷Ä _Ì?ðP“”朩bož>—²ûÞy„ï_DÕNjFYLDq“:ZŠ¿j~÷Ÿàñå[â i.yÆ*4­‹Zí[$yŸŽâ&ÍK^0iÑy÷(õŒÅOWj*W斐=Ondɞ&Ù²BOÿ¿{ùâ`°ÈYäæQ#ÚŸ¹«DeBw2þò)]WêQ%à¢î£„°€b7œg9Š* q‰¹ ÏÈdd(ÂKKשŠŒÿ =i¿çwaãØ™°ß¶††XÔc”l ͚;—ðìҕÒk&Šß“lŠX1À¹ …ŒR{pþ.ï8$ ÙHy«·m‚j­›È΀ާŒÇÆ};ų—î7üßè©Èž77(ג[Æ&ðõºb^<Ã"ç„ïðÌØtR¿û«·Ÿãñ{Sté1yóæMrŸ§0õ|y`L€ €!…3G£f)c4šÉá£Éa¿ùô=&lœ-B郻¶7 ô¿ÔŸ¡jŠTm31љZ&Tl&*"á¡aÂc—[€UD)ïŽòïRÓšº'Uù$/£¡ÜLòŽI›§›;¶OZ$~%]Ý.m`V0Ÿš*úò‘ž\qBŽÄkßyã]šÄ£4—ŒŽä‘€PÐßí¹ÅšÜBR‡ EFDü᥀5é…ùŠfËÂ+™’ËîS5)wÖJ~®‡PÒ$ vƒši¥ýšfôµ;Ïñè­)ºôdQšigÃö0&À˜@* ,œ15K±(L·ç~`ð²K(ß°&ŠT*“‚ÜEH@þ B.‹€¿™OlmxÆŠ™J>·bßìñîŒ;]õÐ~ìàT_MBë~yó^x4 3›/h^«Â çfª‚1ϙ> Üûßzt«WZübœ>wš6»º~×ßdaQ˜6žy&À˜P%òÖ(e„†5ÿ»ÏM•ëióÜAa±h7ErÝ5Ç-ý ï%y ß?) ñ˜æÌó"°ªXFœáÆŽ‘À…Y ±Ä© ÊϯækœÍ7<|ñàUtéŞB;6ˆ 0&ÀRG@ˆÂ’FhX‹EaräBctÑuÑEQù²IÎÉIŽ¿Ï˜€æˆ Ãé©sqe—=tt4Ç.m¶ä†Ç Ü•]Yjó1²íL€ 0&@XŠü9‹ÑÁ°ÝÏðòÉ3ŽÜCä¥qcL€ hWœpöv/  æj…7ïœÀ=…œSšçÅF2&À˜@͍êì)LÑ3«‡3ŸðôÚTkÕæ–)ǝ˜`ê&à~ä,ÊF~Ä »¶ê6%ݬëŸ.?‰EÛö=Q¡B…$÷ÅÕGÓͱóF˜`é“À¢™¶šVҍ8|4ÙŽŠÕÁô{QžézŪ”G‰š•’Ø`š@àÔê-ÙÀ[UÕs҅ î÷ýpÇÏÝzsNaº8PÞ`L #X`ç€ÖjY?œ.zçáKÜò5bQ˜^˜÷ŘÈHÏ…*ōўv©ŒŽm…özÆ? 7]D¡2ÅQ®a-…æâÁL€ 0U8ŒtÚ6,ƒ‰•VõRjþ»^âÆs#tgOa†:wÞ,`L ] QX¹žšÔæ ©9àK/âíHXÛôLÍ0î˘HS‘áØ2~¶üc‹ºæºiºvz_Ìãñ+Üð6B×^‘?þ$·ËÕGÓûÓÀûcL€ h9E3G¢r1c4­Ë¢05GyèÒSlŒä mšÁÌ"é©™—û2&À”IàéÕÛð¹ý[çõD1£eNáçº÷ä®=£ðQ…þa`L€ 0m'°dæ(T$Oa…©9ËWï0g³¢KT@™zÕS3”û2&ÀҌÀñÕÛPŒda¬èW &ºTC™›²\Œñ ·| 0hèhö* *ÏØ`ê!°dæHT,fŒ&ì)Lõ,Ùp÷>„£ò þ€ŽNªÇó&À˜€* D„…a»ó"¬[6 è«r© 9÷ƒ§opÙÓ=zbQ˜!ŸÞ4`L X2k$*eQ(ϑºÝöÁ±ó`Öžô YÉ3aL€ šŒÀƒsWäíƒãó;ªlŒ<ñ#¯·žðXOˆÂ $‰‚s 3ò“Â{gL€ h%³G¢¢‹ByŽê{p(Š-9 ËRVˆiÐ ±±òÌÂc˜`ª!p`Á?Ò¶†X—QÍ|Ö'Þïpö¡.z²(ÌàOoŸ 0&§°BQ.4#ïQ:}WÜ}вGxpÁy9ò8&À”Kàno߇«›‡B—Ãە ÷ßٞ>S÷€^}³§P%„yR&À˜H3Kf@ù¢&hÆ9…r1ý.K6œ…uÃr«P~arÍØ`Ê$p~ã4(hˆIƒ)sZž+gŸpüN,z÷cQÈ`L€ h9籜P² !úu®«å;QŸù›ö]ÅÝG¯0Ø¡.‡åTŸ!Œ2`LÀ€ož°x5ެ賜Y˜‰Šxû}ÄÑ[ÑBZXX$¹ çªèxZ&À˜P¥³F œ• šÕã+)ä%ê÷ú –¬?‹Ž­«áeњŠâ ¢åeÉã˜Pœ€ûW”Îô³ÆŽQ|2ž!QÏ_~‚ë(ôaQÈO `L€ h;¥³‡£\…\ˆ@‘³Üžç*<<_¡³]<ˆÈŠÈT<– 0& 7àÀ \Y²[fwC‘‚frÏÓ'ðâÕž\ C¿6ì)L÷`L€ 0M&°lö”-bÌ¢PÁCz÷1ӖF³Õñ®t}gãáL€ 0ùxìvAY£PLÝVŸ xTŠ ø¿ùŠœ—CÑ ‹ÂCãŽL€ 0& ™–ÍŽ2–&h^Ÿ=…ŠžÐÁS8zöšŒ™8·PQž<ž 0Ôøüê-lڊmó{!ŸyöÔ æÞ©&ðê]v]Á€ACÙS˜jz<€ 0&À4Š‹BåGxDfUadnñ—ò&晘`) à±nêω‘ý§ 7wQ”À›÷Ø~î' ²AÁ‚“œŽ Í(J›Ç3&À˜€J ,›5eŠ£yý²*]'£LþèÙ[,Xsåûõ‚AþBeÛŒO&ÀÔLà‡ûuø^ŸŠ  ³q&5[“1–÷ñ¶œþށƒ‡±(ÌGλdL€ €_ä),miŒ, •vÈÿl¿„ O?£–ípèð¥ÑJãÊ1&0œž²ìØökÄùáiøŒÿ„M§‚0ˆEaR祘`L@%–͆҅MТ{ •8"2 ÊîE°EIÔêh­¬iy&À˜@‚Þî܊\F:˜j׎ ¥!_Ÿcý±@ ¶ΞÂ4äÎK1&À˜€ ,Ÿ3 ¥ ±(T6Zߗ_Ðgš ªvïˆ"•Xp+›/Ïǘ€„@ì­ žùVÏÙ33–4$ð9 ÿþ‚!6ÃQšPÒéœS˜†ÃK1&À˜@ê ,Ÿ= ¥ØS˜zp)±îøüãr†Â4gŽŒà.L€ 0”0y÷—¶ì‡ãPkÔªl•òÜS)ŸþĪCŸa3”E¡R€ò$L€ 0& >+fE‰Â™aÍá£*9„>«®ã…ï;t?\%óó€L€ dLAßà¹~=ZÔ/ƒþ]êfLjÞu`P–»|ÀÐa#ÙSšæ³àå™`L@A+fÛü+ Ë)8Oˆ€ûO#ÈK0x IDATL^|1QÑh=²/CbL€ (L 2<¯¶mBA³,˜Ì—Ô+ÌSÞ ‚~ü’œï1l8‹Byò8&À˜ÐËgÛ d¡Ì°nÈ¢PGò=Z[>eáe›a’ÕÍuSÅ2<'`„@ll,|wî@–È̛І™ô3ÈÎ5o›?‚C±p÷ > … NÒ@Î)ÔŒóc‹˜`L s†¢„… ¬±(TՃáùËnúØñ÷Vd˝MtUÕRïrèŒH'ÈCH‚0sà{Ìuês³¬édgÚ»ÐÌÙꏑ#mÙSšœÇȖ3&À˜X9gŠYdaQ˜FCȯpŒ^tïBuP§_7dÎÎìÒ=/ÃŽ–åÞÛ¹¹#‚0Ó¡=rç4ÕÚœ€'ÃCÃ"1s“FÙ²(LOçÊ{aL€ dHSí»¡P^ î^/Cî_›ŽŠŽÁ¢µ§pÓë#j÷î„L…‹ªÃ ^“ 0- ð w¶ïEy3=L±m Ó,FZ`uÆ01<" ÓÖ?Ç(ÛÑ°ŽŽLrӜS˜1ž Þ%`L@k H<…>Z^k÷ ­†o;p'.>BõÆ5¿Q#|ˆàpRm=K¶› š‚€ÿçxtð(:Ô²„£M U,Ás*@ 2*“Öú`ôh… `ä¡L€ 0&  Xª÷Üøcå–ó(œ?št³ÆÇ,ùð‘Å¡z…Wg@àÆ¡Søt×Nœj¡£u °ˆMø@tt &¬y†1cư§&À˜Ðn+æ ù·Ð { Õu’tòº—ñàéti]Å×Ç­`#üŠÖU—IŒ.`j"ðÞ÷%n< “X,ÕVÍÔd /›*þãŽò)ìììX&‹ßgL€ 0Í&°hJ?XYdF§–U5ÛÐ `›»6ï» CtêT‘Eʀ®³àƘ@ú'NÁ×㺷­Ž}j€ÿM§ƒ:®ðžÂ"EŠ$¹Î)L‡Í[`L€ €g+fBñ‚ŠœSš!‡}Çîˆ\Ãb–æšÛº>Ÿæ)ޝ‘zb!›Á˜€² Ü=y O®ÜBŸ¢…1y`4²4Qö<Ÿ*èè`Üʧ9r$ŠMº`‹BUÏɘ`J# …YùJ ¥UÎD_‚±÷Øm\Ÿé"–æ(Þ°.‚ —UÎä< `AÀãä%xÝð€i®èѱºÖ(sƒ(°H]Œ_õÆ CñâœÀ¢0<¹ `L€ šÀòÙQ¢`6…ê;‚$WþŒC§îáìUOf͊|U*#WõÈdÄa¥zdlH’@à‡ÏðŒr Ÿ÷žÀÌ"/º¶®Š^u-‘S?šÉi]LXí…!C† dɒ, µíüØ^&À˜øÀòYP¢pvŽlXޱh0°ðHœqóÄY7OÚ,Þ¬$ Ðx…wîLå·äjþҍZ±f»6nÍSrzªZ¶k«Ú+ªc'…ÇÅ7î€z"æòØA.Òr+Ü%¹=’9àÓí±döõìÓÖõ›µ}ã6eoÉÒÁ}EJ=œÚöì¬NúhtÛP Š-QšEtȔžz®Pýñٍºú꫕‘qâ£m…§ÎM €õ(ðèœ×ªë-tþ­Gæ麎¬B‹¿ÝdŸïpCf®¶í,PHd”âÓRÝ2Ma­Z)ŠUº’[§),"ŒAjbœ&ಀH—Ûðì wä}û9ËŒVýyB|anÿíÌÝ«ÌmùÚŒ=_[³vkûÎ=*-+×é­“Õœs+™Ñ^ý{µSDxšÓVŸzêRÀŠÿ™ùƒ®žâ õîÝû„= 랟@ê\àÑ{§©ëI„Â:—uF‡ë3sµ~SŽ2·ç)+{¯¶åíWΞb)'Ë;v•»Ç~Þž+o»Nï[ñðëöйå‘Ç햧ңü‚ýJIŽ“ÛíQe¥[ee•2ßÛ-.-ÓÁƒ%*:X¢ýE‡Žwÿ!íÝW¬œûjO¡÷ZQáVtT˜Z¥&šmz’:¶KU.­Õ¡mªÂÂ8uL£ú³ªÅºÂu÷s?èÒK/Uߟ} …§êÉò €ÁxôžkÔµC2¡0xSÐà#› 䝹…öގmyEÊÌ/Vvá!8€CKUZRª²²2••Wš²ŒR••æê¶7ºÍ²Õ¯Þ }ïóö;˜`è >– Ž–,—ïÖ<öÝ÷?ooÀëuÿsÕÚÛí\–JKË)³×çð²RˆËeoÌ'&D{ƒ“]‡¯ûaµÚ|òŠêð†oªzì[Ÿª­/üzÒeèšp»._þ’|{—Œ4f¯—?äœè@BĎ ØÆÙºM?ŸÔeߘ°âòE-ï8æӋ=?’òLjWÎÜĢ9Ò·œ QU¯ýxÞÍ¡“Þ÷w™ŒüýJM޵©ô¿?|’‡Óœ/ÄU¥Ë#Ws¯ö'„±øžh;ÌÙ}»M]nïžnï{Ñ_çÝŠ.·=Íëæb¿ßÌž,mÏ*P»¶Éös惍—ÂB] UDx˜¢#ᄞ(%ÆG)%)Vi)ñjÓª…R“ãůÿ6ø_\NС{_Ø€I“&éÌ3Ï$:qŽš @ 0÷\£nRtþ΁˜­Ž'px]rWzTi6äÝnU˜ÛJsß<籟3¯•*2"ŽÚsþ׌·f™J³Ñ_­/·ÙÈw»•·O©IfOw óŒw<rò í x;ù«ïŸ’üÁÅÞaåMhŸÜ`G(ÿ«êm}ñË»·Ë÷À?ŸALðÊÙUš˜èÅÇzC¡Ç›_ìTíïÉDý;Ñ|{¹ìÔâۙfÆò=ôõፈÞEŽŽ“–*Ê+î’eìËbŸ,Fe);·P§¥·°ƒŽ–]fšÙûëMÞðn–·÷ûB·ik–)+«PddžÌŽâªå\.­Û”£Œ.mªú1mýaÚÇÎÍÞ~«?öæjPÿq»Ì­yêÚ¡•\!–øM¿U·!Õ›`gjt)ÄþààÈǍnï5Í4Ý÷BŠ&Nœš ǬQ% €À±L(ìÞ!Ec …ŒA@\ $Rz1SãǏ×À …ËÑ@Ài3îR …N›êAp¶@H”þòòf;Vgu¡ÐÙ³Eu €'˜q÷Tu±Ã9|”w  € „Dëo¯nÑšQ£4dÈBaÀp4DpœÀŒ»¢îZ 73„ àhÐhÝÿêVsÎ9:ûì³ …Žž,ŠC8¡ÀŒ»¯V÷Ni„BÞ' €ÔF 4FŒŸÍ„Ç'֯޶ €Îxäî«Õ£S+ÞÃY…Q  €NÕCon·¿OhöžèÂÉë<‘Ô†  GîŸJ=;¥k ¡w € „ÆéáYÛíÓQŒ9’Pž-@œ&ðÈÿLQÏέ …N›êAp¶@XœfŒ•¥~ýúÙ?6ÞBgOÕ!€œ@À„Œέ5š=…ŒO@\ ,^Ÿ¥Þœ{kôèфÂÀåh‰ à4wOQ÷Žéœ§ÐiC= €ÎKÐcïd)##Ccƌ!:{¶š@àDß7MOo¡qçö @KÔ£oogOa ^ŽCp®À3÷߬ÖÉaºpL_çIe €8M @š>˜¥ÌUÿԭמøÄ»õ16}"€ Ðh"RtדËtå•WÚ¿@J(lŽ3Iá €Ÿ6O+ŸxA¿¹é|0@@ @+"UwÎX€ë¯¿^]»v%èF3@ ,Y²DŸœÿþûÖq¬Ž’@pŠ€ …¿~àKÝvÛmjߟ=¡Ð™ÓDU €¬^œZo=¯þükBa ^ŽA@ÀX-õ‹?ÍÓÝwß­ŽŽ4B!o @Æ+™™©'ü/=ü;BaãE*GhhwXªnýÓ\ÝÿýJLL$6ô0 €@Ý äääèo÷ÜŠ‡î8O¡¡!u×1=!€ ЄyZè·|ЇzH111„Â&<׬ Ðä ô§»nל¿8Kq1‘M~}YA@êB °4V|l{ì1……… ë•>@‚#pàÀÝõûÛuçôžj™œ"@F&»/R}n©ž|òÉ+ç<…5Ñ@ ˜åååºóŽÛôËËÚ©ÝiÉÁ,…±@h4?d‡èù¬Õƒ>Xc̈́‰h€ lßßy‡ŠŒŠU¯®m‚] ã#€ Ð(–ÿP©åèž{^BaD4@¶À_þò ërPÃvv)Œ €@£ø|å!­Ê,ÕoûÛë%ÖHD@` ˜ïCœ“¥‹Fv v)Œ €@£øÇW{•0N·ÜrKõ k$¢ €@°Þx㠕¬Ôµu v)Œ €@£xùãEµè€«®ºªÆz …5Ñ@ ØsçÎÕºoçêö©œƒ] ã#€ Ð({{³ºõ®qãÆÕX/¡°F" €[à›oŸÑœ÷^Ð}?ìR@F!pßsk4~ÒÕ4hPõ k$¢ €@°6lØ W_|B¿›ÞC1QáÁ.‡ñ@pŽ€Çãя.×/þß©cǎ5ÖJ(¬‘ˆ €ÁÈÊÊÒ̧gè–É­Õ*5!Øå0> €ŽØ D~q~sÇ•žž^c­„‰h€ l}ûö鑇þ¿®£.҂]ã#€ àhì]…zìúŸ{þ¬žžžk%ÖHD@` TVVêÞ{ïՄ–öjìr@G ¬ÏÌÕKs ôÀƒÈ²¬k%ÖHD@'̘1CZì҅çr®B'Ì5 €8WàË¥Žts ýášHBa@L4B¶À¬Y³ŽçRÝxY¯`—Âø €8Zà폟Ձð3uã7T'¡0 &!€[`þüùúrÞkºëæÁÁ.…ñ@pŽÀã¯|¥ý.ÕE]P„€˜h„ lÕ«Wkö;3õóË»šEBt°Ëa|@+ðÇsuÉ5¿×€ª‘P@‚-°}ûvœöÂcºòŒu8=5Øå0> €ŽØWtH>ÿ•nží~uèÐ!  …1Ñ@ ØEEEzü‘¿iL?—ônìr@G lÍÚ­Þ_­ßÜõ€’’’ª‘P@œ ðÐU—”\MÕÛ åP €ŽX±f»þ÷óLýùá×är¹ªP@œ ðöÛo+ã‡úù5ç8¡j@@Àqÿ˜·Bمúåïf\¡0`*"€[`á…šÿÑÓºmÚ0EG…»ÆG@Àq¿ô™Úué¯É?¹#àÚ…SÑ@ Øëׯ×ì7ÔtQ»6ÉÁ.‡ñ@p”@iY…þòäGºä²©:sĕ×F( ˜Š† €ÁÈÏÏ׋OÝ­‘g&ñc3Áž ÆGpœÀÎÜœzþ­…úéM·©}Q×G( ˜Š† €NxàŸ_©[ë MÝÇ åP €ŽøníÍþd…îøÃßÛ2#຅SÑ@À ïŸñ”v¬_ Û¯ã„rš@ÇÌþä;mÉÊׯ~ÿ°¬šÓ®‹P0 @œ °tá§ZðñLM¿ìl¥$Å:¡$j@@À<÷‰:µOÓÅ7<&YŽÂN(tÄôQ €@ [¶lÑû/ß«±CÏPF×6.F;@šŽ@áþb=ñòçštñeê;âšZ­+¡°V\4F¶@qq±žxø¿Õï K£‡õv9Œ €€#Ögæêý¿Õ ¿zHé§u¬UM„ÂZqÑ@À ¯œúŒömý·~>m€Ê¡@‚.ðù¢uZòŸœúã_Ÿ—Ëø¡£ŠpBaЧ@j+`Nbÿõç/iêÄ ¥&ÇÕvqÚ#€ Ðäžzå ¥v©)So¬õº kMÆ €ÁØŒy³f¿3SçôŽPßmƒ]ã#€ TœûŠõÌ[ßê‚K©ÔºBa­ÉX@ Ø¥¥¥zü±‡Õ-%WFõv9Œ €@PÖlØ©¿.ÖônSëÖ­k] ¡°Öd,€ àÙ³gkãŠ9úåԁ  uBIԀ €@P>œ¿YërtçwžÔø„“bc!@` ¬X±B >{_ΊUÇv©Á.‡ñ@Š€Ûíѯ­WŸ£4a„“ªPxRl,„ lüü|œþêKêÓ:_çéìr@ lË9šwÒĉªgϞ'U¡ð€ØX@À /œô’å­Ô-WòœB'Ì5 €4ŒÀÂu!Zž2G·Þz«âããOªBáI±± €€-Z€e‹çiòÙqjÛ:É %Q € '`IOÏޯĀ–š:uêIK(ØJo|øœF­þýûŸô؄“ŠcA@'<ÿüó*/\«›/ëá„rš@X²µµŸZºZ7ÜpƒRRRNz\BáIÓ±  €€/^¬e‹æé¢!1jwZ²J¢@ê]ÀŠí€§ÞZcpÚŽi§4¡ð”øX@ Ø999zû­7•‘ž§Qƒ9„4ØóÁø € #°£Ž—Þ™³@£F:¥CGMµ„†™3FAšG7ß|SٛëÖ«28‘}=:Ó5 €€3¬š6ú÷÷Z¶l™nŸùf%&&žRa„ÂSâca@'˜Ùõŝ×Ç¥[;¡$j@@ Þʆê‘gg«k×®ºä’KNyBá)Ò €@°ŠŠŠôÜÌ¿«}B¶.ÍÎ{>@ “ŽnoW͝;W&LP÷îÝOy0Bá)Ò €€>ùä}¿ìCM9¿œÒRNîäœNXj@@àDVÒ œýñZeeeéöÛoWhhè)ƒ O™@œ °uëVÍ~÷eõiW¬ƒº8¡$j@@ nBc•«AzcÖû €u#`YrµššoVmӂ 4yòduìØ±nú&֙#!€8Dà믿֒/gklÿ(uë”(@“°ûª2¶¯ž|òIûœ„Ó§O?ùΎ±${ 딓Î@‚-pàÀ=óÌ3j“T¡)祻ÆG@à”¬ðdYéõݪïõÙgŸiÜžqêÙ³ç)õyô„Â:å€3@',\žP˖-ӄamÔ)u¿J¢@NJÀJ%EŸaàér¹tË-·œT?'ZˆPXç€tˆ l}ûöiæÌ™jÛ¶­®&ρÌ`—Äø €ÔZÀŠí,+å­ZµJŸ~ú©ÆŽ«Þœ{׺Ÿš Ö$Äë €R`Ñ¢Eúæ›o4~üê’žUžC;åzP4 €@3‰Ž\ŠÒgï%4'©¯œ„F—PØLßc¬6 ÐÔÌw ÍÏv§§§kÚ՗ʓÿ‰<¥M}µY?@&"`%%+Ÿ—V¬X¡/ŸøB\p222êeí…õÂJ§ €N0ß+üꫯ4fÌõê’&÷®y’»Ì ¥Q €Ç°¢ZËJ¯ââbûNs’zs²úúº ëK–~@‚.PQQa·°²²R7ß|³Âʶɳ{~Ðë¢@N$àj5NŠl#óÃiK–,±ÏKØ©S§zC#Ö-#€8A`íÚµš;w®†ª!C†È³w™<ûV9¡4j@@àGV|†¬€ÁÊËËӋ/Ÿš=z袋.ªW)BaœòÒ9 €€Þ{ï=effêºë®SjjªÏSLLŒ<û×ȳg©#ê£@f,à õ6ž¢ùóçÛb^qÅêØ±cƒ  „™A@œ °yófœûî»:óÌ3íÓT˜‹§`‘Q%%eöa£.—K7Ýt“"""L‚PØ`Ô „ àsÎBóßöa€‰‰‰RY÷û…•‡œP"5 €4#«åYÑíô¯ýK˖-ÓÔ©SÕŸ}û 6(7ƒ!€8A ++K¯ŒòŠºté¢Ë/¿Ü.Ésp³<ù_8¡ýôS;öð/’îš+Ï¡N(@©€ëŽ)Rh¬rrrôÄOØ¿4:mÚ4Ǭ ¡Ð1SA! €NøüóϵhÑ"]xá…êׯŸïÄöK•¥N(@™€+ýB)"M»wïÖSO=¥ôôtû‡eBCC³&„BÇL… €8E࣏>ÒòåËíÃzúôé#ρ òìþÊ)åQ €@#°RGÊŠéšœ{÷ê駟VBB‚nžáEFF:j …ŽšŠApŠÀìÙ³õÝwßiòäÉêÝ»·<{˳­SÊ£@‡ X-ÉJè­={öTÂoŒÑqÐ0 þf¢<@à ˜žùöÛoí=†æPROî?å)ÙŒ‚@ QXñ=d% µÏƒkmÙ²¥®¿þzEDD8²~B¡#§…¢@œ"0oÞ<-Y²DãÆÓà³ÊœýUÎ_è”É¡@ÀVt;Y-ÇhçΝöÊtîÜY?ýéOår¹X­·$B¡c§†Â@œ"0þ|™ 1§«;"Cî܏Ru €8I ûì³:tšŠL™â€ Y ¡ÐñSD €NX¹r¥Þÿ}û÷“ÏëšðâÕN(‹@œ"!W›+ôå‚%ö¿&LÐ\à”êNX¡°QLE"€8Aà‡~ÐK/œ€V­ZiÊè4¥D9¡,j@p€€«Í¥šõÞ<-\žÐ>åDÿþýPU`% s¢ €¶À®]»4kÖ,åååéÚ+G©sÂVd@š¹Àèaúû+ÿÔÁƒõ³ŸýLiiiJ„PØšŠ‹b@œ PVV&sÊ sHéšQ£t^Kžƒ[œP5 €4°ÀŠÉzýýùÊÈÈÐôéÓuRú@)…JÑ@£V¬X¡·ß~[íÚµÓå“F*¹b±äñà„ ÐLÞø4O_-Ûª«®ºJ#GŽlŽkM(lŽSGá €NÈÍ͵ƒaVV–®ŒòJõïè–g?Bㄹ¡@ ŸÖoÊ՛ó6)6¥›ýýAsÂÆ|!6æÙ£v@ǘSV˜svéÒE“'ž£$÷wRù~ÇÔG! €§.àöxôÆKµ`y¶&_õ Mœ8ñÔ;u@„BL% €4 ììlœ÷Þ{Ú¶m›ýSä#Ž”gÏÒŠ±r¬ ÐÌ-߀Ì[¡6§µÕ5?û³ZŠ¥7Ba“™JV@À)K—.µÏQÕ¢E ]6iŒ:§Ès(Ë)åQ €@-2·åëç~«]{jò…ã4|ÜO¥ÐžZôàüŠ„BçÏ"€4Bó³äsçÎÕ¢E‹ÔµkWMÝCi¡ášP2 Ð<vï-Òû¯Ðòïótþ芟Ü$…Ä4I Ba“œVV @À)挆sæÌњ5ktfßn?4]É»Ru €%Pž¿X|ŸI_~³E#έ˧LWBBB“v"6ééeå@œ"°cÇû܆6lЀ^§iÜY JIuJyԁ4{]…n}Ž`».ÛšÁgÒ€I“”žÞtŸ7x¢ &6û·? € )°}ûv}øá‡Z»æ;etŒÓùƒ[ª]›ä†,±@ü!Ú°CútqŠV¬ÙªaÆٿ(ÚªU«feD(lVÓÍÊ"€8EÀVjNañõ©mzœÎx†÷n)yÜN)‘:@Š+uºŸX–­…ßlRÁÞ}v?~ŒââšÖÈ:„Â@¥h‡ €@=8p@_~ù¥.\šÒ’bÕ¿‡ÎÚS­]Rù^yÊöHî²z™.@æ%`E¶ÒÆl.ߪe+ŸWëÖ­5|øp9²yAcm …Íþ- €€SþóŸÿhÁ‚ZœzµÚ¶m«Aƒéì³ÏVLX©µÙxÆgØAÐì Œˆˆ€¿Ž…uI7 €8Q`˖-2W³‘eBb^^ž Ô¢E %''+%%ÅŸŠŠŠŸŸ`)€b·ïpÓ©²Ô‰«FMDÀãñØ;£=²ÿWußÞAíñš€¬BáaÞ)Œ;­ýíœOxŸò=gYÞ>dyۚ‡©pÿ!%ÄÇø–·ŒËTµñ¶5ËØËVëÃÛµåíH’Û#¹,—dÚØOYööcû K–ëð}Y.ûõŒ‚BµLI²ÛÙíýËø–³ª–7}›—œí öìSJj’=ŠËbïÍk™Ç!.¹,ßó!!²LmÕû?⟷Z{ýŽQwUMÇ]ŸZÝþ6G¬»·îcŽt»ãŒ7Í!ð{÷îµ÷òù¯æï#ÿuߟ}ŠŒŒŽÿ>2{M4b™£bbbÉ;Ÿq–I(lœóFÕ €œŽ€9ÌÔ| oB¢ùTÞlœ™²ÂÂBíß¿_æÇmÌ'ðf#Ì~éRtx…¢CËvH‘aEF„)""Ta¡ QXhšBC\ ±ì [{ÛÑ»}/·Ç#·Û£ÊJ·**Ýr»+í K—oãÚܘ mû?{›Ù»ámÿ,„eÉåÛ@7·fãÚ~èÀ" ÿ°ŸâWò‡Y©è`‰â¢#ìa‚‹¯\_Hš<ìÕð…ßmõÐñãûÞõ¶—ñuZPxP-côŒVü!Å[rU˜ñÔk·© @þ:ŒmœeÇ<ܳw¿ãOþ:üËø®zìMKU}Vµ÷Õd›94îÕûò†:䘀áogŸÙûë¿ø7è^Æÿºù`Àì•9^;ßæÖ__õñüýúŸ3ï3Ïþ t¬ tŒçüÌŒ~¢ hŸ&ž˜šêªœêÎæŸyÍ©£Ÿ¯>/ǚ¯£Ÿ«ÞOõPzt€=:èšÇÆÀ„'ÿkþõð¯Su¯ê÷M;ó¡OZZšý¡y_š[=̙ûG?g›ÀfÞCf«‡äê!ԌoæØø˜« —æj>L2!Ö;󡒹šþÌ{߬‡©ãˆC×ÿ7aó)PØ|æš5E@ I ø7è«ßïþÑ{lŽÞksŒëc=Œ¶fό9,÷X{„jÓÿ‰j3{xÍ!uG_ªºc…Áã=g–3ßÙòÍêÁ±úµé¿z(<:Øú،m>”0‡8ºÌ±Ú™1Lñ‡ðcíêa¬Iýaeš…¡°X4E@@šš¡°©Í(ëƒ € €ÔB€PX ,š"€ € €MM€PØÔf”õA@@j!@(¬M@@@Š&@(lj3Êú € € €µ Ö‹Š € € €@S 6µe}@@@Züeœ"†£þ ftEXtapplication/vnd.excalidraw+json{"version":"1","encoding":"bstring","compressed":true,"encoded":"xœåšIvâH\u001a€÷>\u0005ÞŠU1\u000f¹*<¥ÁØÆ\u0006;mWÕ«'€\u0000”\u0016\u0012–Ää|¹«\u001bô\u0001úŠ}„\n\tŒ$ŠÄé!éêXØ\u0010\u0011\nýŠø¿\u0012_w\n…b4î©âÇBQ,ÓuìÀ\u001c\u0016?Äý\u0003\u0015„Žïé!”|\u000fý~`%3;QÔ\u000b?þòKz…aùÝÉUÊU]åE¡ž÷›þ^(|Mþfî\u0013(+2œ¶«’\u000b’¡ôV\u0012òùÞ3ßKn‹\u0000&\u001c1\u0000ål†\u0013\u001eèûEÊÖÃ-Ó\rU:\u0012w\u0015K6$㏻ˆ×*\u0017·•ÑÁîaXOoÛr\\·\u001eÝD¬Ð׏’Ž…Qà߫ώ\u001duô(œë_uUà÷Û\u001dO…aî\u001a¿gZN4Ö}\u0004Ì:'[ð±öŒâ‹@\u0006E\u0014rÌ n }ØäznÐd\u001b&-³Y\u0013¹ö}×\u000fb¹þ\u0005’–JÖ4­û¶\u0016ϳÓ9-³\t\u0000Mç\f§OK\u00181d¶Íft”ÓîDz\nåÒ@™†SATr\u001c\u0014\u0003‰žäé.Äwï•íD3þ˜ßώ\u0019ôŠûVL€ÌH\u001e=œW«¬jeNŒ{ãVqp~z\u001dŽÏN¢V-€š5[+§‡f\u0010øÃâläۇuë¶\u001f÷Ú\rò\u0019“ŠÉ\u0002_\\ZìŒÚ}…u©\rʕdžw{Ì;Á\u0015vj\u000fn©÷\në\u000eή\u001fC¿&+\u0017àÚ?\u001dz.é\u001dٛ­;ý”\u001eQ¿g›\u0013Æ £‚\"$!Æ\u0019¥p\u001dï^\u000fz}×Mû|ë>År'#ðóì\u0010r•=„S,4\u0004\u001b›\u0003X\u001dÊۇúџàŽZ\u000f\u000eìcÂOœŸi\u000eèwÍ\u0001ŠÌ\u0010iË[\u0003D4§\u00103$&\u0016\u0001ÎËõ[\u000f_æ¢ö]'—9ÿ<÷4•䇰\u0012he\\I©¶Ö„ÈÍ_LÚå/¥Û‹{ÙùLwGõ\u000b\u0007WË\u001cm\u001bUÌ@LÒžxB\u0005‘Úlä\u0003MÑ\u001aP\nN¥Ö'@æ\u0003M \r†\bŠR\u0010†!ËPøª~*óFu\u001dhXPI… ïÊÙ;‡‚—*ìù^š\nMßފh0/ÐZê&ÎôyØa¢Ó\u0007\u0004ùæ¥ÎõÞ}K°›Ïç°4€€ÚQé¬MÀL)c<Ù\u0003Cr(%@z§$xYQe\u0015eHp\u0003K‚\u0011Ð\u001e\u000bé |‘9b\u0010\n\u0018 \u00003‘xÞy\u0004%àRP\u0006þW\n.ad\u0006ўãَ×փi¬øô\u0013—ò\u0006ï”\u0013h­~,%0\u0010%ñ»\u001fÀ8€Iüž™Õ6{‰Ð†\u0004LgåTÛ5޵åœÎ˜\u0005­EåÙß\u0017j}Γ\u0017\nI&\b$L\u001bk!)[\u0014\ni\rC\\Ë\")Â\\\b‚\u0017„rÍ0Ú÷»]'қ_ó\u001d/šßäd7K1ä\u001de.\u0018\u000eýPÙ±ykЋW̧\u0004é§B\nLòeöù\u000fKgï®Tæž-šqºÜNöÿ³«R\u0010Í÷НH%ˆ‹ÃÏ\b\u001f@£}Œ+\u0007ÕñeÓ>=zp.ðàÓݶÛ1!\rý”:àeIËgµú8\f„õ6èX\"i/²c«ÊRË_Ž.ür\u0001\u0002Â)Ô¢ŸAž0Ó§w¯K!\rxz&o^zÞo\u0014\u000eG‘ò\u0012\u0000¶ \u0018É\u000bŽóŽkɎ\u0015Í^¯\u001eéýšÙT}àŽ=}ètÙâÀQÜe¿€KZŒjb\u0018b\u0002U|Ü_¿í|û\u001bÄ0EŒ"}§2ÇIEND®B`‚fulcio-1.6.5/docs/img/sign-certificate-sct.png000066400000000000000000002503421470150653400212400ustar00rootroot00000000000000‰PNG  IHDRòåV.Ç2sRGB®Îé IDATx^ìX”YÇÿt#(Š"*v÷bwçªØÝÝÝÝ»öºvw|¶kww‹b""ßsîðCHÌÀ¹ßÇ3sãÜß}qùßsï9Zà˜`L€ 0&À˜`L€ h-ò±Nl$`L€ 0&À˜`L€ 0A€…÷rûЬ6ù ¥¥ -mjCßµ¯µ¥×JïiiéDՉT»òqårQþ£€Ÿ"åŒTO|$©tIêÈëz|yŠùH}(·ê[1žØ0·——ÿüóÛGd³- ¯ &’}1ÆWp“וúSpo˹FGé}ùÇ{ù8~Þ06³ˆzj•HÒ:š"”æC+ã”äx U(ï&æÎHÌ͊èJU¢¯£«µ&J¿cq‰Õ˜¿‚qýNFD7 ÿˋüy•È7#D ùëÈ÷•?ú“ê‰ïÊu¥>é=¥Ÿ©œVn'>Wz_1^d=¥Ïmãz/<ááa—ÉÄïdž,TüYäûáa‘ïÉ€zÒgaòz²0„@;<áÈj€ }ÃÒÒÖÖÖȗ/rç΍lÙ²¥ù¿~,äÓ9Ș`L€ 0& iÜÝݱÿøžsï\>œ‡ŽVò䶁­MNñGŒ¹¹9ŒŒŒ ££ƒððpøb÷Ùû0·¶• !XÂÅwñ¿ðHÁù™x<øò×җ§;L-¬AmésñY8ÂÅkùÏôŸøNŸ‰:$bä¯åúQ ڒˆ‚?öŠ‚¢ŽB4Ë7$áOmüyÂÔ2G€–ú‘ T±)AâØßFfqxû£‹Tÿ_?ab%~޹t%«ÉD2_ŒŽÔ¿âµ²^ª ¬A•Õ­˜Ÿ’x–t)€ÈBC¡,’åc+‹kiCAÙ[®,Æ#í¥·$£•‡€%öR¯‘ŸËç*)f…ÉQo)~=rۗ··O#eŽ’WڒäŽñžÔ”F—®ã£‹øè‚=r-D%ayz@þž²0—ŽŸ$Æ%ñ¯,䥟¢Þ“ú‰õJ¢]ú}¡q"WÄïOD8 ~"Ÿs¥ç_úÓÖÖ}iéh‹ïòŸåßŗŽÒk]ñš~µÅϺ¢ŽŸ‘ ô Åk²Ø¡È¢Ý_øÿú777±Q@âŸxñâøã?P¬X1äȑ#Õÿ‰c!Ÿêˆy&À˜`L€ 0M%pæÌì?zŸœB6»È[Ž<ò–šˆ¬9ó*Šd £}m˜êkÁÔ@ †ÚÈbšo>2䛊̓}üúîólÖJ^U[1œ¬Q¯or×pœí•^Ž:‘m"Eв×6aÁ%0¥M”èžážæXZÛÂÓõs€WYÙk¬lGt!,ä­²š–ÄpŽ'%._zÔ.E”Ã_éœxN]H'!¢’Pœlˆ~Z$ú‰mÅ)Åi± $ß🠉<%’؉¥“#òS$‘§FŽIdËO˜¡M? ¡û»Þʟ)‰òX][;Õïr›ë¢@V˜†zÂí“îÝ»‡GA__öööš_¿>*V¬}ó)­b!Ÿ‚0¹+&À˜`L€ 0ŒAàøñãØºk?~F oùº(U³9ô Œ2ÆäxL€ €(|º°³ÔE^“P8œzÚüþý;LMMѪU+888€èxÔ ùGÊ2&À˜`L€ h*7oÞ`ÑòUøèê ûmQŒZcM Û͘@ Ó8ås룔µž>}Š'NàǏ°µµE˖-QšÅÌH™ÂB>e8r/L€ 0&À˜`N`ÕÆíØŽi3ŠÔh ‡Ö}4|6l>`éE ¯….*Øè#¯…._ŸŒ£GŠû÷͛7G:uRÄ,ò)‚‘;aL€ 0&À˜ÐdœFÍÀ³—¯Q§ÓpØ.­ÉSaۙP¥¬õQ>·ŒÝ¿àСCÂ;_Ÿ|yŽk×î·-d!ÿÛ¹&À˜`L€ 0M%@§» 7_Z ž]}M Û͘€0ÒÕÇíKd‹À‘ÇðâÅ áŸK—.¿e- ùß§Ãƒ€Ð_ˆõßEz‹ò€–®ŸqLTŽL-JiŒš¥aaaâØMz[W7už‹š9+G`Jw ===ÅŽ•3ËDfmŸÅz_ÑB‘O&*çiÌÏÄëøêŰKj-?KÌè±Ê)`âi•”U)÷ª’Ê6)Û•'FD†…¶üKÇ02áKzÅWPP‚ƒƒÅWHHˆøò÷÷_ôYP€7‚ýœäƒÐ`_„û!,$á²`yQ2UÇ Ð5‹&„¢TSŽ"€ì1wÆÔ ò Ÿ"Uf4™@3òÊ¥)R|D֖§ÖŒJ\éáù –YL¡£«™w3*O¥h)åãTÊ*ҏ(™#Ï%*ERÎKù<äïIyH…ŒÌMªx?R(yzyÃ2‹™Hq! ‰#ÿ&‰P¹íò‘¢úUdU4“WSÊÇ©H?*å•·‘§‘¯¥hõ †±±ôtt&“)ôŠÒqyàÝGw|øüC„ 451DáÖ(]Š"òØW@ë€6Ÿ.RÏUd«˜@æ&@»õ0 =f"›mÌ ƒgϘ€Zðý…‹›æ eíò6x Ê6±WE‰ÿøñ#>}ú„O?ÂÆÊ:á>yâ×O+wN ØXË¿ø» P¹ `O <"nßœáüÙ/œ\áôÁ ÚZZ°¶Î&D}‰r5`[°’ÆÏ“'À˜@Æ!°téRŒøê²ÆgœIñL˜Ðx¯ïœÇ¯çç±`Ú8ØÙÙ©4ò `rvv†ó{'8¿}ŒŒÖÆÐð^w·ŸÂÓN÷F):µe¥ÒÓÆ•˜ÈÐ(²þ7w/<ó Ï^eD06͂2å*£â ¯P™ =ž`êM€îÆ÷êÕ µ{NC„U!õ6–­cL S ¯üåͳ1°cSŽiÓF¥¹³é‡‡Þ<¿wožÀÊ0Ô €,,Ÿ] o»­òåÎ#CޝÒƕ˜ÈŽ<œüðê>ÿ$îØ›eCÅÊÕP¹zSØØæÏŽ\xâL€ €cǎáĉ(ßw9‚ÔsØŠ=<*`L@™Àœ3»¡çú›Ö¯†6åO€°AD°;œ^=À›OàûËÖVf"·Ž«‡·žß^0_väϓÅ{bOΘˆ‡À/ŸŒxë‚;?àÛwäșÕ룂C˜šš27&À˜@ª?~<òÙCX‰v©>À˜H*·¯ñâä¿X2c,Š)’hóL+ä#~=DšŸ ^<„—o¿ÀÂÜ&F𠆧—? ç·F!»ÈJ¹áž0&À˜@Šðøé‹{O?âöCgøF lùJš×š-ò(•bcpGL€ 0eèÔ©FÌX†§9`L@íD„‡ãðÒÛ»-Z¶l™š}™RÈž\Ƴ{çðü­ òåÎ mmžyøÀÔÄE äž `L€ €>Š~ñÖŒrr©ìHÐWtàŒÎ©OžG`™‹ÀóçÏ1kÖ,ŒZ¶ ÷Ÿg®Éól™ÐW¬Cƒ¬X83Q›3• Âã«[ñäá-äÏc---‘Ù.ŠÊkºυ 0&ÀҜ€—w®Þy‹kwßÂÈÜõ·FÍz­¡££“æ¶ð€L€ d<{÷îŃP­×l|ú–ñ&È3bL Cx÷ð^œß‹Gw&:ŸL#ä?ŒƒG×öÃÖ BÀ¿ÿô% çFÉÂ6"ï;&À˜H¡a2ÜžÿnŒDH„6ýõ·U)èKú[Ï0& ®,XsssèWÐpu5“íbL “øñÕg6/Àá­«‘'§U‚42ŒwrrÂûW‘Eû tÂ}ñáË”,’¥Šæwâ¹0&À˜€z ;ôg®䂀ïP±t>ØÑÅx.L€ 0& ñBBe8xê>.Þzú £s¯±€–¶ÆÏ‹'À˜@êhÕªL_§àl©;÷ΘøMGVNDÕjµ°pX‡Ì!ä))¥ɖ-Ü>>@Y;ʗÌû›¹9`L€ š#¯®?±çØ=üð…cÇnšXóOu4“mbL@M4oÞÃç­Ã+ 5±ˆÍ`L€ ÄMàØšišP±ê’±…Œ®]»†à`yNPð/š\ÈjaÂÏ`L€ dpoŸÆ¡ÓPŸlIô8Z&3øŒyzL€ $‡yä‡ÎZ‰—Y“ÓœÛ0&ÀҌ@ŠòÎÎΞzõªH'BÁíªÕGÉ<¡i™bL€ 0ô'àçŒ-û¯ã³ëOtíØe«6‡–qŸô7Œ-`L@mŽkלÆÎûpµ±‰ aL€ ÄEàèÊIpš^ó†fУõÐîÕ«W000€¡ŠYõ=ùi`L€ 0LJàüõWØwü.ê×(†Ž]úC˲b&%ÁÓfL &îÝ»£y·!p5)Îp˜`jMàÀ’QhØ¢ Š÷Î`ÁîÂÃÃqéÒ%ž¹¹A&“¡H¡<š\0.jœ l`L€ €>÷_ØŽ÷ôõu1hÐ@XØ5HýAy&ÀԞ@Ÿ>}P¯mxX–S{[Ù@&À27Ýó¡]·Ÿ×±v‚ Ž""""4•¯¯/.\žú†šUŠ!¿…+žxMYC¶“ 0&¶Œ‰G/>¡w¯®([³WZ Éc0& Æz÷îFzÃÍŒŒ[ÉŠ1&À€3{£û 1ÞŠjÆòß¿Çùóç*îÄתá¯x­™`L€ ÄIàW8xêZµh„Š'ÐbRL€ dRœzõB³NýðÍŽT&%ÀÓfL@Sl™ÜƒÆÏ€Še5_Èýú§OŸ†¶¶6òḉÚeŒ€š²l'`L€ €×ï\±~÷TšPÝÍŽõÓÉ– 0ô$УGŽé>ŸŒJЧ<6`L AÁþØ¿xúœŒM>A€öGë?~üˆÿýï"š]¹b9P)ßO^~&À˜`*øñÓ«·_„Uvô1FМ~Jex\‘ dì®C¯¡xoP,ƒÌH³§áíႣ+'ãåíÿP²z4ë?YsåÕìI±õL øþüŽ“ëg¡ç Ñší‘ÿðáŽ= ]mÔ.kŠy5æ: ,#wÁ˜`)EÀ/ ëw]AX„!ŽšË윞.¥Ør?L@tíڝû‚“naM07ÃÛžcV<øï€bžÆŠè·x? •«žáçžÜ zÿpÅÕýëP®þŸ°-̱’ËQÝÛyº|Ä¥=+ѵÏ` hšppNµõȓ'þàÁƒÐ’ù yeØç·Vwîl`L€ š10lÜ{ Þ¡2j6rØUckÙ4&ÀR’@—.]ÐsÈXŒD¡”ìVíú „Ÿ¡QšØåïý‡ÿ‡Š:¢XUÕ3„ÈÂB1ŠV6acåŠ]Œ‡çŠ×ƒþ:Š"•ëЉýñ rlÍ4›Y ~÷1éjGÌÁ7Œwċ§Q®n[ô˜³5Ù¶}yóg6-@»ÑKa™3O²ûIˆÉ}ÖÒÒÆ”ËÕù%nŸØÎÝû ¿& yº¿sçNhŒGû†agk•Rlž&À˜ÈÄÂdáØ²ÿ:>»ùaÈš™°±+‰iðԙ@æ!йsgô>Ï fšI»z‹{§wãûg'hëèâñÅ#˜và²Ù€þ©£¯oŸ`i¯(T®†®>/׈ðphik+>'ÏòŒVE`S°$Æo¿)Þ¿~è_\>Vü<`Ùa«Z1ۥՍ¬f.†Zrñ;ô ÓjØÇ ðñÂä&ò5­ÚŒ;:NZl»®ü‡ÿ&}§ Q¯ qöC™֌64Ҳķæª>kiikjõùÕ<¹ô?8ví~5,ØE§ßŸ};B~ÜC疐׆ï2ŠÖƒÂý2&À2#™,[ÜÀ'Wo 1 6*dF µ=O!LÙû0ÎñNoœ‡³[¡÷ü(]«¥šóõÍc,í]¥j4CŸ…{íž^9†Í“»Š×Žì‰[ǶFk—êŠ@òsŽ¿ƒYÖi5l‚ã\?Œ—ÉOÔë: -ÍJ¶]—÷­Áѕ“P³ý@޹8Î~ޝŽ7÷/cìæ«É'© =ŸŒÇ?£ÛÀÒ:ú/=íd‰*ÏZRÇS×úï]ì;8vFŸÆìÎÇÇ;v쀗ËctmjŒ¹YÄ«ëCÆv1&À4™@HšLxæÝøbàˆ©ÈiWQ“§Ã¶3&GGGŒ?÷‚3F@5eaGÇÓíË×ÄۖÀãË;Ð}ó‡^ÀØÜ2UŸ‹w®aõÐfbŒj­ûà§Ûgx{žBW_eë¶AÝÎ#°Œom|~%ùc·\w»ß=ºŽÕC›ÆòTçÆ‘8°t4L-¬à÷ëGŽv©:™ÈÎÃB‚0¶Ž\ŒÓÂeaøéöEŒÎž»ÀoiO®ýdÃâîpûøZtÑ|àLÔï6:¹Ýá얅8œq>,räFÑÊõðãېÇßÀÄMzOFáJµq|Ý \ØùÒr3ãÕísX?æO1¯ ۣیMŠ9ªò¬%ˆš5|}ç<>œžvÑ»a§Õ掌L&"þ³ósti`…üyø8œš=Wl`L Cð ÆŠœ×‚þC'"[žJj~<&À¢ŽmÛÃÇOœp{ÇBÇét–o>¶2u:?ÿøêŒ¹Žò£žœænG™:­St®t·<ìä%ñGA¹â+Òñï_ß¿áÚÁõxzõZö¶:?œ…•ƒÅ)ä¥#äŽ1`hb­]ŠNF©³;'wâÉåÿá—û7žŒï0¶EÊbØêSb£$-˕ýëpdEÔøãþ†CëÞ*›àãéŽãk§ÁËý›Ø ðóòˆ³-Í«ÍðšÚ¢‡ú$øéÊ]H«BWCh=è¥Æàòî™ÊÏZZ٘Úã<»zn^£]ûöèY?át™j#ä)ÅÜãǏáXS…9°]j?#Ü?`L€ øùËÿîŸsS#ô0&Öå™ `@»ví0qæ\ÜðÉ­ñ³Û5§?îÙ+ŒàíÇým>ä¹%1ª,ðcN˜<Œ¯ï\ÀO×O°±/…|Å*@GO?ZµûgöâÙµ“pÿøŠ–Ùa_¡ò—þk‡·ˆ“_Ív`W² r,Žyí¡£«gœÏîàÛÛ'â>|Ì£õRO7™ZÄ{?ì÷ð:Ÿ9=……unwh #“d­+ÝÉU#î{àdñË]ž4ræ/ïªðL–qôß(×ϘÝN.æè ž ûñŽQ¢j¹Œw5Ž®š«:­kµÖœ‘·XyäÌ_\€ÿÓÒÒõ.î^ ú×}æf”oÐN¥¡ˆ¥Ç×÷ÐÑՇ¥un³!f‘…†àüÎå ç€6N²ÚäCéZ-P¹Içhõéæˆ«$ô¬‘WŸì(îÐ(ZSz‚È™XdC«\*Í'œ*=ºpH¬;ý›ÕœnñÍP !óæMœ={mkfC©‚ÆéōÇeL€ 0LHà‹ËOl9p…ìr K¯aÐ2çx™ð1à)gpôGñÔYóqÅ[œÿˆOlÈÃ=³M1QmÞ©0É"<+ IDATþ.•›G7ãkŠ¢Ç¬-±Ä Õq~rûTÓŠ÷èˆõÐÕ§`•[?àæÿ¶`ÿâ±L1±°‚IKèê L–0Ëj-ê‘'wÑ9—ÄL‰ž1µ£NÜÒžµ: FÎüE…ø·Ž¶Sü)wìåöœ]Ùs.ì_uV¶¢Ù@Þ}š‹«ó hii‹ ÚüȞ'zÀÜ †âõÝ (]³9 –­†Ýó#8ÀwÝEN»„³›šÂ3Q0ñT k†·kV§Ó0Á†Ž»wž²NDû§Bl ŒæÐŠ·ž^³Ð鍐 qd=w¡’bó„NSÐ=ùòõÛ¡û¬ÍqŽ.Å_h7fª·í'êDDDÀßÛS\{P.t2ãÌŠùâôq£B¬«¶èŽmû!KvEõ˜i¥ò—®Š®Ó6(‚4ÒÚÑ}ù°•Ÿ5/÷¯˜ÕV.|çžtŽf§teƒ>›æsšñKÊ3@Á+}œ<П]{t­]$ÁŠé.äߟ}+‚Û5tȏêÅ9O|Ršë2&À˜@Êxé䂣g¡J¹šß¬ Ž,Ø3Ÿ2d¹& þüóOL˜2·‚ìÔàdZAÂmëŽ(S»zÍۑ€^œ^ŚaÍEß%«7Áó맅øªÔž#ºLûWü<¡\x(《¡ohŒ—7Ï*RčÞp y‹W÷ÇGהdzú뺷›Óš‡ç QEw¯×l…7÷.Åk7y‡Iܗ«×/UŽ£މñ÷€úâ;ÙÒœqÉ~©czŸîïÇxkwÞ¢AíršØp$ ›¶÷ U2’+1&,íÛ·ÇŽYspé—f­§#ï;çôŒšª…ÇÍi_Z!Ú'®‚®ž€û×$ŠÉýðü!lŸÑKˆªižFój~{÷ N® ¯n6ù†ˆ*©Úhc€ÄõOE9šY‰jM@柜{MtÓ&Åîyƒ¢µ[1š¡|${ÏÛ!¥<º#Öý'ú'KuiS¢h•zhÜg²ðø“7›ŸHÌOÚu7^ᅯ¯}ðŠcBlÆUTå©êúĬ÷ôÊqlž,÷ºOÝ÷Xœ6Ðõœ³MˆOÚHé:}ƒØtQ.RP»˜éê€ðÊÌbŽOâzçì~  :bíˆÑb"4é;zMϔ+òÛwš²VlüÐõˆó;–ãêD×Ó>ìoÝ$ÖmؚӊòôÓU:eahl*‚öY°¥jÊ7€’س&ÙLŽ!)Ý!œŽ‹Sr×(µÚ]?Ž¡¡AèÒ±#Ú;D?esÌtòkÖ¬AHH·ÍœùQ .L€ 0&ÀҋÀ¡Óñî£;;uC²)(*œæÄã2&tèÐÓfÎÆE ò’בr°Ýz ÚÚ:*-ï¡åcqíп¢.‰tòZÒœxòŽS‘<º$¶H0Òqj:VX‘ÄÕâ nBÀÅUŠ6/(Dú_×~ Ohxž £kÈ#êÿ}ÃGÑ$8Ð?Ÿ9C ZÂc®ÜÎÓõæv§â"o+Ù/•{§÷¡›¿Tñ–' ÆŸýñçè¥â=‹‹ºVQxŠºgNÇÐi³aÐ_GQ€rÝ8ç€*ÏÄøÅõ¹r0ÃæfϹËûžžk…»âØzónhÐ}¬âôÄä=Äf…T|‰c掙Ñ}Ö”¯/Oåã‹{ø»=Á0ŠçZªCÁÿ¶Léçžß§ hó†®Ü=µKT[vÅ«‡5›+޹Ó{þ®XžîKF ñNóx÷øºìÒFD\s§ŸiG:  \'±gíÒî•âZI³þÓРÇ8ESi­’ú;“œµK‰6Wö­AxD8ºw銶Uβ‘nBþôéÓžxñ"Æö©ì†ßSbÞÜ`L€ 0ß"àíˆÍû®AWWœ‡/„YÖ<¿Õ7fL@=Pú¹©Óg⢷­z”L+HÏs,'Œ ämŠcÖ1ïÉÇìZùX2ygoŸØ­ sn;b MÍE~qº?×QížL–Ä•òdºsþÕé)Ælº"Œ®R :å;ç‰yWi,åv~^?DÊ:ڄXpöKŒR :a0nëuE?éšž4Ãä%Šãá1 yÂÉ#®ìŠÍ‚ƒËÇ`âλÈb•Sq¥ 1žI]æ _,ëSKµ‹¯Æ¹~L-yŒåÍ Zï=󋀈TbFžÿúö –öª!®&H§$è>þüNĕ–C怮m›ÞKam&tŸ± z†F˜Ü$ŸØ ³ù*ÿ=^ùøÄ¹t'žì%9]yè³pþqéŽF\÷÷{ÖèüÁecDð<ÚT òöÞe¬ÙRümØhik¡wϞhY!áDé"ä?|øòÆwo_%­ÝR›÷Ϙ`L@eNÝqìÜ”(]M“Ÿ«Wå¹"`©N@ùiÓqÑGóóÈ+'AJ9ÅÉãjhb.<§”nÌÈ, rå/&ŽÓjºK-¥Š£ÆïÝ@P€/ò•šˆÜ…J)øKT÷T-±2¯cy!:'l¿…\K 48S›ËK‚[:ªÞeêzTjÒI|¶°Ke!ê (§Ü®@™?Ä1n*”cŒÃžqЁóøòó:–ŸQªž¬¹ò ðÉõ³E[:ipïÌ!DI,vž²ºú†ÑŠyø¯qžzp=ڏ]ŽjmúŠÏ$/ýØ-×Èœ¯2ÏÄø)N6Ñ&‚r ZßBåªÃ¶p|zqOdPÎV Ýý–îþS¶€#+' Ï·Tbzšéù˜ÞÒ^0Zøß7±Ùòéå}üÕ¯®BÓ=í}‹äi É?në ‘ yÌÉsÞfÄ"||v.F•æÝÐqÂ*…GÞ÷çw±!D'”vnYÍÜï£}œØ³öõõc,ïWGŽ¡ s«œøoëbñZyÓ")k’uÏm_ ÚÐ0h0Ú;JЄ4òÁÁÁX°`J/‚?"€°€ô`Äc2&À˜ˆ—ÀÕ»oñðùgÔn6å«Èÿ0à˜€æèر#ŠNŠ‹>vˆ€æW&|hù8|,Ÿ" WÊFÂMdqµ#o:yì)èÜ荗]p)xyð)oý•ýkE$uv&­íÉKJAєƒŽíž;wOïžSò ÆUb¶“^S]¡ä=.XÆAl Ø,.yÌ#ôÊýJùוyÐæÙ©|,îvŸøgŠÈŸNÞiº~pfó!h§ì}ˆ÷On*‚&Æ3Q€‘€(í”v²õ˜œUDñ§Ÿ¥"ÅG àwc7_oÓ&ͪ¡MÑ⥺$„ËÕm#®Sˆo‡_*î€+ŸÐ ôrŽéó¿USÄÆJ×iÿ¢b㎊ûøÔyÞ)XT^Ý>õcÚ ¯:ÝG_9ž±øˆøPš>J ($€u¹þE¬?±~V¬t”NŽÖŒxQv€J;Á¡u/qå‚‡ÊŸGÑ®#Pj7e¯=A46Å1‚R ÀÆœ'Æ2™‚ ÒuÚØ ¬Žù¡œæA÷ø«4ë*ŒëTþ×^lŠÄuÿ]€6b–ôš†ùìÅsšÔgžcòhß=µzú†Š˜“v߇uŸÂjÿ/Í_.äõ0rÔhÔ+lž Íi*䝜œ°zõjŒÐyŒ?ª=L6 0&À2/_~àØùÇÈ_ª1Z·ë™yAð̙@ йsgL˜07 "4<ãyå¥!¡K§ ⠀§Œ5ÛDvۂ"/žó“[xrå˜Ç)ŒX•ú°¯P+VŸõž P·b@!âÈ#KGò«µî­oR'æ]~òŸf±Ê•àÓW;²“ŒêäœþðìŽâTm ŒßvSØA‚Èç‡+ô ãÍNÇ—É ¯X…XAÚö/!rÐSŸuDõ¶}…WY*ªòTŸ¯ÐDéJ èƒgÃÀÈ$Ϊ)Ÿî¶›g³VéŽDBã)_Ï  ÊùNŽñ#ŠŽ® …¢ZÃ(W®\&§ÁÓgšK K—.7nî„BPXÆò‰­yÁwÌî+·ºÔŽŽÓ·µ$ZDøÄú€ÏiDŠäW¥MJÖ!Ñîíá#Ó, Ä€ŽIs26³ˆ7M]jñLÈNb --Å1ù€ÎI¹> fÇÆæò šP’ò¬Iڍ^ŠêöׄéÖä➕…†bÊŽéšnýäLÌI€™?vì}óÄéߐ³PmŽmۖÉ0& azôè!C†àµ^ x²×°åcs™€Ê(ˆáĆòŽ}‹Î»Æ}:jT¯ŒzÅ}ØŸöϏȘ`)LàWøäkƒÊ PºtécL µôîÝ}úôÁW³rpóc!ŸZœ¹_&Þ|ŒpfÓ|”oØ!É©ÓÛö°`üGGëͳbÒØ‘š”^BþÚµk8uêæOhˆ_ӛ Ï˜`Là· |÷ôőK_`ž«(/5&À4ƒ@ߟ}ѳgOžZT€‹O˜fÍV2&©„…†àì–E0³ÌŽIcG bîtòÈSº¹zuª£V‘ŸìÏT O– 0&± œ¿þ_üó¢Jµú(Y²dƞ,ώ d$ä)rýl•ðś…Œ&/«ó“›øòú1¬ló#_ñŠ0µÌ®ÉÓIUÛ)Ÿúšá--·:M’§5㢟Âea8µa.²Xå€1ÃQ!=„ü­[·pôèQ,œäÈÞxõ}VØ2&À˜H×ïÞ8qݹ+ÀÑÑ1=p&ÀҚݏ§Ø¿rTÁ§_,äӚJŽ·kNÜ;³7Z—y‹•GnûÒ°)X…+ֆµ]‘”Rcûúéú³ÛÉ7œçú(¢¡sQ_á8Ÿn²ZçÅ€1CQÞ&<ò³gÏF•ÊåР€/{ãÕ÷Ya˘`L ™N^z÷Ђš]·) *”Ì^ž`iE€ÒÏQêH­Â ñÁ‹…|ZqOqÞ?Ÿ›ÿÛ ÏoññÅœ8‡(Vµj;A‘ÊuSÄ8ûôrÿ #sšL]ÊÛ{—±vdKaάÿœž^.êMàØÚéȖ+&ŽJ!ÿüùsüûï¿X1§"ŒâþåRo|l`L€ 0„ 8öÀåGŸ°.ðZŽhÁž˜PXœz5®^œŠK—.E³ˆRϵoßA¹«áÝÏP5°–Mø]ß?;a~§ hÚo*J×n‰_áæü Ï‚Ëûç¢ûúÝÇ ù€¿;”Jív© #s ŒX÷ŸJõӢҍ#q`éh1Ԅ·‘«§NM î¿3ƉfÂ"GnL= ålôìJ+"""âw‹Ùöï¿ÿ†mî\hë „þJÉ®¹/&À˜`jC`ßɇðÕ)ŠVmamm­6v±!L 3žrå Μ9ƒƒÂÙÙááá°°°À† Ю];ŠÁƒ£M›6ËWo°ÏÏÈ»G×°zh3Ôë: -ÍRL‰î…?8w;g÷ïµ6µ;Mõ)/í]_ß<ÆÒËÐÕ3HõñTàèÊIžŒO~7~ü¶›°)Äq]TᖞuNþ;æV¹0uÌ0”Í•†BžvBǍ‡Õ ‡Ã8ˆ#Õ§çCÀc3&À˜@êxüò ;G PéúšY³fêÆœ3&WWWÜ¿·o߯… ÄÏæææðòò‚••<==acc#<ïýõW4bC‡EóæÍ¡U°6^{°ÏÓ˛gñïžöšÞ¶ڍYkJO¯ÇæÉ]D0Œ¹'Þ§ú”7Œwċ§1yÏäÈkŸêã©2Àú1âÕís¢ê¬£¯‘%»*ÍžN: `wÙm bÜà^(“–B~÷îÝøõëµ±EDð÷tDÀC3&À˜H]A!Ø~øt,Ë¡wßAÐÓKxçóśÎÈYž!ZŽú3 Fä!˜€æ055y×IŒ“ˆWËDÂ^[[ÆÆÆ z–––"քŠ/Ž“ õÛ°ç8ä)RV!âœ=\°rpc!²©”­ÛߜžÁãË;yŸÇœàã醭‹ŠŠÁ+aa×*BÄKeþ™ÏÂs„-S{ˆûùR!È®ÙíJ‰6ä'¯<õ'paçrhëèaîÔqi#ä}}}1dȬÝÆpQBl!`L€ 0"pû‘3^}ðBùZœQ®B¥ꕻaL@"@΢9sæþ¬Y³^÷E‹aÛ¶m¢Ý£'Ï~|eìØ±ppp€u…fžÿ…|FxºœŸÜb8¡B¢{ðŠc ïTÈ£.E³¯ÙnªµíKë`ù!qDŸ<îK{ÕÍ)8EŸŸØÈ$ʳå²Gä•7†®>‰BåjàøÚéž°ëoюŒîtªÀýÓ[ä-^‡ÿ/ޏëTBFx2â.í^)²o,˜9%r€Gþĉxóâ>F9ÚfDž<'&À˜`ñpÿáƒcçžÀ*O9üٕ.ò£ÂRŠÀÿý'îÁüø=zô^x©Ðýúž={‚œIt?žŒó •~ýú¡L™2šÐ²?î~ N)¹Ÿt$ðíÝ3,éQMX@ÞgCs§›ŽÖzy×oPxͧxŠà_LoYXÔï9g›ð‚SñþክŠ(f2i×=XÛÉ_“èžÖ¢ðj·Ÿ@¿—ŠÓëðýéòõåתvÌêƒÿP|ßqö˜'ÈSNBýÑÅâmN»¢˜žë®ðÖÓÑx© ¿í^ß9'r÷ŸŽê‰ñõrŠ*}ìF©šÍÅÏt—~A—ÊÂÃO¥aÏñhÚoj:®­*+û×!$È‹gOEñŽò3gÎDœJÙQ­„zäLT×cL€ 0&öŸž‡_þ€c¿ù°Ìš-%ºä>˜@Š%@iä(<®£ãðGEΜr±B…ŽÒW«VM€œ9r$(G|beüøñ"H^Þ*-që ùÄxiÂçÊQéçžt†©…U4³ýŒ…‡›±ã„•006ÃöœP­M_Ž»\Ô%¡Ÿ{îÜ;³WѶt­è=—x- ŘZòÓ'œùãjºwÁPÜ>±]'áO›Rё·]¹PÊ<ºOAú^Ü<í~þÒUÑqâjXç+ ‚÷wÿzŠŠ£6\DŸâA÷ûçwª€ Û£F»¢Nö<…0e¯<:}Dx8þ·zŠ"<œGžü©ûCK[[–6SÛHPþޞX6o&Š¥¶ÿþý;&O‹§×Š''SƒçÉ3&À˜@æ$pç±3^ŒqA…­PÎAîåá˜@Ò Ð]öM›6‰Tr6l@ƒ ¢u€5jˆhø+VĚ5kTd„ ¢~~‡Vžñ‰…ŒJÐÔŒ’,4cjËÅûžm7»P©Xï[4·ŽmEýîcDnî=ó‹àq=fmFhpNoš§ð¢×l?Wü#ú ow-Gù¥°£M:ß{þNXÙˆ5®££öTºN߀‹»Vˆ£ð$êi"ÒÓyò”ã€h IDAT®™UÔ[|Á]|{ÿ’è?G{ØW¬¥H“Gû¶Në!êPz=J³G…‚à®a)úî»h¯ò¶EÊbÌŠ+bN»ç TûñÏ9[;M㗎â«ù²fzóèyýõý+þ^4E³Ë#ÆWŽ"”Cˆ&í’~|uÃ;É^.L€ 0&À27o?ÿ¹lò¢e¹™mú<_&ðÛèýŸ}ûD”ûI“&aòäÉqöÙºuk‘žŽ„<©WµHBŸ`µVžö‘…ŒªÜÔ­ž§;Îlš/<éÉýðŠ ÂûÝoñ~”š&¿/OŸy¹}GÕéþ8•AÇ奌òÊó"Ïù ¿ÿ»•pnûRœ\?[|\­u48¯ï\ž|©PðºÂk#·}IØ*%ÎIô©Î¬ÿœAžL†…]+Gó¶/üïtõô0¶NÑUbùæž?$Æ%»F¬?¯øÔvõÐfx÷èÆlŸŠeœkŠþHØS‘âuŸ¹å޹í)_ÅFŽb“‹zž{zŸrÂêe‹P$µ…ü¬SQ§Œª—ϧÞTØ:&À˜`©H`×ÑÛðö DŸa³adQ0G⮙@Æ!ðèÑ#tîÜoÞŒAÛ¶mqðàÁx'GbÿÙ³g"çü7Dª:UËĉQŸ|y©Ñ—?©ÚŒë©ø"È5Ïj m]]q/\9j|«!sQ§óp1“g×NŠ`wÒç”:®õ°ùȑ×^1ÓÓçáì–Eâµt—þÕíó8žlŽ"ÊŒ2:ÖÞ€Ïdì[<u: GãÞÅÇt€ïÂapzpEŒ^tÞF&Ø0ÞQD˜'/ýÈõçÅ÷˜…î퇅ãÑùCbƒ"WÁѪHû'l¿…K{Váîé݊Ïé=å“rÙÓ4&õ9vóU5[Q6'&‡çâË›Çøgå2¶JEŒ†êŠg7‡®ß¹àG‘ 0&À2/«wÞâ­³;êÔo ûJŽ™Ϝ š@ ((mÚŽÁÙ³gÅ=øC‡‰ãôñ•iÓŠáÔ©Sxúô©hS·n]F‰ª" ùb5Ûà¢3 ù$ÁS£Êäi_;²•"ˆ[BŠ•«Û5ÚõGé• o÷öp…‰…ô â삎ºùûD»O휟ށô>œž'~–Œßt§Ÿ„C#hëêEóœÓéít·Þ*w~1֏o°€g5ÅfBœ®£Ä±{ºÿåõ#±Ù ¥¥ûû†OŒS${('=ññÙ‘®Î,›µžG¯£=Ú9õíïýæÙ¬Õh5ٔž<œ| ï_džµ«RWÈ_8w/lDŽux%˜`L€ djΟ=páÆ+.˜u:Ì •©yðä™@|F…µk×"{öìXœz5èž|Beéҥ؞q#~üøU«V¡S§NI†KÇõ˖-‹’uÚâü;òIšf ‚ü}…0 ôCpPBý¡odó¬"Œ‘Yhk뀺Õ”ŒŽÑ›e•—WµPß6œ§HyW¡t’ R“€?ëªÚÀõԓB€¯ÍÖÁ>[*zä—/œûhV7*5‚z"QO«‚ezøèm hkGÿƒ/8$ÞÞ^ðþ鎜(YÐ:ZLP=W’­bL€ !!aøwÏUdµ0A—>ã¡euT“ù0&lߟãÆ)ãF¹s'ñÏ?ÿ`ÞŒy ÃìÙ³Aiä’S$!_ŠîŸ8똜.ž HQäI÷ð*Þ?¹…Ÿ®ŸDþ÷y !™?`S G˜OQښÓÙÛû—AñvlوB©)ävoŒiCë#W Í¡£F–„â¥gAèèêC;2„ŽŽŽ8’???Œ|ùwnßB‹ºEÑŒº5Ž"BÕhñ›rõî[Œ˜±Ç6Cž\òèœ\˜`À±óñÕÕ Û"kayna.L ³xÿþœžÿNÇâé8ýáÃò|ى•-[¶€ÒƑà™?>ú÷ïŸX“x?§ày¥K—)¿N¿e!ŸlÜ 0T%ðáé-ÜüßVìÙµ³Š’Gþåó؞n9–NiŸª“Éȝ†ÂÉDzù"‘€722‰yò"ꊗ._ŸŒo_¿`Xï†(œÝˆS{,k·_°»qxý`ŽjXNííe™`)AàþӏxøìjT)ŒuÆ:Æ)Ñ-÷Á4– wÊpTŠL9rùóËï 'VöìÙ#ÿ±cÇD:º®]»&Ö$ÁÏé@©R¥P£e7œ|ÃBþ·`rc&ÀRÀ×׏pqÏ*Ø·RKÈïûwŒ~|CÿÎò”\’N€„ü;ßÂÐÑ3❄<‰wÉ#O=Êd2Œ~ý÷ïßG£F áPÊúÏ5÷̯ÙvÃgîÁö¿ú KëªI‡Ã-%& ǔұýÐMØç·Æüñ¢z¥B‰¶ã L€ €on^8vþ Š̅:ͺA˜¯ž¥mîY L™2EÜ'ÝqOŠ?~ü8þüóOÑvÿþýhÔšÑoOU:Z_¹áŸ8öŠ…üoå˜HnÞàôÆ98røò[Š‚G>"ÈsŠ FíªEPœßLî*’ïW!aZâhœ$äIÌS¡ï$ð]]]ñðáCüñÇšPŸ,t^Ã$ô5ÕHîÐ ¶óõ‘—ÝxÃË;V–ŠhP£D¬{ü u²zÛEŒ˜¹›÷DÏöÕRÅÎÌÞéÆœ×0`Òöh–M퀑}dv4 ΟR„¹žÿÂèŸ ¡ÃÙ6øYIa²ðp¬Þz9²™£SûÆÐ¶i›Â#pwL@œ ×}ذa"0ݐ!C°lÙ²$|éÒ%Ô¯_öööƒ_¬X±$µ¯2ѯ\¹2*Õoƒ£/R€Oî„ 0&Ò(^¡¿ÆãÄñc°K!ïÿœ{õÄ_Óanwچ”žTFìOòÒÑzIÀ“ 'aOÇë©Ðñú/^ páÂ"*"ÂaþúÁ¯ÅÏ¿[|ü‚pïÉÜzø篜ĵ{N±ºÐ¥ÖÎUýXÛò ÿaÜüسª?:4¯ô»&Šiû€Àé§Ù˜„ecLÜ4Ic6éñ7þ»úÕ*_‹ÿ9#ÚÏÕӆ·HR_)]y÷Ñ;8qñ)vüÕG­ÄòƒgŸP¹¥<žÒ“33Q²HìÜ­ª²HÚjÔS×uI¹ŠgŸÇÎ=ƧožèãXŠÅqôúô\ ;Íxxx yóæÂñРAWœI)˗/yòpîÜ9Eü €ô_Ý1cÆ FšP§¿`!ŸL¹&ÀRž€¯—öÌ„“§NÁÎ"áCµ"$õ˜;^Ü=Š-›þÁâIí’Њ«Æ$$3ù°phy©žŽ4>>>prr‚¹¹¹Ø¡Šïúz:0ǘ†L֝yòޝÞv箜čûïb-NŒÙQÈ.²g5"¿@Ÿì8¹e„Ê‹ž`Í)L]zÇ6 KrVƒððˆ$yÿU6*žŠž^~Øvð&nÈk“öÁ¥+:1'§®ë’ìEPӆw9ãþ³Oh^·4òWh%|4NM§Áf1• téÒ{÷îE‘"E°hÑ"Žh‘ôÍä3f`Μ9"(ÞÁƒU[Պ”òŽrÏWšÕž³W•×cL m úaëÔî8uêtêxäm_÷ÏÏ1°k펝Y„Œ³Q쎌ïÒñzš&ý!.œ „ôôô`ia†¥ÍQ"ox’=ócçíÇ_Ï)ˆ’po׎šÔ.…ªå @_/êOº‹Mi•’⥞œâ8fý} vAí?ŠªŒr'.&R;ه Š6oœÝP¥å|ù“ŸŠK+7›hš™…lH ,}Ñß%”"nÀ€IîøñãÇ"%݃Э[7¬X±"É}šÒ`øðáhÜž1Ê×h„}ÏXȫŒë0&öda¡Ø0®N?Ž‚9>ùž,üâ™Q¶1êW/žö³Ë@#’ÿPLxäIž“§chôsL!O"žþcçíí-„„„ 88&ƆѵŠÛÑB«~Ì~ç‘[è1z³èëÌö‘b-éHJ•É‹cѺӞyd2ª”U-B--µ£Ÿ×/莟k€”I±ú¹÷ô#ª¶š'Þ§£éžñÀÉB€RIê&Dr %áeRt°hJ'Âd2|þæ)^̗{Wˆ“ ‰RCû¢ž²§×^|FÅæsDlƒ^~¢N§VU°óïŸÉ11Émè@ƒ.ËpùöÁÕÎÖ ¿þ€¯_È¯œãïŸi&l•?xê>‡¬WŒúþßdŸüPeÝ$!Ÿ–›"ŠEYùəÂù­qûS›êº.I~À4 Ÿ06bmЀë<Ž\¯kÆ&&À… D>÷¯_¿¢OŸ>X·n]Ò:ˆQ»lÙ²šY³&V®\ù[ý$ÔxèСâ€@¹ê °ç‰ªÃ3&À~—Àú1âЁý(f›°#(YB~hŸ×§&òØXþ®™º= ùÅB^WWB¢^÷þþþxûö­È)ïë뫊&}ÍJvèÔÐ:Zª§¥ó F–Cafbˆ_ÏW¥ø:Ðýxº'ŸÔ{Èt?ýßÝW°÷Ø]ä²¶À‘‡€žmÔaHhìkNÆW7/ŽlPÖ ‚®Ž6H ¯7 Ο=0€{]¬œÕ)ÅÇßzàyˆ¯.?ñôõ×xû/_2/.îmíXLd²pè’{>b yz¯fûEB8OÖ [Üé°è(yRNU$eâ·9cÉú3pûî ú9ŸBWNn š[ZŠQ€ödÅɋä<÷I]·»? a×åi³€6š(ýãů0yX3GA]×%-ŸŽkÓŸkâß꟣Wºfi=<ÇR…@PPˆ õêUÔ©S§OŸ†ÁïŸ8™={6ŠOŸž*6K«pêâÓXc‘`wlQJæCÉ¢¹E̅øJbÕÚ.@¿N5ñÏün*›ÿÕÕ þÁȓ+kŒ/7ŒÇÆœWñèùgQ§\ɌֳŠÈmœä¬ ñ¡£ùtBÄÐ zÌzîhƒèw‚ª BÃ+žœò/Þº`Èĕ02‹Ÿ.>56?“èÛ·/¶mÛ;;;lÞŒYŽÓ€BÇþ;uê„2Ujbû#òšŽvl+Èl¶Mï‰UKæ¢Z¹„³v$YÈߺu ÿ\‚iÒa;³-€*ó•„ŒŸ¡™"²«òñvIÜ‚¢Áº»» <‰wcccXXXÀÔÔ²?¶xcœU†u”…|Ó?ÐÓÕyÃéxòÞŸ|ç×ïÞȗ;–Lnº{=mÙQ4¬QÁ>f¡?ðI€IߎC×ãÀÉûp{°<šx[±ù4Ø6:` š²UÊBžŒ“Ù³™ a³PŒ»ÇЊûîttš„& NåBÁð¬ÊŒ@­ªEð¿CÅGÍz­À™ËÏáûrBÜÏ]u3–ÿO|Nc’à”‚ÌœŸ4W˜‹<™O^~Ôwÿ‰ÛDÐ6©M|O—h³nÇeawóze¬$a~ëèdT.w<e&Ê}Çe/ñéÝ¡ºttWwû¡›Õ·¡àM‘ÔÛX#ֆ Õõðô d?ܓ6“Œ}Ѷÿšh›ÒÚmYÚ+Á vóVŸÄôeGÅ&Ðè~ ãŪ*ÏÄÖ%ŸÏiƒ©L£™b~$ŠÕ* ‹’Ã`›ÓŸn-Í&þŸœ³‹*]ãø†nET [[×îX;¯èÚíÚ®ººº¶®ÝÝÝݺêØ‰Ý "Ý}Ÿ÷Î8 Ê 3ðŸÏõ2œøâw,ÿï{cƍÞm©¯€ž›û ”š;A,nZ3HŒËcgî!'ÔÿÑ C…çU …#Մ‹äÉpëÁ[åŽÖÎîõdu;Ï ZÔÆßê"¯µg’WÎÓZ„c§Êª–ÔsQýO˜ Põç÷ɹ©ßŽÜg”Q÷§î aëA(á\-£N“畁 ž¹¹ áûüùsPVzڍ×eëÖ­úö틒e+bÍ Eþ6&À˜€6Ø<¹7fO†š•\Â[c!?kÚ$”Ë„ZUÔÏD®€ŽaL$äßE”B ”±ñ’xWÅÍÓ?)]C1i$æIÔGEÁVv †2õ³°ª yÕŸhW·Eý2šWœží¹rX‰Ó’0ÿ­}5¬šá߅«OP»ãœxâšf»YB Dœ\)„!Åë֋s§j$6ÈuŒn'ERŽÓ[†+ß©NƒWaÇ¡ëbÇ4<"ù«ŒVö7ë6Ö³Ÿhóîãw5m·Øù¥±Òn«ê.ç÷ž1ýM;ò‰-Jüèœ þ¿Ž›%Êõ‘‹ö‘õC„;º”\Žî•JÁI;þ kº‡†Ebïñ›¢,ÜÿZUÝI™ÄOm†ÚUw¡QeB‚›Üë«·™!Ä_¥2`cm§/=ây t­-vêi÷}ïŠþâ¹R%ª(@¶rFWto[ $تŽb7Ø}©p§Šâ:g 1Iï=¯Še àփ7";Ù³ ÓÄB@b6Í) ÿ{§(G‰™&<“óóJ¢”ÞCŠ—òø„ [é!bÜ4þäŒÛÒX’zn¯ß{£`õ1  ‡× A»ËãyqÐñÓ[‡ ïŽ[.ˆf靀Å0y@PÈ ‰[ŹKû¢‚³ƒòç!a2Fò 9pò6L Ñ}ä: íQsÇ·‹‡.©çBÙÖkŒï7ý«Ö–vHé+¹¶Iߓ‹=‰ùˆ°äˆœ‘l!OÍkT($ÜÂ)Þ;1£ìî$ˆVÏtE÷vñw—¹Î µh}éß]Äí.ÍŠàÙ«ÏÊDz¿\'vÕi—pÏòþÊlá$Hé^R<®t-íP—*bóbЬî$JHœš¹~;՟(Æ¿»F‹,éI Vڕ%{ó߬ïÎ9a;{ŽÝD»þ˕‡]œò#B@&- š&¢S§ô˜ŽH’˜›¿Ô™*i×^ڙœuôO”.ŠH†A±ø$ÆHˆ—*b‡‡Ü@÷ÒÎøï=ë!·Ëp!þ²<Å]Ô<§xv²ÑÓwcÎÊ")݅£•^R¬9]Óù×JØ8¯G¢žé^jcÜÀ&˜<ü×D¯Q—gRÏó{çicÕ¶…§Á‰ÍÃàí„Ó—+ëÈS¥Z è÷Ç&Þm©¿€ž›‡—?ì*Œ¢8·m¥ÄˆÞ [2ªêpüü}±žBã|tæo‘ÿAÕhQ‹rhŒŽ(B 8ª  çO?SEjSzšžOê¹PX …„ÐB--®IŠú¬Þ^™ ;ÛŽ)§—Üg¯-÷ÍYqÅÊ7A³ÖÝŽeH<&ðCC† ÁòåËakk‹¥K—¢I“&†X‡@µê Ŋë,ä3̃å‰0 F 2<kÿè‚k§öÃÂ<þ߄ §ª‘'ï^Ý;`Íߍ OÁReŒ¿ÚÓ!!ÿ!²4"£ꥬõô™LUÀKÇ$OçHÄÓÎ|xšÿO yU÷÷ï ^3Ƕ É(Ã|¿q›Å·ª»ÏL1µÒŽŒä†ŒljôîômŒœj¿R :НŠ]k©<[b¢˜\ÅóW%Ä©ºBžú’D "Úé,S"é,êRâ0»”ØMªGNíÑÂÊ® ø÷/>AÈYîw1%ϛó~˜pŽ®iÝw)öŸž­Ü5§c›ö^Á ?·âÞÉ¿DxU&RÌyR;ÂԹГà€1oøç7eɺ{'þnÝß3É£àõ3EÒ5²ûO>À¹á€x·Ü8ŽÝ(\ÕÕ}·¥n’znäޞ·òHåšè];Œn°HHײ÷“á?g‰ßïlL@ÛPiÛºuëŠzðmÚŽÁΝ;µmˆ)6Š÷ÿý÷ßQºLY,Ÿ˜bírCL€ 0”$ðÄí\؏÷®M²Y„ü™3gpëÒ~ w-dÃ|AÒHÈŒr yú#Oçäb/ՓÿQ+t$ä³ÇºÁêgaU‘W'[:Å{Öj?;Ѻç”užÄ™7M%Ö(v]ŠÍ–vc¥]lVj•®ÛNEóÄsoß}ôÚXžªcÅô®ñÇÑõ9l,qÙí¹rGœŽÙ6–技êe7{¯2>9±û$×pÕ$`çwŽBu—BßíFŠ3Š ÔÉîM‰Ÿ¹ã€ IDATiǝbŠgŒm#&È՚vpŸý[Äý'dBmKbžÑÎnb&%ö“’»InÚÒµŽ3^§jQášïT,Ò­›Ä.-$4Z\¡gB ò*ÿ:M$î#QI.öªÙÿ©<¹€Ó å woIRbCÚå—<-’â©îó€ëȓ¡ÛpÅ/Ÿ±£KËÊ£AªŠ@Ç¥E éÙhúnKãI깝ŸøH,ȐÑâÅ×ÚÊ©xù¶Ü0ñ=ymP\:ýl¯ª.ŽøèáïgT:ýZQTèúûq_Âdtªœ$Š——fˆÅ ɒz.…òç5襞|Õ6ë×(c†jò82ýµŽvêV( ++EŸ6& -ZŽhC‡¡xñâ8~ü8ìíÕ/«-sÐdT>ÏÕÕU”Í[ð yMØñµL€ €Ëû× 2Ðû–MN²S„üæÍ›ð]L²aŸ i’§yŠ}'1O™èIÈK»í’KýZ‹ „Môu„<µ[žæ8‘Iýó­yȖõûõÆ¥ŸƒCÂ1eáal;pMžwnYIˆmrK§?þ§,<„Ó[G—mÉå^ãÔ•° 0ŒWHâSÚ¡ŠÝð¿¹K«–æ¢CŠËoÕ°\’%×~ďDæº]—E"·+7_AE;ÖŽóLÙÞild’+;‰âK{Ç|³ M×ÐØ‰ ‰\jçG™è¥1IõÆŽQ5ù]B&t-%7+V{ŒxÄ*1£ç\¶ñd.`«,FåØþ¹5Ñ*”Ønñ”΢ÜYŸ±›Ä Ì©#[¢ßÿjÅËo@!ôLè>ZtŒæž§âÈxátNÕ5[]ž‘ÑÈoÿUŒ~ïYzû!GYEH%E€w)¡©zVP>©”¢&ﶺύÞwJG 4§¶ Wr“î—’G 1€,ÿ”/B2zïÚ5uc”ÊJ1ìô<Oïª|O(9böìõ£ß% Ï={í‰=çœáÚk8ììì4¹•¯e©F`ìØ±X°`(a;oÞ<ŽoŸøBpª :t(jÕªZÀX|%ÑqaŒé4î– 0&(‹Ç¡˜S9,?¹xbk$äçΝ §<¡šSÁ–ѧòŸ¢Ëˆy2ÕØxŠ}W×32,Ù¢¯i$ä©?°ä>îÇ&f¿ Š]?túJ±qãªFîìÿÝxŽëw_ á,ÕZ§dlsÆ)²lSœ/•KS!tœÄ ;*—§N†úäLŒÄ^bm¿xã…rM&+Å隟 …àˆˆÆÍoD̳TÂïîñIžvç¥ÚÂGŠÙ'FÂŒ_—š"㌪%Ƅâñ­,MŸá€z%À Šç±@s€g@c€…ú,¹OS2Br§—xÓ³€ìü‰µsýÎ+8Ïoכ®UÝ=Šözuš¯öž&<£_­JòQRõ*UH‰ýjVþ~U *ÓFBWo‰€:M깑׉mU©MZì w†Äºôžk¿`"’0étßÑs÷`dh€:ß©p ]G?+‰-Ð%õ\TçLÕì*($ª“ï!)^™í<%\sð-Úvî‡"EŠd¶éó|µŒÀž={лwo?hР̚¥(Á™Y쯿þ jŽ3¿üz£ùˆØ˜`ÚB 2< ÛŠõGÇŸ#1¢µ"õL#!O«žëeGñ#™Xu·Řâ}d˜šYˆDwªŠÎNŒt}dD(rÄ^‡!t3y í†~ñ Šç¬¿ôž†„z§A+E–óČvQgýÑVYZN“1’»uV+³T[ Hj,Ž(“¢1ÐŽø '—‰<‰YjòüÑ|¿·X“£ÄΧ÷sKΘ“z.R›’+>-ÄЛfBÃ"0gÓ#4mÕåʕÓìfŸš €OOO4mÚ7nÜ@͚5qîܹjY·šY±bˆÅŸþ‰Õ7‚£[àÑ2&á xŒrÇéÍÿ`ÐøÙèZ5ép'„|Ÿ>}0m@)dµÔ,9ÃSOæ#bŒð9ÒzÆÐ“uÕ€¹˜ØÈb#a-{Yž&·òµÉ$@‹,ç¯<ÁE·gxýþ ,ÍM„k9Å6S¹<¹\–Ì–3çmÌS{Ÿ»äq°o员MsÓÖÜEÕÚ­„K/Hk”©Ø+V ;vì@‰%ÒzZÓ߉'°{÷n¬Zµ ëoÃ?Œ…ŒÖ<`‚ÀÍS»ðöá ŒœòšIZo«-䃂‚0dÐ@¬š¿†8sgL€ 0ŒG@Jˆ™T<~ƛyÊÎhÙîç°upAëÖ­S¶an ü€ÀŽiÓ0}út‘w‡>÷꥚d‘™íÑ£G˜={6fΜ‰SÍñ%$:3ãà¹3& …ö΍|â}ɒø¥8S»mnßÇÇ#GŽ|^›”‚G ym~^<6&Ùxœ{sÛ¢ZëÞhT­ j:$–ªÊEíù«W¯âÔÑÝ÷Û÷“He6à<_&À˜@F%P³Ý,>¢Z=!£Î55çuÂ-ßDaĈ©Ù ·É ¢qãÆžtéêÔ©ƒcǎÁÀÀ “SùvúcƌAþüù‘œš+ÞD1&À˜€Öžuz7žÝüm†ÍA¥üš’Ï0ɱ©-ä9‚—î×0 uÞ$å ˜`L@w Œ~ÕLj xß]€,–Šº;™tùµ§±8~ù=(c6H =zôÀ† ààà€õë×£jÕª©ÑM†hsÿþýb‘£vï©ðOz·+CLš'Á˜€Ö ÄÁÅàX¶:~iÜM‹™ ‡™<Éq«-ä7mÚYØ[tª—3ÉFù&À˜Ð]^þ°«0ï÷`‘îND Fþø£6z„)SŠ|SD †ÇCÐa .ÄĉEéZÊÄ>lØ0žMÚ ýɓ'Xºt)òTúùʧM§Ü `L Oo\Àý£N‡þè^·òfQ/ ºÚB~ñâÅÈo†Æ•¯'ÍOˆ 0&À2¿æ„cþèük¥Œ3©t˜Éko3¬Ú}ãǏ‡™™Y:Œ€»Ìh®]»†®]»‚ruéÒE쳩O€=ÞÉQŠÍpõoâ+™`©D 2<‡—O‚u®|˜>n8Šd_’üGݪ-ä§NŠ_J›¡JIóTš7˘`L cð ΂›n`ÔšQ°¶¶ÎX“ãÙ€)ÐÐP4oÞgΜAåʕqèÐ!~§’ñΟ?e[ÀŸò¯È[”8'!ߘ@ p¿v¯žÂÀŸœÐŠ–f¥~ÕòcǎE§†v(‘/éTø)87nŠ 0&À˜€ÎðÌ†é«®·g[[[<} 4+V¬€ V¯^-Û±%-ˆt:ÑÆšÛu8ôô9)`òHò]L€ ü,¯O8œùT)W3ÆôÓž9µ…üàÁƒ1²kØÙpr)ó L€ 0&) „Ës`ÂÂ1dÈäɓ'S2àI'ŸU; Dv$>©tÅijý<¥»Ïb߁#(à\Å+7øù¹&À˜@2\Þ·QŸŸaþ”ÑțWó„òj ùž={àŸáå`n’t*üd̃oaL€ 0&ñåˆÙg0pà@(P ã͏g”*ÜÝÝѶm[<|ø... žx¶”#põm–._Žo_¢|ƒÈ]°DÊ5Î-1&ÀÔ ðôÆyŒ¿y C\EíÚµÕžãÛKÔòQQQøí7W¬Ÿ\+YðML€ 0&À2%c[ü1ÿ’HJV²dÉL‰€'­>ÈÈHŽnÝZÄ¿—)SûöíCŸ|ùÔo€¯T›À«·0uÆ,„ÇÈQ¿Ó@ĘÛÂ/,FíûùB&À˜@r |xv׎lF“êe0jPïä6µ„Œ¯¯/ƌŠeãª'»#Ÿ‘ 0&À˜@f# 3ΉIËn iÓŠbg• |ÀèÑ£A%嬬¬0þ|tèЁa¥2{÷îaãÆ°°°@Ÿ>}ð*Â×߇§r¯Ü<`™™Àç·ÏpaÇR8ä³Ã²¿GÂÜ<ù‰äÕòïޜÜ1od•Ì̝çΘ`L@#2£˜±þ!ªU«†êÕy1\#x™äâ]»vòÑŠ %µ›={v&™¹vLÓÍÍ [·nå!{õê…w°ÅÍÚ18`Š€Ç«Çøw×2˜YeÃÌ ÃQÆ1×OÍO-!O±ZkWÌŌ!ª3Ÿ™ 0&À˜@f"@B~pvvFݺu3ÓÔy®Ixùò%Úµk‡[·n¡Q£FØœ{7LLL˜[:ž{÷®š #væ³ÇíO,æÓáQp—L Ãxuï*܎o‡ev[tîÞ]ªhžÜ.!µ„üíÛ·±oÛRLêÏB>ß]<1&À˜Hq2£ìXŽë ¹dXŠÓÕÍI,’Û<íÄ/^;vìàü Zð(ß¿M›6áíÛ·šW¯̋×Åc™ŒŒ‡À˜€. ðÅýá­ûmØvF¹úmѹŒ r[êýôŽÔòÿý÷ÎY‡?z±ÿiâÜ`L€ dF6X±ÿrç΍-ZdžyóL%0eÊ̘1ÆÆÆ˜>}:z÷N~’#Fœ:Ž?Ž={öˆžÕÂ5Û""{©Ôéˆ[eL Cˆ‰ŽÂË{Wqãøv@ž4섂ÎU7‹>ZOï+µ„ü¹sçàv~+Ftg!Ÿ¡ß8ž`L€ €(™a6¬>òÖÖÖ"9[æ$@â°{÷îðòòqØË–-˜ tdÖoÞŒÁÞœ{ñàÁ„eGn—&ÈSÄYGFÏÃdL = „ùãû± Žü%+ D•†°°Î.†Õ¶€iŠìÆS[j ù'Nàñµܵrzr៙`L€ èCkl8áSSSŽoß^·ÆÎ£ýiäŠMnôׯ_G5°dÉ+Vì§Ûå҆À“'OD)Àã—ï 4ÖŽe«# Xç⒀ióž& ÂC‚àõî9^ÜýžÝ'‰NQž|-XçÊ }¹ Ås P6}Ø[ýŒKœDE-!øðaŒ¹»ý:WÓ š~üˆÓ.áì¹ ðöñ…ÜÀvŽÅ‘Ó¡Ìs:@f–z††º995`ˆEßøyŸ‡ÇkwxŒr‡ßçÉåȖ;? •ý¹KÀÔ" lLõPÊV!àM R>ç†ZB~ßÞ=øüäzu¬¡ÑDùb&À˜`™š€al9 ¹\ŽÎ;gj™eòóæÍÃĉAìÑ×#Fd–©gŠyRIæû÷ïƒ2Ý?{ö "Ûœ¡‰L-²ÂÐÔ2CDˍ#C ¿·8Ċ]:úý}‰U|#Ÿ‹•É S„ø@ÿ”Ÿã®’ÉUGœ¢ãt?5ׇL®èE¢Oô9þu$Çû¢r>Ž­‚–êm Të„íÆÝ(=•x/Ž`«0å'•c:÷òÇÆŠ×KX¬òÄQñ­â˜âÔ×cŠoãΩ—ڐÚßÇ*ï§ß‡Š[©-•ÏâEûŠŸãŸW=®lëÛóR{1±1ˆŽFLL4b¢£èÅטšÇÅù(qø'î‰ûž>Ó9•{¢"°„ú#$Ðr¹ô ŒÕ6rä- ûÂNbçÝÄÜJÌÓÑZ¥sŠèî{bï˜ZB~çöx{¿µãÕdûAå3&À˜@ú0°Â¶óâ•.]º€ß8žçT'pùòetíÚTVŽž5e@gËøHÈûøø€ví?þ ???#<<\|___dϞ]!V$!£ÔO Ñ"“Ϋ“>«£vU'Œ/á= ¿—î§û¶%]«z<&†$V,bcb#ŽT bcb#Æq>6î{ñY:FãHdÑBB4 (ÑNÜõˆ…‘¡BCCó‰;'Æ'ø›ž… 岇€€¥ ºA¬YÄ-€HK%’ЖΉE‹8øq”‹q‹Š%–¯k(ªKâÆ­(µ®ÊâbÁD!V‹#ÊΝƝûæë‡jÊ£ñ-”÷i=(îڈÈIo•äW-®ފlÏD¹N$]›Èªâ[]úªõEÿ_Wât9­;Q»Ò)I˜¥ùÍπòg"žâûž‘ÆÝ/ uÑœôªü,)ÞWéQ, ‰q‹I2¹žra‰Ž“W\£÷™Ÿª|¯Gçõ ׋;¯§c#˜››!‹edÏnƒ\¹í-[VdϚÆ2ëËÄn»ê×xëO©økP-!¿mÓ „Ÿ†®­«€âPži&À˜`Œ@œ§?Šÿ÷¿ÿe°ÉñtˆÀ‡ijœxñ"ʕ+‡-[¶ `Á‚:',, óçÏ¥ðH„¶lÙ³gφ‘‘$ tb<È N@,$XŒˆ¿Ððua#%¯ú2ÁLRß«.’H÷'\˜ù^»?ºNzĉõO‹ITe!1“®Wxk$n ÏIß'öUá-·€σBq<á?!’UŽKß'öUõ}V矞܊>2£©%ä·¬_‚hßÛèÒ²RfdÄsfL€ 0&<–Øv>’wä“GOëïêß¿?V¬X\¹raùòåhÚŽ©ÖYU4jÔ”ÐXÕ „… êÌ} ''§oÆ·}ûv‘€ÑÂÂûöí×/_D†ý… ƒ²µ³1&À˜€vPKÈoZ·²€;èԂëÈk÷ãäÑ1&À˜€VÐ7ǎ‹±ˆˆˆ€«««V £95kÖ`Μ9"ÉYóæÍE6zÂémސ@‰õ/^ŒˆáPô~ýú —y¯££cŒaR}Šëß¿?ZŽhaƁõÑ.ýÑ£GÓ{JÜ?`L€ $A@-!¿qíèÝAÇæ,äùbL€ 0& 6}3ìº,GHHºwï®öm|¡vðôôÏïܹsbÇzýúõ(SŠŒÖ ’êÔW¬šøbõiÁÆH6mÚ4Œ;6ÞXé}433Ç(4`ǎ8{ö¬øþÖ­[Z57­ÌaL€ hµ„ü†µK t›Wвáóp˜`L€ h1}Sì¹b€€€ôèÑC‹ÊCû‘#GŠê,Y²ˆÄpÚZ}€Ênݺ5Þ4vî܉¶mÛ~35ʰngg÷Íñ͛7Ç+“HIŽ(ù]Ϟ=‘7o^~I˜`L@‹š%äׯYÐ»èЌ…Œ=; `L€ h;=ì»n oooôîÝ[ÛGËãS!@1äƒώ²¹ïÞœ[«ù;v 7c$wr'÷ùČædccƒ ¡Nn÷ŋ‡ŸŸŸòr*›V³fMÜ»wO„Pi=6&À˜Ðê ùÕK`z훹hÏÈy$L€ 0&ÀŽ€ž1Þ4¹f÷éÓGÛGËãpãÆ ±ýøñcüòË/X»v-ìííµšÍÁƒEœ»d9räÉï$÷ù„ƒ§$}ŠŠŠ ëš|žª€§k©.zÆ áææ† àȑ# 2OlL€ 0& =ÔòëV/†qØŽoZ^{FÎ#aL€ 0& íôŒpø¶•K”xŒM{ H^‡BŸ|ù°zõj!äµÝþúë/Lš4I “„9…PŠz ˜5kVŒáÓ®œƒƒŠ-Š5jˆxúªU«bÑ¢E(Uª”HŒGåèÆŒ#>»žžàäɓ¢M6&À˜Ð.j ù%0 »¶,äµëéñh˜`L@» È qôž5^¿~j÷X3ñèHOŸ>†††â«.=«‚ ŠÝwr“¿t邃ƒQšP!ñ4¯]»† Ÿ†EZZZÂÊÊ ïÞœç*Uú~YaŠ­§Å º‡ 0&ÀŽ€ZB~íª%0Œ6yG^û!ˆ 0&ÀŽ–€ÜÇØàùóç"ޚM»Péµþýû‹Ð‡nݺaÙ²eBÌ뒝>}{öì»èäI@F™êǍ'vÔ¯\¹¢t‹§’yäqðéÓ'ØÚÚÂÝÝ]”­£zJlGV»vm :͚5Ó% xÿþ}”-[Vì<+V,e;IÇÖšŒ¹Ð“{ ؈ºéŽ#œtéÒ »óL5ïiwlãÆžzõª˜/-\ÜŒy3ý€ 0&À~Š€ZB~ՊÅÈû­–ý©Îøf&À˜`™Š€LçžçÅíÛ·1bĈL5um›,•YûóÏ?ƒ &`üøñÚ6ÄŽçŋ¢Ž=…PüzŊÑ®];Èd²ïÞGîõäf¯j<@‰%tjîkì#Žb!Ïï`L€ 0õ ÈäžðÒA”4£,âliO€bÂ)y‡‡‡(ÑF»ÒTC]—LµF &&&000еéóx™`Là;Ôò+–-FvùcüÚ  ƒdL€ 0&À4 pù]Q¯û?þÐà.Ÿ4¹šü%w[¿~œš>zôhk5j(,€þIáTRÎÍÍMԍ§„vªÖ«W/¬\¹2¹øø>&À˜Ðj ùåË#§Ÿ;ZÔs֑iñ0™`L€ h+ЁéZL¶vÐÓlT>ŽB(k;‰ÞY³fiÖ@:^MYãiÇ<án;í²?}úaaaÊsyòäÁû÷ïáíí>ˆ’rgΜç.\GGÇtœ w͘`iA@-!¿lÙbäÒwGsòiñLž&À˜È@®{”Àɓ§D¢5¶Ô!@1䃢–bÀ—,Y"ʯé‚yyy‰þ;wŠáR8•Ã333â\â‹/އŠóÿý÷(Nž\éIŒ³1&À˜@æ$ ž_º¹ Ÿ¢y]EŒ`L€ 0& ž%qôØqLš4Iœø*µ ž»»cРA"/^Œzõê©}ÿÏ^HµÙ?Žk×®‰Øô  råʰ¶¶MА rïܹ³8¯j”A¿T©RxôèQŒã'Nï §ðóTù€Â6l(âþIì÷èÑãg§À÷3&À˜€ŽPKÈ/]²vFOь…ŒŽ>f6`L€ €[^N8tøˆÈΖ2h§š’.ZŽŠŠŠ"~Œoߟ)Óž­üý÷ߢ”]Bsqq‚›<-4HvôèQ4jÔHùýŸ}ûЪU+ñ=£$ucǎ1þ”aŸ¬_¿~"QŸªuêÔ ›6m‚\.×`Ž|)`L€ d$j ù%K!ñ34­ã”‘æÎsaL€ 0&êîú”Æžœ@¢íç P"7JGqð¿ýöæÌ™ssóŸo8-ÔšQC$2Ž··;è·N;çgϞ»ñdõëׇ³³3(A]“&M`ll¬ì©qãÆ °ªõN>1ó÷÷‹$ÜÉhž<TÛIÆÐù&À˜Ðqê ùŋ×ôšÔf!¯ãϛ‡Ï˜`iLàö—Rص{f̘‘Æ=g¬îN:¥Œƒ'aL»ñRY¶ôši»ví°k×.lÞŒYžÎKóçÏ£M›6(W®œHv˜Ð¢££¡¯¯/Sü;ÅÁÿÈ|||„‹=ýccL€ 0& –_Œhò›=CcòüÆ0&À˜ЈÀ}?gìØ¹W캲iNàùóç :é$†)^|þüùhݺµæ ¥ÂŽKÞµkW‘¬Ž=** E‹§(ÅÏKbÜÒÒRìÜ¿xñ"^ü<Ýsýúu\,,ìÛ·®®®B€“‹<ÅÀ«šT6Ž’ÚàðáÃ"A¹Ø?~üX”šccL€ 0&Ôò%sz¢nÕB©1nSG DFEÃÛ7>~Áð A@P8‚CÃŽ~p×ˁPÈ!“É “ëA.žL|/>‹ãŠïCƒ`žÅ 2=9ôäzŠs€Žé+ñQùJèhxXŒML„"§6矓ΞoÞÃÖ!ï×vEqãú£»ãŽÓØhñ àód˕zbÜ4ôâÎéÉßËå2詜ӣºNœCÜœt}FÜõ2DGFÀØØPŽ«')}(ÚR,Dˆ>â%è3ÍOOþuQD\·`¡XœP]0ùº0òí¹ø×ÉŽl#&6T®)6ˆQ|ŽŽ¡1ˆŽŽû§ü *U%V\-®‰‰…§w ²Z˜ ê›ûcáñÙÖYÍÄý1Ԇžæk_ž^073RôCŠﮞ\}=éÃØÈæŠF°²0A+3d·¶@Žl00àXý—bßåY[w.Ô$ö2«Q2žqãÆ‰Rj111˜6m† ¢U8nߟ²eˊ1Q¹7òd=zô.õ†††ÊñÒB%ä£s«W¯Voذ!Nœ8!îßœ{7‡ShÕæÁ0&À2µ„<•})•Û u+;fœ™óL~H €oP8^òÇËw_ðö£>yùÃË;ŸþÁ EXx adb ##AßÐúF† ‹@”‰¥M F_¥Ï±B,)DZ b£c C#CñǝSˆITËã>K_Ç££¢D_Já@˜K¢^Zøâ «ìÖbQ@2éÍ7nɱ$šã.ˆ•Éc 3ųt3é9º6î ߟé*…¥¯âqÂTú,‰A‡qÆu¡­ŠŽb#CEßqÇÄWi,q_iÌʱ‰Oґž¯_OŠ~Bƒa"Í+î^¿t›‚bâ3‰×ž¹Ë“PŽ‘ŽÃÌÜäëØÅyÅ3V\ûu^4?eʧ7@©UÐRÿq‹&b‘C,Š(Q”‹)â³r=iE!¶iá%<"Rmú,bâŽÓgz_I€‹¹<îë×k‚Ã`kc }==qŽÞ!z¯£c¢ƒðˆ(„…E"$,!!á‡P‚B#albs+ d±¶BÖÖ°¶ÍŽœùrÃ2WN˜Êñ‹e(Lä1ü)xìŒ ›÷ˆ8pU!˜§üÍÔ(¬`âĉbþ”ÄŽâà³eËŠ•H˜Sù;Éȓ‚ -RÒ:JX·lÙ2ôíÛW\B‰îʕ+'²ØÓ3ÿóÏ?µrž<(&À˜Ðmj yr/+mç:• êölyôñFËáOÿ¢ôðÂ#O_û‹x÷Ö^ވ ƒž>,²fE¶¬°ŽÉ kXf£¯Y`fe™j; $úIÐ aO ÑÑ*ŸcÇ€sÊϱq‹ŠXÅâAÜ1‘tøªrN¹ë+ÿ*8¿ÞB˜å mùU|~՝ s<­ÐÉßXÜâ‚ä}@ç^@xH(ŒÍM•^ßx*H ÂkA± ¡ð4 …ÅWÅ?dqúžNG„FˆçϋAôøÕB9UÏ©-oºÎ烲çÉ-Œ*d²¯‹.rÕï…H–Îé Á-®Õ#®§ø*ÎKžq畋:‰ÒK™Ÿleš‡JØGœ—‚2œC5$$AøFD¬ a12„ÆÈ£gLt4œ}áçé ?O/ø}ö†ßç/øìÈˆXeÏ›<¹PÓ)7:WÈ Û¬Š)3nE«< rÆú-{0iÒ$‘‘=3ÙÖ­[•qð NIÞ€ŒíÚȁ²Ð·hÑBd–'KžÛžpÌ_ªT)qx×®]¢$¯S§²dɂ'OžhãTyLL€ 0& ãÔòeì}P«RŸnæþ‹0øGëÁ?*NžGÊñêÝ|xó žŸ„×›÷ˆŠŠ±›Öv9…˞ÏÖ¹rÄ۱͜ôxÖL u„âãÓWøôâ->¿y‡@o?8æ0CÝÒ¹Q£ba8µOŽ¹Õ4'ðŒvä·ì;³Rµ4DwxåÊŒ=ZĉÓâ%‹£ îÚlǏñðª¥ã(ûü›7oDœøïÙ¢E‹0xð`еžžž0¡/òR †òäÉ£ÍÓæ±1&À˜€ŽPKȓ;\©Ü~hÕ@±êÌŠŸDêár  ž…"4(_Þ}Âáœû ±ÛM;±¶óÁŸp±+H»îlL€ €°àŒü>AÈËçÈn,C¥2аVI)`›>ƒâ^S„Àóg¬ßŒ&LPŠŒiX ñððž[¶lB–\ËiÞÚn”™^51ÝþýûA™ç:„.]º`ÓŠMÊ)Xwrrîô­Zµb͛7Ǒ#GD²;mIܧíÌy|L€ 0&ðsÔòŽ’^Þ!5]òý\o|wšžl„2|xñ^ìº{Ÿ|'ú641FŸREDÒ·lö,ÒìpGL@ä’ðüîܧg¯-«9ê×(ºU‹ÁÒB±ÛÇŠ;^„:cÝŠœ?~àí£g"qí(S¶òÂ:wΟí‚ïgL XGø#øÞmÜ¿rþ¡šSµ8š×s†mvË4wõ3^†:c튜"aš™Y\â̟iPËîݹs'ƌƒäʕ #GŽÔz7zBøåËá1°xñb%QZ„ *?GF¥ñèsá…qïÞ=eŽKKK1WŽײ—‘‡Ã˜ÈDÔò3fÌ@¥BašQŽc6µõÝ ²YÛ¯}ÀÞì Jqe͕öE —£(á`ºK ¿q$ðì!®œº**HÔ¬T­–ƒµ¹îN*“Œü ùÍû0vìX±[QŒÂÑâĝ;w…éÓ§£OŸ>:1=àŽëN;ñd @éÒ¥aee%\é)Q펗/_=qð ,IíÚµk'\èɕž 0&À˜@zP_ÈŽ@²¹ÓcŒÜçP-÷Ón/±ýÊ;xGê!2<9òÙßX!d³ãÝw~y˜@F#PÔ4†¯áȡˢdëFåТŸ3ôy±Nkõ«0ڑß'v­)!š®›Ž“œnÝ:!à $v±uÉۀvÙi·žÇ¶mÛ~×®š™žÜ樓öäVOîõlL€ 0&À҃€ZBžVÙ«Bµ2¹ÒcŒÜçw\¹õ{.¿ÂóHD„GÀÆÞùJ…Uí¬ÍË’ 0”!` Eó0ÞŸ{®À:‹)zwú%‹Ø¥LÜJŠxîŒ5÷‰,î䒭ËFqïä¥G±þ+VqðŽ“­kV­Z5\Ÿ|+W®D¯^œ’þúõëÑœ{wåu”©~àÀIÞÇ0&À˜H-j ùiÓŠ¡zñXTuæÞÔzšŽû䥎_z‚;A†ðˆ…±™ 8çøwM òµL Èi…"ÑÞž~â"ÜîŸBÍJEѹeEèg€Ùeœ)Œ wÆêûD=urÝÖEÛ»w¯  ¥Jç͛'2¶ëªQ–yÊHOñýmÛ¶Uk·oßÙø+Uª€¬¯Ö|`L€ 0T  –§Ú·ÕJÈQ·"ÇȧÂ3P»ÉаHœŒøW_âEŽBƒáXŸì P» Ÿ 0ŒG ži8ÌߺcíÆS"Ãý ×Úȟ‡3gk˓~Q«7Àˆ#%Km–Zã ñJ%h¯]»???L™2E,H肅……aþüù"Šj÷lÙ³gÏ ë(́ùvëÖ "ÀƘ`L@ך%äÉu®–“>*;ñ†éõ€Ý_|ÂÁ³ðT?;|ƒ"„û|¡ ¥a`h˜^Câ~™Ð"†òXúŒëûOàÉ  î^.¥ókÑ3ïPÞF8cñÊí0`€N”c£'E¢2º¯X±†††hߟœˆƒ§Líº`±±±¢܉'⠗âù.\ˆ‡¢dɒâ¹ØW©REŠÅcdL€ 0& $ –§ø:e Q©$Ç^§Ç»sö?wŒë /cø{y£hå²¢”`L !\†Qð¹p7þ»‹– Ëá×úÎ ) Œ‹pƪû1lØ0X[[§óh’îž„.Ճ§x~Êæ>uêTT¯^=éµèŠíÛ·£cǎ"™ÝŸ}ûD©¹:ˆ2rRÉ8  söööžÿŸÎyKhn `L€ €µ…|ݲFšXBûÿI†©Öedd4öžžÿðX\ð7 C±jåalfšj}rÃL€ dnãΑӹW­\Ûðncz>Õ÷‘$ä`èСȖM{Ä)fœÊÉÑn|dd$(?Žj‚·ôdšißR2»ýû÷£E‹b…âúi—þèÑ£¢9Õ]yJDHIüؘ`L€ è µ„<¹×Õ/o†Š%t+¶OWBbãôõÁî£7`ei‚}oba‘Ë…+ðΚ.?S;HkÞÏ_âþΜh^Õœ;ÕHë8±jà 266Ú¢F»Ñôßù‹/ÂÛÛ[ď“=%µÓE Q–£Ѐ;vàìÙ³b*·nÝB™2e”Ó¢øÿɓ'ã·ß~Ú5ktqº|@îܹABßÔÔTœ£c C|||аaCž¹¹¡Aƒ8räôôôt • 0&À˜ÔòôýæÕmP¶'YK­w&&&ëv]‚™©1žœô€m­ÚðÏÆ;ñ©Å›Ûe™‘@·—ppÿ¿˜6ª% åO_A™™ø{ĔƲuEù9[[Ût™úãǏE,ø¹sç@1ä®®®"^›“ï%ŠÆN É-~îܹ"‰Ý™3gDÖyZÉdâ¶5jˆ˜ÿªU«ŠÐR¥J ÁOåè(}vqqÁɓ'9[}ºŒ‘Ü)`L€ ü,µ„<¹ßµü%œ)s:[jØ{üBBÃñö£JתŒÇVŸœ¹M&™ 3À‡cGpõöK,œÔæfƙGšÍ„üòõ‡Ð¯_¿4¯Ã&<¹˜S ø%J_±¢n†XðŠ]tr›§ùï%ä»ví*UªôÝgܶm[¬^œZ„°1&À˜ÐEj yª'ÛºV.”.h€‹sÔú1_r{†ÇÏ?!4,Õ+ÆUëRŽ–kýžy€L€ èö6X2o;Ì͍0~ nÄDëåø#–„|ߟ}…ëwZÙʕ+…=ÕRŽŽnô:uJ«îS¥ŸY³fJÅý(Ë|DD<== €pÚÁ'«]»¶(جY³T7ʘ`L ­š%ä©®lÛ:öp*`VãÊ4ýŒùàí¯#‹¥)ŠŽEP‘rxb˜iæÏeL m 1‰@ex ïžMèÞŠ*šÔqJÛdÂށ66xvý–m:µsº‹…D¶Ô#ð¥±tí!ôîÝööö©ÖÑóçυ€'÷s2JèF"ÞÁÁ!ÕúLë†iŽR©9r¯R¥ >|(bßUÄþƍÓzxÜ`L€ 04# –;v,:6p@ÉüìOæÜwÜwÿÊÍÓ±}-ìñ·F »Ô§$bn‹ 0D2‰@ ë üµàä2& fûÔ|QŒPKÖB¯^œ'OÊ'1%·yðS§N±ã”­|œzõRsZéÖö̙3Eº„Fµà;vì(Êè•/_>ÝÆÇ3&À˜H j yúfçFŽ(‘/-†”9ú zñË6žƒÚ7sÁSK< á™ãéó,™@úh•-YÃýÑõ÷5˜0ž *8HÿAeÐxÁ K×A=7oޝåºuë„Û<¹{yyaʔ)"©^F7ÊRO íhΔįB… ¢V<`L€ 0ÌB@m!ÿ¿Š…QÌ>&³pIõyî>z/Þx¡lÉŒÈU®,޳K}ª3ç˜øJ  q$Zf ÄŠœWpåÖ ,ý» ãI%_dNX²öˆHЖ/_ʬˆS,8e¢§8xJfW§N± ¯+qàîîîX°`àíÛ·uß٘`L€ 0õ š%äG×ÅPÌ.Zý–ùÊïxõî Ö팄Ù,1Àµ6¶|±„G„>cL€ €)òæaši"våÛ7¯€&µJ¥iÿ™¥3o™¯=‚îÝ»#þü?5íׯ_ 7zJôƒêÕ«ƒþ]¹råŸj7­o&ïææ&º¥€Ã‡ÃАœŠõsàþ˜`L@w š-ä»ýZEsGêîLµhä[\ÃãgÑ¡yEÀÞÇx7^‹ž… d.u²„àݕ«Øwâ6ÖÍ&ŸF³õ‘;aњ#èÖ­ÛO%ž£zð$â‹)===±ߺuë4šEÊuúÍ¥_ _¹®9WWW‘ŒNSÛŽi“í&&&2ÓS-u]²šš(T¬XŽŽŽ?~<œœœP¶lYQ㝒ÓÑî<Õ|§y²1&À˜`IPKȏ1œÚ:£Pΰ€[ä+~H`ϱ›žtã~ïQ¡YmqȇëÚŠÄ+c&3@¹ Œ !—+ª+Ўíîû)Õ~ôè®\œ ‡ŠN°pr@DtTJtÍm0'`©C·sžöß,›ö?Ÿ¶MàUVl¿wï^d˖ vvvBÀךQ#©[µú<ýþ­U«–rŒ+W®%ùÈHà;;;#00W®\bŸ 0&À˜ø>µ„<%ÒéÕ¶ s„0˟ pþêì<䆱#Â:'öy[üDk|«*òålaf€ï$äIŒK;òt-ÕZŠLÉ7nÜ@ýõaì` 7Ï:µ3ïõö#œ}P LI~˜@Šxuè ²‡ú`ÒïÍSŒíÌÜ ¿^)Ì_}]ºt»Ò?²éÓ§ Ñ^ŽhQ±SMqñ”$/œì͛7  ù”ŽÆtùòexzz¢Q£Fb±41 ÁéÓ§)Üæ¿|ùªýÞµkWôïß_™äŽÚªR¥Š² ooo¬_¿œ{÷™øÙ˜`L€ 0ŸòŽ›I±xœÚ–…cŽ`fùÆÎÜ»œY0°[ì÷1ÇóPÎÐû8ãÝJBÞÅ8ä1®õ’'1OF_IàS©Š[·n 7Nç2epÇë5ny¿çµÝ^Ý}ŒåÆÃ&On4èŠO/ÞÀ2[V,[YsåÐöáóøt€€ÿœœ±ÿn#ÎݑRÌ_¿&ÌØ„f͚¡Aƒ‰6»mÛ6± odd„ǏƒrӐ 70H?¯­›7oŠtÚ%§±oݺU)°Ih/\žP$ðS5ùµkסLdßO¿wņ@¯^b U«VâÜÝ»wE¬<`L€ 0& 9$wäis̘1èÕ®<³jÞß!Œzë…) cd߆0͓»ŸðnCJŸ’7ˆs­—„9 zöŽ EFîõ>Dá…E¢¥èØ<ðÿˆ;^o«ž&-ìó›ðxùÙóÚÁÔÂÆfˆ‰Aˆ ^ßw‡¡!JÔš¹ž"T€æ³ Ûp!Þ³V£ú¢bóz?zdxÞ Ïž=Ü4|í IDATƒ¥¥¥pq¥¯r}=<ô€{ '"Ó ^¯?Š4û-Éé·Û.Mêˆëž\»µÃÿVÞS²FEd͝ÏÝî)Å}¯“àXîیãþ^>ž~ð$.î8Œð¯y.ò–(ŒÿM Kë$Çòœ žßŒ{g.#$ Áþøâ‹[ŠI ©Ë»‚DgýžP§[ÛdρoŒOàþ…«x}ë>¶Lk{CN™ïG AIÌ]q;wV yÚ¹&O»Üyóæ;ïô=¹¢§·‘k<Õ§'ï%î$ÄÕ±'Ož÷{2ú=+å7nŠM›&vóéwð«W¯pêÔ)j`jjªNÓ| `L€ 0&€@’BžbÜè?œڹ  ?L&~lBƒ_JÂ¥– ¶yY&³Ÿí{HÈW0É Ú‘§aÉœž®'/£?PéLÚý¢wÛÐÐPümne ‡Íj$véSÓÞÜ‚¥ýþH²‹ŸKþ†CiŮ܆±3ñèâuñù·9ãP€’b+:2 ;Š.ÂÝӗP L ôY49^»¯î<Âò”ÇrÌ ›¬xzíŽ8Ö|hTmÓ8ɱ$Œ€v÷Ì[ ·ÃgŸ¹·ïâ)pp.®q›šÞpqÇ!^ŽUÛ4Aó¡I/ŒhÚ~fœ>2<ÆÌĈ™CÐӁ“AŠÄ{dPsV(bäÉhöìÙÊ]wú}Ô®];¬Zµ*%ºúé6èweǎ±sçN±«NyE²fͪV»äI@‹än¿nÝ:qÏ¡C‡ÐŒùל ”ÈO³î«€/bL€ 0&†’ò˜0az¶%!CË8]œûèƒSwbÑ_pK?eœÉiÉLHÈW4µ;ò$ÜIÈSL<}N(äIÄß¹sþþŠ…)zÇÉ¥ÕÈÄE›Ö€^N+Ä€bÌü•œÇ±ÿŸUB€÷Y4AŸ~ðõðnõá¡a063A.Çüʝò€ üÕØUŒuàÊÈS<~²¬ÐÀ LoÝWì¶O;·zq±Íª»øŽƒ_»[Ø.¿Ï_0œUÑ^ÍÎ-Ñš_žblL,¶Nú÷Îþ'î«÷[{˜e±s"£yÑ"DjÛéu;qjÍXåȆœáýÁ¡A025AÝíQš<ÇÞ&÷§C‰²Å°¬£bw•íç–ÄœåGacc#»ŸŸ>(‰íГø¥ÌôÚbK–,ÁÀÅpšü]B×yÕqÒß”ÔîèÑ£Bì0K—.…‹‹‹š OÉì(yŸª©fª×–9ó8˜`L€ è"$…< œ?ÿü=ÛW@Ak_]œcºyû¡ëž~çFéŒMŸy7>5 ùJföJ!O(Kqñ$ê%q,jS"&Šý”’âQ úÜ¥ !«KQDÆŠÞNäæñ³qÿüU4ÜÕÚ%íF{ãÈY욟åÕD»qƒÅ'íØ\5yŠ9‚Üé§µT”uªÞŸš p…L.ƒÏGO¬ú—øJ–Ø.~RÏÇíÈ잟T\ÖoéßÈï€ðžyü'ŽñãÇ£téÒhÛ¶­Höwüøq­š7† 0&À˜€.HRȇ……‰•õ^í+¢€µ.Î1ÝÇL»ñåKå‡MZžÃ»ñ©ò©¢è·lj’c.ˆŽŠÆÌvýàÿٝ&ýŽÒu«)ï ö À䩊2YVÎ@ÞžÒ…Žˆðâöè눅ÚQW5 8·y¯HÌçïùYsçyçÁ‘%¿«yV+TlQ_,`ä,W$Ÿ“ž¹Úã ã ‘ÿ¬Â… M?õµ2:v¿`L^p÷^ƒ©™…å™:uªØ‰×6£ÿÖ“ØŠ…Nrÿ¿pá‚X õòòåæèýŸ€xJØG±íŽ0A@(–Ÿoߟb7ÞÍÍM,þߟ}7Iò(¡…2ÙÛۋ$wTVO]w}mãÄãaL€ 0& -’ò¡¡¡"æ­g;òÞÚ2nGdT4Zõ^‚i“»áŽë—ä÷”IïŒýð-f-?Ž>ō ãLJ!õ§MBŸŠE^˜(òHîô’ë<}¥$ÞÉœžBFȝžD¿‰‰‰Ø•§ ö¡Áø×÷‚¢#4ôÙ {pbÕVqŽ‰K;ãØ²ÍʶH@¿}ðô‡m÷œ?QߌI »Šëg\ܝèN3ŬOoÓGì’K1òä~þO—¡ñvßKÕ¬„úœ:!G>;H Ū–G·™c՞«ŽóO‹UZ5Rû>Úeß4~6_Ÿ!î)X®”(·'-0ŒÜŸ6ö¹ðúÞc,ë?^\SŸq-8–sBxh(nŸøW”壅‰ ×ÀÀØR"?ò@ O¶”%prÕ6Tŵ ]ŽËý;eg™ò­8yGxúôÙ;5+ŘÑñõà-žººj­§ß‰­[·îñ’Q²;ªî‘/_>äɓGì€ÓN=íÚÓ9*QGuïi¢wïÞ¢~ü™3ß&À”Ú£lõ ýìÞœ;åás‹L€ 0&À2$…òXJhŽ*—CéšE‹‰¢ÿ#«_¿Ÿ(=ÇÙëÕz­ø"&À˜`ß%€§ÿ ÿý÷ßèÙŸ ²(d±©O`äԝ°,R&•kª_©1 =#T³Ê/bäÉ€ŒõôYr«§Ï’»=}ŽŽV~O˜’˜÷ÂÙ/O5òÔ¶÷{,ømDŒ]pŠÿv1Fˆì€LUŽY;¹ ; &:ci'n¶i>r:ä‰× Å¥“ë=ÅçwøsÈ7nùßëóÜŠœÂÍœîoíDÖyuMÊOîù”PNóóü‚é­YòÉlòäîþ/nÞW&¬ûcß*኿føQ¯ó”ápªUå‡Í¿}øT,žHyÔ _£>J(xuÝü»Z‘4‘-q=ü0cù1lØuNÅìñìõgLÚ}»|ýn\SeÙŽÕµ^ÝçK¥óF%âÞoÞŒ™ämŽÓO¥èœQŸ|y 6Lˆ~JŽ×ªU«$ïç ˜`L€ 0Ä $)ä)!ØŽiÓЃ„Œ•sԐ@›~ËPª›+Ììí5Œ“/ׄ ùêY +Â]ÊZOŸÉTŒtLøtŽD<íÌû&[ȓ芌ð’»8í>Ú±”ŒM]Ûòç\QÖMÕœþŸ.Càùúý7YëÉ¥~×ôÅžyìŒH7zç2±S­Ž^Œ^Äìkê"ïóé3f¶í'ºšÑ¡¹(]'ËIðœ~ÿÝ~Go‰í‚}ýÅ\$£q·ÑG$è#“æê:}4ŠW¯ðé||úJ,œäÌoa›ˆk)ߜNƒ@aû+BؒG€Â!vŽŸŽ“‹º![V³ä5’ÁïZ²ñ,&Ï?+K|þˆž«‹]x ³øaTá&Å1en yr«'ŸaÃñT©ä\£FI‡×̛7OܗÐV¯^=Ô÷Êà¯O 0&À˜€Æ’òäfGu`{všŠü–Ÿ4î 3ß@‹Û Z…†3&gf i2wIț› Ñ.ÅÈ«îÆÓ@€˜yÕAÑ1Ê&M_iGþôgwwäiGœJ¯=ø÷ZŒùRœwóß{ŠõdÇ~ãèY‘ÏÒ&~28Ú¹^ÚïqÍØœ+%‡žç¿=Çp`Þjñ¹íØ(מ|?}Æî™ËÄ®6eЧiumßܕžºï„Z;ß Û€Ä};Š,‡)éíίV$üü>{#4 VÙmÍ^‘$M*×kÁ$,S¯î=‚çËw0·Î‚¢•ʈxwÉ€Ä~mÿ(bädTŽîïæ=„»þ_'6‰çG‰—ô#²ÜÿoÚ(uqðuß!p`úBÌp­„ª.ŽÌH…ÀÑs÷1yþA±h‹<¹¬1ñ÷æp.ßcFº%žþZpÝ»wיyòÆ£NJfwìØ1‘€Žþ û?{gUõÒµñìîî»[¯zk]»Q»ãڅݝØÝØÝ-v'** ïÚÃ{Ž`ÿáçÀ3k}ë»Âž™=¿ù{ßûÌÞ³gƌêÍx-mõêÕhÜžñOŠRé>þüZ†    À/ò;v,Z6!ÿŒ pôìmL_u…{t3¢MƒB@„|™!B^DŒNœKŠœî=ù?+6:!¿ïÕMx|ý¬ÙkGN«ûær×[¢ïÍGõÁ»—¯ •äuM÷TÛþ¥°{îJ%>kÿ×6¥ Á:’5\Ã†±³UŠŒD®ÛLªÞ}—&÷éÇ7鬟4IMýøûßÅŸÓâž®8_›iC‘©@.-]ÙÜ8~›§,T…ÿÇA†»¬@ÔèÑáÔq î_rEåÖMPÞ®îçU§ZgYÛÚšÒÎö¶¯4Ò1bÇT‘‰ø7Ô*ÿeôºØ!0—ù«Ð$W4¯ûçk…›ëç:e Î]yˆ$‰âÀóƒzµýÍëÿ#‚¯1rÀqò888X„×U—ÿqQyòäQO̕,YÒš-—ûðòìܛ7oðöí[$I’eËòº™QiL$@$@?0(ä¥x€Ö·hPٱ؝1_ÐÒ ÇqâŽ;2Ù2Å×nA±Õ y¹#/wßEÌK%zòºh».¥þOã{|úš"òZ…ŒT‡]Çÿþ·ˆøN£(•$ú±ë¬6U‰nÝýõ÷aV»þîÑôGDŒó8‰róåƒÇXÜ{t á,)å"XSe3üýkÖŠÓÝÅ sҗ\ŽáιËx|ý¶Ðr@!k(Rýo}jŒTîß:m‘š¢Då æþi:)ÌçéþÛg.Tëd§R÷ 5ݝú<14ÿ{§·ìEޝ/0€KµÉËû+†Nيi‹\P,Fœ8W¥Ð÷io8µ\À}™Ž“,GÈK^ÿþß_‚߯_?Ô¯__ÿŒg„þ žx  0…ü»wï0aÂŽlX éâ|¿ÛjŸ›œ R¥Ø3Vb$®TÕì}µt•O˜ q¢ÇTK x7^°×ÒÞú——Ú…ŒÜÉZÕN -éí?£û՜žoÞâôVœß}X‰|øÍYŠ U)¯ÄÿØWªŒKäþ“ǀϝ É2ŠÕŒ®_ù!ö$OúÛùŽð h#ÂþW÷兑\xâzG™¬R™ åA”šQ!®ÇÏé'Ré¿pµòŠ‹¡&¶³ÛP#rµ@®,ü§¬ªøÏf:)<èsþŒø95ÚôÑ-c„¹+«çä²dH†Û÷ÝPµ\.%âS%|Øö§Õ|‹iƒA·š;á–RìîøñãWkòæÍ«"èl$@$@$@æEÀ —4ž‰'¢e£ÒHû±yyoæÞtŒɊAô|.ÚeæË°÷DÈÿ?#âÆŽ£ ÝlZ"ñ:ûOÞ^pyéŠ÷FtSÞ¡A© ûë+;LØjQù /–I€H€H€B…€A!/OÎÈó1-•EÚX÷CÅ©ð2I•æSðÏÞø‘Âð²§\ D$~ŸŸØ9p8ÖMu@¢øáû :__%àGÍ܁ò%²ãșÛèÞ²»þ‹šQM»ª!BŸÿø-hÕª•Å€ÖG€ïœk%  K$`PÈK•Ù)SŠ e£rHëž%®1L|~ïù :ÎEÅÑ|z.L6€“’  ÃÇ`b¯Ȟ)E°ŒgŽƒ,^w ÊnE†4‰ñôå;äµIÇn5#KÊ`q×/v6ô»­[·Š¢„H€H€HÀ ýú5ŠM›‰ÈÇ€×úÉܺÿœÆ:£ô ï•µö¥  ˜ Ó“Š¢kãb(Y(‹¹žl~:yS x÷÷3zTxùŠÒèkTÈlsšbgCï1›ÑŠM ùà%ËÑH€H€H Â0(ä_œz…3fÀ^„|Œ»”± ?yá&-;‚"ÿu7¶+íI€HÀl\qrBƒrÙQ­|³ñÉTG=uÇЩ[°ïèuØdNù÷uÙâÙá<·£©Cÿº?…|Èpåš$@$@$ ònnn˜9s&•Gš·#0*ã–ŸëÐU,Ý} :¶7®#­I€HÀŒÜ^²år§@£áãõÓ·©(|ÅR9pîêCÔ¯Zƒ»Õ@’„qBŒºUœlè9jÚ¶mˈ|ˆQæÀ$@$@$±ò/_ŸÄ¬Y³àÐèo€‰q+bÑ1aµëwœ…ó™§ÈßÊބQؕH€–À£5+‘7UlŽlôªía»ÿÙWl:©|š ñÎã’$Š£Òè‹åÏâîYÅΊ^cüïÈg˖-Äçã$@$@$@ៀA!ÿâÅ 899Á^„|ô›áŸH0­pÉúãØsÛù›7 Š9  „>Îë!®5:6/ú“Ì'ÎßEÿqáùÁ ãǃ'¯•€oZ«X0Œ®m«ØYÐ{ì6»Ó†‹V$@$@$@hò+ Mކ€‰˜³â<÷A¡Æõ„H€,–ÀëmÎHù ºµ¬hQkxñêœzNnóދ(”;¶í¿¬üà®5B}V±3£÷Øíêù9FäC?'$  pIÀ þü9æÌ™‡Æ‘:škž„‹šŸx?ºGEñ†ÿ†Äð“H€B…€û®-Hðízµý'Tæ ŽIÆ9íRiôòŒëç(^ “ñ™Ò% ŽáÃ*v&tŒ5B™2eŒîÏ$@$@$@$ð#ƒBþÙ³g˜7oìWBêš×HP# ó÷âØ‡Ø(Y¿šÆ4# ó#ðnÏ6ÄözŸí«˜Ÿs?xŽnûY%à“'‰ï/_áãã«|¥29ÃÔw«XÑgü.ØÛÛÃÆÆ&L}áä$@$@$@ჀA!ÿþ},ZŽ­l«"uÔ«ácÕ¡°Ša³÷ââמ(Q×üÿã7pp   %ðvÏvÄùü};T5Ûœœü@ ø'/Þ"uò8}ñ>»Õ@ûfæq¯ŸBÞl?:F$@$@KÀ òä .\ûƕ‘*Ê‹]hh;Þw– nûÄEñ:–“Žڌ8 €ùx³gâ™iDþÍ»6e Vn>…b2áèé[phXZEáãÆŽn6p­be@ß {`gg‡9r˜_t„H€H€HÀr ò?Vy‡&ÿ eä˖»ÒPöŒÇŒýxà‹ùPæÎéH€‚—€ÛŽ­Hâ+wä+ïÀ&Ž6eÁ^…/[,>}£ž•kP£šÔ4¿÷î­bŠG¿I.hÖ¬ræ Û4±³;   €™Ð$ä/^ŒÿAªÈ—ÌÄmów£‰ãFŒð‰†ªí›™¿³ôH€~Cà҂…Hé & h`Œ6﹈aS·š§ä"GŠ„ÇÏÝUŸ~µBfá߯œ°Š™ý&í£7Û¢c$@$@$`y ùGaɒ%hÑž REŸhy+ #»Î<€Gߢ£d=» £-àŽ$@Á@àé–MHÍÝÂöù¹Ë®O0têÜ}à†,“a›‹<'Wìïîëð[ÅL‹~“öSÈÃ÷È!H€H€H€ü ò>ÄÒ¥KáÐŽ*RX_ 7:OۇgÖqPŒvÄž#ïñÚG×mGŸ¿K!eÖ )^?áØºí(V«2bŏ«¹ I€B‡ÀÓ­›6Š7º‡Ñ;òžŒ”€Ÿ¿êª”ˍ“çïâïR90€Û¿H"Aè@0q«iÐÊA4mÚ¹rå2q4v'    BþÁƒX¶lšVG ësdŠ‘@Ç){á5ŠÖ¬€±‡y˜yöÂ͓çq÷üU|õòF¹fu‘$mJƒÎ-î3®ÇÎ"Oùh:ì?ƒö:ƒãwbó€ùšÜº ÊÛÕÕ܏†$@¡CàÙÖMHÙ=Z…~D~æÒ*ŸTá,xõÆ‘"Y«4z¹oIÍ*Fj ˜z7Fîܹ-ÉuúJ$@$@$`Š FäEÈ/_ŸöMDȟ5Óe˜Ÿ[í'î†{¬$(\£‚ù9÷ƒG~~~x|ý6Îí:ˆ“λý¶tÚ޹Å×ðÉã†VµS6…«ÿz};h^óæÉóq|ÃN”nTÕ;ýy̓ҐH Ø<ß¶©¬?£GëÐ;”ÜqàŠðqbEGœØÑ!Ïˉ€oÙ°t°­+4²Š‘ Š¡M蜋H€H€Â9ƒB^ޑ_±bšÖ@r«3áGð-¯Ýøx?% V5wŒµ2?_?\9t»ç®ÂëÇÏô&©²fD‘+àÃÛ÷È]®8’¥OóG0'6îŠIó”MÙŠµQ¥œm û÷no°Òq’JŸÏ_¹L ß-ë?WŸ‚ÄÈV¬@ðmG""äSX}BÏ6!_µÞõÎsU‰þò'ȝ-œž‰– K)-jä`YOX b#%úL<ˆzõê¡Hó«ªL8'   €i ù{÷îaåʕp°ýÉqÚŽÙ"PïÖc¶ãc’Ž(ðÏ_f¹jß–o„ˆl]³)Y¥TGŠ‚ÚS?}}|0Å®^>x¢†ù§-ÊÙÖŽæ³;`Ýšˆ3†íYèwct€û³—²s bĉm–¬è Dd"ä“ã#zµ ¹zï<>aœÓ.L]è‚:U â²ëcd˔¶µŠáߊù,¿Uô”8ý6lˆ‰€‰ãâãG/Œ|í©ªÑ‡¯ßÍè)0húq yóûŒé   X,ƒBþΝ;X³@à| IDATf ìmk"¹ßI‹]hh;n?|3Ÿ¥ÏŠŒåK†öÔç“"vcê·W©óÒ²—(šî§k)jpð·ÏÝÔ8Ò§I©Òóå~ŒÜ“Ø6Œ›Ó[\ԏ:Í‹46™Õ?Kq<)’W°JY4ÐÙ ß4 }/¶oFâožÁþÌÛŸc®*>r$k$OÛ÷Ësrÿ¢{Õ iªVѓcàôò! šã“  @" YÈ;ØÖF2¿ãiKmæžÈdƒŒ›Ÿ—•œzô «‡OÅ×;ú…æ.[ e×DڜY .Þç›æuuÄýK®(Óè_XGŠ„ƒ+œQ¿' PÀ××#k¶ÒØï©îÝKÛ2e!Ž­ßŽFƒºþtwÞ 4 "ä}õD¿ŽUƒeŸû_+äô-”)š»^Eí (Ÿ4Qœ`™ÃÜ±Šž §Ÿ€7·¡?$@$@$`Á ùÛ·ocݺu°!ï{̂—º®7²‘²æFοŠ†îÄFÌ&Õê¢Þq—èž®¥Ïõúuüc„~Çìe8Žb€0^§QpYŽ–mD£Á]‘¿Ò÷‚v"ô:ԏ]­“þr •îœ?}F¿ s?Yb#<§) @hx¹}3âñÀ€NÕLžrøŽm:e šÖ*Š{^#VÌšJÀ/Éä±Íy«hI1pÆ) ysÞ$úF$@$@FÀ ¿uëÖ¯_ûfuÌ繅-/ìܵ²ÖÙò góòéŒyò'6í‘Õ[Տ¥0Ý˜ŸÈT ×O¯>…¥ýÇ©Ÿ÷^=SÝ­ß9{¹ŠÈ7þò”+¡ï£{^N÷)š×bl?Ü:} z CŠLéÐmÉ€°Û(ÎL$ðG/·oA<¯wØ¥zI­ØtÊlEÎl©`me…K®•€·­],ÈcZRG«hI0hæ4hЀÅî,iãè+   ˜1ƒBþæÍ›Ø°ašÕERŸ#fŒórÍnÈÆÿ yËzjÈãµ;V šˆWn( #\V"JôhzžnŸbbÓ.êÏÿŽmªî׿žó‡VnÂó»UáºBÕÊ£J;Û@Q÷VS1¿ÛPÕO*Ô¯> 7ŽŸÃ¿ÝZ¢dœàIÙ5¯/€Þ@ø p{ÕJÄþü54zA'ÎßUiôžŒ9]8y üŸ“‹P-Zb žyõë×GÞŒy#ÔÒ¹X   ! IÈoÜžö¶"䇌ápT;Ç °Îž9˘——·ã­Ú„±c©¢tr·ýÇæýÙ ƒ+6U?–h¹DÍ¥y}ü„é­úzsþǟɁ_¢nÜ¿xN!C^Ž›9ãwV}SÛdÖßÍŽeb'Œ¿.‰Â‰ÈÇúèŽ!ݵ‹ï—¯=”€wÞuUËçÁÑ3·Q8OzŽš_—Ž `ŒX…UŽD4ó…ŒÌhJ$@$@$ðg…ü7àìì ûæõ‘ôëAòÔH@ y›ŒÈYÚŒ„üÇ÷VÍ^­Bu¡ªå‘>OvXG²Æ·/_áþÌ WžÀ%—£*œŸ÷š™*Ê.wٗ Ûg.é ÈÏ3æË‰”Ù2âѵ[ž~ä4ŠÕªŒÚ=Û(¹C/wékvo¥„ýŸÅë°gþj}ÿ¥‹ÀntDiF$žlÚ îÈé^SÓôŸŸ~ÈòW”,”no<àá饞“«ü×Ï×t4 Œ¢&ÄàYç)äÃÃ^r $@$@$`& yWWWlÞŒ-š‰?`&n›¿-†l€U6ó‹È 9yò-`q»ßÑŽ×_¥Îòø€ÿ WQôxI¡éÐÿ/Y"ÄOúœ@Ýù݇°fø4Uü®ËÂñjHÝ<"[Ñüøìù£ë¶S‡ÒÚρôy"^tÎü¿^zHß ŒØ¶ ±>œÅPBþÍ»èâž.G®«úÍËgԄpœ}õêÕcj=¿   `!`PÈ_¿~] y‡æ ‘äëþ`™4" ÒÂq¬Ì0"/ì}}|póÔ\=x®Ü„ç›·ú-‰Ÿ42Ì­ž¡K<‰ú¹óĹ8éŒ[œßzªc ¯ë(ëwÍY¡¢øÃö,W?^ÃA=;×uá€ÌšAýìîù«ÊNîÑý·bDøžF°hÏ·:#Ž×{ Ñp¯}Ú" ²võJ(/N ‹^{°95g_Dݺu‘/_Ÿ`–‘   D\š„ü–-[`/BþËŸˆKÊȕKDÞÚ&r”*ldOó3wž0VVVšÒ¡¢ÅˆþK?ŸóÀT‡žˆ“(:Ï«löÌ[…ç÷Aގùç»øæ·RzD$ð#§›7"þW8v5|GþÁ“7p÷rù×Õ`û?(ñáèt‰Bž   @°0(ä¯]»†­[·ÂÞ®’x»ÛÄá} Žëam“9J[Ÿ×ºWRHVP¢ŸH |;ò }>`p—ácAa±Š(ñàèt™B>,ØsN  § ù«W¯bÛ¶mp°kŒÄÞ{Ã)†à_–œãzXåÈ."òÁO‡#’ X ÇÎë‘Ä÷“IïÈ[ÊZCÌÏ(qáèt…B>Äs`  ˆx ù+W®`ǎ°·k‚Ä^»#¡ ®žÅÿGäÃAj}° @8 ðhÃ:$³ò€ÎÕÂÁjÂh QâÀÑé*êÔ©ƒüù󇑜–H€H€H <0(ä/]º„;w¡…-{í OkѵøGä G©B!:' $ðpýZ€ˆäþ(äƒÌ9rl ˜y µjÕBÑ¢Eƒ< ;’   €Ž€A!ùòeìÚµ -ìš"ñç$§‘€yëœùaS2âܑ׈†f$@DàÁº5Hå+úu¬jA^›™«‘cÁqÎuŠÖ›Ù¶Ð  °d…ŒDäEÈ;Žh†DŸwXòZCÕ÷z=–Â*KN>±ªÔ9 @pž¿f5ÒÄðAßöU‚{èˆ3^ä˜pœãJ!qvœ+%  '`PÈ_Œx{ö쁜ùOÛCÜ¡ð2DŸlJ2µ>Œì)×A‘ÀÍåː6Š/ufÕú pœK!d~ìH$@$@$ð#„Œ}ÚJ„ 88®ƒU®‚°)A!¯Yš˜-î3isfEùæuCe>Nb>ž÷Aۋ;+W S+ôj÷OÐ`/ R 8́zõê!oÞŒ$B$@$@$@&0(ä/\ž "òö-(äÀ­„|ÎB°)YЈ^4 i}JÕE²ô©ÑcùԐžŠã›î}Ð6ä֊åÈÏ=ÛRȍ €HÑ1xÎ Ô¯_ŸB>ÈّH€H€H ƒBþüùóØ·oìí[ á‡Í€§‘€Ãàu°Ê]6%(ä5" 3sñ’&BÿsCe>Nb>ž÷Aۋ[˖!kÂÈèÙŠrÐ`/ R4 žs 4@žûùùÁÊÊJ?œ¯¯/ú•©™Ò¡Û’IaåVšÌûíËWÜ»x^?"W™¢°Ž)Tæ5×I"ÒÞ÷\_ŽyRÄD·–‚{èˆ3žud šs5Bîܹ#κ¹R   #`Pȟ9s‡ú¿ß øù„˜3áià–’ZŸ«0#òa°©"b¥Bùó;Ð~öH$NBy!?PŸ2äµA»™#ÂÀ³Ð™òᕛXá8ïÝÞš %¡FçÈQºHè8`†³D”œ ô"ä󩌉®òAæK!dtìH$@$@$ðkš„üáÇagg‡„Ÿ¶ŸßÈR‰È[å)‚ìÅ h°ŠIpøìùCªØ©!§I‰ÎóÇ"z¬˜ðúø Ž•›![±üp˜008§4›±žÝº§Nƒàýé³òI*ô¿|ðDý³íˆ^È]¶˜ÙøšŽD„œ ž~ŸŸž±tò€ˆA!o `«H4÷#òŠ0d_   @ ùÓ§OãèÑ£hÞŒ9~Úø~%B ”Ï͈ŒT!bòØõNl܉;ç® ±cw…ÿäñC«Ú!Oùh:ì¿@óJêµµµuˆøZƒŸzô Ó[õV"ŸDÝ*šÔº1bυÇÏaQïQÊ ¹R W "ZûÓÞG4Ƭ××Ç·–/GîäòÆpûÉÖʃæÞEãÆ‘+W.“†bg   …ü©S§pìØ±ÿ ù€ï’Ó@ "GäݟœÄÝ W9rd̟S=÷fíí‹WS¯ Wÿõúvлt`¹3,݀›æ!ZÌÁæêÇwˆ7¬¬¿ßÓÿqð¯^ސC„ßÍ«„Ô©‹pᆔ™Ó#MDŠù'=^»cF›Ÿ*Ÿ\³:ø§mÓ@6g¶ïÃúѳPŒö?šõ_ë_®QË\~Ÿ~øúÅQ£Gÿ-'±‘¬ˆ˜ñâKC‰ïnž FœØ¿üÞ~·÷Ç}tížÞºøI!}^u¢µœåŽ'Îá«÷d*ë‡%²G_ŒŒÕŽo؉. Ç#U֌|N'7ïÁ‰»TVÀ]K!¢>š{ŠõÛxóäVŸªxKKŸ;;*·iŒŒù¿G>µ÷:çßœ| ç‰sUæBÀf?®¿ŠG×nÃÖi‹õý»E}Tjõý›—ÔþC+6áÜ®ƒúÚÒ¡PÕr*{"U¶L¿ý|¿}ýŠÈQ¢è/ëL˜")b'Œoè“7ù÷ªhâšÕÈI!o2ˁsï¡iÓŠÈ™3§Écq   Ð$äOœ8¡„|‚O"äœHMº]Yr£x4X[Ÿ‰Ï×oX6p<\U‹A)÷kï]žŠþÜkõ %žE»?‹Ò jàɍ;ª×‡OèµjºȋúŒÆÝsWPžZyÔë×QæåƒÇ˜ÛÙQ î€MîÀێèùST"£'œw!g©"H”Ú_ô>º~3Ûôŏ"kT6H™%ZŒí§úʁX>hÂOcS² 茘qcúÝØ ™ò>ýºÑ3‰Â–“#k‘ŒžŽïV:NB™Fÿ"ç_E1»ýý©m2£óŒ±ú?ß=s»8ª?KŽ^æ¶" Tþ uÑۊ8Ÿb×Cý¹ïz'D‰®ÞÄ珟1_N$HžDýN•—Ÿ2†®3×Ü®CÔþȁB·EUÔýƒû;u€sfû~œ¿rx“­x£ö,(߆0ö¿jõûuD¡jåÿž÷Iwê8P흎<åJàٝxýø™:(žyÁ3*ö-^‡=óWë×-ìu߹C’åÇúvåäé­{z·ë÷ï€Dœ49(ɐ/‡úŠ×™…3Ûö¡¢CCTphèšDåS,}š_®=ž~(®_‹I¢¢‹=‹Ý™ÂuàÜ»hÚԖBÞˆìK$@$@$ '`Pȋˆ—šŒ¿ßøøÑbû3ˆ‘1#¢FD§Ã„HŸÇFE×ÇÖï LóÑ}³tHû.§åèºpö,X­þ­§Á¹p~÷!=Ø!;—šTiª"zEÄf-šO‰š$iSâàòM8žÂYŽûoù”@Qhþ“lGßï]žŠ9Qµ}3üÕŽ–~žŸ©“èºDx¥•¬WÅjÿƒÉéó`í\îŒËÝw]“tëq:ªÔhI‘–ŠÒµzŽþmŠ„ç›·QÓŽŠÃÿSZi’?²Ö÷»åÿ-ŸŠ€éSëç^Ã!PĵŞ~H, &ÛõPÑt‰öË!ŚáÓô}Dˆüìòãè²`œJ±Ö¥¯‹¡°H›3«º¯Kýx5@l&ÙvUtÜägÂS€®Àݭӗ° Ç°@÷䍝KÆŸvø–öèoÌ×dHwœè ʞ鄌1߯üîÃpûÌ%åKÀL‹UC§àâÞ#*Ê-Ñî_íýY2¯€¬_Þ\÷ãÉíåZ„\gýšì­ÜË·wóô©^‘£FÁޅkà²p­bÓså4u8°]r9Š•C&#KáŒh9iò²—±âÇÕg ˆð—ûêr¿^·ÏÂ\ B²É]þÇÎë)äƒò€9wЬYsäȑ#Fã$@$@$@€A!/…îä-ùf͚!Áç=À·™Šõû yy~® &{K6:Œz ¶ÏX¢ Û}|ûþ§;Ýuz¶Õß5։µß­W¢ù÷.\W‘v‰®fÈcI}QÕuÑD}¡·Ó[]°aìlý0"’ú®›­/Š{nLDÏÐÝËÔuIé_Ü{4ªvhŽ¿šÔÔ÷•TfS vV‡ "ª$ÂZû¿6ÊF ֎˜([@"ŠÍFùGK¥X]¿2õõãÉaƒ:H/éÉ—(ñŽÙËÔÏE˜I*œ€ŠKꎀP×íÓ^ Ï~5P6r0!¿ Øä÷5º:º§ß§TÝ@6•[7Ay»º*ª/)ã2WŸµ³°aÜlœÞâ¢_¿Ü›7v.™ÈÓýÆ7ê€âNöœõG}F„ˆÍ ì™±ßFŸ ¥Ô<2ŸŽ€Ïëé-tW~µ÷RÉ_:òV(¥þ¿îÉ>KYêö퀀éRýö¯æœÎƒUäœN¯¶(Z³ÒoíDċ˜ÿ]¡ÁÓ[öbÃ8§@BþwƒIFŠ\C%¹ÞÐãÜýWÇw!/©õßÊBtÒp:8…|8ÝX.‹H€H€ˆ€‘BÞøæF®ZÖŽ­×À/wĈÈ/é7׏œVÑåLùsáþåëxyï±*ƕœXþ@•¹Š5‰–GŽWŸR›+é꒶®»Ë-)éù*–V¢QyÛÃTÁ9ISÞ=×?}\đDºE„‰ kп“Š‚JÓ ÜÞkfªâp:1'wÔ«uòg^Šy (ï_”¬Öm%juÇ]ž«k<€ŸyQW$º+­dœj8¶~»úç]ìQªAõ@Ñz]X÷µJ*»€Ž‹RM €ý·bš^$>œyÓZöö/|V¯ª*J'B²ýì‘jì{¯«õ¥Í‘)2§ôA$‚«kÂiÀæù*j0ú/wç¥b¿49,ÉV¬€º `Ì\ÒW¢Í {TwÈ6Ér”zyÂïõ“çAÚ3c¿ I-Pî{A99ìi;cžŠd^µÛg.ÕGÕÜû€‡#\ü¿¥Ûg/«CÄiS"sÁÜ?[”kòmÊw–¥Pýýua.‡RáWMŸWI¯ÿ:Ì­?„ñþìÉ Ø2eÚ_ٗ¬EóÚOù&7Môër ÓuÑÕ_—"Ÿ‡då{ ùàûߝN·Ñ¬¹#òÁ‡”#‘  @„&`PÈËòçΝSwûxíŸzDh`Zßfðøæ.¢©êµÖ1ÍÕNŠ…IA/]$øO~kMÜ>k©Š†,n§{*L„Ÿ€€L¡8¶.°X›`)’'wèui±RðMîBËœí€)ӺȜŒ+ÏÏI•u‰òþØD¬µšè_Ö?‚¯¥É:ÄG¹šKžì_º^_ØM:ì‚cvàÈjÿW dl©}0U² í™èHýiZŸºœÛ©ÈŽîé>]D]"Õº(œ<Ã'ŒÜû€8ífŽP7jR‘LýöúuJý†WŸaf›~úHŸ|ًPuäÀE÷좌b0ºn;}ôy²Ã㕻º.¢kwEþJeTö‡î`F²Fä…©õ kì0{$’gJ§ºè²+:Í‹46™µl}l€ÎÅç Ȟˆù  Щ¿Ó-ØÙÙÃÆæÏߚ©ó°?   @Ä `PÈ9rçϟÿ¿ß| \5¹"FD^¢ÂRÉ\WŒ®`•²È\(¢DªDžëñsúßIÄ6YÆŽúwã·Õ™”çëtâ^þìñú-¢FúS±0Ý]w{ðD‰yg^Ú§÷žêº®ITr”*¬[ª‡K ˜¢,bYž&‹?îoS—ß¹œ†÷ÇÏH–áÏO€ÉX)~µfµ^??u°˜œˆLIçOœ&…ª0ÿà²+®:¥DžîžŸÊ[1h¢VÒó³ɧ¢Ârð ‘ô+‡Nàª¡[±×:—\™ž{á*äι܇7”) ceÏä[’C—?5Ý·!‡"ä原øH“#ëȑÕƏíÇœóôŠÚ÷ÔؔmZ©²gTÂ]²'®9­/67òÀj읿F}Ïe›ÖRE6ûÁåxâz®ÜÔ_=(Ýš†:Ò5yþ³ÇuýãÇ¢w:Ù3?¿ïßþïXhù®LýW©ù'›6À&qTtnÁ;òŠð!ߟ%²gÏnÊ0ìK$@$@$@Š€A!øða\ŒxÑ_È{ŸŒ%: Zô]¯ÌyPšJY ֖o")žÎãç*÷ãªämqK!y§×òIú¯@е­>5P%ü€kA]³[K•ê/‚nÙÀ *“@šDÿ üóbŋ«ï"ù“‡'<_¿…§û[øúøª¹w­u®è±c©ªîºaÍZ÷’€)ÕÛ¥à ÇI^Pž.‰šWíØÿ1îï±"ÏÁ* IDATü}øøÎS]é°äŠò9’DC'»ò–Œ”0÷œÿ¬háЊB>Ìw‚  @ø `PÈ:t—/_F“&MÀûðÅ=|¬<„WÑnÈ|ÍQX¥GG€&ñëÇÎÀýéKXY[+á—&Gf€Í™Íl ¥ì‡€ƒKÄüÙíJ|ÇI˜I3€FÆŒ9 EÒ@ː¬I±˜â-WŒ>}ÖßÿqÝk3—¹ð“¬„Á•lÕðòÄ^P›Døï¿ªê<Œ}á†h1c"qÚêńäÓÊ`ê–ÚORüŸ:¯GÎdÑѱ9…Œ)ûØo–+ìZSț‘}I€H€H€ô ù-[¶àÚµkhÓŠ z†ßÿ§žØþL ÃеðÊ^P¥p³‘@h”ìkGNa§ÓŠŸªÊËür·;IºTHš6’ŠO yŸíǁÐð38琗 d]òŒ[ðÐ ù\Éb CórÁ?A±ßLW8ŽjƒlÙ²E Us©$@$@$@!EÀ ‘ÿrð~RŸ„«q;[‡ÏYó#Gé"áj]\Œez’!‘üž‰*Á®å^»e¬î»—ò|ž<£×aö(€ËMÜû'YrG>Oò˜hßÌžëÁ틥×}ÒyØ6³GáÂ<ܵôœ€ÿ$@$@$`4 y¹#ß[„ü+sðÛì}è=": úO܌ñ3¢À?òpфHÀ è"òÅ2&@‹úòŠlQÏ)çѹk/dȐÁ”aؗH€H€H€‚"äÏÁïÓC¢Ó@`À€-ž7= V)«Áš&$@$`~Œ>|RUë‹gJ»z|JӔ¢7…û’   üHÀȈüyø}z@Š šŒ·c§A¡ªå5XӄH€̏€NȗȜÍëRț²C='ŸCçnœ‘7"û’   è hò͚5Cüoçá÷ñ>ñi à8e+nÆLƒBÕ(ä5ࢠ€ðúðQ»+™51šÕ)n†ZŽKÿM:ƒ®=ú!}úô–ã4=%  0[F ù ðûxÏlcNŽ9N݆ÑS¡põ¿ÍÉ-úB$@š |þð7–.C¡ МUEÍýhø3 y~$@$@$@ÁI@“¿xñ"š7oŽø>á÷ánpÎnÇ:m;®EM"5*„Û5ra$@ᛀy‰È—Ζ¶µ‹…ïņðêzL<œ"mÚŽ!<‡'  ˆ4 ùsçÎÁÖÖI¬¯Ãï݈ÀÅä5ŸŸ—#'GÑÅ2& JÈo\26IÐŽ…Œ)›Ð}Â)ôì3iÒ€1eö%   E@“ÿ‘¿ ¿·‰N‘3và‚uR«YIƒ5MH€HÀü|öüšªÖÿe“Mj5?-È£îN¢gG y Ú3ºJ$@$@æLÀ ßœ{7.]º„Ö­[#ŸÏø}žeÎë1ßFÏ܁sH‚bµ*›Ot„H€Œ! „Œóz”Í™ ÿ-bLWÚþ@ ÛøèÝo(R§NM6$@$@$@$`2ƒBþСCÐGä}¯ÂÏóŠÉ“F„ÆÌމ3>‰QŒ6…|DØo®‘Â#÷ç/ñzÏN”Ï•(äMÚân㎣πáH•*•Iã°3    #…ü5øyÞ 9 Æ9í©¯ QŒÎ?¬iB$@æG@îÈ?^¿çI‰†5 ›ŸƒäQ×±ÇÐwà y Ú3ºJ$@$@æLÀH!~ž®æŒ³ñmüœÝ8á%êV5Ÿè  CÀëÃ'<\¿óŠDƒêòưûÑ¶ëØ£è?x4R€HaÊ0ìK$@$@$@Š€qBÞÏ~׉NÑ³vàÄçž(Óè_ Ö4! ó#àõñ¬YÊR£~µBæç yÔeÌQ 2ɓ'· ¯é*   €¹0RÈ߀ŸÇ5s]‹Yù5qÞû%êW3+¿è  h%àýé3î­Z‰*…Ò ^U y­Ü~e×yôa :ŽBÞˆìK$@$@$ '`€¿ ?«Ä§À€ù{päC”€×@ë»Éý‹×±yò|Žßñ“&6ª/I€‚—€÷g/Ü]±Պ€CÝ*ƒwð6Z§Ñ‡à8l’%KÁVÎå’   „ã„ÈYšÏ]…$kŽM†|ùì…Û˗¡F± šóOCæüýtuCGNF’$IȉH€H€H€L& IÈ_žpvvvˆÛð{ÙäI#ÂSžàÐûè(ِwäe¿?ž¿CähQ=VÌ?nÿñ ;UDŸÑ ®È_¹LDøTžF0[_ŒŒqkéRÔ,žµ)äMÚ§Ž#`Øš)ò&Qdg   #…üøœ¿DzL]肃"䘿ÿðö=|}|7qB +3ÞD fªÝ)³€G»™#þ8À±õ;°eÊÔï×…ª•7~2ö 6_œ¿àÄäi(Ÿ/ ºµ¬lãFā:ŒØ‘c§#Q¢Dqù\3   @0Ð,ä[Žhxž¿wƒÙ…ð9ÜŽE.8ø6:J˜yDÞý¹ÆÖo¯6¡TƒêÈS®ReψÈQ¢ÛÆž=x‚‰¶]‘Ú&3:ÏûÇq¯Þ‚í3– ÉÐÈûwÉ`óAë@r a)ÒOærñö¹’gJ+++­Ãю,šÀ·/_p}áBÔ)•µ*ç·èµ„µóòaœœŸH€H€Â#…ü]øœ»Ÿ„ÐjŠ/އýo¢¢d£š!4Cð ûèÚ-ÌlÛï§Á²΋ì% ª{ê ’›v§S7GŽÒE`7ºÏß¿tvÏ]‰ãúÁŠ„•l?_?XY‡¬xþêåé­z«ùz,ŸÈÇ7O_`NçÁxïö5º:  ÏÇÇQ̞À·/_qmáÔ+5+Qț²aí‡ïØ ³ AS†a_   PŒò÷à÷î<Ñi 0cÉ~ì%×Ò`v&ŸŸŸØ:u!änúïšDé+84@² i‚äè­Ó—° Ç0«]µÿkóÇ1\®ÅޅkÐfÚPd* {æ¯ÆŸÅëÐld/äú«Xæ×ÒéèºíŠCâ4)ÑkÕt}—7O^`VûþëÒþjRU;4×2$mHÀâ ø|ý†«óæ¡^ÙlšY1ŸÅ¯',Ðn˜ ÆMrBüøñÃÒ ÎM$@$@$Nò‡Æùóç¡Rë­îÃïí¹p²ô]†¿„k‡ìDÁ0úí³—1¿ÛP5R¿sàåù7O]„ë±3žÉU?C^mQŽf%£gŒ°ç0V›ŠŠ-¢‚}ƒ?öß鎗;£ãÜ1H›# Š·îƒ'®wTŸ® ' eÖ Fϯ¥ƒó„¹8¹i7lJB‹±þ o_ŒÂŒÖ}ô"Ÿá .È_±Lˆghñ—6$|Ÿ}Õ¹sÑ lvüK!oòvC÷bÜä9ò&Qdg   #…üøœ=KzÌZº{_Z£d“:¬ÃÖäìŽX7j†ºßtøœ‘w€ÏluÁÖi‹ÔÏký×ÅkW6Êá#k¶bÛôŚݳ ŠÕús_¹/÷ä»/ŒäÓªtöcvàÚáÓ(úo”i2W–õ‡«‡Oé#îßy`Vûxýø™ZkÛÐ1_N£ÖMc°tR3⒓•ρòZúrÂÌ???Žî‚ñ“ç"^Œxaæ'&  ?Œòá÷öLøY}®dÖ²ØûÂÊ"„ü¶‹qdõVTïÔ¥ÕDEªV?»ub#wÝã%M„þçENe·Ñ ¹Ëþ9=~ÞÙ8œÅ}ÖÍFÂIÿ8ˆŒ»®áùíûˆ—4±ºÓ-Ft£|ÓÏn?®ÜPÏÞåú«(œ:ÖgŒ¯ÿ«ÁݟœÄÝ W9rd̟S1Ò5O÷wžyâ<²Í÷Ó«Ÿ=?àõãçH•=¬­­ƒä7;‘@HðõñÅÅY³Ñž…Œ)œ}ýüÐa˜ &L‡žqãš2û’   €"`œ·~?÷ÓD§Àìå±çP²©ùGäçv‚»ç®šªò’Î.ë_?}wBDjÀŠã—Ǖ'T„]î²ÿØÜ>E’Ž)U…÷•C&ã’ËÑ@ì~‡pÅà‰žŒÿ8o[„XñÿŒ’öŸ€Ïh<¿ûP?”è¶Ó†!Qêäv(°ÉØÔZ%àà g\Ø}XÔïß …ª–ûåxRlלŒƒ€­‚}}TlÙHýhã8'œÚ²¥Ö@õÎ-ôfr÷xT6*m¿¬mmTigkŽÏì@!MÀÏ×çgÎBӊ9QýoFäƒÊÛ××Fž` ù 2d?   ÀŒòáç~Š 5pZ~»Ÿù¢dÓz¬ÃÖdp%[xúü['2äµQiå6¥ #Mfe7Í¡žÞº÷“@•߉žžb×5ºØ«'íÆ7î¬RÔóW.ƒøIã³çGÀ H•5#ReËšþ¿®-ì97O^À—•ˆ=šúñE—£JÔg)”GýùÛkÌj×_¥ÝKK–>5^>x¢þ¹@å¿ wٍiÙï÷—ÿÝýŒJ©Ci’ Y ¿j"ė ×cþWM2Ì =÷.\Sîµz§N§ŽU–“#k‘ïBèÞÅk˜Ói°²ýÓa1ë - 7I ??}l+çFµòþÿ،'àã㋎#\0qÚĉÇø؃H€H€H€~ `€?÷“„šÀœ‡°ë±J63o!ïñÚ#kµV+Aœ!_N€ÈœÉ2€U©íq'ü©ž[@á+©è"Ð6—Ek±wÁ®þ7êõí "Ï:Ñý+t%êVAÍî­Ô¯tÂw̑õú÷Úå !~ÒDúgátið±ădÈAÜ W1§³#ÒçΎö³GjØ¡ï&ò>ü˜úíõÉV,¿*z÷«7åÅPWM?ZÌp˜0éóØà‹—ÆÖï ¢ìÍG÷QO÷éÖîžc bƍ­Ÿc˔8¶~ŠL†ž+§#RäŸß®7j4&"pfêt4ÿ‡BÞŒß||щBÞ„ìK$@$@$`’ô~oN¢ýÇmÀ‰—>šÖ£ë°3‘”zI­O›3+:έɉދž–&"TRèuMî}®ÛNEø› é®"Ü…|E‡†ÈVŒD„ŸÝŸ.‹Ö©®íf G†|9T€ÿõ“ç¶g¹~Ìá5”8sx=ܟ¿Äž†ÕïÄ_ñ[×Îí:ˆÄ©R ]îlšÖ¡3’»ñr8°És{Ra_®üØÞœ|ÑuÛê,OÖIf°Ô=S×ßyâ&N€Ÿ¥ýrFZ«?Øßntä(]Ä(iL¡Ià̔i°«šUËåÍiÃÕ\ߟù ÓHLšŸ±c?Ð W‹äbH€H€H€B•€ÁˆüòåËqíÚ5ôéÓñ"=‡ß›c¡ê ¥N6oÕaì|ø%šÕ7ë%œß}k†OCžò%ÐtXàŠõ¿sÜç›ú—õOE(Š%R¿nÔLȘÒÚNŠŒùsAwÿ\Òì%Ý>`Ӊt]Ÿ€äKj~ÀˆŒî º˧@ªÉKJºD‡ìZ,EâtÏãýžÞ*ímQ¶éÏÏJU}©®/…í>Ÿ}¯Oë—þrO¿N϶ªðž4ݵÝÓyߟ~ŒŸcpëÔE•IÐnæ³þ>è \˜1M*ä@5ޑòÇðõ›ºˆŸ±±bÅ ò8ìH$@$@$@:…ü‘#GpæÌ888 ^€ð{ã˜íÏæ­:‚¿ €™ y(5&"/+ŸÓy°º.ÑhÛ=)R$lŸH T]«Üº ÊÛÕÅŠ‰ópÂy—ŠÂwY0^‰]¹c.?Ó=k'ééيPwëEÈLE_ÜgŽº‹Þ``gdÈc£€å«Xò¶œˆzSÚÞ«õ™2ŽŒ§«`7Š/r”*hø%ýÆâú‘Óh=u2åυû—¯ãåœÇˆ0>²˯¿Û/õ…ÇÏ©5—iô/.í;ŠªÿKc4ޔ]cßÐ"pvêt4«’ÕÊñŽ|P™ùêƒ.£\0eæČ3šÃ°    è òǎÃɓ'ѪU+ĕˆük y-ßÏüÕG°ýþ”lnÞùœ ×ÀeáZ%^гZ£º“ÈøEòD¬Ktÿø†JŒöÛ0nž`fÛ~z[±‘gít}%z-¢Vî£Ïï> ·Ï\Òß1?twEþJeô։nyÒ.}^$Ϙ)2¥CäšQ ¹è÷«‡OÕW©ï²pŒª ©öºz•Z5B¹fuô©ñº{üºƒŠ?MöØõfŽîóK“ûV!JŽšFùJcmçŠMG³ÊyPµÈüœ¿|C×Ñ.˜:kbÄ0-ƒ(ÈN°#   @ž"`PÈK4^ÒëÛŽiƒž‘Üà÷Úÿþ3۟ Œž¹Ÿx£b§–fJDñ¥ýǐµp^ȲÏ"ÉSVòVûÇ÷žˆ—$â&JðSE|¹C~ýè]¬kß{ VŒÀïʋˆ¿{þ*žžÞÁƒ«7U±9ir@ÐmñDU^KóõõÅãk·‘2k†@òwbÇìeˆ#$ R”Èj8©0«}5¯Ž‚UÊ"s¡<ˆ5*^>x ×ãçô¿Óݍ×ù¡‹þ·×6% iq6$ŠDÈÛJÕz» ò>|öú‚ncöaºÓ D=Èã°#    èò§NÂ¡C‡Ð¶m[čô ~¯’ž‹ÖŖ;ŸPÒ®‘kš9(ðxåŽè±cš|oސ?òԜóø¹úÂ~¿²—l)–%z4õë¯^ÞX¡‰òÍqûbýÁ€¡¹ø{KêùJŒÈ›²^Þ_ÑmŽ ŠÏY‰hÑüÿ}ÀF$@$@$@Š0(ä¥ÐÝþýûÑ®];čü~¯˜2_„é»hÝ1l¹õ%[4Ž0kŽˆ •ûÿ׏ûӗ°²¶V÷ëÓäȌŽ9³ýtWÿ¢ËQ¬2¥Ö@õÎ-"".®Ù œ›:*æD͊ù,Ð{ópY"òÝ%"O!oB/H€H€H 0(äϞ= Žoßq#¿ß«ýá`Ù!¿„%ëaÓM ù'm93è*ýwY0©²e²Çéi„&p~úL4­”ÕxG>ÈßÁ§Ï_Ðc¬ fÌ]šQYà2È Ù‘H€H€H@OÀ ?þ÷c΢°²âßSX²/   €?ƒBþúõëX·nºwïŽ8Q<à÷rÙi °bÓI¬¿ìŽ’-m5XӄH€̓À¥Y³Ðèo ySvçÇ'ô!¿d“)ð/    è ò®®®X³f zôè8Q<á÷r'ñi °bÓ)¬»ô¥Z5Ó`M 0OòŠï‹û»O8õœ9›>G    -ù›7obɒ%*µ>y|_øŸØAp¬Ú| k.RÈk@E 3&pyÖ,4dDÞ€zíþŽ3cö&ÃÎ$@$@$@$ #`0"ûöm,_Ÿ\¥ÖǏþŸ/¶“ž«·œÆšón(Ùº¹k𐠐€yž-Z€„|¢Ø>ð}Ÿ%žæ×ã¬Ýv«ÎŸ`D>\ï2GáŸÀU§ÙšW6;ªÿ7ü/6„VøäÅ[LXx ÓæRȇbK$@$@Ž€A!ÿðáC,X°@»KÇŸÏ7G8HAYðºíg±òô3”lÓ"(ÝهH€̂Àµ9NšS&jT ê†AɶöZÌiC$@fIààȱ(;5úޝb–þY‚S÷œÆÌÕç1iÖZKp—>’   XƒBþéÓ§prrB§N,Aø>ã;žZöU»;õ ¥Ú;h1§  ˜%óæ¢zñLšU9¿Yúg NÝ}è†9k/aÂÌ5–à.}$  °…üóçÏ1kÖ,tìqEC IDATØÉEƒïS>Ÿ£e_‘×B‰6$@æNàæüyšR4êüSÀÜ]5[ÿn?x‰ùë¯`üŒÕfë##  °,…ü‹/0cÆ %äS$Žß§¬º«e‹×n;‹5gŸ¡xk»Ó‹6$@æIàöÂùšT(êV)hžZ€W7ïœÀâM×0vÚ* ð–.’   XƒBÞÍÍ ÓŠMC‡2I,ø>eÕ]-+©õëοD±V|G^ /ڐ ˜';‹ B4šWµy:h^¹ÞyŽe[¯cÌT y Ø.ºH$@$@AÀ õêŠNŠöíÛ#U²8ð}Âb=ZvvՖÓpŸà†"­šk1§  ˜%»K lîÔhX£°Yúg N]»õ«vÜÄš)+-Á]úH$@$@$` ù7oÞ`Ò€IJȧNŸOX¬GËŸ®Üt [®ŒF!‡fZÌiC$@fIàþÒE(3ý[Ä,ý³§®Üxе»oaää–à.}$  °…üÛ·o1aÂŽk×iR$€ïëѲ¯ËObÛ5w²·ÕbN 0K–-FI›dh\³šYúg N]r}Œ{ï`ø$ yKØ/úH$@$@–@À ÷îƍ§„|ÚT‰àû˜wüŽl첍'°óÆ;°kªÅœ6$@$`–-_‚¢Ù’ i­bféŸ%8uáÚCl9pC',·wé#   €0(ä=<<0fÌŽmÛéR'ïcÞñÓ²¯K7Çî[9…Œ^Ž!0OW.A¡Ì‰Ñ¬vqótÐŒ:wå!¶~€!ã—Y€·t‘H€H€HÀòžžž5j”òéÓ$ƒïcŠjÙØ%ëÁåŽ'ò6k¢Åœ6$@$`–ž¬ZŠ¢yÝféŸ%8uæÒ}ì:öŽã(ä-a¿è#   XƒBþãǏ9r$Z·n éRÀ÷Sµl좵GqàþGä±m¬Åœ6$@$`–ž­Y†’   XƒBþ˗/4hÚŽiƒLÒÀ÷# Zöuþê#8öÄ 97ÔbN 0K/×­@ö±Ñ²ai³ôÏœ:zöŽžþ£[‚»ô‘H€H€HÀòŸŸŸèÝ»·º#Ÿ%Szø>bDAËŸÎ]y'ŸAŽF Ž˜Ó†H€̒€Ûú•È’,&Z7*c–þY‚S‡OßÂÉËnè;‚BÞö‹>’  €%0(äeœzõB˖-‘=[fø>äˆhÙØ9+á̋oÈÞ°Ÿsڐ €Yxµa2%ŽŽ6Mþ2Kÿ,Á©C'oâÌõ×è=l‘%žKI€H€H€,€€&!ß·o_ØÚÚ"WNø>äˆhÙ×ÙËâükd«O!¯…mH€̓ÀçÕHŸ Ú6¥ê8~nº£çЅA‚ýH€H€H€H MB~àÀšW¯òåÍ߇ü-ßÐì¥qñ­²Ô««Åœ6$@$`–Ü7­AšžQПYY³ôÏœÚwì:®ÜyŽ ,Á]úH$@$@$`4 yGGGÔšQ… „ïþ‡ˆ–}¹t?®Œ·Bæ:òZxцHÀ< ŒÛŒ)bGBÇæåÌÓA ðjϑkpœïîƒù¿Ÿ°]t‘H€H€,‚€&!?|øpT¬XŊƒïƒù±°°vrÆâ}žþ!2Ö®Ö®5¿÷g/Ü 3¬mm3T¯(äË3z GÑ*åÐæž דµ-Tê7‡ìŒu›–@ÄöõÈm­ÅžLä3zdwº _ÿh þ߂ŒVÁr (@ P €A‰üÔ©SQ³fMŒûkäµ2ŸAàóÿ­€_Œ €X+‘ô]>r{æ¯Æ“‡þ)qæ/Y5?l‚ÈÐpThTžÞåw qñØòëBœÞ~à¥> ˜5E*—Mó¹HªCƒäû÷ÀÿÖ=Ü'7îÆ¡Ó$œeÞ©ŽúŸ¶B±j^ŠG$ý«Æþ‚KOÈïšöê{'lþE7ÃT€R ˜ýDò~ïüUœÛ}7Nž“ƒ¯ÛlrÙÉ:\¡V«Svó*V ïgÉù=cÍøiöñ­\óÁ5o„‡`ÝÄYødÄTjRÏ z_µÓœóWðÇà1ò«ÚmßGh`"‚C`am…Šê¢a§6®;+ Îì;~×ïȪŸ\ü3ò•,’Õ²3Ýüò;Yâó®ŒF>£?…­û. àiŽú#£U°(@ P€H#`P"?cÆ ”*U ͛7‡æÁR@“HÆ7,\s>bP²cGÅY…=Á€û§ÄUïÓVšûq žðzm¬§wÀúIsä÷çüïŠeäkq:þڟt³ÓßoYˆ° §˜Õwdšz ”)ŽBeKÀ-Ÿ'NoۏÇÿúááœñN»–™¶¹|øV|?MÖSõý†hÚ§#Üòæy©ÞŒœrž”˜„œ WãÑÍ{xú(!þ_oVï¡ÝšÏ3ÝC*×ê?ºí §Ü®)gKˆrâL„ãvâêß>šõa4øìí,Òî£| u«PÊËœ;ÖW~° póÞóMBÿ‘ó!â(@ PÀØ JägϞÂ… £U«VЗ“CJHbfüÌÎCè9õ;ˆv3»‰ëëhÚbvÜÞé®Nœæ/ÊŸj×Ú¿8(¡ßO B*_ ^E Á£P~XXZŒ²ŽØšhyf‚h§p¹’ð,Zè?×ÇF¬:&±˜à³Wä"„·}.ȁý6tÙ/È[¬°AýNŒOvŽöpÊífPq|s99òº{ƒŽLs'¿•ËP£„:ÄË52z„7ì>‹°g@ßoæfŽ –£(@ P€i Jäÿøãxzz¢mÛ¶Ðñƒ âôú²õkÊý.:‰£–3ébF=õ&ðS[öb߂5HLH+Õ{W*‹Sç_3‘Ïš!ËQ€ (VÀ D~á…pqqA»ví yø'GÇ7ì9|ów_EÁk%®g+Ð_·׏ŸI‰Ó»BiŽûvPÊ ýæé prÓnŽÖGž‚Ÿ™méÈI²­s'@Ž“ÙM\ÿ>ñ£Ÿ²‘š‹ù^µ˜žHôE‚/’ÒÎ㟖û\¶{¬’¯ÅÙâô‘Ž[»»æ>ŸÝ¯ýÑûhÞ¯“LàÅ Ø&]ÿŸ‰í¡›°{ž®‘tç+îK‡të ŽÿvªÐú’?D¹†µ0wàÿR8ôƒ&û—¬ÅŸEÉÏEûGAñ_»úþ…ýÇäº%ªW”·Ü0e® Ðoâò†€ÄĔµÄ1è6i€,3åÓÏå壷-ƺI³qãÄٔrœù%kVÊìáby#ž2g:5¯ˆfõÓ.fi„]yk!ÿµý4b,Ðë+ÝåIÜ(@ P€ @f Jä—.] [[[tìØš‡+€€ØÌ¶kòåOœœƒŸ–@㑆­Ÿþ¶AžúâäæÝ8ºf[JÒØ}ò(«Zë'ÍÆéÑmâ”kP+S¡.úz†šuKw [1/®…ðÁ nšßñC9pç_옜\ž¹ fçÅ)ú³úŽ’m‹Åõ³÷â;qFCÓÞЀ§nƒ›y œ™þ+†vm€ÚUžxbFüê­>HÐX¡ÇÐÙ­‚å(@ P€ @ƒù+t3‹]ºtæáJ é¿oFcàê­Gúën4ývØ+O1Wª‘8•{åèéø÷ò ]2¹ެÞ"ÜWÝS>œýX2b¢œéíóÛ9kœÙMÔ%êÉzîyQ÷“rvÛÒÊÊ ªÅ†ž7|êY|1{/1DRýâŠOäÇï_ùÊYq1 þ[÷a)§ó‹º –..oçOÐÅ x¹ú5å%âRý&fÇûÎ+?³÷CMEþRÅ…ãkw`ßbÝÌŒØÊ7š%× xqeúñ­{É€òßëåÙß¿÷™Ü¿Õàòø¥ÞÄÚ¿t*o=(ΐøó»©iNáï1õ[žzzà×îà îhÐcÊ·™r'Ó81a& oƒRE_¿Šiõ8ë{³ró)hÕ¶è6Dwé 7 P€ (Yƒù?ÿüSÞ¬sçÎÐø­£3ۮɗ¿{?ƒމ:ƒúÁÎñùboo»ãbõö#«7ÃÎÁ^^ýªëØõ ȉXÅL­˜­žÒ^w‰€8 ŒÅÀ.œÉ╿ÿAçñ_Ë[¶ev·Ñ·Àûà‹î2¶ôn"ñ^0ôGyË<±‰ŸŽøkvÊ,þ‹õéù¶/‘§£‹mýä9ð¿å‹Á‹ŠÊ5fõ%ˋÄ\ô5õÖr`W4ìÜV~tdåfìœû§|-Ny눵No? ëüdä@yœº~³óâ2ˆcëv€ <ˆ»õàž)wÐ߂n؊ßàžÏ ÿk¬»kÂÿ6/xi;‘è‹»ˆÄÀìñ˜7htJ[mŸê#EÄ&Ä% YL0œÇƒû+OààÿÆ`ůœá檜¿Ç”§ôß­Ùêƒx%z å©õÆvì/(@ P@©%ò˗/‡¥¥%:uêßj 1J©ýQL\þÃÐâVTìÚ)Í©Ùo;ÀšðŒû@·ÊŒž»zËÆð®Xj 5Īæ!þAž|ø$.î?–&©M={,ʉÙݲõª#)!QÞr.&âœ=rÿç-ìD›+˜.ïE/N-§˜gvÛýÇJús#JÕ®"gÐÅ̺xˆkçÅ¢{ÑÏ"eŒ¶öòšq­»žOœØÄ~âÖy/&ÛÕ[6‡_õI9?uŒÓ>,g°¿Zö‹¬G$ž"ÑÛØÝËqbÃ.l›±Mz}ŠŠœ: ðÞ¹àž…•%ŠU­ Ôo[~](÷Û×+GžÂùåëG7ïâ÷Þ# âhÿÝ ï‰ëÚõ‹Ú‰z1€qxÅ&Ù1ø fÔÅ)úú5>ý~0ª4k€±Í»É}D=¢>±‰µÄb‡;f/“gGˆSéłúÁ}»ú8õuб(7ó°ÖÄcÛš±wÅ×P©Ì§ßYÝÓµÛÏ *^‹ÞÃxù¬¶e} (@s08‘·°°Hž‘ÿ H|f®^÷;,"ÝÇl@±6"_ e][ªOÌÞԙo'’Ÿ-¿-úÏû©¿î”s}[úDŸvÛ÷ñÑð~o áßo˜:>[÷¿q?±ƒ˜% «˜ÅŸzÔG®@/f£ÅçÝ&ŽDØã`¬ûkJ]/ÞjO|±ð«qòºr1QáÝ:raë7óGÄFFcÒ'ýå~£·.‚ƒ›KJ<–­ÇÞ«_:CÀ tîdÔêà@Ÿ·æ}nÔýxÛÁ¯«ÖGiÐûݝ5žQ€ (@Ì ”ȧ9µþÑZ !"³íš|ùÄ$ Ú _‰Œß“ Æ)i§“ßüç<®>…/ßij§¡)ቅÒD*nCçêåñRØ¢ìÅýÇqç쥔[»‰a‘HÖlõ^Ê­Ý^×ßMÓçË[®œ˜ŒfÔGjœŸŒH~E¢.TÂùåéäö.ŽòòqyˆØR/'öÿ|ÞĔ™fqïø5ãfÈYw}2œ:¶Ô§Ãë?—§ã¯™%“_¿wåâtb{¿_'ÙO±ž\êMÜ+^œÅ`“ËÇ×íÄ»]?’—:€ÞÄõðÂIœ/n“—z€Aœ‘ËÉA&ßâöpbý²xš\LO,ª§?c@¯K×ÉŠŪýúMœö/SÊ¿[;eÑ>1 !ŒÊ7L{¿pqfÃԎ_ÈëìSŸêŸÑcÆrÆ#pó îìދES{OÐ ŒtÃγ‹JDßo(0:†D P€ €1 ”ȯ\¹]»v…æÑ: !Üûšã1w³ïRrfÔT7‘(Ÿê:û×õW,úvåÈ)ÔnÓLÞK=+613!c‘ž¿i‹Œýز»ÜmГàY€à›Š€|/Ö˜;à;¹²œž®]œ†^«M³4×ÔoŸ¹GÿÒ­þ/V™¯ÜŽ>œÜ]åÊôbE{ýmÝR_‡þbâôwñÐ>ˆ—œ ×Èkð_ÜDRÞúË^(Pº˜üJ\>ñª{ËG‡?ӝ¢ï┮c&êLïq6”;*Z üÄÄßœ‰)£Ú):N¥·a×Y„E& ï7 •*ã£(@ PÀH JäW¯^øøxtïÞšG끄0#éÞÛ sØÌýžmw»è7㊱:¿…¥eʂué‰L,žæôóÔåE~tÍVy:üë¶JMê¡åç]á’'·ÁM‹zÃ?Á¿ÄGÇÀÎÑÎyróºuƒ¹czü¶nBa«x|Õ§iz‹rÿTâÔúˆšDôa"Ïß(@ P€Y$`P"¿víZDFF¢W¯^Ðøo⟟ŠEq˜d5S֝ÃvŸûh3Ž·Iöúo±Êü¥C'|ßO^“.îGŸ·ž7ŠV.«š;ð8Ràu×-FójðéՉ” µ;Î :&œ†sF>Œ,J P€ @*ƒù7âɓ'èׯ4þø" °øà,ÝuY®`žËÉр܅ €rNL™Žïz¿‹ê•”µ`§r„ ‹dÍÖӈKÔ ç0^#o˜÷¢(@ PàM%ò[·nÅÇ1hÐ hý7Aÿ|Ѭ75`Îßo>ˆßþòAÖïÁÓÛðë°Íٌ}§”#°cähl™7NvÊ Ê#Y¹é ¶@×/yû9#<| ™ ( HƒùÝ»wãÆ:t(4›ž'ŠìŒÒ‚:z? £ç@éºÕPŒZ¥…Çx(@ ŒV@¬ÅpsÉblš7J™X¶þlmlðÙ๙¬‰Å)@ P€ €NÀ DþСCðññÁȑ#¡ ØÄÓρ‘–è7vÄíª6oh@ îB P@7ùÀáæüúCGedÄQ,Zs..h?`¶÷‚¡S€ ( $ƒù“'Obߟ}øá‡  Ø Ä)©ŠåN¬†Ï;‚Ȑp4ïßY±q20 P€/ ü³z#ÞõÐ`P÷ÆÄÉ€ÀÜ?£`>7|Øû÷LÖÄâ (@ P@'`P"á¬[·&L€6pޱég€ÀœX+üŽå|/]GƒŽÂÑÍŀR܅ ÀÛØ5m6ŸïPê”~ûÁy3ïG™âyьۯFÞ†O P€ €R Jäoݺ…ùóçcÚŽiÀãÐÆ*%~EÇñoœ~?ñ—G¹µP°l EÇËà(@ èVûG‰…îl‰’I©óv£Võ²hÔn\&kbq P€ ( 0(‘÷õõÅܹs1nÜ8؄€66€~<ˆ³ÂÒ»À¡›P°LqTl\׀R܅ ÀÛžå&nm߉=3»¿Ý@L€õñ¿oCóæï£V³ÏM€Gì(@ P€o[À DþÑ£G˜9s&F§è@|èێÛhÚßâ€ù w">&Íú|f4q3P PÀ|ޝ߉Úg˜9Ž©ù"daÏÿ7m:uí‡ µÛda­¬Š (@s0(‘Ư¿þŠ!C† OÂ> )ΜÍÒÕ÷§‰œù&n^Œ…:m߇‹—GºÊsg P€9-°~òôÿšz6æå@Yaÿõøµ2j2Š”ššÕ± P€ (`Ø©õ˜2e úôî…ÂêCdK§ÀÖ+O1c­JT«€âÕ+г4w§(s1Ï"±âûŸ±{ÙP±×ä\Ã&ÜÒç߯ÂO¿­EîܹMž—ì(@ P€9)`Ќ|\\œŒ>ŸS‡¶(ãt1'ã3‰¶’’4èøãV$žy¢^ûL¢Oì(`š—„ïÅëØ<éžY&™f'sžW=G®Á»`ee•Ã-³9 P€ LUÀ D^t~ôèÑhõ~=Ô(ðÐT-²µ_n?‡U§¡f‡6Œ ]¶J³r P 3Ûg.‘‹s.êVÖ*mfªbYQÑqøjò>,\Ÿ™ (@ P Ë Näþùg”/‘Í*ÅgYãæTÑÕ[þòôzuÅ(^­‚9u}¥ŒD >6ËGMÆŽ_¡uAµ‘D­ì0ýB1}Š̘œHف2: P€ ŒJÀàD~Á‚p°G‡Æ.FÕA%ûýϛdᄒŸ¶WRXŒ… €žžÿ®ÝĖIŸÀ^Íëã³âgqù†ÖÃ„ “²¢:ÖA P€ €€Á‰üúõëñøßÓ؎«gô·³ûÈì=vù[~mž­†å(@ d‹ÀÆióСIy|Ùªl¶ÔoŽ•þ}î1þ¹m‰‘#Gšc÷Ùg P€ ²IÀàDþðáÃ8¶wŸëW;›B1ýjƒÃ1eîn”¬RQU™~‡ÙC PÀh‚þõáyËprI?XZZMÜJtóßÁŠvŀ”*ã£(@ PÀˆ Näϝ;‡mk~Ã×=k#—µuQY¡.ßx§/ø¢Õ€Nž¬uSVpŒ†0[ƒË7 ²S"&jj¶ÙÑñ%;ƒáäQíÛó’ªìðe (@s08‘¿uëþZ4œÛU‡—‡“¹zeºß·}cÖ²ChÓ¬2¯…' œùÊ4*+ 2%íã§cõ€(R÷:Ïæ …§ÿˆj5ê¢qãÆYY-ë¢(@ PÀÌ Nä°è×!h×¢2Jñ4s¶ÌuæÒð}ðéŠSQ™«Œ¥)@ dRà̖Ýð óÃoß}œÉšX<€•þ7ë<:wîŒò厠(@ d™€BÄ IDATÁ‰|dd$~ý±Þ¯_Õ+zgYæXÑÍ»˜±d?Z·ª‹…ª#‰·j6ǟûLEÄÇÄbÏO?ã×á jùЈÉT‚P9ÃÀïÿÂO?ý„ܹyЃ©Wöƒ ( ƒyì€ïû JIG4kPN ±u s–ÂÍ{h:š'nÄç2êŸ0x PÀx®mß×àû˜þý§ÆÛ …Fc[ ƒ¿›‹Å‹+4B†E P€ €± €+‘_2wŽQ·Ð£Ý;ÆÚ_ÅÄýÐ?cۊw›×ÅãRŒ€b ¡€ D…GàïŸÇôá­Q¹lA3êyÎtõNd9,X¶ÓŠM˙Ù (@ P€f#®D~ï®Í8}p9ŸÔÒl€²³£k·ŸÁöÑ`p?„Ù8ggS¬› ÀK7×®E>m~ֆ:Y-`a‡#wòáôéÓ1bDV×Îú(@ P€0st%ògΜÁÞõÓÑÿ³:puæéà™ýíÄÅ'bØž¿àRÔ®ï·Îlu,O PÀ`íý;8±t5fëŒü^.—㎆ šrÂÊœAÐh4èÖ­›a…ž(@ P€0P ]‰üœ{÷°vÙT|Òž0Šö0° îö_Wn>ž™;PŠk8(@, P€9  ÅÕY³P¯r!ôîP?Ú3¿&T.Uñó‚šZµ*Þ{ï=ó`)@ P€ÈVt%ò¡¡¡˜7sU²BÍJE²50sª|ÞÊÃØy!õ„ÚBmN]g_)@· wpî_»¹?uÿÎɖ# ò|ÿÿ  @‰%²¥ VJ P€ €ù €+‘LÓŠL@É܁hý^%óUËâžk4Zôœ¡Þš×þƒ,®ÕQ€x.àx [¬Ã˜¯>D…RùI“* $z¶Gÿƒ±`ÁXZZfG+¬“ (@3Hw"¿víZÞڋ/ºp¥õ¬üÝø„⣫Qå£V(Y«rVVͺ(@ Hׄ›5 j–DÏOëQ%›T¶^žZ K–,ÁÔ©S³©VK P€ €9 €;‘?qâþÞ³ڗ†“ƒ9Ûeyß컅_À‡C{!wŒY^?+€Ì[ ô¯¥Ð$$`ÒÈOÌ"›{¯r®€'žàΝ;øòË/³¹5VO P€ €9 €;‘¿}û66­]‚¶õPŒps4˶>'iUèœà4®œ»Ž¿k[›lk‹S€æ% 9ž WÎÝÀ/?t@nWóê|÷VíÕ³nBÁ‚ÑŠ oí—ÃülŽ (`éNäÃÂÂðÇÜÙx§d$êV+fH9ÙÉcv˜4gƒž¢Í°>P©T9Ù<Û¢LP þô1œßó7~ñJñ4Á*šKÖîPçûß|ó zö쉲eË*(8†B P€ €©€;‘Ÿ5kÜ,î£c‹RŠâ ˜~ÿüs.t—ÝجŸ (`ÆJä÷íۇÓG·`X× °¶²0cŸìëú?‘¶ø~òÄ'$¢yÿN°²áiö٧͚)`šÿ^ž‚Ç۷ȅíZ6ª`šTX¯Älü™KŸØ²e Ə¯°è(@ P€Š"¡DþòåËØµm >mèŒBùÝLÅB‘ýè;inÇ¢Q¯ŽppuVdŒ ŠPžÀƒ3çá¿{'ºR­›ðN9q„Tvù¡òl?ÿüIIIèÑ£GN4Ë6(@ P€0C %òOŸ>Å AéÔª\Ø Ùr¶Ë“çîÂÑ+šÕåSä*T(ggk €Ñ Ü9tÁG ç†hÖ œÑÅo¬«ÜëBåXcƌA˖-Q«V-cí ãŠ(@ P@áJäEŸfϞ õ|ւ×\æÄ1^²îvŒŒú-À©V]u³—Dµ …Qÿã÷qϏã-M€wì(ÈÐpœ^¹Þ1øßàÏÓ%3Õ±l:TöÅ òhlÛ¶×ǧӏ»S€ (> 'òâ~ò×.C›ºv(ÉÛ¥O={? ŌÅûŽþ]ޅCérže‹`ÎÐgB•E)`Ü׎Á՝{ðé;E1ŽOSXðN9~@E/’ùE‹ÁÖ֝;wÎñØ (@ P€æ#áD>66¿LŸŽšÅ¢ÐžvQóSHO×lõÁÆ=çP©LAtnW÷ìŒp.ÒV!Ñ1 P '"CÂplÝ$>˜ï qÝ29Ñ,ÛxQÀÒêüí•%†.¹+_Ÿ<(@ P€ @¶ d8‘mذŸW÷bX·Ù +~œ€_@(®ù×n Å»åQ场8ŸäÊëçù£¡€ü³u/.>…†uËâ·þõagkeœVfUNe¡r« ???L˜0sçÎUf ŒŠ (@“ÈT"éÒ%ìÜŽŸ5ˇ‚yyº·õ«ð¹ø/þÜpŸD EÓªÈ]».njœÞV8l—ÈF ûáʑSpÏãŠíë¡k5llU" öjØæÇŠM›d2?xð`CŠq P€ (aL%ò˜ùÛÔ/“ˆz5žz}†B<|ò&Öï<ÿ pT¬Sεë#ÉÑ5‹jg5 ÀÛÐ$ipnÏÜmR%ò&QÛÈÎ^ù¯ùáÖœ@Ü‚À'Ïàäî ûÜn°vs‡:·r熓‡;Ý\`aiad=džY% ÆwÄP ZÝsÊ{ýçúÏtߋ-í>ÿU.ù;Y¿î_º¶ÞÔ^ÚrúötUŒŠ=Y÷«Ëéâ~^ÎJ%õW$ì* ,^1n©Õj‹ §ðóÅÀ< Å£ÀP<Gb’ù<QŒp”+•5+An7‡¬:D¬'§ԖPçkXÚcåʕˆŒŒDÿþýsªu¶C P€ €™ dI"/ Åéõùs[£}[3'5þîÇÄÅãÆí@Ü}Œ‡þO‡Á‘xƒðšxh¬¬¡²µƒM.;ØØÙÂÊÆÖ¶Ö°²¶‚¥•,,Õ |‚<ŒäÌŸZ­{šÔjXšÄ³x¯–§;¹9É×j µ<›CŸ–ñº×*5,Ô*D„†Ã-»|-* ñ,ŸÓ•‘õ[@~'Þ§|g¡B|Lìs%НW%gJE»*µ.á”1@•wòwÿ‘ŽB¥…J«Õ%¬ú4%L•ÌŠJ*¡Õʶ’“`ii!ªÐ%Ž¢ñŸ.ñ…6uœâ»çuÊ6EYƒ|JŽ#9I}¹¬.y[ä³88ÚéÊèÉ ¬n}ÛùRüK·[òsò÷©ßËæÅ÷òI‹ø„$XZšEÉŽee©>KÞ?Íg)m=¯ïµßkþOå-05ٚlO¬ô®ÑjSÚ$-’’ÛÖh4Ðj€$­xÖí#êOJÒ=Ëz’ŸÅë»÷£há>1q ˆ‰M@tL"£ã+ŸUPÉûº»»: On'ä÷twÁÜ(éí‰y]aeÅÁ0cÿ›Re_ *F²C‡Eߟ}Q®\9cïã§(@ PÀH²,‘÷ññÁΝ;1ä³²p±‰0’î3Ìô $&&áIh$ž„Í–G¢áFÎÂðÍA@Ÿø‹Á++]ҕrŠtr®KuYœHH ð‹³Ì¯™qN™iÖÏd§ÞO‹Hq–€.IÖMŠë‡ôï“Öä™vý1IœoêbAaðÊãœRMJmúõÔU?P¡o3å}Ú6ø‡ p~÷ç ò`…n\âÅŠç)¯Ø_”Ó'Þú:^ìxõ ‰Ÿ]9@’<ˆÁõÌáO«Âúhéuþv€ÊS§NEÙ²eѪU+…Ép(@ P€0e,Kä’˜•·£Õ£T OLٍ}£(@3P9•…Ê­®\änìØ±˜7oïoŠ¿v› (ð¶²4‘÷÷÷—ÿCóiëš(ëø¶úÄv)@ P€Ù#`aµWkÀÊ‹-’môîÝ;{Úb­ (@ Pà5YšÈ‹6–-[qšý Oòñ!„§(@ ˜Œ€Êµ:TΕƒ/ŸøãƍCþüùMŠì(@ P€Æ!å‰Œ¯¯¯œ¥èÑŸŠ:û‡£€(@ ŒIÀ&7Ô^ŠÕ±víZˆ³ÐĊõÜ(@ P€ @N dy"/:0þ|@›„>­Ü®`ŸÓ•íQ€ @Ö š<Ce_T.|9hÐ |ùå—(UªTÖ7Ä)@ P€ À²%‘¿wï,X€ŸŸÕ‡·“?(@ PÀšD/y±mذâ¿sß|óQ÷‰ÁS€ (`ŒÙ’È ‘È'%Ģ߇¹Ä(ãbä (`Þ*5Ôy[ÖHJJ’ׯ2eʔ1oöž (@·&m‰üƒ0{ölôéPÅÜx+º·v„Ù0(@ dJ@åR*—겎իW#00_}õUŠêda P€ (lKäEP+V¬@PÀC íPÐÄe&N–¥(@ 䌀•‹n6^mƒÐÐP|ýõ×øá‡àííó±°E P€ (,­‰ü“'O0yòdtü ªI :(@ PÀšT¹ëCå [ÐnÞŒy°ŽŽDŸ>}Œª – (@ÓÈÖD^píÞœGìÇ÷œJÁÆJez‚ì(@ ˜€€*W!šò4“}»víf̘éÓ§ÃÁÁÁ$ûËNQ€ (`<ٞÈ'&&⧟~Båâ¶ø°^nã‘a€ (`Öj¯ÛŒÒàÇDÕªUѺuk³6aç)@ P€P†@¶'ò¢›×¯_Çü¹3ñMÏêðrÕ(£çŒ‚ (ð•S9šÜêÈo·oߌ7Ž^ (@ P@9’È‹ž.]º!OƒðUçrÐÆ(¢ó ‚ (𒀥=Ô^–öÆ·ß~‹aÆ¡lٲĢ(@ P€ŠȱD>22cǎE‹-О‚ÚèûŠ` (@Ôb&^ÌȋmÚŽiðòòB×®]‰D P€ #c‰ŒèñÙ³gåÌüèѣᡟmämÅ@0 P€ €Ê6/TâÚx;wîıcÇ0qâDÂP€ (@E äh"/z.ù   Œ1Úð ІžQƒ¡(@óPy6ƒÊ®îß¿/Ï"ÿ­*SЌù‚°ç (@ (R ÇùøøxŒ?•+WÆ'Ÿ|"O±×íS$ƒ¢(@óP9–‚ÊœŸìð˜1cP±bEùß)n (@ P@i9žÈ ___yÝaÿþýQ©R% 6šÀJ³a< (`.VNP{¶,°hÑ"„††bøðáæÒ{ö“ (@#x+‰Œ0Ú·ovìØ!ïÍëììÌdÞÈ~8 — €) š<Ae_ {÷îÅ®]»0aÂäʕ˔ºÈŸP€ (`Bo-‘†K–,A`` ŒµÜ83oB?-v… €qšœÊ@åö®^œŠŸþ_ý5ʗ/oÁ3J P€ ÌRà­&òB|Ò€Iððð@Ÿ>}˜Ì›åOŠ(ðöTÖ®r•ú'!‘7nZµj…f͚œœ€Ø2(@ P€0@à­'òâþòâôúwÞymÛ¶MNæAžË€ð¹ (@ P ãª=a2€¡(@ìx‹ßV_ƒ›Wy¶7 P€ (`ÌŠNäì¹sç0oÞ<ŽnÝZ>ÄŠžmÈ)cvgì (CŸŸ`îêÓ(W£zöì™C­² P€ (}ŠOäE×ïÞœ‹9sæ B… èÑ£‡.™¿mèéì“aÍ (`ô'ÏÝòõÇÑòãŸhÛ®‹Ñ÷‡ (@ P€BÀ(yhxx8~ÿýwØÙÙaàÀ°··‡6ü<Ž¡gy$)@ P€/ lØuûŽ^C÷ž}ðNÓ®¢(@ P€&#`4‰Œ×h4˜?>îÝ»‡>}ú dɒºðB}MŒÉv„ 2.‡…kŽ"8äú÷ê€ÂU»eŒ2–€(@ P€ 0ªD^ï·mÛ6ìܹmÚŽAóæÍž`™ÌkcH̐(@ P §.ßðÃò 'Q¬pôêðlœ;V.9Õ<Û¡(@ P€9"`”‰Œ¹zõ*–,Y‚"EŠ [·nptއ6ä4Ž—sŽP€ €²Öî8ƒÃ'n íûUЬaEš\kBåTNYA2 P€ (F›È‹ŸGFFbÙ²er1ŒÎ;£ZµjÐFÝѝjŸ<¬‚ ”.ð¯ßSü¹QܖT…š¡PñZPÙ¬œ•:ã£(@ P€0êD^ßã`óæÍšR¥ Ú·oGÛD¹¢œ6úA†PXˆ ”/ ÕwÅã×ñ^£:hס;Tŕ•òƒg„ (@ P &‘È‹þaåʕðóóC»víP§NhÃÎBv><,J P€JžxÝëwœ†£':u¥ßQb˜Œ‰ (@ d‹€É$òzÃ‡ËÙyooo™ÐçwÓÍÎ#!<[Y)(@ äœ@HXþÚy—ï„£MÛhña‡œkœ-Q€ (@…˜\"/\CCCe2åÊÔšQï7©í-h£î)„aP€ @zââ±íÐüçªÕ~:v““SzªàŸ (@ PÀdL2‘×±ÞúõëñäÉŒ÷Þ{šWɹ⮘ÌÁcG(@ ˜º€F«ÅÞS±ûèð.‹?þŋ7õn³ (@ Pà?L:‘×÷ÜÇÇ[·nEBBš7ªŽ%’Ë"’? P€Pš€jì?†}ÇoÃÑÅ ­Zµ’w&áF P€ (˜E"/t\\Nž<‰Ý»wHBÓZùQµ˜œìø; (@…Äisá€Ožº'çÜhÑ¢jÕª¥è(@ P€P†€Ù$òzîšš(œ>}ûöí⟠fi[T+_ù<]”qD(@3‹sÀîã~8væ. (ˆf͚¡zõêf(Á.S€ (@7 ˜]"¯'‰‰‰Á¥K—°÷fÄG>B!OKÔ®\%‹xÂÂBýf9îA P€™ž|8rú®ÞöG… d_²dÉL×Ë (@ P€ €) ˜m"¯?šIIIž~ý:Žه G·a¡y†w*çEÉ¢žÈ›Çٔ=ûF Pà­„E&áðù0ø\z„ø$KÔ®][&ð..<3ê­6J P€ €Ñ ˜}"Ÿúˆ=xð@Îҟýç0Ԛx8&¡jÙŒ(RÈî.öFwp0(@¥ÄÆ%àä¥`œŸ‚»#P¶\Ô«WOÞ"”(@ P€ @ú˜È¿ÂK\Gûömœ;w÷¯ aÈë”/•…ó¹ÃÃÝ1}Êܛ €9 š-¡²rCt¢-þ¹øç.ßÃÍ;~(ä]\&îõëׇœ=GÍé'ÁŸR€ (µLäßà___œ?w !w€„PžØ«PŸd>ðrE~/WXYYdíQam ŒEÀÚU&í°v¬\ñ0àÎ]ŸƒË—/ãþýûðööF•*UP·n]žººK¯'(@ P€PŽùtžÇCœ~íÒ)øû^*) I‰ (QÄÞÜå5õ^Î\,/ŠÜ•0" [šl<OšluÏÁÁÁ2ikÜºu bݱX]¥J•äì{®\¹Œšƒ • (@ ‡ù §ˆˆøùùááípõâIÄDŽ@ 1Qƒ¢…=P8Ÿ<ܝàáî'Þ«>ƒÌ,F ŒM+çä„ÝK&ðZK'Üœ{7oޔÏâl%q)RÑ¢EQªT)¹ê|ñâÅßfÄl› (@ ˜…ù,:ÌAÿÂÿž|/âÖ_ÄÄÄA¥VA£ÑÂÎÖ…ó»ÃËà n.öpç\°Pó6wYÄÏj(@,Ðϲ‹™öX­|ïÈÓãřH>„¿¿¿\YŸP¡B(V¬ʔ)ÃÄ= ÜY(@ P€H¯ùôв\B¯!88Ož†â‘ÿciëԕHŽA£F«V„'ŸÅà„VöSÿ^ŒÖ}&Ÿ×}'ßˁ ýç¢NÝ÷úòi÷ѵ—æ{ñ^ºèëK~­5‹·,Ñj¡¯eÜh5ú^hMòŸúº EBB",-tgT€ôIwžÇ­ŒÜBÖ+ad„ò³”>ˆ2bpG«…*¹ý?ù^×oÝáeuÇY÷šS‹°ðhž8åÒõS÷3Ò?%¿Q¥}ŸŒƒn×äÉ-%ÿ “ßé‹?ß'4<nÎÉ×<«€è˜xØÛÙÈjd+ú]UÉmŠ|ô<}âY_FKSF…°(ž»ÚC¥R‹¯äC–Ð÷1eÿÔmé»èÿLœX.>! ¶Ö–ibNÝþëÊ¥AQ𛞞DDFÇâYT,"žÅ""2áÏb DÄZ"Ôjµ|è7}’,žEÙߋÏôuÿן/~§/“ú9%!O•P¥ŠÖ'K/ò‹ÏeR›j`CÿZėº?©÷}]™ÔŸëÛJÝö›^¿îûÔ±× ^ˆ?¡òsµn`#å;µøN‘.v1Ÿ€IJB’Fƒ€Ä$$$%!!A<ŸˆžøDXšU°±±D.{ärtƒœ“]Œàèì–’Ž»»»ËÄ]<žQ€ (@ Ÿy#:f"yɍxˆä_<ÄìœX%Z$s©?Ÿé}}²(’‘¿ø¬ÿL$ÿ¯ÛçueR×'(_¬ÿÅ$WŸÌˆ}_õÝ}.ú+,^•\§'!7¢CÎP_Ðd¥çِ}Å@™þŸæ¯ÛÿU]©?¿OñgH¬â.fžS˜‰?©ßëÒRšœøYê÷ú?7âϗhC ؉AñçA âèÏÔ+ċϹQ€ (@ ˜¶yÓ>Ÿì(@ P€ (@ ˜˜y; ì(@ P€ (@ ˜¶yÓ>Ÿì(@ P€ (@ ˜˜y; ì(@ P€ (@ ˜¶yÓ>Ÿì(@ P€ (@ ˜˜y; ì(@ P€ (@ ˜¶yÓ>Ÿì(@ P€ (@ ˜˜y; ì(@ P€ (@ ˜¶Àÿkšðl¬¹c tEXtapplication/vnd.excalidraw+json{"version":"1","encoding":"bstring","compressed":true,"encoded":"xœíšÝvÚH\u0012€ïý\u0014:ìm¬éÿŸ\\\rþÉØ˜Ød°\u0013Û3sr„h@AH²$þœ“»}ƒ}€}Åy„iÉ\u0018I\b0qpÂæl_Øš»Õ]ª®¯ªº¥Ï{†Q‰§ªŒ6*jb[®Ó\u000e­qåUR?RaäøžnBéuä\u000fC;íًã zýË/Ù\u001dŠí\u000f\u001eîR®\u001a(/Žt¿?ôµa|Nÿææ\t•\u001d[^×Ué\riS6•Dx±öÜ÷Òi!\u0007DJ\u0006\tœ÷p¢#=_¬Úº¹c¹‘ÊZ’ªJõã¥dü~\u001fñFíÝMmrŽ\u001c5³i;Žë6㩛Š\u0015ùúQ²¶(\u000eýŸúàŽã^2÷Býª»BØíy*Š\n÷øe;ñT×\u00110¯|PÁk#«™$7!NM’+™:’û©0q® ¶ סïúa\"׿@Z2ÉZ–ÝïjñŒvÖ§cµ\u0000 YŸñìi\t#ŠÌ—yžrºœ8éBy6µJ\u0017€b \u0011—<{îdŸàŽÚÂ_‹\u001aìYa0ÓT%•+'kryŒhHycÊ­ñàÚ­ãð¢ÿö}4=?‹;ˆ¢Î|¬‚åYaè+ó–/¯ÖÛœ?è^’\u000f˜Ž,\u0016úâw›]Ô\u0007[\u0018—¶ÁiíþÒ»9áœð\n;;·\u001al6îìWŠÊaж\u001e¬\u001f2*(Â\u00002A²år\u001d¯¯\u001bœ¡ëfuŸÝπÙË\tü•€bº†TŠ%CTnL*¬åÍ]óÍGð¶Þ\fÚ'„Ÿ9?’Tú$©˜¢5€\"€LÊ)E@l\u0003UH-«Õ)£Š\u00017A®@^f\u0015QºÈ*aH0ÿ9X=\u001ažœ©nT{?è_Ÿ\u001fßüÎގŠ÷[\u0018·\u0016zï\u000e¯Æ·\u0000:ïO¯î&SëðbžMVsVö¬Æj\u0012/ÃT ¹\u0012S&\u0011Ē\u0000º1Š—Vp{U?³ý‰ÝoÔ&b\u001f\\1°\u0002Ӟe÷†¡ziP!x’T‚¡)²\"‹ êF–+\u0014}\u000bšqhyQ`…š†2¬%t²E8!&\b\u000b\u0002ñ\u000bDÒmÚc¶ìŸ\u00177{•ºœBí\u001bkàžÓÂÊ¥†ª%5þþïþmL(Æ¡\nãŒV#¥'O-T\u0014n«ºN7±éŠ«:Ec\u001d‰Î›c?\u000bš\u0015[‹aéáÂÓöâãø¡Óu<Ëœ\\!Ò³€Ó®uu\\D€1\u000eøæÀ\ršþš~ۘúÎqË\u0019‹Æðð7ÑÝyà0‘kB#DÛÌb×\u0012‡!ބ8N\u0010C\u0010ŒD8Ü5àÞ\f]ÛñSûv:ššX\u0019ÕaÜÓ(èÅÝ\u0019\u0006×Jù,,©$«°”\u0014#ÌÐæÉê'\u0010Ži݊0èžN¯¯>YoÎVAù]’ÕM”ÀD\f\u0010ø\u0018æŠAPïøt¢Ê\u0019Ç\fBž(×vrUDh\u0019Æ|ž…?\u000e\u0010\u0014z÷€f\u001a›Õó?=ÃP\u0003Ëq_[ž§~U\u0013k\u0010žj~”2Óï\u001cÄ\\òð=@\\/àó\u0018ä«sQB“l4\u001f*ž¢ðÜ=žx×j^\u001fIwä\u001cз¿Mh§Ÿó\u0014b“Hcò‡\"\n\u0014bÌ\n\u0014Ÿ\f†R”)D¥\u001d\"€PÈ\u001f°EŒžrG#\u001eWokûãëªÍnÆ^Çúa[®ocŒ1l¹Žmœ©ˆ¬9iÖÒ»öԇR¶X;G8\t/\u001c`²y ¥N5Dƒ\u0016`ã±\u0007‚îž\u0016vŽñnŸúHÆLš÷Ìp\u0016J‹qTçœ4\u0017eó‡€Ï \u0018!ÑRlÙ¡O&Ô\u001ca˜³ËÇ\u0013Y‘\u001c\u0007¢ïðOpjBriIéԄr\nŸ*RU¯úwÓc6¬…­“›cðñSÔ±‡»\u001d©\u0010€ÔÔú\u0016ŒÐô\u0000³`æ\u0002š\u0004\u0011\t±&!Ùޑ\u00171s\u0004–DªrŸ(¹PäÝÎO˜..Ý\týé\u001dhuªÂ#</ÚúéTø\u0002\u0001æ\t\u0019ׂøà\b–ÈsQrDB±\u0010:Oá\u001bƒžÞ3í$ˆqhr>{‹P\"\u0011\t`\n\u00008’œ\u0011‰„ø¶×\f+Q\u0014ÜÄ:Â0*9Jʒø£\u0003#’”s-\u0004\u0001H”_\u0010B„©ÞÕ1ø¿²±‹b+Œ\u000f\u001c¯íx]ݘ…ºÇ·Ü§\u001bŒ»JÙ¶‡‰”z\u0007\u000e©dz\u0015šà\u0012`”ëÓµ‚TE&F\fϏªgíó·\u0014\u0015\rÒÓ\u0002­O«\n\u0002i\r\u0011Ê\u0019Ô[3‚\u0005g%‰ž\ts\u0005\bV\u0012ɵ¢øÐ\u001f\fœX«œá;^ŒšÞTÕ„ðž²JnD?RŸmÑ\u0015\u0004ɈŜ#ûedŽ€\u0017óßœZÚ{¥\u001d'e¿lÂÙx{ùÿ_›NàÕé\u0004\u0013Œb€àæ\u001f5ôïãÓúIãSïš1Â5úñäü®ûC?jXæÄšÉ™Î!„ÞÇ\u0012A ,\u0016¥NM«Ø$\t–’ ‰\u0016³hd›ÚY\u0000„%\u0013\bÁœÏÛŠSƒt‰\u001b+\u001f\u000e# ÷4\t\u001b™»í¶žw\u001e¥ƒ¿ag\u0011|\u0017v¬%™ž\u0005\u001f£kހrÉ\b\u0012ró\\~\u0014·Š\u001f‚þ4h݂Ÿº®WÏìûó]£oÙÙ/ÕŸ[\u0000š\u0014T M›¶©U\u0000˜Îè‹_ûlóÔiù»ÏÒ±“v\u0018É·#òÿ§NƳI>Œ4Ž'±òRûß\u0005Œ\u000b\u0002í=j-ÕXÅ\n‚fœ°ý˜Îè\u0005wÚ³‡Î†­Œ\u001c5>Xö\r[Z’QS¿\u0000š’åþüeïË?\u00022ó"}C‘ç€IEND®B`‚fulcio-1.6.5/docs/img/sign-certificate.png000066400000000000000000002546221470150653400204560ustar00rootroot00000000000000‰PNG  IHDRíé9¿Ø IDATx^ì`TE׆g{6›Þ{£÷Þ¥éˆ(¢‚VŠù¢HQE)‚R€ ‚ô"Ò€€wÒûÖïÌ&—ÒËnòÞÿŸ/»÷Μ9óÌ%ærFÀp€€€€€€˜$Iz§@@@@@@@D;^0Qí&Ú1p @@@@@@ Úñ€€€€€€€€‰€h7ю[       юw@@@@@@L”D»‰v ܈vŒ     PþK"f„ër˜`:N­//`ºÇìè„yßµL ø÷³>OÞ3-ÓäyÂsƒ=Á¶¶z„ºÜzòMðÞ,eÓêëâ†þõãߢ<Ÿs ŒÚðžŸyžéþ­K ÌûœçÖÛÊ«‰±‚Ï ßóLéiórçóÈ3Š{ܯ‚Œþõ“·¯`?äñ1À,àG>Ûüçy}¥!_„†~Ëã!ÈóC“ç—0÷»&þ¿~:Ãà7gýž_‚<>ùïLçyåŸC¹v5yõ²~ž òýÌ}5™!¿ÁO­‘_û^è|Ÿô/A®ß†nå/|þs¡8÷³:ïŸ@zòëÍž—ŸðK£Š.5<˵®Ö>îGþûeš\›ëµ•¿Ò!Á¡ùm"_ ÚM€#à€€€€€Éà3PªCɝ’ %KJ"JB‰o;ÒNíÄα‘H'$¥”+–H ‘ªâŠ%WŽðûB^8‘ÊËœ:^ÔÑ}±XK‚S+ò(/•0FBºÏåŽ^pq"úNåEÂܟ\äp{$²„ú²ŒN*Ê )¿Ÿš\q¢÷-ÿâùô7é!Õ¯7f…Œ~òM$ÖêŽZ¡@ßž—g¡Ï\Ðé4ýOœÉ\GuZîÍõ#¯Œ|®xÍ»opÂPˆd¡1ÔcpŒ åÖEöèYŸ÷ü>U¬ÕÑ=ýM=s=}s‰•–|¢n ryuåÛæu’˜£êôýó¯Q£È\02PââyÚWïO!—áñcÏI©òw‹ÈêKp¶Ÿ ®Ñ=Ò»”ƒ?ãyž}#¿ùG}9ÃE7š3r¿‘ýüúø«È‡@šïujúiÈCï/¢·û9÷å¯–ZŸ÷0ß·Œr|@†ûÆßgZÈ4J!Siš³sè³ZšÕ©è§FšÕR]ZúÎ}Ò䈸g~ŸiŽzÆíÓ}úÉ?Óû{×Uê蓠Se繒câT áQ,3>†œJ¥ôˆR0¥ÈŒï…¢®Ì›í•I¶A@@@̒€šAßç… ]ÔÉ¡Ÿºì GIôG~85&‚’ŠR¥dJ–Lîä uñ+v ˆr­)zBڎëVþÝ :žˆä’‰îý+rž ây¹hɕ׻©¡Œ™Rº¯å3›úg\Ñ3ý (ÝãeHEåÎNòÏü™áŸál <ü>¿øl%]48¡Ï«VUî åäÊN_AàëëÊ+“+ìô”]o;OŸp›zŸõßuFåB‰F«!1iœ7o@n;õ%rŠaD/ïH1E>(¢d|û›+ ù ‰Áž@¢ÈÑå€ëÅrÙ.ã™é‚ à¹R«2ƒê5¬v0 lpMž¿â_yËñsŸå¹Ÿ¿Dßøža0#Ï­¢È·G¢– XŸ¥æƒ.|…ˆ~ÙzîçŒUŽ¢‚7º¯_y‘{/÷™~E„þ»^\ógúŸüyÞwZ¢·G?õyhu‡P(Ñ1±„8ÿɿӿ?þ\D?ÅRZÌ!ÑÑ¿Ó'C+[=±Užz=8vÓ€t–ќ2¶ŠÄ·ÄpÑŸÒJ| ¯R.ˆöJÁ £    fDÀ‡Dú<‘¥C ¿vɶ]_œ%u­_i€›ž  P€,< ÍòÏöЧGÝó_}s˜ÒJÙ ¢œ¢‰Â€€€€€ù°v_,–YïÞ6Çá)€@u •û µî·‡sœørù”ž£Ä—™üLé÷Šô ¢œ"i€€€€€yš?`€8áÖByӁÁ΃çÝ0§á%€€© }÷5ÍŸ°9Ÿéä[OJ(ñYøÍ”øør_íåF    æBÀëÝpyò¹¹Ë”±÷::þà”Ü»e…üQm.퇟 •C€b:œ ÎL;ɂšøR £(ñ`Û(…”·FˆöòDy³!`Ùbðz*§ŸûøÇÌÆi8  `hÉ|:…d<2ˋG–“’œÒ¯”î”§í塇²    fC@Þ ÷,V=ÜcÒÖßÌÆi8  `v(X]”Z£ÞþžÏ0r^Aé;J emD{YÉ¡€€€€€ù°vŸ.÷o;Ðý¥¯ÿ0§á)€€¹à‡ ՚çøŽ 6ØSâKå#ÊÒˆö²PCs"0DV¯Û۞“¶3'§á+€@ ðÇٞþÔJk(e•¶Uí¥%†ü    æDÀ^dã~Èkúá£"…?K€T)ìÐËáQ«‡zP¥‘”6”¶rˆöÒC~ó! púÁáé@µ]§—BÍÇix  PÓ$ž\+Lþõ#5µë ¥‹¥iD{ih!/€€€€€ù;ñ׏[ç„^âûÚo×bˆöâá9€€€€€9p&g7x}|ƒT&oaNŽÃWÚC ꫃UY)+5Ñ·(®ÕíÅÂss"0€œí°$2” ™‹99_Ajø=ó[eG܌S…ž›X\«!ڋ#„ç    æDà-Ƅ¶~ËÂ¥BÆð·®9õ|ZD é÷uu³nš“=~`€-ªéøEV‹^ 4@@@jÅ·úÞ3Nðeòž@@À$ dÞ9áœøÛ²nVÏþBâçœnBŽ›d7Á)J °Ú¢ók—=†è[ ¶a@*„€2!Â"îÇwúÚô˜ŒìÑÆ—„h¯¬0    `¶Ûøô”}Ç0ÓnA ¶Ðd§ˆ£¿zþYë>Ó%lšž¢œ¶Ÿ h7€€€Ô>{œ_ٞϺi_ïÚ×tŽ@ÀœD|þôH˯,KÞ=ó;ˆvsê9ø     P»ß=ŸÍÚ£AãòAYšl_*®Ûs]æÑe_AŽW6mØ0§ìýÎÚ» D»©ôü(”@Äê!Ã-êö\›zìÓ5íxI@@@@j _œ^ٞÊißzµ¥Áh'€€yˆX9p„Uóá+} Ñnž}¯A@@@JOàŒUÏ[\Nw)}Q”ª#º°Ã«²Ö£eÿôkˆöªãŽš@@@@ª—ÀiËº žíZœn v(š@è¢dÇeþºt=D;ށÚBàgûg–ïŽï2ºAmi0Ú  `žÂ?í=Úº÷Œ÷·Lü¢Ý<û^ƒ€€€”žÀN‡a‹wØ=õr£ÒE ššL:§}í ÏX÷ž±ú‘ÂéQu ÷²¶©€m/OŸˆÏúŒVFß®/oØëO÷ ?.«­ÄƒŸ4K>þųöOÏÚ^ñ_ÖúËRΔû¥,í)ªLʅmŸ7Ô·hùܒäßÚ[T^ÌŽW4}ØšN{­†/XáÒùÕnÕéDE֝~m¯Ç£=ïÐf$:Ûµ0çGû^ïܭȺ ³•C{o#¿hÝnÔiÇAó®—7Õ~)mK’Ÿ¯šÈŒ÷{€¢õšÅ¶LÚÑ^jÈ    Pìµòѧ.Ý&ô¬ I»ºÛ3~ûŽW˜V#–×ë~AæÛ2<íÒO4I‘ž$z£œçœÿв—>gŸ·^ó쁅MªMǗŽ©“Bíµ9L«c– {Ý炜‹?eøõ&<ÇÛ»ÖÉÜ¥?Ú=·mêÙï9^ý­uëá‘Æý·}ZçôK?õ•8ú…šBüŒËUE¿•€MUáGÁ: \ø}›Î¯üê4|Ñ¥²úñh_P«ÔSë†J\ê>7ìyS“n¯UeK™P€±í6ñŠeœ® áË{Ÿ(IÔ^ïÞ^ÖzJ[îÑî÷éœØ8ˆ „ZÇgþ`Ûñåƒ Sí—Ò¶±$ù“ޝnvÅ˪ÍÈEñ›&„h/ 5äš ~’øh…{¯ }Íœ1šôDIØâNStÊt+»ÞSw:ôŸõ7o“21D±€ûtŠU‹]^üjUË¡QÝ֔ÓëêfþsÚ_“g§N‰qÖŠÅ;ÿ§¡X-¯ßý‚û„MG49i¢Ä‹Zç_¬£hùÌUŸàÑ/ŽIýcÃ`çV®·nó\„qù̇gb׿òªóKk¿Ïº}ÄÏž\E·Å`¯Žmª,?žd—o_òÔÛÚ¬[žÇžÏKâ‹V«e‰ûþ×F{ÏE“o§JŒt×å€Y,+˲ízOÞgßçÝ[Ÿ?=Ráî÷á͕%©£¢ò$XS?óïƒMÅö Ÿm#Kó®U”Õm'ñðò&ª˜œdíž_œža\‘Û °<Ÿº{ õƒ€€€T$}òA Ý{Mì_‘F«Ã_rž~egEËa'\_\sÊØ‡ðeÝǪâî×±í5y—ã€Ù7Êê_ÜO³îœhN‚ÑQdã'u®aÛó‹1k_˜ü›"±JÐéšÔ³y„ŒNÇhY@—‘TŠ-¬nŸ_7ë֑º™7{ÊqhЖ².¿æ[²Ã¯žJœë%Òrê0¡H¬+K[ÕÉѲ°…mg—§Me©·4e¢×¿Ü/ëαN™uێƒ?ØjÛý{%µÁ…pҁ…£ æÊmS,:ސùŽŽ°šÛ%FîÓ*Ő'ò‹!Ïæ„_kâ÷I肊\±Áqb¿{u€2掿.'ÓRìà%ójL3ëtäß¿qÊÚ/Ê€ ±[NY߇’2­Ì| ¿.j®LvŽi÷â‚Ø /-ª.ˆöÊì ØšjûäO¿¿ÀœÏ[«ºâЬ‹ž°ZMg±Æçƒ‹+ œK:úyã”Óßöq|æãŽ'ù±¥çÜMf²8á—ù2oi§UfYJì<£lz¿sܶÝè0ƒŸñ;ßkŸvnó€ÿø-–e‰ä¶©L,QKëDH\êÇ¥þ±~°ÈÚ%Îwþ•¯‹kgæÝ“N1ߟø¶!ŸÔµá=‹zïJ<ÇËý:>*IÔxuZœ4vÓ€9![ìˆìœ#ÜßüyKÁãâxÄñä#Ÿ6UFÝô`BNdén÷ôô+R¿,CYÎ#jõàµj¥€,m* ÏâžõœŸg·ù‰{Ÿp©oëûWw÷2ސ|É.ãÆ~›®¯Ý~Òqy™÷N;ÆmykŽÈÒ>EêÖ ‚iµ‚Œ›‡º@0ò«Cržkí5÷ü’âŽáÓjԂÄý¶Îøë×všôGXš#¶÷ŠV4pÝ®_à߯¢ŸÏà+£þnôŸz‡\Æ|¹Ý²nçDÃ{ZÚ~ÉŒuÌ%fã+oHÝß-ž¬ÿÑŸZŠ]ØÖ“|:ç2ê³?ËÓ'•]öÑ/ó[kRbm¬»Nü0fͰí•MöA@@@L…À.I¯™{˜6ÔT*‹i—öŠÿqê\(b{‘û] Úω¹mýõÈqžÎ‘ DÔ2S¿Lš–³»œ¶ùkŸ—Y“™"ûžõt*[nÓyü~ûŸÓÿ¢œÎºô‹Ûü“ÿX߃¢Ô»»MÚö%ÏËí¿_wŠ@ªÈôûßõ/ŸÔXKâÞ(IæÑ85z͈‘ÊØ;õ Ë+È3éŒöHëίüiÛùå`C9ƒã‚=rÕàW4ɑŒ„! Ðê„0OŸl\Ñ€ÿi×qëì*ãXFó‹šä(~O ±ÈbB©Jlçç:î»]R§…{A_JÒ&^Š$<ËÒdž2|¶9âóŸ¯Sœ…Ûk[ÖŠ_Þѐï÷wŸp“mçqÁ<Ÿ~F<ìJ3«¶Ïqµâ¬q}|EøòîoØšû‹ñ  ?–:Säïcùû’¶E/à>í9I›þȉ ~Ç疝ÛzdÇn|µ/íïlÕ~ôo.Ï/?§àŸÁ©{ÃŒŠÛVÐ>ß7ÏË ERýrôÿ5™ª£Yjÿ…÷–?ɗZœ)¶vN4Ì~êZ;ÇÓ²ú¿µY©–ê”hzNÚÌ;:¿=Ùç­ ûžÍcå • A·ñwÈÜŠçD\³‰\5d*-±Ÿé9eÿ.îCNÌœx~·eÕnäQ‡Ÿ3®ŠíÜsø’ÿô ۞–ž6žçx|ëý-A›Jʳ€ýS0߇µ¢ß tÄ[ÃvC0:ÇK7Úv|1TϟØjÓâ\ FâçÏøÞèä#Ÿ?§h1ä€ëد7ÔaˆÄ.%f^Sü\˜±'ôâ³ñîoíZ%”ÛšbÖ¿<†„¹;Ï+[d{N?ú_ŸžóxUbš¿Ïgî]^Ùx˜oàïIÒޝ2h„ˆúÙûýó_Ç~?©þ]k;êpa³ÝÊø`˄Ýsºg_lî¿øÁ’‚~÷®|.+ÁĎNyN9°JæÙ$­¬ýRåâwÎnGQrEÏiÄ­èUhtƒíUÑ#š@@@@ ªìdßø_À𞫪 +£ŸÔ9æ›Þ¡ÈßœgþþCIëˆÝüz÷Œëû{ðhì|‰°Ì»yŒ:)Â&õÏÍœ÷I‚Ä6[YX]!óOӋöE÷—=ɗÐEí_Ó)³,ü‚n¬æy2ïŸuˆYûüd‹:/{ŒñÓcGZñ%í†ýðÆåÔ©|ïyÇ@Šh®ôœzhÔµn†¡ŸŽ+»=¥ SøŒ0¿±²ÿóʈmºNÜë44èª!_øò^cT±wõ³üŽÏ/ßhÛ~Ž^øþG– M%åYÒþ)˜Ï Ð-h6Ü#o6£•1wëú|py‰ØÚEɗ•G~Úg†Ô£É¢Ž3.§ŒŒi˗t‹lÜ¢}?žü͓ڪQf C?h0Wâl|v|ÊÅm> ;ÇÊñ}ðŸsÏ­/ÌNqm* ϲôµÞןfœÂËZљì:­Z€zôЕ¢¿ûóm üŸÌ¯ÝuÏ·÷ì ž[wŠN•eé5çÌRãœúŒRN~9œçÍÝÎÐí‘Á—œÈ›Ö‘+úMç1Œå¯8ˆÞ0®¯eœ.Á<8`ÌÆW{ó`<¢ŒNcaÓíõ_œ†Ì¿Š_Ù°rл"Š…àûþ…u†’' ‚Ä¿m·wgÞ<ؒ"vj€Á·žíÓ;¥_ÚÞ¯° …Åõ‹aŸËKk¿±j>8šÛL¿qÐ-î‡IùöïÙgVñ÷¯,}R•eb·ŸÝU«ÕíF, ŒžßèrQuCŽWeÏ .Ê&°µ5+`ôg£*»¢Ê¶Ï—ûÆ~ÿÚXڛî uot×¶û€3ÖmF†êåŽE g¥aÆ:áà'ÍRŽÇlì IDATñ¬uDZG,¹rv£öý3~Ž/\mÙ {ˆqYÃcyÃ^Ž÷÷‡b÷þ†òÔ+ª„`?ßo.YÚ©¹¡ ÚŒ®ÓjD~ÿ»¶†7ˆ)Çá‹i/öËúœØçøÏY9%øŸqݓx—#º°Í F³ÊŠƒO:þòTaÂyPސ9~ˆ¬]cœf_/)4ÉG>kBKòsŸhþ.: Œ‡†–”+Z =á:ö«ÿì.®M¥áYÚwÏ‚ÓJЉŽ2Áò±²"©R jžh—y·ºáöúö_DÔ6ØÐ/¡7*§$x~KŸ§œÛ(m>ŸÞsÏËó¢µËëuœè>édžÙiþ¬à,zèÂv5)1n|&~ÇôžtÊ@GûeìsâáeM’¯Ê·;xLÞ÷]ô×ύáFößßfßó­ c“Hïj2œ«…ÍŠ×/vÏk“zö»ÁGÿÇ¡TÅß³M<üé02S¡h6øwחמ,mTG~ŸŠƒi™Àù¥¯§…ÌòºV”íÕÑCš@@@@ ²ìc͇ŒôÕŽŸª¬ +Ó®òQˆœ"‚RFü՘1€„QíÙÕh³’m™F-at ›ûë;×ÈýÛ&ÄLI–fX¹04ì/ª†%É|fÔªÃØ‡Iµâg°‹þü¥ÖFKÒõ,9ÜÓoáƒÅO:ž«`9<õôº!L§ ‰R·†Áäg˜eã~aŒ?#V|Nqœ ÍçètZÓš€|¶Ó³‹·Z·Îgš£×>?°£ëkÎcVÿf!œž6•†giÞ}”÷&œD{ümùÒu‘Ü.CêÙ4RÞ W8͖˜vf}݄œA/Êö<ç>aóoÜ6È»iâ8.LRy&?U€ow Éò=¯d\ÝÓ«° Ž?|Š6'ÝÊ+ð÷υb™6vë[Oó¥åAmXöN+bŒfüÖø”‚üœõtôœÄ»yBÌÚÑo2­Z,q©÷@ìà§ÍN—«âîúéã(ìÝ_ÛúœÌ«yjè¢4I^6OMØç4ì£+…±áG&ü8®°U$Åõ –Ÿ€óیނ¶)ß—– zä¯6(M¿Te^> »åínB¡€¹ŒþjZðl¯ëíUÙš @@@@ : ìc}§Œ¹ñÅêt¢¢ëÎŒwÊ)åĚvʄwmZŒµb;ËÆ}oؘ{·ÅóĬ{ñMŸÜõ•õ,öŒ’ú ]kGœaÕbè)ZÞ^d,nC/€O­ÆE™WóŸožÿZ1\/,é(®žSGyL=ŽÎ ޓޝnúç÷ÝœÞ=ºAdi«Ÿ¡/xV.åÜf¿äã«{k’œŒóS$ü Zæþúö]$Þ$q[ß€ŠŸS‡óžÕv<ïžñ>gÎ$nó[cŽ™Év$"÷; û0_D׊Òð,isÁNAÇó¥î6]'íåKÑ –M:º²QÒoKGJýBi©÷FÃ󜈿lâ~œ:Dw?€ÏjËýÚߎ4ï 謘ucªÃÜ nˆ\=ô™œÐË-xp6>“ĵþ}ÏéǶðwF?xsëHg—WÖ}cÕ€¬±/ޝ]¶žódE³þt|ڊ³)ç¶øÒÑ]Ô !>Ž”^Æ£ÃKèüuEËa—l{L¹mXñ¡Ÿy?²â9çÑ«¿µnýßãyšœ QÄòìzŒuÔ¶Ëø‡Æõ×/™¢¡o)T%±ÏƒÞi(À]ÁãßJÒŠÒðŽíþÆœâüá[hu@C‡~{ž”?íòïøíÓÇS; Aýгû€ç|p†"¿ª£ãäD^tdÞU‡As¯Nà唱÷ÆÿŒm¥]Ýí)’Y©hp(Îø>Ÿ)ЁݓÞŸB€šãöŠjOIúÅPžGßO;·É?a÷û/?iDYÙUf9> ·ûýNb ëlç៌÷p¶÷ ˆöÊ$Û    ŠD`7³š?#`Á‰—MÉ©ªò…‹˜øMõÇxý['͎ÓÒzÃwÝ .c×n5œ‹^RßžmuB°¥afœ€åL9_qmªhž|UØÑ;CêZ??*~a|ø ¡…•ÒpN{yòY]Mf’€²XÊãcÁ²Åõ‹qþèõ/Ñ@ÕñNîoý²ÒxûDEúSѶTiÑÒäß>oÉ£ÇۏútzøLŸ¿!Ú+š2쁀€€˜*œÌÂmJÀ‚ËãLÕÁªð+óáY‡”“ߎÑ$G8é”ÙR¡•}ªÔµQ”¢Ù€‡E-›¯ ß̱ð4Í^ã3þ¡AÍŠ‰IÆ[ LÓÛœâ,l/ÈÔÏ~>=l¶ûMˆvSï5ø    PQ~aÌbJÀ²ùÇ~U”aØ0-)§×éƒöŽª3-ïžì:)Ê"þà¶bKûLûá‹f‡ºß‚h7—ÞƒŸ    å%ðx7`Yäkå5„ò ŠM@~|ôíz>ï_\ng³hòã“~]Ô^(·ÎvŸtFè{·!ÚMû]ƒw    G`™šâ·éÙåã>àÒ}-yÒ2>ƒ_¹®µE¬¹BH Õªu$M.ƒ/†[…§öiIs\—êw/¢&oDä:ü†>,ȋþ/E=~_/Òÿ}crsæœ •ãöIìjxŸÓO­Z] N²cx±ÇÀkác $†uú}œü'ï8CÝz?Œ®<¿ž/ü~p;$°ùíü6ÒJ ëÜ~žxºÇ?“§ÁšÿHÏP S•LœÅDéJ&ÊÌf¢,%&3YR&“Šg1ij“¥ç0)=“šÔL”œÉ4Hg‘Ã,”j&რTÆB̔4sŸf#cI¶ öˆ~Ÿ<òwaÑ~N,©S#OI4Ÿ$ÉRÊòN  €˜äÃLÿåÃé?ô|²€˜Ÿ<>aßG$ö^I6æFÌñŸ_”ƒí•ß}T㎔øgWJ|©–AŠÌÚÁš©Ý왠Ž;Sy91¯+ú:3‘—#ËqŽªì"šÐÄ ¥'©Ô㒙49IîEi­Bã˜MT³ŽOeÖÉéÌ2-[¿RG¥T1©œ‚¥º:°ú=”àãÂBëÚ³°.MYšA̳‘,µà ŽÒ{„  P©žhÏoYÔ`å“$ž@ Æà"0ê‹!ã­Z;ç44èjo°™7P-‹ßõ~‰³¢íÀ¹3Âgù<€h¯ºNåbÜ=/¹ä‰u5ý±+p¶a Ÿ·ÜÁ–‰Œí pgš:nLWÏCÈü]Y†‡£HYun¢&xœ@DŒJ/ŽŒöPëð0š9š·MHe6|I>mCžÚ±$ú]õšU‹«çÆBZÕ‡Ñ:‹GR»/‚%÷xŸ@LŠ?òm®ß²ðŽþ‰O˜à2S±[Þê–qã`‘KœÔµ~žÄÁ'QâZ/Á«E¢Ä«EJa«ÓÌŽ©åv;éäšú|ŽÄ¥Þ}ï™'·”Û T*uZœ4þçY]¥îcmûLŸ6Ç÷!D{å!ç+dœ(yæ u«:.ÌÂǙÙÚXÒ2w!s€eìj?7¡’–ŸŠ5ðbiõ=EØOZyýË L *A%œ¬Ï?`®÷#™3‰yñbŠ©‘C«ƒ’ZÕaQÍ|ٍîÙ%i{€àxÜ0 P\°ù/ìGۙøjG\fJ á׏[€œZ7˜†cËê[#Ê3¥® Xµ}îªmçqÁfÚÄ s;nûôN闶÷“8ú‡xÏþãû 3 C•B@“‘(‰ûñÝîR·qvƒ>˜:Ó­ÈwËãKß VTė'RìnLíëÆœ­™“XÄ\}œ…i4ƒžÜÔW›ÜÌW˜^Ô>òÒW  PýîGiäw#ŽÖ'o1¯{̕öÓ[ñ@ŠŽ€>ÆÃ–]¬ïÍNL\ÍnŒWPýžÃZB`µsŸßòˆBÀ­–޹Æ6S«Q Ô)Q‹Ÿš)oÔçO:×:C•îšNŠtÑ$…óÉ3&qô uÿÝO4ŸQ B‚šœcß{Ê!Û®‹Ü‡\ŸêˆúúùÁÙζY»ÄùοúUU֍ºJO@“™"ŽÛ6¹—Ô­aŒýÓóЇÌq)Ê D{Éó &õH€×ñ÷dN$Ê-)³ƒTÌ\œíX¶“0µ‰KîØP„ÀM%ã‰\ 5ˆ@DŒFvùŸÖîÌmæù †9ÓI6Ý>É֊·³ß֟d× æ¢) ŠO`;¹H3í])úš‡é» ‹#qÍ&rå wmžzu¿Ó°— ù3ïŸuHúmi·œ‹-„ ‡÷7~Ú(sk˜^œœò>~¿îL©g³»žoíÞ[^[U>|éS¯šâƒýD6®±Ÿ\ùº¢ìÂNåÐädˆb7œÞGæÕ4ÊaàœéÁ¡íec-¥Èì óál0ˆöö…nne-£X{:çŒEr§ãŽ™0.UhMQÜSÚÕÓÆvo.LqtZ «B6š’24âWµN¿ýÅî„1/µ†%Ѐ艐P¶'$ƒÅÔ h$€@UXK®ò[юúô«êÊQ_ÅH»ŒÃ;þÇw_U4xÊõåu' ÖÀ—Ї̩û>Ͷ'úýïښŠ÷àq‹!¶x›iT¿n­šìºJjÿál¿9ä“TÐñŠç›;÷•ŽòU~Üvì÷zÉÜÄ[öš=-jžg8Dûp‘ÎäÌM¥•ž{HÕáV8k*—1%užœÁd:„ºM‹íۊÅÙXŠŒN¯žÎE­  `Î2³5j=Ž\euÃ♣NËBèžËœû/±ØÿnÎ= ßAÀäl%û/j)ÐéꘜwpšÔR.nóIØ8^Þ°÷Y÷ ›Ž4~ã [ÜŠ‰“D^ŸsÎm(u…H¿¶×#;üЫĹ^¢u»QaB‘XgÈÆE»N™má¿ðî§ÆEÓ.n÷Ézø§—uDZ·äŸm“+’Úx8Ëk>Óév}ßýÙ¡_à͒–CŸê#µîŧeM¢­̙ùžWD{ºÌB“"ꕜ¡óýñ­÷…»B/O{m E{g1IB›Ö,ªo+mt€›$»úº5ƒ€@Í%Ÿ¢‘l=©õ=|5NIgbgö{K/¶%è'Väò°šK-š@\ް$Œ ëU ]˜ª&i—öŠÿqêyýçÝ'n9ÄÝà³ëÙÏ;€œúŠMÖݓ˜N+,L°òó˓ÖJ“eÏ$J‰W’ð.?éž8~WìŠIhŸ|KCsEöÞîoþŒEjï¥×Æ¢ÛO9ºªEæc-5©1úÀ‡…­H:úyãÔ?èŠIOpZÚ'éÏSöáC)§×Օ×ï-u­›ÁmÆ®=’"ŒÛ9ýp—u›çò&3Yœ°ï£vê€pG±œg¢]¿À+"…³2ôý€˜P€ñ™wi©ØÚGIWÓ»Zšj£×¿ÔOêZ/ÖºïŒw"æyGBŽÐmf6‘jöÌOg„Mþa.žڔ%+µBQçF,jXQli`#/€€@ùü~CåðýqÖôA,s•KØßŽâé‹_/²"Ï+-_(  Pà l€ö}æ·,²1ÍÇ4¬ám­Í3ìig"±Šf“…‘D©Óš%ÆGÁ)Z >é:víïÆ@ølyüŽé/êTY–tHœN ³JgZ•ز~KNc֜IeZãü\°G®üŠ&9҃‰¥9t×uB˜§6+ÅVÑ€ÿi×qëD»63ÙNêÙäŽ2òfCœ$˜úžµé>éªÜ¿C’Á.ß»ýåÐç”Q7â÷„–¶ÉÚÌ;þÙ¶ÇÛ»ÍýK«QÓò~ÿyTß=©¶G~ÚëeT.7¿]’Ïüë_ð™þœÈ›ÖÑëFÓf$9ìKœ‚Ý'íØ¶°íl¡µsŒßüÊßP+^º*hdô†qœÅüÈ·þ³&‡¿çўG`ódæžÊÞŽzžÚjÓÒ²…v –5°6ŒeIZô ªxØ$tͯÚÇn°&LÇþNÉ`_ލbw @Š МžÍ 4’Úð'ý\NÑãëQôø& gþ2os‰ùîå7‹j‰Aòè—Ôïœó¢@,SÚõšŒßŠËøû"™BñYŸ”Ñ·Xµ}þˆËšgmF~1äٜ°+ÍDÞánã7îà‘èõ‘ëW ™*ójqÓsÊþ]¯XîÏÂf•í ìW>¬°«¶Ñ_ žF<Û¶Û€‰\­N‹±RÆü㊊ýÇW›‘èÈœ°îøÒçŸ\Ô䀉Âޟ¢SgÊ]^Z·ÞªI?ýJZ~ÌVXPó@:ÛB ¶ÈöœõûJÒwujŽ,laÇ@>‹ï9õПLÝвŽ+»=¥ SdnôÇɅ|ÔêMmZœ‹þ9ÍÈ{Í:œÂ`ǘFʹ-Ÿ ;g£÷P«hÚÿ ß64«.L=¿¹‹&1ÜÛ°GŸû:¯á<>À˜N ŽrŽ÷˜²CÆåþt€ÝHëö/R4y:˜\p¡ï1íð†åý91·­"W ˜ÌƒÐñº]^þf­U³AôZù¯e¹kˆþáõbK‡ Çg?œ2Ë¿È>« ¢œ^«6bP;æ–N3랎ÚÔ!m„‘¢¬r“†J%°j¯ªÎ/çX“Ä vóf[B•%Vj…0 `ªø¬æK”ÞŠäJ‰/k¶ ÄÏ6®_Àéïéû~KÂŒ„BQþŸdSmü*ž€&=Qúa³¹‰E–ÿ¢K –H¹°Í7qßGÏê” Ïw¯È»ê˜ðSàž‚GÄÅn}»kÆÕ=œ å-›<ý‡Ûž Çø÷Ì;'œc֏}KdãíûÁe>ôÄ+tqÇW¹èæ³áü§ñÒyãB¡‹Ú¿ŠIŽòz6œ­ŒžÑØø™ÈÎ#Úóíœß‹íÜs ƒü¹@j™á6iÛ·<~ aAÛÙrZv/qò{”zzÝPûs~ŽïõŽ~ [£ÌF­0Zw¯®Ô»åßÊðkMy^÷W7þ'X_ñ”‘£ª ð÷Q(Uä8 ]0>øý€"·h×dÑnOà;?ӁÕmäÃêҎ6ª{ØØK”?jVÕƒú@@ÊF`ÑUã]2>cvôzû„þã•Å·lQ @À ðóœ)u€4„ԔB‰ïS·¢ÄÏ¢æÇ{ýY -üìì5þË"ÝèwE3h'\,ÑfŸßùX$³þÏ©Nñ;g·K;÷Ã@>+-õnÃgž-êt¹äñƎ_¹èŽkN—Œû»Óñdû^“$Z2‚iµ"ÇÁóŽí:á~``a›L­”ñýñΣ¿'ò†uäŠþÓ¥Mo{œûÛ>(~uw}]N†LêÓ*Òæ© ÷DR¹~O=:O{ïÇóώ#–|oÛqlˆ¡Ÿ f“E–v)$ÆÿJ=µv˜ÍS¯îw¶à²2öEì¯?C+ êÊüÚ_ó|{÷/|€.']áó¿¿>3Ø.Zd©&±?NíLŒë¬F-|)vfÝž¢Üš©¢œ-5ÚBæ+— ëéÀöl&ÂìL5œš@*Š@à·ª6Go°ºNr¶áÔ]¶¥¢ì€€Ið'/žHçéiJ<6ÿ[•GìæÇxÑ$ {‘éÿä=Wˆç|–ôߥá."°œIŽ N”‰€2öŸ‚äKÕCIjhI:ÍBiY¯Û#cƒ<¢zÔªAcù~o»ÞSwÚv{ýNø'ßÑf¥Úò™k*[Σˋ¬]cÝ&mÙ̗¹§œÝ䟰gœO:U»QG‡-Œôےæ4›=„çågŸKÝËŒ[…Y6îfد·mJ—ô+;ûðpÞ³Noҟ!¿=ðŠÓˆžOòz]/ºOúñ@æœÓŽ1ߌðŽÄÁ7Ì{ÎY>ôċ¯Ïä7# IDATà+€^ÍnyM=ô“qF Œ÷lNԍ†./®Ù·iÒëü™Pn›¢ÍÉPðxRÚkïþÆO»ù~}¡>é·åÏÛ?žÃŸÏ»·Ë…ªŒ@ìŽÀŒ2ëáœ3·^|Q×4ÑΗKõ’‰Xêà¬×³Yêó]%En꯲^AE  B 5S#z}¶Gä#Š{ª1ûxùnöw…†ª&ÀgÒù,:&7œ_îLjúRâË÷QÚKé/JüÈ+Ÿçs%.€xY¥ÿÌžÒœ”Öø- w „Ü>.3$yç8-WçÁçtZ²£ÓjDÚôxgEËa'è˜,8Bík·VÅÞwUF߬öIœë<ôœq|3Ÿ!O¿yØ5á—ùƒ5©Ñ®B©eŠÌ¯ÃMççŸÛžçpÈm”tlÕ0þÝeìWßY5é›rn³_òñÕœ5Iá^ÆØžø—8„)ÚšÀƒÎY·qÊa臗WDóÂ@™wËðâê3ÃW¢Æ¹¿{n[mF²¥íð¥#£‚<6U°±5IŽó‘T;9ŽïËZÍ!ŒvŽ¢ˆÖžNFƒ@@ ¶øîˆÊ‡v"vñqbçvÌaKƒYþ;µ Ú&H€o[ìFi ¥N”PâAäø¶E~¶õuJP:Ié¥äŒ6,£Ÿ<ÈÜJó)£B‰ŸÕœñ íü–îã¿$ÔV w1Ap©ôã7Ž{ Ôb³ÓQpòzÝ.‘>VØÒù¢ÊÓYèV-(x¶yæœSN™wNz)#ox©Ã]µ™IvtŸz²×Ô›˜DNKàs—¶.L.åø—­Z?ûPêZ_¿7éøêI¿ÀÑY6î{ÖŸÏ”‹æ©êä0yƵý>™·7VÆÞó³èpÃ}üƣŶ“2ðz˜J%Y9šJ’yL—@üÞ VêäH;‡Ñß<9×+¡(Ok‚h—PQÊq¶f_œÅ¬†v” Ȝ韟ð @*”À䵪öwÙnjØ7-š³cÎÃŽð¬PÂ0Åð¡=)Y%Y›Ï {SâgJóÈÖ|«"_òÎgÑù÷›”øì#ì…]Át“ÿg˜ñIŸù¬(·Éžtñ™ø¯}—E(DLPTŸb† ÕK +øŒ}ÖœSš”x+­2]ŠUfJ™*[Â$*EÝ&áš)vôOV4é]PtW¯çÿ֞tteCšÑnˆînˆoÈAñsìúî²ïùßò«H8ðI3eìǑ†Ey¹•ÛÜE;_>Å#@Æ7óaòË«DŽ_EȗVášEœW9/ÜÉú>݊ýõ¿ÅÛÅ9ꋂ‘zq€ @ ò ô *æP²£Ä£Œ{Râ³Fw(]€tœé%Pã3ë|†™ãÑâùŏôâbŸ/mnG)ªˆféE»ßÒh ¡@Ëp@µP&EX$^ÞZuۋÅY äÖŽ×=Þ²aï–-†EòÀuÕê *¯ Ž=C|ÙÇyüƁas|‹\-h΢ÿÂæ#¯cº³˜SEü,NqµG¥  &A`짪ž9*&ùn û9CÂ~ñɰòÊ$zNÔp<×AJg)qqΖT DÃcTpñϏj3Þãy‰ŸóÀZ×(}Z Ïuôü[ÿ¥aR@ăÚá“#ôûWõ²ïŸõs}aý  Ö Bý4WÑޏZϏ|ĺ7µ%Án®m1¹€€9àg»ï9ÇZ}øÛÝ« Û$xZ¿g€€i˜Dî­€Ž›Ò˜®~LßùL;.ß¿Íà3ík}?‰ŠDŒÿ͈ @LŽ@Êٍþ×÷5‘OÚÒ;iv~œå/sºÜßç)),=y›X­c‚ú&×p@@ Z \ ÖXO]«øL'vzÖHö™` K­V‡P9€@Qøz˜ŽGz¿U cWúŸRSJu(•$à$?î¿eá:!z0Eiwx§^ØÚZ1nk÷Ä zEþbN¢ŸÓÈG^“‡Žf ?Ϲ Býٍž@@@  µF0êíOGùÍlŸàYý[\ ŠC€ó¶ƒ?ä nñó{( Ž¹„®MùÖ,cL,âÁŠq€€ÉH¿ñ«[ò‰¯:ÛŒ³­Ë£÷¹¥È\D;?&€?m˜Òmx—åŒî&q69êp@@À$ LþJÕ>)É¶¿ÇÃôg@ãš~üX·”žpÿý îl€ûєxyœ®€/·ÆwiˆZ$ -i!䁪$qïŽcÒþ{ÛNÚÞ>>šIzQu›ƒhçG†ôñtbn痱x;‰Œ*a¢.ó'ŽEÕôòCæœû}6Ùr‹0ÿ¡ `¶øl{)ñ€r=ŠhÅ»ôŒ‹úö”—²µ|Oû—þŸDš"À &G 3â†UâÎÀöS·ŽÙ¢Èø;Š.ÚyБ}Z²ºæ‹"lÎäÞ58 fC`å/ªºû/±& Ʊ™Ýÿ³oÖlÚGAÀŒ p±Î÷˜¿@igíèDÏx„x.ÚùêJŸDŸ4×”ù3ïea* =Wš‚È  UE@eýí˜çœßÚÖ<*šm‘¿çLYŽÛºÛ²Ñƒ;°ú_Ÿ)áç|ârX¹GUïÌmæ»ò5ö¡ï$v³\ÆP@ €x¹ ”îQj[L!!=WQâ³åë)ñ#äJ{m¡K}…ªÄñÈÒF~š šÌqԗC_P՛؊yÏ,÷Ž;ušË^kSŸÕ]1QÂÉだ!ðÝ•ÏOgXˏ^f‹:ÏП' @ òðHîã(œCiM ªá÷ñ(Ê<˜ÜÏ%È_X–ïéæRÿ%‘j.£ J'ŸŽëË*Ïn­ÙµfwN»µ»{md7VÙxÉÕJ'… @@jõ‡5Ÿ¿œ×6ýb"ûŒÞ›ìd­€ƒ@åàA„ÿ¡D!ÜY›V÷åkN‰G”ÿ²„e ˶ny-WIű尃¢  P©—÷£JËîÎ2CyÐÍ'^ж<žGøjÖðë·%W*!šÕÖк¬mŽq:[å:–§ÿ êj54*ŽÀ*2ÅgÖÿGiA ÍrqDéMJGJXæIÙþ Ó|‡&ŠÅâ—Ëi ÅA@ Ò„.jÿª&)’yyœšJLMŽؚùíù@Uid`@@ò¬ =îÞeŸÛÙzÙßìˆ ˆi@ ÌdT’ï[ç`u(©Khɟò£ÄÅþ–)*Ûiz8Õÿ㇠™l|؃ š!·™ M‰é•÷»ó‰u˜’hêåÄZßýJ-‹0ÛQ)¯Œ‚€$0u­ª}Z6“};EŽ]ŠÖŒdP(5 *ÁgÖWRšVÊÒY”ÿã ìŒjŸ~¶ç’ˆl™PðZ)}Avššìq䊁#Õ !šÂ"ÿö0Ñþ”LÌ:œYÆ2›ûIðÇR•Œ&š@@À@`ÔRU߆,&h¬è˜4Nó«àu}ôj\ %#p—²ñ=ìüτ’ÉÏNŸvSšRÊrEeçöÞõ]’#’J^¯@»0 F +ìªí£íÓz«âîóXE^Š Ú“‡}×Of)/õ’H‹sÏA@@ ¢ „Åkd3Ök»÷h.|ðÎ`á!É0õ‰Š®ö@ àûÖù’v~.ú+¥lŸ/å¿Ei?¥Q¥,[\vîÏÿ…U©Œï‘Ç &G ùÒNÏŽ³ßÕW…_í^œsÕ-ڝÉÁ1û²à/ߒžç,žƒ€€@e8|EåŽék:¢#»=² ûB0œyüJeù» `&~'?[RjEéa)}îHùùlx(%þ¹¢¯­dð »Q +>°€ @LŽ@ÂþZ(£nвîý1Ž8çª[ŽOs¶bQ‘›D &òÈñž@@@ Ú¬Ø«©wþŽÖgÖóìÇÓõ¢€Àãž§¯Û(í¡ô\áÌ⢚’°Œå‹+¶Ž2ü@ÑãoPôø©ÅeÆsš±›^ï¡Iïe^Û5±žú«SŽ÷&ç:šw‰njB×âÅsš o®QuÒª™pÛ,‚ÒÅWEš̄ÀIò“ÏŒ÷£tª>£²üX·ÈrØ(ªè§ôðžsPÜïÖ U`%Õ³  P.Qk_è/èp0ýðò‹3T]¢œ9öü÷“Ù…Ñœ$Å9‰ç   PUFiäó6k;ûž²kŸía‹«ª^Ô&L ùv˜ÒyJÅîœ4vÌ$’YÐÍïvsMÀž PÆÝWÄý8íiÛ§WÆûâúâðT‡h· §Š>Ր?ŸPT— …•µ4ªž¶ã9€€J`û•Çá‹, KÉŸþùOv˜@ ØImFi ¥fûڌҜ€e‘Afâ3ÜšER/ÿì•zæûvîSöÎ éõkqM¯Ñ>ŠTº]Ö.QŠ@ Ž)ÎA<ê ðÞFM«ÛaZñ¡«ì ªǑVG' Îê$P—*¿Bé:¥®ÕéHênGexÔøWý—EŒ/`ÄM*Dš<ñ{>h¥ÍJ¶tóÅÒà@OŸ]šÈ«ªE{òæ•3‹ÙíJüŠsÏA@@ ºܧeòýší–ÀœœÅ6W—šªÀ&ªó%Jüìô/ª¡þòVéEøÑyþK"Ç „LQ^ƒ( E@«Q ¢¿1Ôªý ׬ۜž1d–;?Ã€Dû‚~­ØÙýó%ÞÅ9†ç   PÝÖÖøŸªuÙ}N¿·œŽÇZU·ûšJKÀ“ \£”H©Ai ›Xþïȟ~KÃ[ B{ó î€Ôb™·Ž¹$XÝÑyäò£"ç€ÝŽ<þÏâpTåLû@™5HÛ)zD'|ȋs ÏA@@ÀŒ÷ªÕ ,ên [` þÀš$«È.?Óü#JA•TGUšå«Ä~K#²„N)ªJòš @ Hq{ƒZjRb¬Ý_úúŽZ Øèq¹8dU%ڝɑwÌgöi%q/Î)<S!pì/ãúߎþ?ŸeߓOgLÅ/øDÀ–ìüg« ýL­ »ÕmŠ-90Ñ{$öÞüïP\  Pí”I¶OïmÝæ¹¿íFÝPf°o¢‚<2‹s¬ªDû.ö,-bƒ{ŠŠë<09ÿÛªi¶ïŒöÑßaìó$jLŽ3ªrP|ï÷jJ|fº&]Rj̗öýgÇÛ÷ž¬¬I C[@̗@Ò2nhäúêÆÝ:K˯#Š{óíHÅ^U!Úýɋ·"6²C.¶ˆ€€˜[ł­Ú&;ÿd?“ã‡ÌÊy8 ÿ%ÀÛœMID©¥ˆ iŒÔ¿Ã³^oí2¬$š¡ÍD³@́€&'Mûý€~òúÝþ±ìöƜÈ÷ŒJü»·*DûŒú®ìÜß_‰ü™@Xõ™CŸÁG3#ðùMýÇµI·ÃÙFr=ÒÌ܇» ` À÷­/¥ÄÏ_çâkòå#õj¹Òö© Ömž-ñÇ5Ú P}’N®©ŸõÏ©ëþoÆ1ìji<©lݚœé§Ú->§c‚ú¥q yA@@À”ħh$SÖj›Ólû~òkŸ)ù_@ „ø¹ëõ(u€t³„eÌ:›Œå°eºÌ€®·a…ŒY÷$œó& Œ`™°A'‘ÜaGúåí¥>J³²Eû¢Öžlï¹/DÍ0ËnÞ/Œ`lÕ>MÝoiïD±‰G˜€€™E~n¥tÒ`3ñ¹BÜô˜öÛ3‰¿'¯ßõ¡}÷7îUˆQRˆÛ>œ“2!$N|ŸL+œ*SŽ·£¶ ÌÚ%>-ꖲ]È  &G *A#¥Ùöf{/ê÷µï69áü—Àït‹Ï¬?Médmä³<ªMÆù­ïdÜ<`×ýµë–Kô©¶qB{A*@Êù­>érÉ œ0‰j‰*KM•)Ú¶òdûÏ!jŠYö²t ʀ€˜"{4õŸþMûèaŒ~æ2Ü}„O @ºS:Lé<¥nµšHN(\]gŠ@$mî1íà‘HêMQ–,k54@ J€^Ùã‘uë·º !KYÄ_eÞŠSY¢œ Q¢Ú%>¥Ã,{•Œš@@ j„ŪdÓÖ³û/êÑÞª©µ€@©𘠜)œJ‰oåÀ•Kà]J,H·ÄÏ2|”P j0  PYÒ¯ïwÏžy0@dër>õä7óÊSOe‰ö÷i–ýøùՒfåqeA@@À |ò³ŠÑ†ßŽ¡!Ø6ò/Ö}„Oµ’@ j5ì ”ZÕJÅ7šŸKŸÉ˜ßJÿe§Ÿ0!¶pÏ 9@JI ýöqçŽs›š+Z¿eÙlÐì°9ŸI¥4ñXöÊí<*éDšeÿ•fÙ1‚YžÞAY“$pîŽÆvÙN­÷ŸKl9xÜ$„SµÀfjðJS)•:2q-ƒ5“ÚëĘüK¿%÷z …ÿZÖ~4@  ð£Ý²Ãÿr³ hiÝå՟CfzþRÞê*CŽOqŽf¡ÑEÎL(–×A”S$žAÓæÇSÚûq)lù—cŠ>§ZA€Ïó}ë<ÀZsJYµ¢Õåo$ß:àÉD²Ë~‹8Cž—(,€@m'qÍ&ù̍Žéñ6ŠVÏÞŽn=,<%CŸ21È1µŒl*ZŽÛCKB7±-î֒ÆåuåA@@ÀT ì<£qÿá€ÖöÀ%Æg8ùùמ@ ª ðõ7)-¢4¿ª+¯õñ}ÿU_˜à4j…ÌŠíL6ՀNE@ ª šÒ
n©« œä-P8¥9ôvMê쟩aº‹¡3œ~­*ZŽ²0ëÔí"-EŒW„ƒ°  ŠJ`ü ÕSÇÿbg£“Ø×Šê#üª‘ÜšU—óZƃÿÆÔÈVVM£\©š‘”üå zXwmÕŽ?âTT {ÔfM +ò†u浜þ9Ñ7ݘZ-¶n÷Ü ë6#õ§Êèt:uzfʊø &éÑȊíËw²ýƒºHêW„s°  ŠL`Å^Mœ“7Ž:šmÿ’ü 5e_á[!D-áQˆù@Ñ;5ŠUÕߐL($õiݏvw:Éêu»oY§c¬Ü¿C¹‚GU³à€@EPÆ?°ÌžsÒ=çÁ?mvº…@"SY6pǶØ0}=:A¶VÈ®jUª å >gìwEŠö¶ŽŠhpö.Q0ͲË*l€€€)žðÆví!mÓÓ·Ø®XVî@3ŠØFød2äɵ ô7r/Aî3¡Îð™?ð­¥<ýßfJ ªNÿY_Nš·KŸ©¬é(å%+և>¡/ž†:âuœÌÅ=¿•‡sÍ®‘ãŽzè[Ž s…ŸZxïdÎÁ#Rë™7Tð-÷Ò!_…G¿ªaF„oà }>`BîGFo™Ù?šËhǝõµ¯v±SnN‚ƒÙµ€‰ D€X(ÍG€BçnËy/ÝeŸßxÆþ±P5I-ë$€§]Ác‡ A.Xç4lFkü{× Òűœ ž . ø·/Zx_à&ˆ”8ãwÌK# xÝ`\'¬òŸkhÅ`Ì(ム(8®LŸXG±@?+ý$Sé6â Öœ" cq†E„w¯%|Ë×,/hk°Úÿ3§ÄkhúÇïÔBݱ!þýlø  ž„;ðUŸhŃեI)+ÞU¿­œˆÀh!‡çt`ŽÁŠA2&tùoIžÿo5˜"˜€°ŒŒŒÚŸmbÜ.@ue<7eAÆž†Qò-\1niøÌ ±`˜:â\au­[™á„Œæ« ”ˆâícKäix–ž0ë'ïLÔèk’Ø­ÚxÓ.¡ÞGc>a^ð`ÐÔæñ™Ãºêžô€O|bÉý`«$€Pèã­ö†¥XÐk H SÁÅ |¶†…*P,qqȰh¥×Ã\`ÁȰØÃ’ .Ààñ;Þã8 ?sžøòï5ü,‹/øðyJ?°st c‚S8ï™/ÈÞ§HŸÓ/ÄÎÙóNc Y4ÇÛEGë£cäšžè`V:šÍÆùg|Iæ MÓ -Jäau®­ ï©"@ˆÈ.îJŽ ¿“«ÁŠÀ•ݧزì2ošg†è#ìù€U†FË Ò‚@r‹ï»fÜÏû>㬓[XPl€ÔÚßÇŸ’¶S®_W®áBÒíüÔl³€÷ Þ.VŒ}ˆF‹†kI¿+×pFÑë(¢ÜWڜH…u Û㉢|NúÓžžñ=ül,دñwËxC³H‹Ô^ µjMß0Åök%€;Ú© D€K!0ýk±Â‹0æšyÍÆm»ÂÞºÍYŠ~€‡Õø4® Òä7«Óž&D€³0‡ÑîéíÂÖ<ÿZ8iVÍš3"@ˆ VBà«#RÁ?oËùK`?MÞÎöZ‰Ú€Šåh*ý r€Žå©G"@ˆ@V0‡ÑÞºuÖö‡éÂŬ˜Iˆ D « \õ—\V”+öa/æ”f5³) ]V?+ÿGУ ²Ë õ'•‰ D ƒ€Ûh÷qg‹§ueòЖB†FÌË ùS·D€"@ÌB`ıFD sØ6šÍpèÈš¥Sê$;Àõà žùÑ D—&Ms$D€õÒkŽÛÍÃ~ºŸ†ÿÞRšŸ6Õ$D€"`^«”Š^¹/çíP›ýÒa픚—®Íö¶fÖdÈJ›%MŒ"@ÒE ]F{Ɍ죒ùY…#é҂"@ˆ°rÜ=¶þÆÊV.ʞŽiI`º°x+Ÿ©Ÿq*@× è5HuW7õLˆ ÖN ]F{ý2ì‹f•˜8©£pÛÚAd•þ2ç‡{Ž-ÏybŸÅdˍèê ŠùÄ=Êÿxô&G+i²Jå÷Ž{è‚ä³ä¹ÑéÜ>Ogž\ü,ò)‘RD€dQ'iú¬”åñâ—”WÛ·a72bêÓê ¬ƒôY2ÕêgC D€ 'f£=ø smõ)ûqÓv°tA!*Ã5µÁt|.û;…L’ŽžŸï›Þ•[÷XÕ2%Y»ç—}®µØdɆûØMRµµ?ËÖåöoÎØàc£)"@R$0ýk©BÀKÙky¶?__ö¡"FŠÂgLå†{á9öûD‡"@ˆ€i6Ú× bwŸaÍŸW3Õù/§¹ç×~íÞ©wjl£ÝÓÕñÑw-ÚpœIªŸþg¹ÿÂ^܊ñù;©Íî§@ýÉb÷kþ¬b.ölFwnÏüÓŽõD­ˆ0'Lývòºì×»)w­EEyŠ-{cÎþ©/«%046££r IDAT²d°Õ΂'D€,!&£]œ9|ú9[ö2‚¹o-œÎÍm`Pßµ-"\šŽOm*ÆF;ÖÍ(Ãý÷˒÷‰Ì÷É+æ¥wÎç­ Yø »èæÄ«vɱAª±ñW¹ßŒnÜê]yr MíáŠáþÔ¯¥ŠËöËC•Šœ†é·ä¶¯È_HCwԄ38w[ro£ÊµJrÃZðûì:Š™±{êÊúä•Ï€äi Béq­ï’ÆD€,'&£=öV€Ã¶¬y%vgX+ÒÚ€ñ1*F»^Ö³;þ™,Ëo{Ҁ÷œonææâĒíæ2ÜÑHÿá<+véŸ\ô~+Å|’N¥JvúÏeÂNµSºNªõÕorŸ%}¹ecÚð÷Զˎõ&m“*ÎÅ·äMJ—XkŒøñ¥¬nÓòì犅¹€M¿ÉáÙåü€1·kóH>KÑp—ñæ–syÞ¢þ0ƒ³ÆÕÇÉ£c™ÓõuÜ*{-¯Oë;—Öç–ÖñÌÑÎRŸ‹9æf‰}t]"6-ìÅ,î­9©í }c‰:’N™B`Œ‚á1ÿ:Fˆ§Bˆ D MÒdŽÇ`åjŒeë™Ív{» l,Mè3ÞiŒŠa’üï†6>''GŠåyöÏí{¬r™âÌËÝý‘ ;îכ|É$QµrÕ_rºNn{û+ó&šy+Ú ,Ò÷ÝòË¥yš?§æ5ǘþA>—‡³&rÇ8þ„Ú)øBª»ã˜üñŠ܂ÞMøÇjÛeE=\$™µ[_þŸGúvoè‹ÍîÁíïZÌ }röç ‹Ü!Ì3eŒ¢Åq¯#™Ï‹¯¹)ŸwŸIN-gËCÁC¢X¯†Ü®-£³Îp‡…^—²Z,æŠT-ÆG˜2¯Œ¬»ýw©ÀÀ5ò4ãþFnTœ|\ZÇKësKëxæhg©ÏÅs³Ä>îKß~ÌrnÁN{tg,QGÒ)C ž@ï‚i r4CG£Î‰ DÀæ €Éhÿ¬ëüë_¬ÿ‘ùÂ~›'”46ÚãââÁhÿw§‡uŽ·gð}Ÿð”Ù Zæ—Ï—i’<1Ÿ°-_æüìoµj¶ž#¶ùíŠáæêÈ^×.¥9Û®†æê'Ùc4Õö“Rœ>+¥»OÊ=Ÿ›ÌÍl[ƒ¡¶¿Åû€’+~»wšË^?„Ç?v2Ž\Œ'¹õZ.÷yø‚•1šn)öû±…ÂÞ <±ó=ÅQ±Ì=fŸ0"¹ñRb’«—8ÇÁŽEl+íB£$mµ1òšÇ¯XñA°­?œcÍ`æÞÉτo3c.Ê5>{ƒÑ^û‹AÜ"S=2RφSÅ.go±&ðë$Åg¬ÔžÛ7§$ßi_ËÝn®çV€gGßTˎ‡ÂF~Ím(œ—1no©ÏÅÔ9ZKý/•üN]“ýF·á.Õñ“W@ê7ÕGŒ¬eŽ€gŠ>†;[@N€4#ND€"@ÌA MF{ÏúlXw¥·0Ç(•40v¿~ïá;;íØe!ߌÌÃͅÅŋ, 0ˆÅÄÄ2=üŸq)åø÷÷ÕâfÿŠV…ã×$¯³äù.Ž, vgš;-[ÏeRãïÎÈ]O,ä&Õ.Ň©Õ«ß*©þÎrO4ªæÌ­ß>ã‚ØÝ œN“'…E±\Åò²«-*sçO\—ËC`·ZžÅŸúŒ›–»Ä^=ÄÏ"c˜žµï Ò;†FêÝt2ã ùp/¶áOŠÄÄ­«ž,¯'{|{ƒ°Ú˜¯ÿKÉ¡Ò(y®³ Ž`ùôzƵªª9p`šöµÏ!œõªŽû^õg5ë–fGóysÁÏCeoQÇŽnNšš5C4¿¥g‡;­ºá‚FŸò’8‘9ÃbǛˆo •æ’ÚsÛxD*4bœZM¥ÎŒRùŸ/ÉU}œ4/ÿ7Cû“)mM©[fž8ü^ +_œ;ùÇa·Ò¶@?qrP(ók_Kóý·µªBԎœïŒ”ç«£rµ—a,GÈæý,„¶ïüÂ}^oöðÑfa ö›Ïn⒜5þîaUÒ±ëATyɰÃw ‚aՏdnW×_ªÕÑÔz%Çñ[õ Ÿ‡êsŒŠ`ށ¯™Ÿ(1‡€ýž:±]ãžÏ[TáƒM#œõïìÇәœØ)Ì2¥OSŸîŽò¹f{÷œÐTŽä璞¹ZzÛ§Á’ýø­rýŹ€‰ä™š˜Iÿ-Žôù‘~ÿ!Юü‚±<Ðh'Ï zIˆ DÀ¬ÒdŽW*Â-éÍN7('Œ6«6Ù¬3ãökwüÇ=>%<íeKfœ†K³ÑîâÀBM5^Ô<žVà~Üï_ï↹$‰: Œ ‡Yi0êøŸÙ­ŠEøLO…€ì‚ÊÅnÞXí6>Ða¡®ÅOéÛCðœ? øÞ×jæ›\ôf±Aîþì+ÈñLÊçÅšTà.Bó—á¬@Ò6¥ò³K• swj•`ÛÕdÏryòñÉõ{ö–äqö&Ë5¯<À͙…<Þ",J‹Ž¿_…„gYQg;òCv+¥ñÔôÝxºØéÿuÍãÉV+Šù§Zqë*ìiÙB|€šþÌ]#y7™!ρØb ìŽûž³§O¶ M'_qš)ÏíçKRÎvóåùàåpŒ~6e¬Ôê.Ü+•†@-_„±üð;VÀ‡=ðwrPsÞßžmZž îÖ?yÉŠ&q­OM'ºŸ<>+ÅîÎ,zÝ`6ŽÒŸÙô[‚¿ãM@ðØÍW6=Sš D€dŽí®ý؏Vü»C™eÚ[ùÀÆ;í2ø2'ñ|OyvðÔžÄÃíiÝi‡øvñAÛ¹‰NŒ|úŠäùÓVèÊ#¹Ðã—Ì72–¹ùx° ¿–ó[BÞè…);X͏ª³»jΚãÙáówXý€çŽñ|ö¢ïä~àŸkˆŠêK›sÛa'òüû#º|Y+·øë« mìYD‘\ìNŸfÜ©a­x“3À.û0Øe¯ðõ8nNҀs‡.H>ý¿‡P‰;Ÿ=…à{…{ñ~¹äEÀÙ! ü‹ßLàz»ñ†€Œ®Î$yJr‘øÝØ ØW×øåb÷ËàúKnÅr«õJš0Jxë «ŠãØiYLӊš#%|5ÏkgϛWdÁII’rÅÀ{œVè›ì?+w€„ZŒïdÇ"ÖáVõlôß<ïËöI%Ž\‘ËĊÌŸéÙPs9)3Œ€ŸùˆÜÅ&JäÓ<ŒóT_‚Vߎ[¿°7%µ_ÑÔxŠÖ>µûe‡‹Cﲊ³»s«æ}+£ý‰ 8\Rõn7…… 8:Q®`.öPÍsłúSä%µK²c'TÄÀߍͿÊ-ÀK¡0þ^x¹²µJj.}Þ_s2¯÷¿ 8žà4úKùSIf n6‰ÚÈ-«h~Ü?…ûœp°€å¹àûuû «²q·Ð8ˆd`ˆdïôèØxæøÛ\nEV-À€ö¬-íþŒo¥2ðßÔ|kz³‡±PKӏôI7L߆GüAjƒ„€»Gê€"@ˆ@ ÒbŽ×hU…M90]0ëRv|BŠÑ.ëeöÏ­ûï€|{žçX…Å AêÒjŽÃn·=Œ¡‡®Dc#ŒÁè\ìi¹Bš›xZ‰_$7»vkœ°&©^åGˆCÐXûn²öÞÀW`X–Ø+|ªÔ»Iª¶îg¹?,KhpÖюÅ#ãúŸ¬~sZpê$~ïöce®ŠŸÛJß©=7ô()=\^ ïçé3KÒ%¢aŸêG¹3<£ˆ÷°)§;/b0ÄAkäÎ׳êXGàY¬·+ zõ†åÕIÌß±Ï>áŸTú•*ŽxÄÊáû¶~(w ž/‹ÚsŠå_ý“Üߣ±vZNšÛ“]ÄþYšy.xVŽVØ=ØÄM6n?õk©â²ýòPøo…î¯åÜ$2ÚÕœ•_óýú7+–Ç…Í^u˜ÝQ׊jY u g'Lçf’玕̏Ô$D€ #`²ÑžÓ•õùš&k°a˜áŸ-Œ•ÙÕÉʝöD£v왔׋=,WPs«M ÍõŸM5ÊnNžþd±Û¹;¬Qãòì—Ãs„Æ.ܕÜëM’çÏÉîÞß(¬À{•F‹!õX¡W»Cz­ýg¥Ü=–É31(Z¿žíJdø:ް{^ÿ‡)܌ÖÕù—ÊX`(Öxó062Zâœ{ÊkÑÐGc¡3n‡²+ðŒ”kÆ×r{ÜÑ­Q‚8œHØ£æá<†sŠEÉ«1PWÒ n©µŒFª³õwù4€ft嶌mÇßÅ3ݹvÏåšï„1ØGŸâ0„ ‚QõYÿæ|€q¿Ñ±÷4„9(gý•ˆÞ°S?«Cm>(9¿ÂïceFÈãñ<|M˜»›#‹„ñr€ûv.8'ŸŒ.‡~ÀÊ͉Å|~P²u 7¯gþ©b b 6ˆìŸwRÑ8/ØWžÚC¿&aÿ"\«2FŒlÑ8\؛;ÔšÿzÇ1)ÿ€/äéØþænZŸRŠØ ÕÜø«Ü·Gn7ÓK‰«Zž©=—”îù‹ä7z“<Þˍ][Í}†ž`ޝ†~þ÷7%Œ«ŠŸÛÊX©=7|wœzÊëÊbç/ Ì{NÉ]áw€Ç>šUd‡Íþ§%Ákùs°»?LãŸ,ǰý§ÛXÝ'äŽà¡Ý7…›_¶x˜ ’W¡§É?_p3’ô{*ÙÝ ”šNg‹;×áŸÝ5ž?fÌ&µç‚Áú Ýð¹™ôwC bW2+œÈ€Ì i}î–Ôî£Ûü›\Žf,ÿî¬!ýë'€ lïvÕñ·þ)Ñ ˆ DÀ˜lŽçö`³G|È\'vhç OØx§ýڝ‡ªwÚÑš.—Î3í°C¬™Ø‘Ûع6{ôŸ3L#u÷«8¥3·fNþšñ”ÛÎÓµþåo}›Š`„ü FÞà o¡o˜—’{üƒYbûãWY ÅPQÚ£Ûû÷§YÁñÿß|†Øv£?8»„›€ÑÛ]»ˆËÁ tۖ۰žÙxltõ.=\éÿ‚•:·”›€æ|<¶ñî!-ÝzîÊç܌€i±Rzœèò^e¬<£ƒ!v®a9îjNwµïŒ\óÊ#V vo”sÒ$.NÇ£¿FŠözT'öÁö{Æs³;ÖáŸ'W?)¬SyŽØwg!úÄêÅùpãvhÔã‘t͝÷{ÇNÒº\ài%· w’M}·•±Ô<7»ö→Ÿìr™BÜ}xOºÀÙæ—Í*r'œ“ÛáÖ?«¹ ó¿eÕÑߟ«kž%I39àÂÃȍòdt³ŸÐž;Þþ3y^J/šºûûö‘×  ìðï2f“ÚsÁ#2MŠÉ‹ÊÁBƒâ ‚í1ŽBÓò ›A ‹ŽTˆ D€d“vø£wÓŠQìQ‹Ê«ÌRÒVÇ1Þi  5ÅÑãÑ5ý‘ {Jã*®Àã;Àåÿ=£Œç¿;-–g k}¯†Ü®-£ùSØGñ!âèˆ(æôuB„n¥ý€ŽÜÚyœø«ï›_÷%RÓ}ʝgtãVÏèÊßpC£ àÈœÜðärÈ$Ž{ÌJüŸ€›\¯4¯êÌh¢Kv'Lõù¬7§Žcl¬§b8C›À­¿º.+÷w®ñš}q=82œéžÚ³¬5^ìué«»ò •]ù]Ç¥|«~’›œXÀ}ÆwR&Ø'x)ô/…zïK)¶ýw©ÀÀ5òކåØá#s…0MžÌ»Þý’­GHN?d AÎò=ÜÄMR\€1E^í‰ò,pË7Ä#@7îóËžiÉ-öŒÞ$U_G!Œ#ðc$í6óå^‹zs›Wæ_™Â35†I@¹‘òˆ‡A¬,zTT,¬¹õ2Lïy?ˆÆÌX„ì™À͟µ[nƒnåjßme¬Ôž[œÄž\œäµw Þ_Xàyr|·=, íÇðÌëNïÂ}ñà9ˁ $)-‚¬üŸTlâVy<þ<Ó³wvüyBj^"b•·{ž4HajÏR@êN•ãïōµÂZe®ÊïoFeT0õùZ[ýv Ė‘lï·™*o k›_6Ñ·4Ìó8þçΜ÷ØO6aBÓ$D€L&`²ÑžÓýïÉVþ'cêLÖÙf†36Ú#£bþ“§=¥‰ò’ÜÅÙÑp;­gÚ!žº›ކáû€v_&5ÁÂܞìѥϹåhÈ¡11s§<”¹`Ûúeؑ£óCNڒCÄQàºí‡.îø]ٍ‡óèAðlCJ;ÊXW1,”]yŒÚÎòoÅÍ7”îÃÝËœÊZáŽð˜§ö}ÄÝH8¯=ÏÃùá@ȑþ¿i]ØU·ÄH÷èBgîeã3œ9{‰óЅ5Š—–g“Û ^#Ö>—]»ù„-ώó·9cì“q ˜Îíc˜M"@¬”€©F»ìỗ3†]U*é#`œòíŽÿc“vÚK*æ@t.ÅÏaÐéöZnLj.âhä‚kø§žK©$ƒ@p9q·²k=î{<«k/°h%œ²3w`:7œääFWåŠË£1àމ/èÃî–Χ¹_¿Œæ~ÏFÌߨèSv•GÅ`…Ý8ºu ŒìÐàæ;”¥P4@Ï/åŸL-jzÒ§„g¹Û/?:y5ųý‹tqbao¢™ºã£a7€·E âæÑU\/1Ç뫹‰ïã!ióô– »”ÆgõSzKàœq 8ÿݯaYöë‘yÂþ/~’ŠLÙ.„TlÁŠa–”‰±1ö?YûkrýãݺÈká¬ô}Œ7€F žZÂÝvô£ûvù‚Üýæ•ØýNõØ3%˜Ÿ° ãàŽ:.Ì xÖß쀈úž0Qy¬<w²q!gýn‹“õPܬ1žœ%_ñ׿þÉ yäpÏ{~97Ïl«åiêo—rˆòå`þùrh‚”Ñ<èX‡àJ~âd|oSßmEŸÔžÛ·§¥Œ¯ ž&#?ä6-ïÏcîfCÁwÄo€ŒÜåCîoâ>+ÐGžÐ‡à€ÀنƒÅ•BàíPùÏìέŸÔ‘¿©Þ`ñd޳= Sâ$Ç=% ŠD1ðNf읢æ¹ç³7îR^ügµ°ÉÔçAõ›ÿXúë“,þQ›H<¬Š@AÐöH^V ¿[•ö€, D€ØSöFüªó©EBª©œlŽTLÈx§=­Ý§e§]t!rž3ìîmP³CAª ïtNj÷X4ÖË`WF·áŽán%8«)ÄZ›Ï-ÀsåJ€±v55ûöNJˆ(A²z­?:{›ÕÁ]X™+F<ÇŒÙ`þŠ‘ÆqœÌpy҈¹ýhš`=  öÛe¹æÉW|m¢ÁygàÜïiIùfÌÝŸ'ïÐ7ŒýL_ôU8Ë®ø9\ÙóJE4×Ö Òü®žÎC ®~WýY Ìvò·¢§T0BûÕVù}Áڔ¶‡!ŸwÛùò< ¶‡, 8àÙáE}ž•cÚð÷°^rLÐ /;LÓŽ"w~ý0þìûtñtÕŒùq†öG¬óûeÉ{ÜV¹Ãí§¬2ž«VÚáb #ô_ܛÛóa Ô4ÎÜduQ0̆¶à~2>)ÀN“‡B<Ò ±?/|.l3ÖÁ»‡žvµœq±E xØŠºæ‡ï§hc=SxªýœÀTƒgo±&x>Ž=¬JîìužOęà1à ó\ށ±oSÞmµÏ œšÍ”gÍÃn_^õ_c·ç2©ñçäö÷ŸÉ”ò‡÷Y)ØU÷ÄÀàÞX¯ŽæüÂ^š?”E"|J“§BàÁ°Ûë…/Râ2tƒTëø¹ZrS{.ÊïÛʭѳ~ßx<þ¢&€Úç”Ýêaù…{™xö́¹S<ëxðŒ:z³œim*“–D€"`ëL5Ú{t®ÅÊíš(<²u0™1¿€Œ«š†»~Ð9=cz2x†[ôICôuK(xŠòºW†ŒáŠK°¢žmÞqœ9Gïw?H_($‚å„tnníüãÔd)͍UµéÝÌɃq5Ÿ)ÏÂÝ} .6µ ÷c›êìyXDöþ“å?xN®t=€•sŽg‘6òKï<×;).ó©éÑl†ØñäuÖwûÁÕÿ҄ŽÜïmkð/Rk—žûõßYVøïra0Œ ÀNo4âÁ û‹€yØß7FÏO. Š[ñƒ<eôÅò°ë=q'”EìϞƩèRÒûÃ󨰘tñàtnGJÇðèÆÃ¬Œœ/= S{n˜öÍǃÅ»š+ã¡>u«ªdCP®cL IÖk’‹ß€uÐ3ªhryþ›»Ý”9€ö\’öå7@œð2Œå‡øãÓ:Š)úÙb]Œý1q›œóÞsCZ° ýœ¶E~™<'OïH9üwÙpäËF f®(‚ GOldN4 "@ˆ@¶"`ªÑ>f|;æµ°·ð4[QÊ ÉŸvëPàiîS™̛4Nz\öQíLa³–JFÀÔuƒ×ÉÕñè2Ž;äʘè5ÐŽ;Œ©ŒLÕ㺿äR"‹JÉX3µ?KšŸ\lcœÌÉ]ö7aE揜çïÕ×ZÑ_sÒç³­ñ¹¥ö\vùú-¯àÇÎ]X.l·„wÊuÀ²~«äwÆ8xhsÈ&:„yιÒD²¡y·„¹l)8§𳟍ÍцM…"<SÅù›†³èÞM)rŒ¹^š ï‘åÂ]š×Òsöjûԃ¹š•ÃC}_­üÙ)úlˆÚvT/}0öŽ]¬Êéër¹ˆægùãÀûeœ2ÜíþÍØÝÔÏ¥otÛkM<-÷™â±”Ç䏍X®¶–«zµœ#—¹óŒa¬‹wRfZ®ÖÙJ3üw÷HEÌøñ•ÍŸÌ³¶àÂþÂ hŒ£ÛÿÏ66Wš DÀŠ ˜jޝÿk»[ÁO ³y6ýZÐäˆÈÎ0hÄœp ÞÉOU÷";³JmîFŠUo=e[¡ÞŸ©Õ¥û™J Œ†^$w@€Øâø÷0¯Ž ýA¶€Ì™2wß©"@ˆ€•0Åh×B`©mQßSäx+y¶€& DÀdûÎHyº/“g7­Èýœ†ã&hã êNK^žkÈómIÅ"`ÔZ ³A¬%žI1Þ4É ßÑÇàÀ†Ì%FE€Ï‘ ÷AʀÁ…£œ •A.[ē %ˆ D@SŒö‚®NlJÈ.áoU=S%"@ˆ°:ëŸäºo¶u7¯g#žâ—€ó ~4_ôýõÃà­ÛÒÙ5O?vÐÅ~Ç A¬)ÎÀÐ×€>f¿h ²¿ã‹ù IDAT Äça.yゆúu£ ±foÁ죒ÔÅsï¿€/õ@ˆ EÀ£œš¯'k÷h‹QÊP¿D€"u0Î@ÞŸòbÄì"÷ò£È5>ýÏbÐÑeÛï,zJºšþΩS «x“D£ƒÎY[ oACÝú1#ŠîüdO2“QŒvŒ%ƒàŽûF ÆÁk±O컞§Bˆ HÀ£œe™ü¬ÎåÕ®PS!D€#"Ù(¯ôta/žï0·8•t˜²EŽ_þ#s‡næ§³+jž6Í M@Wñæ Öì-ˆný8,hˆ£ÁŸ;,p=+º$\_r€.e¢IÛ;F­ˆ NÀ£œ[ýÒ¬ÄÑÂó ׊ D€,!ÐÜãËä¯Ècú+*é$ðÅAQÿé6CÔî)é슚›N R 8‡©8‡™ÞÜâZ| -KÔjü“І/á~,HYˆ$u'Â÷E èvçû_YÜlI!"@ˆxKÀ£}HçºÌc×§ÂkâGˆ D€€N`÷qQ쳚•„š3@âSoA5Ì@P<£m‚»ë˜¡Ï¬î#Ÿ¯A—x,Ï@Ð><‰b˜ÒM1ÖÑ(Ÿ‚’Øö&¯ÃŒô5@0ÖòA×y*D€"`ÁL1Ú'ŽkËäE}„€«µ<=R"@ˆ@Ö8ú·ÛjžÁžB÷ø7Y§I¶w×1Å`ëj#³VRµátp§Ýd$æZÿÄØ­ƒëá€N‰õ0ð^«d8ìƒk˜›ƒÔQ!D€ '`ŠÑ>Í öjPK!ÚÂçDê"@ˆ°WˆQÕdzŠ ÌbrAΞ§‚.àxæw’17yÒhê7rÆ÷|†Àšñ;@zƒàn;Îë¡ñŽ»èJù>tÁ3íxŽKuF 9@üAN\Ëxµi"@ˆ0SŒöÕ¿Íew”ÈœÏ\ô©"@ˆ°iÁ¡bžo?C^l<ƒŒy¶©˜Ÿ= ‚;ÌšÍÖªaŽvÅhñ凟7@Ž xàŸÄëž8„çÕ ‚Pà`ó¿kÔ# D K˜bޝóßÌnæõ&£=Kž Jˆ VG .^ síj0ªV‚PÊTó>A4LAÍm5o÷ßîšcôx†  ‚à1 ~˜\Äx‹Ÿ)Hˆ ÿ% Öh×ÛµO@-*D€"@ˆ€ “ÃŽí¥jPóaßUфªš#€‘Ó1-!Qk ‚éͲc™ “ž‚Qâ1ðºÎ·Á4wTˆ DÀFš5Ú]غð=‚-D`µ‘GGÓ D€K' ×Ëö€r ç7 tŽ8ý Ïjãyîâ hŽžþ.-ª7Ðó§£ñ h|§ ƒb”xt•_2Þ¢fDÊ"@ˆ@º š5Úsy9³EA;t»¢Bˆ D€š ÀÑ®í •€ªéû/MšJÊÀ-ÜUFüŒ)Ël©`úµ èæŽs+‚®î+@Ð_ö<*ä¢-¡¹"@ˆ@µF{á|ÞlÚÃÍÂyGˆ D€š# gòûöR!š}„ŒÕÔaKZ Sœá¢Gµ hžÛZÁ…ôÄi ⠂Qޕ‚»í@0.ºÂï¡@s¶öÐ|ˆ )PkŽ—/ž—ŒŸV ]z•ˆ D€š$ ×ȑöí€ë²}¬`É4c£©"@ˆPA@F{; wNÃAŸWÑ";V™“Æ]uŒžŽ‘Ó-±Ž¥€àŽ9Fm¿‚îë ž ‡@ÐõâŽ:>o¥`9ÌðwÏCA†€ly–X Óµa[åLû1øŒF}j9Ú-‘éDˆ f& Êhwqd];Ôb­7(]™uGˆ 6L@–ãÁ=ÿ­ÅHàÊ®ª OØ€©U…Ú˜Ê Ïü÷Á€s–X&‚R‹SPì%\ÇèîAÐhGcŸ'–SÊ*ø0 ƒé¡AÿŸ‚;ìbb?–È‚t"D€,  ÊhÏíÁú¶ªÆêoFîñYðŒhH"@ˆ°Z`Ž·—М}kµÓ0¿â ¡K4Ô1ª>Šr3ޙ6ÿhéë¶Ù2;ø‚”©‚Áòð úÜMOZp×]ã1Ï|JQßÑXÇܹ§Bˆ Dઌvg{¶ŽFqVúð\"ßÒ Dˆ D@-œ,™öâPÓyÍRÛ̆땄¹áîºÀ+­`®‹@ÇI }@¶'£ogžæ ²!…¹àÑB4îÑÈÇ#JAƒ. ƒ@j€`>úO¬€©Hˆ ™L@•ÑîæÈFtšËªn&œÍdýh8"@ˆ ÖK@/ëÀhWôÇÈèÙ¹LÉÁsÚÝßJ`=oü ‚»ê©•†P¡ .J «;.ÖÌAã}-ˆÓÚ¡±÷° [=žaǟTˆ D€ŒC@•ўÕ ê\U_5RŸÑûCˆ D@=Y÷øšiœÐœ:;t%Ç k¹Ap7z¶BX:c𞟠ÛRп \Ç ƒxn+ÈNÜ9w¹R8I;ôŸÀšñÈÕQ”x+|1He"@ˆ@fPeŽ{ÑÞœ«öù@á¯ÌPŠÆ D€"`dY†@to`. ɹVÛÄ4ß3 <ç=󐷹b¥Æ‡Û‰º—ƒŸO?£‘޹×Ñ}ŸÈ9LӆAõpç w<»ï2€ë×AÐ`ÇsìTˆ D€Œ—€*£Ý݉ ìՐU'£Þ&"@ˆ &ÐËzpƒ® ÙÉ=Ïkcp¶" ˜Ÿ#§[SÁHðy@””lš;îšãÂËo @úƒŒÉ‚.ïhšã F‡F:îžWÁ {Ó¬iò€+ D€XUF»«Ô» «ºb€pѲÔ'mˆ D€X6»ö"žáFit™Î¥LrˆHãV8i<{> s²c>uôÀíè)€;êxVwÙ1+ÀFå‰u§ŠÇ΃`:\ÀÅ*D€"@L&@F»ÉÈš D€õv4ÜÐø³åÂÃäpWS›aîòÞV0ڟÑŽÆ1·­ Ÿ†ç»1õŸÖd s©ã¹ûp³‰F7Š_CƒÝߓ–_à.RçiÇ¿¡0NF‘ÇsïhÀS!D€"`vªŒvˆ,3`T[Viq]ßš"@ˆ * xt£%VªïÒªlmqÕêFž».ƒ`Dõ•§¡z…>‡ªc«‡ÂÏ ×Rhž®_)˜ØÆøYbÀ=Œ2oQòÕÓ¢šD€"eTíieð趬"헳LS˜"@ˆ€ðè&>ŽcÅ­ÜÀEòsAÐ@ÅÝé@0zºµã]rœÃ OS™LyžÄ󯣋="@ˆ N@•ÑZ ߎ•_Ø[Àü€Tˆ D€•<;‹Q:Vªãή5–Š ôÿ@0'ù.9Ö8 #àó &‡ø·έ*–3.íà ºËßKŒø!üüÏ·¶r€> D€X 2Ú­äA‘šD€"`rô"¢X9Ðsu[[ÁÝõ~‰J·„Ÿ)¹[ÓŒŸe1EÓÓك`v4Ì1…[”Ñd0;Šì«nt­HâgJõfMOt%D€X1µFûàĝv:ÓnÅ›T'D€Ì'³›ø(<Î`Ž£ ¶µ”¢ (ž]GWpÜeWÎ~[‹þïÓwÊÑXLj÷k+âÙüÑ `Ïx}|‚gÚ1²<"@ˆ ™N@­Ñ>tB{VfÁ'ßÊôGD"@ˆ€5È×K|ô2ŠU9,²’yL=ñ|·3ž]?a%z¿OMˆ©Ëz`~ö<‰ïÃϏA0U.N î¢wÁìXЈâ hh D€"`…Ôíƒ&vbeæ÷’Kƒb…Ó&•‰ D€dB}ćá÷ꅙ3bšGÉ-É‚yÉ1èœ-Ü%ÿ€FâdÐXG×ö_Ap§=>ñzøùø}@Ü@Ÿ9RÇ@Ј DÀ: š5ڇMìÈJÌïEF»u>fҚ"@²Š@±>âý€pV Æ_U:šwÔù,ÑPÅóÞhŒÛJÙéò wÛOŒgbhç®M¬ ?ÑKâ¶­À y"@ˆ€õPkŽŸÔž›÷‰4ªªõ͘4&D€"‰Š ïŒbuaÈy™8¬Ú¡0’úü ˆ £¥cDu[*h¬çÁ4mjR×bÀ=ÌΞ@0H"@ˆ YF@­Ñ>bb;Vd~oáV–iJ"@ˆ°BÅŠwý_±š º¥iÇ]çõ‰FúXø‰iÐl±Œ†Iy&á/M˜ þ€7¡>U%D€"!Ôí#'ud…æõîdˆÔ) D€%P~šx÷vkӛmASD—ñ’ þ Ÿ€„XnéQ¥4Æ rèήÜGásÆ ÇÓÓ9µ%D€"ÔíÊtb~sz è:G…"@ˆPI Â(ñö­'¬)TŸ©²IFVC÷÷ý žãŒdyF–‰}cÔ÷ èрåHk AÐŃéâùôžLԋ†"D€"njöѰӞvÚÉhO7rê€"@²šãÄ[?bÀœ§gñŒ·ÃøÕ@t hŒ?Ìb}Ì5Œt„;ë~ WçW~â¢ÄÄÄAÎÃOŒà†=Šy£Bˆ DÀjš6Ú'wdŸs{ ˜&…  D€" ’@¢ÑÞªOSÙÄÜÕÐ5ƒÍ¡ üKØñ7çG@g_ä8_t‰ÿó²cÁv4Ü1Ûh 4G…"@ˆ€UPkŽ™Ü‰åžÛS°•Uy«x8€$ D€X?ÚãŰæ0“YY0ÌCŽ®ùxλ-ˆšèéY fº†Äsê @ò€`Š6ÌɎßǁ|nÔóBø<ä0Fˆ§Bˆ DÀ*š5ÚÇNéÌ|æôYŬHI"@ˆ B éñú©Û¬ š39UåŸ@"TÜ]¶Õ Ãsê»AÐõ=7Ȑ† 1F“®Ÿ1ÿús»¶ ƒæEˆ ¶G@­Ñ>nj'–cvOÁßöЌˆ D€d§‰ÿ¹i8CŽ»Œ™Q0µ\}2 ž»~"3ÍÂ1Ðhϑ8~üÄÈø? ÌH'Œ¿Sۑk|>,š"@L' Öhÿ¢Ç{AôøÓ‡ ٕÀn©y7Ì՞gzœF/éyN¯×ʒŒ?õz^ ÿŸg’^Ëée-Óé&ÉC]ž§‘õZž'hd™ÓHzß9ž.éôv<\3Ž—¡N÷µløÎ‰z'eWæ4o"@,@ÛyâÕ_þf@3%(ZF)‰Fú ñ gAeÔ@™Ü/îŽOÁ”mžKŽnî7tÀàsyAÐ=>¹ÿþׅëxÆœÐáI&ëOÃ"@ˆHÕFûŽ.ÌcVwþ¡KîìÓ88BÔN'4Œµswf2c²>1].Øä ໒AŸAŠy{¿àÿ4ÿÖà೯â=þi µ°`{Žã@ۀõw¡, ðLæ@ ë  ¯køÉ2D%‚ë*màTÀ…šŸ`ÁÆâõP/±œx\pàd.Á} ú†ïPW Âp ýÂ`)q±$pñ°Xñ¶nÂb|…>à:ô%p°ø ,\À".Tð°b v°0ë†k,bpQ¯… \È`‚‚$êíyQP1Y–YlŒÄÅÄ2Îс{ËÖðnà;/Ú‚Þ*D ÁhÿñoÖn£ÑžQï î,)ÒÏÙBqJœK3£ÉŒ‚Ï%@^'^Ãtn˜Ö­2HÒ3ûKà<Óßäœ-@¡9"@ˆ@ö" Öhîñnàÿ4{á¡Ù*¢c%ÎÿsŒôPöŒ÷Œy†0W‘ŒËÖ%Zäât‡Xg/‚ý¯Ó؇…Ææ<œDÎN+kÀêåíŽØ«ØØz §aœVUbŽS\ÃŽ‚ I’ln,!0¢;¬yîCÑÚÛÁmo‚± ííµ’¯ã±?4æ5`œêq£þ­æŒÌ`m{ŒªœíE]¬š…á¡ø/-p AÁŠãB%\@¥Pš -o&³lxC?ØVÃxÔ/^4š0ÌÉ^ÐÉ¢¿$üç- K‚A7ÃwÃÂàA&x[FØÞ G“0š€« ž.œºáôXHXÔø÷W"ÀÈÔ£¡Ÿ°""*È ž£ÝêHèÜë`wBWP!xpsE× g Ÿv.Ã}\~‘$¬†]ú„… è»M\u‘à;ÜÇö=<\ø€ÿ“e˜ ÔÁ±e¬c 1X‘Ä„µ ì*ÂP& ê‚L×]`$aÈàÖ; gäß V5š„±XÊ@ÚÉ:˜ø`Î4¡Ž)4ÑÉ ^–„i¢Úø44eQÇŽQqÌÃӅ¡ î;ïÛkY ŽìxooÇâëhÇbíYœ«‹öñde ²à&ž—^9\toônÚpÎI¥qÒæd¯ã ±çÆgn“Aßm€@ÇE`ޟ7ìŽã™vs/¬„>1ï:® ùƒ Ÿ-\ˆØ‚pѵœ(æ_ÇyŸIœ(FæÿƒÐ­A/4Ò±óxÞœ+š£Bˆ DÀêš5Ú'LëÌ\fõžYÝ IaÕîËŸNWB<=¯:øÜ|•'((Î;44Æ#&ZrŠ“ìÐþÑ::ê7gÑÞÃ]Žsw³s$­“£Nëè ³w…뮎:{7WÑÞÝó 7Y”84ÒÀØ;Rƒ 04ÊpãŒj°¹4p?á§? =ÃO0ÁV„:h÷Á}4 Šôi0YÁ€3ìâã=0Æ æږ£.aÚÁg6œÑøÏà…/3øŽvxBßã2áoi°1¡oCç†> [ð`ûÌâ„Í{Œi0ð~(g Û ~ÃU4ë±ØÂkÚ£Aú¶Œm–ÐuB;C× *AãÄ~•&õtäìì`#œ Î ‰m` ;zÊ8‰ÃWÅØGsõ3|WÖÀŒF—C_°@!h?°6h‘ž`šCÂZ,jF0,T$ÁŸ†î`1ÁpÞ†€…ÃâˆÁF†‹,ë*À%VI6Op1'aQ$@@GTÔð?ð;^×ð†ï†Åž— k>Жçõžýêe\$ˆ–ã%Ìx­†—µpöBç2ÀëAⵜõZ-+1à)Áë%­ÀIvàÚ`c wƒÁÛ^ \(ÐÓ_,ƒ7F¢wEThŽ6èuŒKxXœshžÎ92ZrŒŽbcu1Q¢CTX”kì›’àw#ÖÁÓ=Ö9§GŽGэŠÅßèãp䎯æE¬Ñ;Amˆ@Ï¥âµïÎ È© æ<Ÿ3úÅg‘ Ûl›2•ð¡ê?¿g~sàÆ ’Ô¹߇‚üeƒlhJD€"Mš5Ú'NíÂgwð,+%!;jj 8=Óû8É^N#ÜïÄú<{“380Ü;*8ÔIžØ2ç¹KÞ‘Î>ÞQ`\ĹæÎ††«hاb ðÖÀFc?q/wv i`×%`Bgü„ºïlƒ34Xõ %ÁNZRø5M0¥Œe4i•£Š›hÓã²o_:„¹Œ vŒyáõ"ÄE'8ûxŸ)êËô/åÿgç Q–£1ibFF;º°‹fèÓ úÀ³ë® á ž €?m±àn:þGçšÒ¿?pœ”£xŸ=#ÈO;[äEs"D€$ Öh;íN°ÓŽQY©Xr•¥ú%#4®Î±ÌÞ.âIcø“ίMÙé¡-ÚUŽ’Ç8|œx}Óöš‹îìŠf @ƒŽ8xJ±AnXÉŽÍ©&îJ:»—ðƒË}BÁåÌI™ú"D€‹% ÖhŸ:³“ŠwÈ=ÓBå„_ Výå‘gm;ïb|dŽ=DxÏQ¢PXŽ’…h÷ÁBŸ©EL%`¯‡Œ‚ÇöÅ^9|ÙÏ^`ñƒ>àN÷nÂÓ¹wSAfrý1`ޝ;Â>‚açƒD©ŸÔCwðû G@0Ý"@ˆ D PkŽO›Ý‰S»aِ‘EOyù!mño¬+ç+l'Ar{w—øÜUK‡8{»§7ؑEϛ”#ٙ€·&,B{ð«˜'_”ËáÊBfôàNÖ£3ïûJŒÙ Fû!Ã.ùBHŠâÙõj …@ðìú mš  D€"`£ÔíÓ!],¢Ã(®T,€À7§$ßí—ŒªE®æ'j0·µo²Á.¹œ™ÉP IDATÓäÈfE*" š$ú++Ýx±o·æØßbÅUØßsz×T·§Š™F`<í«òŒ£{üûŒŸêÁ}Ü]G }2MɌÙ¢çc 6ô8@7w*D€"@ˆ€ jö3»³èé]rµV5#«DÇKÜįíª?òª”7Ô9ŸWô«0ÇŒÕJ{Bp¹Œ—ú&DÀ2 8écãŠ><ôô_¯èdÇâ–öåŽT,ÂÓ«-èqM£}Å!ÖTÂTm)-~¯€{ÍAʀŽ9`AS0‡*á=ObGOà'ºÿ_7GÇÔ D€[' ÚhŸÓENé*a˜…oĞ“RŸÍç=kkj5ÓŸxðÜ'wŒÁ>e‹÷C>šX <ìeH؎/ù«7Þø}܈ù¡ðÀRtËîzLûZŒ±t?kÐ0OúßìJpm&H^ Œ2okÅ& òäHw4Ü«ƒŒ°µÉÒ|ˆ D€˜›€Z£}æÜî,brÿÑ¥’ÆmãªÞq¯\àwa÷È篜 7¯ýÌÞÕQÊUhH"@,”€†IrÎG__Øs¬Pݒúۋû—-TÕl¥Ö,0Ú?ÛÏZ€q§Ý86Ì\øŽ9ÇÝA&ƒlµ10ßÁ|^ƒàY~Œø>= 0*þCô.@ž  D€"µFûT8Ó gÚӒ_–à§“@ÏeRãØfݜÜxéçá—7·ZYü#ˆ  D YNº71ÿ,X™¯Ž×›GÛÆ ˜×›J˜·GŒ1o¯Áh_‚YXЁìÁ]wLʼn»ë¶èõÌ Ýàq®@>Ao,˜oŠ’­ BY²ð¥¡‰ DÀ² š5ÚgÍëÎ^Oê"P³L|žwŸINã·èmÛð呿Ä:E[Õ{ìœÓ“¢Âgâ3 ¡ˆ€5žœvKžœ‘^ž&ŽæyX»î ÷Š7gï1œiGƒwš‡ð Ÿ±Ö>ÍäôÇÜò˜²Î+ñ&ÎwەR>LA/ƒì˜ÞŸ9͉"@2€€Z£}Îì,xjg Æ xÉuyö–䱿«R»Qþ€¯îkQºKó€Lš†!DÀ†Üüæ—üÞ/nŒ<úiè÷64-«šÊ²ïÅSw±Î t]ˆÁ£˜Š0?ˆ±{ŒµÌŸô$D€"åL1ÚÁh—³\cWwØ·eåºÔ‘o­š^Çý£NÄÜÆŸ9Md'k¿põŸí/ˌñh •þRŽk4 ÎbcâYa`‚纷p6Ÿ C}«¬LÔÕþ€M2úãœÐ`ǀró@6`TxZ ÅA¶LYláó'õˆ D€XµFû<ØiFF{Æ>¿ÇÁ’ýÄ­úúõËjœÍSP×uŽKƎHœ"]8°žø³fzT+¢¿·ŽŸðwv™wVÍsĩ桋rQÇ$™] yÃn.«@‚³J'ã¢;ûy ç@0X\ O@î‚lñOÒågAðì:ÖU¥âîzY ›AðHÆÅÁÝw*D€"@ˆ€ Ôíóô`'tL蚪šJ Í<݇ÝêÿŸðÈÁ7¢çtÏXœþE…"` 4Ýúrüwõ4eLJ¶™¥Sêä?ʎ‡FÅ0§á¬Ð¬îÜZ7'yÿèìšžĒó’ctûq ëA0Xžš‚u‡€à™}%næ_Gã úýÕtDuˆ D€ä š5ÚçÎëÁ&u0Ú-• Ðo•X¯eevÿØ5ÎÏ{ðHÝ#œo® †º$D °c¢8áõüÓœ?‹éŽj;X»”`‹iƲì OÝ.U\v@š×›=ðvaÁ—V † k‰·Fm6í_€XªÑÞtC7wLœVæ%WrÀEã8+Wá{9¢ @*`¶<Îǻ¢@ò‚Dfك¡‰ D€X9µFû‚…=ØÃñdŽgÈ㞵K*ïä Ç_Äåm=ŠùœYãŠ2uJˆ@¶'P]Ÿózÿí¡‹¬Ò™%®lÄLªŽûŸ g9ƒÂX¡r_-ëÇ_RºÞ|DŒ5l=kßׂ™iHsvƒ©ÙÐøÎ‚gÖñìzrœ¿0ÀÜ/ ž³ŽFùÚ þ OAê$6œ ?ÝA0›â"oN©/"@ˆ ن€Z£}áŒ^ìÞ€ŽùǛùÕ8|IÊùã¹0*rŸ7Ê÷ÌgÂðú:Vkæaš;"@ˆ€€V¯Ó­Ž[ú[ס•ÊϞ­(\ 4i'°xŸTrîyXOæ/hYü_˹õ.NŒdÜãv0Ú®7D`ßb‰F;zŒÁrLE÷Ÿ²nŽÁ|ëƒ@*ƒ`Äø‰p·ïcŠ‚œ þ ×AðŒ;"@ˆ D Ôísç÷d&vèŒu ¿¯I‡º–ù}ô¯j•Òž¯5Þï¥Þ w<š"@2Œ@ võ^‡ÐݏZ͑ûnÅí©^œϰÁlžãú“Å˜_x4óîRûaóHþäŠ»ãšx{ÀZÖ îáùoLûfIS²¡Qâ0·ú3#åðo'tqW .*ÁEˆo@ºƒàßèRÿ~1N‹9Úǀ`p;ÜͧBˆ D€˜H@­ÑŸhA/vsBGÁÁÄþ©ú{LÙ&Ue™ã9N.òqÇ7'õÕJ0"@ˆ@Fà™,-Õ,?ºu°ßO±*,vgô˜¶ÔÿÆ#R¡¹»åžŽv,J'3»ƒÓ¹uå ñ)žÙþæñæ'Ë F.ŠB³$£ ðË åÝÜ÷‚8'~Ǐp÷v\Ô¹Ò$Ä Íá9ö¶ ÿ{ÏóÅr˜ß#È·¥÷€æBˆ D ³š6Ú÷bׯvðs*f pø¢˜ãçKÌ/ðµÆ{úä2g—JŸ40C·Ô D@ÊìÖÃOµ;o4Ÿ.všVœÝ_ð‰@» *È5Ÿ)¶¿ÀÊ@*7ÇÆå5'÷NÒI­Ù·§Ä[n8ӎîñÆ;Ù©5ÍèûÞ0ºë'w$K„ë7Ap1s¶çÁŒs% öŸ@N€`ôø÷ È× €ˆ%-Zd4_êŸ"@ˆ€Yš5ڗ|֋ýó)ífŽ øBª'Û iÁ.ÿ¯Ô„’úœ‘—  D s號ÿ¿ ÑçÿÐÌÜÃÚþ³Zؘ9[ç(ûÎHy†®—‡zž°WGE·€7÷}ëêüK5³ùîñvÏå£Ýã-ÉhGõ;‚ôÁ˜5˜kýJ¢ Áo4? >׃Õ)sP2ÊŒs†?±q^ö~p ÏÀ¡÷LÍKCuˆ D€PkŽ/]ԇ]×Vp#zé'ðãy)×¶ãrÅ"¹¹àöœ+^.uqd/BYŸeýžuý›óxŠÛ€rà¬x§ËR†yÐñL»¥íާ6ü÷é7ÌÅŸ ƒÊ¥Vð<<íIÿÆÀÈô¡ž  D€"`µFû²åýÙù‘ ÙÜžÉUÝVÊœóž\©œ÷Žs·âþŸÉýгKjNˆH,ðå¥9+}ËdËo󋧫S+oÜc™Ôäð%¹‰«# ϟƒ=IO°ŸŸ.ˆw:|fˆÿ%È+BƒAæPg4Ü1PÝ Ƒäß7<¿ŽåÑÅ]ï_€üeEs'U‰ D€X 5F;ÖYº¬/;7ª€îmTÒA`Ø:±æÃ –kÏ$îÐçvÃ*<Ð@7B*f à%ž:æròpá5ɿ֒Ö%—œ§÷Ýó{÷Ã)ŕ˜S¶C Àý#G6­pi¥°ÅvfeúLn=“œZϒ‡ÙiY\@0+>£+·~jÏw§¹£œuíÕa’`ÿ­ï‚ÞX¶ŒI1B~šáPC"@ˆ D UjŒvzYŒ€7;7Š€‘f©€‘À…»’ûär³–•žëm;~2G7š8ªyi1û4«™£Dþz>eÊsš,v@ñ2$”œ‰ŠbUʗ”vÝ>yþzˆÿëìCˆfJR!én̟·oíˆc£>0 Y¶+ƒ×Huöœ’Ûùx°@7p‰ÿ{•€ÁÓÒ]~œ$Þýh>k a¶Çéî0c:À”®h”+ÁåpŒ?ä猒z%D€"@ÔPc0¢Ñ>o)œiÝ^È©ŠSª“<yßJeŽ\’ËšÍí]m?šÜ-}áüÄÊ<F–ø°‰“Öƒ¥X£œfŲL”uVežëõzŠ‹ŽågÇä¢4›"õ’í <8t*—Ó?G#ŽÍ”0_w¶)‘Ñ_íSyš€gÜÓ`VlXknÛ²~ŒÙŽ üþx·ålƒÑŽgÚM>Ÿ‰bŒÕäÈ 1>µ s™š Eˆ D {PcŽãªû¢Å}ؙ±mŒK%N»TðcÆ,p}ºnxc=Óà‚3_º}+^±ßSŒv¬f-†{\ØáØŒu5œ=¢ëLì}åõýÇ.Î>Þ±.¹œã̀Žº o èeYslâçÕ®-™›“Á<Ý6_Æo‘ª¬ùIî_ȇÝ¿'ýÅåÜ:'Þ¬‹c'®‰wšÏ4DÇvK6ÚmþyÓ‰ D€X#5F»&¶pQ_vf\¢œ§ñ)8'å^º_n<·÷ë_¥ú朊)Q(]Q³d(Fû«Ð0ƒŒq±··cEòûŸuÇv¥X’ᎻéL–™†7öN…èOK¶—üëFX“€*PG¯7üÞºÌóºæšî—Ý äŽIí¥£bxY§Óhœ$^à¡ë-QÁ¡v=›¯lÏVßsÂz'˜Åš_\··€o>§gG;ü¹ÛÖW+ûGD3·—Ì·K]îàæ‘üéŒÀæºx·Ñ ÖúFw{2Ú32õIˆ DÀ† š1Ú1êëüÅœa§œÛ†YdèÔ¯ë@P£[gå:<^þw\š˜‘€bŽÇ‹:û®7§VÐ2gü:”EDF³šËŒ32î;o?#äq†Ÿq?>s}Õð€ç^N9<"'Qpv™¬gñ‘ÑöáO^x a^ú€³^Å >E…Ø³Ž‰^’9ÞN+¹åÏêèåúè™WÌ«0p—k¹jüq{wW]Rœhàßýß©|þ'.ŒxúùÓò²o²5Fv»‘tqÀ”ǁz=:zÎ7>:N‹‹°( Ô×ëº)}€µîݟNûþ³ýÇJUwŒè׎FPZû¡vÉ€"ÏGÇÿ*0qb…œÃŽßßµENxTiá^yhav+2޹œÆ­«X„“Qs=[Œ[oŠ!z<ºÇûgÔ8Ô/ D€"`›Ôív0õ9K`§}L"§á=ˆ‹5 бž=rÊ­>¶» —ÁèŒTÌH@1Ú%Ifqñ˜aèßÂÃεœÀ¢bbØÝGOXÙâ~ÌÑc.ý[ÂÅè7knýtҌ*ý§+Ü!þyØg©.ØÔÜïLž*% î—ŸÜWâáÑóÅÄ׫;¥ïy*• Ãëz€9œx[ÅWîøš[ñQÑ=0'òÛ.œš»¹ºb¬»æÍÎ Z  °Rµá].jXõeZæ{çàÉ|7ö)+ŋè…c(ž“[¯rÔÑÛý]øi •68þ՝‡*ÿ°Þ­ œ?zCdû.OÎÝX©ñ€&î(°ósÛTi5Kl{ë +ÏÜ–Õœþn²öHFOðíµÈhÏhÌÔ? D€›% Æh·‡ÙÏYø ûc|{2ÚÓò&ü|IÊ9ók¹õ÷óÜŸ™é8¥±Ä’ø?§¥SjóÅhñê5{üê{Žà_¢p!õ!¯ÙËW¡L’ß=²ªµÓêÅ^>œ‘XŸž»æýçò¯kyÊRep‡kÏ^:E>íi'Çë8ÎÞ^ÊU¶H섿ÝñÿqÐüƲ(òu&õ=—£d¡wvŘ8îÐЅM4œFßvË죊îQ/BìOÎÙX \sU,þ¬t‡&÷s”ò{£—$vhÄ↾C_ªcÓëe»5÷7uŸ×¿9RèÖŸ£eµvbáf5ïÛ»9Åß>p²$ìŽÛšWùaQÝҕK>·Ëm×á žEóç«Q6:KññgŽnþ·÷+þ8È-æuž#,vžÇ¿‰~×U&ƒ^>n}µÈµž›2/ªû_÷ŸÉóúÁ3›c®-ôp~ÃÊKÓÿ³w`Q\]ŸÝeèœ7éœY@DA[ì-öØkʗÄ5F±×š±“š1ÍDiÆØ{ï Ešô^€»ûÝ»f}y}£Ì. »ìžgž{Ë9¿;`þsÎ=÷nðƒtÆÃP—)u¶fÒþŠey•.ÝJäâCÞVˆ¢ýUÂÇ\   Ð ðíô­yKF0§faeÿÏK1gsC‚œÙÄüó­ª,­€« ԎŽgäüw€ýeSÙY[0¶–¯DŽþ`mXQr†…\`ׅàâç?ø=>}Í­vºüó}®nÛç•xø‚ѧ­=‹oìøÕ#þ3>Vþn™Qó§Ê^BÐÈû¹U»Û%§[Ð=íd ¿ÐÊߝ|>E¡—Çfol—Ÿbþá˜smÿ“ æÄ‚cçöW׈z|þÁ#;+¥ŽˆWV /nøÁ??>Õ²ŠŒBÛÈÁºˆdä“ÿ–^Û¶/äyßuL +ì[û€[x»Zx9•·°©³ _]ÌñùS%y:W7ï :¶HžÜG”ª¶™ ߞ;Ÿ³M2ÕތIMÍcÜ?›ÀlÃÖù¬¡ŸƒÛÉÜ£àwŸùÑÞЀ1€€4s|D»>a0wé(æäûƒX§fΣÁÝË-³çH& ~·ëùxçnà×à„ŸXûÈ7‰A¡ð鯀²‘öÂÄ4ƒË›~jIŠ¢Ý’Gžk»˜~ñŽyêù›v…‰éf€x› ‰R×ôÿzþßùñ ó>6©((ÒÕ53©r Íxþ ö?g,‹,Ï+4ì·cÁAVOGòoè.¬ù6 õÜM—Ns'¶ ò,–ï7޵,¶ié‘ý$#Ï0ï~’ ‰V \"C]¢‚ÓI1ŒHEE{ÎÝã“ó·vzQ?Zq<çN‚ y!qæßΒ§©ü÷öüíšrúš W^¥M÷Øû¿W[üŸ˜·%$÷^âÿ»Ô57)“JÄ}r䝙«C! ü ’Ž]òø·œüôxiä°'æokóþ@áïµIz Žú,¬és%^ÚJW›©p0g2ά`¿k*?îÑÞò]YõøíäNn*;0/€€€€zà+Ú?^<š9ûÁ@ÖY=Ýl:«¿>Ì9­ÿSЭõª…+¥ÚŽ>®F íY¹ùLzv.ïm­Ks¥EûœŸ;ßÝs8F}c–œsZ^ˆŠÜ›;~ó§‘uZÞÄÅ.¿(1ݒ&;ºœ‡]ÛH=RM>zÉ[gõ̌žœwø¬^€R|Y¯¿°@©,QšU`<`Gì_"]mɓÌ\Ý£³6t€{Ìåã[zdŽz£O9"®<ûÖC“S ·wŽñ{Üᣱ·ø‚’GðÛLxÅ=ŠœBÛi€ÿøŒ­aùE†Ž`©š_MÓÛIÔ_ÜeñŒStzö­xb×i…ü°÷F]°ò."õµ’]²#ÕâœÈùٌ|ß~yáqtö†(‡öA)áÍ׎SŒÍâðÖˊ;0.ýÅz6mëÃ×9‹7Ö0Ó-M˜ìø &hîëÂM³‡ŠœÖÂËŒŸŸFDû[²ôø­äF€œiÌ  jG€h7 ^ÍY8’9ñÑ`ÖEísºûç×?~ÍÐÚìIÏ Ÿú7tò跅§sN—%3.ÉÛT=©¥]žiEÒÍED°ÒœîòϒŽ]¶¹²ù§¶î=ÂÉ~÷þ²ýî|®g©ú³Ç?«`ϧ=þÐÌ5)ŸZ&µÛ÷¡¶‰!wyÓßÂÈg@绁#z&]ÚøãÓïûEÞ õZâócWäkË_ˆ”€fëzou4}ùéäk|ì@Å €œŒjU~á”àڜ‹{ä?íّoÿó|7¹0@@@@¥ ðí†ÄƒÙ±Ã™ã³†²®*í 9›*Œ&e÷#ÃJTÐŒfcÒ³H{^>“™“ÏÛ¯†ØÓþ$#W÷Ø'#þ‰ËöŒ;Zµ{kØu>•Ì©ð'ó(®ŒR{À޲ˆ9uàÀžy15•ÕlßíŸú·”óãs7µÍ‹K¶ ŸIö˜×ª8ÿ2çïý|Äéî)Z=^ޏTgk5®ß#Ÿ€¯mßç•p肗މA…kTH’©›cIyn‘n܁ã>”—üè¹S‹¶·ÎŸùСÓ܉$Íß«øeã—€fÑþYŽ¢)þ|mF»§ “Ò îoûÎ)ieÑ Ugr'YlØg‘dš‘.SŸÉMï%üzõÑU±;>KðS&Ú·‘¢]Uv€€€€šà#ڍˆ//ÁÿhëŠ&~©Œ™>o Þòü¿7³lioÄU‘‹ör¬Yuõ³ ó:glšêñW·‘óÔ“óÔÉehkQÜuÅÿ}Ñ>ô3êÂg»RÏßréŒ`ÚIz<msdÖúÐÂG©VþCcnû ‰I©ÝO~V¹‰“]A·ÕÓѢ݄žùáüáÌÑÙCYõwùÕy°ýoÎyõ1³ŸmÍJ~u³jæLrўWXÄää?ӂu°¶0g,ÍL”íŽÀڕmûüsnÅÛëš—“³Ô¯–çè]ûê@k*l-<sƒ§ ŸM À%:gwmû/Át_wðäAq€›˜'æ8ÁùÕ»ƒ2¯ÞoAp>©Ÿ~^n4§‡g®%b6Ӝì}¯±ösË*IˆÃ'? IDATÏ5)Ë)0"g’ׄœ?ê‚]kŸ¢:¬Õ@žæœäÍÿVퟮ±è>úk_ì z’žkJÛژ—ÔT×hU—êÑâzŽ ^ïͳOÐÏäs¹u ž2è¥Èœ»ºCIZ¶YÀ°î·|E×y$×o“u!utzmüèˆPš%œ²å'?r^œÑ_—øü?.­ÿÞg éõ#ËDZ×U‰Ëû_ŠC6þ!çíÈÜ(,e,öÍn ñ©ì€Ì\.Ñy²¬z<í(D§Jl5 ÀGŽÓÿ9ŸùéPæè'ÃYYú/.~ÞÙʵ;Wâäõîô—Fù†V/#P»2€=òž)þûô%]èŸl*ØIZûY’_Eçι›hLÄNpEA‰AÛéC.¹D…äP±{zÑöºß]ÛH¿’ìuÏ'‘òš‚G©–$Ü€VŸ^4㌁ÍÓ1äM1?œô«â”Ìg©å–Ÿ.ÙDœÞVæÿðȋ¢þ|øÑšyÒñË-ʲò + Š Yý*rNz‘G·°dùþú‚G ÍÙ)dٚšy“ÏŸì%Á£ƒçì¯õK›Žs&œ±må]狈3KŸl•yý#=wžŸ, ÇÀт|O¿$ôóñm^Nàö÷¹xdžŒß÷¡ð/UaÕõnPZ>cWTÊX†û .웭¥2¶œˆQf!í㟥Ç#Ò®*ì5!ÀGŽ›_ޛ;„92wë­&~©„™ýs=‹ZŽ1w1Le#@*ªŒxÏ·_Vš¥¥ìPIO²Ó÷<>Ã;šH£à¿ŽíJç#ãÏþ[ÍÚŠ¶€€Â=nÿq÷Ü» vTŒÓŸt¿7¹©Žªú¿›£mhêyòÉk6±X@mA}Ä6¯,·ð…iúÊò{Q¿KëðK9u͍óæÝ/êŸKç¶YºŠ†\ifžnڅÛV™WîÚÓìVãúÞ°iéYH*ëó*H@_>œŒÝÚ¡º¬RÇØÑŠœÙþ˜TžOˆD í‚F—|âŠµäø¯Õç‹¿ij û/Ù#™àÄ\JÉeÜ·Ln.RèøÁŠò!·ˆKrÇпŽD{S-æ5%ÀGŽÓß»s†2‡ç g}ÔÔÏ&1»ÓÇÜp£nœ«L;uâ%DšÄÈf2ép—N!NV¶Êºs2ëÎÍ ùRéOů«%Õ1ýÏÙê|úÓ(}ar†‰Ž‹MZؔ7g¡I_\\ݲ×'騥ÿl­?;äçòKÏÂŽŽÃ‡c.ó©Ž_›/ÝZPS^)Ò11R©¢c|žui“Ÿfõå6Ã+ÄMztZØLnTn ci Ë”Y›0‡²{Յ!µ³°”K²-‹ŽÓsÚ!ÚÕiñ`+€€šŸ¢ý͹Øãs_g}UÀfµ1¡õÛ܄S&y{@T4òª°:ZQցžfچFßæ;É­'•eçœË«s5ß1Ñî ÐÈøÃ?N;ÓtzrŒyÑQiæj_äÐÖ?W™œõ`üjT>aoÍ_îòh£ô³W3ãÏòùobOŸ‘Lór`n?Ì`Vc6LîÁ&7…-õ™³€œKŽÉt#cÐH;ï#ë3'ú‚€€4|čq÷ÍYC™#±ÃYÿæãzã{â5{Û?vNªŸ¹ D{ããÆ  L€f…\þh¡Ç¹EÜz³W{ì[—OžÁ‰Œ«¶6SmaÈœ_Å6yŠŸ²xŸH»ÅhŠé¿¢]YŠè  šK€h·$xޞ59;¢ï£RX&Ö ™)|'tí‡Í9ý™/ŽPOߝë±ç­ªímŒØ'¯ÂƒoOŠ—þ$é­Ë2•·S˜vnŽ!ºý*æn¬9Ê«ždÓaL4ŸŠÇ'6Ö<@@@ yà#Ú­ˆëoÍÀŒÃ6O ïՅ8ÎdôFÝñíÖ,@*dÃãň ¯ˆÀõbö/Û;š#›ÙØSöYXÓçj‚Ž•¹“Gj Šo~ÎÒtrµ¿ª‰h7ö¬z|ŒÚ;@@@^)>¢ÝšX4cææ¯%íŒçۓœã¢ßMŽY:'™w'4#p瓅vãÞ{§Ûh/ ÿŸ&¶»V2ÍނIÍ*du^7ItIÅP(mNu5—bøú³êñíJ“DGÐL|D» A3}f?æÏ%cٖš‰Iq¯—ïå|Ÿ¹iÝ¥å§3ªH®øLè G ~ñR‹nn…׍fo6Æ,ÃVÔĹ)laÉ$•V0F§—1mÍÙfuâÆ?¢]^=¢œ1$Œ   ͘_Ñ>íÝÞ̟Ë'°­š1‹u탯ž6G ܂}ÿoªZœ#Ü Îc0fC í³ºFy7Nc/6€Sw’ņ£×H^ Ib6ãÝ»­ð¯]ï‰N4äª2–@*}̬¡¢} ¹!ÚUea`€€š >¢ž}=õ>Ì+dz­Õį&7óÍÍ\èί•ÿô±Mn % €¯]­ï¡“Ÿý-öŒ’CüO·‰ëÅ{NKø¶`nf0Ž?~(Üî+*jšñUm #IÕ î Ñ®j+{@@@@=ðívĕ)ïöb~_>‰m£n5œ•S6qá瀭ÛMžÒôÖÀPŽ@úúÏôÝEYé_Ÿ]Ñ^U#ŽzK2C‡T†Ï.bìÛy ®˜«õ‡r–©O/‰X’Š;X܅XL«Ç#Ò®>KKA@@@%ðíÿDÚWŒgCTÂj50bÊ®Ãi­öíZOØhśÔLPséë×é» Ó3Ÿz‡=]W>Ú!nœöWÉäÖnÌ9"Øm–Ž~?¬“(œ>cªK_¡@’ŠÕ_ܑØû¹q䛺,ì!ÀGŽÛ['ÍèÎü¶f*D;ßu³^uU·mëVãúAŽó…†v *G cÃ:}WizæWï²§”5®ë'Ü ’oSYÍè»Ø2ÉDZ?+;–:ö“H%ºőÄvz„"íꞈ°@@šÑî@ì›8œs`í$¶]ÚªVSÝhÐý®N€o«±}ÔÊp  µ€oú\ßEœ–µã]ö€¢`–ý,ö]ðƒd‰®Ÿ¿•ÌŽ]"{‘)$¢]k žᷝÜåˆö   šM€hw$ˆÆOéÎX?• Õl\üœï³Ù¢O¢¶§{«7ú@Žódž– *F }ãF'IJæ.E{ć܈ìbÆÊX)ÑÒbÄW±»T̵WfIÏü'=þK2éƒW61&høˆöÄÓq£™_6œÉ¶o^¿':}f3"GÏÁ6xÒ €BŸޘ@ q$®YgjË¥çîŸÍþÅg†ü±–û$É?gææÕxŠã'Øõs_gïòéÛ\ÛH$’,ÝAââD{s]dø  H€¯h;¶+ó˶lX#ÚÒ¬†šc2µØÀÆ"âÃ7n5+Çà €€Fž»²…IUnÑÙìw|?w_l:m³dšTÂom`é¹ä‘ôøl’߁€øŠÜq@@@"ÀGŽ;‘njŽb~ùò6\¡Ñ5žqçõv¯ç›zXÁà:€€šÈغÅÀ¶"1çû™ì±º\ÙwNl;fäã±ÑÂ6L]š«œŠ|.e$9:ÄÁÄßo!Ú5eÕá'€€4>¢Ý™L7|dGæ×¯ßciz.¢ÖY+Žòµ Ú çŽóà…& ªI@&Úˉhÿ nÑÞwaÍkk'Ž¹Ù‹*TӛбJ*‘äê ÓB®;ȍ=íM³ ˜@@ԖÑN#í#‰h?ÑΝ#?³^bïoî7žëcþœÐ@T‹@ƶ-úvå‰yßÍdª–eêcT*ÉÓøLŽ#=^}––‚€€€Jà#Ú]©hœ=³÷›ØŽ*aµÑiµåˆÒAfŸ£!ÚÕ`œ`"€À¿ ¢DÚóHzð@@”%ÀGŽ»“Á‡Å„2{þø˜í¬ìDšÖ/b™ÅšJÏ`#ï~‘횶øðšZˆÎº,1ŸˆöÃÍÈ­Wê ÙÓ^HöŽÓêñˆŽ¿Rò˜ @@š>¢Ýƒž:Ž{fÏosÙ.ÍÃíÆ÷¢Ã2³QÕÞmŒú@Ž7>mÌ ÐX2¶n2°-KÎû‘v¥“=íEdO{2À.rßSz tÐH|D»'!3€Kóã_ Ùh€€„Ó–šŽªömoèÕ»cºÝÑ@T‚@ƶMúÖ%É?~ŒH»² "HŠuú‹[’þߐ{ڕ‰~    ¡x‹önAÌ÷¿Ç²1ÊIa·#–šŒ¬ò7ôê‘¡pgt!±e“ŸeirÁOíJ¯I/!éñrюH»Ò$Ñ@@4“ÑNÓãµ÷a~<µ”튙˜÷:l±ÉhI`žŸD»âðÐ@@ednÛ¬g_–”»ûöžÊ¥f†ôø'$=>ˆ˜M#ííj¶~0@@ššÑîMŒìÆ|{~5Û£© V—ùÍ‘ŽìšëѳCŠºØ ;A@ày$Òn`E"í{>fÿå#ßJɑoíÊñC/Ðt|D»4 ­=³ûìF¶§ŠãëØ"ڃ;ézt‡hç í@TŽ@ú?¢€ÇCŽ+¹:$=ŸŒ€Ç@Ž+ Ý@@@@à ðퟄQ?f÷œ l/ çÅÛ}ˆvÞšÐ@@… €mÚdh]žœÑ®ü"‘ôør’ïOFØMî»Ê„ž   šH€¯hïß’ٙðÛ[!)ãsØÃ1Òà(]÷îaˆŽ+}@T‚@ÚŠDާ@Ž×c5„DŽk {‘!~„h¯Ht %ÀGŽû6}¬ ˜é»ÙŸÊIa·ÃŽ–¶ë¬ãÝ>[áÎè *B€Šv"Ú±§œ> "©Ð ŠõaŸ#7 ÑÕ%ú‚€€€à#ÚiJ_†ÙQž¢ï3ND»$„ˆöˆvŸÌÐ@@õ€nZoèX•šùÝì Õ³NM,H*µû‹éV3€Ç«É’ÁLP%|D;-žCÓâ¿®ÞÏöS%ãUٖÐùcDí£u\»†f©²° @^Fàñ† ƶ•s±§œωTR¥=Piÿ–ÜØÓ^”è   šH€h§ÇÔÐt_Ñ>@!)ãsûXƒÑÂÐh]ˆveè¡€€ªHÝžÞÈŠ"5¢œ>+"©&éñtO;D{}0¢/€€h(ˆöFZø°ùzca1ڮѡØÓÞHŒ1,€@ãHY¿ÞØŸ*5{ÚëÁZ*áH€Ý¢œ Ñ@@4˜ÑDøô ÷×Õ¿ˆú1R¡Pƒyñv¢7*4Pa)Ÿ¯7¶«NÍ!‘öÃ*lŠj›&•ÔÑîÑ®ÚËë@@@@U ðí-‰ñÝe¢}¿ˆTŠTÕU² ¢]•V¶€(K yÝz.5‘ve Ò~1Iw‡h¯CôÍ% ˜hß'êÄZš‹‹¿çDŽfºi»E·Ëáß -A@@µ$­]gê.LOûæ=öžjYŠFÖH$íAbgbñ÷䯑ojŽt0@@TÑފڍÜ_U?í¬*®ê6ޟ§;ZØ¡›ŽkìiWõµ‚} /&º~œ‘]ejΏ³Ø#à€$íýÅ®€7=§Õã•Ĉn    ©øˆöÖNWrÓôxrô›P[Sa)âwíÒðn:î(D§6ŽP1 k֙;KÒÓü¢œ>K£=€s!ýQ=Ÿ>Ñ@@4”ÑN÷ŽÇ{‰Ž¿F"í:ÊJ!·‰hED».D»BØÐ@@Å$¬^kî,ÈHÿñCˆöú, D{}è¡/€€h6>¢œ AMhïED»®f#ãç}‡y:£€aÝõpN;?^h  šÑîÑ^ïŁh¯7B   K€h&tºû+’ߋ€Çëi,-ï0O›DÚ{èâœv ¡)€€ÊxŽr­…›(#í{DÚëµ6DŽÓ=í»É=íõ"‰Î    yøŠöÎÍ×UûE=ŒP_ó0)î1í#‰h׃hWœz€šG«ÖZº 3Ñ~Tu¬R?Kˆhw$VÿÑ®~k‹A@@ © ðí!ÄÈ(™hß'ê! šÚhu˜¢]V 6‚ÔE uÃç†nÒŽŒï²'ëj‹Ï_L@wç&‘0»H ù†@@@@!|E{€LŽÿBD»ThšÐ Úžã|íáâ°ˆŽkè·A J¥Lªu–îlÖãïfŠi¯Çšêàœ%OÓãï×ctÐ@|D{[Âå©hß/êFÒã4“Â.wøT{íî1¡Y wFPí ·ú$Ò^#avBŽ7SŒ  šB€h§Õã©hßEÒãcHzŒ±ŠÀ©Ÿ‘óµ_¯ íaDD{v}ÆA_h*R±˜Iølœ…‰Ž;St¬©ìhóÑîþhGz|sXPø  ¯ÑގØÓ‘Ü;ªöŠº „B“WhŸÚNñ©Öˆš°ž$ÒÞ‘vµ]EšM@Z#$®]oî®Ñ^ß'AçQSÃì ã@Ž×&úƒ€€€†à#ÚC “2ÑŸŸˆvFhªaŒ”r·ã§¢á\X/Cˆv¥ð¡€€ sbAòçëÍ¢œ=1/œÜ4=Ÿ I7o:sÕgf*Ú«Úõ2òèÑ®>«KAjà*«…[¶¹2ˆŽ×ïـh¯?ôM& h¯Ù'Š’„–š Œ¯ïQóDC+Úõ2hçK í@T€˜ˆö”›LH!ºÔoÞW5ûÔÉ"ÚœI€ý bsœ:Ù [A@@šž€B¢T"éñí<Ö-jžˆöžDއ£^ùÅÚgWîlÓfBÿ;æžN¥<º  €@#WVÑŸ¢œ8›ŒÎyTTËÒã4Àp@@@@ƒðíŽz}h›{?vŸ»çp k—vBŠ F$Š/8ށF$ÀUT Ó6ÉDûã]ï‰N4âTÍ~h“aœOE³8Š¿oÍ~µá €€4,>¢ vZA~GÕÏ¢H¢Ït!‘ö2™hï v¢œ,;_çÑ_çÓ.ÞiQž[hHým=¡ÿÕº^@Ðã¡~7¿[Me2mÈe×.mÿçŒz1Ç D,+}žá•M{|’Ž_ñh9ŠÏu¯>Óù0FÆ%À•WŠÒ¶l1ö$GŸí„h¯lˆözáCgÐh ‰öš¢Ž‰ÐV£‰ñtŸË|fpip/sϞê!Ú¥b1“pèŒ}òéë- Ò,©T ÒÑ®±ðrÊ!)²¬w¿Îñ¡/s?éÈEÛ+[÷†Ð6?kìSX»}qJŠþÑÙ:¹Å„>j5¶ï£ÚŸYöuËÌ«÷[ôÞ2ço= “jž˜Ñ @  pe¢Ž­[!Ú€±Ù0ί¬ŠÙL†Bz|ðÄ    Ií¿ˆ"$R¡&RÖ×®DŽ—÷$¢=B¥#í…OØ€Ãì_v­È+’EÕuL Ë]#ƒ“œúF=Ö16šáËàØœíòŠÈ¶OD/yóÄó{Óå¢^×ÌžŒÏ¶OŽÕ÷à›Ë;qUUlß/>=Êw>Žh\TŽglÛjhñhótö|ãÎÖŒG'¢Ý“ˆvšߌ=…w    M€hï@&mCîÝ€z|R=ÞŸ¡hŽãu/Tܺ»¥×k3TÕ?©TÊü6yatUQ©µÑÂÓ9Ç­[h²sdpŽ@ÀçÑøgy÷“ŒŽÏÛ҉FèéO{møè°EUmß8éxk÷­@:ø»% ŽD²4ùª’2­_'.èaéã’ÕyÁŽ+ªÊ v€Šš.-×Jÿb›¡ÙÓŸãÿD'5Íÿ†ô÷ŸHû&2æÃ†c€€4|”ímÉœ³f¯(\":4,õ÷ˆöDŽ[©ºh?0v^7²oU[€­%&ûÉožwS83€ŠÿCﮊx’‘gÊêëV‘èœNÿ±Y=qm’çVï L¿pǙþ¬ûê÷Ž;ÙVЯŸŸnuñóïCý‡ÆÜö“Rú@ !@Ž7ŧc˜àüK+˜ äKDÚ+F ÀGŽGtŸòΚ_Da$=ÞQ#ÈÔÓÉn € [öŽVeÑN]̹›`|iýÁäÈ5úœ©›CهŸšHŽýöw]ãö÷§•ßKR3MòãS­~·øÚçš°ÿuBl×ê'åºtž°÷GŸwl˜O¿ŸðÙî€Ôó·\bVþß1E*Î×s‰Ð@ UOHzü—[ŒI!º¯i¯×ób9‚ (©`ÖCŽ× #:ƒ€€€Fà#ÚÃiÿ†ù֞ùÖB#I)èt·ùDŽ·êiãÕ[õ+¡‹9± éðy»Ä£—\Šg™SWõ,LKÝcB}vyü²TùœÛñ&§ÕÁÀÒŽŽÛªwϜ\øEÝ×>ø‡¥¿ D¢gÔÒ/Þ1?·j=‰@v ë~ËwPôcZqþÀ„Ør*€ßWó(ˆÍA‘€\Žû°Y)_œ#:ՈS5û¡-ɑo%UÌFâhB³w‚€€4(>¢ýY€Û§*œԂf:X·Xiÿ ž¶êv|YÎÝDãø?N»dÝxà ájD–Ÿ.ٍ»ö|ª;]6ZÄîð‡k:ՔW±N;mææX&/F7ä§¿×^Ús«w“Ôø[Î>:ߥQy+?·¬šØ©WRN^³ºŽá‡Pçšà„v3^¿ßLžjI ª€\+óË­ÞÚُ!Ú뷄$ÒH"íëÈ(ÿurFýFEoM ÀGŽw$ ‚Éœ“ûE«©3&ۓŒëåz.”ôÍ ìaçÝ;Re ÑœÌzVû¹Uߎ)Jΰ0uqȏYùÎUŽŠéî'>ÝÜ6/.ÙŠõžŸ×ôø6—šà€ê'eÚD|›$Š[HÅ!m4ª× ï~Qi$jozzñ—ä|öøàɃ4ù@’.ïLŽ–« •ëì­Š{¬û‚@UØ¥±䢜¥A&Ž|«çS`5’kY\ά&Ã$Ös(tÐ0Љö}Z!$=ÞUÃ)å.íy=ìœû©®hß;bvOIXèÝö‘[Lû4SW‡2ºFÆóÒ rn>°ž·÷X€¶±~eÏÏ?:ÎêéH(Œ€c—m®lù¹-9Þí¿Øú*qU5KÇôÔõNÀ°nÉŽŒP]ÄÇcÏÚûæÜN09¹`+Íà]µÛ*@…@ՓrQΎíº^ZéÛßB€œ>‰hoEDû*ˆöúPD_ÐL|D{'‚Š5¹iz|IwÓLTŠyÝ+¶ŠoN@OiV¬ç«k}vÅЌËw_Z£@KR=Úf IDATO§:ìœQ—l[yQ˒Ž^¶¹úÅŸ`¡–Hbí皥mbTeåãZ`àVDÏe¿²iOÒñ+!ӆ\víÒ6›ö9>w“,>zɛ'äQý³Ëwe\¹çdâdWœìíó"öé™íž@T‡Žg~¹ÍÀW7;™ˆö3ªc™úYòh_IÿŒªŸõ°@@@ ) ðíŽâ·ìœvn¿V0IwoJƒÕen"Úûdû÷láÓ?*U•mN»pÛ"ýâmۂøÇ‰’“(»€º&†•fNùÃº'èY˜ÈöŠ'Ÿ`{í‹ýÁZºÚ\‡Æ^Žt/~Þ· k¿õO={ÓÕœ{û‡m&|H??ôÞgJ3sMúïZpP~ æ“cÞ,­ˆØ×33y–v¯Ê¬`h™hߟÍÀ_/;yD{œ–ßf$׺°œYNI®×@è     qøˆöÿDÚ÷iµ!éñGI ‡{/äzgúörRuÑ®ˆk¿MYÜY‹Õ·oäUZ)þßúÞÜù›ûÃßOû:„€„Ïs›¶¡{çÉþx-‡Ð§ç²ãP²=í_l3 4ÌNÜ:CtV=¬VM+mFsm K™¥ÄºÕŽV€€š*Ÿ¢œ q`·W«µT(ðTUgTÉ®Ÿ‹ž^ŸœœU9=^Q^é—4ùByŽüßúÓªòw<ìâÐÎ/÷EÂ^ÑyÑ@ iPўND{+£ì„ÍÓEçšÆŠæ1+D{óXGx  MA@!Ñ^±_«•ˆx5…¡ê6g߅ÜkiÞ=\|vy¬n¶Ã^ þíFDŽ“êñíõy*lGs!¥Ì"2þMšHô $ÀGŽG.­Èœ“Û§Õ’€Ç{k '…]Š¢=Õ«»³ß h•ÞÓ®°cè  1žŠö-F­Lrã7O×ÇÁQ"ÚÛÑŸ¢œàbHhæøŠv?ÂỊœZ-EBO3gÒ îõ'éñ)Ý\üw…ho¢@àU GŸemßbÐÞ"+nÕxö꫞¿9ÍGD{ð?¢]eOiNŒá €€4'|EûÓHû/ZäÈ7ßæ ±|¡¢ý±{Œ³ïüZcAÆž J€FÚÓ¶n11Ë}°aªèB£NÖÌ·Åæ?aæ7ñoB3_kž   M€hV=ŸbŸV€H  Qw\u ¢œgŠ{Œ‹D;ž5% ííÌrã>Ÿ*ºšŠnš„ÙDŽ·'¢}.1&]% ‚   jC€hÿϞö_ŽüH€=@mŒkBC.æz&¹u%¢œ¢*Mž˜@@yU%åZi[6·3‡hWžâӞDއÑþ D{}I¢?€€hŸ¢œ%A³‹û‰ˆv-ˆv>ÉÀ%\dçhWß×»CŽóö ۈ9Npqí÷¯w‹7v²­x…Sc* pãëæžNÅN­sUÀ•6á™h·$¢}2"íõY,"ÚsŸ0³É™õ}A@@4€B¢œúWև3Aš‡Iq-áº'»D»ú íŽTHÅñ5j²ì|?ß\ãÕ§Óý–cz'4êd\åü>uqg} Ó².‹g\R9ãTÌ ª'¢Ô͛LÛ[åÞ[7I^õX‡7žðÜfD{= ¢+€€h(ÅDû^"څí|ž•Á$ҞàÔÙÕoXODÚù{…mždæêþõöÊ®n1¡ñÁ“=x…Sc* ð۔ŝuŒô«º­z÷œ ˜£Ò&@Ž7ÜòŽ˅f3sȈY 7*FЊˆöoª÷³ž ­$«C–q1£<ü†õ‚hW±§åIíï¬ìêÚ9äQÈô¡q*fÌid¿M^ÔEÛ@·ºûš™gy*µŸºŽ\ëñŠÍŠáV¹wÖL]V{‡šÐûq\D^ó!D{.Š5%ÀGŽGßZ“{wõ^փDÚéמê 0x×=Ñ!ÒÝwøk8§]Ş–’Ô,œCï}íÞ=üA›‰ýãUÌ<˜ÓÈ~Ž ZÏÔ€aQr†þáÖvñéy/pÔk‰*fÌidÆÏïjì`]ÜyátDŽë`͕UˆR6n4‹°É»œz‚èJ#/M³Þq×)§ˆy¢œY/3œF!ÀWŽÓêñ4=ލü7žQ,ifƒÊD»]„»ßÈŸíM޶ŽàÜ©…ÛCÍ<óÛÿßÈ»r3 ❜!Êÿõn·üw}ÜDæ5úŽTpÝÚý§GÆÕû¬ŸNµwŸšx×è¶Ù>±ŠOðËŸv3óh‘9wÒ57µÉ͓‰öõDŽÛAŽ×w1Çr‘9ÅÌ;dœŒúŽ…þ   šE€hïDÐ}ìí <¯¯àbÚDxюôxž5dÓŒžd£ãŸnîÄH¥Ï^âZë÷ˆŽŸs7Ñøäü-ZŽésÝ«OÇfYÝ¿ª€LëøÜaO2òLÁ?¿æR)ãÑ*)ôÏ^`4$oukßšOºÛzdvøhì-u±¹©ì€¢=iýFóHûŒ›«Æ‹®6•Ía^Rˆ.Š¢{‹ø’ßü   ¯Ž€b¢ýãÂHض¯Î<õiíqV<ýG÷ƒhoÂeÌ»ŸdôèàYçʒRšùSe¢#ëÆÓӋ¿Œ™2èŠk×ÐfWÉY\Y%<6ws(Ù`aßÖÿqà°îñ ùM¿öå/~¹wíšóË >ÚÞá³z:¶|¬é//ø°âÊ+EIë6˜wvÌ»¹bD;f/jCD{g"ÚgÏ ê3ú‚€€hŸ¢Ý ù¡z?í ÛNó0)îñð\×ûVáDŽ÷GzŒâøµG깛–Ö|ÛŸý»#/Žoù,Uõä‚mmt õ«Û¿7êN£ЈƒKkñ[CH–Ï€ÎwGôL’O'%‘öãs6µ+JI·è²øÍ“Š.öåhŠJ-‹™Ÿ‡ÍêíÖµ]|ð”Á ~Ü-r˜uã¡9«¯Wã˜ÇêëŠUO£šhO$¢œK‹Œ+Ɗ°€'·kFD{"Ú§CŽ×"º‚€€€†à#Ú;6tû7Õû'FÀ†j(+…ܱ‚‹Ž³‰ððÙ7C¡ŽÍ€qiVŸÎÍ]¿{çÜydËH¹—Snë±}ï·°©š¯‹UEO؇¿ŸjQ–Sš/ÔÑژ—ùŠ~,§×1Aґ‹¶W¶î é8gÂÛVÞEŽyYn¡öŸÓ—vk”üŒh/LL3HwóyøÎuiã_¡€‘þۑyUÅeZÿ8ՂŒ8°Ð·4+}{Øœú®ŸgŠ8%Sÿڗûý ¥YRF.‘!)žœ#Òkó¬*~¢õëą=ŒzwŒßò> Ϗ›}+Þäö÷}Jg™kééTÛ¶öÉžÐÿHWGò2èZßùþ/׿žô•Š%Bږ<+Ud .Zû»—ÈûÒvqûŽ9%¿âRž_d(ÒÑæŒí­‹"Zй÷ìÁ÷æÃ£!ÚÈDûÚ ÑNyז]oˆ15u "Ú£‰hŸBü—ýÍÁ   | ðítO;=æmWÕÏL ˆmÏwpMn7b}Ï,ÌËÿiO¿xÇüâç߅Š«kDZº:*âªjVÏ€쵍ˆDLE~±6Eb‰$I/îד.Þ΅î1íeéê?ÿÁ/ÿA²UÄÇc/·°}&ô³o=49·ê›ÐšŠ*mºW[ÛP¯RR#¶kù8xҀ-‘ŽösGÅbʙÖD€=Û»NEò­ÝŽêŒhÆ *®i{*4OÌßÜÞwP×8²ïûYôý>Xw~8H÷Å DB‰Ž±a%2lË7zߔÛZ{ŸÃ¬ {’™c2p÷â¿®nÛç•xø‚ý\ J£—ŸyÂÌͱìÚö_<óŽœ?åTUq©ö…µßµ'㈠õÚ ï~‘ÏžZLïøŒ­aDàÑù ¯êê'åºB-‘žËâ§èxòùi”÷ïÖuÖ16šìõù'^$4Ï.ßD8: صð ] ù¥È\¿ŒCö;ëÔ®À/æ8Áíoº“î²õ¶4-m9úµ;d8EÖL™gƒÚ~èý5ÉŒZµ×ÃÊÏ-«ã¬q×ä,JR³Éq«£É:ߑ¿D‘·¿œû·ž'iV£m€_ɕUêH%}ˆßãºö¿Ÿ[œ;0ýÂ-gúLZx:åT—•k?IÏ55q²-è¶úœstLúB‡¬}ГŒ\Ù†ú•ÚzÕ¥9Fôù"Ïya§9.“ß“jú9µUþ’+î—-ŠS2ŒI]†d}k Ò È:†:ŽóKk3qàÃÆú[K_â$®YgíTÑ^OÈÎã¹ÈÌBY€œžžC¡;€€€€†à#Ú;&ô˜·]U¿0Ž)ŠaŒ”rwä*®Ë]Ó0oÿ±š%Úi‘·3K¶wˆ¥ÿ!]ïxõí”ʐ¯ÎÙϘD/©P¥‘Ç3Ëvެ,.Ñíºôí‹'æo Μ›`G…R¿¯æ¹¶}ŸW¡§b·váŽôËäeÀÚïBEÚlMÐèÞ·œ:¶Ê±¬ôø§›ÚæÝO¶ñêÓé~Ë1œÿ+zšpø‚íµmûB"çO%óºÉ"ž÷~:ì|wÏáÀôe‘ÿÛßtÛܟŽ)l=®ÿ«·b %…ÌzPqX;R/HŽÏ%¶JéK˜ý!œØ!kM_š„Ï}Ñ:г˜Šáÿù֊(òrI«ß×óÐŸ¿¿&Œøqйü¹n7ãõ{ô%SEáöޞCn‰G/{Rv=?ÿà$) ({¹ññø³¬n y®èћ Yۛ$í>÷ØìÕ¥åºôePÏ &ýdB¿¡/ZááêuV=\ ®,yC„sÚëØi,“UÌL C<ËŒšÇpè     AíßTícì6\ƒø(íêh"Úzû€Q‘viŠÕÄÉ®€ÍT’Š\žw?ÑìÑ¡óD„ ˜×6Ï>¬gfĝZüek"Ôm[Žêuóú׿җB²t‡1wé÷ZºÚ\MÇêöÚŠY'ĕÕÂß§/éRSY͒£ºÎXúº>¡}ht÷×ñ±ÝèÏiŸ^>:ªcbT#_ž”“׬.mø!ŽõžŸ×MïÿsƲÈÊâR݁»¢ýå//tL *\£B’LÝKÊs‹tã÷¡Ñö¶3†^r‰ ɑÏÿÛäE]ˆÓ!‚9îáo§|i‚¡E‰HW»†Dóƒ§ ’íáŠQÛÛßþÙ2üÃ1çä)öŠÎEǑgPáH³)š(&Y÷ˆ°L¢_+»fŠ>Ôê{ea‰>ýš0>IŸúlüýޚˆÒ¬<“°÷GŸ'Åçòsn'˜œ\°µcí"„4ƒlòlU±vdۀ]°o¶¶‘—rêªcæÕ8Gšjßcݧ_ôÇ@Ÿæaï$sŽ|VœŠëÓôrù³zbþòr*юŸ€©}¡|ܛ;søûi_j9’®äðk»žwoÿ0ûæ#êmG3Ò.Þu ßÓô}šqÒfbÿ«îÝÃ3•þcõ’ŽTާlXoÒÍ1çzì(övcÌ¡)c:ãºe1㈿²¿]ž@@@@€/ÅDûόI§{ÜqÕA`ôj®ómãv>þãkŒh— dš\YüD€œëÉ1QaG#À>ý£dÕô©0ËŸñÀþ\š%”üq©žšÑïµ u«:}2éü•-?Ò èƒŸ_úgÆ¥»æçVí ~/ò¯xhµ|×.í…L'ÿ^.Ò\;‡<’ï¿–÷éµiÖßµ#”€ººguq©ÝÓ.Oa¯M§Âôèìõ¡…Ò¬ä㇟3ü¢SDëgûÛŽ ºªšTFgÛNrY.ªŸµ¢£@$öXûÁ™ÚQáÚvÉ#åýwÄ$/!Dß^M…™®‰QÍRšýÈѪð>|ãٞušþç›Ëcj·‘§€“œú‘åÅ¡o¿D ï]ݶ×;ñðEO¹o4]‘¹äsÐñÁ·–w¡©ðôg­Ç÷¿æÑ3üY ºMB™5SôÙ`ÄÁޑ³{I%RåEÒþÿ–ÛH^^8Ú ­}v¹Cž¿d"ÂÍÎ,ûªCm[éþü”WÜ-}]²é~x WólÏÀÓèù$zîþ”fzî;çÚ}¿œ÷M]џyFIøLò²$ôëȟ9’qÝ:УŠvÙ ’¢O3dÛ"ȋ j-€gC}©}œaCÿaŠ/^®\cÝË£ðҢѢÿ©ÐÐó5çñœ&pݳ ˜7ˆ²ì\    À—ÑA“¢#éñ¶$=ž~«š(ÚϮؔqù®Sç…ÓOš¹;”&ŸhGD·1‰fW±˜]»Z¹\˜QŒþ¯w»•xô’M­ik‰ÉÑl§iÚö…µßú§žœéJ¢œGÈþ^}*Ú€„¿?æ6MçŸE÷O“=ã:ІåA£zݹöÅþ6€˜ íô¡Wœ:>ÒŽè–1&ÎvÝVœ+Û[,hÊ#²ôg9wÈÙí[; „)IÑÿ‹#s§)úrqGö!ë^ݺ7 ÷^¢­…—sŽ]Ÿ,š®kf\ùÉÄóÆN¶TÔï6ë5*²h„Žö^cÊ&ëzœcÿ] ûdShQbº¥©›CI…¿ />F¢¬ĶÖ4^–]šG¿– oZñžõ³ÑfäoìSXû$œõ©È“ÿŒFŒ#fOž!;«þŸÔjZd/ôݑwŸ¹<’€~õÿzþA’Ý –ÏËw.:GEa1{jÁövò¬ú3²ŸùQó§\¢cÒïå¢]Ñ5SôÙ "Vø÷Ì5Ï|¯UqíËž õ–¿ì‘÷GDü]š@íümÊâÎ$¢ÌöÛûweA‰vÒыv¥¹Eú&ŽÖOœ:gÓ̐ڬ©%ütä[+Ž®=]O*úÃß}œvŠGí~ò—2òµ?{tðœ=©³€kjTœdÆYòBD[ŸžôóèOÓ÷iù{º¿O^ܝϞ{eÿ`‹««…–¯±îíYxqá(εW$GNuð˜$é–YČ!C<«C¡äpè    aøˆvY!7M·!éñ²Ô`\/'@Eû£¶>~ã‡hL€ýäÂ/Úä܊·þ(µ#%fd·LžÒÔp"„ ÛLpU^à-ùÄëË÷Ž£éÂd?vÎo.ëL£÷4úIÓá©8&•ãK:͝tÑÀÆ¢*íÂM‹ k¿¥EœŒûEÝ Jªµ“ ç{GÌ~ÍÄÉŸ@žÊN*±;ßýéH üõ˜ÚGÏs?þéæH’Ê,Ka—}?o -Â( óUÑ¢kŽM+¯ôŽ»!bERyĞÚÓfâ€ëmýò7¿;ك\ÝsýÇÇYœÿT—ï§QÖ{?õ&{Í-"çÑýýO÷ÙӋVv?òÑ睩à×55®ŒûãßAn]CÉÑdOÓÚ_vÕçŽM‹·ðqÉ%ûŒèÞgú3òr£ÂÔÙŸ€îó&é×¹]—Ÿ%Û;ïç#NŠÌEE>ñǗŽëœ8¬GÂùÕ»[åǧXӈ°K綉€]"M­VfÍN/ßъfað}6H*{5}¡C}*&™òâÆÊ×5›ì—äÞydG³8¢b§ž¢E âɞöÙ¢è:vš3QV Õ#YZœ7Ï9L¶"Œ0RNÛÒ}î§l %/ƒLHõùëŽÀ!Íæ8·jg(¶ÓgØ‘gáé\@¢óV>.%òbôÅÊÑYë£è¶j«‘ÕZÔ° á±%ÍÎÐ57)‹š7ù3•%¥ÚŽ6ƒ±£M!Y·ód˃¬šý_ï¬ìH_T‘}í§êzF”ùœ“>X¶ÚŠ·Wáˆve>í#íSˆh/€hWž"z‚€€€æà+ÚÛDŽzŒ5I§BWÞøŒ‹ºeâë7~šÆˆvy1/C[Ëâ®ËÞ:'žþ*’²L£äÑKÞ:E#–Ïܰ€éñ®]ÚfËۋ91ٓŒ*¹cëÇ~C»¥P!}õ‹}AD0³úOãj9ºw|í”dZxŽDš[Ñ1"È~r*ŠÏ­ÞškbX%|ÓÊÛÇf¯2÷pÊ%Ø/Ѷ4JN …uðêÕ!Áµkš¬‚}¡óv÷öó©.)ÕÓ#‚Ê%*8ÙwpהÚÇrÉö§“¢p4BÚkã¬ãY×tX‰ü(9¹/to3‰œF‘jêdû@¥æò=öµùЗÆö–OHŠ@Ö±9#…,[C„ÜYyÁž=v4ó€Œ0èA_X<ßÆÂ³E|#š^-ÿŒ€Ê_”g#Ðâl|çºóÃß.÷÷  ãxõ&…ÿÞxZø^»Œé'¿ÇgožÚZ”ÐmôçʬYæÕ{VŠ<$‹¢”T§ósÛÄÕî ÙkßZ¶E\t«±ñ®M—,œÚùÛÔÅÑ5åUì€] þ¢‚Zþéù-ÿƚTý·#iì4óˆ± öK%§ÈRÆé ×wüê›s'Á®öÐtvc›¢Öûߊ/ hö9Σ(%Ӝ3€™%Fö6Eä¹Oq ͔Ÿ~@Ÿ—?Š-‰&QôŽvo »G«žßýá/7߁]“k¿Xxôçû»?öï÷uìáÆø£L㖮²ëç]x>v$"íÊ2.¯ }§IbˆhMÆ(WvôÐL ‰öÊŒ9tJVÅ×Ë Œ]ÃEÞÔ ñó›š9¢ ßCﮊ G]ÑH¯ÿ°î÷Hy¡IŠ“3 HŠ·Mæõ8»ÊÂ'úÝ×~p\×ԐkŒs©©à!Õëyñž[©ô‹·-„Z¬äù4sežkZÈL‹TøŠ•ì•éÿ¢>—Öÿà—rꚍޒ́û$‚E™•fæéŠ]žm•yå®}Iz®I«q}oМó²ÊõqÉ64Úmà!{ñ`ì“CÎ+Ï¡‘[RÝ=ˆ{R®C*£§ÉŶ|nŸsÙ¶ôJO=ËõùÚòqäéåðüš)2]K*Úå™T˜—“4wr€ZMíl¹Mô¥ Éj0’gtЭ‡?\I÷æÓ#âHaÀ€p_iMUµ0/.É8õÜ-»œ{‰ÖÚúz$£¢ÿíók¿ ‘(~Èô!×kŸÁNǧµ²nśå?L1#uL* Šõ©ˆ'ûâ/‘B„ÿU€ŒúH¯ý(Â@QÞ|ÛKI„øî’Uvý} ÏŎ¡_pϵ+¯ ýgHbÒ ˜Qä£gGX*9º€€h>¢V‹oGîo*÷1B¥aŒ”rwÂç\Ä ý¶~>c‡4JUg¥ŒzªJÊŽÎ.ÛцŠJ¿h:º's™ž×NS¿OÄnë@Å'=Œ€þˊþñ¹øÎþÁèËôs÷ÿœÏgüÆl#í#{ݔ:Tt>ÊîìªoÚV’‚}²ŸÏqе\£Û= ž\÷VEçVåöôÈ݅«úûž…hW~¥JËÅ¢€·%1ùÌH2 D»ò(Ñ@@4’€b¢ýgÆ\(b;k$)–EÚu[ûùM®1éñµÑ4àä“WI±,=†IzyÙgœïÐÎ?î?W§F7§Qò‡œv.ËÊ7${ùµHa¿J3Wû"‡¶þ¹Ï§Í“Ôr3unOöM‹h¶ƒugÙ#]V]ZÁV—U°$ž­zRªSUTŠKþ««¥ÃÖø èò@^å^‘¹TeQä'<nœ¢öÑTp’þnOŠÕY“Ú ºZºlŸ•y™MGIŒÝ IDATž]°þË27K]Úӗ9wc—9 ò/>óépÑu±[Õì,!¢œíiùÌb[¥ªÙ{@@@T›ÑN£ìaäÞ]¹‡1#{lŸUiVmךֺ±k¹Èº­|ý'ŽHoZK0»Š Qã[»ÿô¡•î_ä;ÙË-Ñ53*'‚Ÿ$hdÏ4R¯®œäÇÝÕ>>O]}Q5»©h¿3™Ã âÓs_ÝU5ûÔŞÂN+x&Ó9-W–—–ê²p°@@T„ÑޞØJ«Ç[¹ŸDÚ6ZElWi3Æ®ã:Ý`[ùûO¡‘‘v•^ 1ŽîÝ&ޘì{7¬)¯`Iž2#ë2“¶eFŽÖQO )ÐRa¹ԜžÖæOº¯™)+€‡«áÜ_ŽÂzX`ޙ±užbÐp³6¯‘ ËÄZ!ïHºŠæ3Ã!ڛ×ÚÂxøŠvißU¹—1 Ù®¯Â0uŸc<í׎ZúûO Ñ®î‹ ûUž€üžÁÈùô=÷gÇ詌áj`àíyKžž7œE€]ÉõÊ-³íߗ‰ö×ÉÕJƒn   J€h%lh1º]{cR!;FCY)ä6D»BžÐêE€õGÏ1÷éy/pÔk‰õ ÿ‹íƒ ɞv{ڕ|6šh›)‰yœÇ !CpJƒn   J€h§{Ú#d¢}?c(bØnÊJ!·iõø«¢ ÿ)£°§]!rh ÊH:zÙÆ1<(÷ߎySnDô¢šhB"ísiWúEÚg’H{3¢]iŒè  K€hoKèt”‰öœŒHÈv×XZ 8>q=킠¿©í `CS#pgþR‡þ…gæ#Ò®ôÊdе;~,霜#K¯Qz tÐH|D{kB&ŠÜ»¥¿0ºœ”í©‘€tú©h$¢}4"í ²CsÕ!p'v©ýŸÂ³óG"=^ÙUIËëtþDÒ%%‡LÆ+;ú€€h&>¢=øÑŸ«ü{†ž] ÑÎãY™Žë@D»¿ï”Ñ™<𣠀š$;±Ëìú{œÅÞVIÕÀ(*ڻ̖D'ç1ƒ ÚÕ`Á`"€€š>¢œ ±¹3¹wIc޹ö5óA%͙BDû%© ßŽ7iWÉ‚Q |Ü#¢œ¯OÁ…Ø‘ì->íÑæ <&¢œë'’®$=~ùTF     >¢ŠÇÓ³Ùw•ïaX-¢`*Ú/K|§ÉàÓm@@@ Ü[°œˆöüó±#iWv}’sÄºÝæ’H{ӟŒ!UvôÐL|D{K‚†ó¶Kº—qB¶f¢RÌk™h—øøN Ñ®:ŽP!÷b—Ûöñο°éñJ¯Jb†X¯g¬€KRÓOéAÐ@@@@c ðí„­¿[º‡p,ÛWci)à8D»°Ð@@e h9™)Ûӎ @@@"ÀGŽû“ŸŠÇÿID{K«ß⪃ÀŒÍ\èyη¥ïôq8ò O €€Úž¿h¹M×üËKÞ`oª­Mløm"Ú__ÆD=ÊB€œ‰—Ӄ€€€Zà#Ú}‰gtÞNrä[ 9òm ZzúŠ–EÚÅŸŸ3 Ú_1zL Ѐˆh·îéšuñìV£†º‘ÀøŒ‰x”!;ò €€€(D€h÷!#Ҕ>š_MÒã)4ƒ†6ž¶‰ ¿XíàûæxDÚ5ô€Û Ð< ¢œí$ÒÑ®ä‚^yÀýœéð¢]I‚è  šM€h÷"ˆht`©_EªÇÖldüŒŸ¶ »$õñ÷™6>›_ŽÕ#ð`1í.íõY™KqœÉ„õLøˆöú`D_ÐX|D»'¡C…úéïL%DZC4––ŽO!‘öËÕÞ$Ò>‘vž¡)€€j ¢Ýª«KþµeˆŽ+œ0ˆhŸ²‘ »ŸÆ`{™ÒÑ@@4—ÑîNðŒ.íû™rŽa‡j..þžSÑ~…ˆvˆvþÐÐ@@å<$¢œ‹sþõåcÙë*gœštæ>g:cÓ¢]M f‚€€€Šà#Ú]‰Í#d¢}SJÒ㩀ÇU"íþ$ҞX   ®.]iÙ¹EîÍcÙkêêCSÛ}âgöþ×L›Ûɲàž@@@@@!|D»3q4¹¿–îfžpì0…fÐÐÆS6r.s^~ŸoN„h×Ðgnƒ@s ðhéró.-òo,‹#ߔ]Ïã79ó÷ŸdÚÞMePÈUYˆè  L€hoñhß)=À”pvžóâíº,=ŸÊËÏ等(DǛ‚š"Ú-"òo­H»²ksägùáNŠÍÇ²ú0ž@@@@@!|D»#q<¹¿"éñE$=žŠÊ㪃ÀdrNûÕ"Ú߄hÇà  Ÿšhïè{ÕxöªúzÑŽ–ÿy™³úô[Šõ­ˆöŠ] Ì  êI€h·'®M¢¢=kS`nĎTOW_­ÕS6p®Õxúxœ9)çÕΌÙ@@ á’‰ö­L:g ÑÎçQ™žž‹ž-ñðð˜1Y-Dûý}ǜî|ÿWÜ7m#ýJ /—\Û \‡ÐÀ<= “j>~¿¬Í©ÅÛ[gßxèÐkÓ¬¿ ¬Ì^:m›w/Éf෋ÿªïŒŠôç*ª„—>ÿ>À&Ð#Ï£WDFퟅÅìÙå;ۈ«kŽº,š~Õ×+26ڂ€:H^¹Ò€eîÃõ“ØKêh¿*ØüÍQÎqûÆý|ƒÓWTaA`€€š>¢Ý€øô ¹·‘sÚ“sÚ'š™Mb®º‰v®¬BtzñöüøT«féã’íÕ»c"ðJ¿„82k}haBšåà—ý!ŒüÑ;»5ž0)ÃŒÿŽØÃԞãŸn©©ªÖê4{⃚ÆZÔk_ðLøë¬·{÷ðm&ö—ÏS‘_¬}bÞæö¥Ùô%ññø³vÁ>…eÆU!²j¥I+ÓÜø Sًªb“ºÙñåߜóÎãŒÛ…8fžºÙ{A@@šžÑ®GÌü˜Ü; Úù/ØÄu\Ç;7÷é“ ø÷jږ·¿;è·ÿž¿¥¯KvøÌ7®çÜydšy-Î*?.Ùª4;_&Vég³&\eõßgþ×;+;V•”éôûzþ‘º<¥"œ4+ߞ϶OŽIÅbæ×‰ »V—–ëšyŽÈ^4ýbc§û{æšðâ”Ló–cz_÷êÓ)ÚI#ì'æn£‚]ÇÔ°"xòÀëmÔf]ëbÏAàeRV®42ËMØ4•œRÊØ~ˆsÞ}’q=wŸ¡Üè    Éøˆvh¹·J¥L÷ ;I“ñõ}<íqwW×éSÔ&{uÛ^ïÄÃ=ÛLpÕœ{Xfm_Ër µoó‡Wêù[.€ˆ\aÔŒÉuLŒŠxÿ:iA4«£ÃõÜðÑ©º8›œ±]UÉݞ>–µ¥óÇí?æZ˜˜núöð›dï}e]c(óùŸÓ—F’¹Œ:Ιpƶ•wW^):6gCXIZŽ©®¹II‹?[Wj¿2ó¢š*ÔÕ+ s7NC€]Ù5Úzsýñ4ã|¢]Y„è  M€h×"„–PÑNî„êý,=þ WžŠv"Ú'«h?1oKHîœDÛë>8òo¢˜FœO-ø"” X¯Ÿ‘÷ZŽ~-Q‘aßÈ9=ˆà/êºìí:#v¿¿&œa€L·ÕkiXzþŠey~‰.)pWhîéTZWŸ}þËØy1DšëŽüƒZÚ¬äø§[򾂤XÓ=þc§­«êý‹Æ¥Ù$S@KÑÊú~ ÐPˆh7ò3ÊMÚ2=ßPcjÚ8›þäÜöcZœº‹=횶öð@@‚Ñ.$­ ÷fˆvþÈ©h(òtrž:é¥UÒùØø-›²žsUQ‰ŸÏ€è»º&†Õ±Xð$#׀€Æ–e呎!#• HQº²Ns&^ 6ýòóŠÜ"]÷ž2^¶Oî™'‚ž§•Ÿ[VTìÔ+uysðÍåtŒõ«º,yë¥ûhI*»þù5»Û~M×ÌžüÿÛ»À(ª­àwfv6œ7’@ $ôÞ€+H‘ òPAEP±¢ˆ ¬ˆ€œ‚ bEAŠAT@º‚t€wHÒËÎÎÌwî$ˋ|*›dw³å¿Ÿû¶Íœ÷œß,ʙÚ÷ý'Wo~ýóF§6ìL6ù›•ÎOݵ!º^Íܐ±ëPØî/šŸs2=Òàg©Ö¢þÙVc°Ý®nís¶<·çHÂuOßœ.¶IÊå+ósÚ0ÐÖZT,w}nÜ&G\ðïj¶øåà{Ú„œ?ñÁxùªÐÊ3®/-ûÎ÷Jí%[Xõ5{ØH_ʹB€ à{Šv>ÓÌÒ¢ý°e±t'ÓE^Èãñ/·¿Š\wؔR£æž±¿uš3àmEõ?Í Ñðšñ—"Rª_ªwÓu'mÅå’ÑSº[r ü¯}úÎuqMëþ%W:>bë ›÷œ>aÝÅ#gBÖ¿üqÇðډ™ v9Tt1׏ö<ËŠ€ktÃä¬È”êùeçŠCé¯MŒËî2eì6þ9/š.][œvÏögmçÓ_~û.þùÒ;§v£«ÎK}?xê§²×8öӖjdԚÎÑ×n|gÒO(Ú˳ư¬+ÎŒ>3šŽÆ©Ù÷É\1Ÿ7Îñæ%õÇ,ŽÚmޘr‚ @À¹öí/Pó©°|'ÑÕãEɹayþè£f)]ŽÉµ“ÆÝã{ÚÓw_÷âGxñZ=6+ŒVÂ¥°ÕrC“âò“â þ®˜ä‡Ë÷‹œQÐû?ÿ~僯v£‚_ôً+Ô"‹žhÔÓ}hƒÇùî/ÿõȁõ/}Ô¥¶Ï²HM ?Ϗ0Šv3í÷xFÑn+> ñ-=Û³rÏí=ºvÊû×ÒùïÙtüº²} /åÊ+˜Þ•ßÓŒÿGϬ€œî‘¶¢¯É]ۜŒ¬S#§àB–ߎO–5- Cïkvi}äš{‡ýÉÇáç¿'^Ó蔭å÷O_L…obÛÆ'h#Àî“ë¶Çðñhã…îÓØd;žï‘?µ~{Lb»&™’,ì}\ökâÎO¿oa[žn-WØíå ëþéÂsÅY¹òòû§_ÏmoQït|«æ åį۪§mÛ_ÝæB§øÓ•ó»Ç5¯{†N+Øn?7íŒ?»ßUE톷&þŠØ+–ƒ€«Ο93°¶)ãÌG(Ú+L>s‘R÷—],vÕN6ªÂƒ # @>+`oÑÎ/D÷%µÝTŽßAE»ì³bv&΋ö~) Õǎ͵³K•.öǜEu¬Ü\·õž¡¿'_ß&Þ`2œ^ýÔ;]‚ã¢r®Œ"ü†Wæ6=»u_í}/æ÷Z?µqgôæ×>og,ºò–og¶ÐîŸvŠÌíó΀µ|îoožtcÂ5 OvxdÔn[,ŒŠÈëõÚ£ë÷-ø±æÞo~jB‡­m;á–}öÄ{µel÷h/»ì¹Ý^ypœ_È_"àËüö΂'ÖlMá·Á»xøtŽŠX/"ú[è¶y[øùëŒ8_1áÕîü^÷]Ÿÿ»m|~/z:Ï=Ÿ"õ»Z.øŽH{sf@-)#ýãä«ÞõÁQszÛ8Ó*õÖïe1+¶£h÷¶u‹| @®°·hç·|[Hm';ovEpž<ÇșJ×Óþ)q‰cÇþå\mwÍió¬ÏóÛ¹5¹µ÷Îú®?eOœª¢ KÇLéÁÏ)oy÷ ­)=Ú¥óCÁ7͚ߔòÍÇ0ÎÕ~oò*“Ù€-œó¹^šª &ݱ1ŸeýËWÕ_?mn³Žmûjðœæ=^}ОBõÂáOô‰ª[ó\ًÖÙ.”7ð³–ÓáüüPvÉO¶¶žœßŽäîmÓí‰ùߖùõÅ9-2vLäˈ&I$QãçÇG7H6.žwå…íx<*íeï?wêEsÌÇ~ÞŸw>+0¬zlnÒµ­2"BŒ=ç|ïÿÒÑS»+…E憃ºí­ÞŸé¹]ŸÿP—ç,Ê&µßì§ŒòÔ‚Êæ‚þp”@úÛ3ýkèçæ>$Ôð(¿ÀK ”¿d‘Ë·áœöòë¡ @öíSˆjµmާý6ÚÓÎïݎǿÜ:C¹þLPíØÄ»îñˆ¢}͔Zß{$>¹këíÇÛoïÊ=üÃÆ„s—¶à^ó .ŽZdµØb✣Ü yaÚ`Ðõ{ï}lë» ê[œ5U2ËV~¯w“ŸYÍMË -º”(ù™­¿c“íÊê‹o{Ч(KêM³ŸùÙV,¯šøFû¬g#‡|=í¿ü3ÛÞ|+/"¥ÆÅ˜É«5«{©"t£CØ;Ó¡ìa|,:[á¥3]<¯/Üã[Õ?ÝjìàœeaççÝÓ¹úŠŸï=¹Š¥ÿ×{Öï[°ŠŽ XÕäJW~.ÿuÏÜý‡œÞX®Èxû5¿D--sÞÃòWÏí-óñ¢}ÛQ¶l í-9!@€\'`oÑ>‰Bú…ÚoTŽ¢¢Ýßu!zæLÃg(Ý҃jG'ÜuO'dðÛÛ_78±v[J“[ûОö.víi·åÅ/à¶sî÷M 2/‡$Æe%^ÓøL£¡ÝŽeå™×OŸÛ’®Ÿc;„ý9‹ë_ý[*¿’ºÑŸŠï˜†Éioé}¿|*Á¯/~D{œ$–œ*ý%k«ŸÚŒ+±ìÅÜö}ûSÒá•ëð ҕuö ËOhI·];ø€œþ«Ÿy¯uæŸÇªÑå¶ÚöÜ_³5ö÷w¿iÃou’Mçî?vùÜ}[Œ mìøØmÆUâÿíA× H:Ž|]k‘"ӅôͪJ-Æ Ø–Ú»CÚÕúâ{T•À¹·_3WÓÒ.ÎX^]U1xúŒÏ}©4ÞuŒ….ýÝîé¹ ~@€\/`oÑ>™B[Cm#OW¿ÿR ¹>l÷Ÿqøt¥Û¹ÚÑÕ<€hç·|;¹qg ?ÄÝٺŹ…Röñ³Á¢IÔ’ªüÝ¡áüjñg6펩ѩÅ9¿Ðߋͯ$ŸŸëP8Ü—Žž §[·e寷lp†ný¶ÇÞ|ø…åèÖtÁ՚׹D‡õ_îvðûu‰–ýZ7¡mžûøæV=öÆutdÌï?OW¬?U')ÏZl3÷ =µqWü¹}Gć–ž3úË=®étòÒχё?Òùï¹êŸœñb9žB óÝYr¬%=kþ£2ßp‹GžýLirà4 ^Ž…ÝQîè@€€ Ø[Ž?NNü\ã_‹¿“F L ôq·«ŠÍÃÊš‚À˜fS&–ë¶cW ž•¿Wü†óÛ]Ì2£#h¯üåù­ã’»]sžl±Ï7,œû…žt^ÿi:¿ßž¥pWOŸlÍÉÛ4£Sq^ßM>}ù"{ޟ52ôT¯Nmy荻äß<5‡ªŽ›í'3™ß‚õlLUǂù!@ð<{‹öñ”Új+éðøátx|ˆç¥êڈ'~¬Ž\“V­EÝÇ>çڙ1›; Øîm_»{ÛCå¹Hž;ç„ØŒ[àðKÓ¢ºÖŒžcÚmòïÎÔyÙñÿœÏfŠ/~ew:oŒ @€€· ”§hçW_F‡ÇßB‡Ç‡z+ˆ£òšBW ^z0®Cƒ'Á•Á…êãüöÖW OüúGí멌ý5¶QJŽ€„Œ\àÀó/Åh”µé©aò>/OÕié=ú±Òêb.?[ÃîrÚ$€ ¯°·hKÔ/”nD1ÌkE”ØÌEJݹDwo:å±rÝ>ÍAÓc7àçŸ/»sjU±Jƒ>ñÛýçÝ0T„Ë{žy1ñÎvÙ«îï'ó£­ðš€ÀÃs”Ö¹…L˜÷ Šö ð¡  @Àçì-Úùyxü‚jßÒáñÃèðøpŸ—» À‡+”Z¯­Œ©åó“ŽÃ \€ßVoÉ詜£ÂòúŒûÄZš@ÀvL~>éñÞ¹KG]/cdWس•k ‹˜6÷vw‡@7@€|XÀÞ¢ŸÓ^Díc:<~(áÃfv¥þÍ:%þé¥áC[œ<ù˜]°Oly󫆵³ëöí|Æ'F’/ðÇÄgkŸzKá×}ÛÊç=>™*JàöוNÌÊÔ/6à>íUŽ 0- @À£ì-Ú§R–üæÓSèðø!tx|€Ggí‚àÞ¥Fû4ä?͟~øž º`JL@Àá¿Mx²ö’Ç•9 kÊùÜGŒaŠÒþc«üŽ“ ô‘”‘& @°·h¿•æäË~F‡ÇŠÃ㣃Wµï„4èà1uï›’ÏRÀ€€G çJ;¶Ö¡å×=*p7 vü»J;Q`ʇ?2~}< @€@¹ì-ÚGКµùtxü :<>º\³øà—òUS‡©!ã’þ3âBtƒä\$@Ê€€‡ ä<"ÿƒèoÊzx*Uþœï)m©hW?X‰sÚ«tE`r€öJ+ IDAT@€€‡ Ø[ާüdjŸÒáñéðøÍ×¥a7ž<.²wŸ¢šeºtbL@ÀׯóËYŸÌoÃtùs ç³CÜ÷ŸÒVי>ûGܧÝgH€ P {‹ö[h?j󊿕’[‰9}ŠkÛÃoÓ^X÷ŠëNûLÒHðŽE‹ƒÌ{7®˜*/ñš€ª íU€Ž)!@^$`oÑ~3åHíë©ŸŠ‰ÕŒÈÀi©t{#vhFhJB³ÿô=êŽI00 ' œœóQXRށ³Ÿ?*ÿâ€)|bØ *m5±W2~ûT< @€@¹ì-Ú‡ÒšAÔæ-”ú‰"Šv{”ÏKŒaWVT“kîœùO{–Ç2€ÜIàðŒ×£;FŸÝ=ëNy«;Ååi±ðûŽ«*èœö;é?ºüN,x@€ »ì-ÚùmjøãçXI}5AL°{^püu;.ÿƒ]×áÁ‘{“„¿šùðo©CÀöMy)îŽvY«'ô•xbüîóýï)׈"cïþÀîíî²^ @ÀSì-Úo€„’©œm](Ýš‰b¢§$X•qNÙÞ€éŒÅ75Ÿ¥÷¡Ðq…U æ† P^Mº4<¥G»SÕZÔ»TîЀ@ dŸH <öú[Q{ßÞ­¢ŒfÚÑo(«…³ÜWG°ûQŽ{ÍjE"€ — Ø[Žw¢ˆ:S{ÙútƒÆÄ.‹Ðƒ'Z€vIœ8ëÜšèµ.€öî˜æÁ© t@ÀÇŽýò{¬Œæ›Üµ/É |,u‡§;j–Ò%¹»ðÒxöÐ•Y>„ @À«ì-ÚېBjS•%ŠÞº&$yµŠƒ’[€\›8å+mRPln9fÀA ‹a 8]`ïŒE5šdmþsþ#òj§Oæå Ÿ¡tk’ÄҞíÂ& c™âåé"=@€,`oÑ΍ç·}{RYlê¥ëBMÇá•Ã}gœ.aÖº˜Þ§6íŠïððÈÝžW®f$¯Ø:ýƒ:·¥Y1y˜ŒÏ+taRC§)=;ÔeÇ»‰MŠÃã-.œSA€ àöí©”ë]ÔWŸ3õԙPË rwz ËŽÎñoí©×õèO[j4rýѐ„X\ÌÉéê˜p„À†É3}9æÜ»íëÉ9ŽϗÇø‚Ò»GKvðì)ïË¿ä@š˜€œE;ß³~µÉÊ"S]ø•äñžŠ/Úçe_×vÛß4¬Ù¹åÙĶ/ €€» dH Øÿþ§IG^͙áî±zB|7NQúömÍÖ?ð›î ñ"F@€ÜKÀÞ¢œ…ýµç©ho‹¢ÝŸ•xP¯4UœûúíŸ,I5É&­ÉȏÚ×KAš:KÖT÷;º#wÃÄóŸU]Þ3s÷§”!CÚ³O&Ìa_zOVÈ€ W Ø[ŽGP@OP›YŒHj'bœ«ôôyæ©}“?ÚØåäú íŸG2›5OÏ ñCÞ-°ùµÏ÷HÍ^÷þÀ³ëœ;S×d×y’2|̵ìÉ»g³®™³@€ àMö큔ô3ÔÞ+^,ut1؛œËè#·t_ýíökê÷ër,²NRž³çÃø€** ë:ûù‰·Ú}ñtà¬naÇpJOE!Ëôkûˆr۝ײÁ÷ÎeéC@€ àcöí¹ŒHm®e¡Ô‰‰¢ècN•J7ƒ…›;L‹}(ŠYý‹)=Úâ/m•ÒDg@À™g~ßy역Õ›”ñjœ”ƒ+W;§@‘ºLf#öœ`+9ºC€ à£öíœç¹€öãáå†>jU©ŽG|Ù}[ARóÖ÷ =P©Ð€€vÌ[–bò“•#לãÄi|f胧”ÀA¯°îϰŸ>“4… @À¡å)Úl˜ÀŽíxGÆùìX‹7«Õ&¯ˆš:zDzHB nýVCtœ/°ö…9-{®·fN“k?›÷ÏðóN%òÞ÷X£lŒ÷g‹ !@p†@yŠö»š×dæß^—gâ c^÷„õfœ]¿7v¿ä ù"G@À³Òw?Œ|}ÒoÏd¿Ç.àÐx¬Ÿy«”€'æ3ÿÌ\öš†Ã€ ø @yŠöAÍj²æ¿¿.ŸöA'‡€<}¡Rï«-þŸølš.Hž.€CT1 à(­ï[¯NdÞ¡ïGZâš1}}œ¿TL]ÀNÃëŸnü!@š˜@yŠöÎM“؈­oÈÛ+6z?§ú{EÖqHۃçÚ Ž wP Š€õÏØâ×ÇÎOKÑ Ý%.OãŽ7”ºŸ¯a»)yžž ⇠@ jÊSŽ7¡=í~IÜ(©U®çÏzë åúB 3×y쑬Ó,…»ç¯Rd¯8ž|}‚i÷ÆÂMOfê ¹I×MRêl:ÀøõŸw“ @&Pž¢œvÛºì…Ƌ¿7¬)å{Xžnî²ß”Øiß²n¯LˆúaNÜÃíA6¹MpðY-/PoBÓ#‹'ô—û,‚O£Ô=s‘-€¡79ax @€€”§híҘœùøPqg·ŠÒ°qZŠ}Š*7Ud—ꌝµƒÕOvÚD€€»…ÿòóÀ¯*Ú±8)‡@àP¥žÕÊÞ§.‡ÊÑ ‹B€ Ëå)Úýº7e îèÎþÚYNƒaÅ~Þ¥FMüH8ý±‹?‰»¿}ÅGBO@•ØúÒ;)·Õ?±rò0ùÏʏ†lº®åø Rù¿ãŸ¢– @€ Pòí¬WsöEûF,còüÅ®"Øeû zIéâϊb&)à¯ÿñØÔ€{{««îì%ŸðI$ýóåÇбghªÑ.˜S@€ àÅå.Ú%ƆéÈúÏTæ‡üáá Ï×* Ϭ¯7²ÝãcpŸd™b@à¯ü<ö‚_VµK—Øâ§äàã$]Ӄ©[ÆÑ O;i @€€”»h'—Ví뱇—=#® ”TqrIšC¿­×{ûIsÓ¶nAáîqLßÞŽ$kÛwR6MçÉ&I÷­ì]—­ÈŽsЁ*Ý„EQ›íº™1 @Þ(P‘¢œfœDöØ÷Š'p1:Çþ$2ÔpsÏϛܭZ­R³Q}:vtŒø²€xtŸeï;s«õ˜øeÝD §á8óÇ °æJGšb'µŸ9Ɔ @Àû*RŽF³'_œCÔF^/áâ:þŒ ÞÙ|þ»¿÷MŠÏ©{cç³ÃAŸ(}AßóâÌø—oÕ÷i%÷EWæ\Tš, Á&ӜoPÃu\‰¹ @^(P‘¢3Ü÷è@–üÒ(ù€šTiJ›ô†o«·vÚüÆ é¢tÙõûu9S¥ar@À³è<öíOIº¯{ÁŠñ}dÁã䵩ëÚ%¿Aêbšf&µ NžÃC€ à-Ú»Ñyí#ÖN“·ø€‘ËSœ«õ«œNo‘úˌ¯[Å7¯{>¹[Û — !¯ØöÌôÚÏöÊüføu2ŽÜqÅՕ-æA̟ŠêAíWL‰9 @ðnŠíuRª± '‰G֔òœ›šj²Ëc~Ò×ÖÞµŠœ¶PpRb~ÃÁÝp*BÕ¬ Ì P Š€/œY{TËÌO “÷ydž4]5^ŽPç ]Ùp =Ú7ž–â… @Àý*ZŽ…ø³'ß'*·\+áðm'®×ÝOì9+â֜ÐêáMîx܉Sah@ÀKòÎ_’Œö~Ç{\úîŽòI/IËíÓíŽi€ºœ}™Ú§Ôp'·_k€ àþ-Úyf÷ŽëÅRßžGÆ_J\°žGÎÒº*Ž«UüíéÖ p“ ŠÄ€€ \:z:àØ‡ŸÄΖ¿àÆk€s˜‚dž¬©Êjÿ!Œo$yÚhMC€ àV•)Ú;µNaÿÙ8CÞæVyq0O~Š4]ŽIèÜŸ_ËœÒõýÍ‚¿Ÿ§‹Ô r üùÍÊ…[7Kݙ?¿C9«œÝ±xetÍ*[ÕyÂ0ֆ†éN ç³WÆ}!@ž,P™¢œfÍhöÀדؙ–)r.L]#ðç5pôkÚàšéÒ ‰ýömZ€¢xw=f€» ^È6ÿñáÂzuüÒ¬z¬`¡»ÆéÍq L?(Ž®¡o£Æ7˜,ñæ|‘ @®šLÑÎÌ&öÒÌÑ¢0öé˜ëBÆL\àη”N¿b Æô6ýâ×kˆø«Þ²>d ß8òó–žSk¶VÕ©xÉË7^Øî{UQþ8ŒñkŒð{³¿JíŽ{D†( @ðtJí”üÀ›Z³>)ÿæéžÿòߕ˜çŸbœd‰©£†ÄmÞ×êŽÄszd„'悘!ò dì>zxņšþþRá'£²æ¶J»TŸ°Ž£èÞìùtoöÏiŒ$jR{ØQcc@€ PÙ¢œ^ãlⷓÄݵ€BpVÀ ”† Ö³NÕ"Xf×Q]HêQCLžX]Õ¬Ì § \:v&èÀÒµ5-y…~»6þsöµ›–Vg狝:)¿šÀó@…oŒJ-„ÚÇWë€ï!@€€œ•-ÚýâÂÙŽi·‹¹·^'áP@{՝ŽÜC³•6¿ìfÍ2Âoè[,4jcvÒTp±@ÖɌ€Ã?¬¯‘{ö\Hk›œ£›Œ~ˆiå‰`V¬º8Lw…€Ì”Â@ã<öç©ñ{³ï @p”@e‹vLjQ]Y§9äŽ ãT\ 'O‘&}ÊÚl<À«árh‡E5ztŸ ɒ^ñQÑš*~Îzúâ”ü"S­É'ÇõZ=Húéd P¬UUL˜÷toöótoöïè“ j¯P»>€ @À‘Ž(Úë¥Ä³‡WM÷T‘pˆŠ#×N%Çzï%ù›MŠV‡óÂê…Ö«›[­Mã‹qMëdWrXt‡œ,pñØÙÀ“k·&d8“›Ü:åÄ] 7 WžròÔŸœº®lôÄöP·ŸÔø9íï–s,@€þUÀE» Šì¥÷DZÂÛ»Ëéðv?ÃgՀi µVÛNù×Ï.–#B“bs"5(ˆéØ6GðÃÞ:÷[eˆÈÇtUeg~ß™¹ÿXdö©ŒPJ_©WóB³î÷‰<žo øóiYÔpތ»ý.M“-ê§tov …ÆïËþ5^Àã@€&àˆ¢ÓïšÖiý ù°Ã"Ã@Nøãˆ2ÿVû1–|ú‚X=4&4'ŽVBž_íÚj@£fZPTÿË'€@%d]±ú Š%@(²˜™UU˜IÔuAÔI(.TLÇχŠï?qáÈÙèÜs—B¢Â “«çÆ6MœZ':œ§iˁþâ곕 ݝ( ©ú ÿ!֕4EµIÔ&8q: @€€ 8ªh¯A÷l¿q:Koš,ã*òòcÒ4œµLMÝ|€Õ<™Éâ.ä Qš9@ ˆ+ HŒWüj§Zã‹Ã⣋$ì‘÷ÕŠ0, ÑnpÁbñŠVlñӋ•@Vd ¡b<@/RBÄKž–o ò”1סg+Ñ,ËÂ÷Œ+VU8‘®ùÿ°ƒ%ì>ÆâOžgÑçsXd~1 öcyÕ"Ùù¶uر{úˆcÂ$ÅÁ¡c8' hšò“ÿ`v”ŠAM¢6ßÉSbx@€|PÀQE;§{ä®îÌòΜ2Îk÷àÒº=JÄê=,ñϓ¬ZÚE•iñ‹Ì)6‡3?QÕM!!š9$Èâdñ )’d“nò—U*êU“ŸŸj€gz-˜MšP€Â$‰ñó'Á‘?µ*֙.0:«@Ðu±ä€eÚJûPéèeʒŸ£gúŽéôœñ%} kL¢Nô9-CßQw‘/cŒÁ—§/èCzm|F=è3þÿ%Ÿ ô!]ðŠF}uËèT2.}¯Q ô?>õ)ýŸtŽ’XøüŽÅ"ñDK?³Åb2ùŠåš§‰÷çËïy¿’ÃÁMFL¥cñ‰TÊÁDnšJßP캕–V©«fx‹4&7Óš`6^sÛx4?W™j|F±ê"ràϲI¥Ÿ S)ŠATu«UÎd1³•ºäç3Sn13å1S!í:/ gÅÊú³’‘ÍB/æ² ì”_Äi™@‹Âü8]h Ë¥;m\H®ÆÎ·Neg»5Ï%DI8ª¥Šÿ(Wjz]Sä]êOŠ,¶(&¥H5«Š&©Vjª*Q#Q %^ºXã çÉ&ÁZRòJÖ(ý˜I-ªŠI¢@ÅŒQòâŒÊ6ª8©xâÅ%íq4jS£æ¥_“ñQà50/éxcúžÞkưTñïø8"U†Tä ŒÚ-ùž^òbÐ(ˆi<^”òqx͋Aê@ŪÊ?ç÷΢÷Œ–+Y†s:Us<>QHó‚»äÙDqð:ž$7c\Þßvî±1ÿšì6 ³De§Ægùßx%:ïfDþ—…nýÍÏ €C™Å£ZTªsùƒf¶Ù06/îý¹%éåm 0Æ,íWº÷W£Z‘ö —¹4`IÑ­ñ:Ö(TGé\FïÿÎ%ߕl00æ*;aÉÆÆd*†ÉÕT²‘ÀØpa[öòÒYŒM&ŒŸ±Ÿ/Çs/Ý Á£§v9Òҍ |9㈂’µBɆc9cã ßÂÇäFŒ&ô\RóB]è5߳Ϗ!àïù^|ŸyƒIËÑÞï’ÏøXíº7™4êˏä`ŽWŒdãïÇ祱Œg‰67ðåicÑŸïÁŸL7SlƳLÏôß|9͏÷¡æO ‹žHí7jk@€œ!àÈ¢Ç7 :„¥žýTÎqF°€ PÕt`OŽiÊ¯Aíej÷TuL˜€ ïptÑKTþ8•íîÒTñ^6d@Ÿ+ üfÈvPþ£šñ ~é»È€ g 8ºhçñŽiXƒé;Þ€Mñ€ x‘]a1Ϭª_ÓœÙù%0fS{ˆZž¥ˆT @p3gíI”ãžc³ÙŽÄh9ÌÍòE8€  ÈLùQȎÓݩգöN…CG@€ `‡€3Šv>í„ö©,oí«ØÛnÇ:À"€ àtÛÅÓŠêòÒPߊ皥{@è€ pVÑ^“Lî=;—팓ƒ<Ø¡C€è® š&ª „‘Œ_hµ'µÔÞ  @p¶€³Šv÷C=š²ÜÿN¥»Aã@ðdí2V6—Šð&=O£v֓SBì€ x†€3‹vãÜöK_³ýAf™ßÃ@€€ h…ò9õ+a¬q¥x~.{#jØËîk!C€w.>·°tìáô,SûÔsaL@€ p5Wí<–nÔZ/b+&µg‚èêù¯æï!@ÀÇd?å;¡;O Õ©M€ö€“ }@€ªP *ŠæG(ßõúBvF€žTžÓ]áð€ Tœ€ ê‡äþÖÕ¥‘ŒHÏó©í¯úÈ @Ÿ*PE»?aÏ€6I_Àd‹IºAÄ _]È€ÜD@׬²LŸ»‰PD#K£úÌM¢C€ øš@U휺)µ¡ÔžÖ—±@‹Eê#ˆb€®€ @n  +Ê&¿al7…ÒŒÚ`jžZŒ¬„@ðuª*Ú¹ûåœújæoɒú L ÷õ‚ü!@Àõ¢š¥›ú«Kif3µ·©ñû²óÛœá@€ªT *‹vž8ߋñµÝFáž-õt1¬JE09 ø–€®)²UýFÆò(ñg©}Om›o! [@€ÜU ª‹v~~ïÛÇ©åÐ9î3íqGáÄ@Àëd]Y' bRb£šRûÆë’DB€ x¬@Uí.ŽÚÓÔîãoŒÂ]–СòüŸîx@€œ& êÚYÓ •ïYïM­.5Ÿ!@€ à6îPŽsŒkJÿÂôœQžʂ,!Æ9î(ÜÝæ§‚@ x›€f‘MêºZ| ev3µ§Œ-Cä@€€ç žKÑÎ%Pãç³Ï³îjšÔ_ÓÅ`ÏgF€ ànšª¬öÂ2)®ç©G{á5Ò ÐµIDAT@€ÜMÀŠvns5~µÞ¯ø›óKXH„.݄ÂÝÝ~6ˆ€€g L?.Ž®¥,Þ ö5~.;€ @ÀíÜ­hç@wS;Gm±­pÕèªòL t;=@ž' kÅ/œ©.œ²†Í à'RËõŒ$1 @Ÿ"àŽE;·Ÿ@퀭pח³PK±qŽ; w_ùe"O@NÈÏR~ŒžƒM¢áŸ vÉIÓ`X@€ àw-Úyrü÷PjŸò7ŒpWŠ¥þŒ‰Éƒ@€€Ï €e*ÇjÞeü÷…ïa/ð9$ @€€Ç žsÑÎ1淪AmQžÇÂ&݄ÂÝã~g€@• ì?£°æXkMcR09U€ @vž{ÑÎSžƒóã˅» õcºèoG~X€ ÀVïV"‡ŸÌæ²{ˆ{Øñ›€ @Àc<¡hç˜C©EQ{Ÿ¿É^À"ÌR_îó;C €ªLà“UJÒÌŬÎÁ³l8¡UY ˜€ T@ÀSŠvžZjÝš=CÍbîíqEsòF@ð‡ç(­÷Ÿda«Þd· ]™ÕRFŠ€ x™€'휟>µ©œLíDÎ,Úß_êÃ*ïe¿K€@ ÒCŠ)œ¢ƒYΛcÙÁÃXz¥Ä€ @  <­hçDAÔ^ öµ_õe,PU€š ÆUŠ„ 78|V ó&ë׿ûãá~òBó`e³›…ˆp @€€ÝžXŽÛ’ãW–©œ¡ëLP–Ê­˜ªµ œîžœ“Ý+ B€Àÿxá+¥áʬé+·±íHÇÍ;Õo…)8¿@€Î[÷ªÕ‹d @(#àmE»-µ!ô¢#µEú'ì÷âézQ«cÍC€€g ,Ü ÄÏüŽÕ?ŸÃöœ8Ï^¥l,ž¢‡ @ÿ.à­E;Ï:–ÚmÔ©}aYÄLL—Ú0:Ù? @ð,u{•Ð'æ±Ôœ'Y~~1›MÑó#ªð€ @^/àÍE»måñóÜGPËӓý÷ÝñRSAƒœ~Í"A@^ p䬢z¥ì8ÆB•}M)ýêi!@€ `·€/í6Œ.ô¢—ŸÈ2?|€e¿Vö³[ B€€K6íW¬÷ŸÇjì9É¢hâ©}ïÒ0 @p_*Ú9¹‰Zwj=$2ṑ,³;9ÓMÖ€ àÛºŠ/Ø Z&Ícɧ3Ûy®€¶Ô·Q= @Ÿ.àkE»m}KôâÚà6žC=ѧ ;5Ž£x*&L­‚|ýOò‡\/ k։Ÿšò'+YLŽ…ERË©ýäú@0# @p?_-Ú/¯ ÚõÞ19ÝÂâ[Õaç‡twh e¹ßªBD€ŒKàÈ)E7›E­ÛËj©;UZšoñ®,‘  @šœ€Ïíeøj'F³~aþ¬UýLïڄéÖLLOM +GŒÞ€ `P¬ªðò·ZôWkXàá ã.ëš­ vJ€ @ÿ_Eûÿ7‰ Z%D±~ ‘,Šn"S{·ti¬«)ãðyü)‚ Pw–*1‹g ۏ°ˆœB¶‹†ØPZ°W`4t @Ÿ#€¢ýß×urhkκ&F±ÐZ1¬žs#ñd«v±q-)Ïw~&È€ÀÕtŠè˖T!ûÈykÁ„X­m‡Yʅ\VƒzŸ§Æ}_C­èê£a @€ .€¢ÝŸß¿p]ähÖ98uˆ gTÌ+Íë°S­’Yf‹1±³KA^  kŠ(² M34Šdù™X6 fYBWOÙµŠÖ”ZMj©í€¶‘Z¶dŽ @€€ËPŽ—Ÿ\ õcÉ-ë²NV•]È•Ét!»œæÉ,­~ 1«Uª–†CéËO‹€€[ Z‘  éšjM7k, e™‚Àtе6µÆÔêQK)-̏Ðó¥MsË| @ð í•\Y]ê³ZÍRYÛ< k{æýVg¢(0-0€€Ä±‹õÄKµãYnƒ$–$Y+9ºCpº?Ì]dBš&Xӊ,,=l»H“ò‹ÆÕ)-Ôé9‰¿Pç!jRÛM/‡ @€€PŽ;3ï ·z?»&ý"k~$Å>ËbsŠY€HshbCY6Ÿ[;AÌJg5¢YAj<+”T†¡ ”K@×µ^€«VkúÄOXþ[?0~AÎêÔøáîÕJ tŸÑñ µÔøÞt^šç”k", @€ Pníå&³¯CþB/šLüu X¹ƒEKgQÇ3Xb^‹-(¢¿‹L§bžöÉ31ÀŸeù±œð@*ê#X]ô./1ŒŠTg…×€²‚˜ŸjÆ?*5™o ùöÆ¿cVjeŸèXÖËËÙúðïy_úÇJîQϬtd.Y {% }§òåhy‰Îæ4Ë6ï[:މ:ª ù2ü{Þ×øÇöL¯ùW*ŠÏøsÙïÛrÆVÒïtã: Ž\IXx@ŽH¿šÈ[1}ã~VŒùOŠï¡<·ˆÑ,ÑÔxÎü¢qéÔÒšñ"ý0µ,ÇF‚Ñ @€ì@Ñn’ã—áîa¥-œžãšEQ㇟FRã+?_”/g)}ŸOÏüŠõŒå–þº˜žùU˜ù³­ñ÷Œ?—ÔÖøX¶ÆKdŸgŸÍ_ۚí=.)ÃÿºÌÕÞóñyÜeÇ)Ùšð¿ñlïmcÙ~üó²ŸÙ>/;'ÇèO“H4™`’hƒ=S2¢Ù^Û ~ʕŸhc‚ÑŸ.˜e,dz֩H*ø†ŒŸ1â£Ex'úœ6Vè²±±÷tŸ1Æ5Ÿ+YЈ6 ˆF'úˆÇBÿÇ7Hètž¯± ƒK óóMü-_Ÿä㒇яÇ7ÈðÏù|%9\^)ÆÆ>2‡^Û¶dð~¶1x_zolŒ1ò ÷mâýl1”c‹jŽÛ”¶Ï”ÄU£—‰úÒ{ÑØHTm9úNSÉϖŸ±âJòã6Æo–çÀÇx_‰éŽi‰¿ù{þáêüµ‘8Óè##N/ïo¬ zÍ¿0Ƶ=øi'°Æ—/]o%NôYéÜ%‹–8ó1(’1©ßÿƶÍŗ£ÏKÒçhôšÞ“_þò¹Øüs¹Ž¿1&œ7iŽlipü=­tÿßù:¢‹1Ÿ,1Íøž–%cLŸ“môÒé7¬ÓJÕýh9ã³Ò1y>|ÎbÚGc0~¯Iº††hµ0ÁBÏ+ éuN“óò˜Ùx.fra13å3s=g糀ü"æO ͙yLÍÌfZN>Ë¿˜ÏDÚÀÆc¿TÚøëLjŒ@?I Œ+ó»ÃK@€ PÕ(Ú«z üýü~ô1ßóÅ[µ`j¡ÔBJ_ógþ_Ο×W4^Àóïm9Ÿ…¯kþY2µœÔÊòWŸ¶,|cŸþU–çýmøë²ËóCjKkÉËsòÄšmˌ[öµ-ޗ/W6Ÿ¿[Žo„°Õw¶ùyŸFáTŠ?϶AÄöù•϶±ls–ñÿƲo›£ì8üu٘lc\ù\¶oÙxmcñ1lNeÇ·ý¹µ­'ÛÆ+cœòó²óóŸeÇ.û«lœ\öß¶~<¶¿;¢ì>Š-¯ÏÅkZŸ!€o,1jvúé¢ÌD­dC„ÑJ¶³0…ªl?c™ÒM.¥¯yñm2¶ð /¥AJ7&”Öð¥9ñM %•ÌUºQ„ýBýx,t  £ƒCJ–16(#0“1.G£%Ç»” Åc¡|y>ßÈÁßÒ ‘šJS nô56aР*müàýùyhC iÛðŃ/æ²ä@vÆ_.Ùgl(à(&*æ‹øF"*ô­Ž@‘MÌj–šÉL¡VX¬°s™¹ìôŸãìD‘Õ(Òy1Î÷–ãv•ÿô'ŸC€ 7@Ñî†+Å!يµ+ O ! @€ @ÀU(Ú]%y @€ @å@Ñ^N0,@€ @p•ŠvWIc@€ @€@9PŽ— ‹C€ @€\%€¢ÝUҘ€ @€ PNíåÆ@€ W  hw•4æ @€ ”SE{9Á°8 @€ @ÀUÿ;ä ñÿ8l tEXtapplication/vnd.excalidraw+json{"version":"1","encoding":"bstring","compressed":true,"encoded":"xœÝšÙZâH\u0014€ï}\n>æ¶Mןx5žµ\"*݈­N÷ç\u0017B\u0001‘`\u00126ûë»yƒy€yÅy„©D$a•¶Aé®\u000b%uj9©:s\nŸme2ÙpÐVٝLVõ-Ó±«ŸÙËŸ‹ê»Ê\u000flÏÕ\"\u0014?\u0007^Ƿ▍0l\u0007;ïß'=\fËk=öRŽj)7\ft»¿ôs&ó-þ›šÇWVhºuGÅ\u001dbQ2\u0015—`²öÌsãi¹\u0010œ\u0001Â嚁\u001dìëéBUÕҚé\u0004*‘DUÙÜí…düa\u001bñbþãuŸ¿¿}\u0010”’Yk¶ã”\u0013k\u0015xúM\u0012Y\u0010ú^S}¶«aCKáDýŒ^Ÿ×©7\\\u0015\u0004c}Œ¶iÙá@בäå\u001eW`'“Ôô£NˆSƒ€\n\u001e‰£þT\u00188U\u0010›ÐkÏs,bœ6NÆh[\u000fnRLÓ6#~€PÈ7HãÎËN·ËÃÜM~»w•³ØuÏ­™«K‹$Gxõ,\u0017;\u0015Ƕ2'j#œeJ›…”.Œ‚ÁœÍCU»\u000bí\u0018¥d˳J휏Z\u0015Àz=\u0017ŽëœŒ_;À›}\u0005#\u0019\\à\u0018·\u0001\t\u0015OQ)A\u0002ðŸ¢\u0015!QQlÖ%\f˜Æ\u0015ŠLóé*T@&tÊ÷ÊžþJ·\u0018ˆÌ7iš÷Rè\u0000ƒ.mÒ¹ró~pÀ:y¿rt}\u0000nÕÙl÷ƒ\u0000\u0004\u0006ç`d¶ãÞ\u0007\u001a\fC9JÃR‰Ø*\r\u001a\u0019þg:ړ\\H(tnø[dY3S–/î®^75Šëóў¥_Cùkp\u001bÏèž\u0010¹G¶g1'æ·\u0006(FT€åœÈâÃf#‘ƒŒÃ1ä&nò\u0019Óñ \u0010L`ÞHN×ĜÐi\\ºÌp)\u0012\u001bBp‰°ˆ\u0001>\u001d\u0010\"LuîÅàk§_˜°ÅD\u0006¡é‡»¶[µÝº–%^êé‹áã%Ÿ\u0006Š\u0019¶:‘: \nÑ%Ó«Mõ‚\u0000ŒRmêf;^\u000b\u0003#†G—ÁCùèÂ?«y^¡ÅAјBTPB9ƒ”K¢ý\u0014›Òˆ\u001b0U€`S*9f\u0010îy­–\u001dêõ-z¶\u001bÎ\\Ç\\DrC™SDž~¥Žl\u0012ùv4âxž|Ê$TÄ\u000f£Ï_ßÍl=×^£²=eªÉp[éÿ?\u001c\u001f°¹w±‘;Ô! Y>„Ç…£â]c¿ØÅyz{tv_Óß\u0001Ì:«šÁ„\u0004Pm3\u00142 \u001dŸ]\\ŸN‚\u0013N%Az¥'B`-6t‚Hpt-ƒ\u0010Äë9» qZMç«\b\u0000\u001c£‘(ù+\u0007\f%íÌ3Vâ‘7!¯œÒ鑲­!ÆY³Ý.…Qýӑ§wÀ®\u000e_=\u00199ÛµUowÖoCâ\u0012\u001a“\u001b1¢¢õÿö}ëûÿkK\u0005["}PÚ€\IEND®B`‚fulcio-1.6.5/docs/img/verify-challenge.png000066400000000000000000002517501470150653400204610ustar00rootroot00000000000000‰PNG  IHDRyog4Û IDATx^ìt”E†ßôN/¡÷Þ« (R”" X@~¥‰JQ€H‘ŽR¥iŠ"H)Ò{ï ¡$€÷îl6$!MÉîæNN’Ýùfî}æ ç{÷ÎÜk£ØH€H€H€H€H€H€¬‚€ EžU¬#      M€"7      XŠ<+ZLºB$@$@$@$@$@yŒH€H€H€H€H€HÀŠPäYÑbÒ      Èã=@$@$@$@$@$@VD€"ϊ“®     EžµÞ~ˆ‰b"aãVÌZœ€_$@$@$@$@$@‰Pä™é-°°0„‡‡ëïÆŸ###ˆ° û öW_~ @DX Òs!ˆŽ R_áÐ5îíÝqè\ ªT©õOšú&ïÙªbÔ?ýšþ2ü.?^7\ago‡šš(¹(Ž”a ïò³¡©keÌèhšÁô·µ±EtLŽalu¡îï»ñú8[ÔûÑj5ŽŒg/6Èž±×ûì5XûfœQ†ñ ¿ÚÛÙ!"B‰]ƒ£jLƒŸ‰ÒÌÔb_|ì®®oç#Æ®F s}µU>D«qµ=Æbá×B¿nž –d,W1GXD ÓGïÇ7=Ÿñ8ØÛ#"JÙ‡æ8[â»· j*es”šÓx/}ÑãÇùf°B–ZüsPk©®‰QëllÆûL~7®·ØkŒÏôÖþDZ,Îú8œ¢È£• Т-Îvãƒû#gŸ>a†÷œœì&âÎ(!â NxˆµX¡b"ñߏUŸ ‰'@ÖOD‡Hï€ÖÇØ;1;[DEˆØ2øiðýÉ-þûZ@©{Èpí¬Kô²­º?„ŸA?Jx$þãnà ôHx+µ€ÅRŒ× }Ùkü0@^upP"2"JÝÛrÉœmü°Àà[Â5¶QÂÞ TcoÜž÷õ˜zcðU¹ íœiˆ†¿Ýâ I¹Vü• âJðàØ©šPŠ"Ô2"Håñ5R}XŠî§Ð0ù'BŸÔž®.Žúƒ Wgxž;ÁÃ# ²f͂lY³"GŽðô̋lÙsÂÝ#›6vΈ±uT n°qÊõÔ5æ›$@$@$@™EÞs\óÜœ{÷ïß×¢Îßß>>> ðWϗaJÀ„#<4Q‘¡ˆ ‚‡›reu@Þ\îJŒ9ÀÕÙQ?üɗ‹³ÜÔwGõ: €uq©"öð Å¿ ø= Q_Á𐯅Á÷žŠÖG¡³ú@'{VWä͝ùrgCṑ; äÈ[\ï *їW‰P;ëD/H€H€H€RE€"/UØ¿H¶Qz{{kQçëë«¿=Œ{›0%èBՖʇˆ €‹}$rçpFŽlnúËÝU}jïîŒ,êK¢l$@$‰ü=T¢ïž_ |”è»{77î<Àmµ9JGº³eqCÁ|ÙQ¬xI”,] y ”Köb*\©¶²‘   dy©\j£šóŸyÞ7.ÂïÞ-ž:ª-Yáú+\‰:wWGäÎé¡>mϊ¬Y\ô§ï®.|ØJ%r^F$ðA* 茛·ýୄ߅«>ð¹ûP÷΢þï)QŽJ•)’e«!Wr°qÈJ–$@$@$@VL€"ÏÔÅU Mîû\ŵËgqíêEøùÂNEélcÂõٟÀà0ä÷̆<9<ÔvË,È£Ÿd[  dHµœÓ÷~®ßŒ‹Jô]÷Ÿ»êwuž·Tñ(_±2J—«ª¶z–SPå\ßÓÏof„œ“H€H€H u(òžÄ-ðbBŒpóÆe\œzל|u2y@’ìŒáêJÎÉț ùÕWÏì©[^E$@éD @û»î}'Ï{ãüåÛ יQ+—/‚Úµj¢p‰Ê°uVgúä\Ÿ-?€J§eá4$@$@$æ(ò’@zïÊ¿8ì\RŸ~»«³r’aO’ø«„E æD‘9QŽ`•ÚŸ©ÎÓüŽä€$@éF 0ç¯ÜÁ¡“×pæÂ-Ì«¬2ƒÖªRk6‚m¶j*ƒ§kºÙÉH€H€H€҆E^,GI‹~úôiœÞÿ;ê­£taŒÒÅò¢Pþœ:¡  X#Éôyíæ=|ˆŠåK¡\ŸP%îΚ²Ñiƒ  ÷b広8y%ï¶ï‚UFN6    !`•"ïèÑ£8~ü8òäÉ///Ô¬^UŠÛ"Æÿ˜wQš“’ @f pç®?¯ÞƒûÁNhß©ªV¯“ÜŠ$@$@$`V¬JäI9„-[¶ÀÃÃÁÁÁȓ;êVÌ ›€ã@t˜Y§1$@$`ÍN_ðƊu‡-oy|Öw8­Ù]úF$@$@fEÀjDÞþýû!e\]]úµ Â#Z¹‹ 4+à4†H€2íûÎaÑïGñöû=вÕ[™ÉuúJ$@$@FÀâE^`` 6mÚ€«Ü¹suªA9O?Ą?È0šœ˜H€H !?ÿ‡ÛYðiïÈŸ??ñ   (V¶®õ8FOH€H€Hà9Èp‘‰©S§¢T±üx£Fž à©/6  HD`ÿÑ+ØŸïº}9Ùr!   'Èp‘·dÉ>@—¹€š`.   <‘ÀƧpäÔ-|3z`çDR$@$@$@IÈP‘·mÛ6Ø·Ÿ·-  <Þ¡$@$@ÉXºf/¢l=Щ×÷*áŠmò°   d2&òΞ=‹5kÖàÍ Â3kh&ÃNwI€H€RK@jè-XñªÕš‹­¿Hí0ŒŽH€H€¬–@†ˆŒÀÀ@L™2M_)‹j…X-\:F$@$ð|œ¹x ›ÿ;…æ­Ú£t7ŸÏ$•H€H€,”@†ˆŒÙ³g#«‡3ÚÖS…m™hÅBošM$@K`ó§qêüMtë=n¹Êf¬1œH€H€̈@º‹Œýû÷cýúõÚC¥À¹aF(h  €¥Xš¶mººº¢}×Q€cK3Ÿö’  Às!®"Ï××Ó§OÇGï5Da— ÏÅ!J$@$y\óº‡õ[£FÕ²x¡Y_ØØ»fçé)   <@ºŠ<©‡WŽpŽš®2iF‡qQH€H€Hà™ lÙurFïý·_GÎòTÂMûg“  €%H7‘wøða¬^œ#{7‚¯X23ÚN$@$`Fbbb0uáð̎wÛ¶ƒM®WÍÈ:šB$@$@éO ]DždÓ?~<þ×ö5w?—þ^rF  «&pñª¶î9ƒZUŠ¡Úë_sÛŠU¯6# HŽ@ºˆŒÅ‹Ã¡xïUgfÓLnEø>  @ªü¶á0nùø¡K×^pöTÉœØH€H€H “xî"ÏËË S§|A+ÀÃ%“RŠÛ$@$@ϝÀm_ü±éJ—,ŠFmG6ªL   dBÏ]äM?U ¢ñ‹Å2!^ºL$@$ž€vÞÅk>h÷¿ŸÈUžZzN͹H€H€HÀl~ýyÚ˱I€H€H EücåºÈW¶Zµi—¢kٙH€H€,‘@šˆŒ˜šP ëÛo4š„šUŠY"ÚL$@$`Å~ßxX%`ɂN݇ÀÍÍ͊=¥k$@$@$€‰È»{m/óf0á ï)  3$pòÜMì=vµ_뉪ժ™¡…4‰H€H€Ҏ@šˆŒe³¿AðCo|ônœŽ³ÌÌFЉ±EpŒ;¢àðDËNßqAñŒŽÈc{Eõ‰13šsþòmüžx+Æ|N*Y  X3°°ÌW Xò{ ïvøÔš]¥o$@$@$ð쑌˜èH|Ù¥9z}ØE å²J€Ñ1v8^!ÑîOõïè™ šY¡,ò{ gø>³z¿þ¹ôž‹œkŸA-n±µÊû–N‘ $$°eç\ŒŽvGŽ9ˆ‡H€H€¬–À3GòÎ݌…s'aTÿ·¬ÒœÈ|žQ.YÿŒ"/{6žDy›µÐ[ºf/:~1›鋆/²p}²‹›ÊœŸ]Š5 R™óõÛšR®P*Gâe$@ÏJàÌÅ[Øu@}ך+ª×¶Þ'Ïʉד  X>gy‹›p_|ЊŽåÓx‚w"‹À;¢D²þÅyÒùy œ+7îâÄ9/ÜŒõ÷ý‚P€@NŽmQ ŽŽöÉÚhìðóo{Щï¬û©7šÖ¯hòuìh:5›Žàín3â.õ™?®Þomœ+ŠÓaOH!¡ášyŠ×@›}ÓßÎH$@$@éDàÙD^L4úvkŽîᅡEó€“Éé?QäÅDÇàÜÕ눎ŽŽ3Â6(à™YÜ]‘X䥕ÐQ·S}ú,_ÛöžÃÅ«>Aøäœ—1{ÌÿL†³hÕ.tîÿ¶þÚ¯ŒPÚäë2cÇÕBÁ|ÙñBÕâ)r¿ë׋1ùøæ³7Pœba|=v5.]óÅÌQÐ¥ý+)+­;<~—¯ûêÌ©EEEãýÏç@RÞ¯ÿ©ììlSm^j×-ÕŠÁ…æº.iàšÙ !ŸÜô A—~3àì̚®f³04„H€H M <“È»qaƏúS†µOS£Ìm°ø‘ŒÀ DEGÅy€«« ìíìpììT¯P9²fMàBj"zŸ÷0ô‡5ØŽã®z݋/gvw4®W•ËDáü9`kk‹óWî g67ôìÔÐdtóý].Ɓµƒ•)bòuÑ1&&k·ÃÑS7àìd¯ÄîEŒð*ª-éÑÊ6 •œæÈßߊhºFí'ââ5\Ù9V¯Óÿ ÙÛ±ÿf|÷ºŸ_?Eã¥eçnjí«h®Øæ™;áýš–ó€t,)Z]«åwú2¿Óàážú‡ðÔ®[JmNËþæº.iécFuäÔuì;z[÷Fé æõ!GF³áü$@$@ÖCà™DÞÊ#ñÀç"$ŠdÍ-ŸÈ W"ïQ$Oüvqr‚­ .\󂓃=Š,›„D ÛGV»;&cúö‡?ðÝŽ¿tÿÂràÃw^BsU‡°F¥"Z0º§·ŒD™âž&÷ÏÎÓøüÛeøúÓføßÛ/š|]j;ÞöõGç~ ±Q‰Ýø­wçÆøaHú5.ùÊ@ÜòñGÐÙG[/ãÛò$&å A%Ÿw®þ:®»døkþálßw &|ˆ) þAœZ¥Òýƒ’ü„ŸVîÂîߊ8B™Úµ4åº/FüŠ© ·ÀÁÁ¡çg™rÉû$·nÇÏx¡Ïðeú\ê³D Sj€ý‡!X5³²fqMp¹¹®KJ}4çþ%^ºfJWz ¯·a–Ms^+ÚF$@$zÏ$òFö-V@e+O&»æÉ —Dò}Ñù‘-‹;ÂÂ#pÍû6BBBU…„%^*„Ò9˜ŒR×Tô®tƒA(è™ §ÿ™æeŠ.ü_ŒXŽk»Çë­ˆŠ¶Ù¿lǧƒÖá/êƒuŸ_Җ{Qïí±:RÙ²Qu–íѓ4WG\Ø>:]¢PE_ú 7ŒïcÖèŽz¡Š²FFFiqܜëx“|µŸT‘Ý"úÜcüö0 åQ¶gÁñ³7![Göm­·uŠWëôå|üüû^ôùø5WYq¯+ÿÂÂ#µ(ýBœö,ŽÔú ž`þúœiž\žuà‡Ô¥¯KnÝöœ‚ºmFãÈúoÕÿaŸi.S/–µ»Œïø¡É+°vÁç Š9®‹©ŸYR¿%¿íFD”>é?Ó’ÌŠ­$@$@$`2T‹Œð‡×еs{,˜ØÙäÉ,µcr‘Œ'ù%7g'GývY§}p± J‚¬?C‰ÂypxýÐ]gJç ³7è3bwNFö¬nŠ\×gí?ǰbÝ”*šC{·Lѵ)éüæ'ÓðזãZHý8òƒžK붍ýÇ®è}»6Iɐ&õ=}ÁRbâêÍ{žªÎCî>t ²e4~³U‘Û:Պã¿U†(]RL ŸÐOgÕü{ñÍûÙÐ_…ÏÔÛ9˶ÃçîC¬˜ÑÃ$ûRÓÉ_‰ÓK¶AÎw^»yWmW»‚€ÀÐdž*Z0'6ýü%JIÿ3¶Æè²%Z¢Ì)i)]·gœPµÙpüô}gt|«nJŠzŠŸw|ªµØŠ}G.ãû!mñçæcfœ.Ï䬙^ŒuÏYÈýò^—ï;_ÊÎښ©K4‹H€H€HµÈÛ³q.6oZ‡ÁœZX=Òø‘Œç/=¶]óIì”È«XŠ8lmlS-ò ä͞â‡]Sdè÷k0jú:µ%nЊÊ%ÌÊ)ѪÍÿFDD$œTyUÄ)œ›1ÊòúËåu$,þÕ±3ÖcЄßñq»—1g¬éÉfû ÑÒÞÖá€JB"‘ÉZ•‹âíf5ðý܍8|òúc.¿ÓŒ^­SÕՖYo®.NIb¹yûÎ]Ÿƒª¡d>Ý£jŠŠ]õR wÔù=ŒŠÎa>i>SÆî7j&ÍÛüXWª­^«ŠšÊ÷**š•+‡‡)Ã¥y‰lUxmš>ûxOEòª–/„} JÑ<µZŽLѺI£2*Z>âË71(ÿÛôß)Œýq=ŽžŸ¡3eWµ(‹¢û¯¢vÕb |JͺH40 (TíHžÕ3E°2yçs—oc‹Úz^¿qTzñÝLNƒî“  X#T‹Œ9ã>Aö,ú¡ØÚ[üH^ŽDtužìŸ:—g{8/µ‘<ٖxcÏØÛÛé-ƒ"H$ßÉs7qGEJϋÅ?|ŒPµÕM¶ßIŠLSÎØÉÙ§9Kw¹÷ßêú#þØ|TùØòsµ …ãÎ2JÚ{Sîíþ£WbŠüÖ©^Ü€uaYHmíõa#LþöœäLĖ]g0^Ýã{UN-•Q{òÿŸDšÝ\ ~aÛP%Ý»ã79÷÷­Š|˶\›ØÿR³.rIæPÁñ“&‡©óž“Õ–âlYÚ7Ã{² Í C É T)…reË Iûáf`M   Ž%:‘~}{¶×7öóI= IDAT±­+m$?šQäE«’ÇÎ\LPBáiWËC]•2¥tR–ÔŠŒÀ 0ý@(â$þC£|Š/‘—ÆõÊë‡Fc¶LIÎ"ç|·wºÏÀ *jÓ¿[Sý–$xøKo»shR\WÙ¢Øñ‹yÊ¿œQ搈„“£Œ÷OD%X€:SŸK3žÇ[Ÿv¿+℡ˆ™ufÍ( DèMñÉÉ-$R‘­R/uoåÆÑ¿‡%¿@‰zü0wŒY¥·XÊyCÃQèÜ®æŽí€{?g£î#¥ –Më†b±çÒ€äÁäùÿ MÓjX2éÝ·]ÏÙXµþ :#öœ:+–tT3>“Uë©ä4KõŒ‰›ˆæRªÜH›ŠÕ1@­EdTþÞz"A팞C~Á¬Ÿ·©è¥ šœZI±~ˆÇ®â%%:w¬ü*nHáÔí›Åªî×.ýš|y²j¿WÏú•TÖ'5ãÖÈ_§wÅ»o<=à)àGõiVÆD°Ÿåï†×’  ÀÓ€JäùyÀŸœ0+uÙ,y22’'"Ošl'á%¢N6Èö:c4@ÞQñãâ­:ëåšþo%À}ËÇ…ëP‘µÒøgi?ý^û^s”pž‚‹;ÆèßÏ\Œ…j͇ë$ óÇ—9³Ç %:âwößïPªX^ÝWæZúÇ>ٚ¢·tº–ýT Cyžœ£î cÔO¢_ƒÕ¶J‰VôèøªzŠ49+&"Oü”ÈNJڂå;ÑåëEúÁ{‘ŠpÊöJ9UºÁ7†2ǧêáꎥ"¢×°Wm¥–ñ›$U‘ípƳŠÆŒ‡'7ÐÑž€Z|&òŸŒÑàœ ú<ŸD¥Ä…œ‡;¯¶qžU\$’ ‚SCÛOgés—UT#£ ‘Ä#-è­³©ÊšÈÙ1%7öNÐÓK­F¹î÷Gô¶ÕAJèQçé$=|Í#u⒠ÛFÃÝ-éKTù‰ØÊYGù°æIÍTž)Y£ø}%•ý«í& \‰|:Ó§|˜‘¥Âgzëì–e†{5¥÷¶qüäÖMî]çÒ=ðA›::.«JF$k'M¶¢KôמµY^“¿¡å?v×S¹^"Œ_©³­áêçC Ñ×ì•?×ßÏlùî±6mœ÷ H'_™4Ž>ÿšqtÉ­‹$§qW"ø5õÿ@â¿ cҖÏ?j€ÆN>2™Ú5³–ëvºˆc§¯£}ÇÈQÔº3D[˚Ñ  Ó €Jämßð ölý z43}& î?’wâÜe“#y"**=㙌ššHŽEÞÓÎKIZvù$ÿÏùœðFÃÊ hK))É B`„Êâ(­õ'ÓUŽ{qµßŸÿÆÍü;îÁÖ8€lÃx훠"lÙÌ"BB¢zo;MÅÒ©]ЮemŒôÖœPÒúÇg.…ËEð³@ÎP‚Ÿ—ÛFb\¢E_©¥Ža_ŽÂÏ“NŒ³hÕ.tîÿŠ ÿ‰[^SÂ39†Iœ/ëTýZŒøs°þAî^Õ*ÂÖ_ûëHUJïmã\Ь›}ñ®êž­Š·KŽNlè¡Dï`µÕWĵÜã’ÍU"rÿìX1à±L·"T_l3FoûüT}˜QN•ÎxRD]l“(œ{¹žz+óÌQ†¢±%·.²e[¢dš5FšåZ9*uÕùÚóÛFAêi²=€|°µYmOoÚøe”­ÇR Œ_H€H€¬‹@ªDނßÁ-Ú ï¶ši]4žàMüH^šª“'QSZZdה­’>‡m©|ÒŒízÎÒ[ÁVÏþ­_¯×팊Uc€~°”­p²%NZӎ“pãÖ}œR倷¶­™ûZ6®òT÷&Íۄ~jK›$DiZ¿"òÖøBŸ 97#É~ßŸˆ­{Îéíe…TwSšl”3V-UÆ/Sº<1",£Ðj¥ìQ)[éŒM"[ëöŽ;ÃäX²›:We‹àsɧP—ÕóTñxˆÆšßQss¹±–˜‰ÌÛý›%˜»lÇSSô‹èÞcŸzž5¿„¯Ú +GãöØ€x ÓcªÎ›lË3nù¡]¹É0œœPšD /ª2I}8 âSDhü ¥]ì>ègˆ€xáÜ:ûªˆySxš²ŠñûÈߐlkü{ÛI±•µ—*{ÕJÉü)M¢z‡Ö ÑP€äÞ6Γܺ‰ˆ“(ޜ›Á/É^þQgÙ$‚ÛõëŐ­»²õY2¬Š ~’hÞ¡jJÔö£¶/éz–õێO6 -‘êò**Œû÷„Iy’[‰–KT^JЬ™÷YRãßïóÊ8›Òõµ„þwïèH¬lcéÍo»€£Þ–à m$  ÄR%ò÷WŸ~7ðL2 „5"Ž/òƒB«“÷$Ÿílí”81œcK홌Ð«"Ü"$žÖ&Ï߬#/š€²ÍMüåáóÝOgâîý@}©$ÿ!“ܪ ·D dË¥4cŽOÎID®ŒJò€f|5ng“íÇÎÜÀµƒÜ’4d€Š"ŽVY<%âŽH¥ª¿Åôiþˆ(•W9ÛT¡t~õ€ý&Zš¥£zȕ&[:íímœI’L‰Rdú柉:š'ÉO®ÝŒ¯¶Xz*áZUŸ’&Q4§RÝõÏ~'Š%[nĔµ>ùÏ8Q«Y*ÖÂÜxN/1éc~IEWŸ“Œ\»¶-€×>ø’HE„ÕBÅëI©Äñ;õÏ-˜K¯e—¯ésbß©s`R[P¢Õ]þc·ÇÎ~mßw ߛ£ž{þüç(ÚtùQEŽ»©sz5uæISx>õÆ|›”€ÿ^ ùøMîBù³ãºZ39xxÝP}®0¥÷¶qÌäÖM¶@çªjØ,Bï Ún)âVšÜw"B¿R»$‘‹py»YuœU3þ=,"œCïyðV[¢ÿUwrß5Q È™Âk‡<DÝdûnÀ©éq÷ŽtNn]Ć"/~…»JÐOÒNŸÙ1u­.l/Išnü!A˜Ô¬MfºFÎæJô¶uG•ÉÕ9é­Ø™‰}% °©yÚ·Äœo$›%ÐZ0Å/¡pîêõEòÊ-œêÄ+’B¶²Ý?6%Ù-‹"Šä¡]êÇp\ºæ«£!ŸyGŸ5’­‹^êL—Fã'ÿ綎BI•DN%3Ÿ$øøjÒ*ÑG)•a²jW)–@$#ÆÈÆÒ5{U–ùJÐ:©mj•õy8yP—Lb¿IL‘žTCr÷‡DZD\MQ…Ûe«b®ñ‘š•9KÕþÍôPj÷Ó¢D||ÚOÉDêŠ"8ÒâŸ5|’=?«ókÔù5IZ3öë·±ëàEœUÃä3‰ÿÀ>æ«·”˜Jzk³1šôr­’úŒ€ˆ†æJ€K4OÎ}ɖÍz±ëP©LÁžä5’˜EŽHdG"v"ä…Çdu«§ªœ'BV2J€LÖoѝU&VÏ8ÛþêÉŒjkš÷ý€ˆD‰žÊÜŠòLn¿oÜ,(HdT²ÁJ&Ó‹h_^TÊ%šgŒfŠôÞ6ΗܺI†Ú*M‡éîËT’I„blryq€лˆJ¯«3¬JÖÏk”PôÄè,·ò%6¯RŒH4r£ÊrÚŒÓdäϛ-îüdR|$»C•ǐ&ñ˃˜².ƵO<®sèlŠX­*ÝTYV{÷ ›,åM¿=I€H€HÀÌ €Xä?s§ÀžŸ¯š¹kig^üH^jGMM$Oˆ<ˆ”z€4%&I$cäOꌕˆ»7_«ŠÎ 5ÔÑÙ6(Ñ:9û$ç⌠5Æ©‚âýb ŠKRˆá“תâÜ; gñŒMD¡dò‘#’¡«÷ÎXŒð–~°•& Cªh‚ˆ”0õŸl|µNY=jJ(Äç,‚NŠGï:pg.ÝRB.Tou“sOœ;7ŽÛÊù¿/çãµýê“÷^Æìd’‰@’4ô²ñIÉIŒ6\ºæ£Ï;Iry —(¢D7ª"çR²BZRLDÀ5ýß$|к>|÷¥'Þ:ŸþY'êø¶O+ÝG"<UùIX#c›ˆ÷ÚªÞڔaíUvÇ|H•l# Õi°:ÿŸ€Ô—¬ª›TÍC)ö-E¿ã·âõŸÖç2EœüȚJôJZJxšúw!¥;d›«ˆ»õj»oRgǪ6†goꈎ$Α–’{ÛÔu“(ª$ŽiôR9-ò·©êéÇ(ç6eMFªˆ™dßôºõ@'Bª ¢Ý²¶«,šÆä>ÒùófÅ_j{ð“šDY%[gR‰…’[ãßÛwÓÿ‚¿Ú&®2NJ6%Sª©ë”YúÉ6²Ežk·nÈZ$aœÌ€~’  X'‹Œµk×âæùíèúö£D։æ‘W>‘…p3¢Ô3¹YÞiœl §g, .–3Q«ÿ>¬³7·š‡•³YR_Nê}T‘œ‹JäH9€)ª–Øûê¡6¹&ÂDÊG€w“‡o‰ÌHôPÀ U5É$ЈNIa/‰iÖ«mx”­‘üƒã¶p&g«$3‘€&rí;Íkª¬ˆLªG˜ÜžO{_²¢JvNYÏ"4¢Ôº­ÿùcuðž6ŽdMª œð,«R˱٫u–M£h—ñRÂÓXîàivHr9O&39Ë(‚9©&[‰7l?—ŒæY&·nr¯žªÈµqpü¹D°­øëÀc5"%9Œ|ŏÀÅ¿N—ŒŸÚâõÉ­KbõێÓ÷·lNíœÏÂØ’¯•š›Tò£V-š X­,ÙÚN$@$@ €XäMŸ>E²à— gW2C ŽöÀ¹0I2£ª›§¢9ڄ ‚ó^u¥©UÔS1 /Ñ$cžlS4Öè“-Œ36‰J~­"U’?¥M5ȹŸ'=ܧt€~™dc\§ŠŒßVÑ0 %‹æUÅÛËš:ge’MŽ’>VZÎ,äiŸk5ï×è6pI‚­­æk­ùY&R$òŠNŠR¥J¡I…{@tšùxAKH€H ˆ9«öFébyq|ãðLäyÚ»*õ¥nèï4B‰{¥ý‘H€H€2€@ŠDÞСCѺukTÍyLUˆÊs9%  €è7jªW(lRíJ{2‡!˜Œà][³òëCT¥œô¯ñÉõ!  Ž&"‘׫W/ 8žáëÓÚŽG$@$@B`èkðFÃÊšÛŒ/à˜3Clà€$@$@$–LyÑÑÑøðñø§ùˆŸŸ(-màX$@$@$a&ÍیÒÅó¢e»Þ€[‰ ³ƒ“  @Z0Yäyyyaüøñ˜:i¢oü’Vós  ÈP‹VíVÉk€N÷„M¶j ''  Ž `²È;xð Ö¯_¡ßôAŽ×ŠŽ˜›c  @†Øžý.]»‹ž=:Ã&w£ ·‡  À³0YämذçΝCïíýû³ÎËëI€H€HÀ,ì:p[÷œÅàŸa[à³°‰F  À³0Yä-[¶ áááèô^SDßZû,sòZ  0'Îzaéû0æ«w`[޳²KíÝd#   &`²È›5k<==ѺIMDßÙ`Á.Ót  xDàâUÌûuF|ÙÎÅÞ²   X4“EÞžqãP§NŒR³0b|·XŽÓ4žH€H€ŒnÞ~€© ·`p¯ÈZŒàZ”pH€H€HÀ¢ ˜,òŒ¶mÛ¢rqDßÝnÑNÓx  0žï„13Öã«îM‘»ø«*Ãf5Â!  ‹&`²ÈëÝ»7úõ뇂Ùso·E;MãI€H€HÀH $4C&®ÁŸŒ†‚e^Mö‡H€H€,š€É"¯W¯^˜0aœÂÎ!æÁ‹v𯓠 €‘@LL Ÿ»=:ÔG± a“ƒ"w  €e0IäEGGãÃ?ÄâŋãwX±‘  €µ0z%:·«‡r՛šH^mkq‹~  dR&‰Œ‡¢oߟ˜;w.bîïCÌÙÝ& °Fƒ'þŽwš×@µº-•È«e.Ò'  LDÀ$‘çíí1cÆ`ÚŽiê<ÞNÄœÍDˆè*  €µ1åO4©_uê¿¥D^Mkw—þ‘  X9“Dޅ 0gÎ}&/Úw+tÉʱÐ=  ÌD`¬Ê®ùb’šß€Ê®Y#3¹N_I€H€¬€I"ïèÑ£Xœz5FމŸÍˆ Ÿf…(è  @f%ðÃŒMšTŠ^oÙQ‰Œê™ý& °&‰Œ]»vaÛ¶m4h¢o¯Bœ­Ä}ºA$@$@ÀŒÅ[Qš`Žzë#Š<Þ$@$@OÀ$‘÷ï¿ÿâȑ#:ùJŽ÷@ž¯Å;NH€H€HÀH`Ö/Ûà™++ÚŒ÷ l²²:ï   Ë&`’ÈÛ°aΞ=‹>}ú úæj âe{MëI€H€H ¹Ëv g67ŒÝŸ«ŠäQäñæ  °l&‰ŒuëÖáʕ+øì³Ïíõ+hÙ^Óz  ˆG`Þ¯;-‹+Þý »ŠäU%  °h&‰Œ5kÖàöíÛèÞœ;¢¯/¢Ã,ÚiO$@$@ñ Ì_þ²ž» m‡JäU!  °h&‰ŒU«VÁÏÏŸ|ò ¢¯-b¢,ÚiO$@$@ñ ,\±n®Nh×±§y• ‡H€H€,š€I"oÙ²eG§ÿýO‰Œùí0'  Ä­Ú GG;Œÿáç°ÉR‰€H€H€HÀ¢ ˜$ò$«Š &N£DÞ"‹v˜Æ“  @b_Ž\G;Œ?Q‰ŒŠD$@$@MÀ$‘·dÉØÚÚâƒ÷Ú úÆR‹v˜Æ“  @b?ÿŸG¿Ôñã/•È«@@$@$@$`ÑLy‹/†>h÷Š!»&   XeìCDd:uíòVä]! ȌLy‹-‚ƒƒÞoÛR‰Œå™‘}& °bË×îGHh:wx”³bOé  @f `²ÈsttDûwÞPÅÐWd.ô‘H€H X¹îÃðñ§_«H^ÙLä9]% °F&‰Œ… ÂÕÕíÞjªDÞJkä@ŸH€H€21UëÁïaº~6p/“‰IÐu  k B‘×D‰ŒUÖà7}   8¿o<„{‚Ñ¥ç7*’G‘Ç[ƒH€HÀ² ˜$ò,X777É{]‰ŒÕ–í1­'  DÖl:Œ;>ѣϷ*’WŠ|H€H€HÀ¢ ˜,òÜÝÝñnëÆˆñþÍ¢Šñ$@$@$˜ÀÚŽâÆ­èùÅ0ØPäñ! °p&‰Œùóç#K–,x÷͆ˆöþÝÂ]Šù$@$@$Àºãʍ»èÕw„y%‰‡H€H€,š€I"oÞŒyȖ-Þnù*bn­±h‡i<   $&°þßžtÝŸ÷ÿ6n%ˆH€H€,š@ŠDÞ;-ë#úÖí0'  Ä6n?‰³—n£ÏW£•È+N@$@$@$`ÑLysçÎEŽ9ðV‹—U$ïO‹v˜Æ“  @b›ÿ;ÓœÑgÀ%òŠ   X4“Džl×Ô"T$o­E;LãI€H€H 1wÁáS×1`ðÀµ(‘  €E0Iä͙3¹råB›æ/"æö_í0'  Ä¶î9‹ƒÇ¯bÀïaãZ„€H€H€HÀ¢ ˜$òfϞòšô“ïò%ÂLÿ¬Þ—Ÿ#c_—×í¡^7Œçæêÿ€X1;;„©ùD …U6W< ‰X†ÕprtPvDÆ-­#Ÿx“±Ô45G;5Ç£ke.7g=‡4ƒ 4FÕWøhÁi|ÍÞV±Šz$úb¡ô Bê}Û8±èìd¯ìÖ×ØÆ FyßÕÅQÙ¡^S}õ5±‚Rýâ¢Þ“¹õ5úuÛžŸ{±ÁV1S¯Çi{;;í‡ø/ïÇOƱWý•„5\Ïã8Æ×íäZõŸüžðgÞòz|ÞÖþwBÿҗÀŸ£—!µòŸ=6.yéKŸ³‘  €5“E^Á‚ѲqUÄølJk8žž÷ P‹¢à0Üó œû†ßCB#TÌÉ L®ßŒ§ÄFrç̪–ˆ„ª÷‰7%Èbš³£=•XpPÂÅÞÞN‰-ìÕïvJ,ž(1!Á1òš£êcû€/"ÂAõÑüöJ šïÒOüµ0kސ0ˆ»XÁ ÂAZœÀˆ)qÂ(V$ÅÒ7±ˆ‹€K™‹]?}MâpßSÖÖ8‡IË2ŒŠR‚V«BÍI~WRSñU¢0 z~yÝ‘„A«ïúýØ/š4ü.×G"”"N%‚¥ÆÒ×Èx±B3VžŠh|4N¬žÖשybEvŒØ'ãŊom‹"r óËub§t±Q m[;„†‡Äz¬—ï1Ò_œïèàˆààe“L&OYsúëuP?;š>‘J„Ûª±” PwŽªJ?¹埭œOúè×bß×}Ô×ý{>êC,X ysÚ£ThT(fƒBžY5‹«IËÄN–Kààñ+økË 7 6Îù-×ZN$@$@ò€£²’},>}:Š+†æ **‘·™à¬€<|_õº‡k^wqÛ÷!Î_¹ƒ·îë‡j‰š…†EhA–5‹ ²guƒ“Š"†9!0Ô ^·ýQ(g0JɩėƒŽèØ©jƒðRßu„&6$á±[!µ Ñ+%XômhV1êá[?ÏÇ ý³zMޓqDlHӗè>±âJý¬#iê!ß8vŒ[Ä£ˆ£‹ÛŠiC] ‡2h=žœ²["wFDÉÐú%FEñ Fú픉u‡x¯‹â0áŸçø IDATÎ#ok_ }ì•0 WâæÑ ø{mì=Š}S¯I³··×BÆÔæ Ö"""ÜÐ=©m€ÚŠGÛK¥‹ñƒ$#fñv¢JŽ.þÿ úÇÎ%Ýå~ˆŠŒx‹¿m5vnƒH—š€ÈCÃú%nñí4°7Dã_†× ׊À4|ažÑŒý⮩º>ú]îÁhÜ»wGórvvEXXˆú B ËÈ0D…?€›s$ ävBá‚9Q$NT(]…ògGŸ<ÙL]ö3s‡Tù„?·Èqs”ÈËgæÖÒ<  x:“DÞŽiÓPŒxq%ò*(‘÷™Z €ÀP;s” »Š¢qŽözûß=ÿ ”)š%ŠåE~õ[À3›v÷]àãï†;îžóÐ]õMâiÜJØÐ 0C` ?ú݄]Ä5Ü÷9 ï[·µ(õpwF‰ÂyðR­’ú{ÞÜYÎB 9y ¿o<‚‘æ)‘çi¡^Ðl  0H™È{µܝÃPÆóŠåy€+׌qìô lØqJEÅí”Ð+„ÆJð•TQq6ó' "ï÷ G0bü<%òžfæ¿bސH€HàiR(òÊ(‘·•D-Œ€lÇÜžã$Šȅš•‹`×ÁKxš’§4|©,òæñ„·ŠÔy?ðÐâ.2JU°‘ €„€ƒ]J(¡WÊó.\ÂpðÄUü·ï‚Ú}Å çF‹FUPZmf3_'Ïyaéû1vÒ"%òr›¯¡ŽŒH€H€L `²È+UªšŸ\ 1w·™0,»˜I8ñÇæ£*3aZœV'Ï{ã¿ýP³æ Ȗ³Œý=ð0ØÉL¥ $`$¯LÁQ&ß]äöÂÙK·Ttè0|ïèÈ^ÛµàâìhŸZ›g.xcÑêÝ?õgÀ1—µ¹GH€H€2“DÞäɓQ¶lY4©WB‰Œí™ ‘eº+¥ÿ¶ ê–Õ—3=ŠÀȂ(RºA\¶FËôŒV“€eÈæ‚²ùÕVÎÜ Q¢E«vëڐŽ®£¶H· '2‘•"È,߉‰Ó—*‘—3yNWI€H€¬‘@ E^q%òvX#«òéÒ5üœí$ºPA*Š7yÑ>d+Üyò¶*?é XÇÔ)áÏlXûÏ1ì>xÕ+Å»oÔŽó3R6fîÒøþÇeJäåÈ4~ÓQ  ë$`’È›4iʗ/×_,Š˜{ÿY' +ñÊ÷^6n?‰oՅ÷?üŽú(JTï¡ê€Ù[‰‡tƒ,€lã¬ZèÊž‹+×}1yÁ?(”/úukbyÎX©ÅòáØŒ%[1iæ À!»•zI·H€H€2 “E^… ðZÝÂJäíÌ,l,ÎÏÓêLÉöœçÑ£ã«:±ÊO¿Aò]Té&S±žÅ€ÁVI H.ŒPâ†*z‰ñ³6š_b0žW «ôÕҜº¢² ÏúyÆOû6Žy–¶~Ž—H€H !“DÞ÷ߏʕ+£q‚Jäí"C3$àu끎à}üÞË:‚·dÍ”®ÑS׺c#0ÙÝBñJÙ«pUÛ8§ýŽ·|ü1zÀ[æc`&µäš×=Lš¿Sç¬R‘Œl™”Ý& °&‰Œ‰'¢jÕªhT;?bîï¶ß­Æ‰Ú-_{]ށ¡øqÉ.”­ýB¹EÓj™ŽX'‡(ŒRæ*rycú¢-žÿ CûŽŽ*-͙ëÞ÷1E‰Œf­‚CVK3Ÿö’  @)yù”ÈÛC„fF`Þ¯;ÐìÕJ(à™ãgoQŒn‰p13+i @|¶61š^ô–ª­w£Šÿ…Ü9<Ðõýú„”A®ß4Dò&Í\['Fò2h8-  @0IäM˜0Õ«WGÃZy•ÈۛFSs˜Ž °ëàE‡„ãµ—ËcÑoûæü*<²—H‹¡M#: ŽÞ°õGŒ="Üò"҅gZLȞ™™@±Ü~š\à zYŒO;6@­*Å23Ž óý†Šäý0o~P"ώ"/Ãց“  € “E^5РFnÄ<ؗ63s”g&à÷0«ÖÂ'êޞ#×±é+JWhðÌãŠd7ïCÈv}'l#‚\šµ0üJŸŽ×Ü)Ž}I SÈá‚Üv;1÷—Íø®_äÌîž)9d€Ór®ùû¹ñýŒU°wf$/#ׂs“  <;ŠŒ\JäíöY9BšøcóQΟ%‹äÆÐ™WP»^»4×ÔA²_ø&Ù=6:ªç[±³2uHö#LKÀÙ!7Ï,‚¿Ÿ1ãfºß"ò$’7~Ú 8ºr'Bº/'$ HS&‰ŒñãÇ£V­Zxµz%ò€©,uüUoáÊ]èóñk˜·òüP Šß6/‰à垎é1ãc` Ÿ*ԖÍÜÈ}rBîáV®ˆv0¯3‚çÏWÅá [¶œ©[3žÊÛûªJÅ“®ënn[µ v6ÁXœ€¿Î¶Y¢H«öÕܜ»yû&Íی±"ò\É3·õ¡=$@$@)#`’È7nj×®­D^v%òŠlö~.Öÿ{B%ZÉŠ·uM_á*µß{.ó$9hLòï›»ˆÀÇގrp‡w^úõ¬×¶#ËõÝð/\‹Œœ~ö%3ShhºuiŒèèh”*U /ÔiŒÚ/4@ö억µtø·]pá xæ+Œ^hšý(\ž€ÙpŠ!©#zk9Μ;…ñßMÝŒ*U€ôÌ÷s6bÌÔpvc$/Uy  €Ù0IäI<9“W¿jVÄø2ã3³!Ã'ÿ‰oûŽÂÜå{UÔ¬²ç̛n8nÁóèOOœ/0u„»æAÖ«Ûa‚0üð©Ú)Uömßþnz]ÆõkàåuZÌŒüróÇ"X"Þþücråò„œœþW.ŸANÅæöíps˂þ_MRŒüØ»ç,^ô=>| í²³³Sd4DÓfï¡DÉ )²õÁ_ìÙœ!!Aˆ‰‰F`àC|øQÿ¿ó±c{péâ)äΝAAøcÍOȧ„œŒûðá}4jüÞmÛדÙ3‡ãúõ‹q——)SEûP£æ+°µµŒ‰ýú¶EÇÿ}*UꊚŸ¥_X<Ï=Ìøq$~ÚeKæ³tw,Æ~-òԙŒÑSVÀ…"Ïb֍†’  $MÀ$‘7vìXÔ­[¯TñP"ï0Yf0ãgŒpñšªW,Œ%ën£dåöéj‘«ïYä<û»ÉsF:ºãÖ †èž©-Zeìœùã0ìÙ³9î''gDDDš\”eo¿Ó-ZvTbÆV÷Yœj.~ÿmþ§puuG·îCµ’Šƒ¶aË?¿A¶o[e%0:vìƒ|ù‹$kîÿ­Ç¢Ÿ&"4äQâ˜S§ÿ‰,YR UQÆ&Êϰ'Î]¶l5 :S¿ƒS'@ìØµsCÜ5ùóEåCå*u’õ!%Ä>ÛW¯œÃéÓáïÑQQ T[G£!ŒÕ:‰]žž…Ю]ž¹g1yŠO»7S™|_Æ']¿1ùkëèh…—f«"é~ò9kç¥×ú ï‰s6aÔäåpuOùßnzÙÉyH€H€HÀ&‰<Ù®ùâ‹/¢^%7Šç>¿üŸ/T+ŽƒÇ¯áNT}äñLߒ Î÷/!÷©&{á’·kv3¹¿t\²x6nX®¯qvqŧ=‡£ZµzˆŒŒPQžÍøyÉåzˆWê·@×nƒu¿*¢õᅳm—¹pñâI>ôŸÚÆØmßSBÃÍC €¢[£F~ [%6lmÛþÄÉŽplþÆû*bÖ퉱͛Vi'ÂVoþîîY±bùL-|š5o:ôN‘ÏÆÎkÿ\¬#xîJýþÛ%FC0hð œ-ÓÅÅ ÎΏŸoümõ<¬_¿_~9A Ÿýû¶h[£Æ+Z0yx€îŒQHp(!|úÔA\ºtZGD%Z™TsUŒ]œ]ÃÛJèµU"ï¥zMMæÐ÷‹wô9É!ßÎ6ùkìX­Ài > Ë쮘:Z£‹fçÓm_L˜œßý°nYr˜}4ˆH€H€RBÀ$‘7fÌŒôÒKxYDžÿ‘”ŒÏŸiL <<³~ގN‰ £|íi:€3üüî¢Ó‡ýðÚëï$xß(Àº(X_ Á§µýÞCppŠÏX§»]¹r?-œ ·LV¬Tœ>¥Ebü&ï SgâÜÜܵ )PÀôæèÑݘ8þK-LçÎÛ¢ôN¬à1Ùû„{tkª#cSŠ®yê Œ×É —ë€Í¥¿LÕÑœÜj{ê—}' P¡”}pöÌLÿ…‹ÒlllQ€H)=^u~ñ¿#X‰Ñ‘£~BÑ¢ežÙW™CÖ"<< “§š)N%Z³Ÿ¬hîX÷û4T©Pï6¯eÖ¶Z‹qw|bŒy#'-‡»#yÖ²®ôƒH€2+“DÞèÑ£Õš—U$ÏUEò(ò2òf¹xÕûŽ\F~•tåèâð,T#Ýͱ‰…çáy°0iî;*ÛŠ©ed›ßˆáÝpAmŸì Îf5múä²"BFú ŽŽN˜1ëoýÝØäÛʳ0lÄ|”L挝‹ÐÐ`œÅÒØÄ‰$þòó-àŸ>WGьmž/püø^ 2eËV{=22Ý»Ÿ7^Žϖ!±SÇzšP±š³„OkF‘÷ý€Uț·`\×Ó§aòä¯õ×!Cgk‘fj;Šë%XEÔœývT©ú¢Šf»|È õyÀEKvš:d²ý nãçÎÃE•dжŠÌÊYEkovѰ÷[Š{Ï⇡é[ÅÚÙ>É?y“lÆà±¿À#+#y™õ> ß$@$`-Ly£FRѐúx©‚“Šä³ß-ҏwŸ…œ-vœƒÅ>HðНI/÷É_áxÛ€éóÕă’¯™ÔW:Éù²1£{¡RåðÕ×S’œ®÷ç­qÿÞÌTŸÀËvIc“€*›6®Ä,•-/þëI Ø¿o;•4%0.’¿DÇD@ɶÏ^œGé·$Ò8ø›N:Êøyïя ¹ü×8rx§˜Im­L֩؁þJ06ÁëMÞÅÿ:õ}êe æÃ¿[~‹äÅï,QDZc>×g%ê&ÛVMm·n]×g뒊HŠÈóöŸ†ù ·&;œlû\»v1vïÚ€¢Œ÷E=D—+W µN¥/òdËêÎÿþÆ•|çÚµózŽÖm:ãw»&˜oÿŸ±fÍBÜV¶æÎM›¿‡ ތë#‰l$ҘUÍ€’×L:Ÿ>ÞèÑs˜Î®j®­Z¡³è=p<6.ùÂ\MŽ*»|î"yÃ&þªïO6  °d&‰ŒïŸûN=45À‹å)ò2xµ­Ú… ¥ à×-þšQ·CºZc‰<Ç+wÇ€y Ԃ_±†jŸŸ!1Š)͘<Ŕm–ê®¶3:šD'?Î\Ÿ`ø‰úªÈÏI-ò’k_öy[gٜ·àß$»Ê¶Çõ떢óÇ_)QÒFgð”³wœûŒA­Ú ’>Õï_V™A‡þH <zOksçŒÂömk1ò»ŸP¬xÙǺŠèü~b?•@é5ôì52Õ6Å¿PÎÏIÆÏÙs¯—¿Ÿd•ˆšl­•–¿@QD©ˆç;^úwaúáGýôÙGywïÞÒg Ü¡Ð888ª3ŽïãÕW["OÞqCGEEbúŽ!8°ß 2%Âçë{KÿÜãÓaú, ”ÉøšÓË: Ù狱;ús•0Ɛ!Xê$Nüae\âž4’†ƒÊ釅sGà“ö¯ nõ”mµMC32ÍPŸ÷0Níøv¯Ț"/Ó,<% +%2‘WÎ1OX) Ëpk✠(Wª(ö])®"!é»UÓùÁŋß"\s# @M8ß¿ ûPUŽÀÖA•LðDPÞ*ˆpOyY‡Ëg)õŸì7AgY|Z3 —zªœB÷Ctýª{}Žnè°9É.¬!èƒÅ?ïJ2b%[9{öh®"A9ñÃäÕZ°üœ~† Ÿ‡’¥*&;~j;ìÛ»ÓTÔéëSõÙÀ§µY3Gšš×zµ}t†Ž%ÕFŽèŽóçŽkÒbËã矵‚­Ä;þܲ}õ£N¯èó•"Ö>þd êœÜLw¹¥¢€"–%±Kã×ÞÖe'DäI‘wirðŗ^×YT¥ìEâ6sÆ0}æPü•ä2²Mõȑ]ø^ üê5^Öç¥}Ò¹!Š+‹\Jþ·cJ©ó~ªì…B¹?Ÿ÷Líz¥õuö¶1ð:9 N¶øôÒzxŽ—ˆ€ˆŒñJä ÿ+²e§Èã B$@$`ÙLy#GŽD£FP·œŠäQäeԒ‡aæÏÛ™¹ 7AŽœÏvÞËT?l¢ÂáäƒÖÃ!ø^Üen¹áSé}D;šŒŠiÔ$3äl%X$«å›­?zâšÁ*eÿ·C>VÙ¯k±•ž¶]·.¯ëç"*’kFa1j̒'žYøÕžqã’‚Û¶þ Ù)µêÞlýarçúýVš,£?`ڏk“-Ôn<“÷ŽsŒ‹~ú›7­ÄÀoŠés~ÏÚú|ÞFGڞ&òdÙr*[O“Š|ÊÙGITsRmӕ3‘²U×Kq–&g '«„3‰“ÞÈ{gΆdEµ³³GËV•Ø®€K9¬]»DŸçlþÆxÿƒ^ÊŸp-2E0ŠÐ”ó•"ì$[è”É“=÷ù¬Œžõú ›«pæìQ|?˜çòž•er×ßœ€±3ÿÆÐ ËU†W&^IŽß' 0o&‰Œ#Fàµ×^C26*’wÒŒ=²bëŒn=ÀßÛNbˌيKºx*gðòœøE‰<ßó='H"oŸî Ïэ÷‹.‡žÉ6¿Ӈê”þIWØõ“ƪ¬A'Â?¹&û²åOúÊ5ñ›dz”ò)ñPPe§3ög-lDàHiƒ^êL^Uµðyޟ—LƆ¿ÅÂE;tìiMÎÊ9Ä€Î2А’skù±3ñ‡º@ü³6Ù®yÿŸ¯²oûS‡’ ¡’œtá¢ÿ’Ü9ú»žz å”ièí—"Ò$º&µ [œù¡Z—ÿ­Ê¬zEÕê«Y«Ÿ^;ñÑØ$j7pÐt}öð®ŠÖõéÝF¿%gò䜀D1åŒ`×.µlÿþgϊâ¹]pëþœeÓSV‚ä¹dÅß{š"y0pÌRäÈÁHž/5]# LAÀ$‘7|øp•å°)j—ŠV"ïTŠcŽNž8ë…?·zã†ÞdË€•ý®wN"çùµ …[øêÞãõÚÒb^)pY 8IøÑùã¯QŸ‚a[ªœ›“$Rð\Òú¿P§z~6â±:v²…OMºuÂ)' I< .‘äPã¶H)Õ Äelï›Wu!v™O¢PR³nÀW“QŒDym‹džœ:eN÷ßL%úhÔø­ž¬–rVPD„ԍKm ):.‘J)<Þû‹1*1L*?lTýŸºu_LüŠ˜Ðÿ=äËW£Æ,ÖÛ(}îÜÔ%¶š„,’”DÎŒ}Ôy4|””äYÖKæNsçoIy4ñ˜’€æÚµ ønÔO(RŽtÜÛRóPÖR2¡Êù¹–­:)Ÿ;ëstTò ¹üÐîœOÕvÎw”ÐuБ»û÷} [Eå<€Do*F‡Õ™CaTB­œ¿³··×óHVΑ*[«4©5X®ü£­¬ýŸ|WEÃóâ%ÍµÙØDcö䏰eé—f{vÐ\Ù¥Ô®û~Aó£ÚòW·m#ÐãüŸpô…}˜Ü\áÏYàÉD"N~øa@ܶœìª&›“*~綗Þr'¥€Ðž«ømÙÒé8®2)zy]NÙ1öqrrÁ€)¿é,“rëÆ‹Z€I ª\BˆŠŠ8º{÷vÜõrMýW[à‹~I–Í…jÛŠDEÌIºÐÐÜSÙ>eœüù‹bŒ+)iT™)†.å!$"™T[$ú$âóÊå³ZÀÊü‡íÐÙIݔ Vbƒ4y¯ºJdÒªÕÿÛ֚Û÷ýzÀûšµdì”èٓšQt;«BéU«œš óàÞÝ;8qr¿®³'çç>ï=FE-—á×e?*Q_S /‰äI”OÄ ø ë-çöä,_ÿ~íPŠL•d‹Š ÇïFöH2ꌿšƒÛUù pRµ͵ýùk?|ûùk([âñs‰æj³%Ú¥EތõøFEòræÌi‰.Ðf  ˆ#`²ÈkÞŒ9j•ˆ@LÀâË [÷œÅ¢¿|QŸJ“¶N©ÉÎ÷/"÷©• . wË«"xíŸ[/þd"Ÿd‹ä~µÏGmϔN®\žZ4VûRð;~! Û%šcl"²$ (ç°J–¬ˆÂEJêq$RôñG ô¶ËÄMޗˆ_‰ôWõõ’-ÁpòÄ~ìP =$ªuûö -"‹—(§ì|eËUKzxR‚ÁØìUæÐjÕë)ÁXŋ—׉^dÛ¡Žqc{ãÄñ}/‚H2GÊ9Eñ¡JÕº:*šÖmø°®zk刑 â"œOšcëÖ?°cÛ_ºü„œ“F²6¯7i—øDjúMœð¥>3'%€‰Ð›7gŽNÆR£fýÿ³wUeMÿ#  ØÝÝíÚÝÝÝîÚÝ`+vww­ßÚœvw‹- XˆR" |3‹ùȃsöãÞ»÷œ™ßœìÞÿ›93è×ßQ‰>yÜ¡{1Tœ¥Ú/]c‘Ékñ‡a‡ ¥sVN O[‰ÈæšmŸœ[£[ë(ùGm‡Êû¿AÀóœ/&ÎÛKéšëéß5ß§‰ÿÆÔrªB@(' “Èspp@­ZµHäÈ»åFʂ!žŒ;ÜP¶bÛîU‹LNq^\£B+ûB§ $÷*oóH-²™öò\\!“S3¹Ì>GÁXþ,]’["<~Ì)¡é” â}ZüÅÅl8­1ºGߞÒ^3îÓÅK+™ûÑà”ÑÇ÷(›YÄqõHö!I’”_5†×—/·©x‰«ËcT«Þ4\Kp:ëÏs5NMª¥fR…ŒïŽ‹Åhî•Ë'1“¢œrË·?CÃæƒéAØZ¯&ÆôrS=ñšÔŒAàé†Ln.QënÁ-.xh*hjŒåè\×îZ[q€saŒºrlòçH‚Ö Šº©Fm‹<Žä ¿†>ø‰šÊÅF LŒB@ƒ& ³È«[·.þÈà‡`Ÿûí)·uÏ%lÿ×uŒ7cz=§– ¯á—$‚­~]Ý1J ’E„À7|©û±c;ñðámx{œ£hB€I“ y(êÇ骜~kìãٍ¹H`G­(Z•7vW Úþ÷$òƓÈ""Ï ¯“'„€ºÐIä5 õë×G¡ô>$òè6³éVl>…“7QµvïHŸ[&BÀ0 <Ÿ:qmƒÑû/iˆ®Ï+äåýãæR$oÜ*ª”ûû-Fôi«Ì-„€B@Dވ#КQ#LçE"ï¡¶9å}=Xºñ.ܳ@ÅêÝõŽ‚L+„€¡‘5W„EÞ€…ûÑÏ~9íqM5‹Ê*B@! ôD@g‘מqcHóÁŸôdŠL«ÀµGqói,”©,‘µ±’÷…€©xte6âÇ F¯?%’§Ïkêí㏱söbÐØ"òô ZæB@(! “È>|8š6mŠü©ß’È{%†É"߁Óû`g LÚ8ò'—C °È;gú;,¥Ÿ”Òx^n ! „€0n:‰<ŽäµhÑy’¿D°ßSãö؈­Ÿ0w7> =rniÄ^ˆé!À ÀW¯šŽ:uÛRywyCc=çÙõ¹°±  IDATDßUŒÕ£°Û×ï#FÏڋ£EäÅ#…€Bà—tyC† A›6m;™;‰Œg‚4šØÏøÖvّ%oøšOG“¹²l$ðô|ƒ^=j£E˞Ôü»u$Î,S:—›sa#ý;V5tSÚ>¿á@"¯¿ý€NÚš}ㅀB@„S乑ÈsjÑD`èämH”²ÒfkMȲÑEàíÛWèݳ.ê7hÆM:G—²n4p»3ŸýÑ¿“ˆ<}âg‘7zÖ>ôµˆz-ŠÑçR2·B@œÐ*ò‚ƒƒÁ}òxO^îdÏIä¹èÝ(YàÇúÛŒt™Š!yŠ:‚ÈÌxxŒDŸ^õP»N4oÑÃÌŒ7ow_ÜYˆÀ@o îZÃŒAèÙûþ3{?z ŸŽiÓêy5™^! „€~ hyŸ?÷ÉkÕªr'uEðWýZ$³ÿ”@ÏQ됷@ÄKU](™×¯ÝѯO4jÜ v03ïÍÛÝWN áçç…aÝkš7={ïÿ1ö3ö¢÷ˆùH—.žW“é…€B@è—@8Ež ‰ŒçúµHfÿ)Þ£7 PáJˆ•ž²P23/^ž``ÿ&hÙº7j֔Â;ætùߨÊåë˂B@! "“€V‘H),*’—+ñy/"s}™+š÷XŒÖ­ZÃÛ¢x8Ίء8~lnÞ8råë Ðe"6‘œ)=Œ ûèÛo2 ))sÊ$ÆAÀëÙrž¹¹aLÿúÆa°‘Z)"ÏH/œ˜-„€?$N‘÷˜DÞKAMw]€.íÛãͧ"ÑdAȲ.ÎqáÂQÜŸu®ÏŸÀ&–- ™Ié2e×çϟp÷Îu,‹wwguÌÐáÔÜÙÆ6ôØ~ŸôABÕ dI)ÿ£‹Ë¬'Mì…¡Ãæ OÞ¢‘~ý¹°‹Óœk°µ£æË&Òא #FÀÇy9\\Ý0v€ˆŒˆÔí¬ÀÀ ŸŸ=‡ÌBƌu;IŽB@!` ފŒ€*+=fŒJ×̕è‚?Ÿ2PWLÛ¬OŸ>£iEèÕµÜ?ŠgOžÜ‹=»×ÃÕåQèúÖÖ1I°ÅFŠ0åÈQ@œÎânÛÖ%8q|7Þœó=–…CŒø‰0qâZØÆŽú:§…rzhï>QŽXÅùàû·âðá¿áãýžÒr qÓ.¡6i&ÝŽq,,b Yóîß­ãç磢—÷Hì$K– ­Z÷QÂôÌéðö~;»xȚ5/ò(!v áõëfƒ‹«,X •*7DŽœ¿:üÒ¥ã˜5cˆJÍ’%÷wS]8ÿ/þùg%^œI“ŠBõšÍQ¡B=­vr‹”û7cÓÆù TÇǧk4˜tÓgÈz>WÙ=vt§âëîæŒØtýx¯f©25P¢Dbj¡u-9 b|]Và™³+Æ ”œ˜#šÛYAAŸ(]sº œL™2év’%„€BÀ@ hy?~ÄžqãТE yIäœ6PWLÛ,. ЪÏRôëÑÎ>_ }y~ãú9$Kž)R€…§çkôêҟÏÚ:–jÈÍ)œ)S~_jü̙ƒX0Ï^›”ÄR£F/qċ—ð‡ŠÞ¿k×ÌÄÀAӕÀïðô|ƒ‰ã{ {++k藞o_#fÌX˜0iíW6öèVï©RaËVT¥²VH•J7{÷lÀîÝëàçëT©3 mÛþxýÆ+—OQ¢•çåý‰Þ>ïѱÓp-Zá;3Yƌi£¢`¯^¹áð¡¿IæA‘/Dz»yó œFB,¥:ÿÚµ3˜6¥ÿws±­S·mèë,°/‹ÉS6P£æÿ@?} "< )ZªxÓŒ•ã¡Ëþœ•+ŠàÈáíJøæ/P^^žxüè²eËûÑKÔ 4M “E ÆšóY<Õ«ÿН€¢[,Ê8r×öÏTm/‰•èܱ²1c(¢–ù›ˆÚ’Åã•2t6æÌŽ®%J” sæíÄö¿—©/Õª5E›výÓý“ iKÂbY­\îgJ‰mѲjÕn¥Þc!Ƃl֜$IŠP.Ó§ö#gÎBèØyžº^W¯žÆô©”ï?`êO™=J,–NR  ž‰Œ™r(Ñ6lHkåãÜù»Ô¹ãÆt“ÓõPÛ¹ƒ¥¥|HðîÛ»;w¬!vIP¯ÁiŠz²`ŸGç?¶«WMSçMŸ¹M ßiSú+öŠKŸI€ËÐN À}5îÝŒICk?XŽˆ0Ζ2uzÒ߂Dò"ŒQNB@! “È?~ŒJ×̑À ø/ýÎ@|0 3ŒŒ? ãUÜ» x揟Fµ§‡}_LŸ9t=N]ÜŒy!<ÞŒ }KªôXµëŽFªTŸ²‰Ó'wïZ§"dþþ~ˆ' œŠšRµ âÆiökÄGÙªÕh†ôé²âíÛWزe‘Šæ  è §@†o[Šÿm_®„ -N5lÞ¢‡¢,侒åš"EÊŽJ̱PåÁ.{bÂ#W®?0|äü¯æeÁuéâ1ŠôÀüy£Ô{ $ŠÞv}Td“°xJ•*=§n„‡ÇKôé’RÉѱ³þŠ(iLŒ|銑ÃÛ)Á5á^•»wïlX7‹—DJåq÷îL×]ùQ§nd!Aú™Ô®]kñ€¢£5kµ¢ˆe¯Ÿ²mßÞ°ó;wáÐã^œ|ÿšWXõÚìYÃT€EtÛvŸ›ÛmlÞ4_…ñññ²¥ѵ›ƒx>øªãûÒ,‚ý?øÁÆ6¶Š˜.XŽï§ÑÝH»AL`¢ÀkpûÞC8kbÞ® œ’<ØqŠäeÎüõþbõZ,B@!ðcZEއhÕD•®™3Á=Œ–Ñ@Àóœ/º [ƒºâΫ|QbÁôiqãúY,"a¡:Œ0? ݹ}  ºpžÓƒQ€„T£ÆŸë©Ç){,|ÜŠ§2–-W[E5©™\xe͚Ȟ=?ÊWМL<§öïۈÄS\•JÉiŸaÏÅ©•ߎ@õ§ ={Gñÿ5˜gÈB0ìþ7öy*E¡žÚšfpÄ.oŸb¡¿k¢j,ºX¬±`äH#‹aދ8œÄGãîÝœŠ•«OšïƇì 䜈Œ'Q3–.™ öNšŒiIlíøg¶’peѧáÆ"üÉ'ª¶YN‰0¬šÁ{YŒý*zÚœk •ž¹tّ¯öH~ËK•9jáw{ùX /vœúÊ"p*)G2Ytóug†ì#G)Ù{‡ÅÈF×\Ư |~³W¯ßÇŽ‘M• (‘7e/zÐC"òôZŠB@(! “È›:u*7nŒñiON g”&‹|MàÍ[ot¹ƒºáƋŒQ‚‡Ó9œ1l€‡ÓÃFí8%“£u\d…GŸŸ“P°Piµ‹÷š…M-dQ³sç%9rå@{Ÿ’вýû6aÝÚYTP$ «”F]§)²°âèG™žå]ZÃÚÚ9)ÒÆûÊŸÞT”…SYpr…§:rÄOSñSԈ?Žžq "‹UÞGV菲X±|²JBÕ.¹H È㟹iùþ}›U(GâÆŒ[ŽÔ©3Ò~Žé8x`+æÌÝIûó΃ÅN1e| ®€Éþh„Š&Z6‘DGØX8õîYW¥x2sn–~åÊ)9˜9—*ceeõ•ûŒ_Ž÷#j®ÉÄ =•XçŽÎ.]9Ò÷‡Ø×¯}Ž·®-¥˜V¥TÓ°ƒ‹æ,[6‘æL‰Qö‹”Ød‘ǃ ²°_œjÊC³Gáè .{u¹LýË·påŠ&KºŠ^/5ÿ»`EòºÓžÙ,YB¢Ø2„€B@+­"ÏÏÏ“&MR‘ŒñïÈ{g¬ŸµÝ/_{¡—ÃzŒÖW\¿¯®šç4M‡ÝÀþMªh¶nÝWíáҌ‡Ô"a4õqcñÆ{¹4{ß8šÆ>~]34‚¥d©jèÞc íÛB"jZ·é‹ê5šëìÊ¿GþGbˑ¢‚Q!˜.ZÏcQÈ{õxß\­Ú­Õ~7.frD'Gœ8]“_ã#(]’úâÇOš„ÿÌövî2J‰§TÉrë–Å*ݐ#X\XF#òòä)¢ÚDðžF·çOÑ«÷øÐâ+šýrœŸÈëpÄð—/ŸPéœ,žÞPÁ®žÉ"r’ãzU@†‹ž¬Z9U,᪙înÏ0h`3ýE1mƒ}˜êØOŸ:…Š«'Oî©×8šÇ~pÊ&GÖX§M—YLáÁם÷é oÞbHMûï|) z÷ÎeUä…í1r%NŠ*p²Èãhãä)Õ>ÄC·¢FhÕŠšÏå(bå*ÐŠm?mŠ›ýû1<Öãì•;˜e¯û߆ÙC‹ €“vS$OD^ñÉiB@!`@ފ<___8::ªÂ+9âß&‘÷ހÌ7SÜ^ŸCß11iTO\xš+Jçê‰\¶ìø•*ÊÑ NáŒE"ypK›8$€>Sdéµúž,YjUdã5٘4±gh¥Ç ’𠕁•hâQ¶l-tî:Jã8©·Fa#ڜä(Ù0R±(Ræà@Q0?œ.ª)Âûïj×i£å}o,ü8º–žŠŒ·BœÎES6oZ üJž" ª ©X©ÁW­ø}n)Á-§n"±ºI!á$ìWÒ øøU#ù   %†Yü²žbÄûóîÜŸŒ-Ž×‘#qœêÈÕ;[“Ò€f²š:€¥YiϧE²ÈcÎ,”Y€þjœ?wsçŒáN鲝»ŒT?s1ÞOwñÂ1ÅB3bQïCŽrÑ.HÃûÿöÐKN‰å}…Ì”)§bR€hye3nª}‚œzOÀ…Ë*xýÚYi Ûf¯…×{Oôêɔñs–žpêüMÌR V†þ vÜK-ŠJºŠþËÌB@!Eފ<pºf³fÍHäÝ"‘çEŠÉ2a žº¿ÅÀñ[àhßgGÈûÙàÖ lÁsYªU÷¿£H#©OÕ)9¢Ãƒ…§qž:¹O‰ Nßä=bŒ®p‘òT€…j9ð;cÃú9*]”×oÚ¬›ÚŸ;v\Œ£¶ 7nœSØŸRĊ+f²Ð«[¯:îÛ¡)À^[|©ÐH,jìΖGxæÑ€…N›±Uµ© AÈ"Å³F4…µ‡£{–EÔ€¡r¥S®xÊ7Ž@r=ŽHúúzáŸÓ %TYœ• ó¥HΚ9TE9ò¶¯Ám(X qÓzŽðœ~íŠöÐq[‹ï›ÜV‚ígœñÂà ŒŒÍñx+ύ8~î:æ ©Ž*CMދ.ý'Óߨ="õ·šÌ,„€B@ފÁE”rÊLy|ë;‹ê®ÝPšP™ðN-ǁ˜ï7àôÅ;˜1ª™Xdºf š²©8PöìÙM×IñL! ̂€V‘çåå*ò²Çe‘çc` ÍÉg®è?~3Nîƒ#wEä}{}8-÷r ' Žhe€tÂŒyŠþ23:¯³Š-7lçTшŽ&;¶“ŠÉ܆·×;ªä™P¥XòÞ@îå÷£š`Dגó¢ž@,¯M8xü2Mlõ‹›ÙŠ"òÌ삋»B@& Uäœÿ³fÍBÓŠM‘=î5y!}¯dD-'.o(]s3–N돷$•(jéëgµ³g©~zƒ†ÌDþü%ô³ˆÌjôlHäí;z K&·3z_ ÝûÙÿ¢u{äÈ!€úµû„€Bà×ފŒwïÞaöìÙ!"Ïî*ð)$-LFÔxôìOچ•3úbÏuI%ŠZúúY÷¿9P.ÃÅ`d`‘wðĵ'ÏÒ2†@Ò#¡ÓâÏî£iqôî{Ö£‹2µB@˜ pŠŒ+$ò>˜ ÃrÓé‘;fîÄÒ©œ°ûšˆ<ú:³F5§^w\ÕrÎŒ¡Å["6›œeª¬ßoÄÅ«÷0n@}*œóuïCSõ9ºü‘]äe]! „€ˆlZEÞÛ·o1oÞ<ÉËç‰<ÿȶAæÓÀûn;{–OWsêp†b 4ÍÑÇMX…Œ%EÌ®YTÛ‹DÞñó70yHcØÚČêåÍjœá3Ž ]7{äÌ)ÿŽ5« /Î ! L@øD^ì‹ÔXì£ b0|—n9=DŽy»±|Zìž" †Åt³‹Äpk„‚…Jëv‚ev,=×áüå{Ó¿ìâü^˳ƒN‡‡Í8Œ¶]F!wîÜáUFÂqÌÇïhðtøÌ#hÕq8òæÍ «Ë’B@! "€V‘÷úõk,^Œ8Däٞ£†ÒA‘·ºÌ€3+·žaÖ²C”®Ù Û.ʧÌ:ƒ“MŠÀ€~‘ aŒ²_dR~ýʙϯVáÞyí+#I¢žfãwt8:bÖQŽh?ùò勎åeM! „€‘F@«È{õê•J×lÔš‰Œ³$ò>EÚâ2‘î.Ýx‚ùkŽbù”Ø|ÞžEÞíۗ°bÙd >I’ŠÔ‚iöú÷m„žñ`ÌØåfÃâóËUxðÄÝZW@ò€ñÌÆïèpTD^tP—5…€B@Â)òΐÈû¬;dN-.ß|ŠÅ돫†ÈÏw*ÑÚÕ3pàÀL˜ŽéÓg•k/t&зw$K– ÃGÎ×ùc?0ðÅ ![¶|2lbÅ2ß^i;UAÑ"бóp}_ƒ™?ˆÒ5_Œò@“Z…‘!Mƒ±Ë ±Ÿw [öA¡B…LÑ=ñI! ̈€V‘çîîŽU«V¡aÃ_Ò5͈Ž¹Ê…W®=ŽåSÿ€ 9dŒ~} v잎'o6S6mœ‡Ý»Ö!GŽ‚hÚ¬+Ҁ͌ýû6áۗ£\¹:f%pŸœ*íÿ,‡ ê¡M»þ†sÁôl‰Ÿóxy{£^ՂȔ.©žW3ïéæFƒ–œDä™÷m Þ ! L‚€V‘çææ†5kÖ AýzÈjsÚ$œ6F'.ßzŠù«bÅÔ¿ð¿K9àh%nøûûáÚÕ3žtéž>œÏ·¯PºLMüÕ~p„×ïØ¡"²d΍¡T]SÛ8° Ž߅‰T€ÅÆ®k±yÓ|+^ ݺ•Õb~×Î5ôÞôì5ÅKT6_ùøùó'Žm] õêÿ‰&M»FºÿŸŸÞžuó‚‚‘'oQƒÙ/ê댟>~šU)²dHé~˄ÿ‘'wƒB@˜ E^Ãõ%–ˆŒèºðªOÞòCX3³#þ¹”cêՔ÷ïßbýºÙž|é8>~ôWkYXĀ-ræ*„þŠ~µþ¹s‡ÕCqΜ¿Nsò÷ÿ€Ží+ p‘òèÛo²Vl®öíMž²Aë±?:À×Ç ÇOìÆëWn*Í1Y²ÔšP±>ùò}áš'ïÁ:fL€I“‰ Ûc Ueq[·n;T©ÚXM€›7Î+3f,¹ÝzŒŠëû;!uîìaÜ$±ãñ慪bÉë=sHùƒîø ¡|…º°³‹¡kò£“>|ðÅö¿—áèÑH”(™ŠXòqâü׎EXJ×lÖŒêÔmóÝ4ßÅÖ-‹ðàþMu^ñUКq§ï8þh}w‹ŽÅ»woÔۖ––èÔy$} Qã«ÃoÓ^RÛÞF :&eÊt(ZŽ"*Unšþ6ô1|ž-BÝw•KçB֌Éõ±„Ìù…ÀègQ·i7.\X˜! „€0jZEž««+Ö­[‡† ê’È£ 2¢…ÀÕÛΘ±ô ÖÎêˆ]W²Ãç£~EÞrêcwôß”¯¹óAõ͑+×?Üöâ… öo¢Þ[ŸòØw|öí݈;w.«ŠˆÜćNÈEÅ38"ÃbҏÞmmã SМH™*ýWç/\0©RePdžw<~tS§ô‡·÷;%P$LŒÀ€T¬Ô€þ;~WÄdâøJÈ,]~o[ªÒ#Cø­à8u#R€H‹{w¯büžnhÕºJ”¬ŠÃÚ(x”-[ »Ž 5“ÅÑŒ¹£p‘D€Ôðõkwõs·î£QªtõÐc9J5|hž¹=Ã$ÇuH:ãÝ=}j?˜ ÷‰Ëœ%w„Öš7w$XÈú£ mÇÐâ7,9Røò¥«p v «(†OH@ñà×Y|Š¥Ò®äCÜž_ =Á~~>Jðó‡û÷m€ù-I”µUç3 Ï: £â%Õk,šùžxøðÖW>óuô8KÇò`QÏö=w}¬üä5{÷Dç‡\¶5I’êçãÇwÃÅù!¯ê€ær§kZcÆôAžrù$ZŽì‰Zµ[eû{íÚŽï8D5k?1=ȧW•ÓYhrŽoÔÈ?©Òe3%øž=»¯¢’7( Çl.ÞOâ D€³cQÆÑM.’šyٗåK'‘m§/^BÔšÙ’ÖlD×þ&ŒëNÂԍ¢gÝQ®|ÚKií,xX€ <ã+†'©"èÚ531Šê?¶«W…Ž:˜>s^Q4uڔ~$Ÿ>!õGÔ€àž<±‹…TËdñÔµ«= ÍçJŽ%&¡4aâj%.5Ÿwéf2”2¬ǎîIJ¥•Ðbñ̑fyú5VÑNí?ϟ?QâúóçÏèÜeʐPç±b¹#þ=ò?L›±U‰ûm[ãŸÿ­TïñõìÕg‚bD×xÙ:AŸÉÖ5êÞå}§£«/† i¥ÎëØižºFu€§çkuܜy;µŠ…z=^ k¥Ò9(ò¬ŸÓ{¯eÅûú¯°ø–ößmÚ8_E}8ÒÄ»uêµSb“fìß¿ëèÁŸf­VhÙª×W45‘¯ìÙó«‡Þ×υŠM›uáCÛhïãk$L˜”ÎË/bÃìx°Pêß·!E";S€­œz-Œkñ9©âh‹këX”†úQE"ÛPùxŽ6ñ˜3{88ºÇâ„S'5ƒÅ3‹a#G-DŽœÿõÓ®®Ý”Àã4L}‰ûèÿÁO 9¯ íSBié’ $C*­¶¥FÔU«5Q?óù‡š…G9풣¬£Fü©Ò|YXóàtÜýS› /”.] •V×ô4õadñ˜‘¢ÃãÆ‡ˆ³ Ž\rúeýíÑžIçÐC>øùâñ“»ª]Ÿ¶kVOWóÙÓµÐyÍ œŸ9ÚŸªUkŠªÔê‚ï?ŽÒ]¹rOŸ8©ÃZ¶î­úCòïœÖËæ^œ'šý—¿ï- ·)*Y"rdNùÕ¡‹×GÖLÉðïé{8zæ®ÝqAE{eŠfEÎ,©?gi»ðKº_¿9~ÉÔhÐID^8˜É¡B@!`˜ފÝÁ([, ·¯EÞž9»°ïèM\ŸåŒÒ…³ j¹Üðxëߏpq‹[÷ŸSeN%ö*–ʉ„ñb# íëËJ\€Rç÷ØÇ.Ÿ€š :Ò>Ë¢¿Œ&òŠB@C'‘WƒDÞyC÷Çdí»íäŠqs÷`ÓŒ.8x33<|Ÿ.˜¡Ç=©—?œkÄG}8ªÇ‘WڋÄiqC†Î† ‰8ް°=v™Šøœõx…3…F14NÿìÖ¥†Š rX€R<5CÍâtž£8ztîXYíñŽOë¹ë§TT+sæ\ê?lÕLö©WÏ:*zǃÓ:§nRÑSÞëÈ"‰÷èñŸÀU+§âð¡¿1ˆÄ$ÏÃï…w-žwõªé8r8€x û΢›‹¬p!,ȘGAíG/QB–‹ë¬Z1EED9zɅRøÚ‡*jDÏQ‚ Ÿðþ6^‡‡f"‹Þٔޫù… :aÅŠ“ÓuŒ£ŽÒ|ùK(¡©‰–qŽ‘Ãó`1Å\ç-Ø£"ŽçÏ¡ýpî”f›‘¢¯¥øÁï!åd.èó¿í+hÿåµ¿Ž¯Uê4?Þ ©I§åkÊB5láŽ0.˜ç@ Ë_cÄÈêï…íÒ\KN‰åtRš=‚ÞÞïéN{=Ò6V(F©˜ßŠ<ÍßCPÐ'œºô·èàóןÀéÑ Ü}èŽ$‰ìž%ùjme o_Œóú@}÷Þ+˜_‰?2#ž-2ŠM¢ŸXüñw[ýîûÕåo9ª·ø"ª×obŊEõÒ²žB@H% Uä={ö [¶lAÝÚՐÕöB€..“éNàîC78ÌØ‰- ºâ‰Œ7Q òÌwPÕ5YðT®Ò8Žè ‹„ÓSk…ÓèÐqU«¬§RÙ8¥«&¥è7c1P³VKܹ}™Ú/8aâäuJ4p ènJ[äŽ=.taKûæž={@©ˆÏÕ2G¹4ї®«$ JíÛûÃý€?"ÈE* lŠ¢ŽÍ᪌,ÞxíA$&LŽˆq%KN¹lA}±8Ó£[M•F7uúf•®©ܔœ… OŽØpQ–ÿ`‘—"eZŽo?D­¯IQÕå*wí\Rß«Cíìâ©  7ožÉ̵*¥€hªMµ—‹8ñÏZ(­p5]+.J“/_qtê2’Dã6ìøg•Ú¿È"ŠíäÈåÜ9å"ÑÄׄE tNs@Q/ŽÀ±°ãÐY‰*Nõäb4/S‚† ¯Lž²Q ÁC·¢E}[µé£üãëÑœk µ§#¿mZ•Tׯ‡D_³¬Ôô÷B²°â”FMº(‹å!ƒ[šYÞ·É£g÷ZJä͝¿û«ÈèϘó=ÍQiŸgùÞeæSè>`\P†?``ß²eϧ¹æ>à{~È –*ښ!Cve#¿Æ=¹( ßË}ûNVUW¹pf? ‹>/ò÷¬òœÎ÷&ÕsÔÈ¿Ô}©­=ˆïӅäÎ'”,œ¹²ŠÒåv =Æù¹î=~GO_á©«žÑïÏèûÓçoðžÄ^™"Yñê­·€<ü?âœ÷ŒöðFüž¶(;- ÅžÈHMØYøeø"Mµ)»ˆŒpÝ^r°B@0­"ïéӧغu+¥kVCfyÑu-ï=rÇäûšOޟ8z73^yý—ê§/›ø!›ŠùážE§iò^4??o]ãхªIjŠUpƋSpD%oÞbj§<>|pK¥86kѝJ“—Sçqa‘=»×«¹yðŒœÚȂ’+7jƆõsԏ-[õ—›œÈ{üœÀŽ„[ñâ•QŸÒâ4ûÍx2N]JûÄxŒŽ_€üâýiš ‰š9Ŏ÷[q‰þYôU¬Tÿ»â0\þŸ÷°qQ^ܶÅ‹mƒS.‘Ðøvp£aŒO382ąPx°Öu-Ž8qŠ ïYäôÆÞ}&…F¹Â$G yß Ia‘ÆÑŠÕ«Šâíß³$ї;OaÚ·ÖEEj5ƒ‹¡pÁÞ+Èk8ՒÓ/y¯Ù…Ë‚£fׯUûìÂF¿8œ×뜧*`Òºeqµ/­u›Ÿª©¥„òàˆ&§FjÚ°šêߗößùŸÇ’¥‡B Ý|)n£m¿âìåå©Ä%€ÉRa&µ¡àÁחÅ(ZÑì!ä×ùžO—.+ím£ìcÿ¡ûö¥…r•Ó1Ù_®’É÷º&âÍóqê/ÛÍ÷-§-s±š*U›|%D¹-°™·`÷/oûs+Š%J“ ûY$OÛýõ£÷Yйžœ¥ˆž'Ü^xâùËwxNßÝÔ÷w°‹ ÿÒ>?{±mcŠx|¢kà÷!¢~H‘4>ŠȈžv6J|r0szú¢ïñ)-ÔÇø%—Q•ZŠ/®[ր1ú(6 ! „€yÐ*òžG.](Už(EypZðС­T!޻ǀJ„l œ©òé%ŠD_»zFÙ6dØl8NêƒWT-Ž9õÚûöÞåžÇ§…>~|GEäžè ‹ûoeù‹S>4ÂËàW|YäِÈ+É"O×ûýÅë÷¡ÂÏýÕ;õ³ÛË÷õ ÀÙ+ÁïÑßoH1Šô³•e $Kš·Sñ ôÉQ8_äϕ– Ç€@œØú­ ¬«_?:NDÞïГs…€BÀhy?ÆöíÛQ¯Ved¶œdH¶›•-wža •çŸ7¶.=Ë·wñÌÊctö¥.rƒí°ÑJNÕ 1]»;š‚,6yÿ§µrTŠ«LþH„ýŒƒ®kqdû·±ˆ2”Á" Ít¥Ö\‘•‹Þ°(ã¡©|ª™‹#ru(:¶zfD։®sB"y1šbf¶ïªkF—Mß®ûÁ?®tåˆ }¿ÿ„öÒŸ@—çoñÌÍoßù’(ù!Š5}šC) éR'¢`J ¬T*—AT°ô2ªÔ‘Hž¡ÜWb‡B@Dœ€Î"¯.‰Œ,"ò"Nú7ÏŒMUòŠQŸŒ™öÍpÃ-'ž{ŠÈûM€Qr:—ø?vl§Šy{œCŒø UŠ_j0ÏÍÌÊ-n#Áé”,V&JªR[y÷³ã}lô¢9žÚ©'¥ ò>9ŽÖoR1"v;Œ»\`xf§=ye‹g3j‘§í°ð;rú.Î_} ރÌûœ|>šœ€ñãÙ"}êÄ(’?#j”ÏKMß)"MÑÀÈ“V\G¥š­DäE6X™O! ¢œ€V‘÷ðáÑW³"¥k^ŽreÁ,òæ¬<‚ÑýêâÑ»Œ$ò&ÀQœGnㅻKHcôÄIUdŠ¿’&M®TNCÇÄUNïܹ‚yów!U•ñ57N³Ëڒš¡gG¶L)ÌÏýÇîØì6ºƒ›NÏ՞@ÎýŒÓ Høʛµ+åCÚó÷»|&,¿ŠÊ5[SûfÇYB@Ó" Uä=xð»ví¢H^yŠä…4N–õîvïލ:ÕË!sì«눩v‹>Á^²á8úvš‚Wðäu"SwYü3µä†îܔžÛOÈøš€y–šR67µ(‘÷³ûãì•GØûï 졯Ôž÷÷ùø~D†4‰»rŲ£,¯IžôçÑâ‰Ë¯“È£^Œ"òäÏP! Œœ@8D^Yy!ý«dD=N×\¶ñ$ºµ)wÁ…ðèUâš7BVz"pŸúr‹ ®ü)ã‘woµ“ˆ‰Š%r #õ “¡ãçpì¬v¹N…^\TAªôɅ]êT.€jåB„_Ø1iÅ ”¯Ö ¥J•Òm9J! „€Ð*òœœœ°wï^Ô®VšDÞuuÃôÍb‘·bó)ŽoV~VEðð¥ˆ<Ó¿êâ¡ ^€T]øŒZ•òST*‰ ‰®D{òÂCüïÀlÝsIUò޶²„û«÷šU1/ Ÿ<šFÑŸõÜHä5‘ÆrŠB@­"ïÞœ{Ø¿?jU-I"ï†aYoFÖÜ¡>yk¶ŸE‹ºEñɶ(œÜåaό.¿žjÆÞ8ÍR…FêU-hœäLáRp%ϯâû¯àõ[jÜ/=Œ(’œ eËWÁˆ#šÕISpU|B@3% UäÝœ{ H^)*Œ"‘ŒèºOî>tǪ­§ÑŽvĈ[ ÷Ü%m+º®…¬+¢’ÀÛû³ô kFš”Rp)²Ù?v~­ߎC×pëÁKwéñæÍd˖ ­ZµBëÖ­©Ï¢md/+ó ! „€Ð+­"ïΝ;8x𠉌’$ò$’§×«ñ‹É¿P"¯~Õ°I\wžK†èº²®ˆJžæÀ? ÍëEªäÒ:EŸìGÌ»€WžŸÔ›©S§FŒxñpúôiT¯^] ŸFésy™[! „@€ÐIä:tµªCŠØ·"ma™(|î³ÈÛv5+äEü¥pË5yø&£…€0JïÍUMÁÛ5*õËʐF霁=yÕm”©ÔeʔQÛ–.]Š£G¢\¹rðóóïíãʛƒ ‚Y/æ! „€ø€N"ïðáÚY¹šˆŒhŒs={…uÿ;§"'I]7\DäEã吥…@”ðz²i­jŸË8®¹Råk£lÙ²†àíí­*orº&WßìÕ«J•*…éÓ§GxN9Q! „@x hy×®]éS§P£B~Šä9…w~9>’øøúcô̝(Y8 þ(\g€‹€™e!  •@ ‹ÏðåtÍÇ/á8¬±¡ši2vMYó¥*ÔÖZxE‡¹òf›6m0þ|ØÚÚÂÁÁüßÓØ±cërº#„€Bà·è$ò8å€6EòÒK$ï·`ÿÎÉ?bšã6”.’ EŠVÀéûég:9W#  yžŒÄ€¡"òô}ÉŠ¬}€’åjýV$ï[»ví ___ØÛÛ£@àŸ³%J”з+2¿B@˜9Dޙ3gPœ\dˆsßÌqEŸûŸ?Fo‡š@}òŠ+“N¢ÏYY(!À"ϛªk>¥>™ãiOž ýp\û¥ÊՌT‘ÇóœyóæáܹsªÅBÛ¶mÁâO†B@}Ð*ò®\¹‚³gÏ¢f…ŒÉ‘§¯ ¡ËŒ}F“È+‘EŠ”Á §ŒºœòÛÇøúxásðgê•ૹ^ŒpA²d©#FŒÐ×Ãsìo&3 `ƒDޓExêêq뛁ÇÑëây%õ òØ«óçÏ£f͚xðàFŒàà`,ZŽ(z–Õ…€BÀd è,òj”ÏM‘Œ‡& Â5ýș%*–«„£wõ/ò<ž‰ÓÁßÿ&OYäÉC*z.˜ï€3§ •ïÐq˜z-<Çk±QKŠäyQ$ûd:ô­g&™Ž S×=Bñ2ÕUƒs}Œ·oߪ>z{÷îÅŋñøñcÕjA†B@È& Uä]Ÿ|Y¥˜Ôªéb?ˆìõeŸp2yòdKª•*áß;™ÃqfÄ]µr*ú[Ü¥›=#š //OtïZCœ–4Y*̜µ]ýžc#fœ%̏€EòÞ=^wê“iß§Žùˆb§È+¡G‘§q§xñâpttÄÇñÏ?ÿ`×®]Qì©,'„€ŠN@g‘W³|.€óÈÔyŽÉ˔.)jW«ŠÃ·õ/òNžÜ‹ëç"SМèÞs,U…³C@€?'õÁ«×nhÞŒJ•®®˜…çXƒ†,Æ "À"ïíÃùððôÅ𞵠È2Ó4eêº'É«ª·H^Xjõë×G¿~ýTÅÍ'Ož`Ö¬YŠ UŒB@h! Uä]ºtIí%šE"/ˆŒh¹HšEÇÍمô©£VՊ8x+kŽÚ"‹ ! ,ò^ߟo éA—¡?369£hÉʑ^xåg*T˗/Çʕ+U'÷ԓ!„€B 2è,òj–ˉôv#cM™#‚&Ìۍ€‰â¢IœjØCD^1ÊiBÀhX[~‹»óðácu‰šËЁiž¢X©*QÉÓxaccƒ÷ïߣaÆèÑ£‡*Î"C! „ÀïÐ*òxs8Wج^&ÒÆ–tÍßþ;ç;.܇xv¶hѰöÝÈö;SɹB@«Ÿà~w.‚‚>¡ǪF`±q›8eýS”(µ"ïÑ£GšV­šÚŸ—#GìØ±Ù³g7nbœB@D;­"ï… àâ+ÕËd¥HÞÓh7؜ è;f#lm¬1¬wKì¹&æ|/ˆïæA€#yçF0¹;}DSóp:œœºþEò*¡|ùòQj^Yºt)¶oß®REOŸ> ‹(µAB@Ó" ³È«A"/ˆŒhœúCÿÆÇ7ž v]Í­¶ÈâB@蟋Œc»F IB;Œî/-ôM|*EòŠGq$OãÓìÙ³ááၔ)SâæÍ›X°`ŸÝ•ù…€BÀ„ è$òžøJͲ,òž™0 ÃwmŖSpu÷ÄÀ® °ãJNÃ7X,Bà·ØZâÜá ø#oz4©Uø·æ’“µàH^ñҕ£tO^X«J•*…©S§¢oߟ˜?>Š)¢Ýh9B! „Àhy\Y“÷äÕ(›…ªkŠÈ‹Î»hãÎóžqÏö}›âŸË¹¢ÓY[( ßööü=õª@Õ²¹£`Eó^b ‰Œ’eªDYuÍoiß¹sMš4ÁæÍ›Ñ¢E ѓ!„€B "ފ>ï±gëH,ÔIÇ50ëLӜ)Hä•6,‘Ç-ŒÚµk‡qãÆaéҥعs§i¯„€B R hy'NœÀœ{÷šðJjy‘Š>b“¹üWn>C⹁øU"6‰œ%„€ÁxòÄ w..Áº™Œ­Šbà” n$òÊT$ÙÖ«W:tÀèÑ£±|ùr,XÐT‹B@! 'áy©HäœÐ“2­®Ü^ŸÃ†çñ ñ‘.o']O“ã„€02lE¶dÏ0¬{5#³Üx͝Ÿù%Š—,‹2eÊ”—.]B·nÝT4o×®]jž ! „€¿"‘—’DÞK¡iŠ,ڇÀOÖHž­âØÅ3‹Ä! "›ÀÒÅ0Š{”)š-²§–ù~B`ÊFw”,UÎà"yln5ЧOtêÔ gϞEš4iä: ! „€ø)­"ïøñãª_OåÂI:®ˆú h^+ŠæY›…ßâ€0UÜ/ ð#š5jŠº…œLÕMƒõk2‰Œ².ò^°dÉÑãJ›2„€B@|K "/‰ŒwBЀxˆ‰q+^Ã×ÏqâÄEÁ‚¥ È:1EðÆÇŸ8h2$óFél.á9]Ž“Hä•/_¥Jö¿K.\ˆ›7o"A‚ȟ?¿ŠêÉB@!–€V‘wäÈ<}úU‹Ä‘g`÷Îç``ó¹ŒØñÏ*ê¥EŠU€Mùñ ÌJ1G]üœu)’§HƒÒej `7äH){ uá™Ç‹Èûüù3¬­­±{÷n̝;{÷îL 2—B@˜pˆŒx$òޛ€ËŠåƒ‰°ÿB \º|V–Vš\¥‘i9(Þ3 àtïNœØƒNG(o«ç{€„qüÍÀsÃrqÒú—É+oð‘<Š6dÈÅëÚµ+ž?®ªnÊB@! ! Uä>|Xmî®Z8.RÇ÷rHÀåm|,ùß+úýS€N•¹rÿa€VŠIB@üˆ@PP æÍµG»? y҄”ŠéŒäñ}V4˜²éÚçV¢D‰hX=|K|8=z€DŸ ! „€L@'‘Ç‘Œj…ã •ˆ<ƒ¿kÞùÚÀqµ+.\:‡Ž†Œœb 0W[6/B† YѳEdN.=H£ÿ> ‘GÕ5Iä;v cƌAŽ9B÷çE?G±@!  @8D^lyŸ†`³Ø …€ïǘ˜°ÂçÎ_@z1bÄfB@€ü³}’'K‚‰} !‘ô93ˆKc׺Uº&sK‘"æÏŸ¯Ÿž¯­ ! „€áŒäْÈójFBÀ?Ð 36zbûŽíh×n’$Mi$–‹™BÀt žž<ÂÞ=QªhØwΆX֟L×YcóÌ’DÞsT®\ŋ7ëûôéƒÌ™3cüøñž}û6’&•ýØFsñÄP! „€ häñfnWWWT- ©È'ÎzŒ‘>u@%þ>e‡9‹#_ŸâTŒN€¯! ! @PP.]<Š×Ï¡C‹ hU->h ˜ C"`a… khÿy•*F%òΞ=‹à?þ@öìÙѳgOC¢*¶! „@4ÐIä¹»»£r~K€L }›¢é:ExÙ O8ᔋWn†»»3jÔjAû€²Gx>9QðžuóNžÜ‹ÉS¡W)äN/ÅUÂG0ŠŽŽa «©’Ž‘‰<ŠÃmfΜ‰íÛ·cýúõQL–B@C& “È ‰äYS$ï£!û"¶ý‚ÀçÉpúŠ3¶íØëXñP¢d {Ùh¿ž¥pB ’ àΝ+žvõ4>ùáÏf•P·\"ØÅ’ö‘Œ:òŠ‹ãW=EõêÕQŽhÑț7 fTŽå#íç“!„@ø Œ~ýW/ŸÀƒא#F,yOŒRä?£F‚ÚŽiƒ D1.díCï~±í?ûéxzí?ßÂØôÅ~Í9¡>‡BãÿüŸ?ãspÈw>/˜Н`~]œF?óëêwú™þQ¯Ó¹ê5uNÈœ€OôÚ':îÓçO FЧOêxþ]}ÿô™^ Y—Ž ÒüΗÎ£ß?RÇ©/>æËÏϞ{àc@ Ƌƒþ|¿škêêî oŠ|Ûʼn…D 쐊>ôȖ!9reK‰ì™RÐëòaG˜[Îxތ±Ëï£V­ZF)òÖ­[þïõõë×Uñ•Œyóïµ˅€Bà· è,òª‘ÈK)"ﷁÓüüæ­ÞxúPÄŸ€ƒÔîç;_õ0ÌÜüîâöô^¢„vޟ/HýÌÇ~úòÄ¡µ%>’HŽ$ÑfI‚ê¿ï–ˆIﱉI’¿³XÓœÿ_ˆˆãßù{ˆÐ° y­èAžøCŊ’d_Gm¥ø}%Bԓ5>|øo)VPhÎQß¿œ“0^lx‘ÿ]ÆëkÖúOl…È7ü𥥥švoÖiô_)}¥ÄBD!˝/ÿS¿³_Ž ²“ç±"ñʜClýb'ŸËÇò9a|gÆþ|챥䙥Pšï,žèòõák¬á Ø|fì kï€æÂÍښ>øÞÿL>³pÖϰâ^#VC…\Oe?FüáÂ'š;ˆî)u(AO÷‘ù!b¿‡ÞWô³}¡Ž!cùœX1­”ðãsÔqê^üïç/ßÁÆ6&²Qš¥]ìXˆ;&âÚÙP$;¡v¡3Š{…ßV «8³ÌÉhEž‡‡‡j¡Ð¡C$Nœ\ŒE†B@˜/E^ՂɓƜæ{«üŸç$2Iñ—æg‚, é5Žº°ÀàÈJH&ä5þ¡ yE"Gù5!Q›ÿ"Fêuú=6=°³( *šh’?šQˆšä¹54ÇDZ¥â4ñ hJ©ð„a¿‡È<›XV𧈐ƒa"ŒÿÉÀh£F*!Ã∣JÄpä3D÷±HQKq“"1ITqJE2Yj~=êXµž&z²¶ŠžiDUˆX‰ˆ†Õ̖Wàï!*¢èØÁaåuC *œ!DZ°bqK?‡±Cãè÷ЈjØuŸDo¿Ìºþ!2ˆ2„@€°ŒC‘<'Ô®]… Žôé£bB® ÚŸ}{lÞŒGŠ%e ! „€0Pº‹Œ@ªD¿~6PÅ,! „€¿$`a£—ÞAݺuUcqc£GV‚8::ÒþQØÚÚ£b³B@D­"oÿþýÔDÛUò&‘'M|#¹L!„€†F€EÞ’Ûš_¿> *dhÖéd·RèÓ§R§NV­Z¡aÆ:' ! „€éÐ*òB ¯`‘gzÄ#! „€°ŠG"ï–Q‹<ŸŠ‰%Âäɓ©¥ÇUiS†B@˜'­"/4’—/©Ë^óŒMÄk! „€‰°Ž‡E7Tô«`Á‚FëlëÖ­•ý‹/Šþ÷Ö1\! ~@8D^ ‰Œâ2„€B@˜ë$ò®£Q£F(P€6¡éØŸ};8msÕªUª1z²dɌÔ1[! ~‡@8D^‰|®®®š’Ç)“Ä2GFâ³B@˜:˜I1bî9ÕDlRbØÌøóÏ?‘3gN“ð;A‚hÜž1 *ôö®0ªb‹žBBBè„Þ{ï]@QŠ"(‚ ‚¥wQ€ƒ(H€i"AºôÞ{ BHBŸ3›–ÈnØ$»›;þý»y;åΙ÷–9sÚ·oïs’I‚€ X†€$ïŸ"yޖõ*µA@GBÀ3“"y›Ñ²eK(PÀ‘$¡¬:u‚››1}út§˜“LBAÀ2,'yE1eœJ-A@AÀpñʬÌ5·h’—/_>’üÅ¢4W¯^ÅÞœ{%)ºS¬šLB˰‚äÝS$/¹å=KMA@AÀApñʂ^#ÿÄ矎Œyó:ˆÔ/såʕZƒ·jÕ*„……9Ŝd‚€ –!#É[»v-®\¹‚ÚEIò|-ëUj ‚€ „€‹WVEòÖã‹/Ÿ@žM›69ÍŒd"‚€ /GÀ2’wù²òÉóMžÜM‚€ N‰€‹wNtö;:w9s:Í—-[†3f`˖-pšyÉDA@^‘ä­[·—.^À[ÅT 1הûIAÀHF’·]»vEŽ9œf†/^Äk¯œŠóåmذÁ©¬Ó,’LD8@ FMIÞõkWQ£àm!yq°Ò¥ ‚@Â#à❠ݟ]nݺ!{öì / %H—.ŸÒ¬Y34hÐÀ†=KW‚€ öŠ@Œ$ﯿþ¹³gu …L~xÅ^RäA@xŒs£ÛÐeèÑ£²eËö Ù_ÓÚµk#mÚŽ(P è£'EAÀùˆ‘äisÍ çQ»Ø}!yÎ?È A@H”žxçQæšËÑœ{wd͚թ0})S&§šãÞœ{Ѻukœ;w÷îÝsª¹ÉdA@b©É[¿~=.œ?£¢k>’'w‘ ‚€S"àâ“_‘ŒÅNIòáçç§¢:téÓ§wÊ5”I ‚€ « жz\ŸGÈ¥Þoߺ Ÿä)P€H9dϑ)}\+?òeŒ÷0‹0’Jö‡€KòèØ¡L’!Cûð%ʒ%‹ÖPŽ3UªTyÅÞ€¹ ‚€œ# $ÏÞW(åãyæÒ“X»åNžœŽŽé2+â–ŸžÈî÷~é|M›cU/,ÌŽ9ãXmˆ¹©&™ }bÚ4ëM²Ú+‡…E~ÏvŒNâÂzÜ8³žé:I[hšª¯7Ôªž»ê/„sYÐ× b p1ˆ„‡‡»îïEM5amxx$Aؓ0-ë“'®Št˜Z°ÏΧ®˜®‘Œrnäeý cÄ»~Sÿ…Ã]§Š¶úŠðª±BBBu_‘}šÏI’žé9Ÿš„†¹),ŒÁ”îªï'Ož«nšûJ‚Ј18?^'ŠÜ&2ÄÏsÔßFLÖ荧|а‡‡«1ˆ­©RÄÿž&Šô„EŒoàQ+‰;çÑ"²±©÷">˜H¶"íUôžš{äé6¹Ší‘í Ï.ÜÕžŒÇ"I=ëi¢o"øü? žªŒ`ÄÁšg: Pl¯Èëšÿƒª©\x˜ Lïÿù›‡ ªN@€?(¹Ÿàþ}€I㇂…J¡B…šÈ•þ*ä¹üÂõ•/ì—äÑ¡ß| 8Ð)5]5kÖT¿KhÔšZµje¿ !’ ‚€ ؁IÞÆqæÔQŒUuÙP·Ò©¯š}*âI&«K=2äÐÌÑDD#ž”©ÎS²£Mô𐈘(›‰|šHè3BjŽ2‘MÓ_‘yFX#ˆTÄ÷šÐ˜×ׄë-ÖßGj5Ÿ-Só¿MÈ“„ÈøÞ GÑÏÊy¯9ŒGŽìÁ¥‹§Qåµ:hR_>!z·à.Ÿ…Сï<§%y;vÄå˗‘?~ >ÜáÖGA@°Iޟþ‰ógOɳW‡©œótVüºæ_ìÛ· ¶AšŽ~#»*ØÜÃêU ޶pÌ7õ‘3œ¿=‰'²Ä€€‹oaŽÿf˜n€ÉÝ­Lœ8kÖ¬ÑÚŒ¥K—:Ûôd>‚€ Qˆ‘ämذAkòê” Mž“Ý>ô±úú‡+ØàŽiû“ÍNŠ#$ ›7­ÄÕ+ç1{ø[Håý8a„Q­GÀGiòúÍŐ!Ctâpg+ô¯§)*£k9rÄÙŠ'óA@°–äýõ×_8}òˆ<'Œu殟ŽùËâӖ=pv2%A áغu5®\s§Ÿ+ IDAT:ù£Þ„OR“oŠ;GÀ·:|3ÛiIÞ¥K—P¹re\œzõ?~ŸvŸ2"ž„„„ S§Nøê«¯3gÎȖÆ C™2eðæ›oZћTGF FMIÞ©‡P·Tšhòy¥£ÈþàaÞïºUªœ‡r®¹sçÖ…žþR‰õH«kÙ,c$y<õ9~dŸÒä ɳ Rû¯uüü}tºµkˆÌYžÙìÛ¿ä"¡ àX8°üÙ# ɳó¥ ó.‚ÎýgƒŸK©R9§Õ Í÷víÚ¥ÉO·nÝì|E^MŒ6mÚàÇÄ7ß|ƒÒ¥KãË/¿Ä™3g0eÊŽmÛöÕ:·ãÖçϟןxƒ Bÿþý#%͑#råʺàHI$ÖgàUW—¹‰øá4iÒ~~Žq>F’·yófå“w@¥PŸŒWœqì¥ýü?ü1緝øø“n:µA@ˆ;Fì‰•?~L©ƒânéù•ó)ŠÎýf95É?~<~ùåTšP#GŽ|eÌbÓÁãÇáææçÿöŒþúë8}ú4.\žæðô÷÷×ä–ד'OÆçŸñíŸ çLÓÌÑ£G£{÷î‘ò҄“æº+V¬°û98»€ò Ø÷ 38UæÌ™Ñ¹sgüïÿ³oac.F’ÇÄ£‡v£nép1×tè¥~&|ß©·±wÿ>4ÿއ“ÌHŠ!Ø/“' BßvUðf¥ôö+€H†'ÞEÑ¥ÿ,|÷ÝwH™2¥S"òÛo¿i>àX°`Íçøûï¿#C† :ŠctåàÁƒxíµ×ôéøÉ“'áââòÊ20—/ýŽŸþúk|ú駑ý(P@›ÝîØ±#òZpp0Þzë-ððšd§^œz¯<ŸµP;@9ß~ûmk›ZTÿèÑ£(\ž°ÖXšÙôéÓë ; .Žš©;ä° 7žÜ¿üMJ‘"…eâ©Öŋu`*þV0·š#‹I^RáȒÑ9MXy­•ýò]_tývîâ³Vœ­m.õAÀJŠMŠê%=1 sm+[JõøD 4YQth2×tV’·{÷n4oÞ\“,úÛÛ²À•(Q>>> É`tJ9öܹsux’i[’™víÚiÍàÚµkA  çHÍUÔM7–$€ôQÛºu«-D°ª:uêÀÓÓSonã¢ë@œ?ùä“È!h‚ÜšQ#mÂ*%ngÀ2\ÃÂÂŽß(5fµk×Ö_©Ý·—röìYýû5kVˆ‹è U<œq€4$1’<þýwÞ.õTHžœÜ¯ ÇáKéñõðŸUáøèã.¯ÐSü5åi¯g27žº¹ŸpÐP!…·/n_€Dg*×®]Äúu¿èHšI’x8ÓÔÅ\.˜ˆobDŸÅ|u’!ŠäuW$äÃÞN–m…)Ã듈q~Ô€Ù²\Ÿ| ÓÿèÑ#ѲAƒÏuϱéF-÷4¡ŽUY¹r%/^¬Í8‡…iU“Ä/jéС˜Onúôé¶Áâ~HŽöï߯7ŽqQþùç”/_^“HóÀ3ɒ%}ŽÝü,.0³UŸò XŽä7Žß͘1Cª„,üñ6lØ šŽ;†#GŽüGÎÐj ¡LÝcƒOŒ$oÛ¶m8Žê–q’„í¬ 5yýþ· Ož NݏìLºÿŠãêê‚ìyS"©—ûKe=pìÊ.€°(èºSœ;ÖaÒÄþë‡ÂÇA`jòí±PKÇuª àsÛ¢E T¬X%K–Ô‡X|Žb[èÜ©S'Т‚–e˖ÅûᅬŠM›Æ¶ËÛÅHòhÏþïÞmš#$/F0¡Â|5f7BÃBQ·®ý‡’N‘Ú³%Zƒä¥J™·o>t*¢·}Û˜üðCM¢X8¿ž={¢P¡BzÃO_Dó`c¬û믿êMM;šýqîÝ»æ N›6mÌ7ªÁM"5eL_@M! ÍF©% •…‘=©AäXŕä–IsŠAhذ!8÷èŠ6ŸjôX8ŽE’MÙ¢–={öhÈ5c=ú 2Ç5,{÷î՟éëÇ92 ׋ĝZÑšåðáÃà‹šT¶yQ±dí-žšâÁû'ºÂûí³Ï>Óž÷5œÔ.¿šTªTIϑŸŒÖ”Äü ðžc~FÞ¯ÆZ%Ož\ßwÑÝ{ÑaËû‚ &æu¬\¹òsZŽðY É$ïÉ}ûö¡Y³fz úCF}V)“~šŒ‡i=Àß Ö­[?—&'((Hí‡ë‚Ï=¿xßҟ•÷Mp_TxÃC%þŽÄt`ÃÀOåʕÓÁ ¢þŸýôÓOz,”‡€xÒ€IžsçŽ> àá ý™­-‘Œ»7£^9wÑäY‹®Ö÷ôD·û•&Ï1H^¿dH—Ñ;F$ÍI+Û;Ñ£Oä·CÛ£ñ‡íÔ©tµ—ÎoÛÖ5˜2yzõ«’ùVŒ ©`_ü±fŠg»‚î­ßŽ/ÁDšçJZ_«7ÂÆ?¶Î7 4+ã);ɏ- 7vÜDqcróæÍH¿<š7Q»Çš–_|ñEä ìÆÍI ƒ€°= IŸ|ù4€Ÿ OŒéëG²ÄµoK–,Ñ䐛+nú8ýñHÚhREs°š…NB’$n8I@ž¡b //¯ÈêQ¢–XYJòÚ·o¯çÈÍ$}w( $7ªÜ޲tíÚUAnd¹‰åø<Ý'ÁâF޲…8’Bæ÷cñööÖmHތ$ïQç8gÎ؅$Ë XF ‰‰'þ‡”1 'Sk°OFà$n¡¡¡hÕªU€ÿµŠÜ$SãAsX#É: 3ÍÚ ’MÒDÈ5`áÚp£jŸæ†Œ–¬œ¥÷æõë×µf—ióBRLLje87ÞG,ŒïHÌ ‰9û04:$+†§¥²$æg€š.à œ~²ÔÜñyÎ4›8ñ^%A2ž=âÏgzìØ±`R8˜ â}S­Z5Œ3FkÀxxb<ëÔº‘,åÖ­[Új€¿!,ôæX$qôYÎoØhKrÏ瞿C/*|^Hòh"Íß(óò÷ßëçßÑÇ{ÔšQú9ãaM˙æ„Ï%}d9_>÷óæÍÓŒçh@‹ êp Ê}àÀýÛhM’g ZNR·Å€£Ê|#\™kƝŠØVP$ïiøSœ8ñ¹“:žšˆ¯éáë“ QIǏ-ÑãÉÏ ­õX µF‰’•Ôf#ö*úè°Ø³{ƍý Ÿ4ïŠNŒ?|)\[6¯ÂŽ©Cзßd(XÒVÐJ?ñ„À_þ‚|~çÑ«í[ñ4¢ ‚’UšŒÙZ‹dlcӏœ·¡#7$^ÜÛºÁUžaaâqn޹¡áŽ„‰D……'äUªTфb„ zCÄÍ5#@nߟ]oÀi"ErHY¹Ib2÷š…æ›4Ǜ?ŸÖޱð7œA'jšž™£ùç}üøqM*IÆž¥æäÑŒs ‰(ÍO-)ܬÑ獛ÃÕ«WëÓw’ŽbŊiâʍ 5f îÃ}úõëkÅB-7ÉÜ\òßšr‘ÌQóзo_m~J>n9óþEœW@44 3Ž¡œ35™³gÏ~ÎdŽŸP웛Unz«W¯®7ÌÔxrcNRÇB9§©S§jÒI"Ïà5Ôr20EŸ>}tª ’YΓA+¹”sà&œÁ5ž)' æw–®œ%ž¿¬ç >‰ ˆ¹¶6ºvŒ/žœ5°Œ‡bcž—XŸ>£|^ùW­ZU›Ÿó=ºÂƒ Þç|Ÿøœñw€Úskøðžã¯Óº‚}ñþ€vžæÚlÃ(¹$>ô=å3ÌC!þðp†ÄŸõùÜóàŽš\¶%¡bj’?tœšÐt—šœè‹ØÆŸ÷ŸoãwÍèÏ8ð¡ŒÄ€d—÷"I_ÔèÃüœâÁI¿ãóʃþ®‘ ò@Š¿|†¬Ío#É£úuïÎ J“—Y3¥~ÕgNÚÛŸ :¡þ ÅÛu‡ä¶‡A ‹DÁ·“%ó‚»z°?…R…ó!u”PŒ&¢wMýèXüõë—гû3{|O¯d(\š Š+"EË©à^ÝAxãÆå˜1ý;tìĈæª$Q†¹6ך‡<Œ1/Ô`ó^¢Y$&øüò9æáŸ ó@,ÆaM4Ù7É !žáïï-’>‘ô/^\ûTR£ÌÃj¥B .,X ÝÚÒ¬$ÚÀèŠIÕü91êñ™â¡‰É ÿ=¡y0MØç‹ Ÿgj29wjü9ޟ<âïÍQ)¿5Å"’·o×Ô-+$Ï`í¹nçáGqËÿ1Þy÷YN!{•×Ü\388D‘ŒçmîœÔ‰‹ ÎrêÂe$M⎜Y2« Âó³¹tîîšTÿ––_™†eKM&2QKöìù4A®P±V¬NùØÉÓâE“,ÒÎý¹~ fý4#G-FÆLÙU۹رý|Þ®¿ŠV—ßÒ)Y]ïĉƒ2èseÒU}úþٞ?¬ÓŠ QæGŠü1$€Žp/Y €ìÞŸéÉûºƒu?Î6ÞỡÕÁœûðàác‡>QTaJCòT™œ‡©Ïáj3îŸdžHî­^>I‘Ìëù@–èQ œ‡ÎÒDĝFžÐS@SLΕPSÇM# -7ǔ›<܍Fú ä…fÅ$&ææ€$RܲµQ,ÜpëE‹ió8ƒ“€1× y ΅Xš/®ƒÉPSB"jä$qä5Ê˱hž5ª' !7çô¥¢7Ÿ–®œ¥Ø“ÔòxQ!9%FÔÚòÞâáçý²Â5äZ8Xk֜XŸsy4×<|êìsš< Ÿ#s&€ôõApH(.\œ®ŽNñTýg^Œ]|öغ,.œÂ7_7S'›é0ìû¹Êà:©T"‡í©“‡Ž&4CÆlø²÷8e6“Éj̟€Õ«æcԘ_bÔ þñÇb̛3ã'¬@ê4é1qB_ìüûOuÂ쇁ƒg(- `­K~Ž¥¿Í@µêõÑŠí7º9éÈ`0IÑüÓšZ­®:U³_keqäúÿl_ˆ,ŸWУ­äÉ3ÖñöÝžr]™°Ýž‡ë7pý–éuíæ=­™ßä*EìBBžÀ;YR͟¯ÜU›J}ŠëŠRªžóåüñ((k²—4©;òåôCŸ\ô{ù¹P®„‰`Œšä}óý<ÒÜ?ˑïœèd§VŒ›%n”š5Š‹bá 6ÉOÛiNiš5ò„AnŠè_GBCó,žTSÃdjúžá!#!‹®PsD7‘†¿˜Aü^túÍÃ*niÞE“1ž€scJ’OÂbF—š ššq£IM؋r-RãÀ  ,ÔäŸù7ýzža$)æ\¹ùePjš!¡F‚›KšHÒ¬“ã/’RãžåýËMš9¹5‚Ð›húÑь‘Mj¬†&—4ëäšE5~󩕣Ùµ FŠ ~ÇuŠ–‘Ė䕘ssMó9šÆqSM9øïƒÀp>Ö¬œ¥÷æ¬Y³ôŒx@Ó8’Oj„8®aT“Kú+’8ä“°>HnY?jÄVKå0¯—ŸΟ&Ä|®HŒXxA¿L>c$2Ôêñþeá³OsJþFÐÜòÝwßÕ×yÿñ7€hîð€€Ï$BØŸsjØ©µ54í$d™3gÖÏ?98>הüLí*ͳi6N²Æ{™¿?¬Ïþ¢Dæ%a7ž-zP>ƒ|ø{Åg‡C’W~Çu§¯! ï#ÊE2k|â3Ï7©µç¡5ø<Ø¢Š‘}PŠM’ÔŒMßIçpääU¥yæo¯SŠI“÷"¹¹ ôLjú‘9{ü.B?3óŽd®GŽìÁwßvD­7ßǧ-ž?Í ~Œ­[VaÁüñêá÷Ɨ_ýOÀ>‹îfIÿԄmQ}LûñOõãerQù}å\,ZøŠN[o_õã‚Í›VjÒIVªŽõ—,‘qö¬Q*?߯ø°IÔ§™n2göh¬[û‹úáñÔóΟ¿ž%]%ê:;·.@Šä—Ñ»Ýۉ‡û‚púÂMœœx Ž\ÄÉó7qáÒmMênû?Ôä,}_ë 5rƒC‘;Gz\ºzWiã<”v.©&l>ÞIQ$œS}±®azÍÜP¥Õ»}÷¡ÖôÝ»€ÚšvªMöÌi*…7<’˜XçðÉ+hP»$>¬W¯•û¯óúCâøjèOz£jDtÆãfŠbš3›-[ϓ3cSB- 7ú v`L V‰§ðQÍž¢Êb˜ R+G‚]1‚1˜›/rƒDŸœE”d?ôË£©dÔBm7…ÖnH©EäF–Á8/TjÐ8w#Ù3ýìHj©Ù é1'FpSj8)¿çАd”ÿ®‘šqH“Sn†©© "É7ÍÜÓ‘§þÔ(°0xƒ°˜›ŠrƒÊ '7¡/‹²JÍÉ5aÜT›€p nj¹æÔÔšAÞÛô¥FŽæÈÔøñ^å}Ïß(lðÀ‹¿ûæÑny B-;M;iMÀÃÊFsQ+báoM‘IøxÃÃxðÙ§6ŽmøŒRvã¹1æõ~åÜ ˆŸ·<„³U‰‘äi&­?Ô-çlêN)ŽÀžy§±aç%• Ýt¢gÏÅ\“wèä™ÿ˜kŸHv7õƒQ$.žºžÆŠä­ýãg̝3íÚDå*ÿõ¥¢&oÞÜq )e‰’•ѳ—é¡·ŽŒÕÿ܉ÙsM×^V~ýeª2ý ³æl³È<ôìÙcžtñ4ÒûeV$¬D¬“ÿ0¡Ÿ:E[Õsù²ŸðËÏSušî=F x‰Ø,q®(¿ˆ1MÝ)Ÿÿ{Ë|­ÉûÒÉHIَœ§±sÿœu*o€Måƒ4)ÕK}&A{•Âq/\¹ƒãg®ã„zñýÜ¥[šlÖš\P™szj™®*²9ò›_iúŒò0‰"yß:?É£V‡>sÔq£W…'ñ<Õ§f(j„:Ãdž'ã$c/ t͉7ÍFJ€š2sSÈ  yn8š òtÜ0ýŒn®Ô(rSÅÍû¡¯Ç$ѳ¶P+A-I7–F¡vˆDŒ§ô<±'™£¿MœÌ µÜüÒ‡›I’VÃ܍ڊþýû?çïG 5ôab°jöHÄhFƹ%( žp£Í( §á'GâLý²Â5âÁGTü)/µgÜÈQ(©$A% ¥F‡rQ£GòK²hÍÚ[‹¿œÕOŒÏI ¥PSNí ›6®Pa°›"GÎüJÕî¡~€®(Ӗ žvõ‚ú:©~l‚Õ?|ÉЭûp.RV™÷\ÅQ¥,[¶ºÖžœ¬ôëÛ7US§¯‹̹ÊTó¯ ËðÓìÍ/­ûøñ#̙5Zk’7oQM@c’'ºŽ‡)M&ç3á‡ß•=ü!Lø_]í‹v¢%ŸFþþ·ðے±G¥^yú4\«iÒŽ£: 6mš Ãè"‹Ò÷ðÀþøü‹~(XèYÞªA²ã ‡wÎ@ÚäèÖº–Kœh$r{þ=ûÎàà±Ë8rÊDäš9£¹ti’#mjdöK¥Ì#ýP¬@uÀ’YkÓÒ+bgåüåÛX±þŽ*"zN}~»zQL[°Ö/‹]MŸ9÷݋£Ï°Ÿô Ž-̵ìaÞÑÉ@À 9ɐaV²2I 5v<Ñ7/ÜRCGwn‚èÿÆÓunÆ섧íôíâæ‹›jp- €ò*s¡Í%¹!}¿Lš‰‘PsÅyh‘t‘€ÑôEù׈‰æÝÒ¹P^ÃÿŽmšYãfÚÜċëÎÍ5sr±Ð·ˆ›JnŠIiŸFBN“3bÀ@&”—ÀÔ’D’(Óì™fßÔ:’¬’$RñF £¥Xb$yìp›ÚìŸSÁKH^BþZØpì9+.àçµgññ'Ž£É Wdáà±Ó/LvúëϟWe‰ ÉÐï3u }~ú¢åÌUP™CÅJo*µŒÉdÒT@”µhúQGÔ­÷És"=~„Ÿ}š£µòmc»ÖŸœ®ýØŸúzŒ:]œ©5[Ԑ1° ‰™ybÍiS‡bÿŸm˜<õY˜oj©©3"}’à‘”U2ӄŽX± ZþÛ·¯áÝ-ðAcëMs{öhŒ*Òè€A?jÓÕàà û:~l?Fì¡Nì©)_˜? | ýGŒ\šçáº:²û'€Hzœ<Ó£¹ IDAT>·Ïèšôg;¥Ì)÷:ÝŠÐ;uMkŸîÞ TŸ®OŽï›Ÿ"r™3ŠB– ©P¬`VT(™ •ËäÑŸrŽVþÜv}G-E¥ÒyP(oFÌYò7¶üÒ’”Pæš3ŽVÂð'q޹Y"/ Mš€`ùòå–4‰“:4€FÑŒÀß<óȆ”~rԊŇù,7`Ü\QÃežk+N&o'r3N“O#A³±Ð€›Ÿv†Ÿ£µbŸTôC4ŒbokoíŒlUßÞp°Çg€‡?Ô®GÍih«5xY?ü=¢™Ž¹æ..Çåx†&Ôø-ŒúL2j'ÁŒÜ”1É#ÉcN–m-Ç;“Ià•˜Ðtï¯9ƒéKŽ+'î¯ì^â„Ðäñ€±M«7ŽŠ.K–\ȧüβfÍ­LrÀ/Cu“þ9f€øUïqùÒôVŸjL·`^vîüÇ÷E£÷Û ^ýfhùiô¹c؆cöVäÏšÂ@+$lcÇýÙ%ÇòóË¢µˆ,Á$ìÜõ;uú“F|Ý@÷®PŸB Žï0ȪµW©*Z~ZM>s“ï®ßK—®Š.ÝŸ¡ù'ƒÕ0'ë2 ËkUëèM âɓÿbè°Ù:蠁mqáü ü8sãs}ÑÏpúŽo•c>]לèZ%ŒU>°}ÒøÜ׊À&T¡ãÉs7ôëÔÙضçNœœ®ƒŸ?Ñi]™Ë”> ç˄Œ9üP±tnTUŸkö¢³5vË×íGÛ¯ç`øWÊ7mâJìÚŒý†Ïց0 'y[iýñ„šZ*nžšñIèBŸú“Ñď¿ôm¡FšFúÅW1üËèÏÃüÄRx?ÐčZ;j iZjøKñ º –bcøD£¶³—µ·t>qUÏ^p°Çg€Zà·ß~[›v&–ÂCšPӊÑh ˆ‘^$ÈZ3ÎIÕö›”ßQƒJ>¢És’;엵ç0eñaŽnc2¿³çbÊ–{]a²ŽŽmS A1múzx%3%ü5ŠaúøuŸ š4$Ä±ö[‘Giïxjúó¢ÉÊŒg‹òŸ(„AJÓÅBÿœ;*ºç0ùÏ(Ô4>RcœXÙŸ]uÚí…ïG,P& ÏòYž>}DGáŽ6' b—NŠHW,ÔÀõí7IËþ¢2lhå{³Wcy­j]e¢“Y›y2B' ۄVj?<ÏÐ'!˜ 6ÖF!±î÷M mKŒhþê,eÿ֩Ȝöº|öò|ˆ¶˜/5pÔʝVdîŽzߣŽs €ÂÀ# fÂt|eɘódDù’9Q±TQÄÎYÉÜËpe”Ϻ-Ç£G›7Ѳçl|¢Ž8 ›ȶX¿øêƒæ€Ôæ1 Šô-cžsšV:ËS|¯-ýhžgä €MÎ^–ã0Ÿe”ñ^Œ@B?4&á%©ãAÿŠy$Í^{õê%K b$yLù— Bñn¥äȞE¯Äc»k²qÇq žvm?7…Å·çb®É{¬òä‘ XR^%ºæ±£ûðíÐö:Þǟt±d8]§2Ç£Ù%Í*̓ŠlÛºF§`1j‘&?$y<µŽšB]ÚŽª¡#hNžºV¢ŠÀ÷ßuÆÝ;7u[£˜·ü)*â&¿ëý¥Éwpè·¶9í2rä™Ožþ‡ýL6’èÁ;0rDwmŠJ‚È—Qš ü¬õWÊ<¬žŸDýàÁ=叞>r3Å(žŒæ› 6/PUÜœy2Рމ¹fšÊwA¥8£ÈÜ’9EàHæ˜Bä¯íǑÂ×KE”t×f–ô›Ë™5-**ÓÊ¢³( ]f†@hý÷Fø°ÃTŒ^³.:t€}4ŒHˆ tËÄù°ÔqEí™D挲ud»Ä„-SÐ/Q ™Üš1ˆ'#žr³þT‰ ßžž«‘÷-!ŸP“n˜Ló3µWFЕžÆÀû‘ä1Ä†5‹…ä9ÑêÓ'e،ÓhÕúëXG^Œ/8ÌIÞÃÀ ÿäÉ{‘nJóäãí¥¿¶Ö'o×Î ˜0þþúm|Ñ~€ÅS3ºöí݊ڵGµY·ög…󊜚"­õPAPJªhœƒ•É"M›4í Í7ÂÔ SUzúý‘ä1UÁˆáÝpFiä̃ŽÌøñ;lTfÔ_3Qiý £S‡zÚ­ÐàœÏ^y]7n\ŽÓMZLžj'OžR…Ûö×&¢ÿšÿ6/F šï†ÏW&VÙÔÉíF\Tæ›)U¿* §á;È6FÔΚµé¹ïÙœI¥£˜ 1êóÍ(TžŽÅ˜;BÅ·Cšä¡èi…OÞ)¥‰[²f/nÜŸ¯ ۡ㗵Ÿ5r¹²¥Ó‰ÀÕÊèüp7ï樂Ï%&ùš©€Ï¡¥ÑŠcêOŸA@°?b$ytÌ^þËt4¬šF‡ã–âøL_ž‡Ï†¢Â]22‡F`ÑÂðûʹ=öW¹Ó˵ã•Y« º¶ªåŒÓsš9ÝxZߎž‰'ê9ñߟ/ŸøB‡~_ºt©Ó̓iÕª•6×’çTË*“Aà9b$ygΜÁR• ùœªi…ä9ÉÍ3i®òºç‚|e:9ɌdŽˆS&tîøŽ&wÌ¿ç¬åÆÑ1zjBòì{…¯…Ç÷ãæhsM£4iÒD‡„_Žh‘Öì9Ka³iÓŠEF@t–yÉ<A@ž!#É£ãù/ó&¢Qõt:?“ÇG ÇÐÅxšUÞ²Ÿ<ÇG[fð"˜F‚IÝ?iÖoœÝÄi:žy NV>¶¿óÎÑïrHQŒš8ãǏœ1/£m’è9Kiߟ=&Ož,$ÏYTæ!‚@4ÄHòΟ?E³Æáý7ü„ä9É-Ôû»_ÉsA…ZƒœdF2 GD`¬J±W¥‘4xrç)ìˆS°Hæ K»«ÄäÑ닷,ª/•Ë¡Å0Z‘<]1/LлmÛ6m²™9sÌÑmFzëFíÔ©“6K¥¹Šä…³;©-‚€£ #É»páü4Œ‘AHž£¬j rN™· ‚­„c^qØeQ4 Îé7iʝ<Þ‹wÒP,˜Ù }:ÔE±‚Îésè,ëv>š0&Lûcǎ}nJëׯG›6m@bÄ0ãÎP˜l˜d–)\\]]aJ2A@(ÄHò.]º„9ÓGàڙ„ä9Éí3û—mžu÷!2ëå$3’i8"[·¬Â•+çЀiGGß"™ƒïÇ¡ÝóÐéÓ7#«˜»[ZU:÷š~øñWŒcò¡4/éÓ§GƌUzƒ $m‡e¢aΓÉЙËRŠ ‚€ó!#É»rå fMýkdBîì靁D8£ ۏá×Õ{ðþGpóŸó%úM„K*S¶S.û×.ÄÈ>ÀÝ]6ÓvºLZ¬3…0õ§ß0jÔšÿˆ9pà@í«Çé¹rå²çiX$[ïÞœut͛7oZT_* ‚€ 81’Œk×®)MÞ÷*ð }ò„ä9ÞÿWâó—ná«á¿¡oï~8tÙÏŠ$sìÇƒprߏȑÁŸ\Íî䁞GàôÃB˜6+z’GrW·n]ôë×;:Ÿæ™š<úä=~üXnA@'E F’wãÆ L?MjeAžBòœå>øšÓ4|Ý¡Î=ª‰Àà$Î2-™‡ `7ìݳ™|N¡T_T¯XÀnäA¢Gàԃ‚˜1w9FŒmÔ¬Y˖-sxé_Èdè÷îÝsø¹ÈA@¢G F’wëÖ-LÓMkg’çDwÑÔùŠà+Ÿ6ýÍéD3“© Àƒ÷°oïVäIsí>©ïdI^(‘ड़(€Y VbøðáÑÖ{÷Ýw±yóf§ FM›6Õs¹zõªÜ‚€ NŠ@Œ$ïΝ;˜0²>z+»<'» ¶ýcúˆKepùnr'›LGH8–-‰r¥Ë @ºQ÷â 'ˆŒl1Çü `ÞÏ«ðÝwßEۆš¯¡C‡bÕªUȓ'ÅýÚcÅ·ß~§OŸVÑmOÙ£x"“ ‚€ ˆ‘äùûûcÜ÷_*’—ysŠÿ– 0·›.nß}€Öœgcö˜vX¬(BÃ$0„Ý,Žâ<}ú«W-@ÕjõqtïBŒûº’CÎ#1 }ôn>,úm&rÑjŸ5j€–Ô¯_ß¡!ª\¹2=z„ýû÷;ôyu߬„w/AÿŽÕááá?ƒË(¯ŒÀáÛù°xéZ|ûí·ÑöEׅìÙ³ëï™gΑKñâő2eJm²)EAÀ9ˆ‘ä=|øc†õ@ãšY‘/WçD!‘ÏŠÚ‡~£—âϝwP pd˞¹sRTÏA†òðé~žªÏlÇ6üŠç§ÛE|6ú ÓãšÆ{6Ÿ!ÛèFÏŸgÿr…_©ïtßÏä׌k2›zW ô—º¡©šÙœ\Œ¯¶ŒÀ~՛‹‹«K}0:W—ÕgW“®ùÿõõuÓU£o7•ÙÔ¥éÿÔnnî?ӟz0ÝÊU¿³­éÿbݰ°'ŠkºÕÞÕÍÔ>òšj«®Ý۪׮±o%¿îÙš£æÉºúzÄgS~/¶øN]çgó¿Y—³®é;·gòD ð*oàâÅSžqý22€O‰â9ƒTʄãhÝŽ*Œ<=^¥kiÏü{+/–¬øC† yáÈ9rä@50cƌx–ζÃåΝ… Ɗ+lÛ±ô&‚€ `7ÄHò1¬G4«›[HžÝ,[ÜrúrŸýñ¬ÞŽÞó¿¯d>ðööћw//o$÷M¥7í$ኙHT˜úÛDœÈžšëOMßq“¬ÉF8ɕÞð»ªþBMýh²e"o&âe"Q®Šp„…™˜¿1‹2äîž¡OB"Ÿ7mô)‹Q86Iœ&æ„$‚4˜6ÿ$KŠAø·~øÏ=I„S†‚Âënî$=ªO³Ïž¡º£l”ŸM)çE9žª¿5qÒßE¡Ù§«"".ª~ØE–"ˆ’ž„ŒÏ!-4!‘$‰‡ÆÁÄT9^ç÷j܈5Ñí"f$jMTýˆ‹&kÄôÑԏîƒ}E¬›A:YCærmtͺI’$ÅÊb¢gŠ5Q퍹˜Šdê“ÅÃÃCË¢±0䈘°®!š©ZsÒ¯>ë5æEf±eÿ¬ÏûÐÝ]áü8ò$Ùcƒ’ô%ñHj’QËì…)ïO®‡A MDÑ]¯Ïý{w¬îkæœóööE2/OäΆdn·Q¶xT¯ßŠDÒ ù‡ž™Ë~ÿ ƒ~á(Ù²eCŊ±xñâ8”$î»fb÷7ß|³gώûÁdA@A F’„Á}ŸÀ§õó ÉK%J˜Aƒ‡àÔ¹ž~ë>vî?ƒÁș5­ÚèªÍ®Úèºó=ⳛµ>jsì®4*z3lÔ!1rSõù=¯¹è17ÌêóZ’ ðq2]ÇŽ™ŠfÆD  ™AØôg­é1mþ 2e ãï!w"F$ q_B”Ÿ£ WÜ1‚ š[<ûVšWCÓj®ù4}þ¯FÓ€õ€ÖD(ŸõA5#5·ÏHçsu"5ÚU³¿#ûÔZ\4i^MÚV’<ÓA…úþDkqYçIš:|Pߑȇ)Ùxžah|õá…>ØÃíÛבTìÙó!Š@ʆÌ~Þȑ%»x»Óm?ÐÞk¹°jí0ñù‹JR>yùQ(ofçDAf%‚€ šØ~.+¶ïÚÿRM5_Y²dÁʕ+«¥K—¢qãÆU†€‚€ 8/‘Œ¯º|ŒŠuò¢hþ,΋„ÌLA Ñ"°õlìÜ}œ{÷Žƒ{÷îi-^—.]0lØ0‡Å‰e&Mš€¢ÄÞvØ9ˆà‚€ 1#`ÉëÛœ9Þ¯™Å e¹G©!‚€ 8›NgÆÞý‡Ñ«W¯h%ßžq#š7o®¿ïܹ³ƒÍ|ðŽ=êðBvDpA@â ‹H^¿ÍñNõl(]4G<‰%€ ñ‡ÀƓ™pàÐ1ôèÑ#ÚAǏ‘#GbÞŒyšV­Zü f㑘"}úôXœzµ{–îA@ì ‹H^ÿ^Ÿ¢ÞkYPŠXN{’]dA@l‚À_Šä9vJ›cFWêÔ©ƒÍ›7ãêÕ«H‘"…MÆLˆN2eÊ€S'H"ô„@_ÆA þ°ˆä íój”Í€ò%sşd2’ ‚€ O¬?žǎŸF×®]ÿ3b`` Ö~U¯^«V­Š'‰âf///Lž<-Zވ›€WA@»@À2’÷õgšV:=*—ÉcB‹‚€ ‚€-X{8=N=­¿ÝO?ý„ & ^œzúè#‡Ÿ³‹‹ îÞœ ’=)‚€ ΍€E$oâ÷í‘5+ê×(áÜhÈìA@%KvûâþýhÕª•ž?M{ö쉙3gbŊÉâŋuڄ   ‡Ÿ‹L@A f,"y“†w@ÆÔÀ»µJÆÜ£ÔA@ _v%óáÑ÷Žš®€€€M›ÁÁÁ6“èÅ¥&òàÁƒ8räˆSÌG&!‚€ ðr,"yÓFuBjŸ'høViÁSA@p:ÿí­IД)SàïïÚµkcúôéȞ=»SÌ5wîÜšQ£†Ž®)EAÀù°ˆäý8¶3’{ヺe™¡ ‚@¢B üéSŒÞ|Ž2׌¯‰^… 0uêTí‹ç,ÅËË k×®Õ>†RA@œ‹HÞÌq]àé„&õË9?"2CA@DƒÀ‚e;ñi™hÓF¥ R€î¯¿þÒŸxå˗w ~ÿýw4iÒ>tš9ÉDA@^Ž€E$¯ûïÂ5ü1Fôù@ðA@ÇÁ¡5m­~ujQCz6D͖ótDÍ­[·¢tiçrMšV­BBBð÷ß;ôº‰ð‚€ –#`ɛ;±;ÂCЬaEË{–š‚€ ‚€!°÷ÐüŸáFLY‹žmkë×ÙK·ÐyÀB$õ͆–-[âã?¶#‰m#Š››–,Y‚ ØŠCéEAÀî°ˆä͛ÜaA×É«d÷A@3nbÁò]X°l’ûx⋏«á³_Ö]'1|òÜ{ðÿþçɐ³‘ŒùóçëÔ ¡¡¡rS‚€ $","yó§AèýshÞHH^"º7dª‚€ 8$GO]Ū¿þÕ¯«7îá£wËëWŸ\°vóa ð;Ü¡ëÝþmŒU­àšó7»ÂÕÕÕéH^©R¥t*ˆuëÖ9äZŠÐ‚€ ±CÀ"’·pæHÝ9ŠTŽÝ(ÒJAÀ®˜0kžªš’[ÖŽ+¹b+̺­G°jƒ‰Øyyz îÅÐèíÒ([<œˆ9 “NQ IDATKþÆì_wàã÷Êë b•Jçy6”«lqÕòÉ'±ÁîÚÑÏÓÓ7nýò€‚€ $,"y‹fODà=hÙžJâAFf*‚€"ðç¶£øŽû Üœˆ‹¿D…’¹r–û\ÄŠ¿cãß'°}Ï)”+žuk×ä.gÖŽžpùÖ«¹Nš³..Ж(ŸŸ_ )}“ýwŸ®I±p«+ÂÃÃѬY3‡Ä#:¡Ç¯¿þZ'y—"‚€ ž°ˆä-ž?¯nCKÑä%®»Cf+NƒÀ•ëþøžËt8r 5*ÄO£ZÂ7¹—ÃÌïØékذý˜&ví8Ž\ÙÒ¡zÅüxœbÔ®Zîîn ñ[Ÿn?V¬?ˆ{÷¡u“×ñ+†â³Ÿ|žnžXžÅÅéHžŸŸêÔ©ƒŸ~úÉaÖYA@° ‘Œ%¿.Ókô?˜RA@ 6œg«à#;•Ö.7FõmŒ’…³Ùõî?ÂßûÏbçŸ3úÅÏuªEº4É5±{C»J#÷((*âGâ:óçmH›ÊïŸYïÔ*3±3CÀÅÍK™kš.8Kà•Y³faȐ!:ªf‰%ìzœE8A@Û#`Éc"Õ³û¡có궗@zA@ˆ&Ï݈îC#U oü8¢êŒ^4NÆyÕN™Ú`ï¡óžxå.–¯?€ËJëXQ™‘V(•[œr©Ï¹udL–M;OhÞ_êõïñËš©Ž’õ©«U¥²fJ;QܒaÖúÇðññAãÆcׇµòõõÅoŒe˖ٙd"Ž ‚@| `ÉcT®CÛ [KñɋE‘1A@xÖo9‚fÊï.øq(ÆþÈ®rœþ{ì²&t{±Ûó¯zW¯ÒE³ëWÕòùŽ®PÞLzúAC°m÷iìØ{g/ÞÒ©ª–˧ÍMßP/[ùºž{cúê: eÆ _z»h;bÄ :GŽAÖ¬1˜ªÚ…Ä"„ ‚€­°ˆämÙ²[ÿ˜…¯ÛJ [/€ô'‚€­ ª×òžrý:µš¡œÞ³U×V÷ø(XEµŒ„ƒêµ_E·äûáW_¥1(],;Ế2ÅL/£Pƒ·cÏiHÅô:~æ:ª”ɃJêEXµ\^æÀæÅÍ“–ßAŽ9P¯^=›wߺšH3:u¯HA@HœXDòvíڅ5¿MGÿv'J2kA@ìË×üuÄLš26kX³F·ŠWi™pü"p$qþ*jçï*Áµ›(Q(+Š«WÉBÙLF’4FÙ}ðŒzÓ¯Ôçâ³h_»ÊŠÔñoŸƒî>ÿëu,Xµk׎Wìl=X¯^œ0nÜ8<|øI“&µu÷ҟ ‚€ƒ `É;xð ϙ€¡„ä9ȺŠ˜‚€ `š€ÏûÌÑÑ&银jV—8õõ[Z»F­Ü¡—5©;|â*2ù¥@ÑüYP$f¥™ËŽ‚y2!OŽô‘²(B·ŸœÃTrò¬Üp·î<@Y¥Å+["§ÎeÇÒ¥ˆSù_ع{rŒ^x¥K—Ö~lŽZnݺ…Ê•+£yóæèÛ·¯£NCäA@°‘Œ“'ObÖôqÚ¡” †”.A@^KWï¢ëàEØúÏIäȒ‹&~®S تø<Ä¡ãWqôÔU>yGOòý*’š4•JçÖNŠ*BGRÇ“åºÒàÑõΜ|Ôʕ,’ U0•b² oN?[‰ûêýžû*’w+VD•*Žë{NÍ]Š)póæÍWÇDzA@ph,"y.\ÀøqÃñm»bððpwè ‹ð‚€ 8*Ô€ ·ó—íBroO1óSŒ­R Ķ܌}GUþ¹cŠÌEŸŸºŠ Ù£ ʗ EÔËôžiTŠ£ùNMǓ°pcºº µƒÕœõØŠñY|’y⑊XdÿÞÉqöº6ÍԚ=ež€î絛hº¢J+G͜é=3ÒŠNn±\öRÑ%i:|9fÚ¶m‹ŒyóڋXËQ«V-íƒ×§OÔ¯_ßâvRQAÀy°ˆäùûûã»ïŸC·Æá—ÖñþwÞå³íÌü•†`§6¯âŠ÷iøS€Jé­6t*”yhZžze2mîÕÆ˜êð§j7IŠøAmâÕ59{ªH^E0HÌ"®© ì3òouÝÕÅ ®j³éêê®2$Iâ¡ÛººªëŠ„˜Þ­P㹩µ‹ªoúÌ{lgºî®Ú…+™]\Ô5Ÿˆvжê¥ê™È‘jG¢¢ÞÓúÄËÔÏ3bÃöŠºšàp$5‹Ùïy¢AZ"ØGä_ꃩµ‰Iñ“WÒPøx(ÒI†‰e7‰žŠJS}M‚^fT:\áGüõØÄW¯EDÝgdØDˆ“' †»«‰Üèï"Xš±Vü3ò³&Jc«ÏŠ5h±• ‘מžªvž"@üO!§Ÿ3%ŽçíÉõ‡&Pì!ŒmY—ýªJœ_Ù€vH×ѯˆï#ˆ×ðIhÄ÷J&âªÈë²Þ³æ}šþ6‘8Þ/Ùåž¡ì#‚Ø…«vüN¿Tÿ>ÞIu_úŸRIÔºóÝ]}ïÎûL‘D&¶§V‹„‹„)¹rg÷CÓwÊ)³ÉgŸh¶xBGMýÆ®Pc»¢ã§oàÛ^/ñCÊQDìˆ2±<¢Ì+IV—¯; ’莊WFí3WX}NÊû9O»¡5zçT”ΜÊîˆ"tì/·2-’ßÔŸ°Òè‘ÌåϝÑÓ³><3¡ÓUèׯ2dÈ`2Y(EëÖ­qêÔ)Ä$UŠ ‚€  ·€jcUód=z„AƒáóY‘#£)!­çA`ŸÚÌ-]»_ç®bð†4ϒIùËxäÀñkipï‘WœM6<œ„€›qÓ{59ÄÂtÃDõg^ã߯{ÄuM šYÔ$Äš¯úԄÓDXù®ÿŽè““ Sã>O<#Ìsdôù¶îîIÔæ^1_MŽL/ÊgºA¶"æA”4©—ÒFj'Ÿokh'#XD¿^^Š`>‡œ¹–1R=Qƒßyx$U$†²YV<=“áÑ#cŒgZRóÖÏÆTÚ4wwœV&Blzñó3’¬™m€¶1‰’'ì µ &ÂIºÙVpòH2!?×Q§¿'AFÜM}(¢¯H˜»[’H®Iœ"al“2Y(”Â8’èó€×õa€›»~7Y†Tôµ<ÜÂP2çUÜ÷¿¥"JÄúmGu0‘/¿xûUºÕm'ÍÙšýîÒšƒ–æ*¡gÛÚH—ÆtÈÆüq†‰ä¡ãWÀt fâŠæYX™V’ˆñš¶|*eAJ±Ò(ŒOILÏ^Œ­}æøùµ|êf•…òdÔ&–¹²¥EaåoG2HrëÔ%YvŽùz&L˜€dÉâN#kk ?ûì3Н¢jÕª0`€­»—þA@‹H7]4ùŽ^.ÈêäÿØ;ðbZ+:Íø~\ŽUŸögʐÖ+‡Kw}qEœÎÝJemwR?Ž0?‡yþLæùóÓwQì$-é™é£aFi7 K@Îtþ(’õ|”Š–äìà±K˜ú]óX¡³bÝ~|ÔåGEdêåó£o§ºÊù1ö©äáL$ŸGÆ0B%µi4‘ä‹>tùsù=g*ùH©àIàhŠÉ÷ã$sêuZ¥;(šˆÜë UŠdú35{Ôð9=™{ÁŠ„yæDëÞs0{öìX­YB4zóÍ7áççoooL™2%!D1A@ì‹Hå8p êTVá±óZ¿‰Žãù'ZÑèË6eþ&Ô®ZŽ]EÑR pÙ߁ÁÏ¢ä%Zpdâ‚@,x«Ø)€ò~Œ•À/«ö`ÎØÖVõ4nÆz ¿R“-ú2õÍL3€õE!¥U«ûzQÔ«Q\™†>3 ¥oèñ3×Tàå3gQQÄîÖÝ(¥È_NejI"W€d.w­Ù“ò<þ¡YðÍèeA–6oތ5j f͚xçwП}{YNA@Aà?XLòF…yœñFqe"%Å¡ Ægü¬ hù~eÌXŒµj‚C—í(œ¹C£+Â'fR& ÂÛÅOkÖm=‚õ*8ÉÈŸ-†€ë E˜©žI{I¯ˆÝ›U £z…|HŠèlúûVo<€ÈÛC䊈VyÛÿ!˜TüÍ× ëCæAT²gIcñž‰œâ…€t˜Ÿx† f×Pôïßüñnߟ=z C‡v-¯'‚€ pXLò–ÙÓ嚟‘@Éj#§yÿ‘‹žšòl…( AY•€øß[•Eƒçt«,J(J垆üoëáÛôžæ +âµòù,ÇÀ2L“°zã¿ø{ßYì%@ûsŠVþyÔÊy&M¢ýðhZ÷õbš\6Þ©UBç̓b={ÏyaÕæSÚbÅKˆŠHüúë¯Ã××çϟÇêÕ«‘3gN{UdA@°,&y˗/ÇÅӇС‘˜úØÉÚÅZŒÅ¿ÿ£üw2`Ë®“hønCl=‘=Ö}ICA@x$*Ë;¥NÀÃ= ;öœÂì%[åŸ÷V³±ØŽë*”̥̩ kâVLP V‘<œ„C*•‘“Ž?³dTþ³Šž»t[ió’¡qÝ2šóFQT.ãx©ê^Z»÷ N^F—.]J„Ž;fÌí+èáᡬŒ=ÚîdA@ì‹Iގ;°þßÑï³\ö7 ‘È*fš`+ŸÉ=‘-S<ôš‰›÷Ÿ£nUgRYþƒ@Ît÷P!Ï%}œ^ËÿaÖèÏ,ÎÇ|tE”ÿ%…ÉÑeó˜J—@<~>£«ÜñÔÑL3ù¥@֌©u`–jó#­JûÉ/%2«—JŠ.ńÀ ÷îá‡f͚٠$S§NÅ7ß|ƒ%J`˖-X³föœ"‚€ X‚€Å$ïðáÃXŽhú4ˬM…€8.“çnÔ!Øßy« v_®àžÉ;FÀÂÒ±ß|mJIÿºø,GY\ª"unÞyB'1¿yçÒ©Då|ö̅¹™’!}_dH—™U„ÝQ}>P)’Ƨ˜v1Ö€%W³@Ô­[7Áå™7ož&wY²dÁ±cÇtþ;Šv"‚€ Xƒ€Å$~³fÍB».¥»5cH];C`Ҝ¿p]ùøÔiÐY¥JHig҉8‚€s P!÷eäLïIêP…¹;šDæ Y˜ž¹0O_ž¥µ}ŒÈÉäé 䝁A!X>œ#*•É“b&ÈØßÎ<‰Zu¢B…„;ôZºt©NUÄ<}LnÎx Ž’:uêÁDA@pl,&ywîÜÁ€I“ðћÓOÒ(8ò²OœœB¿\„†IÞCG^K‘Ý~(šå†Êw£§­EReýÐ1Ižý"•ð’ ˜zŸ¶jS$Ð˗ÍB®\QŽXyû߉%‰$y"Er/ êÑÀ‰gëžS£ÉꐙÇ1iòŽ8Äõë×5±›A«V­â`Æé$¥sA@»AÀ*’·xñbø_?†¶ïf±› ˆ Ö#0}áf> Tx££õ¬ÅÚ ¿ Ôí R¥JƒŒÙŠ"}ªŒ?CÿÛèÔ¡š~Ôuë}9Ÿž=#ƒ_ôürŒÃÏÑ&Þ75 ŸÅàq+C%/oÞš’#ˆèdÜsPåÛïªrä ¶ù܃‚‚°aÃŒ7ÿü󌜜õ«E‹: Šäº³9äÒ¡ ‚@V‘ŒíÛ·cÝê_1 MüF‰“Õ²-ó–þm¢Ú[ÝmÛ±ƒõ¶fýb=º®®®È[€|SŠAÅžèÝœ{;Ÿƒï}†÷?h¹*=ºœ”©Ò¢_ÿ)¶RŽ)®AòŸüî”/‘ Þ.m—Ù{èJMŒ¹2—¯;€ëa…Ñ®];›¬ÏñãDZjÕ*úÀȟ??®\¹¢©Ø•*UÊ&ãH'‚€ ‚À˰Šä=z?/š‹.ïgÔIw¥8&¿ý±+7_Wæš_9æl õšõ‹ÁÛٓ9Ñ+”«$ÒŠð³Á( Óŝ;7Ð¥Ó»šW¿š4í)D÷®Ü7% ž‘0‚%²Q ’—P),»eϙ8 ¬îû!ÞšTÀ’&NWgꂭÈP°Þ{ïœXÏmíÚµÚ¿nõêÕª0Bƒ tZ†êիǺoi(‚€ Ä«HÞµk×0cÆt|òzRd˜&6ãI;@àM‡0wåÔ{¿ŸHÿ"lÞº {ömúÏÀÑKï—å UÁl4â­[×ЭË{hô~Œ×°Ud¯];¿§}ôúôýÁF#I7/CÀ;©ÊEYêZ÷ž…6VEùR¹ì°áSÖ`ØÄU:_^¿ÎõÑ·S=»‘-Ÿ>e=j4ìråÊY<45tŒˆÉŽBûö탧§§˜R«V-M™Ž»é$$$†Š&E© ŠHQšD± RE‘¢RUº  bAD~)bQ”.œiÒ€Búî?w6/Y„”Íæ <^Ùy3wŸy ïìÌÜëæ†#ö"ê B/0š4º>Ü^7>yýúÊ«åûHJŒ˜ÉÕÕÕ SŠ-S1¯ü3¯ýžzbbΣ룹³({'ž÷:îk‘5­Oï6šQãNôí÷N‘ê÷‚l¬yý>ÆC» 4ž`‚ZKÐów§üó—m‚¯§¹{¯ô€ž“çâìùXŒšº}Ÿ2ó1Ù°a-Z„õë×ãàÁƒê‹šxž©ßå˗ף}íÚµC£FŽÈc"  G%pÃ"o͚5ØúÛ7ü\CGmíºÛcâÜ?”È_dX­]¿[·ýO/T­]®îî8Œo7¢ÏŸËdXJ ŒN9xk~üV ŽnOȬçË¿Äòe_âãÙ?æ ÿcÇÂ1ôîx±Ï4iÚ:³Žz¶Ä]õïÅó/Œ™'õ²ÐË ˆÈkÛcæMî ?ï|CwŸ/þÓ?ÿq IpsuÁ;¯vB÷‡å› Ž\QZZ:þÚvsÿ ێÁbò‚,GAç®~7¡víÚhÕª•^WW¶lYGnm#  ËܰÈÛœ{75º)o„*öSá#°éïÃøðS%ò/"oío˰uûú̎ºDèíUB/ò‚CÊááöÏåhïŸC{0bxO%ð|0løÇ ­ ëúûï xü+ðô*†Ùs~V±øT0>•~\œ_|þ!&MYŠÀ@x2—“Ø3üíç0ð属³~óÌҟíÑ ÷ÞÛݟ.Ú^Us÷ײÆtiÍx>ޞyZuzz:æ¿ –o¿§£qúìT*_Ã_î€V÷=È1±ñï©(„À&&a›ò"zèèY=z—šÖ"ºž˜QÌӁ·”@³ûZ£qãÆhÓŠv˜ÂD$@$@…À ‹Œˆˆ̙öºŽF¥[ƒ {û‹€ý[wÅÄÏ6àÁ®cœŸýkשŒ¿»¬†Ð“iXñ‘1h}ÿcp1»äˆÇ„q/cçο0tØ T­Z'³ YÃÚû…”tQOÙ °ýŒüúë÷ødö-«T©£:ÿëŠ=»7cÌè~òÆÜ^ÓæLÂbIÇSO6A‡Ž=Ð¥kï\¯“^™@ÓÊáxiÈûøfÚ Ê9‡{ž`Zµn7ŸXŒáGÎÀb?-ë`PÏP³ªs –ÄÄdWBVDÜ µ!·ïÐiù÷Œ·1.* FF*€ [Š£Vµ²hzg%ŽŒ»J•ôÅ;jë­Û¢ÑY¡Fò€“X(   ä3ybßÈ·ßD+êç.û‰©ð‘7nÖ:têæÜ8®æEÓè1zUjÔAó©579{?zôÞzóiÜÕà>ô0ú²‡á›aû¶ß1B…-ðTõIÚðÇj|4}øe#mÿ)ÜölÁ.%$Å=»¯ ƒ #teˆ]ñ–-[Öa҇¯ë:+U²à$$Ä¡—š®ùèc}Ñ®}÷Ëî‡1ß-žƒ-›×i‡1"{ü¥Ì‘Æ#‡÷ÃMMc+SŠ¢úܪG"·lY‹öíŸFË:_±Œv D‰@Üv[-‹ðJ)%% «W-ÂO?-F|Ü匢*:wíu‰X.|?aY7ªx/Ÿ6Ë>駞1×\kŠˆ™Ë6bòg?£B™@5Ó¬GïïЯ<߁Ås­®ü*(æBΚQ¶µÉhÛÙóqúX¶Ó1ø÷LŽŸ­\©@_ÈHŒŽ‹‡PIÁJŽ•W,ª†£NõržœJ(*«/"ƒTÞ«¥Aï.ÀðѳP"ˆÿ—åW?³  ü!#‘'ñ€âOýç;ߑ?V²–\%°u—y3•È{ÒyE^l\ fúÞr «XíÚvמòrš–}ÿ¹^{7`àÔ¿ëÞë*Æa}^¥Šˆ= ïY±âk¬ýe™o]Íi“žOæŒÅºµËu>/%œl®Ùe:fÙr•.«SÀ|Iï“RqN„Y¢”8‹ŠIÐÇÑj/çr [ýÚ·êQ9wWý¥€L?•i•qqI°ª™ÎÁ~(⏠eK"¬\ nU‚.L‰8r9µG•PžúÕFLüxIAbcÝ$@$@$'r$ò$.Ð÷‹æ`Hšê¥Ó-O c¡yG`‹yÌYöNìx%19s”ÈKI± ì)7ž”9O­O]¹b>FŒœƒJ•o¿®NÛµkƍéç{Ÿ‰»ïi‹Ù³Fãw%̌ôƛSQãöújŠ¥S&¿©F×Ö¢ùœí•ˆgX²Žrán=NZ¬F/õúóOßá³OÇ_²æïÔ©£{«÷ IDATüêcèõâÛžûu‰“–wFöR/ÔixêéAÚ©óÞKʳàNŒ;úsvრ¯ê5†Ï>ÿ:>U¢ÓÏï„„”×åeú§L•é©ãÇ Ä^5ê(bñŽºwkA*ew}Ž–.ùÕª×Õ>“’ñö[Ï@ìz U<òHOó.Žó§ã‡ÿ}¥Ոڞn-qã'ŽÇ’YYAésÒŠ©sÖÞ1]Í&ž('*;Tóç»[‹»ÊJå€ÈÌ{b3D™8ha§šÇ«MŽE°É¹ÞÔ±Ÿ¯ö…ŸÎtÂ.]=¯~j¶lÞ^ðòtSEý-#nª6ùò 5U ·ÄÄ«é–bŸbž)UB‹<™a)¢µ¬š^YFö¥ô¹Ÿï{»œ”å?ý“ñ¥ÑgàÐkeåç$@$@$PèäHä9s³fNG·Þê[ÕÀB×è¢nðæ¿`ڗ¡uç˧: Ґä‡Ǐ`å’oõè’}Ê-'eþòó|úÉžL¡s=üdäìÝw^ÔBF„ÔæM¿êé‘+VƒŒ †…UÇÈw>…á±SuSS4íM‘5eûwRkåÑO­É«S§ñ5-ݹã/=â%#W2-ò%®zözK šA/wƹs§ux…‰ ÆñãáÚi‹+IqjÝÚ¯?¡âìEêsñÜ9qÒw(^ŒDfœß/‹EJ,MŸ±BžÙb³‰˜5âŒÔï]4lt¿Ÿ¶CÌMPÞ?eÍ\dd„ÞŒ$Ó0Ÿ}~š5{H_zy@'m—LÝAwGÝŠúú[CŸÖ×F)Q:uÊPlüëgåvŸë%<£"Ïbô{}!AÚ;wé¥b÷uÄ+QÞH‹k‘'¶Ù'µ”QNgHü`ÔØw±ü“럮)‚폭‡0èÝop\‰®RÅÑðŽ0Žn~;ÎFÆá€Z›v:âNQÇ1zÍZc%ŠbT؄€Þž¥„üKC€ ٠粉°’YÞ^nHWB-5%Éjz¥ˆŽÈèxœW›L­<®™DFÅ+¡˜€óJ¬É^Ä\ ¿nQ›ìetÎG‰¿’jݟ9¹࣏õ5uœ›ëóê9èóÎÏxoü4õ òÿ°ŒbÌrI€H€ Ž@ŽEޒ%Kpúèßè݉ñƒ ®ûrVóobÎÂ?ÑŠ³ó¬É³*Q—lN@ºùòé™çNŸÁö )ï–ÁhÚž•^G–›IÄҔÉCõÔÐ6mC‹ûF©R6¯†²Š.ñb‚tF™~9iâý¹8>r¶^“&éëyS±â‡yüú$,_þ…ïÁø÷ €šŠyH…F˜3ë=œ8qXŠhZÿÛš£FŒúx/SJ ŸoLÇè±_©€Í¶5{rïV¡ûS¯ Uë®úšŒ¬Éۘqóôú·MjDñžšŸYÂ?P‹UcŒõxên=íòáGž×›‘>™3FM5]¥Öêý¯~ðšþHF÷„L-=Ÿ[MÓKQ"Ó§~¯Ä埘ñÑ==TŠjŠ7Ð}jtS<V«^O‹NgI¥‹ŸÁžñC•ã•—®[øÔi=D(¡æ­§Îƪ5iÞÅܵÇÈj•J£‘qk{o-=Å14ž„s'Dø)¯’†ÓÃa‰8*9£D£°µÐBÎe6áŠDše6ñVBÚÝ¢„Ú-ªn¹.‚QFõœ-?€‰ còäÉÎÖ4¶‡H€H€4‹Œ={öàۅ 0èñ55‡ëò Óóôë†ýZ;O…Ts"RÔž‹ÅM9i°šàÆé™]â™æ äí3*bæ35móŸöj1'ž/eݙŒŽ‰8’)Œ"Ö$ýžz‘òNù^K÷ޘ/2¡|vøð>œV­íƒÝÔÔÉÌýl‚öü)yã”3“ɬ„ÚËZI¹ŸÿvìøSOñì­ŠtŠXûiÍb}ßs=ßÐqñ$êfÍ^£§Xëän­Po©ÙžØÛµoß6%6=2C2Ÿ%''eŽV¯QO_–p âÍóâÅ8øû—ÔÂoÙ÷sÕ4Ïñšwç=ÚÙʯwƒ‡®Ã‡ÏBh[ðxgL>qøpÂ@,üš÷ ˆÉZŒÛY—÷·r²"kêRÓÒᯐ4QqÞÕ«€ýµk;ïÌúY"7  p&9yaöìÙðqKÀ£Í}œ‰‰Ó·eů;±zÝ4lå<ŽW’ÍqJܙàfõD:R‘ê"£zjÌâ˜ñÂ.\ˆÊ\/—ý“5l2%³Ví†×ý,f/oßÞmÊ £ë%SEüý«Êœ+#ԃxï9üy=úX®|e<þD?_BJDœ9m*Ÿß–Í¿êµx2 )Xr’fªppæ¬Õ(VÌö»âëySÔŽÔ¯µîúè‹*tD3õYqÄš° X^ŠŽUÎbd­bavÀ䛠DÞ|1ñ9œŠízÓäOB1/wÌŒŠŠ÷æ­ŠQJ’©Ö?ÿ±Ÿ.ü]{ìØêN $Vª/nŸüî/ |ö~%öššXq¥¯·ª"—/Õ³ z ùsçÎ-rmgƒI€H€Š›y[·nÅÒ¥Kðö3”Ç5›£ &Ç'°lÍvœ>§þýÿGÎñ[’eaŠ)Q(‡.²ÌVxŠû)Ù'Îۙ®F@Ö N›ú–žò)IКÊ:0û$ëóú«8€¿.'i€rø’ªŠ|J8#I‹~ŒåË>ϬOŠ¢J v#•.]^yÙ|?sm`Nêv„{–~ÕÞì‚r¡¹ëàcã߇õˆŒl®*¬B‡–uôÏÀu^:ÈŸk©XŠ˜Ø‹hìD!r÷ä>y_NÆÊ•óuÁåË߆d,þÌéãø`⷗„ŠÈýš·ÄŸŸ†Ð wŒz¥cŸˆõ›aÞÒ¿°~S8NEDëu˜^žîxê‘F˜6ª[Û˜W˜KµÆž)óаaC4kÖ,¯ªa¹$@$@$ànZäI+ÄK™‹%ÝîË?WõA¯Ñä|øy{¢ö=C‘šîRH[A³‘€¬ç[»vDìÉ;IÕª×Åз>rDsóÅŠßW¿oTŒ£KŸÔw#•€§[”è ×Ó:7í8‚_æÛ‚Ù;[2¹•@jÉöxá…èUÓÙ:—í! ž"\yÀW_}…×»W@1÷,ïxd^„wTD‰r]p6ÖÛ1€U…š€8T™?o*bbÎã¥þïiG.E5Ø3é©QòbÛ¢Š ÀÛm Œ+օãȑ#x饗 Ü@$@$@yM WDž9tèPtm¥Œâ•KÊk›YþMxiØWèúP}€úŽ¡È»I–Œ®EàtøBÄE†cøËí¯••Ÿç/˜Ê<Ž÷ލöíÛ£V­ZyQ Ë$  ‡"k"ïçŸÆæ¿Öap·rÕ@s9#æ£åÝÕá܉" ä1}›Š£€_*úõh‘Ç5±ø+0ù×Ç?çŒ1sæLŒÿþû„D$@$@E‚@®‰Œžž8Œ=/t(ƒòÁ9 š\$ˆ;@#ߛú?„–öGÙjÝ)ò ?h‚sø}ÅPŽkQ­›×tî†:bëL®0—톩Óg",, mÛrʬ#vm" È}¹&òÄ4Y——ûžnšû–²Ä\#ðÍòÍØ}à$:u~Nß\ ë\3Š‘€òMÀ'3‡`âۏ¢TI?'l¡c7Éä'RœªÓáŠcw­# ȹ*òNž<‰éS&â55eÓϗfó ¿r¥Ès‘±è;lfŒ~®…„ä¢9W`²øû¶Ì…9íFŒÜœò™€xԄ ~þí·‹‹çž{.Ÿ-`u$@$@$PprUäI3&OžŒÊçѺIù‚kkŸ&ñ¯Bñbxìá6Xµ³ò5ó3 ÀH‰ÞŒý»Wᩇ Z¥¢ë]ôÆšå^nSp;˜¿Ê#¬,%$©ÏôÙ÷Ø]3Š”ö[”P|rÍšËvŸíFûc7•?-=ý’köyôýò7ã^)_Äœ.^ý“¬Úž”êša_FŸ+ؕÙf{;2ڕU_Öm±ÔšÓh»Íø¬ë&õœdöÙeð lY€³wO¶ÞºŽëÔ3)íŽZ,°XmûtµYUX2®Y7‹<{êZºŸež«{õ5Û=éjsžŠHøû€£Æm¥àç ÿ^ˆ‰MÄÉÓ1hrg%4ž£â™ÆÏòŠ€g(ÌÁmtéýû÷×ëñʔ)“Wµ±\  pXy&òN:¥ώ;nqa;à°hXž þ=uáG#p.2NœÔZñïÉH€Š¥#(ÐO¿èŠ¥Ù^vÓÕ>-ݪ†ªÌëꚌ\»ººšÍ W%øÔq1/ŒëJªkr]D›Ê£ÅbF^w•×$"Rœôëk‚Rîq‘c“º×vŸ(›ðT{•߬§M|–7£¡¶ÏmK®‹Q§:‰(Õ"K Tãº!š >— 4CÀ؋ÉìBR ܌)Ë6m›!n32fžk±k«'Sۉc}=ó3[‹êÛuu¬˜KßHZÐÈ^}n”%BÆvn—_‹@åés•/#¯ä×HmZ,e–¡ÎuÝr=+ä&©©iÚVª’Oß'›:—ÛlåŠx²jÖòlÙì•Ï ;m{›³µM:N_“|êTéœ<IÉ©ú3©Ï([D©”­û;£ïmτíË ww]vRš‡~m_\Ϙm¯Ÿ¹ŒçÎ8Ž;oõ,W¯\Z?ónn.ʛ°ʕ@U:X)ž_§/Ž àêÕ«WãàÁƒzº&   Ey&òægŸ}ŠFX<ñøcÁrvšÚtŒ(2.²mNS/Ø2uMöò²m"Q®+q(âAòÈÞøL Iú¥]>³œØË Œä3ŽåÅ<1)U [ÞÌM »kêÜÃÝUÚ¥d !¢È^Œhq¢®{yº#áb²MÙ ²lBK:W„ŒäÇÆ%föuæV¶Þ¿d$JԇQö<%Fýr¯ÍŸ¬JcTPï3Ê0FùŒ±â>žº-™×3l6Fò.)#£›¶mZÙgŠdUŽ!˜lהØVÂH¬3®âêÊçR®!ºl÷J9"Ќ²²F‹mÂìÒë"î3D™ú†0³•eˆ²«õE‘ýÁt҆›üëÃägsróì³Ïê%^jŽž‰H€H€Š"<yñññ6l†ŠÀ[üa9µH.ŠœÙf'&på)¥Wn°ýšŸˆLw•©Š6yiYöS5+›F×MÀäî“Љ'CñsçÎÕ_.>ŠŸ\d"  ¢J OEž@ýá‡ðÏ?ÿèõH‹WBï;5!^7™H€H€Hàæ ˜C:ŠŠÂ›oŸ‰™3gÞ|¡,H€H€ 1<yÂF\X?óÌ3ží¶Û`M<kĪBŒŒŠ“  8 Sñê*&^cm΀I“P·n]ÜsÏ=Žbí   !/"ïèÑ£ú?_Ù$Y£·Âza{4˜•’  8 O9[1»á÷ßÇúõëõ—ŠL$@$@$PÔ ä‹ÈÈ_|ñ…ö€Ø­[7ÍܱR9b9YÔù³ý$@$@9$`j« %õìÙÓŠM£³•²äm$@$@ÎE ßDž`wÖC† Ahhš^—g9¹HOp.¢l  @Þ°‹‰7yòdœ M[Œ<&  (êòUäíÛ· ,Àȑ#mÜSÎÃrz™š¿©‚]1‘  Àõ°‹‰·eËOŒ83‘   Øä«È“ çϟ€€$íˆE’5n¬‘°?H€H€HຘÀä[)))èÛ·¯žŠéááq]÷2   ù.òêðáÃÑŸ}{Ô«WÏ&ôί…5þPQàÍ6’  Üû˜xo¿ý6:vìš=j2‘   d(‘—€×^{ &L€···Ryé ”Î§’H€Hà¿ ˜=`éžúbÞŒyHOOÇSO=Ej$@$@$@وȶmۆU«VéÀµ:1P:N  «0Ã\ú!À#;wîÄÒ¥K!#yL$@$@$@—(0‘'ŠÈÒgΜAïÞœµe ”ÎG”H€HàJÌA÷«p ·"66ƒ ÂìÙ³ ŠH€H€Hà* Tä‰MÓ§OG¹råЮ];›Ð‹QÒc(O,  €€É¿>L~µõq¯^œ0vìXøûû   €£Š<±kذaxä‘GP§N›Ð;ó¬I§Ùi$@$@Eœ€É§2LÍ4…·Þz ]ºtAíÚ6ÁÇD$@$@$pe>’g˜õÊ+¯èÿÀ”–$XO-a t>µ$@$P” x†À,ÎM˜9s&*Tš€V­Ze"l;   \‡y‹E¯Í{ÿý÷áëëk ”~jéu5‚™H€H€œ‹€É=ŠÒ핟sŌ3‚”gM&   kp‘'–&''£_¿~˜}`M‰†5b…Š£—È^% (ÌÜü±íT̞ó)ä œàààÂÜÚN$@$@A Ðˆ<¡õý÷ßcãÆ1bÜÍÉjDïå¥%Þ!@Ò  $àR ‹~OÇÞý‡ôïu“Étƒ0;   À•*‘' عs'æÎ‹îÝ»ãŽZUlB/õ{—H€H HJ±bòÂã(]& =zô(D–ÓT  p|…Nä Òøøxí}­bŊèñÔã°j¡íøŽi!  6lý_¬8ާŸíƒ&M𐠐  @.(”"Ï`°`ÁlÙ²¯ €’Ö-Ê)Kd.ãaq$@$@¹I`Ɨkz ^}s<==s³h–E$@$@$A P‹ ŸÆÉ£»ÐâΒh~WExpd/ÿŸ4ÖH$àŽÖo:ˆUëöÀ§˜;mßaÕ(qžuó¯IDAT“g×ß9m¯³a$@$@ŽLÀéEžÿðáÃXúÝb-öîŸãŽhooºïv䇓¶‘ 86Ukwiq䇵Aõº-`*VN ;:¿r잣u$@$@ÎN Èˆ<£#?ŽeK¿Ã©c»P¥¬+šÕ¯ˆr¡·8{?³}$@$+¢b°ò×]ØŽãÂÂÂЩóc(_¥)`vϕòY   ÀÍ(r"Ï@vêÔ)¬Y³ {·ÿ†Ñ¢émš]µ ÜÜèùíæ+–@$àl¶ì8ŠŸ6ìűSñhÒŽÚ=Òþ¡ÎÖL¶‡H€H€œ‚@‘yFïÅÅÅaóæ?ñËʅ0§œÃmƒpWí +_R…rb,'§xÊÙ 8rü~Sëíö:o¿ÒhѪ#mŽÊâM$@$@$@ùG È‹<{ÔöïÁïkŸÁ¡ýÛÕåtÔWb¯nr(@Á—Ï$k"(@§#¢±nc86ïúpóÃ] ›£Ùýí¢œš0‘    yW芄žhÜŸë×®DTÔ€¥§ãv5•óöÛBQ^­ßó.æQ(:—F’ Àõر÷8¶í>ŽÝÿDÂÅ­8jÔ¬‹f-FŊ¯çvæ!  p0yÿÕ!–dD]Ãá»±uG8N‰‚Uå/Z5ª–GéR(äwwû`ëVX“ÏÖ4ëjšC$@6ÿžŽRS0#±÷H,ö†ŸAphyÔº£ê×o@aLJ„H€H€œ€EÞ tbBBŽ;†={öààÁƒHKKƒÅbA™2ePœzu=)00ŋWBï|ÖÄÓzKÊ ÔĬ$@$ \Œar-†Ã'b°ûÀ)<ÃÇÏÃÍÓ•o«Š5j Aƒ*œŒw.TÆ"H€H€H€…EÞMô„Z—mÿþýZôyxx 55UïoœõVýxɒ%_Ï4%ü”àKRÂ/Iíӓn¢fÞJ$P$ šøs&—b€‹WÖf–cO-栎@ø‘“8|ä8þý÷_œ&øº'ÂÇ5V5ê§Š†2‘ F°o“Y¬ŒðjOŒ&ýÇ*ÿªsÙÛŠí>»$Ÿ®~OšXsY"ÎS‹6oV³q"î̶©áñññ™NDœüî‘MŒûøøhAW¡‚ò¬âØU­ZU…†±ŸR^HÓL    ÈË1ºkß(S9ϟ?ÈÈHœÉ˘@96ğLùtuu…¿¯Š›è x'ÃÛà /O7xzžÁKm²÷PSQ$%" ¢B†ª/d¯…HœÏJ`؋ öÂãz?3DŠ!Fô}—”U·œMÚF;á£{LD64ÛgÙđ!–®$Ž®úYF†ˆÊžO³¹ŒU³Œë×WoÞ?{"ÞbbbpáÂÄÆÆjÑ&¿C¢¢¢­7ùLD›ŸŸJ•*•ùå‘;™Aàââ’÷†²   ‡&@‘WÝ#âO^ää%N^êdîÜ9ý"'0)) q±‘°ŠÆ+ÿ-j“}z²}é+Ü]]޳77µWÁÛ=Üm{ý"«Þ¡å¥\oªm;÷Ÿ@íjeÕÚAåÆjÚéQEÛŠå‚JùÌ8¶ØÞǍsOßg»W^šÓÓ-:íšäÏ(ÏVœí_åKSù2THFyb•~Û·Ù€ßÿ3Žíî•2mI}ŠN\”šIWÜ2L„«Ù©Êë©0™]\\µ'TÛ©­]ƒUòØJq-åØîÉi±U£óžžØÚŠ™šèwww€€€f¶IX™ b%ë>}šÚ+/ØiiÊ®Œ‹™íÐ!MpS‚>U ư̂fªÏä^±ÍÝÍ]Oû•2ìc5ÚØgµ×86FŠíóÇòBJJJf9FR­®Oñ’<²7î‘öʗöI>aqµëöuåÈŽeûë6F&=Y®çr-» Æ3lØhœË=†ö×ä~ã90ê.r,eØ·[®I>7òÙßgð‘ûì?ÏüÙ2~Æìî7Êýûï¿Q«V-ÍT~Ö¥ ÙËœò³œœ¬Û/{ãXì—ߟX±bzœl%J”Ðk|e­¯lAAAZØI&   žŠ<}6äñ’—Á‹’pՋ¡zALJJÑÂ#Y6õ²šr6ycˆží;v¢N­Ú0«]Û í¥{“œ«ÍþEÖ86^ZQGAegÙ5Fì_ ¯ôòlÿbnŒ`/ûÆœöeÛ×)/ÊÙóØ ûcã…={YÙ_ä³ ™ì÷ً£|Ù‚"û5{¡eÿYörŒ2² 3£Üì{ã~{±bœÝ&{ûì?»’HÌý™Ê:ó‹ûzí˹’}Ò?F£LûsãØ<ÙóÚÛq¥û³×i(£ù™±·×^\âôJu× ûrì¯uuÚÛ'ùºd/"¯^œzZ\Úÿ,‰“ÍÓÓ3sóòòÒdž ã(œƒþBŠY$@$@$PÈPä²£¹$@$@$@$@$@$ð_(òø|     € Ès¢ÎdSH€H€H€H€H€H€"Ï      8Š<'êL6…H€H€H€H€H€(òø      € Ès¢ÎdSH€H€H€H€H€H€"Ï      8Š<'êL6…H€H€H€H€H€þiyÒù'ã`@ |tEXtapplication/vnd.excalidraw+json{"version":"1","encoding":"bstring","compressed":true,"encoded":"xœíšËnÛF\u0014†÷~\nBÙÆÎÜ/\u0006\u0002T–ïv\u0012Åv|I\u0013\u000445¢\bS€BR±¥ »îº(Š\u0016Ýæ5úVÍ#tHÛ\")R”ãÐI]˜\u000bC\u001cÎ\fÏÌüߙ9‡þž`\u0018h4Pe£¡.,Óu:yÞx\u001c—PAèøž~„’ûÐ\u001f\u0006VR³\u0017EƒpùɓŽÅ’å÷/[)Wõ•\u0017…ºÞÏúÞ0>&õ\u0013§\u0013·mŸ;Œ\u0017\u0011oo¿<ÙŸX]\\\u000b÷“ŠI¥kc\u0002eEŠg»*}t¡Ë!†xR0Ò\u0005‚NnϝNÔÓE„ %œØ€JO9v/ŠëH>)Œ|Ͳ\u0001&%a\u0014øgªå»~\u0010Ûò貛ԒSÓ:³\u0003èuÒ:]ó\u0014\u0000šÖé:®»\u001f’žõÔéijLõte/œ*ŸÕJ¿Ðîy*\fsmüi9Q<\u0015$\u001d@lÜ`«“,ÂÛéî{f0žêŠ‘\f\"c˜Rñ\"Q\f$⒧oIµ@8ž.}î{‰. „\u0004C!œÔpÂU-ˆ(éµkº¡Jç0~óÚŽX²‚ɈŠìîâàÅÙ³Ãpô|'ê¶CŠº\u0013³sÂ1ƒÀ?oLž|z\\Õ¯=^±\u000fÈ\u0011&§&\u000b|±g±\u0017»ý\u001aú¥\u001d°µ=>ðN6y/x…ö{·9žY¿W¿ÒU\u001b\u000e:æå\u0004BF0\u0001„0ΐXÈX1…˜Ú\bŒ³C{mgm±¹î®¯t\u0007ÎîÍ\u0011#\u0010æ\u0010C\u0015\u0018C”Ìe\fRT3cÄbªûC\u0019£µ1\u0006\u0005…\u0012!Iy\tdˆ™!Ä\u0001'@àº!»KÑRJ$–°BŽÁ‰5ºpNeË:=[\u001dœ?ìúÄ6¿BŽ\u0019§sé\faQŽ\b\u0014UJăHg‹\u0014b„^ž2‘BIgŠ”aÉõ\u001e›©ñ\u001fß\tV‡›;Ê\u000e·\u000fûg\u0007‡ç'{ìهў6ñëý”â*ñoŒ7Ž\u000få\u001e\b֞mŽ<›î¬Ž¿Aü‚?ˆ¿\u0006ñ#©÷ZT8ï$\u000eº@ĵö\t\u0017ŒP\fk—þ]\u001dV\u000eäøUk\u000bntším֍lîѓ³{\u0014©@êus4„ªs„ZM_nƒç›æ*\u0012E€\"u\u0011MӄyŽ&”¡«’&\bHœ8Eé…\u00033ÐꘁTÏŽzÃ@Ý5T\u0010ÔG\u0015GRJ†AYpàÌs„„ë³oíT}ƒú竔3Æ2\u000e)\u0011›îèËç?7^l­¶Œ­Uã@ϛ÷ÆsÂpÙP\u0017fàª8š~ã…ÃÓeÃô<õS®xI_\u00195ø^ŽïŒcû2’ŒK×ÍŸãŽr\u000b\u001a¿¿é:v<Õ\rWu3ªÒ³\u001d9:šŸ<ŽüAV›¡r\u001d/Y‡ô€o鷘º4؊‡ì\r]7•NàØŽgº\u0007µž\u0002u§»¹¹yì\u001e·Ošûöæ»îŽØŽäÍPg ‡:Éd\u0017®Q‡X\u0014QGìôy€sÊ€Ž\u0001Yi€Ãä,Ð)fPJŽnCzNƒÅÀ™k\u0018qFãËç?~1ÚÃS×±Œ\u001d5úpAq\u001bž\n\u0003š`¥¿ïØ}Ý\u001eùÎÚ©s.ÚÃֆ°oÄ\nf4Ç\n$ÅÔ[6;÷ÀÊ×°B\u0010C\u0010à2V4\u000f3ã,œÁHÝPÜ&ãV\r\u000b”\u0000ÈâÖu©µõ¡k9ŸÑŠuÝÕʎ”Ñ\u001cF=-ÌèŸâS9€\n 6ŽNÄn¿‡µá{7€{g/÷Jò\u0016e›\u000fÏçو,ž3aæìù\u0000ÔW\u001d31çŒë(¡Œ(!f\u0012E\u0010ÖçSÎë'jööóׯÿüý›Ñꙮ«<[ÝG‚ЇPALõ‰{ꎝGFGãK:<ËoDHÒ%(xq7‚\u0004–Àƒ`œô<\u0012ȒPÍ ç»ä<ê䆯QV\u001c»”pCèln$ã\u0012\bp«\u0000­’›8ˆÊ~R\u001aøÎtX—þ2ÒµLn&¿ß>.­\rÓo\u001bñ…ÉÜ\u0006\u0018f\u001b@!æµX„9“ŽþÒ\u0016\u000bS-\u001b®\u0019F-¿ßw\"=\u0005íx€ÓÓ\u0013Ff\u0010­8^Çñlý,h¯¿ŒnÝ ý‘8\u0011k\u0018Ïâ\"XBL\u0000„õ\\c€€àŒdªÙæ QE‚ÝUñ$íÓP^gŸ)ÕÉ͌)`‰\t\n\b`\u0018ƒXOD\u0016\rÁå†$³ÒŒ=FO™\u0005¥ÍÌ>Ë\u0006òå.ª:uUí¢X‰‹\"H–»(™æ;&\u001eЧ0?8š’š\u0012\u0001Â¥(K\u001fQ1󋄀˜\n†3ÍêrO\u0014CˆÓ/µº'‘óN‹l^}‰³õ\tœW1çÌXÆûݝgªþЗs\u0007úÐ\u0004$F„\"Ä\u0019HãϹî n¿„° „c€\u0017\u001bé=\u000eà¢%è»8ŠÞèÕKLχÍ÷áØ\u001e2\u001bŽ\u000eK>í—D\u001b\u0002“\u0012¿\u0004f\u001c0ù\u000eI¯ÿ—c¢Œq!ai^›Ï<7aÆ\u0000 \u0000¥m~‰ãlæà:Ü8TÓ\u001d\u0019ÖõIÝxúÔž*\u000bup`F¹8ïž\u0004 7\u001aÔ%V\u000bWN­a\u000e\u0006û‘ž²‰‡Ð\u0002p:WƒMßÖøàšó•²øJ®ž×\u0004ÕXŒ*^•Ÿ\u0016>ý\u000bí‡ÆH"}ý»IEND®B`‚fulcio-1.6.5/docs/new-idp-requirements.md000066400000000000000000000105061470150653400203510ustar00rootroot00000000000000# New IDP Requirements ## Summary This document describes the minimum requirements for adding a new IDP (Identity Provider) to the Sigstore Public Good Instance. Adding a new IDP option to Fulcio helps drive adoption of signing and verification for software artifacts using Sigstore's Public Good Instance. Because identity is a critical component of the system, it's important that new IDPs meet the minimum set of requirements to ensure the security and reliability of the ecosystem and users. You should also reference the [Fulcio - ODIC.md](https://github.com/sigstore/fulcio/blob/main/docs/oidc.md) documentation for additional requirements for the type of IDP you're looking to integrate. The current two likely types of IDPs are: - `Email` - Email-based OIDC providers use the user's email or the machine identity for service accounts as the subject of the certificate. - `Workflow` - Workflow-based OIDC providers are used with systems such as CI/CD pipelines, such as GitHub Actions or GitLab CI. These providers will require more onboarding and you should [file an issue](https://github.com/sigstore/fulcio/issues) to discuss the requirements for a specific system. ## Onboarding Request Identity providers should [file an issue](https://github.com/sigstore/fulcio/issues) before creating a PR. Fulcio and Public Good Instance maintainers will verify with the requester that the IDP meets the Technical and Security requirements outlined in this document. ### Community Interest New identity providers must demonstrate that there is either a gap that will be filled by including this identity provider (e.g. support for a new CI platform) or there is significant community interest. For any newer IDP, we would like to see additional demand for it beyond the IDP maintainer. We recognize that this adds a barrier for smaller IDPs, but we want to make sure that Sigstore's Public Good Instance is associated with high-quality, trusted providers. ### Preference for Automated Signing Integrations As outlined in Sigstore's [roadmap](https://github.com/sigstore/community/blob/main/ROADMAP.md), Sigstore is focused on simplifying signing workflows through the use of automated signing with workload identity, e.g. CI providers. Sigstore will strongly prefer identity providers that support non-interactive signing. Additional scrutiny will be applied to providers that only offer developer-based interactive signing. ### Removal due to Inactivity If the IDP is found to be infrequently used (e.g. a certificate issued once every few months), Sigstore reserves the right to remove the IDP from the Public Good Instance. We also request that you notify Sigstore maintainers if you will no longer be maintaining the IDP so that it may be removed. ## Technical and Security Requirements > The Sigstore Project reserves the right to remove your identity provider from the deployment if it is found to cause technical issues, does not meet the requirements outlined in this document, or if it is deemed to be a security risk to the system. The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). A new IDP must meet the following requirements: - MUST host a `/.well-known/openid-configuration` file that conforms to the OpenID standard for this file. - MUST have a secure signing key. - SHOULD have a documented key rotation policy. - SHOULD have a plan in place for key rotation in the case of compromise. - SHOULD have a documented signing key storage policy. - MUST maintain good uptime. - SHOULD maintain an uptime requirement of `99.9%+`. - MUST challenge the email address as an OIDC provider for email IDPs. - MUST prevent identity subject reuse. This requirement is focused on immutable vs mutable identifiers. For example, a person could give up their GitHub username but the GitHub `user_id` would remain the same. - MUST have a configurable audience (`aud`) for the token, setting the audience to `sigstore`. - MUST provide a contact during initial configuration that can be used for outreach for issues. - MUST support the following claims: - `issuer` - `subject` - `audience` - `iat` (issued at) - `exp` (expiration) - Other claims may be required (especially for CI providers). See [Fulcio - ODIC.md](https://github.com/sigstore/fulcio/blob/main/docs/oidc.md) fulcio-1.6.5/docs/oid-info.md000066400000000000000000000515361470150653400160010ustar00rootroot00000000000000# Sigstore OID information ## Description Sigstore maintains its own Private Enterprise Number ([57264](http://oid-info.com/get/1.3.6.1.4.1.57264)) with the Internet Assigned Numbers Authority to help identify and organize additional metadata in code signing certificates issued by Fulcio instances. This document aims to provide a simple directory of values in use with an explanation of their meaning. ## Requirements to support signing with CI/CD workload identities In order to support Sigstore code signing with CI/CD based workflow identities the following claims must be included in the OIDC ID Token. See example claim values for each extension in the detailed [Directory](#directory). Providers MAY choose to emit extension value in other formats to generic examples, and consumers MUST NOT assume the generic example format. Requirements: - MUST include `iss` claim for `Issuer` extension. - MUST include claim to support: `Build Signer URI` that identifies the specific build instructions that are responsible for signing. - MUST include claim to support: `Runner Environment` that differentiates between builds that took place in platform-hosted cloud infrastructure or customer-hosted infrastructure. Recommended: - SHOULD include `iss` that uniquely identifies ID tokens originating from the CI/CD system, e.g. not shared with OIDC OAuth 2.0 tokens for email/username logins. - SHOULD include claim to support: `Build Signer Digest` which is an immutable reference to a specific version of the build instructions that are responsible for signing. - SHOULD include claim to support: `Source Repository URI` - SHOULD include claim to support: `Source Repository Digest` - SHOULD include claim to support: `Source Repository Ref` - SHOULD include claim to support: `Source Repository Identifier` - SHOULD include claim to support: `Source Repository Owner URI` - SHOULD include claim to support: `Source Repository Owner Identifier` Nice-to-haves: - MAY include claim to support: `Build Config URI` - MAY include claim to support: `Build Config Digest` - MAY include claim to support: `Build Trigger` - MAY include claim to support: `Run Invocation URI` - MAY include claim to support: `Source Repository Visibility At Signing` ## Terminology - `Identifier`: Immutable resource identifier, e.g. uuid/primary key ID - `URI`: SHOULD be a fully qualified URL when available. MAY be a mutable resource identifier, e.g. `https://scm.com/example/repository` - Fully qualified URL: Complete URL with protocol. - `Digest`: Output of a cryptographic hash function, e.g. git commit SHA ## Extension values `1.3.6.1.4.1.57264.1.1` through `1.3.6.1.4.1.57264.1.6` are formatted as raw strings without any DER encoding. `1.3.6.1.4.1.57264.1.7` is formatted as a DER-encoded string in the SubjectAlternativeName extension, as per RFC 5280 4.2.1.6. `1.3.6.1.4.1.57264.1.8` through `1.3.6.1.4.1.57264.1.22` are formatted as DER-encoded strings; the ASN.1 tag is UTF8String (0x0C) and the tag class is universal. ## Directory Note that all values begin from the root OID 1.3.6.1.4.1.57264 [registered by Sigstore][oid-link]. When adding additional OIDs under the root, please update the above link with the child OID. GitHub Workflow specific OID extensions have been deprecated in favor of provider generic extensions starting from 1.3.6.1.4.1.57264.1.8. ## 1.3.6.1.4.1.57264.1 | Fulcio The `.1` is added to the root OID for sigstore for all OIDs set by Fulcio. ### 1.3.6.1.4.1.57264.1.1 | Issuer (deprecated) This contains the issuer of the OpenID Connect Token that was presented at the time the code signing certificate was requested to be created. This corresponds to the `iss` claim for non-federated tokens. This claim is the URI of the OIDC Identity Provider that digitally signed the identity token. For example: `https://oidc-issuer.com`. ### 1.3.6.1.4.1.57264.1.2 | GitHub Workflow Trigger (deprecated) This contains the `event_name` claim from the GitHub OIDC Identity token that contains the name of the event that triggered the workflow run. [(docs)][github-oidc-doc] ### 1.3.6.1.4.1.57264.1.3 | GitHub Workflow SHA (deprecated) This contains the `sha` claim from the GitHub OIDC Identity token that contains the commit SHA that the workflow run was based upon. [(docs)][github-oidc-doc] ### 1.3.6.1.4.1.57264.1.4 | GitHub Workflow Name (deprecated) This contains the `workflow` claim from the GitHub OIDC Identity token that contains the name of the executed workflow. [(docs)][github-oidc-doc] ### 1.3.6.1.4.1.57264.1.5 | GitHub Workflow Repository (deprecated) This contains the `repository` claim from the GitHub OIDC Identity token that contains the repository that the workflow run was based upon. [(docs)][github-oidc-doc] ### 1.3.6.1.4.1.57264.1.6 | GitHub Workflow Ref (deprecated) This contains the `ref` claim from the GitHub OIDC Identity token that contains the git ref that the workflow run was based upon. [(docs)][github-oidc-doc] ### 1.3.6.1.4.1.57264.1.7 | OtherName SAN This specifies the username identity in the OtherName Subject Alternative Name, as defined by [RFC5280 4.2.1.6](https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6). ### 1.3.6.1.4.1.57264.1.8 | Issuer (V2) This contains the issuer of the OpenID Connect Token that was presented at the time the code signing certificate was requested to be created. This corresponds to the `iss` claim for non-federated tokens. This claim is the URI of the OIDC Identity Provider that digitally signed the identity token. For example: `https://oidc-issuer.com`. The difference between this extension and `1.3.6.1.4.1.57264.1.1` is that the extension value is formatted to the RFC 5280 specification as a DER-encoded string. ### 1.3.6.1.4.1.57264.1.9 | Build Signer URI Reference to specific build instructions that are responsible for signing. SHOULD be fully qualified. MAY be the same as Build Config URI. For example a reusable workflow ref in GitHub Actions or a Circle CI Orb name/version. For example: `https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.4.0`. ### 1.3.6.1.4.1.57264.1.10 | Build Signer Digest Immutable reference to the specific version of the build instructions that is responsible for signing. For example: `abc123` git commit SHA. ### 1.3.6.1.4.1.57264.1.11 | Runner Environment Runner Environment specifying whether the build took place in platform-hosted cloud infrastructure or customer/self-hosted infrastructure. For example: `[platform]-hosted` and `self-hosted`. ### 1.3.6.1.4.1.57264.1.12 | Source Repository URI Source repository URL that the build was based on. SHOULD be fully qualified. For example: `https://example.com/owner/repository`. ### 1.3.6.1.4.1.57264.1.13 | Source Repository Digest Immutable reference to a specific version of the source code that the build was based upon. For example: `abc123` git commit SHA. ### 1.3.6.1.4.1.57264.1.14 | Source Repository Ref Source Repository Ref that the build run was based upon. For example: `refs/head/main` git branch or tag. ### 1.3.6.1.4.1.57264.1.15 | Source Repository Identifier Immutable identifier for the source repository the workflow was based upon. MAY be empty if the Source Repository URI is immutable. For example: `1234` if using a primary key. ### 1.3.6.1.4.1.57264.1.16 | Source Repository Owner URI Source repository owner URL of the owner of the source repository that the build was based on. SHOULD be fully qualified. MAY be empty if there is no Source Repository Owner. For example: `https://example.com/owner` ### 1.3.6.1.4.1.57264.1.17 | Source Repository Owner Identifier Immutable identifier for the owner of the source repository that the workflow was based upon. MAY be empty if there is no Source Repository Owner or Source Repository Owner URI is immutable. For example: `5678` if using a primary key. ### 1.3.6.1.4.1.57264.1.18 | Build Config URI Build Config URL to the top-level/initiating build instructions. SHOULD be fully qualified. For example: `https://example.com/owner/repository/build-config.yml`. ### 1.3.6.1.4.1.57264.1.19 | Build Config Digest Immutable reference to the specific version of the top-level/initiating build instructions. For example: `abc123` git commit SHA. ### 1.3.6.1.4.1.57264.1.20 | Build Trigger Event or action that initiated the build. For example: `push`. ### 1.3.6.1.4.1.57264.1.21 | Run Invocation URI Run Invocation URL to uniquely identify the build execution. SHOULD be fully qualified. For example: `https://github.com/example/repository/actions/runs/1536140711/attempts/1`. ### 1.3.6.1.4.1.57264.1.22 | Source Repository Visibility At Signing Source repository visibility at the time of signing the certificate. MAY be empty if there is no Source Repository Visibility information available. For example: `private` or `public`. ## 1.3.6.1.4.1.57264.2 | Policy OID for Sigstore Timestamp Authority Not used by Fulcio. This specifies the policy OID for the [timestamp authority](https://github.com/sigstore/timestamp-authority) that Sigstore operates. ## Mapping OIDC token claims to Fulcio OIDs | GitHub [(docs)][github-oidc-doc] | GitLab [(docs)](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#token-payload) | Buildkite [(docs)](https://buildkite.com/docs/agent/v3/cli-oidc#claims) | Codefresh [(docs)](https://codefresh.io/docs/docs/integrations/oidc-pipelines/) | Fulcio Certificate Extension | Why / Notes / Questions | |----------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------|---------------------------------------------------------------------------------|-----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | aud | aud | aud | aud | N/A | Only used to validate the JWT. | | iss | iss | iss | iss | Issuer | This already exists. For example: https://token.actions.githubusercontent.com | | exp | exp | exp | exp | N/A | Only used to validate the JWT. | | nbf | nbf | nbf | nbf | N/A | Only used to validate the JWT. Optional, as per the OIDC spec | | iat | iat | iat | iat | N/A | Only used to validate the JWT. | | server_url + job_workflow_ref | "https://" + ci_config_ref_uri | N/A | platform_url + "/build/" + workflow_id | Build Signer URI | Reference to specific build instructions that are responsible for signing. Can be the same as Build Config URI. For example a reusable workflow in GitHub Actions or a Circle CI Orbs. | | job_workflow_sha | ci_config_sha | N/A | N/A | Build Signer Digest | An immutable reference to the specific version of the build instructions that is responsible for signing. May include the digest type followed by the digest, e.g. `sha1:abc123`. | | runner_environment | runner_environment | N/A | runner_environment | Runner Environment | For platforms to specify whether the build took place in platform-hosted cloud infrastructure or customer-hosted infrastructure. For example: `platform-hosted` and `self-hosted`. | | server_url + repository | server_url + project_path | N/A | scm_repo_url | Source Repository URI | Should include a fully qualified repository URL. | | sha | sha | N/A | N/A | Source Repository Digest | An immutable reference to a specific version of the source code. May include the digest type followed by the digest, e.g. `sha1:abc123`. | | ref | "ref/heads/" + ref **OR** "ref/tags/" + ref | N/A | scm_ref | Source Repository Ref | The source ref that the build run was based upon. For example: refs/head/main. | | repository_id | project_id | N/A | N/A | Source Repository Identifier | Stable identifier for the owner of the source repository. | | server_url + repository_owner | server_url + namespace_path | N/A | N/A | Source Repository Owner URI | Fully qualified URL for the owner of the source repository. | | repository_owner_id | namespace_id | N/A | N/A | Source Repository Owner Identifier | Stable identifier for the owner of the source repository. | | server_url + workflow_ref | "https://" + ci_config_ref_uri | N/A | platform_url + "/api/pipelines/" + pipeline_id | Build Config URI | A reference to the initiating build instructions. | | workflow_sha | ci_config_sha | N/A | N/A | Build Config Digest | An immutable reference to the specific version of the top-level build instructions. May include the digest type followed by the digest, e.g. `sha1:abc123`. | | event_name | pipeline_source | N/A | N/A | Build Trigger | The event or action that triggered the build. | | server_url + repository + "/actions/runs/" + run_id + "/attempts/" + run_attempt | server_url + project_path + "/-/jobs/" + job_id | N/A | platform_url + "/build/" + workflow_id | Run Invocation URI | An immutable identifier that can uniquely identify the build execution | | repository_visibility | project_visibility | N/A | N/A | Source Repository Visibility At Signing | Source repository visibility at the time of signing the certificate | [github-oidc-doc]: https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#understanding-the-oidc-token [oid-link]: http://oid-info.com/get/1.3.6.1.4.1.57264 fulcio-1.6.5/docs/oidc.md000066400000000000000000000321641470150653400152070ustar00rootroot00000000000000# OIDC Usage in Fulcio ## Summary Fulcio uses OIDC tokens to authenticate requests. Subject-related claims from the OIDC token are extracted and included in issued certificates. Sigstore runs a federated OIDC identity provider, Dex. Users authenticate to their preferred identity provider and Dex creates an OIDC token with claims from the original OIDC token. Fulcio also supports OIDC tokens from additional configured issuers. ## Integration Guide To add a new OIDC issuer: * Add the new issuer to the [configuration](https://github.com/sigstore/fulcio/blob/main/config/identity/config.yaml). * Attention: If your issuer is for a CI provider, you should set the `type` as `ci-provider` and set the field `ci-provider` with the name of your provider. You should also fill the `ci-issuer-metadata` with the `default-template-values`, `extension-templates` and `subject-alternative-name-template`, following the pattern defined on the [example](https://github.com/sigstore/fulcio/commit/9f02ba2924c6f8a0b46861b3585cb497a7560454). * Important notes: The `extension-templates` and the `subject-alternative-name-template` follows the templates [pattern](https://pkg.go.dev/text/template). The name used to fill the `ci-provider` field has to be the same used as key for `ci-issuer-metadata`, we suggest to use a variable for this. If you set a `default-template-value` with the same name of a claim key, the claimed value will have priority over the default one. * If your issuer is not for a CI provider, you need to follow the next steps: * Add the new issuer to the [`identity` folder](https://github.com/sigstore/fulcio/tree/main/pkg/identity) ([example](https://github.com/sigstore/fulcio/tree/main/pkg/identity/email)). You will define an `Issuer` type and a way to map the token to the certificate extensions. * Define a constant with the issuer type name in the [configuration](https://github.com/sigstore/fulcio/blob/afeadb3b7d11f704489637cabc4e150dea3e00ed/pkg/config/config.go#L213-L221), add update the [tests](https://github.com/sigstore/fulcio/blob/afeadb3b7d11f704489637cabc4e150dea3e00ed/pkg/config/config_test.go#L473-L503) * Map the issuer type to the token claim that will be signed over when requesting a token [here](https://github.com/sigstore/fulcio/blob/afeadb3b7d11f704489637cabc4e150dea3e00ed/pkg/config/config.go#L464-L486). You can likely just use `sub`. * Add a case statement to map the issuer constant to the issuer type you created [here](https://github.com/sigstore/fulcio/blob/4d9d96a/pkg/server/issuer_pool.go#L40-L62) * These next steps are required only for non-ci issuers, as it is already tested for generically. Although, you are welcome to add tests for your provider if you want to. * Update the end-to-end gRPC tests: * Update the [configuration test](https://github.com/sigstore/fulcio/blob/572b7c8496c29a04721f608dd0307ba08773c60c/pkg/server/grpc_server_test.go#L175) * Add a test for the new issuer ([example](https://github.com/sigstore/fulcio/blob/572b7c8496c29a04721f608dd0307ba08773c60c/pkg/server/grpc_server_test.go#L331)) See [this example](https://github.com/sigstore/fulcio/pull/890), although it is out of date as you'll now need to create an issuer type. ### How to pick a SAN SANs are important for users to describe identities across platforms. They are used in verification policies as the primary identifier for a workload. Unfortunately there's no one size fits all answer for how to pick the best SAN to use for your service. To help, here are a few things to consider when making this choice: - How will users want to query / write policy for artifacts? Consider what resource(s) users will want to query against. How would they distinguish resources between different teams? Production vs staging? 💡 Litmus test: what value is appropriate for `cosign verify --certificate-identity=` - What's the most-specific identifier that can describe the workload? Choosing a SAN is often similar to figuring out what service account your workloads should have. Too broad, you may give unintended access to workloads that don't need it. Too narrow, and you end up having to manage the same permissions across multiple accounts. - Will the identifier change per-instance? Identifiers that are based on UUIDs and can change each instance do not make good SANs. They tend to be too narrow and make it difficult to write a policy that will work consistently. If you need to reach for a regex for most policies, your SAN is probably too specific. - Can the identifier collide with other resources? SANs should be unique for the issuer. Resources should not have the ability to use or craft a SAN of another resource. - Is the identifier well-defined? All SANs for a provider should be defined and documented. If an issuer has the ability to produce different SANs, differences and conditions for these SANs should be documented. #### Case study: GitHub Actions GitHub Actions uses the `job_workflow_ref` as its SAN. This has a few nice properties when working with GitHub Actions: - It's tied to a particular Job in a workflow. - It can identify reusable workflows for common shared behavior, so multiple teams relying on the same reusable workflow can also share policies. - The ref included can be used to verify it's coming from the expected location and not a branch. To understand some of the considerations, below are some reasons for why values were **not** used as the SAN: - GitHub Repository Example: `https://github.com/foo/bar` Too broad - this could apply to any GitHub Action in the repo (even potentially from pull requests). - [Subject](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#example-subject-claims) Example: `repo:foo/bar:ref:refs/heads/main` Slightly too broad - the most specific you can get with a GitHub Subject is the event type + ref. Users may want to distinguish between different workflows. - GitHub Action Job ID Example: `https://github.com/foo/bar/repo/actions/runs/4725056848/jobs/8382992120` Too narrow. Every GitHub Action has a unique job id that it can use to uniquely identify each run of a Job. While this gives you a specific identifier, it is not stable and changes for every run. Most users would likely reach for a policy that matches a broader set of jobs `https://github.com/org/repo/.*`, which makes it impractical to use as a specific identifier. - GitHub Workflow Ref Example: `foo/bar/.github/workflows/my-workflow.yml@refs/heads/main` Slightly too narrow. [Workflows](https://docs.github.com/en/actions/using-workflows/about-workflows) are the entrypoints to GitHub Actions - they define the trigger conditions and configuration for what will run. Workflows may end up using the same underlying job configuration with some minor tweaks (e.g. permissions, inputs, etc) by using [reusable Workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows). Instead of requiring different policies for each workflow that modify how the same reusable workflow is invoked, the job_workflow_ref is used instead to allow users to centralize these policies under the same SAN. ## Supported OIDC token issuers ### Email Email-based OIDC providers use the user's email as the subject of the certificate. * Dex (`oauth2.sigstore.dev/auth`) * GitHub (Note that this is the email of the user, not the GitHub username) * Google * Microsoft * Google (`accounts.google.com`) ### Source repository GitHub supports OIDC tokens for its workflows initiated from GitHub Actions. This removes the need for persisting authentication credentials. OIDC tokens include information about the workflow and source repository. * GitHub Actions (`token.actions.githubusercontent.com`) ### SPIFFE SPIFFE-based OIDC providers use a SPIFFE ID as the URI subject alternative name of the certificate, scoped to a domain. ### Kubernetes Cloud-based Kubernetes instances can authenticate using OIDC tokens per cluster. * AWS * Azure * Google Cloud ## OIDC token requirements with extracted claims Certificate background: Identities for a certificate are included in the [subject alternative name (SAN)](https://en.wikipedia.org/wiki/Subject_Alternative_Name) field. Fulcio includes email addresses and URIs in the SAN field. OIDC token: OIDC tokens are JWTs. At a minimum, all tokens must include the following claims: * Audience (`aud`), set to "sigstore" * Issuer (`iss`), set to one of the URIs in the Fulcio configuration * Expiration (`exp`) * Issued At (`iat`) For example, `iss` could be `https://oauth2.sigstore.dev/auth` or `https://token.actions.githubusercontent.com`. ```json { "aud": "sigstore", "iss": "", "exp": "", "iat": "" } ``` If the issuer is in a different claim than `iss`, then you can include `IssuerClaim` in the Fulcio OIDC configuration to specify the JSON path to the issuer. ### Email In addition to the standard JWT claims, the token must include the following claims: ```json { "email_verified": true, "email": "user@example.com" } ``` `email` is extracted and included as a SAN email address. ### GitHub The token must include the following claims: ```json { "job_workflow_ref": "octo-org/octo-automation/.github/workflows/oidc.yml@refs/heads/main", "sha": "example-sha", "event_name": "workflow_dispatch", "repository": "octo-org/octo-repo", "workflow": "example-workflow", "ref": "refs/heads/main", } ``` `job_workflow_ref` is included as a SAN URI: `https://github.com/{job_workflow_ref}` All other required claims are extracted and included in custom OID fields, as documented in [OID Information](oid-info.md). ### GitLab The token must include the following claims: ```json { "namespace_id": "72", "namespace_path": "my-group", "project_id": "20", "project_path": "my-group/my-project", "pipeline_id": "574", "pipeline_source": "push", "job_id": "302", "ref": "main", "ref_type": "branch", "runner_id": 1, "runner_environment": "gitlab-hosted", "sha": "714a629c0b401fdce83e847fc9589983fc6f46bc", "project_visibility": "public", "ci_config_ref_uri": "gitlab.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main" } ``` `ci_config_ref_uri` is included as a SAN URI: `https://{ci_config_ref_uri}` All other required claims are extracted and included in custom OID fields, as documented in [OID Information](https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md#mapping-oidc-token-claims-to-fulcio-oids). ### SPIFFE The token must include the following claims: ```json { "sub": "spiffe://foo.example.com" } ``` The configuration must include `SPIFFETrustDomain`, for example `example.com`. Tokens must conform to the following: * The trust domain of the configuration and hostname of `sub` must match exactly. `sub` is included as a SAN URI. ### Kubernetes The token must include the following claims: ```json { "kubernetes.io": { "namespace": "default", "pod": { "name": "oidc-test", "uid": "49ad3572-b3dd-43a6-8d77-5858d3660275" }, "serviceaccount": { "name": "default", "uid": "f5720c1d-e152-4356-a897-11b07aff165d" } } } ``` These claims are used to form the SAN URI of the certificate: `https://kubernetes.io/namespaces/{claims.kubernetes.namespace}/serviceaccounts/{claims.kubernetes.serviceAccount.name}` ### URI The token must include the following claims: ```json { "sub": "https://example.com/users/1" } ``` Additionally, the configuration must include `SubjectDomain`, for example `https://example.com`. Tokens must conform to the following: * The issuer in the configuration must partially match the domain in the configuration. The scheme, top level domain, and second level domain must match. The user who updates the Fulcio configuration must also have control over both the issuer and domain configuration fields (Verified either manually or through an ACME-style challenge). * The domain of the configuration and hostname of the subject of the token must match exactly. `sub` is included as a SAN URI. ### Username The token must include the following claims: ```json { "sub": "exampleUsername" } ``` Additionally, the configuration must include `SubjectDomain`, for example `example.com`. Tokens must conform to the following: * The issuer in the configuration must partially match the domain in the configuration. The top level domain and second level domain must match. The user who updates the Fulcio configuration must also have control over both the issuer and domain configuration fields (Verified either manually or through an ACME-style challenge). `SubjectDomain` is appended to `sub` to form an identity, `sub!SubjectDomain`, and included as an OtherName SAN. ### Buildkite The token must include the following claims: ```json { "sub": "organization:acme-inc:pipeline:super-duper-app:ref:refs/heads/main:commit:9f3182061f1e2cca4702c368cbc039b7dc9d4485:step:", "organization_slug": "acme-inc", "pipeline_slug": "super-duper-app" } ``` These claims are used to form the SAN URI of the certificate: `https://buildkite.com/acme-inc/super-duper-app`. fulcio-1.6.5/docs/security-model.md000066400000000000000000000036741470150653400172420ustar00rootroot00000000000000# Security Model Fulcio assumes that a valid OIDC token is a sufficient "proof of ownership" of an email address. To mitigate against OIDC compromise, Fulcio appends certificates to an immutable, append-only cryptographically verifiable transparency log. - Fulcio MUST publish all certificates to the log. - Clients MUST NOT trust certificates that are not in the log. As a result users can detect any mis-issued certificates, either due to the CA acting maliciously or a compromised OIDC identity provider. Combined with [Rekor's](https://github.com/sigstore/rekor) signature transparency, artifacts signed with compromised accounts can be identified. ## Revocation, Rotation and Expiry Fulcio is designed to avoid the need for revocation of certificates. The Sigstore ecosystem is designed to avoid the need for maintainers to frequently re-sign artifacts. ### Long-term Certificates These certificates are typically valid for years. All artifacts must be re-signed with a new certficate before an old certificate expires. Typically this requires long deprecation periods, dual-signing and planned rotations. There are a couple problems with this approach: 1. It requires that users can maintain access to private keys and keep them secure over long periods of time. 2. Revocation doesn't scale well. ### Fulcio's Model Fulcio is designed to avoid revocation, by issuing *short-lived certificates*. What really matters for code signing is to know that an artifact was signed while the certificate was valid. Sigstore accomplishes this with a tranpsarency log called [Rekor](https://github.com/sigstore/rekor). A verifier should check that the inclusion time in the log was during the certificate's validity period. An entry in Rekor provides a single-party attestation that a piece of data existed prior to a certain time. These timestamps cannot be tampered with later, providing long-term trust. This long-term trust also requires that the log is monitored.fulcio-1.6.5/docs/setup.md000066400000000000000000000227671470150653400154410ustar00rootroot00000000000000# Setting up a local Fulcio instance There are two simple ways to set up Fulcio. The first is to use `docker-compose up`. This sets up both Fulcio and the Trillian instance used for the certificate transparency (CT) log. See below for details on customizing the signing backend, as the default uses an ephemeral CA that is not persisted. Simply run: ``` docker-compose up ``` If you need to change the docker port on which the metrics port is bound, use the `FULCIO_METRICS_PORT` variable: ``` export FULCIO_METRICS_PORT=2113 docker-compose up ``` The other way is running the Fulcio binary: ``` go run main.go serve --port 5555 --ca ephemeralca --ct-log-url="" ``` This serves the API without a CT log, which is not recommended for production. See [sigstore-the-local-way](https://github.com/tstromberg/sigstore-the-local-way) to learn more about setting up Trillian. ## Signing backend Fulcio supports various modes to generate its code-signing certificates. These modes support different signing backends that are responsible for both generating and signing a certificate. Note that when using `docker-compose`, you may need to mount files under `volumes`. ### KMS The KMS signing backend uses KMS to generate a certificate signature. This requires setting up a KMS key with a cloud provider, such as AWS, GCP, Azure or Hashicorp Vault. You will also need to certify the public key of the signer, providing a certificate chain. The CA can either run as an intermediate CA chaining up to an offline root CA, or as a root CA, though the KMS signing backend is primarily meant to be used as an intermediate CA. Configuration: * `--ca=kmsca` * `--kms-resource=gcpkms://`, also supporting `awskms://`, `azurekms://` or `hashivault://` * `--kms-cert-chain-path=/...`, a PEM-encoded certificate chain Be sure to run `gcloud auth application-default login` before `docker-compose up` so that your credentials are mounted on the container. ### Tink The Tink signing backend uses an on-disk signer loaded from an encrypted Tink keyset and certificate chain, where the first certificate in the chain certifies the public key from the Tink keyset. The Tink keyset must be encrypted with a GCP KMS key, and stored in a JSON format. The CA can either run as an intermediate CA chaining up to an offline root CA, or as a root CA. **Tink keysets use strong security defaults and are the most secure way to store an encryption key locally.** The supported Tink keysets are: * ECDSA P-256, SHA256 hash * ECDSA P-384, SHA512 hash * ECDSA P-521, SHA512 hash * ED25519 Configuration: * `--ca=tinkca` * `--tink-kms-resource=gcp-kms://`, also supporting `aws-kms://` * `--tink-keyset-path=/...`, a JSON-encoded encrypted Tink keyset * `--tink-cert-chain-path=/...`, a PEM-encoded certificate chain Be sure to run `gcloud auth application-default login` before `docker-compose up` so that your credentials are mounted on the container. ### Google Cloud Platform CA Service The GCP CA Service signing backend delegates creation and signing of the certificates to a CA managed in GCP. You will need to create a DevOps-tier CA pool and one CA in the CA pool. This can either be an intermediate or root CA. We currently do not support the following CA Service configurations. Please file an issue if you need support. * Enterprise-tier CA pools (The certificate ID is not sent in the request) * CA pools with multiple CAs (Multiple places in the code expect only one certificate chain) Configuration: * `--ca=googleca` * `--gcp_private_ca_parent=projects//locations//caPools/` Be sure to run `gcloud auth application-default login` before `docker-compose up` so that your credentials are mounted on the container. ### On-disk file The on-disk file-based signing backend loads an encrypted key and certificate chain, and also monitors for changes to either, reloading the key and chain without requiring a server reboot. This signer supports a CA as either a root or intermediate. See [generate.sh](https://github.com/sigstore/fulcio/blob/f024a03d981f9f955b259ee7c126dd5c08d534b3/pkg/ca/fileca/testdata/generate.sh) for examples of how to generate an encrypted private key using OpenSSL. Configuration: * `--ca=fileca` * `--fileca-cert=/...`, a PEM-encoded certificate chain * `--fileca-key`, a PEM-encoded encrypted signing key (RSA, ECDSA, and ED25519 are supported) * `--fileca-key-passwd`, the password to decrypt the signing key ### PKCS11 HSM The PKCS11 signing backend supports using an HSM to sign certificates. Configuration: * `--ca=pkcs11ca` * `--pkcs11-config-path=/...`, a path to a PKCS11 configuration. See `config/crypto11.conf` * `--hsm-caroot-id=...` * Optional: `--aws-hsm-root-ca-path=...`, a path to an AWS HSM resource See [HSM Support](hsm-support.md) for more information. ### Ephemeral - **For testing only** Ephemeral CAs create the key material in memory and destroy the key material on server turndown. **Do not use ephemeral CAs for production.** Configuration: * `--ca=ephemeralca` To view the root certificate, you can access it at `http://localhost:5555/api/v1/rootCert`: ``` curl http://localhost:5555/api/v1/rootCert -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- ``` ## Certificate Transparency Log support All signing backends can be configured to write issued certificates to a transparency log. Signed certificate timestamps (SCTs), proof of inclusion in the log, are returned in a custom HTTP header or gRPC field. Only the KMS and File-based signing backends support embedded SCTs currently. Embedded SCTs are recommended, since a client can easily verify proof of inclusion when using the certificate for artifact verification, without needing to store the detached SCT alongside the certificate. See [CT Log](ctlog.md) for more information. ## CA Certificate requirements Certain signing backends, such as the KMS and file-based backends, require providing your own CA certificate chain. An example PEM-encoded certificate chain: ``` -----BEGIN CERTIFICATE----- MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl LmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C AQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7 7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS 0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB BQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp KFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI zj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR nZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP mygUY7Ii2zbdCdliiow= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl LmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7 XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex X69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY wB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ KsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM WP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9 TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ -----END CERTIFICATE----- ``` Save the chain to `chain.crt` and parse with `openssl crl2pkcs7 -nocrl -certfile chain.crt | openssl pkcs7 -print_certs -text -noout`. For the root certificate: * Subject with a common name and organization * Key usages: Certificate Sign, CRL Sign * CA basic constraints: CA:TRUE * You can optionally limit the root with a path length to prevent additional CA certificates from being issued beneath that root. * Subject public key: We recommend using ECDSA-P384 (secp384r1) or higher, or RSA-4096. For the intermediate certificate: * Subject with a common name and organization * Key usages: Certificate Sign, CRL Sign * Extended key usage: Code Signing * Lifetime does not exceed the parent certificate * CA basic constraints: CA:TRUE, pathlen:0 * You can choose to add a different path length constraint, but we recommend limiting the intermediate CA to only issue leaf certificates. * Subject public key: We recommend using ECDSA-P384 (secp384r1) or higher, or RSA-4096. We don't recommend mixing signing algorithms within the chain. ## Calling the Fulcio API To call Fulcio, you can either use `curl` or the gRPC client. It's easiest to use Cosign to call the local instance of Fulcio. You can configure Cosign to call the local instance with `--fulcio-url`, for example: ``` cosign sign --yes --fulcio-url http://localhost:5555 container ``` You will also need to configure Cosign with the local instance's root certificate and CT log public key. You can do so by setting up a local TUF repository, following [this guide](https://blog.sigstore.dev/sigstore-bring-your-own-stuf-with-tuf-40febfd2badd) Alternatively, **for non-production testing only**, you can use environment variables to configure the root certificate and public key. Set `SIGSTORE_ROOT_FILE` with the path to a PEM-encoded root certificate. To get the root certificate, call `curl -o fulcio.crt.pem http://localhost:5555/api/v1/rootCert`. Set `SIGSTORE_CT_LOG_PUBLIC_KEY_FILE` with the path to a PEM or DER-encoded CT log public key. If using `docker-compose`, the public key is available at `config/ctfe/pubkey.pem`. fulcio-1.6.5/examples/000077500000000000000000000000001470150653400146275ustar00rootroot00000000000000fulcio-1.6.5/examples/README.md000066400000000000000000000005231470150653400161060ustar00rootroot00000000000000fulcio examples =============== This directory contains example code that shows how one utilize the fulcio library for certificate generation. # request-certificate This code is a minimal example how one would request a short-lived certificate (20 minutes) for code signing. It uses the fulcio oauth portal and generates a RSA 4096 key. fulcio-1.6.5/examples/request-certificate/000077500000000000000000000000001470150653400205775ustar00rootroot00000000000000fulcio-1.6.5/examples/request-certificate/.gitignore000066400000000000000000000000241470150653400225630ustar00rootroot00000000000000request-certificate fulcio-1.6.5/examples/request-certificate/main.go000066400000000000000000000073551470150653400220640ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 main import ( "bytes" "context" "crypto" "crypto/tls" "crypto/x509" "encoding/pem" "fmt" "log" "net/url" fulciopb "github.com/sigstore/fulcio/pkg/generated/protobuf" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/oauthflow" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" ) var ( fulcioUrl = "https://fulcio.sigstore.dev" oidcIssuer = "https://oauth2.sigstore.dev/auth" oidcClientID = "sigstore" ) // Some of this is just ripped from cosign func GetCert(signer *signature.ECDSASignerVerifier, fc fulciopb.CAClient, oidcIssuer string, oidcClientID string) (*fulciopb.SigningCertificate, error) { tok, err := oauthflow.OIDConnect(oidcIssuer, oidcClientID, "", "", oauthflow.DefaultIDTokenGetter) if err != nil { return nil, err } // Sign the email address as part of the request b := bytes.NewBuffer([]byte(tok.Subject)) proof, err := signer.SignMessage(b, options.WithCryptoSignerOpts(crypto.SHA256)) if err != nil { log.Fatal(err) } pubBytesPEM, err := cryptoutils.MarshalPublicKeyToPEM(signer.Public()) if err != nil { return nil, err } cscr := &fulciopb.CreateSigningCertificateRequest{ Credentials: &fulciopb.Credentials{ Credentials: &fulciopb.Credentials_OidcIdentityToken{ OidcIdentityToken: tok.RawString, }, }, Key: &fulciopb.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &fulciopb.PublicKeyRequest{ PublicKey: &fulciopb.PublicKey{ Content: string(pubBytesPEM), }, ProofOfPossession: proof, }, }, } return fc.CreateSigningCertificate(context.Background(), cscr) } func NewClient(fulcioURL string) (fulciopb.CAClient, error) { fulcioServer, err := url.Parse(fulcioURL) if err != nil { return nil, err } dialOpt := grpc.WithTransportCredentials(insecure.NewCredentials()) hostWithPort := fmt.Sprintf("%s:80", fulcioServer.Host) if fulcioServer.Scheme == "https" { dialOpt = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})) hostWithPort = fmt.Sprintf("%s:443", fulcioServer.Host) } conn, err := grpc.Dial(hostWithPort, dialOpt) if err != nil { return nil, err } return fulciopb.NewCAClient(conn), nil } func main() { signer, _, err := signature.NewDefaultECDSASignerVerifier() if err != nil { log.Fatal(err) } fClient, err := NewClient(fulcioUrl) if err != nil { log.Fatal(err) } certResp, err := GetCert(signer, fClient, oidcIssuer, oidcClientID) if err != nil { log.Fatal(err) } var chain *fulciopb.CertificateChain switch cert := certResp.Certificate.(type) { case *fulciopb.SigningCertificate_SignedCertificateDetachedSct: chain = cert.SignedCertificateDetachedSct.GetChain() case *fulciopb.SigningCertificate_SignedCertificateEmbeddedSct: chain = cert.SignedCertificateEmbeddedSct.GetChain() } clientPEM, _ := pem.Decode([]byte(chain.Certificates[0])) cert, err := x509.ParseCertificate(clientPEM.Bytes) if err != nil { log.Fatal(err) } fmt.Println("Received signing cerificate with serial number: ", cert.SerialNumber) } fulcio-1.6.5/fulcio.proto000066400000000000000000000207461470150653400153700ustar00rootroot00000000000000// // Copyright 2022 The Sigstore 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. syntax = "proto3"; package dev.sigstore.fulcio.v2; import "google/api/annotations.proto"; import "google/api/field_behavior.proto"; import "protoc-gen-openapiv2/options/annotations.proto"; option go_package = "github.com/sigstore/fulcio/pkg/generated/protobuf"; option java_package = "dev.sigstore.fulcio.v2"; option java_multiple_files = true; option java_outer_classname = "FulcioProto"; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { info: { title: "Fulcio"; version: "2.0.0"; contact: { name: "sigstore Fulcio project"; url: "https://github.com/sigstore/fulcio"; email: "sigstore-dev@googlegroups.com"; }; license: { name: "Apache License 2.0"; url: "https://github.com/sigstore/fulcio/blob/main/LICENSE"; }; }; host: "fulcio.sigstore.dev"; external_docs: { url: "https://github.com/sigstore/fulcio"; description: "More about Fulcio"; }; schemes: HTTP; consumes: "application/json"; produces: "application/json"; }; // For Fulcio developers: All features should be designed with HTTP support in // mind, since some clients may access this API over HTTP rather than gRPC. // // If there's a feature that you think would negatively impact the HTTP API, // open an issue to discuss. service CA { /** * Returns an X.509 certificate created by the Fulcio certificate authority for the given request parameters */ rpc CreateSigningCertificate (CreateSigningCertificateRequest) returns (SigningCertificate){ option (google.api.http) = { post: "/api/v2/signingCert" body: "*" }; } /** * Returns the bundle of certificates that can be used to validate code signing certificates issued by this Fulcio instance */ rpc GetTrustBundle (GetTrustBundleRequest) returns (TrustBundle){ option (google.api.http) = { get: "/api/v2/trustBundle" }; } /** * Returns the configuration of supported OIDC issuers, including the required challenge for each issuer. */ rpc GetConfiguration (GetConfigurationRequest) returns (Configuration) { option (google.api.http) = { get: "/api/v2/configuration" }; } } message CreateSigningCertificateRequest { /* * Identity information about who possesses the private / public key pair presented */ Credentials credentials = 1 [(google.api.field_behavior) = REQUIRED]; oneof key { /* * The public key to be stored in the requested certificate along with a signed * challenge as proof of possession of the private key. */ PublicKeyRequest public_key_request = 2 [(google.api.field_behavior) = REQUIRED]; /* * PKCS#10 PEM-encoded certificate signing request * * Contains the public key to be stored in the requested certificate. All other CSR fields * are ignored. Since the CSR is self-signed, it also acts as a proof of possession of * the private key. * * In particular, the CSR's subject name is not verified, or tested for * compatibility with its specified X.509 name type (e.g. email address). */ bytes certificate_signing_request = 3 [(google.api.field_behavior) = REQUIRED]; } } message Credentials { oneof credentials { /* * The OIDC token that identifies the caller */ string oidc_identity_token = 1; } } message PublicKeyRequest { /* * The public key to be stored in the requested certificate */ PublicKey public_key = 1 [(google.api.field_behavior) = REQUIRED]; /* * Proof that the client possesses the private key; must be verifiable by provided public key * * This is a currently a signature over the `sub` claim from the OIDC identity token */ bytes proof_of_possession = 2 [(google.api.field_behavior) = REQUIRED]; } message PublicKey { /* * The cryptographic algorithm to use with the key material */ PublicKeyAlgorithm algorithm = 1; /* * PKIX, ASN.1 DER or PEM-encoded public key. PEM is typically * of type PUBLIC KEY. */ string content = 2 [(google.api.field_behavior) = REQUIRED]; } message SigningCertificate { oneof certificate { SigningCertificateDetachedSCT signed_certificate_detached_sct = 1; SigningCertificateEmbeddedSCT signed_certificate_embedded_sct = 2; } } // (-- api-linter: core::0142::time-field-type=disabled // aip.dev/not-precedent: SCT is defined in RFC6962 and we keep the name consistent for easier understanding. --) message SigningCertificateDetachedSCT { /* * The certificate chain serialized with the leaf certificate first, followed * by all intermediate certificates (if present), finishing with the root certificate. * * All values are PEM-encoded certificates. */ CertificateChain chain = 1; /* * The Signed Certificate Timestamp (SCT) is a promise for including the certificate in * a certificate transparency log. It can be "stapled" to verify the inclusion of * a certificate in the log in an offline fashion. * * The SCT format is an AddChainResponse struct, defined in * https://github.com/google/certificate-transparency-go */ bytes signed_certificate_timestamp = 2; } message SigningCertificateEmbeddedSCT { /* * The certificate chain serialized with the leaf certificate first, followed * by all intermediate certificates (if present), finishing with the root certificate. * * All values are PEM-encoded certificates. * * The leaf certificate contains an embedded Signed Certificate Timestamp (SCT) to * verify inclusion of the certificate in a log. The SCT format is a SignedCertificateTimestampList, * as defined in https://datatracker.ietf.org/doc/html/rfc6962#section-3.3 */ CertificateChain chain = 1; } // This is created for forward compatibility in case we want to add fields to the TrustBundle service in the future message GetTrustBundleRequest { } message TrustBundle { /* * The set of PEM-encoded certificate chains for this Fulcio instance; each chain will start with any * intermediate certificates (if present), finishing with the root certificate. */ repeated CertificateChain chains = 1; } message CertificateChain { /* * The PEM-encoded certificate chain, ordered from leaf to intermediate to root as applicable. */ repeated string certificates = 1; } enum PublicKeyAlgorithm { PUBLIC_KEY_ALGORITHM_UNSPECIFIED = 0; RSA_PSS = 1; ECDSA = 2; ED25519 = 3; } // This is created for forward compatibility in case we want to add fields in the future. message GetConfigurationRequest { } // The configuration for the Fulcio instance. message Configuration { // The OIDC issuers supported by this Fulcio instance. repeated OIDCIssuer issuers = 1; } // Metadata about an OIDC issuer. message OIDCIssuer { oneof issuer { // The URL of the OIDC issuer. string issuer_url = 1; // The URL of wildcard OIDC issuer, e.g. "https://oidc.eks.*.amazonaws.com/id/*". // When comparing the issuer, the wildcards will be replaced by "[-_a-zA-Z0-9]+". string wildcard_issuer_url = 2; } // The expected audience of the OIDC token for the issuer. string audience = 3; // The OIDC claim that must be signed for a proof of possession challenge. string challenge_claim = 4; // The expected SPIFFE trust domain. Only present when the OIDC issuer issues tokens for SPIFFE identities. string spiffe_trust_domain = 5; // The type of the IDP (e.g. "email", "username", etc.). string issuer_type = 6; // The expected subject domain. Only present when the OIDC issuer issues tokens for URI or username identities. string subject_domain = 7; } fulcio-1.6.5/fulcio.swagger.json000066400000000000000000000343671470150653400166400ustar00rootroot00000000000000{ "swagger": "2.0", "info": { "title": "Fulcio", "version": "2.0.0", "contact": { "name": "sigstore Fulcio project", "url": "https://github.com/sigstore/fulcio", "email": "sigstore-dev@googlegroups.com" }, "license": { "name": "Apache License 2.0", "url": "https://github.com/sigstore/fulcio/blob/main/LICENSE" } }, "tags": [ { "name": "CA" } ], "host": "fulcio.sigstore.dev", "schemes": [ "http" ], "consumes": [ "application/json" ], "produces": [ "application/json" ], "paths": { "/api/v2/configuration": { "get": { "summary": "*\nReturns the configuration of supported OIDC issuers, including the required challenge for each issuer.", "operationId": "CA_GetConfiguration", "responses": { "200": { "description": "A successful response.", "schema": { "$ref": "#/definitions/v2Configuration" } }, "default": { "description": "An unexpected error response.", "schema": { "$ref": "#/definitions/rpcStatus" } } }, "tags": [ "CA" ] } }, "/api/v2/signingCert": { "post": { "summary": "*\nReturns an X.509 certificate created by the Fulcio certificate authority for the given request parameters", "operationId": "CA_CreateSigningCertificate", "responses": { "200": { "description": "A successful response.", "schema": { "$ref": "#/definitions/v2SigningCertificate" } }, "default": { "description": "An unexpected error response.", "schema": { "$ref": "#/definitions/rpcStatus" } } }, "parameters": [ { "name": "body", "in": "body", "required": true, "schema": { "$ref": "#/definitions/fulciov2CreateSigningCertificateRequest" } } ], "tags": [ "CA" ] } }, "/api/v2/trustBundle": { "get": { "summary": "*\nReturns the bundle of certificates that can be used to validate code signing certificates issued by this Fulcio instance", "operationId": "CA_GetTrustBundle", "responses": { "200": { "description": "A successful response.", "schema": { "$ref": "#/definitions/v2TrustBundle" } }, "default": { "description": "An unexpected error response.", "schema": { "$ref": "#/definitions/rpcStatus" } } }, "tags": [ "CA" ] } } }, "definitions": { "fulciov2CreateSigningCertificateRequest": { "type": "object", "properties": { "credentials": { "$ref": "#/definitions/v2Credentials", "title": "Identity information about who possesses the private / public key pair presented" }, "publicKeyRequest": { "$ref": "#/definitions/v2PublicKeyRequest", "description": "The public key to be stored in the requested certificate along with a signed\nchallenge as proof of possession of the private key." }, "certificateSigningRequest": { "type": "string", "format": "byte", "description": "Contains the public key to be stored in the requested certificate. All other CSR fields\nare ignored. Since the CSR is self-signed, it also acts as a proof of possession of\nthe private key.\n\nIn particular, the CSR's subject name is not verified, or tested for\ncompatibility with its specified X.509 name type (e.g. email address).", "title": "PKCS#10 PEM-encoded certificate signing request" } }, "required": [ "credentials", "publicKeyRequest", "certificateSigningRequest" ] }, "fulciov2PublicKey": { "type": "object", "properties": { "algorithm": { "$ref": "#/definitions/v2PublicKeyAlgorithm", "title": "The cryptographic algorithm to use with the key material" }, "content": { "type": "string", "description": "PKIX, ASN.1 DER or PEM-encoded public key. PEM is typically\nof type PUBLIC KEY." } }, "required": [ "content" ] }, "protobufAny": { "type": "object", "properties": { "@type": { "type": "string", "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, "additionalProperties": {}, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\nExample 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\nExample 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "rpcStatus": { "type": "object", "properties": { "code": { "type": "integer", "format": "int32" }, "message": { "type": "string" }, "details": { "type": "array", "items": { "type": "object", "$ref": "#/definitions/protobufAny" } } } }, "v2CertificateChain": { "type": "object", "properties": { "certificates": { "type": "array", "items": { "type": "string" }, "description": "The PEM-encoded certificate chain, ordered from leaf to intermediate to root as applicable." } } }, "v2Configuration": { "type": "object", "properties": { "issuers": { "type": "array", "items": { "type": "object", "$ref": "#/definitions/v2OIDCIssuer" }, "description": "The OIDC issuers supported by this Fulcio instance." } }, "description": "The configuration for the Fulcio instance." }, "v2Credentials": { "type": "object", "properties": { "oidcIdentityToken": { "type": "string", "title": "The OIDC token that identifies the caller" } } }, "v2OIDCIssuer": { "type": "object", "properties": { "issuerUrl": { "type": "string", "description": "The URL of the OIDC issuer." }, "wildcardIssuerUrl": { "type": "string", "description": "The URL of wildcard OIDC issuer, e.g. \"https://oidc.eks.*.amazonaws.com/id/*\".\nWhen comparing the issuer, the wildcards will be replaced by \"[-_a-zA-Z0-9]+\"." }, "audience": { "type": "string", "description": "The expected audience of the OIDC token for the issuer." }, "challengeClaim": { "type": "string", "description": "The OIDC claim that must be signed for a proof of possession challenge." }, "spiffeTrustDomain": { "type": "string", "description": "The expected SPIFFE trust domain. Only present when the OIDC issuer issues tokens for SPIFFE identities." }, "issuerType": { "type": "string", "description": "The type of the IDP (e.g. \"email\", \"username\", etc.)." }, "subjectDomain": { "type": "string", "description": "The expected subject domain. Only present when the OIDC issuer issues tokens for URI or username identities." } }, "description": "Metadata about an OIDC issuer." }, "v2PublicKeyAlgorithm": { "type": "string", "enum": [ "PUBLIC_KEY_ALGORITHM_UNSPECIFIED", "RSA_PSS", "ECDSA", "ED25519" ], "default": "PUBLIC_KEY_ALGORITHM_UNSPECIFIED" }, "v2PublicKeyRequest": { "type": "object", "properties": { "publicKey": { "$ref": "#/definitions/fulciov2PublicKey", "title": "The public key to be stored in the requested certificate" }, "proofOfPossession": { "type": "string", "format": "byte", "description": "This is a currently a signature over the `sub` claim from the OIDC identity token", "title": "Proof that the client possesses the private key; must be verifiable by provided public key" } }, "required": [ "publicKey", "proofOfPossession" ] }, "v2SigningCertificate": { "type": "object", "properties": { "signedCertificateDetachedSct": { "$ref": "#/definitions/v2SigningCertificateDetachedSCT" }, "signedCertificateEmbeddedSct": { "$ref": "#/definitions/v2SigningCertificateEmbeddedSCT" } } }, "v2SigningCertificateDetachedSCT": { "type": "object", "properties": { "chain": { "$ref": "#/definitions/v2CertificateChain", "description": "The certificate chain serialized with the leaf certificate first, followed\nby all intermediate certificates (if present), finishing with the root certificate.\n\nAll values are PEM-encoded certificates." }, "signedCertificateTimestamp": { "type": "string", "format": "byte", "description": "The Signed Certificate Timestamp (SCT) is a promise for including the certificate in\na certificate transparency log. It can be \"stapled\" to verify the inclusion of\na certificate in the log in an offline fashion.\n\nThe SCT format is an AddChainResponse struct, defined in\nhttps://github.com/google/certificate-transparency-go" } } }, "v2SigningCertificateEmbeddedSCT": { "type": "object", "properties": { "chain": { "$ref": "#/definitions/v2CertificateChain", "description": "The certificate chain serialized with the leaf certificate first, followed\nby all intermediate certificates (if present), finishing with the root certificate.\n\nAll values are PEM-encoded certificates.\n\nThe leaf certificate contains an embedded Signed Certificate Timestamp (SCT) to\nverify inclusion of the certificate in a log. The SCT format is a SignedCertificateTimestampList,\nas defined in https://datatracker.ietf.org/doc/html/rfc6962#section-3.3" } } }, "v2TrustBundle": { "type": "object", "properties": { "chains": { "type": "array", "items": { "type": "object", "$ref": "#/definitions/v2CertificateChain" }, "description": "The set of PEM-encoded certificate chains for this Fulcio instance; each chain will start with any\nintermediate certificates (if present), finishing with the root certificate." } } } }, "externalDocs": { "description": "More about Fulcio", "url": "https://github.com/sigstore/fulcio" } } fulcio-1.6.5/fulcio_legacy.proto000066400000000000000000000076141470150653400167130ustar00rootroot00000000000000// // Copyright 2022 The Sigstore 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. syntax = "proto3"; package dev.sigstore.fulcio.v1beta; import "google/api/annotations.proto"; import "google/api/field_behavior.proto"; import "google/api/httpbody.proto"; import "google/protobuf/empty.proto"; import "protoc-gen-openapiv2/options/annotations.proto"; option go_package = "github.com/sigstore/fulcio/pkg/generated/protobuf/legacy"; option java_package = "dev.sigstore.fulcio.v1beta"; option java_multiple_files = true; option java_outer_classname = "FulcioProto"; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { info: { title: "Fulcio Legacy"; version: "1.0.0"; contact: { name: "sigstore Fulcio project"; url: "https://github.com/sigstore/fulcio"; email: "sigstore-dev@googlegroups.com"; }; license: { name: "Apache License 2.0"; url: "https://github.com/sigstore/fulcio/blob/main/LICENSE"; }; }; host: "fulcio.sigstore.dev"; external_docs: { url: "https://github.com/sigstore/fulcio"; description: "More about Fulcio"; }; schemes: HTTP; consumes: "application/json"; produces: "application/json"; }; /* * This implements the pre-GA HTTP-based Fulcio API. * This interface is deprecated and will only receive backports of security-related features - clients should prefer the GA GRPC interface! */ service CA { /* * Returns an X509 certificate created by the Fulcio certificate authority for the given request parameters */ rpc CreateSigningCertificate(CreateSigningCertificateRequest) returns (google.api.HttpBody){ option deprecated = true; option (google.api.http) = { post: "/api/v1/signingCert" body: "*" }; } /* * Returns the public key that can be used to validate the signed tree head */ rpc GetRootCertificate(google.protobuf.Empty) returns (google.api.HttpBody){ option deprecated = true; option (google.api.http) = { get: "/api/v1/rootCert" }; } } message CreateSigningCertificateRequest { /* * The public key to be stored in the requested certificate */ PublicKey publicKey = 1 [ deprecated=true, (google.api.field_behavior) = OPTIONAL ]; /* * Proof that the client possesses the private key */ bytes signedEmailAddress = 2 [ deprecated=true, (google.api.field_behavior) = OPTIONAL ]; /* * Optional: PKCS#10 PEM-encoded certificate signing request * Contains the public key to be stored in the requested * certificate. All other CSR fields are ignored. Since * the CSR is self-signed, it also acts as a proof of * possession of the private key. * * In particular, the CSR's subject name is not verified, or tested for * compatibility with its specified X.509 name type (e.g. email address). */ bytes certificateSigningRequest = 3 [ deprecated=true, (google.api.field_behavior) = OPTIONAL ]; } message PublicKey { /* * The cryptographic algorithm to use with the key material */ string algorithm = 1 [ deprecated=true ]; /* * PKIX, ASN.1 DER or PEM-encoded public key. PEM is typically * of type PUBLIC KEY. */ bytes content = 2 [ deprecated=true, (google.api.field_behavior) = REQUIRED ]; } fulcio-1.6.5/fulcio_legacy.swagger.json000066400000000000000000000236251470150653400201570ustar00rootroot00000000000000{ "swagger": "2.0", "info": { "title": "Fulcio Legacy", "version": "1.0.0", "contact": { "name": "sigstore Fulcio project", "url": "https://github.com/sigstore/fulcio", "email": "sigstore-dev@googlegroups.com" }, "license": { "name": "Apache License 2.0", "url": "https://github.com/sigstore/fulcio/blob/main/LICENSE" } }, "tags": [ { "name": "CA" } ], "host": "fulcio.sigstore.dev", "schemes": [ "http" ], "consumes": [ "application/json" ], "produces": [ "application/json" ], "paths": { "/api/v1/rootCert": { "get": { "summary": "Returns the public key that can be used to validate the signed tree head", "operationId": "CA_GetRootCertificate", "responses": { "200": { "description": "A successful response.", "schema": { "$ref": "#/definitions/apiHttpBody" } }, "default": { "description": "An unexpected error response.", "schema": { "$ref": "#/definitions/rpcStatus" } } }, "tags": [ "CA" ] } }, "/api/v1/signingCert": { "post": { "summary": "Returns an X509 certificate created by the Fulcio certificate authority for the given request parameters", "operationId": "CA_CreateSigningCertificate", "responses": { "200": { "description": "A successful response.", "schema": { "$ref": "#/definitions/apiHttpBody" } }, "default": { "description": "An unexpected error response.", "schema": { "$ref": "#/definitions/rpcStatus" } } }, "parameters": [ { "name": "body", "in": "body", "required": true, "schema": { "$ref": "#/definitions/fulciov1betaCreateSigningCertificateRequest" } } ], "tags": [ "CA" ] } } }, "definitions": { "apiHttpBody": { "type": "object", "properties": { "contentType": { "type": "string", "description": "The HTTP Content-Type header value specifying the content type of the body." }, "data": { "type": "string", "format": "byte", "description": "The HTTP request/response body as raw binary." }, "extensions": { "type": "array", "items": { "type": "object", "$ref": "#/definitions/protobufAny" }, "description": "Application specific response metadata. Must be set in the first response\nfor streaming APIs." } }, "description": "Message that represents an arbitrary HTTP body. It should only be used for\npayload formats that can't be represented as JSON, such as raw binary or\nan HTML page.\n\n\nThis message can be used both in streaming and non-streaming API methods in\nthe request as well as the response.\n\nIt can be used as a top-level request field, which is convenient if one\nwants to extract parameters from either the URL or HTTP template into the\nrequest fields and also want access to the raw HTTP body.\n\nExample:\n\n message GetResourceRequest {\n // A unique request id.\n string request_id = 1;\n\n // The raw HTTP body is bound to this field.\n google.api.HttpBody http_body = 2;\n\n }\n\n service ResourceService {\n rpc GetResource(GetResourceRequest)\n returns (google.api.HttpBody);\n rpc UpdateResource(google.api.HttpBody)\n returns (google.protobuf.Empty);\n\n }\n\nExample with streaming methods:\n\n service CaldavService {\n rpc GetCalendar(stream google.api.HttpBody)\n returns (stream google.api.HttpBody);\n rpc UpdateCalendar(stream google.api.HttpBody)\n returns (stream google.api.HttpBody);\n\n }\n\nUse of this type only changes how the request and response bodies are\nhandled, all other features will continue to work unchanged." }, "fulciov1betaCreateSigningCertificateRequest": { "type": "object", "properties": { "publicKey": { "$ref": "#/definitions/fulciov1betaPublicKey", "title": "The public key to be stored in the requested certificate" }, "signedEmailAddress": { "type": "string", "format": "byte", "title": "Proof that the client possesses the private key" }, "certificateSigningRequest": { "type": "string", "format": "byte", "description": "Optional: PKCS#10 PEM-encoded certificate signing request\nContains the public key to be stored in the requested\ncertificate. All other CSR fields are ignored. Since\nthe CSR is self-signed, it also acts as a proof of\npossession of the private key.\n\nIn particular, the CSR's subject name is not verified, or tested for\ncompatibility with its specified X.509 name type (e.g. email address)." } } }, "fulciov1betaPublicKey": { "type": "object", "properties": { "algorithm": { "type": "string", "title": "The cryptographic algorithm to use with the key material" }, "content": { "type": "string", "format": "byte", "description": "PKIX, ASN.1 DER or PEM-encoded public key. PEM is typically\nof type PUBLIC KEY." } }, "required": [ "content" ] }, "protobufAny": { "type": "object", "properties": { "@type": { "type": "string", "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." } }, "additionalProperties": {}, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\nExample 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\nExample 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, "rpcStatus": { "type": "object", "properties": { "code": { "type": "integer", "format": "int32" }, "message": { "type": "string" }, "details": { "type": "array", "items": { "type": "object", "$ref": "#/definitions/protobufAny" } } } } }, "externalDocs": { "description": "More about Fulcio", "url": "https://github.com/sigstore/fulcio" } } fulcio-1.6.5/go.mod000066400000000000000000000176001470150653400141230ustar00rootroot00000000000000module github.com/sigstore/fulcio go 1.23.2 require ( chainguard.dev/go-grpc-kit v0.17.6 chainguard.dev/sdk v0.1.26 cloud.google.com/go/security v1.18.1 github.com/PaesslerAG/jsonpath v0.1.1 github.com/ThalesIgnite/crypto11 v1.2.5 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/coreos/go-oidc/v3 v3.11.0 github.com/fsnotify/fsnotify v1.7.0 github.com/go-jose/go-jose/v4 v4.0.4 github.com/goadesign/goa v2.2.5+incompatible github.com/google/certificate-transparency-go v1.2.1 github.com/google/go-cmp v0.6.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99 github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 github.com/hashicorp/golang-lru v1.0.2 github.com/magiconair/properties v1.8.7 github.com/prometheus/client_golang v1.20.4 github.com/prometheus/client_model v0.6.1 github.com/prometheus/common v0.60.0 github.com/rs/cors v1.11.1 github.com/sigstore/sigstore v1.8.9 github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.9 github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.9 github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.9 github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.9 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/spiffe/go-spiffe/v2 v2.4.0 github.com/tink-crypto/tink-go-awskms/v2 v2.1.0 github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 github.com/tink-crypto/tink-go/v2 v2.2.0 go.step.sm/crypto v0.53.0 go.uber.org/zap v1.27.0 google.golang.org/api v0.199.0 google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 google.golang.org/grpc v1.67.1 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 sigs.k8s.io/release-utils v0.8.5 ) require ( cloud.google.com/go v0.115.1 // indirect cloud.google.com/go/auth v0.9.5 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect cloud.google.com/go/compute/metadata v0.5.2 // indirect cloud.google.com/go/iam v1.2.1 // indirect cloud.google.com/go/kms v1.20.0 // indirect cloud.google.com/go/longrunning v0.6.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/PaesslerAG/gval v1.0.0 // indirect github.com/aws/aws-sdk-go v1.55.5 // indirect github.com/aws/aws-sdk-go-v2 v1.31.0 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.37 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.35 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20 // indirect github.com/aws/aws-sdk-go-v2/service/kms v1.35.7 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.23.1 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.31.1 // indirect github.com/aws/smithy-go v1.21.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chainguard-dev/clog v1.5.1-0.20240811185937-4c523ae4593f // indirect github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-containerregistry v0.20.2 // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.13.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/vault/api v1.14.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jellydator/ttlcache/v3 v3.3.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect github.com/segmentio/ksuid v1.0.4 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.7.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/thales-e-security/pool v0.0.2 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect go.opentelemetry.io/otel v1.30.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect go.opentelemetry.io/otel/metric v1.30.0 // indirect go.opentelemetry.io/otel/sdk v1.29.0 // indirect go.opentelemetry.io/otel/trace v1.30.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect goa.design/goa v2.2.5+incompatible // indirect golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/term v0.24.0 // indirect golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.6.0 // indirect google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect k8s.io/klog/v2 v2.120.1 // indirect ) fulcio-1.6.5/go.sum000066400000000000000000001470121470150653400141510ustar00rootroot00000000000000chainguard.dev/go-grpc-kit v0.17.6 h1:lwIs9LmSnm8jwrH1QmigCwMP6MYkIBENq/0xGduYZss= chainguard.dev/go-grpc-kit v0.17.6/go.mod h1:ZNaXn2KEO++2u2WveHs65krYiHmAEGjYLeEtfaQaOWU= chainguard.dev/sdk v0.1.26 h1:HKBekoLX0r1mpmPmMslBZ7hcW7JUm34aHlJQNGxaQm0= chainguard.dev/sdk v0.1.26/go.mod h1:n2kEb/0aR3Pa6CQ1m2GgItfE5mVXraYxmknX2V4PtuI= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= cloud.google.com/go/auth v0.9.5 h1:4CTn43Eynw40aFVr3GpPqsQponx2jv0BQpjvajsbbzw= cloud.google.com/go/auth v0.9.5/go.mod h1:Xo0n7n66eHyOWWCnitop6870Ilwo3PiZyodVkkH1xWM= cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU= cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g= cloud.google.com/go/kms v1.20.0 h1:uKUvjGqbBlI96xGE669hcVnEMw1Px/Mvfa62dhM5UrY= cloud.google.com/go/kms v1.20.0/go.mod h1:/dMbFF1tLLFnQV44AoI2GlotbjowyUfgVwezxW291fM= cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc= cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= cloud.google.com/go/security v1.18.1 h1:w7XbMR90Ir0y8NUxKJ3uyRHuHYWPUxVI5Z/sGqbrdAQ= cloud.google.com/go/security v1.18.1/go.mod h1:5P1q9rqwt0HuVeL9p61pTqQ6Lgio1c64jL2ZMWZV21Y= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0 h1:DRiANoJTiW6obBQe3SqZizkuV1PEgfiiGivmVocDy64= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0/go.mod h1:qLIye2hwb/ZouqhpSD9Zn3SJipvpEnz1Ywl3VUk9Y0s= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/PaesslerAG/gval v1.0.0 h1:GEKnRwkWDdf9dOmKcNrar9EA1bz1z9DqPIO1+iLzhd8= github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk= github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY= github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY+9ef8E= github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.31.0 h1:3V05LbxTSItI5kUqNwhJrrrY1BAXxXt0sN0l72QmG5U= github.com/aws/aws-sdk-go-v2 v1.31.0/go.mod h1:ztolYtaEUtdpf9Wftr31CJfLVjOnD/CVRkKOOYgF8hA= github.com/aws/aws-sdk-go-v2/config v1.27.37 h1:xaoIwzHVuRWRHFI0jhgEdEGc8xE1l91KaeRDsWEIncU= github.com/aws/aws-sdk-go-v2/config v1.27.37/go.mod h1:S2e3ax9/8KnMSyRVNd3sWTKs+1clJ2f1U6nE0lpvQRg= github.com/aws/aws-sdk-go-v2/credentials v1.17.35 h1:7QknrZhYySEB1lEXJxGAmuD5sWwys5ZXNr4m5oEz0IE= github.com/aws/aws-sdk-go-v2/credentials v1.17.35/go.mod h1:8Vy4kk7at4aPSmibr7K+nLTzG6qUQAUO4tW49fzUV4E= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 h1:C/d03NAmh8C4BZXhuRNboF/DqhBkBCeDiJDcaqIT5pA= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14/go.mod h1:7I0Ju7p9mCIdlrfS+JCgqcYD0VXz/N4yozsox+0o078= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 h1:kYQ3H1u0ANr9KEKlGs/jTLrBFPo8P8NaH/w7A01NeeM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18/go.mod h1:r506HmK5JDUh9+Mw4CfGJGSSoqIiLCndAuqXuhbv67Y= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 h1:Z7IdFUONvTcvS7YuhtVxN99v2cCoHRXOS4mTr0B/pUc= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18/go.mod h1:DkKMmksZVVyat+Y+r1dEOgJEfUeA7UngIHWeKsi0yNc= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 h1:QFASJGfT8wMXtuP3D5CRmMjARHv9ZmzFUMJznHDOY3w= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5/go.mod h1:QdZ3OmoIjSX+8D1OPAzPxDfjXASbBMDsz9qvtyIhtik= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20 h1:Xbwbmk44URTiHNx6PNo0ujDE6ERlsCKJD3u1zfnzAPg= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20/go.mod h1:oAfOFzUB14ltPZj1rWwRc3d/6OgD76R8KlvU3EqM9Fg= github.com/aws/aws-sdk-go-v2/service/kms v1.35.7 h1:v0D1LeMkA/X+JHAZWERrr+sUGOt8KrCZKnJA6KszkcE= github.com/aws/aws-sdk-go-v2/service/kms v1.35.7/go.mod h1:K9lwD0Rsx9+NSaJKsdAdlDK4b2G4KKOEve9PzHxPoMI= github.com/aws/aws-sdk-go-v2/service/sso v1.23.1 h1:2jrVsMHqdLD1+PA4BA6Nh1eZp0Gsy3mFSB5MxDvcJtU= github.com/aws/aws-sdk-go-v2/service/sso v1.23.1/go.mod h1:XRlMvmad0ZNL+75C5FYdMvbbLkd6qiqz6foR1nA1PXY= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.1 h1:0L7yGCg3Hb3YQqnSgBTZM5wepougtL1aEccdcdYhHME= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.1/go.mod h1:FnvDM4sfa+isJ3kDXIzAB9GAwVSzFzSy97uZ3IsHo4E= github.com/aws/aws-sdk-go-v2/service/sts v1.31.1 h1:8K0UNOkZiK9Uh3HIF6Bx0rcNCftqGCeKmOaR7Gp5BSo= github.com/aws/aws-sdk-go-v2/service/sts v1.31.1/go.mod h1:yMWe0F+XG0DkRZK5ODZhG7BEFYhLXi2dqGsv6tX0cgI= github.com/aws/smithy-go v1.21.0 h1:H7L8dtDRk0P1Qm6y0ji7MCYMQObJ5R9CRpyPhRUkLYA= github.com/aws/smithy-go v1.21.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chainguard-dev/clog v1.5.1-0.20240811185937-4c523ae4593f h1:xRgn6phdh0RY1neJcftPVEcmb2AbvMvPZF44bFkxi+0= github.com/chainguard-dev/clog v1.5.1-0.20240811185937-4c523ae4593f/go.mod h1:4+WFhRMsGH79etYXY3plYdp+tCz/KCkU8fAr0HoaPvs= 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/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/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.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 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-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA= github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/goadesign/goa v2.2.5+incompatible h1:SLgzk0V+QfFs7MVz9sbDHelbTDI9B/d4W7Hl5udTynY= github.com/goadesign/goa v2.2.5+incompatible/go.mod h1:d/9lpuZBK7HFi/7O0oXfwvdoIl+nx2bwKqctZe/lQao= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= 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.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.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.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/certificate-transparency-go v1.2.1 h1:4iW/NwzqOqYEEoCBEFP+jPbBXbLqMpq3CifMyOnDUME= github.com/google/certificate-transparency-go v1.2.1/go.mod h1:bvn/ytAccv+I6+DGkqpvSsEdiVGramgaSC6RD3tEmeE= 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.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l/DSArMxlbwseo= github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8= github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99 h1:JYghRBlGCZyCF2wNUJ8W0cwaQdtpcssJ4CgC406g+WU= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= 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 v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 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.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/vault/api v1.14.0 h1:Ah3CFLixD5jmjusOgm8grfN9M0d+Y8fVR2SW0K6pJLU= github.com/hashicorp/vault/api v1.14.0/go.mod h1:pV9YLxBGSz+cItFDd8Ii4G17waWOQ32zVjMWHe/cOqk= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc= github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw= 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/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI= 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.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec h1:2tTW6cDth2TSgRbAhD7yjZzTQmcN25sDRPEeinR51yQ= github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec/go.mod h1:TmwEoGCwIti7BCeJ9hescZgRtatxRE+A72pCoPfmcfk= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 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.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= 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/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= 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/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 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/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA= github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/secure-systems-lab/go-securesystemslib v0.8.0 h1:mr5An6X45Kb2nddcFlbmfHkLguCE9laoZCUzEEpIZXA= github.com/secure-systems-lab/go-securesystemslib v0.8.0/go.mod h1:UH2VZVuJfCYR8WgMlCU1uFsOUU+KeyrTWcSS73NBOzU= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= github.com/sigstore/sigstore v1.8.9 h1:NiUZIVWywgYuVTxXmRoTT4O4QAGiTEKup4N1wdxFadk= github.com/sigstore/sigstore v1.8.9/go.mod h1:d9ZAbNDs8JJfxJrYmulaTazU3Pwr8uLL9+mii4BNR3w= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.9 h1:tgpdvjyoEgYFeTBFe4MHvBKsG+J4E7NVtstChIExVT8= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.9/go.mod h1:wCz6cAZKL/wFumDHX9l8VkVITS2GntrOfs2j/kwH4wo= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.9 h1:eXFm3cte0hvxxYsvGpCMd7aBusEgKJdlUw1Fb5AZQpw= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.9/go.mod h1:RYy9GKnFKKwqbg3Uc6rUyhQdichSVkFlfxnY6f7cAWc= github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.9 h1:liWcl12dfFeQXU0JemQVgdVQx02Fls9UPdrFzVrCWhs= github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.9/go.mod h1:Ckx62auqPQvNJWRBAboY+/kHs77gy6L33b6UtB/FB5U= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.9 h1:E+bvFTS6uM//iSAeneNj5pubzntQmio/yAKFzmRzzD0= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.9/go.mod h1:0RKVuZXIZAFhT0frfx+GzyrtlesiRK3ceF55nIgkZI4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= 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/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/spiffe/go-spiffe/v2 v2.4.0 h1:j/FynG7hi2azrBG5cvjRcnQ4sux/VNj8FAVc99Fl66c= github.com/spiffe/go-spiffe/v2 v2.4.0/go.mod h1:m5qJ1hGzjxjtrkGHZupoXHo/FDWwCB1MdSyBzfHugx0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= github.com/tink-crypto/tink-go-awskms/v2 v2.1.0 h1:N9UxlsOzu5mttdjhxkDLbzwtEecuXmlxZVo/ds7JKJI= github.com/tink-crypto/tink-go-awskms/v2 v2.1.0/go.mod h1:PxSp9GlOkKL9rlybW804uspnHuO9nbD98V/fDX4uSis= github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 h1:3B9i6XBXNTRspfkTC0asN5W0K6GhOSgcujNiECNRNb0= github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0/go.mod h1:jY5YN2BqD/KSCHM9SqZPIpJNG/u3zwfLXHgws4x2IRw= github.com/tink-crypto/tink-go/v2 v2.2.0 h1:L2Da0F2Udh2agtKztdr69mV/KpnY3/lGTkMgLTVIXlA= github.com/tink-crypto/tink-go/v2 v2.2.0/go.mod h1:JJ6PomeNPF3cJpfWC0lgyTES6zpJILkAX0cJNwlS3xU= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns= github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= github.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q= github.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg= github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU= github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 h1:hCq2hNMwsegUvPzI7sPOvtO9cqyy5GbWt/Ybp2xrx8Q= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0/go.mod h1:LqaApwGx/oUmzsbqxkzuBvyoPpkxk3JQWnqfVrJ3wCA= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI= go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0= go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.step.sm/crypto v0.53.0 h1:+1as1ogzuCzx15/468M4mEC5juogI5a0Fzbsyh1CuYY= go.step.sm/crypto v0.53.0/go.mod h1:AqLU78RqNUHepLzyOWZuNN/2++Lu7dZENdO9UzWOGSk= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= goa.design/goa v2.2.5+incompatible h1:mjAtiy7ZdZIkj974hpFxCR6bL69qprfV00Veu3Vybts= goa.design/goa v2.2.5+incompatible/go.mod h1:NnzBwdNktihbNek+pPiFMQP9PPFsUt8MMPPyo9opDSo= 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= 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/lint v0.0.0-20190930215403-16217165b5de/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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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-20181201002055-351d144fa1fc/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-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-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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 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-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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/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-20210615035016-665e8c7367d1/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 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/api v0.199.0 h1:aWUXClp+VFJmqE0JPvpZOK3LDQMyFKYIow4etYd9qxs= google.golang.org/api v0.199.0/go.mod h1:ohG4qSztDJmZdjK/Ar6MhbAmb/Rpi4JHOqagsh90K28= 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/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-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU= google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= 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.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= 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.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/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-20210107192922-496545a6307b/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= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 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/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= sigs.k8s.io/release-utils v0.8.5 h1:FUtFqEAN621gSXv0L7kHyWruBeS7TUU9aWf76olX7uQ= sigs.k8s.io/release-utils v0.8.5/go.mod h1:qsm5bdxdgoHkD8HsXpgme2/c3mdsNaiV53Sz2HmKeJA= fulcio-1.6.5/hack/000077500000000000000000000000001470150653400137175ustar00rootroot00000000000000fulcio-1.6.5/hack/github-oidc-setup.sh000077500000000000000000000066371470150653400176260ustar00rootroot00000000000000#!/usr/bin/env bash # Copyright 2022 The Sigstore 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. # Idempotent script. # # Commands based off of Google blog post # https://cloud.google.com/blog/products/identity-security/enabling-keyless-authentication-from-github-actions # # One addition is the attribute.repository=assertion.repository mapping. # This allows it to be pinned to given repo. set -o errexit set -o nounset set -o pipefail set -o verbose set -o xtrace PROJECT_ID="projectsigstore" PROJECT_NUMBER="498091336538" POOL_NAME="githubactions" PROVIDER_NAME="sigstore-fulcio" LOCATION="global" REPO="sigstore/fulcio" SERVICE_ACCOUNT_ID="github-actions-fulcio" SERVICE_ACCOUNT="${SERVICE_ACCOUNT_ID}@${PROJECT_ID}.iam.gserviceaccount.com" # Create workload identity pool if not present. if ! (gcloud iam workload-identity-pools describe "${POOL_NAME}" --location=${LOCATION}); then gcloud iam workload-identity-pools create "${POOL_NAME}" \ --project="${PROJECT_ID}" \ --location="${LOCATION}" \ --display-name="Github Actions Pool" fi # Create workload identity provider if not present. if ! (gcloud iam workload-identity-pools providers describe "${PROVIDER_NAME}" --location="${LOCATION}" --workload-identity-pool="${POOL_NAME}"); then gcloud iam workload-identity-pools providers create-oidc "${PROVIDER_NAME}" \ --project="${PROJECT_ID}" \ --location="${LOCATION}" \ --workload-identity-pool="${POOL_NAME}" \ --display-name="Github Actions Provider Fulcio" \ --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.aud=assertion.aud,attribute.repository=assertion.repository" \ --issuer-uri="https://token.actions.githubusercontent.com" fi # Create service account if not present. if ! (gcloud iam service-accounts describe "${SERVICE_ACCOUNT}"); then gcloud iam service-accounts create ${SERVICE_ACCOUNT_ID} \ --description="Service account for Github Actions Fulcio" \ --display-name="Github Actions Fulcio" fi # Adding binding is idempotent. gcloud iam service-accounts add-iam-policy-binding "${SERVICE_ACCOUNT}" \ --project="${PROJECT_ID}" \ --role="roles/iam.workloadIdentityUser" \ --member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/${LOCATION}/workloadIdentityPools/${POOL_NAME}/attribute.repository/${REPO}" # Adding binding is idempotent. # Used for kicking off cloud build. gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --project="${PROJECT_ID}" \ --role="roles/cloudbuild.builds.editor" \ --member="serviceAccount:${SERVICE_ACCOUNT}" # Adding binding is idempotent. # Permission needed to run `gcloud builds` # https://cloud.google.com/build/docs/securing-builds/configure-access-to-resources#granting_permissions_to_run_gcloud_commands gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --project="${PROJECT_ID}" \ --role="roles/serviceusage.serviceUsageConsumer" \ --member="serviceAccount:${SERVICE_ACCOUNT}" fulcio-1.6.5/hack/tools/000077500000000000000000000000001470150653400150575ustar00rootroot00000000000000fulcio-1.6.5/hack/tools/go.mod000066400000000000000000000024641470150653400161730ustar00rootroot00000000000000module github.com/sigstore/fulcio/hack/tools go 1.22.5 require ( github.com/googleapis/api-linter v1.67.3 github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 google.golang.org/protobuf v1.34.2 ) require ( bitbucket.org/creachadair/stringset v0.0.12 // indirect cloud.google.com/go/longrunning v0.5.7 // indirect github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect github.com/bufbuild/protocompile v0.10.0 // indirect github.com/gertd/go-pluralize v0.2.1 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/jhump/protoreflect v1.16.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/text v0.17.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/grpc v1.65.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) fulcio-1.6.5/hack/tools/go.sum000066400000000000000000000153601470150653400162170ustar00rootroot00000000000000bitbucket.org/creachadair/stringset v0.0.12 h1:APD8dIoAzGv70a6p1oasPDjPwkp+ajszdgKyWUcNqo0= bitbucket.org/creachadair/stringset v0.0.12/go.mod h1:KtNk2s0hRO1T0r78lv9Zq/S/Lp0du2zI0Fj5j5Y4LDo= cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuAKilhU= cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM= github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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/gertd/go-pluralize v0.2.1 h1:M3uASbVjMnTsPb0PNqg+E/24Vwigyo/tvyMTtAlLgiA= github.com/gertd/go-pluralize v0.2.1/go.mod h1:rbYaKDbsXxmRfr8uygAEKhOWsjyrrqrkHVpZvoOp8zk= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/googleapis/api-linter v1.67.3 h1:2GNX2xDx6f1Xb8UWNas1neN0i2N356wvgBwdR1i59R0= github.com/googleapis/api-linter v1.67.3/go.mod h1:FXkj1Z78//S3ydG9T9fUnw3F6wdFo/V5RUiAxhJfAvw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg= github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= 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/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= 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.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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= google.golang.org/genproto v0.0.0-20240521202816-d264139d666e h1:axIBUGXSVho2zB+3tJj8l9Qvm/El5vVYPYqhGA5PmJM= google.golang.org/genproto v0.0.0-20240521202816-d264139d666e/go.mod h1:gOvX/2dWTqh+u3+IHjFeCxinlz5AZ5qhOufbQPub/dE= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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= fulcio-1.6.5/hack/tools/tools.go000066400000000000000000000020431470150653400165450ustar00rootroot00000000000000//go:build tools // +build tools // Copyright 2022 The Sigstore 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. // // This package imports things required by build scripts, to force `go mod` to see them as dependencies package tools import ( _ "github.com/googleapis/api-linter/cmd/api-linter" _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway" _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2" _ "google.golang.org/grpc/cmd/protoc-gen-go-grpc" _ "google.golang.org/protobuf/cmd/protoc-gen-go" ) fulcio-1.6.5/main.go000066400000000000000000000013311470150653400142620ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 main import ( "context" "github.com/sigstore/fulcio/cmd/app" ) func main() { app.Execute(context.Background()) } fulcio-1.6.5/pkg/000077500000000000000000000000001470150653400135725ustar00rootroot00000000000000fulcio-1.6.5/pkg/api/000077500000000000000000000000001470150653400143435ustar00rootroot00000000000000fulcio-1.6.5/pkg/api/client.go000066400000000000000000000134371470150653400161600ustar00rootroot00000000000000// // Copyright 2021 The Sigstore 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 api import ( "bytes" "encoding/base64" "encoding/json" "encoding/pem" "errors" "fmt" "io" "net/http" "net/url" "path" "time" ) type CertificateResponse struct { CertPEM []byte ChainPEM []byte SCT []byte } type RootResponse struct { ChainPEM []byte } type Key struct { // +required Content []byte `json:"content"` Algorithm string `json:"algorithm,omitempty"` } type CertificateRequest struct { // +optional PublicKey Key `json:"publicKey"` // +optional SignedEmailAddress []byte `json:"signedEmailAddress"` // +optional CertificateSigningRequest []byte `json:"certificateSigningRequest"` } const ( signingCertPath = "/api/v1/signingCert" rootCertPath = "/api/v1/rootCert" ) // SigstorePublicServerURL is the URL of Sigstore's public Fulcio service. const SigstorePublicServerURL = "https://fulcio.sigstore.dev" // LegacyClient is the interface for accessing the Fulcio API. type LegacyClient interface { // SigningCert sends the provided CertificateRequest to the /api/v1/signingCert // endpoint of a Fulcio API, authenticated with the provided bearer token. SigningCert(cr CertificateRequest, token string) (*CertificateResponse, error) // RootCert sends a request to get the current CA used by Fulcio. RootCert() (*RootResponse, error) } // ClientOption is a functional option for customizing static signatures. type ClientOption func(*clientOptions) // NewClient creates a new Fulcio API client talking to the provided URL. func NewClient(url *url.URL, opts ...ClientOption) LegacyClient { o := makeOptions(opts...) return &client{ baseURL: url, client: &http.Client{ Transport: createRoundTripper(http.DefaultTransport, o), Timeout: o.Timeout, }, } } type client struct { baseURL *url.URL client *http.Client } var _ LegacyClient = (*client)(nil) // SigningCert implements Client func (c *client) SigningCert(cr CertificateRequest, token string) (*CertificateResponse, error) { // Construct the API endpoint for this handler endpoint := *c.baseURL endpoint.Path = path.Join(endpoint.Path, signingCertPath) b, err := json.Marshal(cr) if err != nil { return nil, fmt.Errorf("marshal: %w", err) } req, err := http.NewRequest(http.MethodPost, endpoint.String(), bytes.NewBuffer(b)) if err != nil { return nil, fmt.Errorf("request: %w", err) } // Set the authorization header to our OIDC bearer token. req.Header.Set("Authorization", "Bearer "+token) // Set the content-type to reflect we're sending JSON. req.Header.Set("Content-Type", "application/json") resp, err := c.client.Do(req) if err != nil { return nil, fmt.Errorf("client: %w", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("%s read: %w", endpoint.String(), err) } // The API should return a 201 Created on success. If we see anything else, // then turn the response body into an error. if resp.StatusCode != http.StatusCreated { return nil, fmt.Errorf("%s %s returned %s: %q", http.MethodPost, endpoint.String(), resp.Status, body) } // Extract the SCT from the response header. sct, err := base64.StdEncoding.DecodeString(resp.Header.Get("SCT")) if err != nil { return nil, fmt.Errorf("decode: %w", err) } // Split the cert and the chain certBlock, chainPem := pem.Decode(body) if certBlock == nil { return nil, errors.New("did not find a cert from Fulcio") } certPem := pem.EncodeToMemory(certBlock) return &CertificateResponse{ CertPEM: certPem, ChainPEM: chainPem, SCT: sct, }, nil } func (c *client) RootCert() (*RootResponse, error) { // Construct the API endpoint for this handler endpoint := *c.baseURL endpoint.Path = path.Join(endpoint.Path, rootCertPath) req, err := http.NewRequest(http.MethodGet, endpoint.String(), nil) if err != nil { return nil, fmt.Errorf("request: %w", err) } resp, err := c.client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, err } if resp.StatusCode != http.StatusOK { return nil, errors.New(string(body)) } return &RootResponse{ChainPEM: body}, nil } type clientOptions struct { UserAgent string Timeout time.Duration } func makeOptions(opts ...ClientOption) *clientOptions { o := &clientOptions{ UserAgent: "", } for _, opt := range opts { opt(o) } return o } // WithTimeout sets the request timeout for the client func WithTimeout(timeout time.Duration) ClientOption { return func(o *clientOptions) { o.Timeout = timeout } } // WithUserAgent sets the media type of the signature. func WithUserAgent(userAgent string) ClientOption { return func(o *clientOptions) { o.UserAgent = userAgent } } type roundTripper struct { http.RoundTripper UserAgent string } // RoundTrip implements `http.RoundTripper` func (rt *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { req.Header.Set("User-Agent", rt.UserAgent) return rt.RoundTripper.RoundTrip(req) } func createRoundTripper(inner http.RoundTripper, o *clientOptions) http.RoundTripper { if inner == nil { inner = http.DefaultTransport } if o.UserAgent == "" { // There's nothing to do... return inner } return &roundTripper{ RoundTripper: inner, UserAgent: o.UserAgent, } } fulcio-1.6.5/pkg/api/client_test.go000066400000000000000000000031511470150653400172070ustar00rootroot00000000000000// // Copyright 2021 The Sigstore 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 package api import ( "net/http" "net/http/httptest" "strings" "testing" "time" ) func TestUserAgentOption(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { if r.Header.Get("User-Agent") != "foo" { t.Error(`expected user-agent to be set to "foo"`) } })) lc := NewClient(nil, WithUserAgent("foo")) c, ok := lc.(*client) if !ok { t.Fatal("wrong legacy client implementation") } _, err := c.client.Get(ts.URL) if err != nil { t.Fatal(err) } } func TestTimeoutOption(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { time.Sleep(10 * time.Second) })) lc := NewClient(nil, WithTimeout(time.Second)) c, ok := lc.(*client) if !ok { t.Fatal("wrong legacy client implementation") } _, err := c.client.Get(ts.URL) if err == nil { t.Error("expected client to get timeout error on request") } if strings.HasPrefix(err.Error(), "context deadline exceeded") { t.Error("expected client to specifically have a timeout error") } } fulcio-1.6.5/pkg/ca/000077500000000000000000000000001470150653400141555ustar00rootroot00000000000000fulcio-1.6.5/pkg/ca/baseca/000077500000000000000000000000001470150653400153735ustar00rootroot00000000000000fulcio-1.6.5/pkg/ca/baseca/baseca.go000066400000000000000000000107011470150653400171370ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 baseca import ( "context" "crypto" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" ct "github.com/google/certificate-transparency-go" cttls "github.com/google/certificate-transparency-go/tls" ctx509 "github.com/google/certificate-transparency-go/x509" "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/identity" ) var ( // OIDExtensionCTPoison is defined in RFC 6962 s3.1. OIDExtensionCTPoison = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3} // OIDExtensionCTSCT is defined in RFC 6962 s3.3. OIDExtensionCTSCT = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 2} ) type BaseCA struct { // contains the chain of certificates and signer ca.SignerWithChain } func (bca *BaseCA) CreatePrecertificate(ctx context.Context, principal identity.Principal, publicKey crypto.PublicKey) (*ca.CodeSigningPreCertificate, error) { cert, err := ca.MakeX509(ctx, principal, publicKey) if err != nil { return nil, err } certChain, privateKey := bca.GetSignerWithChain() // Append poison extension cert.ExtraExtensions = append(cert.ExtraExtensions, pkix.Extension{ Id: OIDExtensionCTPoison, Critical: true, Value: asn1.NullBytes, }) finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, certChain[0], publicKey, privateKey) if err != nil { return nil, err } csc, err := ca.CreateCSCFromDER(finalCertBytes, certChain) if err != nil { return nil, err } return &ca.CodeSigningPreCertificate{ PreCert: csc.FinalCertificate, CertChain: csc.FinalChain, PrivateKey: privateKey, }, nil } // From https://github.com/letsencrypt/boulder/blob/54b697d51b9f63cfd6055577cd317d4096aeab08/issuance/issuance.go#L497 func generateSCTListExt(scts []ct.SignedCertificateTimestamp) (pkix.Extension, error) { list := ctx509.SignedCertificateTimestampList{} for _, sct := range scts { sctBytes, err := cttls.Marshal(sct) if err != nil { return pkix.Extension{}, err } list.SCTList = append(list.SCTList, ctx509.SerializedSCT{Val: sctBytes}) } listBytes, err := cttls.Marshal(list) if err != nil { return pkix.Extension{}, err } extBytes, err := asn1.Marshal(listBytes) if err != nil { return pkix.Extension{}, err } return pkix.Extension{ Id: OIDExtensionCTSCT, Value: extBytes, }, nil } func (bca *BaseCA) IssueFinalCertificate(_ context.Context, precert *ca.CodeSigningPreCertificate, sct *ct.SignedCertificateTimestamp) (*ca.CodeSigningCertificate, error) { // remove poison extension from precertificate. var exts []pkix.Extension for _, ext := range precert.PreCert.Extensions { if !ext.Id.Equal(OIDExtensionCTPoison) { exts = append(exts, ext) } } // append SCT extension. Supports multiple SCTs, but Fulcio only writes to one log currently. sctExt, err := generateSCTListExt([]ct.SignedCertificateTimestamp{*sct}) if err != nil { return nil, err } exts = append(exts, sctExt) cert := precert.PreCert cert.ExtraExtensions = exts finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, precert.CertChain[0], precert.PreCert.PublicKey, precert.PrivateKey) if err != nil { return nil, err } return ca.CreateCSCFromDER(finalCertBytes, precert.CertChain) } func (bca *BaseCA) CreateCertificate(ctx context.Context, principal identity.Principal, publicKey crypto.PublicKey) (*ca.CodeSigningCertificate, error) { cert, err := ca.MakeX509(ctx, principal, publicKey) if err != nil { return nil, err } certChain, privateKey := bca.GetSignerWithChain() finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, certChain[0], publicKey, privateKey) if err != nil { return nil, err } return ca.CreateCSCFromDER(finalCertBytes, certChain) } func (bca *BaseCA) TrustBundle(_ context.Context) ([][]*x509.Certificate, error) { certs, _ := bca.GetSignerWithChain() return [][]*x509.Certificate{certs}, nil } func (bca *BaseCA) Close() error { return nil } fulcio-1.6.5/pkg/ca/baseca/baseca_test.go000066400000000000000000000114771470150653400202110ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 baseca import ( "context" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "encoding/asn1" "reflect" "testing" ct "github.com/google/certificate-transparency-go" "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/test" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" ) func TestBaseCARoot(t *testing.T) { signer, _, err := signature.NewDefaultECDSASignerVerifier() if err != nil { t.Fatalf("unexpected error generating signer: %v", err) } rootCert, rootKey, _ := test.GenerateRootCA() subCert, _, _ := test.GenerateSubordinateCA(rootCert, rootKey) certChain := []*x509.Certificate{subCert, rootCert} bca := BaseCA{ SignerWithChain: &ca.SignerCerts{Certs: certChain, Signer: signer}, } rootChains, err := bca.TrustBundle(context.TODO()) if err != nil { t.Fatalf("unexpected error reading root: %v", err) } if len(rootChains) != 1 { t.Fatalf("unexpected number of chains: %d", len(rootChains)) } if !reflect.DeepEqual(certChain, rootChains[0]) { t.Fatal("expected cert chains to be equivalent") } } func TestBaseCAGetSignerWithChain(t *testing.T) { signer, _, err := signature.NewDefaultECDSASignerVerifier() if err != nil { t.Fatalf("unexpected error generating signer: %v", err) } rootCert, rootKey, _ := test.GenerateRootCA() subCert, _, _ := test.GenerateSubordinateCA(rootCert, rootKey) certChain := []*x509.Certificate{subCert, rootCert} bca := BaseCA{ SignerWithChain: &ca.SignerCerts{Certs: certChain, Signer: signer}, } foundCertChain, foundSigner := bca.GetSignerWithChain() if !reflect.DeepEqual(certChain, foundCertChain) { t.Fatal("expected cert chains to be equivalent") } if err := cryptoutils.EqualKeys(signer.Public(), foundSigner.Public()); err != nil { t.Fatalf("expected keys to be equivalent, expected %v, got %v, error %v", signer.Public(), foundSigner.Public(), err) } } type testPrincipal struct{} func (tp testPrincipal) Name(context.Context) string { return "doesntmatter" } func (tp testPrincipal) Embed(_ context.Context, cert *x509.Certificate) (err error) { cert.EmailAddresses = []string{"alice@example.com"} cert.ExtraExtensions, err = certificate.Extensions{ Issuer: "example.com", }.Render() return } func TestCreatePrecertificateAndIssueFinalCertificate(t *testing.T) { rootCert, rootKey, _ := test.GenerateRootCA() subCert, subKey, _ := test.GenerateSubordinateCA(rootCert, rootKey) priv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) certChain := []*x509.Certificate{subCert, rootCert} bca := BaseCA{ SignerWithChain: &ca.SignerCerts{Certs: certChain, Signer: subKey}, } precsc, err := bca.CreatePrecertificate(context.TODO(), testPrincipal{}, priv.Public()) if err != nil { t.Fatalf("error generating precertificate: %v", err) } if !subKey.Equal(precsc.PrivateKey) { t.Fatal("subordinate private keys are not equal") } if !reflect.DeepEqual(certChain, precsc.CertChain) { t.Fatal("certificate chains are not equal") } // check cert doesn't verify due to poison extension rootPool := x509.NewCertPool() rootPool.AddCert(precsc.CertChain[1]) subPool := x509.NewCertPool() subPool.AddCert(precsc.CertChain[0]) _, err = precsc.PreCert.Verify(x509.VerifyOptions{Roots: rootPool, Intermediates: subPool, KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}}) if err == nil || err.Error() != "x509: unhandled critical extension" { t.Fatalf("expected unhandled critical ext error, got %v", err) } csc, err := bca.IssueFinalCertificate(context.TODO(), precsc, &ct.SignedCertificateTimestamp{SCTVersion: 1}) if err != nil { t.Fatalf("error issuing certificate: %v", err) } // verify will now work since poison extension is removed _, err = csc.FinalCertificate.Verify(x509.VerifyOptions{Roots: rootPool, Intermediates: subPool, KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}}) if err != nil { t.Fatalf("unexpected error verifying final certificate: %v", err) } var foundSct bool for _, ext := range csc.FinalCertificate.Extensions { if ext.Id.Equal(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 2}) { foundSct = true } } if !foundSct { t.Fatal("expected SCT extension to be in certificate") } } fulcio-1.6.5/pkg/ca/ca.go000066400000000000000000000020261470150653400150670ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 ca import ( "context" "crypto" "crypto/x509" "github.com/sigstore/fulcio/pkg/identity" ) // CertificateAuthority implements certificate creation with a detached SCT and // fetching the CA trust bundle. type CertificateAuthority interface { CreateCertificate(context.Context, identity.Principal, crypto.PublicKey) (*CodeSigningCertificate, error) TrustBundle(ctx context.Context) ([][]*x509.Certificate, error) Close() error } fulcio-1.6.5/pkg/ca/common.go000066400000000000000000000054031470150653400157760ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 ca import ( "context" "crypto" "crypto/x509" "errors" "time" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/sigstore/pkg/cryptoutils" ) func MakeX509(ctx context.Context, principal identity.Principal, publicKey crypto.PublicKey) (*x509.Certificate, error) { serialNumber, err := cryptoutils.GenerateSerialNumber() if err != nil { return nil, err } skid, err := cryptoutils.SKID(publicKey) if err != nil { return nil, err } cert := &x509.Certificate{ SerialNumber: serialNumber, NotBefore: time.Now(), NotAfter: time.Now().Add(time.Minute * 10), SubjectKeyId: skid, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, KeyUsage: x509.KeyUsageDigitalSignature, } err = principal.Embed(ctx, cert) if err != nil { return nil, ValidationError(err) } return cert, nil } func VerifyCertChain(certs []*x509.Certificate, signer crypto.Signer) error { if len(certs) == 0 { return errors.New("certificate chain must contain at least one certificate") } roots := x509.NewCertPool() roots.AddCert(certs[len(certs)-1]) intermediates := x509.NewCertPool() if len(certs) > 1 { for _, intermediate := range certs[1 : len(certs)-1] { intermediates.AddCert(intermediate) } } opts := x509.VerifyOptions{ Roots: roots, Intermediates: intermediates, KeyUsages: []x509.ExtKeyUsage{ x509.ExtKeyUsageCodeSigning, }, } if _, err := certs[0].Verify(opts); err != nil { return err } if !certs[0].IsCA { return errors.New("certificate is not a CA") } // If using an intermediate, verify that code signing extended key // usage is set to satify extended key usage chainging if len(certs) > 1 { var hasExtKeyUsageCodeSigning bool for _, extKeyUsage := range certs[0].ExtKeyUsage { if extKeyUsage == x509.ExtKeyUsageCodeSigning { hasExtKeyUsageCodeSigning = true break } } if !hasExtKeyUsageCodeSigning { return errors.New(`certificate must have extended key usage code signing set to sign code signing certificates`) } } if err := cryptoutils.EqualKeys(certs[0].PublicKey, signer.Public()); err != nil { return err } return cryptoutils.ValidatePubKey(signer.Public()) } fulcio-1.6.5/pkg/ca/common_test.go000066400000000000000000000117031470150653400170350ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 ca import ( "context" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "strings" "testing" "time" "github.com/sigstore/fulcio/pkg/test" "github.com/sigstore/sigstore/pkg/signature" ) // cannot use ChallengeResult due to import cycle type testPrincipal struct { } func (t *testPrincipal) Name(_ context.Context) string { return "test" } func (t *testPrincipal) Embed(_ context.Context, cert *x509.Certificate) error { cert.EmailAddresses = []string{"test@example.com"} return nil } func TestMakeX509(t *testing.T) { key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("unexpected error generating key: %v", err) } cert, err := MakeX509(context.TODO(), &testPrincipal{}, key.Public()) if err != nil { t.Fatalf("unexpected error calling MakeX509: %v", err) } if cert.SerialNumber == nil { t.Fatalf("expected serial number") } if cert.NotAfter.Sub(cert.NotBefore) < time.Minute*10 { t.Fatalf("expected CA to have 10 minute lifetime, got %v", cert.NotAfter.Sub(cert.NotBefore)) } if len(cert.SubjectKeyId) == 0 { t.Fatalf("expected subject key ID") } if len(cert.ExtKeyUsage) != 1 || cert.ExtKeyUsage[0] != x509.ExtKeyUsageCodeSigning { t.Fatalf("expected code signing extended key usage, got %v", cert.ExtKeyUsage) } if cert.KeyUsage != x509.KeyUsageDigitalSignature { t.Fatalf("expected digital signature key usage, got %v", cert.KeyUsage) } // test that Embed is called if len(cert.EmailAddresses) != 1 { t.Fatalf("expected email in subject alt name, got %v", cert.EmailAddresses) } } func TestVerifyCertChain(t *testing.T) { rootCert, rootKey, _ := test.GenerateRootCA() subCert, subKey, _ := test.GenerateSubordinateCA(rootCert, rootKey) leafCert, _, _ := test.GenerateLeafCert("subject", "oidc-issuer", subCert, subKey) err := VerifyCertChain([]*x509.Certificate{subCert, rootCert}, subKey) if err != nil { t.Fatalf("unexpected error verifying cert chain: %v", err) } // Handles single certifiacte in chain err = VerifyCertChain([]*x509.Certificate{rootCert}, rootKey) if err != nil { t.Fatalf("unexpected error verifying single cert chain: %v", err) } // Handles multiple intermediates subCert2, subKey2, _ := test.GenerateSubordinateCA(subCert, subKey) err = VerifyCertChain([]*x509.Certificate{subCert2, subCert, rootCert}, subKey2) if err != nil { t.Fatalf("unexpected error verifying cert chain: %v", err) } // Failure: Certificate is not a CA certificate err = VerifyCertChain([]*x509.Certificate{leafCert}, nil) if err == nil || !strings.Contains(err.Error(), "certificate is not a CA") { t.Fatalf("expected error with non-CA cert: %v", err) } // Failure: Certificate missing EKU // Note that the wrong EKU will be caught by x509.Verify invalidSubCert, invalidSubKey, _ := test.GenerateSubordinateCAWithoutEKU(rootCert, rootKey) err = VerifyCertChain([]*x509.Certificate{invalidSubCert, rootCert}, invalidSubKey) if err == nil || !strings.Contains(err.Error(), "certificate must have extended key usage code signing") { t.Fatalf("expected error verifying cert chain without EKU: %v", err) } // Failure: Invalid chain rootCert2, _, _ := test.GenerateRootCA() err = VerifyCertChain([]*x509.Certificate{subCert, rootCert2}, subKey) if err == nil || !strings.Contains(err.Error(), "certificate signed by unknown authority") { t.Fatalf("expected error verifying cert chain: %v", err) } // Failure: Different signer with different key signer, _, err := signature.NewDefaultECDSASignerVerifier() if err != nil { t.Fatalf("expected error generating signer: %v", err) } err = VerifyCertChain([]*x509.Certificate{subCert, rootCert}, signer) if err == nil || !strings.Contains(err.Error(), "public keys are not equal") { t.Fatalf("expected error verifying cert with mismatched public keys: %v", err) } // Failure: Weak key weakSubCert, weakSubKey, _ := test.GenerateWeakSubordinateCA(rootCert, rootKey) err = VerifyCertChain([]*x509.Certificate{weakSubCert, rootCert}, weakSubKey) if err == nil || !strings.Contains(err.Error(), "ECDSA curve P-224 not allowed") { t.Fatalf("expected error verifying weak cert chain: %v", err) } // Failure: Empty chain err = VerifyCertChain([]*x509.Certificate{}, subKey) if err == nil || !strings.Contains(err.Error(), "certificate chain must contain at least one certificate") { t.Fatalf("expected error verifying with empty chain: %v", err) } } fulcio-1.6.5/pkg/ca/csc.go000066400000000000000000000055161470150653400152630ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 ca import ( "crypto/x509" "strings" "github.com/sigstore/sigstore/pkg/cryptoutils" ) type CodeSigningCertificate struct { FinalCertificate *x509.Certificate FinalChain []*x509.Certificate finalPEM string finalChainPEM []string } func CreateCSCFromPEM(cert string, chain []string) (*CodeSigningCertificate, error) { var c CodeSigningCertificate // convert to X509 and store both formats finalCert, err := cryptoutils.UnmarshalCertificatesFromPEM([]byte(cert)) if err != nil { return nil, err } c.finalPEM = strings.TrimSpace(cert) c.FinalCertificate = finalCert[0] // convert to X509 and store both formats chainBytes := []byte(strings.Join(chain, "")) if len(chainBytes) != 0 { c.FinalChain, err = cryptoutils.UnmarshalCertificatesFromPEM(chainBytes) if err != nil { return nil, err } for _, cert := range chain { c.finalChainPEM = append(c.finalChainPEM, strings.TrimSpace(cert)) } } return &c, nil } func CreateCSCFromDER(cert []byte, chain []*x509.Certificate) (*CodeSigningCertificate, error) { var ( c CodeSigningCertificate err error ) // convert to X509 and store both formats c.finalPEM = strings.TrimSpace(string(cryptoutils.PEMEncode(cryptoutils.CertificatePEMType, cert))) c.FinalCertificate, err = x509.ParseCertificate(cert) if err != nil { return nil, err } // convert to X509 and store both formats c.FinalChain = chain if err != nil { return nil, err } for _, chainCert := range c.FinalChain { c.finalChainPEM = append(c.finalChainPEM, strings.TrimSpace(string(cryptoutils.PEMEncode(cryptoutils.CertificatePEMType, chainCert.Raw)))) } return &c, nil } func (c *CodeSigningCertificate) CertPEM() (string, error) { var err error if c.finalPEM == "" { finalPemBytes, err := cryptoutils.MarshalCertificateToPEM(c.FinalCertificate) if err == nil { c.finalPEM = strings.TrimSpace(string(finalPemBytes)) } } return c.finalPEM, err } func (c *CodeSigningCertificate) ChainPEM() ([]string, error) { if c.finalChainPEM == nil && len(c.FinalChain) > 0 { for _, chainCert := range c.FinalChain { c.finalChainPEM = append(c.finalChainPEM, strings.TrimSpace(string(cryptoutils.PEMEncode(cryptoutils.CertificatePEMType, chainCert.Raw)))) } } return c.finalChainPEM, nil } fulcio-1.6.5/pkg/ca/csc_test.go000066400000000000000000000171001470150653400163120ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 ca import ( "encoding/pem" "strings" "testing" "github.com/google/go-cmp/cmp" "github.com/sigstore/sigstore/pkg/cryptoutils" ) func TestCreateCSCFromDER(t *testing.T) { tests := map[string]struct { CertificatePEM string ChainPEM []string WantErr bool }{ "Good certificate chain should parse without error": { CertificatePEM: `-----BEGIN CERTIFICATE----- MIICFDCCAZmgAwIBAgIUAPsd9CUVr9TNG8nRzYHJrC/ZjtowCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MjA1MTExNjI4MjRaFw0yMjA1MTExNjM4MjNaMAAwWTATBgcqhkjOPQIBBggqhkjO PQMBBwNCAATGZIJr9odbCYVecVDp9LB1Ye9ehw7tCvPphaKQY832ftnRYFluAb6G TtsmHqms4TXsTbvKHFJ9IxtvS6m2uJ6ao4HGMIHDMA4GA1UdDwEB/wQEAwIHgDAT BgNVHSUEDDAKBggrBgEFBQcDAzAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTAROUd EzzWfUH12GTQKrm84cGngTAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQKsXF +jAjBgNVHREBAf8EGTAXgRVuYXRoYW5AY2hhaW5ndWFyZC5kZXYwKQYKKwYBBAGD vzABAQQbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMAoGCCqGSM49BAMDA2kA MGYCMQDUnEwydrGWXaMdhE4JXvNAxAPI6iZzDFZAmqTsOyeSV1LWeFQIgrOGHQwB ObpE85YCMQCNhS9zht0xv7j2FGuLshR3aLMTzY3UFBC3pEcI+yy4hI12MHh4laKT yhW8MpHgDWs= -----END CERTIFICATE-----`, ChainPEM: []string{ `-----BEGIN CERTIFICATE----- MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl LmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7 XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex X69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY wB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ KsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM WP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9 TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ -----END CERTIFICATE-----`, }, WantErr: false, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { var certDer []byte { buf := []byte(test.CertificatePEM) block, _ := pem.Decode(buf) if block == nil { t.Fatal("bad certificate format") } certDer = block.Bytes } chainBytes := []byte(strings.Join(test.ChainPEM, "")) chain, err := cryptoutils.UnmarshalCertificatesFromPEM(chainBytes) if err != nil { t.Fatal("bad ca chain format") } csc, err := CreateCSCFromDER(certDer, chain) if err != nil { if !test.WantErr { t.Error(err) } return } gotCert, err := csc.CertPEM() if err != nil { t.Error(err) } if diff := cmp.Diff(gotCert, test.CertificatePEM); diff != "" { t.Error(diff) } gotChain, err := csc.ChainPEM() if err != nil { t.Error(err) } if diff := cmp.Diff(gotChain, test.ChainPEM); diff != "" { t.Error(diff) } }) } } func TestCreateCSCFromPEM(t *testing.T) { tests := map[string]struct { CertificatePEM string ChainPEM []string WantErr bool }{ "Good certificate chain should parse without error": { CertificatePEM: `-----BEGIN CERTIFICATE----- MIICFDCCAZmgAwIBAgIUAPsd9CUVr9TNG8nRzYHJrC/ZjtowCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MjA1MTExNjI4MjRaFw0yMjA1MTExNjM4MjNaMAAwWTATBgcqhkjOPQIBBggqhkjO PQMBBwNCAATGZIJr9odbCYVecVDp9LB1Ye9ehw7tCvPphaKQY832ftnRYFluAb6G TtsmHqms4TXsTbvKHFJ9IxtvS6m2uJ6ao4HGMIHDMA4GA1UdDwEB/wQEAwIHgDAT BgNVHSUEDDAKBggrBgEFBQcDAzAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTAROUd EzzWfUH12GTQKrm84cGngTAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQKsXF +jAjBgNVHREBAf8EGTAXgRVuYXRoYW5AY2hhaW5ndWFyZC5kZXYwKQYKKwYBBAGD vzABAQQbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMAoGCCqGSM49BAMDA2kA MGYCMQDUnEwydrGWXaMdhE4JXvNAxAPI6iZzDFZAmqTsOyeSV1LWeFQIgrOGHQwB ObpE85YCMQCNhS9zht0xv7j2FGuLshR3aLMTzY3UFBC3pEcI+yy4hI12MHh4laKT yhW8MpHgDWs= -----END CERTIFICATE-----`, ChainPEM: []string{ `-----BEGIN CERTIFICATE----- MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl LmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7 XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex X69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY wB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ KsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM WP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9 TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ -----END CERTIFICATE-----`, }, WantErr: false, }, "Bad leaf certificate format should error": { CertificatePEM: `-----BEGIN CERTIFICATE----- BOO! -----END CERTIFICATE-----`, ChainPEM: []string{ `-----BEGIN CERTIFICATE----- MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl LmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7 XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex X69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY wB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ KsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM WP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9 TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ -----END CERTIFICATE-----`, }, WantErr: true, }, "Bad chain certificate format should error": { CertificatePEM: `-----BEGIN CERTIFICATE----- MIICFDCCAZmgAwIBAgIUAPsd9CUVr9TNG8nRzYHJrC/ZjtowCgYIKoZIzj0EAwMw KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y MjA1MTExNjI4MjRaFw0yMjA1MTExNjM4MjNaMAAwWTATBgcqhkjOPQIBBggqhkjO PQMBBwNCAATGZIJr9odbCYVecVDp9LB1Ye9ehw7tCvPphaKQY832ftnRYFluAb6G TtsmHqms4TXsTbvKHFJ9IxtvS6m2uJ6ao4HGMIHDMA4GA1UdDwEB/wQEAwIHgDAT BgNVHSUEDDAKBggrBgEFBQcDAzAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTAROUd EzzWfUH12GTQKrm84cGngTAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQKsXF +jAjBgNVHREBAf8EGTAXgRVuYXRoYW5AY2hhaW5ndWFyZC5kZXYwKQYKKwYBBAGD vzABAQQbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMAoGCCqGSM49BAMDA2kA MGYCMQDUnEwydrGWXaMdhE4JXvNAxAPI6iZzDFZAmqTsOyeSV1LWeFQIgrOGHQwB ObpE85YCMQCNhS9zht0xv7j2FGuLshR3aLMTzY3UFBC3pEcI+yy4hI12MHh4laKT yhW8MpHgDWs= -----END CERTIFICATE-----`, ChainPEM: []string{ `-----BEGIN CERTIFICATE----- BOO! -----END CERTIFICATE-----`, }, WantErr: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { csc, err := CreateCSCFromPEM(test.CertificatePEM, test.ChainPEM) if err != nil { if !test.WantErr { t.Error(err) } return } gotCert, err := csc.CertPEM() if err != nil { t.Error(err) } if diff := cmp.Diff(gotCert, test.CertificatePEM); diff != "" { t.Error(diff) } gotChain, err := csc.ChainPEM() if err != nil { t.Error(err) } if diff := cmp.Diff(gotChain, test.ChainPEM); diff != "" { t.Error(diff) } }) } } fulcio-1.6.5/pkg/ca/cspc.go000066400000000000000000000023201470150653400154310ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 ca import ( "crypto" "crypto/x509" ) // CodeSigningPreCertificate holds a precertificate and chain. type CodeSigningPreCertificate struct { // PreCert contains the precertificate. Not a valid certificate due to a critical poison extension. PreCert *x509.Certificate // CertChain contains the certificate chain to verify the precertificate. CertChain []*x509.Certificate // PrivateKey contains the signing key used to sign the precertificate. Will be used to sign the certificate. // Included in case the signing key is rotated in between precertificate generation and final issuance. PrivateKey crypto.Signer } fulcio-1.6.5/pkg/ca/embeddedca.go000066400000000000000000000021761470150653400165470ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 ca import ( "context" "crypto" ct "github.com/google/certificate-transparency-go" "github.com/sigstore/fulcio/pkg/identity" ) // EmbeddedSCTCA implements precertificate and certificate issuance. Certificates will contain an embedded SCT. type EmbeddedSCTCA interface { CreatePrecertificate(context.Context, identity.Principal, crypto.PublicKey) (*CodeSigningPreCertificate, error) IssueFinalCertificate(ctx context.Context, precert *CodeSigningPreCertificate, sct *ct.SignedCertificateTimestamp) (*CodeSigningCertificate, error) } fulcio-1.6.5/pkg/ca/ephemeralca/000077500000000000000000000000001470150653400164235ustar00rootroot00000000000000fulcio-1.6.5/pkg/ca/ephemeralca/ephemeral.go000066400000000000000000000040541470150653400207170ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 ephemeralca import ( "crypto/rand" "crypto/x509" "crypto/x509/pkix" "time" "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/ca/baseca" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" ) type EphemeralCA struct { baseca.BaseCA } func NewEphemeralCA() (*EphemeralCA, error) { e := &EphemeralCA{} var err error signer, _, err := signature.NewDefaultECDSASignerVerifier() if err != nil { return nil, err } serialNumber, err := cryptoutils.GenerateSerialNumber() if err != nil { return nil, err } rootCA := &x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"sigstore"}, Country: []string{"USA"}, Province: []string{"WA"}, Locality: []string{"Kirkland"}, StreetAddress: []string{"767 6th St S"}, PostalCode: []string{"98033"}, }, NotBefore: time.Now(), NotAfter: time.Now().AddDate(10, 0, 0), IsCA: true, KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, BasicConstraintsValid: true, MaxPathLen: 1, } caBytes, err := x509.CreateCertificate(rand.Reader, rootCA, rootCA, signer.Public(), signer) if err != nil { return nil, err } rootCert, err := x509.ParseCertificate(caBytes) if err != nil { return nil, err } sc := ca.SignerCerts{Signer: signer, Certs: []*x509.Certificate{rootCert}} e.SignerWithChain = &sc return e, nil } fulcio-1.6.5/pkg/ca/ephemeralca/ephemeral_test.go000066400000000000000000000031321470150653400217520ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 ephemeralca import ( "crypto/x509" "testing" "time" "github.com/sigstore/sigstore/pkg/cryptoutils" ) func TestNewEphemeralCA(t *testing.T) { ca, err := NewEphemeralCA() if err != nil { t.Fatalf("unexpected error generating ephemeral CA: %v", err) } certs, signer := ca.GetSignerWithChain() if len(certs) != 1 { t.Fatalf("ca not set up") } rootCert := certs[0] if rootCert.NotAfter.Sub(rootCert.NotBefore) < time.Hour*24*365*10 { t.Fatalf("expected CA to have 10 year lifetime, got %v", rootCert.NotAfter.Sub(rootCert.NotBefore)) } if !rootCert.IsCA { t.Fatalf("ca does not have IsCA bit set") } if rootCert.MaxPathLen != 1 { t.Fatalf("expected CA with path length of 1, got %d", rootCert.MaxPathLen) } if rootCert.KeyUsage != x509.KeyUsageCertSign|x509.KeyUsageCRLSign { t.Fatalf("expected cert sign and crl sign key usage") } if err := cryptoutils.EqualKeys(signer.Public(), rootCert.PublicKey); err != nil { t.Fatalf("expected verification key and certificate key to match") } } fulcio-1.6.5/pkg/ca/error.go000066400000000000000000000014561470150653400156430ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 ca // ValidationError indicates that there is an issue with the content in the HTTP Request that // should result in an HTTP 400 Bad Request error being returned to the client type ValidationError error fulcio-1.6.5/pkg/ca/fileca/000077500000000000000000000000001470150653400154005ustar00rootroot00000000000000fulcio-1.6.5/pkg/ca/fileca/fileca.go000066400000000000000000000036011470150653400171520ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 fileca import ( "crypto" "crypto/x509" "github.com/fsnotify/fsnotify" "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/ca/baseca" ) type fileCA struct { baseca.BaseCA } // NewFileCA returns a file backed certificate authority. Expects paths to a // certificate and key that are PEM encoded. The key must be encrypted // according to RFC 1423 func NewFileCA(certPath, keyPath, keyPass string, watch bool) (ca.CertificateAuthority, error) { var fca fileCA var err error fca.SignerWithChain, err = loadKeyPair(certPath, keyPath, keyPass) if err != nil { return nil, err } if watch { watcher, err := fsnotify.NewWatcher() if err != nil { return nil, err } err = watcher.Add(certPath) if err != nil { return nil, err } err = watcher.Add(keyPath) if err != nil { return nil, err } go ioWatch(certPath, keyPath, keyPass, watcher, fca.updateX509KeyPair) } return &fca, err } func (fca *fileCA) updateX509KeyPair(certs []*x509.Certificate, signer crypto.Signer) { scm := fca.SignerWithChain.(*ca.SignerCertsMutex) scm.Lock() defer scm.Unlock() // NB: We use a lock to ensure a reading thread can't get a mismatching // cert / key pair by reading the attributes halfway through the update // below. scm.Certs = certs scm.Signer = signer } fulcio-1.6.5/pkg/ca/fileca/fileca_test.go000066400000000000000000000034261470150653400202160ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 fileca import ( "crypto/ecdsa" "crypto/ed25519" "testing" ) const testKeyPass = `password123` func TestNewFileCA(t *testing.T) { _, err := NewFileCA( `testdata/ed25519-cert.pem`, `testdata/ed25519-key.pem`, testKeyPass, false, ) if err != nil { t.Error(`Failed to load file CA from disk`) } } func TestCertUpdate(t *testing.T) { oldCert := `testdata/ed25519-cert.pem` oldKey := `testdata/ed25519-key.pem` newCert := `testdata/ecdsa-cert.pem` newKey := `testdata/ecdsa-key.pem` watch := false ca, err := NewFileCA( oldCert, oldKey, testKeyPass, watch, ) if err != nil { t.Fatal(`Failed to load file CA from disk`) } fca, ok := ca.(*fileCA) if !ok { t.Fatal(`Bad CA type`) } _, key := fca.GetSignerWithChain() if _, ok = key.(ed25519.PrivateKey); !ok { t.Error(`first key should have been an ed25519 key`) } signerWithMutex, err := loadKeyPair(newCert, newKey, testKeyPass) if err != nil { t.Fatal(`Failed to load new keypair`) } fca.updateX509KeyPair(signerWithMutex.Certs, signerWithMutex.Signer) _, key = fca.GetSignerWithChain() if _, ok = key.(*ecdsa.PrivateKey); !ok { t.Fatal(`file CA should have been updated with ecdsa key`) } } fulcio-1.6.5/pkg/ca/fileca/load.go000066400000000000000000000030651470150653400166520ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 fileca import ( "bytes" "crypto" "crypto/x509" "errors" "os" "path/filepath" "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/sigstore/pkg/cryptoutils" "go.step.sm/crypto/pemutil" ) func loadKeyPair(certPath, keyPath, keyPass string) (*ca.SignerCertsMutex, error) { var ( certs []*x509.Certificate err error key crypto.Signer ) data, err := os.ReadFile(filepath.Clean(certPath)) if err != nil { return nil, err } certs, err = cryptoutils.LoadCertificatesFromPEM(bytes.NewReader(data)) if err != nil { return nil, err } { opaqueKey, err := pemutil.Read(keyPath, pemutil.WithPassword([]byte(keyPass))) if err != nil { return nil, err } var ok bool key, ok = opaqueKey.(crypto.Signer) if !ok { return nil, errors.New(`fileca: loaded private key can't be used to sign`) } } if err := ca.VerifyCertChain(certs, key); err != nil { return nil, err } return &ca.SignerCertsMutex{Certs: certs, Signer: key}, nil } fulcio-1.6.5/pkg/ca/fileca/load_test.go000066400000000000000000000030151470150653400177040ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 fileca import ( "fmt" "testing" ) func TestValidLoadKeyPair(t *testing.T) { keypairs := []string{ "ecdsa", "ed25519", "rsa4096", "openssl", "intermediate-2", "intermediate-3", } for _, keypair := range keypairs { keyPath := fmt.Sprintf("testdata/%s-key.pem", keypair) certPath := fmt.Sprintf("testdata/%s-cert.pem", keypair) _, err := loadKeyPair(certPath, keyPath, testKeyPass) if err != nil { t.Errorf("Failed to load key pair of type %s: %v", keypair, err) } } } func TestInvalidLoadKeyPair(t *testing.T) { keypairs := []string{ "notca", "mismatch", "eku-chaining-violation", } for _, keypair := range keypairs { keyPath := fmt.Sprintf("testdata/%s-key.pem", keypair) certPath := fmt.Sprintf("testdata/%s-cert.pem", keypair) _, err := loadKeyPair(certPath, keyPath, testKeyPass) if err == nil { t.Errorf("Expected invalid key pair of type %s to fail to load", keypair) } } } fulcio-1.6.5/pkg/ca/fileca/testdata/000077500000000000000000000000001470150653400172115ustar00rootroot00000000000000fulcio-1.6.5/pkg/ca/fileca/testdata/ecdsa-cert.pem000066400000000000000000000011631470150653400217270ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBojCCASmgAwIBAgIRAPtUhtNn5zcLWx6IFhFNbqowCgYIKoZIzj0EAwMwEDEO MAwGA1UEAxMFZWNkc2EwIBcNMjIwMTE4MjAzOTQ4WhgPMjEyMTEyMjUyMDM5NDda MBAxDjAMBgNVBAMTBWVjZHNhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEdUISPLNy nh6rLd9mDRTNrFygLajEOwmeIaZu6/OW8wJAM2r50ZvkpO0X5bOmf1ezSnuiYWpQ VjwQqSJ78zLgV2CHLm1td5g/F/lCIofAY+5w56uJgrzsqrAAGODumWpzo0UwQzAO BgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUpqtq +RZD2VWofB75Lsk67/hlFZcwCgYIKoZIzj0EAwMDZwAwZAIwPjiaLvSRX/ju4rGM /4Dq+xfwVtlri3zWkGpmNf65ciZipKceKz8wzAYZ6aCoBmSHAjBhnavATf3NxRik sMDePua/9rleC/gaCVC9l022c8Ht+i2tjhhwmQ09p+vOf8ugXsM= -----END CERTIFICATE----- fulcio-1.6.5/pkg/ca/fileca/testdata/ecdsa-key.pem000066400000000000000000000005731470150653400215660ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,1ee56fe067d83265fe430391edfa6586 W5NqqRe5rOVe4OvxehYKm6wscR1JFoyRyd8M+Rutp8Q2lxPuKFhR4FZ61b0yy6pr LGJGQWOTIZxrNZ8g4JeS9I3huDWGloZRI2fbTg69HK4EiQQWUc1wS1TWAVoaf4fr LclBWxp2UzqHDaNJ0/2DoGFZhaeMU84VA1O41lO+p5Cx4bms0yWeEHwOrf2AmnNY l5Zm9zoPpXxaDEPSTs5c1loRmmxPHKgb68oZPxEnsCg= -----END EC PRIVATE KEY----- fulcio-1.6.5/pkg/ca/fileca/testdata/ed25519-cert.pem000066400000000000000000000007211470150653400216450ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBKTCB3KADAgECAhEAtBnovvbxszrVoAQ52cyprDAFBgMrZXAwEjEQMA4GA1UE AxMHZWQyNTUxOTAgFw0yMjAxMTgyMDM5NDVaGA8yMTIxMTIyNTIwMzk0NVowEjEQ MA4GA1UEAxMHZWQyNTUxOTAqMAUGAytlcAMhAEvHE6tyPrILBpp/trmJFq47084w PPeuGwL1NUeOs85po0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB /wIBATAdBgNVHQ4EFgQUvGmDwKfk/xiWf+ogGKx6391FPG0wBQYDK2VwA0EARdJM 8/WM/6UC/fUOc0m597lqAiln+XXi1o6IJIwYf849WAwwZoXjcDpO9PM5KM6jg3dB KecnmX3PBCvtMAF6Bg== -----END CERTIFICATE----- fulcio-1.6.5/pkg/ca/fileca/testdata/ed25519-key.pem000066400000000000000000000004561470150653400215050ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGkMGAGCSqGSIb3DQEFDTBTMDIGCSqGSIb3DQEFDDAlBBAodg9wkHvRNwsiMIKj w7HOAgMBhqAwDAYIKoZIhvcNAgkAADAdBglghkgBZQMEASoEEJ/dx5SGu+D6gLpq tNb/o1EEQKKnS4CPbd8fqBfCXebZzq2+yzEmp8LNwQjA4/di+MwqO+Alr/w9QqUC MwKOP0K/c4Rul3Gdj1TJeB79gk6+8VY= -----END ENCRYPTED PRIVATE KEY----- fulcio-1.6.5/pkg/ca/fileca/testdata/eku-chaining-violation-cert.pem000066400000000000000000000032371470150653400252200ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBhTCCATegAwIBAgIQaX/zl+RgBGmPB8xB5p/AGzAFBgMrZXAwGDEWMBQGA1UE AxMNaW50ZXJtZWRpYXRlMTAgFw0yMjAxMTgyMDQwMDBaGA8yMTIxMTIyNTIwNDAw MFowGDEWMBQGA1UEAxMNaW50ZXJtZWRpYXRlMjBZMBMGByqGSM49AgEGCCqGSM49 AwEHA0IABNqxk7mTvl1Z3Lu3EPPuMRH1g0bWyuO7mtSY3iIxRUReGsd8E+OentZj U0WHIkJr5fW6dmsGLq0O8Ga64VOufyCjZjBkMA4GA1UdDwEB/wQEAwIBBjASBgNV HRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQNtutvnfDRxsfmk8BQM1ZJLBZbvDAf BgNVHSMEGDAWgBSjru3PBZQwhlED2N7kkNC5on99djAFBgMrZXADQQC5Fj8miHDD nlw4v8t6oh11s6UygsF5ZsD+2sm9+GuxGrI0HcFbIyQbPZyV3Wv2ZcTJReZ489mF lWS367m4jX0D -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBdDCCARqgAwIBAgIRAOcT6tYbqPoC/S3mafr+lCIwCgYIKoZIzj0EAwIwDzEN MAsGA1UEAxMEcm9vdDAgFw0yMjAxMTgyMDQwMDBaGA8yMTIxMTIyNTIwNDAwMFow GDEWMBQGA1UEAxMNaW50ZXJtZWRpYXRlMTAqMAUGAytlcAMhAP8ne9tAJLrAAf/L kQnlS+tiYBvKZfu+hLCQisMfWlFKo3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0l BAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUo67t zwWUMIZRA9je5JDQuaJ/fXYwHwYDVR0jBBgwFoAUqCLjqJtiXiediSJebsQdCV59 d9MwCgYIKoZIzj0EAwIDSAAwRQIhALLWa6T98PCO/zO/DXzsY5vLEZmiaeJj6ac3 GQtfXkjFAiBh/GcSFfh6fHn/GPs4N5HZXQs7x4+zTlWD7hSCo2jezg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBYzCCAQmgAwIBAgIQA8PGipZ4WhNTXXeiHs9HkzAKBggqhkjOPQQDAjAPMQ0w CwYDVQQDEwRyb290MCAXDTIyMDExODIwNDAwMFoYDzIxMjExMjI1MjA0MDAwWjAP MQ0wCwYDVQQDEwRyb290MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2a1VgMYP 5Uh/eMs/smjDFjCLEq7UTaj1D36Shp/GrsvXXCKyH/4ZlcVpTaVDC0oDDQ6os4UV aoT/4Ix1hU5bnqNFMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQIwHQYDVR0OBBYEFKgi46ibYl4nnYkiXm7EHQlefXfTMAoGCCqGSM49BAMCA0gA MEUCIQDIuZn/YBfndAo7Rv5FUl/9HM9dr9LrDQFfCkn5UnOYnQIgN6ruDqzt+GHG /HJ1qe6CfnglgaEJ+/Vloc2PTcm/rVs= -----END CERTIFICATE----- fulcio-1.6.5/pkg/ca/fileca/testdata/eku-chaining-violation-key.pem000066400000000000000000000004721470150653400250510ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,2e9623757041e0d3ca2814238b20a8a0 in6cGXlJQtojVS3Epbt16OoPR+MIZl+yL2+QMwGszsLHwA0r9OgpyK7cnFQKEJST m6KVpEWprRU//yljH8XZ0hOB8xzh0XR2Xbp5chMU/MptOjWm4yv4CS2Qvvob/sB2 V9e+KmyUJLe123h/IYcZ5upHQdQqlf8kKu2vdL9sLHM= -----END EC PRIVATE KEY----- fulcio-1.6.5/pkg/ca/fileca/testdata/generate.sh000077500000000000000000000234001470150653400213410ustar00rootroot00000000000000#!/bin/bash # Copyright 2021 The Sigstore 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. password=password123 duration=876000h # 100 years tpl=temp.tpl function generate_ed25519 { echo $password > password.file step certificate create \ --profile root-ca \ --not-after $duration \ --kty OKP \ --crv Ed25519 \ --password-file password.file \ ed25519 \ ed25519-cert.pem \ ed25519-key.pem rm password.file } function generate_ecdsa { echo $password > password.file step certificate create \ --profile root-ca \ --not-after $duration \ --kty EC \ --crv P-384 \ --password-file password.file \ ecdsa \ ecdsa-cert.pem \ ecdsa-key.pem rm password.file } function generate_rsa4096 { echo $password > password.file step certificate create \ --profile root-ca \ --not-after $duration \ --kty RSA \ --size 4096 \ --password-file password.file \ rsa4096 \ rsa4096-cert.pem \ rsa4096-key.pem rm password.file } function generate_openssl { # OpenSSL uses a different encryption format # than step so lets makes sure that works openssl req -x509 \ -newkey ed25519 \ -sha256 \ -keyout openssl-key.pem \ -out openssl-cert.pem \ -subj "/CN=openssl" \ -days 36500 \ -addext basicConstraints=critical,CA:TRUE,pathlen:1 \ -passout pass:"$password" } function generate_key_mismatch { echo $password > password.file step certificate create \ --profile root-ca \ --not-after $duration \ --kty OKP \ --crv Ed25519 \ --password-file password.file \ mismatch \ temp-cert.pem \ temp-key.pem step certificate create \ --profile root-ca \ --not-after $duration \ --kty OKP \ --crv Ed25519 \ --password-file password.file \ mismatch \ mismatch-cert.pem \ mismatch-key.pem mv temp-key.pem mismatch-key.pem rm temp-cert.pem rm password.file } function generate_not_a_ca { echo $password > password.file step certificate create \ --ca ed25519-cert.pem \ --ca-key ed25519-key.pem \ --ca-password-file password.file \ --profile leaf \ --not-after $duration \ --kty OKP \ --crv Ed25519 \ --password-file password.file \ notca \ notca-cert.pem \ notca-key.pem rm password.file } function generate_intermediate_2_ca { echo $password > password.file # Root CA cat <<-EOF > root.tpl { "subject": { "commonName": "root" }, "issuer": { "commonName": "root" }, "keyUsage": ["certSign", "crlSign"], "basicConstraints": { "isCA": true, "maxPathLen": 1 } } EOF step certificate create \ --template root.tpl \ --password-file password.file \ --not-after $duration \ root \ root-cert.pem \ root-key.pem \ rm root.tpl # Intermediate 1 cat <<-EOF > intermediate1.tpl { "subject": { "commonName": "intermediate1" }, "keyUsage": ["certSign", "crlSign"], "extKeyUsage": ["codeSigning"], "basicConstraints": { "isCA": true } } EOF step certificate create \ --template intermediate1.tpl \ --password-file password.file \ --not-after $duration \ --kty OKP \ --curve Ed25519 \ --ca root-cert.pem \ --ca-key root-key.pem \ --ca-password-file password.file \ intermediate1 \ intermediate1-cert.pem \ intermediate1-key.pem \ rm root-key.pem rm intermediate1.tpl # Chain certificates together and delete unneeded ones cat intermediate1-cert.pem root-cert.pem > intermediate-2-cert.pem mv intermediate1-key.pem intermediate-2-key.pem rm intermediate1-cert.pem root-cert.pem rm password.file } function generate_intermediate_3_ca { echo $password > password.file # Root CA cat <<-EOF > root.tpl { "subject": { "commonName": "root" }, "issuer": { "commonName": "root" }, "keyUsage": ["certSign", "crlSign"], "basicConstraints": { "isCA": true, "maxPathLen": 2 } } EOF step certificate create \ --template root.tpl \ --password-file password.file \ --not-after $duration \ root \ root-cert.pem \ root-key.pem \ rm root.tpl # Intermediate 1 cat <<-EOF > intermediate1.tpl { "subject": { "commonName": "intermediate1" }, "keyUsage": ["certSign", "crlSign"], "extKeyUsage": ["codeSigning"], "basicConstraints": { "isCA": true, "maxPathLen": 1 } } EOF step certificate create \ --template intermediate1.tpl \ --password-file password.file \ --not-after $duration \ --kty OKP \ --curve Ed25519 \ --ca root-cert.pem \ --ca-key root-key.pem \ --ca-password-file password.file \ intermediate1 \ intermediate1-cert.pem \ intermediate1-key.pem \ rm root-key.pem rm intermediate1.tpl # Intermediate 2 cat <<-EOF > intermediate2.tpl { "subject": { "commonName": "intermediate2" }, "keyUsage": ["certSign", "crlSign"], "extKeyUsage": ["codeSigning"], "basicConstraints": { "isCA": true } } EOF step certificate create \ --template intermediate2.tpl \ --password-file password.file \ --not-after $duration \ --ca intermediate1-cert.pem \ --ca-key intermediate1-key.pem \ --ca-password-file password.file \ intermediate2 \ intermediate2-cert.pem \ intermediate2-key.pem \ rm intermediate1-key.pem rm intermediate2.tpl # Chain certificates together and delete unneeded ones cat intermediate2-cert.pem intermediate1-cert.pem root-cert.pem > intermediate-3-cert.pem mv intermediate2-key.pem intermediate-3-key.pem rm intermediate2-cert.pem intermediate1-cert.pem root-cert.pem rm password.file } function generate_eku_chaining_violation { echo $password > password.file # Root CA cat <<-EOF > root.tpl { "subject": { "commonName": "root" }, "issuer": { "commonName": "root" }, "keyUsage": ["certSign", "crlSign"], "basicConstraints": { "isCA": true, "maxPathLen": 2 } } EOF step certificate create \ --template root.tpl \ --password-file password.file \ --not-after $duration \ root \ root-cert.pem \ root-key.pem \ rm root.tpl # Intermediate 1 # NB: This intermediate lacks code signing extended key usage so its in # violation of extended key usage chaining a should _not_ load. cat <<-EOF > intermediate1.tpl { "subject": { "commonName": "intermediate1" }, "keyUsage": ["certSign", "crlSign"], "extKeyUsage": ["codeSigning"], "basicConstraints": { "isCA": true, "maxPathLen": 1 } } EOF step certificate create \ --template intermediate1.tpl \ --password-file password.file \ --not-after $duration \ --kty OKP \ --curve Ed25519 \ --ca root-cert.pem \ --ca-key root-key.pem \ --ca-password-file password.file \ intermediate1 \ intermediate1-cert.pem \ intermediate1-key.pem \ rm root-key.pem rm intermediate1.tpl # Intermediate 2 # NB: This intermediate lacks code signing extended key usage so its in # violation of extended key usage chaining a should _not_ load. cat <<-EOF > intermediate2.tpl { "subject": { "commonName": "intermediate2" }, "keyUsage": ["certSign", "crlSign"], "basicConstraints": { "isCA": true } } EOF step certificate create \ --template intermediate2.tpl \ --password-file password.file \ --not-after $duration \ --ca intermediate1-cert.pem \ --ca-key intermediate1-key.pem \ --ca-password-file password.file \ intermediate2 \ intermediate2-cert.pem \ intermediate2-key.pem \ rm intermediate1-key.pem rm intermediate2.tpl # Chain certificates together and delete unneeded ones cat intermediate2-cert.pem intermediate1-cert.pem root-cert.pem > eku-chaining-violation-cert.pem mv intermediate2-key.pem eku-chaining-violation-key.pem rm intermediate2-cert.pem intermediate1-cert.pem root-cert.pem rm password.file } generate_ed25519 generate_ecdsa generate_rsa4096 generate_openssl generate_key_mismatch generate_not_a_ca generate_intermediate_2_ca generate_intermediate_3_ca generate_eku_chaining_violation fulcio-1.6.5/pkg/ca/fileca/testdata/intermediate-2-cert.pem000066400000000000000000000021201470150653400234530ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBcjCCARmgAwIBAgIQAR1nKl+HeRAslWxPR6BSADAKBggqhkjOPQQDAjAPMQ0w CwYDVQQDEwRyb290MCAXDTIyMDExODIwNDAwMFoYDzIxMjExMjI1MjA0MDAwWjAY MRYwFAYDVQQDEw1pbnRlcm1lZGlhdGUxMCowBQYDK2VwAyEASpnPvxK/oHr0nGEQ xa/5wBocrBZxLpQOVLIloPYGa9ajezB5MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUE DDAKBggrBgEFBQcDAzASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBS9nH4j IPyBMv3AF3O1rX/uJssTNzAfBgNVHSMEGDAWgBSIX+U/NJHlOgpgZeXlDfspLXEF ozAKBggqhkjOPQQDAgNHADBEAiAY5QUqtaL32tIHoc0gFLT9wtIURE5QEqVZr9RZ QMOPngIgLhqayKYAg/OlMUrIcqSmyIEwnbpZJfH29/IFeRewLR8= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBYjCCAQmgAwIBAgIQSMc5JFd3O+TeHZaBJ6V3XDAKBggqhkjOPQQDAjAPMQ0w CwYDVQQDEwRyb290MCAXDTIyMDExODIwNDAwMFoYDzIxMjExMjI1MjA0MDAwWjAP MQ0wCwYDVQQDEwRyb290MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIViBiRMw n3aHAs3xBLCn/u1rfQaln12vx0VP8z0vRfeZHdQKYkH/l7EjV21YFYY1T61UC6S5 D5T4SqYh+RbUeaNFMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C AQEwHQYDVR0OBBYEFIhf5T80keU6CmBl5eUN+yktcQWjMAoGCCqGSM49BAMCA0cA MEQCID8UGMMN0DqZpOecLg4Iq5Mq8KiEixJaFSkxQl2j8YISAiBaNEuv6kG6sQSP xnWhJ8BG38VFMg1P6bYZ7wbjuxm1kw== -----END CERTIFICATE----- fulcio-1.6.5/pkg/ca/fileca/testdata/intermediate-2-key.pem000066400000000000000000000004561470150653400233200ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGkMGAGCSqGSIb3DQEFDTBTMDIGCSqGSIb3DQEFDDAlBBB6TQUoym4QO78cPsyz ahV0AgMBhqAwDAYIKoZIhvcNAgkAADAdBglghkgBZQMEASoEEOscfDLwf8bCK8lG XCIhJ2wEQMJwdiCjDBXJuG2eSFmB35T02d2vcNeL16aTxKEAPoWHETih+ZSHfsoR xABvb6dHLH8XJhnXabHxnJIdk1tCQDU= -----END ENCRYPTED PRIVATE KEY----- fulcio-1.6.5/pkg/ca/fileca/testdata/intermediate-3-cert.pem000066400000000000000000000032731470150653400234660ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBmzCCAU2gAwIBAgIRAIXq3QoEvEXa6hJ9qmWCmcowBQYDK2VwMBgxFjAUBgNV BAMTDWludGVybWVkaWF0ZTEwIBcNMjIwMTE4MjA0MDAwWhgPMjEyMTEyMjUyMDQw MDBaMBgxFjAUBgNVBAMTDWludGVybWVkaWF0ZTIwWTATBgcqhkjOPQIBBggqhkjO PQMBBwNCAATsWs2QEfAMTNEq+mLbjQDT9sy7OlVVQJevgyS0i/crNf90dxF6hnyb e+20Vce/Tb4gFEgZNzdKirp0TgJf/fbFo3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYD VR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU e1tpZZhejz/Cavl0F+9hUHV2oiQwHwYDVR0jBBgwFoAUtIj5kVkjYTGFA6cfny7W SWckA4AwBQYDK2VwA0EAgcVHHXEvhpG/bFCtJhE102BZ+Ynp8vp4D6GFKqGfoOAu Tt7hge0sgYT3NGXwt2VefffjGWUF+8MmggQAxPCOAQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBcjCCARmgAwIBAgIQZq94KOKSFQ969mDIh0GCdDAKBggqhkjOPQQDAjAPMQ0w CwYDVQQDEwRyb290MCAXDTIyMDExODIwNDAwMFoYDzIxMjExMjI1MjA0MDAwWjAY MRYwFAYDVQQDEw1pbnRlcm1lZGlhdGUxMCowBQYDK2VwAyEADLOSzgUeSkLl/9SP VRZF9sBam6z0kwIRHkemLKcgM6+jezB5MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUE DDAKBggrBgEFBQcDAzASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBS0iPmR WSNhMYUDpx+fLtZJZyQDgDAfBgNVHSMEGDAWgBTMuK2bgBSS5MqEHwIluqygtJEm qzAKBggqhkjOPQQDAgNHADBEAiBolgOd+VaCURT3HVgSrpH1sWu4fHpEc86LV0Qn KniY/gIgG9SyAfQZcMNe72s94mpUoPRjEejSkHdczbQgaW3x6Uw= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBYzCCAQqgAwIBAgIRAOTwiYaYMMiyTm9Ky9oGuFwwCgYIKoZIzj0EAwIwDzEN MAsGA1UEAxMEcm9vdDAgFw0yMjAxMTgyMDQwMDBaGA8yMTIxMTIyNTIwNDAwMFow DzENMAsGA1UEAxMEcm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKgqW7x1 34Y/NlypOw09WUszQG9TYVNx1O3GSakeG7TI0lOkWD66nhieSqX5mG5alHaHmm4w yvHTrSQLRsWzaoSjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/ AgECMB0GA1UdDgQWBBTMuK2bgBSS5MqEHwIluqygtJEmqzAKBggqhkjOPQQDAgNH ADBEAiBUzMazRHcRCPgBjJaWUtp+q4JOpcdg1YVbXwByT+MeXwIgYZFqrJwwMqiT iTrJHUex5hmDNg3kGHWlj9e4aunOgP0= -----END CERTIFICATE----- fulcio-1.6.5/pkg/ca/fileca/testdata/intermediate-3-key.pem000066400000000000000000000004721470150653400233170ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,e458cbeb4fb59b884fc869ce691851a2 UMNmZlFtF1FBML1MCT/6FJdD/yzXkRMRdDdw40/IHTKgqKv68DXLhP9FCLzpVXV5 RTgxTSmP7yHlH6VobCTME0ETaakkRsIqgTMbcD2yskC84U03hM5JQHB9EySxG8Sq mygsGdVDiCUFXdVaDeiVZHqh2ngebLARDu7xW4PhR+Q= -----END EC PRIVATE KEY----- fulcio-1.6.5/pkg/ca/fileca/testdata/mismatch-cert.pem000066400000000000000000000007211470150653400224540ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBKzCB3qADAgECAhEA95TUKc1TzJqEMHUFOix8UDAFBgMrZXAwEzERMA8GA1UE AxMIbWlzbWF0Y2gwIBcNMjIwMTE4MjAzOTU1WhgPMjEyMTEyMjUyMDM5NTVaMBMx ETAPBgNVBAMTCG1pc21hdGNoMCowBQYDK2VwAyEAasfLpByJQSwfhMTUj2sLEgEu tlcyU1NJLUPML86WKtijRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG AQH/AgEBMB0GA1UdDgQWBBROYDgMpZr1yg8zn2hf588ZlN2WpjAFBgMrZXADQQDt e3g9K5hr0+jcP07VjaX4IzoLJBEeyyoZAheVPfbaJe9bAF1UpuN9rWDtveJdBYb+ 0Cz5PdoEOsWfWNpdHIwP -----END CERTIFICATE----- fulcio-1.6.5/pkg/ca/fileca/testdata/mismatch-key.pem000066400000000000000000000004561470150653400223140ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGkMGAGCSqGSIb3DQEFDTBTMDIGCSqGSIb3DQEFDDAlBBDs7K6i/7O7Ab2hB/13 3i7nAgMBhqAwDAYIKoZIhvcNAgkAADAdBglghkgBZQMEASoEEKZLUpbfRYCI3Hzl Hm1NZ0EEQIlqHGS2kNUYOue+bc9EgQymJhKfiAfU3X1EdV16xgRNNnyR0wkB8px7 37rbCigAayKnRx9g+FWy3VTscVi/AQI= -----END ENCRYPTED PRIVATE KEY----- fulcio-1.6.5/pkg/ca/fileca/testdata/notca-cert.pem000066400000000000000000000010461470150653400217540ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBaDCCARqgAwIBAgIRAJTzOITGwXWD7zya107jA3YwBQYDK2VwMBIxEDAOBgNV BAMTB2VkMjU1MTkwIBcNMjIwMTE4MjAzOTU4WhgPMjEyMTEyMjUyMDM5NTdaMBAx DjAMBgNVBAMTBW5vdGNhMCowBQYDK2VwAyEAqrvZiGADVXhmyiyWQ3oFoHH39URD VsNBzAU2CtV5NHajgYQwgYEwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUUH4MIqfco4e+K2EufcXtZFFCbIow HwYDVR0jBBgwFoAUvGmDwKfk/xiWf+ogGKx6391FPG0wEAYDVR0RBAkwB4IFbm90 Y2EwBQYDK2VwA0EArqAz8XVGYcx50C4+t1YLCcKqxpAjDK3ubmneBs51BgiBtPkH R6wTyeP5zEi2INNewT4OjjP7ZHH6c+EIgl8fDQ== -----END CERTIFICATE----- fulcio-1.6.5/pkg/ca/fileca/testdata/notca-key.pem000066400000000000000000000004561470150653400216130ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGkMGAGCSqGSIb3DQEFDTBTMDIGCSqGSIb3DQEFDDAlBBDJZnrjHk98HbNHEChc EcOjAgMBhqAwDAYIKoZIhvcNAgkAADAdBglghkgBZQMEASoEEN7vaB6J+XT52ae2 DJq8a0cEQH9/tyBmcKe/Yp5kGhZAh7DMH1VMPkLEZkmgiJZ2AIJrUjLRz11EVlJg 1EBO9CrrqlmmiMTGxpbHmU4DDSzTnYU= -----END ENCRYPTED PRIVATE KEY----- fulcio-1.6.5/pkg/ca/fileca/testdata/openssl-cert.pem000066400000000000000000000007511470150653400223350ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBPTCB8KADAgECAhQOFCGq1F/UFACHhW2z51EE+dodDTAFBgMrZXAwEjEQMA4G A1UEAwwHb3BlbnNzbDAgFw0yMjA2MTAwNDUzMzZaGA8yMTIyMDUxNzA0NTMzNlow EjEQMA4GA1UEAwwHb3BlbnNzbDAqMAUGAytlcAMhAHoP6VgvmjkF7TQktmsqA2WD FKuEus/Uf1IV+heG91lQo1YwVDAdBgNVHQ4EFgQUZx7Tvdvg0FtL4NwBHyq+vEdA KUswHwYDVR0jBBgwFoAUZx7Tvdvg0FtL4NwBHyq+vEdAKUswEgYDVR0TAQH/BAgw BgEB/wIBATAFBgMrZXADQQDWdhDWFYcX5dDmHuPi3MpgX5lyR+7yOA5keUVWQU8U 62DPFRRsfcpmWELx/RNQD/OgdIUZ9/YTPgFBoTngeD4G -----END CERTIFICATE----- fulcio-1.6.5/pkg/ca/fileca/testdata/openssl-key.pem000066400000000000000000000004111470150653400221610ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIGKME4GCSqGSIb3DQEFDTBBMCkGCSqGSIb3DQEFDDAcBAjrbQwLQsaVYgICCAAw DAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQIo5IbVAAU0f8EOEZix/CL4zM7FCfN RlNM1GD99ZEouGO5jEae7q0medijaG1IbD4y4B90nLuQfc4aDlIMG5AyA8wP -----END ENCRYPTED PRIVATE KEY----- fulcio-1.6.5/pkg/ca/fileca/testdata/rsa4096-cert.pem000066400000000000000000000033651470150653400217660ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIE9jCCAt6gAwIBAgIRAKXo22u23cyFFQr9c1g0xcswDQYJKoZIhvcNAQELBQAw EjEQMA4GA1UEAxMHcnNhNDA5NjAgFw0yMjAxMTgyMDM5NTRaGA8yMTIxMTIyNTIw Mzk1MFowEjEQMA4GA1UEAxMHcnNhNDA5NjCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAMGIdMtj0tMiVoY8ZtlhlZI40gDDoEiTVyLwrgWgdeDeo9QpkDMt zyCAI87RBaJiTNtegPvX0L06GMCjZ5HjsvK2JCoQ1dvvCpy3E1i1Wwy2l6l9zqpX LyQB/KcNY/z2/COeO70CWFv+976eaBFpceqTUZd/nUvBqHeYBrOubXf9aoyupYRJ wjavAAqBG+9FIbY+4JK7nEMl3Ozw9F5rsHngG0QW0yZUMYDmbAGRwXCqxAB2zg05 R0wEXCGkhhUmKV06gQy5kxXOKUgcgrUUUDyiI0h+3coLVytcywZB2+kOxKjSAmIH wmIbCltDeJ23+sercjhLaPMOllS7cbZKXlPm/iJZN+wmhh1n6yQC8051SL0vAPOt 3mqzNuEEnYkbPv2Yg2XGWPou3U0JLi9oV4ZeiBK0YYnuyO2ODF4DHhQnSssDQ0GD 9QTrREme5sgB8OSUNk4T1DgFju5Xr9G4kSp7Gk5axlIm1aB7jbUzubRi83zRjOlh c71EHD6J1cW+rrSxtykQzgtUOGvFu9XnBOs7R5cZILHouL576TptHLp2MRkznhyJ Bojp0RR6pHXBrKHjkTWntfk5jdpTGchSzGNSDBiac/goTN5GOyGdzZXGuX7OJUyu Mp3mDwp+GCBl4UuZxS4ZTH8vetgZdmEoA+P0Js4FVa9ppLizrF1NyYQFAgMBAAGj RTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQW BBQZc/Fy5shVwve4oGg0s9+nfaj9IDANBgkqhkiG9w0BAQsFAAOCAgEAMNBKlHBB 1OvmWen6KOznrSBG94QUgE555nq0KWGnYmcy8YhcDikRro3xDxl7Y7PA33E7gT1B dXKCNbvUSFGeT7Zf/6sbhQ7FdQEmPMbkrGPDLuwNaUKCtiNerLQ9tI2/CyPFknTp sAHI2ovlbL20Qw9nMeRVgyA26zUgtkZKns9JDS5ZLdrkPex60dYD8vWPTLU4mXhe W16tVvG4Phjjezefz/2ZkT/sOw6xj/1RD7Mw+IuU728Tur2RvYEVLEnAXCrLRP+g TpTgG2KldRAqWiZ34eu1/67yc4uaXYIk7t50fTU69adhmrPNPwDzs/TA3/zqDROT dNSKZjxdZZ5CAz+SwOcTBGp0RANax2PsbGkt8jvZAkYwpTY/uqBFHmE0OW24FmAx y2eV+WjFmOloTTlGbEoUzvxfwAyFlqkV54RM1RkuKcFOKjADHt4a56pYIAj6k3Hc DX2lA2N9RfahpSaqV9zw/pCIVRWaEfzRwcjUzBdKrVznI66ySOBu7h4PaOhbW7OV gXU0XKazO2IR8l3ppmcbWD4O6lejjI+7SYIRZQvYH3ilPgYPs8cXCQH70XniM+jJ KzCacN22mXpxrf8kr7jGgwn1y8IuE8YWJlb/aiyUQSK2mrAq+BvXviREnQpUIa8T ANh0wfktajwD9FfeicXh5TDDNLlrViSFrtQ= -----END CERTIFICATE----- fulcio-1.6.5/pkg/ca/fileca/testdata/rsa4096-key.pem000066400000000000000000000063761470150653400216260ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,66ef93f11623a85e93de3c4b3f00ff63 /KbxJBaQHEk+5dufPDZ1co6w6KWmSohpP5pe/trEl2Dbh9FVEP+wMGlhNDR7nXC1 3ViaQ6VOXEjM8ES903SurvJ50mb21Qcw5ewa+JJzHsSyAyEd3jCgxxIun8eTHfL/ ssUss8U9Y1LkgXyf0TTIuk5KVlpBlpZ6+CIbn2KqsdhHi/3v8WrgCLgcdRs6Zcp3 nooo/yeqSxqt8oSi1lKn+j0IBNEqMdVlKr4rgsvAigdnY7tMDsi4WKc/TWm1QwFn 1D94sZDTUHDWjI0Dr7aCHHObqXbm/rhIT5b6hyw36VMpV/M3NRQ41YyE8Rr72Qmr UzhYkHpn5GJNaIMP5hVP/CvQG1LIdHaC/ixwRvwCX67UNaAeqWQr0yghRcQ64uRG 5x5495EoPkexMZn4uiCFSrFRnPfjwzlc8QxpIpc/R0aCAvrB82HVRGqxvDMB3Cwy T4RIp9BezjfafelwXgKplkH2/H0r2hDKIR7M1ec5mmbGw8qJTIRV1xsB5XUYz+6x BzHKae6N6IoCrD61CGbB0SpRgRI1zdP7liKQMQDIqgiOj1BlXSDx6a02X0yNjSPn v+Wd2blC1eLjP52dYB7l82ci7tVlHPKn0jrBU2nfSqu9jLEn4Hy0oBKzWJOBRNMf y0MFIuRT6hezfdu6tTZPGYT/SchuoOlHIsG1/y8MTZM8pMTdvgiDwpeblxmhoPUy Ve2aCRStZP9lCqUy29aSN5yS9wafLaa+y/Eb0OslKQH+hRvO9mfRnjFxLacIvmh/ VGggqnsZOeAMFkeKx1pBbH6B3tjWJrAhIJteifuPHF0bGuMx6Gxf+IEfrgTWtIIM yfo91NnBQD41VUfW+Ozdf4f2tRz7WoEuR/yMOouKaSIPU+RbqaussQ0IVOUJI8jf SEGwR7IQbZo68Z1IC166v7zPSaXH7fOe7KIv5QlpCjqAYRs31a/eiK9tLPP53xUk MN3MTJxjRfB6Y8Ny5TlmDmhrfD9FLhlr3z7TmldfZYWPfPsIaNB8L76p2g4OYl0O gqFkmmzUP9p6URGX4HuxoUqURJLKQkYp2SHQNCmqUWQCTj28xWCZ51cC/qNLqJ8J YALgCWO+a1BPbrQ4962OwlBJbw0WG+gClCdIXRWzLMlzz2lpFWHpcMCv+UjbtXr/ gr6wqa7xA7cL+CcDz0xfB+X1a5pebwB4lm65vzOYDXFvvjnMOvWHK+HGt+4FDZlv BcNnb0LSaN9LBo+iECwrAbSxxwhKSdtGOQoBToe54+F7y9gr+yAOpzYltBb6YP3+ 8Mz33Ocf74Gbs7GN/BROEbiEv108jCpBBmxDi+IV4FfICAeEiIjojCgCP9/7k41O Com0SP9c38c9m8pMhn3zfJ/mTnDHYO4Y7vDu2IgXyHTsRP5N+EqwfQx8nWLgecVz SHyME9/L06yoK8PAX+l+KqkUkWmoY0wTvcytDjGzqXXBbydLAeiuZQsVlOD783MZ YfglSEaTBxuKsLy8gDIucw/AiCwijGo2DS0sLfo0aup/xrJEOE6ZQhlphDXf0nMC jWa8d7z8L8yE/WAHdBwgIq1kW+le5h0qeg91MXdSt2FRm63Ph+tU/s4ECC/EEZoO /+7BwCv0dDdf45x6cHhHFd8rfIXuoH21zabSt8wwneIrkc2OQEJvMWpA8zL4R43a 2MZAdWkSu3U8fINf1ZCReHWhQoS0pAPaGvt1KXygyPYE7Db/d0F8gWjVXr51tZgy aUGQZLQpb1ABC+kB2yBYUsGls3b8UKU+NsKl8HeT7K5EJ6dLHyxYQ0glNmy7Y+Bl r+2ZZdgPnvIsRJas3N9vgiZL/Sf6LJZu0KpCby5pfETBKhEotRQ0zc26wtTm/D/6 xGE3xUK+0oKPKtG2mM4znv0yvOQeyNN/YE6MA4M51RQAKza3F2zcH3PsxXLp6O1L E4f5hoCtF44sJfYfPM7pIzERS66vzcJE2N6LGaFHbgZs43NcCBwqE9+bnhBIcHZH 9Zbk441WI9j37Fk3MVJIlXHEL/TLRosC93JfLRVOThsjS7I5xHQILvR4YUIF9nJ4 SwQXepMwtCFEla07R5PdfR/Btx3TSeIx09fcStL+YgxvweuW0qNZjDZc8ED7M29z S+f3Xfsc41FUs64+VUTbB6gt5VGjmwlr1u0+SUxZ8Kkyyz0VjtHKB0w0tRdKKEv3 bCqZO7KALIUlEgzz5p92UJ7hUJ80IoMs9nL5+jSMDK6qqVmOP50yoMVfA6kAkj4U FM1jeU1GLvyCKY2gENqtm4DyEElrWK7MiySwGUFRyNdbvWB2iNMp1p1csuOoG97f vs3vpR3Gbi5p1n36g/vVCnYvPGXWGpWCZmmfiJ/T4UfqXSO4rTY1foiniTtjkMuq Eolgb3SudrvBzEKxb8f8jPbitMLG35bypwIeY5Tlf4aBDQkDKjhUowutJE5DTTaY OhbPkIOt/kDfhzt4BZRnaEiB9lvekDDkCtGdj7t7V30ZH3zAyP8X312tS9vJEt91 eZS3ycpMWDjCyyDtmAu2dMHgYniZKuW9l4NJ8OQfE2geOo2uDK56iXEFKh/ndgKw ODFKWvZwrjOtkeJXPc1UJrdpCKesBMvI9mavD/VWlKk75g5/eawOyVLYmIh54Tg1 VvADeKl4GxypdaIs28AKFI99fSXsQeBTLA74T6vAl4IGZQvVy6LiUoobCHFUuFkR QZV0qVZhIHjAvzxt0VPhHSyEZSyIhmz9l6JETUv4zlW1u3S4g45r4xEIxrhFrYtT B+dp3kMqrZH9rSvYWeFLxyg+4X1o5QvLn92sdPYYVZcmRYnTnNC6bHO+nbQVbwUn ggv43FEevFov6xmkrL9AazPyhgUdK/Jp5i1DU/4E2dv4u91dWS8MSQYGTD5XwlzQ fdDaAico4p7/D+iMl6oG5S3pqESezAHE/LhkQ83TmV2M5mZ7OA4jPoyKHD9IrIGW D1r7Znh/dA6eiHEmvEcyV1h6AMfNw/tgT/MOm6YsqIf1VCG4M7zrh2aSaXUjF776 rMb0673nBJgWnws42+W6SzLfBYj8zSEVDIujSgcxO/uzBsYGESZN3KwR9pgk+w1l LVStnb3H3e3dYS8aMu+ItHE/EHKzFP+31Z611k1PyM4M4aIcp8d/DJjYHlKlugSS -----END RSA PRIVATE KEY----- fulcio-1.6.5/pkg/ca/fileca/watch.go000066400000000000000000000022671470150653400170440ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 fileca import ( "crypto" "crypto/x509" "github.com/fsnotify/fsnotify" ) func ioWatch(certPath, keyPath, keyPass string, watcher *fsnotify.Watcher, callback func([]*x509.Certificate, crypto.Signer)) { for event := range watcher.Events { if event.Op&fsnotify.Write == fsnotify.Write { signerWithMutex, err := loadKeyPair(certPath, keyPath, keyPass) if err != nil { // Don't sweat it if this errors out. One file might // have updated and the other isn't causing a key-pair // mismatch continue } callback(signerWithMutex.Certs, signerWithMutex.Signer) } } } fulcio-1.6.5/pkg/ca/fileca/watch_test.go000066400000000000000000000047731470150653400201070ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 fileca import ( "crypto" "crypto/ecdsa" "crypto/x509" "os" "path/filepath" "testing" "time" "github.com/fsnotify/fsnotify" ) func cp(src, dst string) error { data, err := os.ReadFile(src) if err != nil { return err } return os.WriteFile(dst, data, 0644) } func TestIOWatch(t *testing.T) { dir := t.TempDir() keyPath := filepath.Join(dir, "key.pem") certPath := filepath.Join(dir, "cert.pem") // Copy initial certs into place err := cp("testdata/ed25519-key.pem", keyPath) if err != nil { t.Fatal(`Couldn't copy test data to temp file`) } err = cp("testdata/ed25519-cert.pem", certPath) if err != nil { t.Fatal(`Couldn't copy test data to temp file`) } // Set up callback trap var received []struct { certs []*x509.Certificate key crypto.Signer } callback := func(certs []*x509.Certificate, key crypto.Signer) { received = append(received, struct { certs []*x509.Certificate key crypto.Signer }{certs, key}) } // Set up watcher watcher, err := fsnotify.NewWatcher() if err != nil { t.Fatal(err) } err = watcher.Add(certPath) if err != nil { t.Fatal(err) } err = watcher.Add(keyPath) if err != nil { t.Fatal(err) } go ioWatch(certPath, keyPath, testKeyPass, watcher, callback) // Change the certs in place err = cp("testdata/ecdsa-key.pem", keyPath) if err != nil { t.Fatal(`Couldn't copy test data to temp file`) } err = cp("testdata/ecdsa-cert.pem", certPath) if err != nil { t.Fatal(`Couldn't copy test data to temp file`) } // Sleep for a bit to make sure that iowatch thread // does its thing. // TODO: This is hacky. Find a better way time.Sleep(1 * time.Second) // Test that we noticed the update and loaded the new // certificate if len(received) == 0 { t.Error("iowatcher should have seen at least 1 update") } if _, ok := received[0].key.(*ecdsa.PrivateKey); !ok { t.Error("Should have loaded an ecdsa private key on update") } } fulcio-1.6.5/pkg/ca/googleca/000077500000000000000000000000001470150653400157355ustar00rootroot00000000000000fulcio-1.6.5/pkg/ca/googleca/v1/000077500000000000000000000000001470150653400162635ustar00rootroot00000000000000fulcio-1.6.5/pkg/ca/googleca/v1/googleca.go000066400000000000000000000176201470150653400204000ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 v1 import ( "context" "crypto" "crypto/ecdsa" "crypto/rsa" "crypto/x509" "encoding/asn1" "encoding/pem" "fmt" "strings" "sync" "time" privateca "cloud.google.com/go/security/privateca/apiv1" "cloud.google.com/go/security/privateca/apiv1/privatecapb" "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/sigstore/pkg/cryptoutils" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/protobuf/types/known/durationpb" ) type CertAuthorityService struct { certAuthorityID string certAuthorityResource string caPoolResource string client *privateca.CertificateAuthorityClient // protected by once cachedRoots [][]*x509.Certificate cachedRootsOnce sync.Once } func NewCertAuthorityService(ctx context.Context, parent string, opts ...option.ClientOption) (ca.CertificateAuthority, error) { client, err := privateca.NewCertificateAuthorityClient(ctx, opts...) if err != nil { return nil, err } c := CertAuthorityService{ client: client, } if !strings.Contains(parent, "certificateAuthorities") { c.caPoolResource = parent return &c, nil } // parent should be in the form projects/*/locations/*/caPools/*/certificateAuthorities/* // to create a cert, we only want projects/*/locations/*/caPools/* caPoolParent := strings.Split(parent, "/certificateAuthorities") c.caPoolResource = caPoolParent[0] s := strings.SplitAfter(parent, "certificateAuthorities/") if len(s) != 2 { return nil, fmt.Errorf("certificate authority should be specified in the format projects/*/locations/*/caPools/*/certificateAuthorities/*") } c.certAuthorityID = s[1] c.certAuthorityResource = parent return &c, nil } func (c *CertAuthorityService) Close() error { return c.client.Close() } // getPubKeyFormat Returns the PublicKey KeyFormat required by gcp privateca. // https://pkg.go.dev/google.golang.org/genproto/googleapis/cloud/security/privateca/v1#PublicKey_KeyType func getPubKeyFormat(pemBytes []byte) (privatecapb.PublicKey_KeyFormat, error) { block, _ := pem.Decode(pemBytes) pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return 0, fmt.Errorf("failed to parse public key: %w", err) } switch pub := pub.(type) { case *rsa.PublicKey, *ecdsa.PublicKey: return privatecapb.PublicKey_PEM, nil default: return 0, fmt.Errorf("unknown public key type: %v", pub) } } func convertID(id asn1.ObjectIdentifier) []int32 { nid := make([]int32, 0, len(id)) for _, digit := range id { nid = append(nid, int32(digit)) } return nid } func Req(parent, certAuthority string, pemBytes []byte, cert *x509.Certificate) (*privatecapb.CreateCertificateRequest, error) { pubkeyFormat, err := getPubKeyFormat(pemBytes) if err != nil { return nil, err } // Translate the x509 certificate's subject to Google proto. subject := &privatecapb.CertificateConfig_SubjectConfig{ Subject: &privatecapb.Subject{}, SubjectAltName: &privatecapb.SubjectAltNames{ EmailAddresses: cert.EmailAddresses, }, } for _, uri := range cert.URIs { subject.SubjectAltName.Uris = append(subject.SubjectAltName.Uris, uri.String()) } extensions := make([]*privatecapb.X509Extension, 0, len(cert.ExtraExtensions)) for _, ext := range cert.ExtraExtensions { extensions = append(extensions, &privatecapb.X509Extension{ ObjectId: &privatecapb.ObjectId{ ObjectIdPath: convertID(ext.Id), }, Value: ext.Value, }) } req := &privatecapb.CreateCertificateRequest{ Parent: parent, Certificate: &privatecapb.Certificate{ Lifetime: durationpb.New(time.Until(cert.NotAfter)), CertificateConfig: &privatecapb.Certificate_Config{ Config: &privatecapb.CertificateConfig{ PublicKey: &privatecapb.PublicKey{ Format: pubkeyFormat, Key: pemBytes, }, X509Config: &privatecapb.X509Parameters{ KeyUsage: &privatecapb.KeyUsage{ BaseKeyUsage: &privatecapb.KeyUsage_KeyUsageOptions{ DigitalSignature: true, }, ExtendedKeyUsage: &privatecapb.KeyUsage_ExtendedKeyUsageOptions{ CodeSigning: true, }, }, AdditionalExtensions: extensions, }, SubjectConfig: subject, }, }, }, } if certAuthority != "" { req.IssuingCertificateAuthorityId = certAuthority } return req, nil } func (c *CertAuthorityService) TrustBundle(ctx context.Context) ([][]*x509.Certificate, error) { // if we've already successfully fetched the CA info, just use the cached value if c.cachedRoots != nil { return c.cachedRoots, nil } // if a specific certificate authority was specified, use that one if c.certAuthorityResource != "" { return c.getCertificateAuthorityTrustBundle(ctx) } // otherwise, get certs from all of the CAs in the pool return c.listCertificateAuthorityTrustBundle(ctx) } func (c *CertAuthorityService) getCertificateAuthorityTrustBundle(ctx context.Context) ([][]*x509.Certificate, error) { var roots [][]*x509.Certificate ca, err := c.client.GetCertificateAuthority(ctx, &privatecapb.GetCertificateAuthorityRequest{ Name: c.certAuthorityResource, }) if err != nil { return nil, err } // if we fail to parse the PEM content, return an error caCerts, err := cryptoutils.LoadCertificatesFromPEM(strings.NewReader(strings.Join(ca.PemCaCertificates, ""))) if err != nil { return [][]*x509.Certificate{}, fmt.Errorf("failed parsing PemCACertificates response: %w", err) } if len(caCerts) == 0 { return [][]*x509.Certificate{}, fmt.Errorf("error fetching root certificates") } roots = append(roots, caCerts) c.cachedRootsOnce.Do(func() { c.cachedRoots = roots }) return c.cachedRoots, nil } func (c *CertAuthorityService) listCertificateAuthorityTrustBundle(ctx context.Context) ([][]*x509.Certificate, error) { // fetch the latest values for the specified CA pool var roots [][]*x509.Certificate cas := c.client.ListCertificateAuthorities(ctx, &privatecapb.ListCertificateAuthoritiesRequest{ Parent: c.caPoolResource, }) for { ca, done := cas.Next() if done == iterator.Done { break } else if done != nil { // if the iterator returns an issue for some reason, exit return [][]*x509.Certificate{}, done } // if we fail to parse the PEM content, return an error caCerts, err := cryptoutils.LoadCertificatesFromPEM(strings.NewReader(strings.Join(ca.PemCaCertificates, ""))) if err != nil { return [][]*x509.Certificate{}, fmt.Errorf("failed parsing PemCACertificates response: %w", err) } if len(caCerts) == 0 { return [][]*x509.Certificate{}, fmt.Errorf("error fetching root certificates") } roots = append(roots, caCerts) } c.cachedRootsOnce.Do(func() { c.cachedRoots = roots }) return c.cachedRoots, nil } func (c *CertAuthorityService) CreateCertificate(ctx context.Context, principal identity.Principal, publicKey crypto.PublicKey) (*ca.CodeSigningCertificate, error) { cert, err := ca.MakeX509(ctx, principal, publicKey) if err != nil { return nil, ca.ValidationError(err) } pubKeyBytes, err := cryptoutils.MarshalPublicKeyToPEM(publicKey) if err != nil { return nil, ca.ValidationError(err) } req, err := Req(c.caPoolResource, c.certAuthorityID, pubKeyBytes, cert) if err != nil { return nil, ca.ValidationError(err) } resp, err := c.client.CreateCertificate(ctx, req) if err != nil { return nil, err } return ca.CreateCSCFromPEM(resp.PemCertificate, resp.PemCertificateChain) } fulcio-1.6.5/pkg/ca/googleca/v1/googleca_test.go000066400000000000000000000153131470150653400214340ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 v1 import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "net/url" "testing" "time" "cloud.google.com/go/security/privateca/apiv1/privatecapb" "github.com/sigstore/fulcio/pkg/challenges" "github.com/sigstore/sigstore/pkg/cryptoutils" "google.golang.org/protobuf/proto" ) func failErr(t *testing.T, err error) { if err != nil { t.Fatal(err) } } func TestCheckSignatureECDSA(t *testing.T) { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) failErr(t, err) email := "test@gmail.com" if err := challenges.CheckSignature(&priv.PublicKey, []byte("foo"), email); err == nil { t.Fatal("check should have failed") } h := sha256.Sum256([]byte(email)) signature, err := priv.Sign(rand.Reader, h[:], crypto.SHA256) failErr(t, err) if err := challenges.CheckSignature(&priv.PublicKey, signature, email); err != nil { t.Fatal(err) } // Try a bad email but "good" signature if err := challenges.CheckSignature(&priv.PublicKey, signature, "bad@email.com"); err == nil { t.Fatal("check should have failed") } } func TestCheckSignatureRSA(t *testing.T) { priv, err := rsa.GenerateKey(rand.Reader, 2048) failErr(t, err) email := "test@gmail.com" if err := challenges.CheckSignature(&priv.PublicKey, []byte("foo"), email); err == nil { t.Fatal("check should have failed") } h := sha256.Sum256([]byte(email)) signature, err := priv.Sign(rand.Reader, h[:], crypto.SHA256) failErr(t, err) if err := challenges.CheckSignature(&priv.PublicKey, signature, email); err != nil { t.Fatal(err) } // Try a bad email but "good" signature if err := challenges.CheckSignature(&priv.PublicKey, signature, "bad@email.com"); err == nil { t.Fatal("check should have failed") } } func TestReq(t *testing.T) { parent := "parent-ca" priv, err := rsa.GenerateKey(rand.Reader, 2048) failErr(t, err) uri := "sigstore.dev" parsedURI, err := url.Parse(uri) failErr(t, err) emailAddress := "foo@sigstore.dev" notAfter := time.Now().Add(time.Minute * 10) pubKeyBytes, err := cryptoutils.MarshalPublicKeyToPEM(priv.Public()) failErr(t, err) ext := pkix.Extension{Id: asn1.ObjectIdentifier{1, 2, 3}, Value: []byte{1, 2, 3}} cert := &x509.Certificate{ NotAfter: notAfter, EmailAddresses: []string{emailAddress}, URIs: []*url.URL{parsedURI}, ExtraExtensions: []pkix.Extension{ext}, } expectedReq := &privatecapb.CreateCertificateRequest{ Parent: parent, Certificate: &privatecapb.Certificate{ CertificateConfig: &privatecapb.Certificate_Config{ Config: &privatecapb.CertificateConfig{ PublicKey: &privatecapb.PublicKey{ Format: privatecapb.PublicKey_PEM, Key: pubKeyBytes, }, X509Config: &privatecapb.X509Parameters{ KeyUsage: &privatecapb.KeyUsage{ BaseKeyUsage: &privatecapb.KeyUsage_KeyUsageOptions{ DigitalSignature: true, }, ExtendedKeyUsage: &privatecapb.KeyUsage_ExtendedKeyUsageOptions{ CodeSigning: true, }, }, AdditionalExtensions: []*privatecapb.X509Extension{ { ObjectId: &privatecapb.ObjectId{ ObjectIdPath: convertID(ext.Id), }, Value: ext.Value, }, }, }, SubjectConfig: &privatecapb.CertificateConfig_SubjectConfig{ Subject: &privatecapb.Subject{}, SubjectAltName: &privatecapb.SubjectAltNames{ EmailAddresses: []string{emailAddress}, Uris: []string{uri}, }, }, }, }, }, } req, err := Req(parent, "", pubKeyBytes, cert) // We must copy over this field because we don't inject a clock, so // lifetime will always be different. expectedReq.Certificate.Lifetime = req.Certificate.Lifetime if err != nil { t.Fatalf("unexpected error, got: %v", err) } if !proto.Equal(req, expectedReq) { t.Fatalf("proto equality failed, expected: %v, got: %v", req, expectedReq) } } func TestReqCertAuthority(t *testing.T) { parent := "parent-ca" priv, err := rsa.GenerateKey(rand.Reader, 2048) failErr(t, err) uri := "sigstore.dev" parsedURI, err := url.Parse(uri) failErr(t, err) emailAddress := "foo@sigstore.dev" notAfter := time.Now().Add(time.Minute * 10) pubKeyBytes, err := cryptoutils.MarshalPublicKeyToPEM(priv.Public()) failErr(t, err) ext := pkix.Extension{Id: asn1.ObjectIdentifier{1, 2, 3}, Value: []byte{1, 2, 3}} cert := &x509.Certificate{ NotAfter: notAfter, EmailAddresses: []string{emailAddress}, URIs: []*url.URL{parsedURI}, ExtraExtensions: []pkix.Extension{ext}, } expectedReq := &privatecapb.CreateCertificateRequest{ Parent: parent, IssuingCertificateAuthorityId: "cert-authority", Certificate: &privatecapb.Certificate{ CertificateConfig: &privatecapb.Certificate_Config{ Config: &privatecapb.CertificateConfig{ PublicKey: &privatecapb.PublicKey{ Format: privatecapb.PublicKey_PEM, Key: pubKeyBytes, }, X509Config: &privatecapb.X509Parameters{ KeyUsage: &privatecapb.KeyUsage{ BaseKeyUsage: &privatecapb.KeyUsage_KeyUsageOptions{ DigitalSignature: true, }, ExtendedKeyUsage: &privatecapb.KeyUsage_ExtendedKeyUsageOptions{ CodeSigning: true, }, }, AdditionalExtensions: []*privatecapb.X509Extension{ { ObjectId: &privatecapb.ObjectId{ ObjectIdPath: convertID(ext.Id), }, Value: ext.Value, }, }, }, SubjectConfig: &privatecapb.CertificateConfig_SubjectConfig{ Subject: &privatecapb.Subject{}, SubjectAltName: &privatecapb.SubjectAltNames{ EmailAddresses: []string{emailAddress}, Uris: []string{uri}, }, }, }, }, }, } req, err := Req(parent, "cert-authority", pubKeyBytes, cert) // We must copy over this field because we don't inject a clock, so // lifetime will always be different. expectedReq.Certificate.Lifetime = req.Certificate.Lifetime if err != nil { t.Fatalf("unexpected error, got: %v", err) } if !proto.Equal(req, expectedReq) { t.Fatalf("proto equality failed, expected: %v, got: %v", req, expectedReq) } } fulcio-1.6.5/pkg/ca/kmsca/000077500000000000000000000000001470150653400152535ustar00rootroot00000000000000fulcio-1.6.5/pkg/ca/kmsca/kmsca.go000066400000000000000000000032661470150653400167070ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 kmsca import ( "context" "crypto" "crypto/x509" "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/ca/baseca" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/kms" // Register the provider-specific plugins _ "github.com/sigstore/sigstore/pkg/signature/kms/aws" _ "github.com/sigstore/sigstore/pkg/signature/kms/azure" _ "github.com/sigstore/sigstore/pkg/signature/kms/gcp" _ "github.com/sigstore/sigstore/pkg/signature/kms/hashivault" ) type kmsCA struct { baseca.BaseCA } func NewKMSCA(ctx context.Context, kmsKey string, certs []*x509.Certificate, opts ...signature.RPCOption) (ca.CertificateAuthority, error) { var ica kmsCA kmsSigner, err := kms.Get(ctx, kmsKey, crypto.SHA256, opts...) if err != nil { return nil, err } signer, _, err := kmsSigner.CryptoSigner(ctx, func(_ error) {}) if err != nil { return nil, err } sc := ca.SignerCerts{} ica.SignerWithChain = &sc sc.Signer = signer sc.Certs = certs if err := ca.VerifyCertChain(sc.Certs, sc.Signer); err != nil { return nil, err } return &ica, nil } fulcio-1.6.5/pkg/ca/kmsca/kmsca_test.go000066400000000000000000000053771470150653400177530ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 kmsca import ( "context" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "reflect" "strings" "testing" "github.com/sigstore/fulcio/pkg/test" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature/kms/fake" ) func TestNewKMSCA(t *testing.T) { rootCert, rootKey, _ := test.GenerateRootCA() subCert, subKey, _ := test.GenerateSubordinateCA(rootCert, rootKey) chain := []*x509.Certificate{subCert, rootCert} ca, err := NewKMSCA(context.WithValue(context.TODO(), fake.KmsCtxKey{}, subKey), "fakekms://key", chain) if err != nil { t.Fatalf("unexpected error creating KMS CA: %v", err) } // Expect certificate chain from Root matches provided certificate chain rootChains, err := ca.TrustBundle(context.TODO()) if err != nil { t.Fatalf("error fetching root: %v", err) } if len(rootChains) != 1 { t.Fatalf("unexpected number of chains: %d", len(rootChains)) } if !reflect.DeepEqual(rootChains[0], chain) { t.Fatalf("cert chains do not match") } // Expect signer and certificate's public keys match ica := ca.(*kmsCA) certs, signer := ica.GetSignerWithChain() if err := cryptoutils.EqualKeys(signer.Public(), subKey.Public()); err != nil { t.Fatalf("keys between CA and signer do not match: %v", err) } if !reflect.DeepEqual(certs, []*x509.Certificate{subCert, rootCert}) { t.Fatalf("expected certificate chains to match") } // Failure: Mismatch between signer and certificate key otherPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) _, err = NewKMSCA(context.WithValue(context.TODO(), fake.KmsCtxKey{}, otherPriv), "fakekms://key", chain) if err == nil || !strings.Contains(err.Error(), "ecdsa public keys are not equal") { t.Fatalf("expected error with mismatched public keys, got %v", err) } // Failure: Invalid certificate chain otherRootCert, _, _ := test.GenerateRootCA() _, err = NewKMSCA(context.WithValue(context.TODO(), fake.KmsCtxKey{}, subKey), "fakekms://key", []*x509.Certificate{subCert, otherRootCert}) if err == nil || !strings.Contains(err.Error(), "certificate signed by unknown authority") { t.Fatalf("expected error with invalid certificate chain, got %v", err) } } fulcio-1.6.5/pkg/ca/pkcs11ca/000077500000000000000000000000001470150653400155635ustar00rootroot00000000000000fulcio-1.6.5/pkg/ca/pkcs11ca/pkcs11ca.go000066400000000000000000000041331470150653400175210ustar00rootroot00000000000000//go:build cgo // +build cgo // Copyright 2021 The Sigstore 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 pkcs11ca import ( "crypto/x509" "encoding/pem" "errors" "os" "path/filepath" "github.com/ThalesIgnite/crypto11" "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/ca/baseca" ) type Params struct { ConfigPath string RootID string CAPath *string } type PKCS11CA struct { baseca.BaseCA } func NewPKCS11CA(params Params) (*PKCS11CA, error) { pkcs11ca := &PKCS11CA{} p11Ctx, err := crypto11.ConfigureFromFile(params.ConfigPath) if err != nil { return nil, err } var cert *x509.Certificate rootID := []byte(params.RootID) // get the existing root CA from the HSM or from disk if params.CAPath == nil { cert, err = p11Ctx.FindCertificate(rootID, nil, nil) if err != nil { return nil, err } } else { rootCaPath := filepath.Clean(*params.CAPath) pubPEMData, err := os.ReadFile(rootCaPath) if err != nil { return nil, err } block, _ := pem.Decode(pubPEMData) if block == nil || block.Type != "CERTIFICATE" { return nil, errors.New("failed to decode PEM block containing certificate") } cert, err = x509.ParseCertificate(block.Bytes) if err != nil { return nil, err } } // get the private key object from HSM signer, err := p11Ctx.FindKeyPair(nil, []byte("PKCS11CA")) if err != nil { return nil, err } if signer == nil { return nil, errors.New("cannot find private key") } sc := ca.SignerCerts{Signer: signer, Certs: []*x509.Certificate{cert}} pkcs11ca.SignerWithChain = &sc return pkcs11ca, nil } fulcio-1.6.5/pkg/ca/pkcs11ca/pkcs11canocgo.go000066400000000000000000000021341470150653400205460ustar00rootroot00000000000000//go:build !cgo // +build !cgo // Copyright 2021 The Sigstore 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 pkcs11ca import ( "errors" "github.com/sigstore/fulcio/pkg/ca/baseca" ) type PKCS11CA struct { baseca.BaseCA } type Params struct { ConfigPath string RootID string CAPath *string } // NewPKCS11CA is a placeholder for erroring with a meaningful message if the // binary has been built with CGO_ENABLED=0 tags. func NewPKCS11CA(params Params) (*PKCS11CA, error) { return nil, errors.New("binary has been built with no cgo support, PKCS11 not supported") } fulcio-1.6.5/pkg/ca/signercerts.go000066400000000000000000000033071470150653400170370ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 ca import ( "crypto" "crypto/x509" "sync" ) // SignerWithChain provides a getter for a CA's certificate chain and signing key. type SignerWithChain interface { GetSignerWithChain() ([]*x509.Certificate, crypto.Signer) } // SignerCerts holds a certificate chain and signer. type SignerCerts struct { // Signer signs issued certificates Signer crypto.Signer // Certs contains the chain of certificates from intermediate to root Certs []*x509.Certificate } func (s *SignerCerts) GetSignerWithChain() ([]*x509.Certificate, crypto.Signer) { return s.Certs, s.Signer } // SignerCertsMutex holds a certificate chain and signer, and holds a reader lock // when accessing the chain and signer. Use if a separate thread can concurrently // update the chain and signer. type SignerCertsMutex struct { sync.RWMutex // Certs contains the chain of certificates from intermediate to root Certs []*x509.Certificate // Signer signs issued certificates Signer crypto.Signer } func (s *SignerCertsMutex) GetSignerWithChain() ([]*x509.Certificate, crypto.Signer) { s.RLock() defer s.RUnlock() return s.Certs, s.Signer } fulcio-1.6.5/pkg/ca/signercerts_test.go000066400000000000000000000032361470150653400200770ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 ca import ( "crypto/x509" "reflect" "testing" "github.com/sigstore/fulcio/pkg/test" "github.com/sigstore/sigstore/pkg/cryptoutils" ) func TestSignerCerts(t *testing.T) { rootCert, rootKey, _ := test.GenerateRootCA() s := SignerCerts{Certs: []*x509.Certificate{rootCert}, Signer: rootKey} certs, signer := s.GetSignerWithChain() if err := cryptoutils.EqualKeys(signer.Public(), rootKey.Public()); err != nil { t.Fatalf("keys between CA and signer do not match: %v", err) } if !reflect.DeepEqual(certs, []*x509.Certificate{rootCert}) { t.Fatalf("expected certificate chains to match") } } func TestSignerCertsMutex(t *testing.T) { rootCert, rootKey, _ := test.GenerateRootCA() s := SignerCertsMutex{Certs: []*x509.Certificate{rootCert}, Signer: rootKey} certs, signer := s.GetSignerWithChain() if err := cryptoutils.EqualKeys(signer.Public(), rootKey.Public()); err != nil { t.Fatalf("keys between CA and signer do not match: %v", err) } if !reflect.DeepEqual(certs, []*x509.Certificate{rootCert}) { t.Fatalf("expected certificate chains to match") } } fulcio-1.6.5/pkg/ca/tinkca/000077500000000000000000000000001470150653400154265ustar00rootroot00000000000000fulcio-1.6.5/pkg/ca/tinkca/signer.go000066400000000000000000000132471470150653400172530ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 tinkca import ( "crypto" "crypto/ecdsa" "crypto/ed25519" "errors" "fmt" "math/big" "github.com/tink-crypto/tink-go/v2/insecurecleartextkeyset" "github.com/tink-crypto/tink-go/v2/keyset" commonpb "github.com/tink-crypto/tink-go/v2/proto/common_go_proto" ecdsapb "github.com/tink-crypto/tink-go/v2/proto/ecdsa_go_proto" ed25519pb "github.com/tink-crypto/tink-go/v2/proto/ed25519_go_proto" tinkpb "github.com/tink-crypto/tink-go/v2/proto/tink_go_proto" signatureSubtle "github.com/tink-crypto/tink-go/v2/signature/subtle" "github.com/tink-crypto/tink-go/v2/subtle" "google.golang.org/protobuf/proto" ) var ( ecdsaSignerKeyVersion = 0 ecdsaSignerTypeURL = "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey" ed25519SignerKeyVersion = 0 ed25519SignerTypeURL = "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey" ) // KeyHandleToSigner converts a key handle to the crypto.Signer interface. // Heavily pulls from Tink's signature and subtle packages. func KeyHandleToSigner(kh *keyset.Handle) (crypto.Signer, error) { // extract the key material from the key handle ks := insecurecleartextkeyset.KeysetMaterial(kh) k := getPrimaryKey(ks) if k == nil { return nil, errors.New("no enabled key found in keyset") } switch k.GetTypeUrl() { case ecdsaSignerTypeURL: // https://github.com/tink-crypto/tink-go/blob/0aadc94a816408c4bdf95885b3c9860ecfd55fc0/signature/ecdsa/signer_key_manager.go#L48 privKey := new(ecdsapb.EcdsaPrivateKey) if err := proto.Unmarshal(k.GetValue(), privKey); err != nil { return nil, fmt.Errorf("error unmarshalling ecdsa private key: %w", err) } if err := validateEcdsaPrivKey(privKey); err != nil { return nil, fmt.Errorf("error validating ecdsa private key: %w", err) } // https://github.com/tink-crypto/tink-go/blob/0aadc94a816408c4bdf95885b3c9860ecfd55fc0/signature/subtle/ecdsa_signer.go#L37 _, curve, _ := getECDSAParamNames(privKey.PublicKey.Params) p := new(ecdsa.PrivateKey) c := subtle.GetCurve(curve) if c == nil { return nil, errors.New("tink ecdsa signer: invalid curve") } p.PublicKey.Curve = c p.D = new(big.Int).SetBytes(privKey.GetKeyValue()) p.PublicKey.X, p.PublicKey.Y = c.ScalarBaseMult(privKey.GetKeyValue()) return p, nil case ed25519SignerTypeURL: // https://github.com/tink-crypto/tink-go/blob/0aadc94a816408c4bdf95885b3c9860ecfd55fc0/signature/ed25519/signer_key_manager.go#L47 privKey := new(ed25519pb.Ed25519PrivateKey) if err := proto.Unmarshal(k.GetValue(), privKey); err != nil { return nil, fmt.Errorf("error unmarshalling ed25519 private key: %w", err) } if err := validateEd25519PrivKey(privKey); err != nil { return nil, fmt.Errorf("error validating ed25519 private key: %w", err) } // https://github.com/tink-crypto/tink-go/blob/0aadc94a816408c4bdf95885b3c9860ecfd55fc0/signature/subtle/ed25519_signer.go#L27 p := ed25519.NewKeyFromSeed(privKey.GetKeyValue()) return p, nil default: return nil, fmt.Errorf("unsupported key type: %s", k.GetTypeUrl()) } } // getPrimaryKey returns the first enabled key from a keyset. func getPrimaryKey(ks *tinkpb.Keyset) *tinkpb.KeyData { for _, k := range ks.GetKey() { if k.GetKeyId() == ks.GetPrimaryKeyId() && k.GetStatus() == tinkpb.KeyStatusType_ENABLED { return k.GetKeyData() } } return nil } // validateEcdsaPrivKey validates the given ECDSAPrivateKey. // https://github.com/tink-crypto/tink-go/blob/0aadc94a816408c4bdf95885b3c9860ecfd55fc0/signature/ecdsa/signer_key_manager.go#L151 func validateEcdsaPrivKey(key *ecdsapb.EcdsaPrivateKey) error { if err := keyset.ValidateKeyVersion(key.Version, uint32(ecdsaSignerKeyVersion)); err != nil { return fmt.Errorf("ecdsa: invalid key version in key: %s", err) } if err := keyset.ValidateKeyVersion(key.GetPublicKey().GetVersion(), uint32(ecdsaSignerKeyVersion)); err != nil { return fmt.Errorf("ecdsa: invalid public version in key: %s", err) } hash, curve, encoding := getECDSAParamNames(key.PublicKey.Params) return signatureSubtle.ValidateECDSAParams(hash, curve, encoding) } // getECDSAParamNames returns the string representations of each parameter in // the given ECDSAParams. // https://github.com/tink-crypto/tink-go/blob/0aadc94a816408c4bdf95885b3c9860ecfd55fc0/signature/ecdsa/proto.go#L24 func getECDSAParamNames(params *ecdsapb.EcdsaParams) (string, string, string) { hashName := commonpb.HashType_name[int32(params.GetHashType())] curveName := commonpb.EllipticCurveType_name[int32(params.GetCurve())] encodingName := ecdsapb.EcdsaSignatureEncoding_name[int32(params.GetEncoding())] return hashName, curveName, encodingName } // validateEd25519PrivKey validates the given ED25519PrivateKey. // https://github.com/tink-crypto/tink-go/blob/0aadc94a816408c4bdf95885b3c9860ecfd55fc0/signature/ed25519/signer_key_manager.go#L157 func validateEd25519PrivKey(key *ed25519pb.Ed25519PrivateKey) error { if err := keyset.ValidateKeyVersion(key.Version, uint32(ed25519SignerKeyVersion)); err != nil { return fmt.Errorf("ed25519: invalid key: %w", err) } if len(key.KeyValue) != ed25519.SeedSize { return fmt.Errorf("ed25519: invalid key length, got %d", len(key.KeyValue)) } return nil } fulcio-1.6.5/pkg/ca/tinkca/signer_test.go000066400000000000000000000077011470150653400203100ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 tinkca import ( "crypto/ecdsa" "crypto/ed25519" "crypto/rand" "crypto/sha256" "crypto/sha512" "hash" "testing" "github.com/tink-crypto/tink-go/v2/keyset" "github.com/tink-crypto/tink-go/v2/proto/tink_go_proto" "github.com/tink-crypto/tink-go/v2/signature" ) type TestStruct struct { keyTemplate *tink_go_proto.KeyTemplate h hash.Hash } func TestKeyHandleToSignerECDSA(t *testing.T) { supportedKeyTypes := []TestStruct{ { keyTemplate: signature.ECDSAP256KeyWithoutPrefixTemplate(), h: sha256.New(), }, { keyTemplate: signature.ECDSAP384KeyWithoutPrefixTemplate(), h: sha512.New(), }, { keyTemplate: signature.ECDSAP521KeyWithoutPrefixTemplate(), h: sha512.New(), }, } for _, kt := range supportedKeyTypes { kh, err := keyset.NewHandle(kt.keyTemplate) if err != nil { t.Fatalf("error creating ECDSA key handle: %v", err) } // convert to crypto.Signer interface signer, err := KeyHandleToSigner(kh) if err != nil { t.Fatalf("error converting ECDSA key handle to signer: %v", err) } msg := []byte("hello there") // sign with key handle, verify with signer public key tinkSigner, err := signature.NewSigner(kh) if err != nil { t.Fatalf("error creating tink signer: %v", err) } sig, err := tinkSigner.Sign(msg) if err != nil { t.Fatalf("error signing with tink signer: %v", err) } kt.h.Write(msg) digest := kt.h.Sum(nil) if !ecdsa.VerifyASN1(signer.Public().(*ecdsa.PublicKey), digest, sig) { t.Fatalf("signature from tink signer did not match") } // sign with signer, verify with key handle sig, err = ecdsa.SignASN1(rand.Reader, signer.(*ecdsa.PrivateKey), digest) if err != nil { t.Fatalf("error signing with crypto signer: %v", err) } pubkh, err := kh.Public() if err != nil { t.Fatalf("error fetching public key handle: %v", err) } v, err := signature.NewVerifier(pubkh) if err != nil { t.Fatalf("error creating tink verifier: %v", err) } if err := v.Verify(sig, msg); err != nil { t.Fatalf("error verifying with tink verifier: %v", err) } } } func TestKeyHandleToSignerED25519(t *testing.T) { kh, err := keyset.NewHandle(signature.ED25519KeyWithoutPrefixTemplate()) if err != nil { t.Fatalf("error creating ED25519 key handle: %v", err) } // convert to crypto.Signer interface signer, err := KeyHandleToSigner(kh) if err != nil { t.Fatalf("error converting ED25519 key handle to signer: %v", err) } msg := []byte("hello there") // sign with key handle, verify with signer public key tinkSigner, err := signature.NewSigner(kh) if err != nil { t.Fatalf("error creating tink signer: %v", err) } sig, err := tinkSigner.Sign(msg) if err != nil { t.Fatalf("error signing with tink signer: %v", err) } if !ed25519.Verify(signer.Public().(ed25519.PublicKey), msg, sig) { t.Fatalf("signature from tink signer did not match") } // sign with signer, verify with key handle sig = ed25519.Sign(signer.(ed25519.PrivateKey), msg) if err != nil { t.Fatalf("error signing with crypto signer: %v", err) } pubkh, err := kh.Public() if err != nil { t.Fatalf("error fetching public key handle: %v", err) } v, err := signature.NewVerifier(pubkh) if err != nil { t.Fatalf("error creating tink verifier: %v", err) } if err := v.Verify(sig, msg); err != nil { t.Fatalf("error verifying with tink verifier: %v", err) } } fulcio-1.6.5/pkg/ca/tinkca/tinkca.go000066400000000000000000000060171470150653400172320ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 tinkca import ( "bytes" "context" "errors" "os" "path/filepath" "strings" "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/ca/baseca" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/tink-crypto/tink-go-awskms/v2/integration/awskms" "github.com/tink-crypto/tink-go-gcpkms/v2/integration/gcpkms" "github.com/tink-crypto/tink-go/v2/core/registry" "github.com/tink-crypto/tink-go/v2/keyset" "github.com/tink-crypto/tink-go/v2/tink" ) type tinkCA struct { baseca.BaseCA } // NewTinkCA creates a signer from an encrypted Tink keyset, encrypted with a GCP KMS key. func NewTinkCA(ctx context.Context, kmsKey, tinkKeysetPath, certPath string) (ca.CertificateAuthority, error) { primaryKey, err := GetPrimaryKey(ctx, kmsKey) if err != nil { return nil, err } return NewTinkCAFromHandle(ctx, tinkKeysetPath, certPath, primaryKey) } // NewTinkCAFromHandle creates a signer from an encrypted Tink keyset, encrypted with an AEAD key. func NewTinkCAFromHandle(_ context.Context, tinkKeysetPath, certPath string, primaryKey tink.AEAD) (ca.CertificateAuthority, error) { var tca tinkCA f, err := os.Open(filepath.Clean(tinkKeysetPath)) if err != nil { return nil, err } defer f.Close() kh, err := keyset.Read(keyset.NewJSONReader(f), primaryKey) if err != nil { return nil, err } signer, err := KeyHandleToSigner(kh) if err != nil { return nil, err } sc := ca.SignerCerts{} tca.SignerWithChain = &sc sc.Signer = signer data, err := os.ReadFile(filepath.Clean(certPath)) if err != nil { return nil, err } sc.Certs, err = cryptoutils.LoadCertificatesFromPEM(bytes.NewReader(data)) if err != nil { return nil, err } if err := ca.VerifyCertChain(sc.Certs, sc.Signer); err != nil { return nil, err } return &tca, nil } // GetPrimaryKey returns a Tink AEAD encryption key from KMS // Supports GCP and AWS func GetPrimaryKey(ctx context.Context, kmsKey string) (tink.AEAD, error) { switch { case strings.HasPrefix(kmsKey, "gcp-kms://"): gcpClient, err := gcpkms.NewClientWithOptions(ctx, kmsKey) if err != nil { return nil, err } registry.RegisterKMSClient(gcpClient) return gcpClient.GetAEAD(kmsKey) case strings.HasPrefix(kmsKey, "aws-kms://"): awsClient, err := awskms.NewClientWithOptions(kmsKey) if err != nil { return nil, err } registry.RegisterKMSClient(awsClient) return awsClient.GetAEAD(kmsKey) default: return nil, errors.New("unsupported KMS key type") } } fulcio-1.6.5/pkg/ca/tinkca/tinkca_test.go000066400000000000000000000112531470150653400202670ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 tinkca import ( "context" "crypto/x509" "os" "path/filepath" "reflect" "strings" "testing" "github.com/sigstore/fulcio/pkg/test" "github.com/sigstore/sigstore/pkg/cryptoutils" _ "github.com/sigstore/sigstore/pkg/signature/kms/fake" "github.com/tink-crypto/tink-go/v2/aead" "github.com/tink-crypto/tink-go/v2/keyset" "github.com/tink-crypto/tink-go/v2/signature" ) func TestNewTinkCA(t *testing.T) { aeskh, err := keyset.NewHandle(aead.AES256GCMKeyTemplate()) if err != nil { t.Fatalf("error creating AEAD key handle: %v", err) } a, err := aead.New(aeskh) if err != nil { t.Fatalf("error creating AEAD key: %v", err) } kh, err := keyset.NewHandle(signature.ECDSAP256KeyTemplate()) if err != nil { t.Fatalf("error creating ECDSA key handle: %v", err) } khsigner, err := KeyHandleToSigner(kh) if err != nil { t.Fatalf("error converting ECDSA key handle to signer: %v", err) } rootCert, _ := test.GenerateRootCAFromSigner(khsigner) chain := []*x509.Certificate{rootCert} pemChain, err := cryptoutils.MarshalCertificatesToPEM(chain) if err != nil { t.Fatalf("error marshalling cert chain: %v", err) } dir := t.TempDir() certPath := filepath.Join(dir, "cert.pem") err = os.WriteFile(certPath, pemChain, 0600) if err != nil { t.Fatalf("error writing pem chain: %v", err) } keysetPath := filepath.Join(dir, "keyset.json.enc") f, err := os.Create(keysetPath) if err != nil { t.Fatalf("error creating file: %v", err) } defer f.Close() jsonWriter := keyset.NewJSONWriter(f) if err := kh.Write(jsonWriter, a); err != nil { t.Fatalf("error writing enc keyset: %v", err) } ca, err := NewTinkCAFromHandle(context.TODO(), keysetPath, certPath, a) if err != nil { t.Fatalf("unexpected error creating KMS CA: %v", err) } // Expect certificate chain from Root matches provided certificate chain rootChains, err := ca.TrustBundle(context.TODO()) if err != nil { t.Fatalf("error fetching root: %v", err) } if len(rootChains) != 1 { t.Fatalf("unexpected number of chains: %d", len(rootChains)) } if !reflect.DeepEqual(rootChains[0], chain) { t.Fatal("cert chains do not match") } // Expect signer and certificate's public keys match certs, signer := ca.(*tinkCA).GetSignerWithChain() if err := cryptoutils.EqualKeys(signer.Public(), khsigner.Public()); err != nil { t.Fatalf("keys between CA and signer do not match: %v", err) } if !reflect.DeepEqual(certs, []*x509.Certificate{rootCert}) { t.Fatalf("expected certificate chains to match") } // Failure: Mismatch between signer and certificate key otherRootCert, _, _ := test.GenerateRootCA() pemChain, err = cryptoutils.MarshalCertificatesToPEM([]*x509.Certificate{otherRootCert}) if err != nil { t.Fatalf("error marshalling cert chain: %v", err) } err = os.WriteFile(certPath, pemChain, 0600) if err != nil { t.Fatalf("error writing pem chain: %v", err) } _, err = NewTinkCAFromHandle(context.TODO(), keysetPath, certPath, a) if err == nil || !strings.Contains(err.Error(), "ecdsa public keys are not equal") { t.Fatalf("expected error with mismatched public keys, got %v", err) } // Failure: Invalid certificate chain pemChain, err = cryptoutils.MarshalCertificatesToPEM([]*x509.Certificate{rootCert, otherRootCert}) if err != nil { t.Fatalf("error marshalling cert chain: %v", err) } err = os.WriteFile(certPath, pemChain, 0600) if err != nil { t.Fatalf("error writing pem chain: %v", err) } _, err = NewTinkCAFromHandle(context.TODO(), keysetPath, certPath, a) if err == nil || !strings.Contains(err.Error(), "certificate signed by unknown authority") { t.Fatalf("expected error with invalid certificate chain, got %v", err) } // Failure: Unable to decrypt keyset aeskh1, err := keyset.NewHandle(aead.AES256GCMKeyTemplate()) if err != nil { t.Fatalf("error creating AEAD key handle: %v", err) } a1, err := aead.New(aeskh1) if err != nil { t.Fatalf("error creating AEAD key: %v", err) } _, err = NewTinkCAFromHandle(context.TODO(), keysetPath, certPath, a1) if err == nil || !strings.Contains(err.Error(), "decryption failed") { t.Fatalf("expected error decrypting keyset, got %v", err) } } fulcio-1.6.5/pkg/certificate/000077500000000000000000000000001470150653400160545ustar00rootroot00000000000000fulcio-1.6.5/pkg/certificate/doc.go000066400000000000000000000013151470150653400171500ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 certificate contains helpers for getting data from Fulcio issued // x509 certificates. package certificate fulcio-1.6.5/pkg/certificate/extensions.go000066400000000000000000000400431470150653400206030ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 certificate import ( "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" ) var ( // Deprecated: Use OIDIssuerV2 OIDIssuer = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1} // Deprecated: Use OIDBuildTrigger OIDGitHubWorkflowTrigger = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 2} // Deprecated: Use OIDSourceRepositoryDigest OIDGitHubWorkflowSHA = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 3} // Deprecated: Use OIDBuildConfigURI or OIDBuildConfigDigest OIDGitHubWorkflowName = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 4} // Deprecated: Use SourceRepositoryURI OIDGitHubWorkflowRepository = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 5} // Deprecated: Use OIDSourceRepositoryRef OIDGitHubWorkflowRef = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 6} OIDOtherName = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 7} OIDIssuerV2 = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 8} // CI extensions OIDBuildSignerURI = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 9} OIDBuildSignerDigest = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 10} OIDRunnerEnvironment = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 11} OIDSourceRepositoryURI = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 12} OIDSourceRepositoryDigest = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 13} OIDSourceRepositoryRef = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 14} OIDSourceRepositoryIdentifier = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 15} OIDSourceRepositoryOwnerURI = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 16} OIDSourceRepositoryOwnerIdentifier = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 17} OIDBuildConfigURI = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 18} OIDBuildConfigDigest = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 19} OIDBuildTrigger = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 20} OIDRunInvocationURI = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 21} OIDSourceRepositoryVisibilityAtSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 22} ) // Extensions contains all custom x509 extensions defined by Fulcio type Extensions struct { // NB: New extensions must be added here and documented // at docs/oidc-info.md // The OIDC issuer. Should match `iss` claim of ID token or, in the case of // a federated login like Dex it should match the issuer URL of the // upstream issuer. The issuer is not set the extensions are invalid and // will fail to render. Issuer string // OID 1.3.6.1.4.1.57264.1.8 and 1.3.6.1.4.1.57264.1.1 (Deprecated) // Deprecated // Triggering event of the Github Workflow. Matches the `event_name` claim of ID // tokens from Github Actions GithubWorkflowTrigger string `json:"GithubWorkflowTrigger,omitempty" yaml:"github-workflow-trigger,omitempty"` // OID 1.3.6.1.4.1.57264.1.2 // Deprecated // SHA of git commit being built in Github Actions. Matches the `sha` claim of ID // tokens from Github Actions GithubWorkflowSHA string `json:"GithubWorkflowSHA,omitempty" yaml:"github-workflow-sha,omitempty"` // OID 1.3.6.1.4.1.57264.1.3 // Deprecated // Name of Github Actions Workflow. Matches the `workflow` claim of the ID // tokens from Github Actions GithubWorkflowName string `json:"GithubWorkflowName,omitempty" yaml:"github-workflow-name,omitempty"` // OID 1.3.6.1.4.1.57264.1.4 // Deprecated // Repository of the Github Actions Workflow. Matches the `repository` claim of the ID // tokens from Github Actions GithubWorkflowRepository string `json:"GithubWorkflowRepository,omitempty" yaml:"github-workflow-repository,omitempty"` // OID 1.3.6.1.4.1.57264.1.5 // Deprecated // Git Ref of the Github Actions Workflow. Matches the `ref` claim of the ID tokens // from Github Actions GithubWorkflowRef string `json:"GithubWorkflowRef,omitempty" yaml:"github-workflow-ref,omitempty"` // 1.3.6.1.4.1.57264.1.6 // Reference to specific build instructions that are responsible for signing. BuildSignerURI string `json:"BuildSignerURI,omitempty" yaml:"build-signer-uri,omitempty"` // 1.3.6.1.4.1.57264.1.9 // Immutable reference to the specific version of the build instructions that is responsible for signing. BuildSignerDigest string `json:"BuildSignerDigest,omitempty" yaml:"build-signer-digest,omitempty"` // 1.3.6.1.4.1.57264.1.10 // Specifies whether the build took place in platform-hosted cloud infrastructure or customer/self-hosted infrastructure. RunnerEnvironment string `json:"RunnerEnvironment,omitempty" yaml:"runner-environment,omitempty"` // 1.3.6.1.4.1.57264.1.11 // Source repository URL that the build was based on. SourceRepositoryURI string `json:"SourceRepositoryURI,omitempty" yaml:"source-repository-uri,omitempty"` // 1.3.6.1.4.1.57264.1.12 // Immutable reference to a specific version of the source code that the build was based upon. SourceRepositoryDigest string `json:"SourceRepositoryDigest,omitempty" yaml:"source-repository-digest,omitempty"` // 1.3.6.1.4.1.57264.1.13 // Source Repository Ref that the build run was based upon. SourceRepositoryRef string `json:"SourceRepositoryRef,omitempty" yaml:"source-repository-ref,omitempty"` // 1.3.6.1.4.1.57264.1.14 // Immutable identifier for the source repository the workflow was based upon. SourceRepositoryIdentifier string `json:"SourceRepositoryIdentifier,omitempty" yaml:"source-repository-identifier,omitempty"` // 1.3.6.1.4.1.57264.1.15 // Source repository owner URL of the owner of the source repository that the build was based on. SourceRepositoryOwnerURI string `json:"SourceRepositoryOwnerURI,omitempty" yaml:"source-repository-owner-uri,omitempty"` // 1.3.6.1.4.1.57264.1.16 // Immutable identifier for the owner of the source repository that the workflow was based upon. SourceRepositoryOwnerIdentifier string `json:"SourceRepositoryOwnerIdentifier,omitempty" yaml:"source-repository-owner-identifier,omitempty"` // 1.3.6.1.4.1.57264.1.17 // Build Config URL to the top-level/initiating build instructions. BuildConfigURI string `json:"BuildConfigURI,omitempty" yaml:"build-config-uri,omitempty"` // 1.3.6.1.4.1.57264.1.18 // Immutable reference to the specific version of the top-level/initiating build instructions. BuildConfigDigest string `json:"BuildConfigDigest,omitempty" yaml:"build-config-digest,omitempty"` // 1.3.6.1.4.1.57264.1.19 // Event or action that initiated the build. BuildTrigger string `json:"BuildTrigger,omitempty" yaml:"build-trigger,omitempty"` // 1.3.6.1.4.1.57264.1.20 // Run Invocation URL to uniquely identify the build execution. RunInvocationURI string `json:"RunInvocationURI,omitempty" yaml:"run-invocation-uri,omitempty"` // 1.3.6.1.4.1.57264.1.21 // Source repository visibility at the time of signing the certificate. SourceRepositoryVisibilityAtSigning string `json:"SourceRepositoryVisibilityAtSigning,omitempty" yaml:"source-repository-visibility-at-signing,omitempty"` // 1.3.6.1.4.1.57264.1.22 } func (e Extensions) Render() ([]pkix.Extension, error) { var exts []pkix.Extension // BEGIN: Deprecated if e.Issuer != "" { // deprecated issuer extension due to incorrect encoding exts = append(exts, pkix.Extension{ Id: OIDIssuer, Value: []byte(e.Issuer), }) } else { return nil, errors.New("extensions must have a non-empty issuer url") } if e.GithubWorkflowTrigger != "" { exts = append(exts, pkix.Extension{ Id: OIDGitHubWorkflowTrigger, Value: []byte(e.GithubWorkflowTrigger), }) } if e.GithubWorkflowSHA != "" { exts = append(exts, pkix.Extension{ Id: OIDGitHubWorkflowSHA, Value: []byte(e.GithubWorkflowSHA), }) } if e.GithubWorkflowName != "" { exts = append(exts, pkix.Extension{ Id: OIDGitHubWorkflowName, Value: []byte(e.GithubWorkflowName), }) } if e.GithubWorkflowRepository != "" { exts = append(exts, pkix.Extension{ Id: OIDGitHubWorkflowRepository, Value: []byte(e.GithubWorkflowRepository), }) } if e.GithubWorkflowRef != "" { exts = append(exts, pkix.Extension{ Id: OIDGitHubWorkflowRef, Value: []byte(e.GithubWorkflowRef), }) } // END: Deprecated // duplicate issuer with correct RFC 5280 encoding if e.Issuer != "" { // construct DER encoding of issuer string val, err := asn1.MarshalWithParams(e.Issuer, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDIssuerV2, Value: val, }) } else { return nil, errors.New("extensions must have a non-empty issuer url") } if e.BuildSignerURI != "" { val, err := asn1.MarshalWithParams(e.BuildSignerURI, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDBuildSignerURI, Value: val, }) } if e.BuildSignerDigest != "" { val, err := asn1.MarshalWithParams(e.BuildSignerDigest, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDBuildSignerDigest, Value: val, }) } if e.RunnerEnvironment != "" { val, err := asn1.MarshalWithParams(e.RunnerEnvironment, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDRunnerEnvironment, Value: val, }) } if e.SourceRepositoryURI != "" { val, err := asn1.MarshalWithParams(e.SourceRepositoryURI, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDSourceRepositoryURI, Value: val, }) } if e.SourceRepositoryDigest != "" { val, err := asn1.MarshalWithParams(e.SourceRepositoryDigest, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDSourceRepositoryDigest, Value: val, }) } if e.SourceRepositoryRef != "" { val, err := asn1.MarshalWithParams(e.SourceRepositoryRef, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDSourceRepositoryRef, Value: val, }) } if e.SourceRepositoryIdentifier != "" { val, err := asn1.MarshalWithParams(e.SourceRepositoryIdentifier, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDSourceRepositoryIdentifier, Value: val, }) } if e.SourceRepositoryOwnerURI != "" { val, err := asn1.MarshalWithParams(e.SourceRepositoryOwnerURI, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDSourceRepositoryOwnerURI, Value: val, }) } if e.SourceRepositoryOwnerIdentifier != "" { val, err := asn1.MarshalWithParams(e.SourceRepositoryOwnerIdentifier, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDSourceRepositoryOwnerIdentifier, Value: val, }) } if e.BuildConfigURI != "" { val, err := asn1.MarshalWithParams(e.BuildConfigURI, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDBuildConfigURI, Value: val, }) } if e.BuildConfigDigest != "" { val, err := asn1.MarshalWithParams(e.BuildConfigDigest, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDBuildConfigDigest, Value: val, }) } if e.BuildTrigger != "" { val, err := asn1.MarshalWithParams(e.BuildTrigger, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDBuildTrigger, Value: val, }) } if e.RunInvocationURI != "" { val, err := asn1.MarshalWithParams(e.RunInvocationURI, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDRunInvocationURI, Value: val, }) } if e.SourceRepositoryVisibilityAtSigning != "" { val, err := asn1.MarshalWithParams(e.SourceRepositoryVisibilityAtSigning, "utf8") if err != nil { return nil, err } exts = append(exts, pkix.Extension{ Id: OIDSourceRepositoryVisibilityAtSigning, Value: val, }) } return exts, nil } func ParseExtensions(ext []pkix.Extension) (Extensions, error) { out := Extensions{} for _, e := range ext { switch { // BEGIN: Deprecated case e.Id.Equal(OIDIssuer): out.Issuer = string(e.Value) case e.Id.Equal(OIDGitHubWorkflowTrigger): out.GithubWorkflowTrigger = string(e.Value) case e.Id.Equal(OIDGitHubWorkflowSHA): out.GithubWorkflowSHA = string(e.Value) case e.Id.Equal(OIDGitHubWorkflowName): out.GithubWorkflowName = string(e.Value) case e.Id.Equal(OIDGitHubWorkflowRepository): out.GithubWorkflowRepository = string(e.Value) case e.Id.Equal(OIDGitHubWorkflowRef): out.GithubWorkflowRef = string(e.Value) // END: Deprecated case e.Id.Equal(OIDIssuerV2): if err := ParseDERString(e.Value, &out.Issuer); err != nil { return Extensions{}, err } case e.Id.Equal(OIDBuildSignerURI): if err := ParseDERString(e.Value, &out.BuildSignerURI); err != nil { return Extensions{}, err } case e.Id.Equal(OIDBuildSignerDigest): if err := ParseDERString(e.Value, &out.BuildSignerDigest); err != nil { return Extensions{}, err } case e.Id.Equal(OIDRunnerEnvironment): if err := ParseDERString(e.Value, &out.RunnerEnvironment); err != nil { return Extensions{}, err } case e.Id.Equal(OIDSourceRepositoryURI): if err := ParseDERString(e.Value, &out.SourceRepositoryURI); err != nil { return Extensions{}, err } case e.Id.Equal(OIDSourceRepositoryDigest): if err := ParseDERString(e.Value, &out.SourceRepositoryDigest); err != nil { return Extensions{}, err } case e.Id.Equal(OIDSourceRepositoryRef): if err := ParseDERString(e.Value, &out.SourceRepositoryRef); err != nil { return Extensions{}, err } case e.Id.Equal(OIDSourceRepositoryIdentifier): if err := ParseDERString(e.Value, &out.SourceRepositoryIdentifier); err != nil { return Extensions{}, err } case e.Id.Equal(OIDSourceRepositoryOwnerURI): if err := ParseDERString(e.Value, &out.SourceRepositoryOwnerURI); err != nil { return Extensions{}, err } case e.Id.Equal(OIDSourceRepositoryOwnerIdentifier): if err := ParseDERString(e.Value, &out.SourceRepositoryOwnerIdentifier); err != nil { return Extensions{}, err } case e.Id.Equal(OIDBuildConfigURI): if err := ParseDERString(e.Value, &out.BuildConfigURI); err != nil { return Extensions{}, err } case e.Id.Equal(OIDBuildConfigDigest): if err := ParseDERString(e.Value, &out.BuildConfigDigest); err != nil { return Extensions{}, err } case e.Id.Equal(OIDBuildTrigger): if err := ParseDERString(e.Value, &out.BuildTrigger); err != nil { return Extensions{}, err } case e.Id.Equal(OIDRunInvocationURI): if err := ParseDERString(e.Value, &out.RunInvocationURI); err != nil { return Extensions{}, err } case e.Id.Equal(OIDSourceRepositoryVisibilityAtSigning): if err := ParseDERString(e.Value, &out.SourceRepositoryVisibilityAtSigning); err != nil { return Extensions{}, err } } } // We only ever return nil, but leaving error in place so that we can add // more complex parsing of fields in a backwards compatible way if needed. return out, nil } // ParseDERString decodes a DER-encoded string and puts the value in parsedVal. // Returns an error if the unmarshalling fails or if there are trailing bytes in the encoding. func ParseDERString(val []byte, parsedVal *string) error { rest, err := asn1.Unmarshal(val, parsedVal) if err != nil { return fmt.Errorf("unexpected error unmarshalling DER-encoded string: %v", err) } if len(rest) != 0 { return errors.New("unexpected trailing bytes in DER-encoded string") } return nil } fulcio-1.6.5/pkg/certificate/extensions_test.go000066400000000000000000000130531470150653400216430ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 certificate import ( "crypto/x509/pkix" "encoding/asn1" "testing" "github.com/google/go-cmp/cmp" ) func TestExtensions(t *testing.T) { tests := map[string]struct { Extensions Extensions Expect []pkix.Extension WantErr bool }{ `Missing issuer extension leads to render error`: { Extensions: Extensions{ GithubWorkflowTrigger: `foo`, }, WantErr: true, }, `complete extensions list should create all extensions with correct OIDs`: { Extensions: Extensions{ Issuer: "issuer", // OID 1.3.6.1.4.1.57264.1.1 and 1.3.6.1.4.1.57264.1.8 GithubWorkflowTrigger: "2", // OID 1.3.6.1.4.1.57264.1.2 GithubWorkflowSHA: "3", // OID 1.3.6.1.4.1.57264.1.3 GithubWorkflowName: "4", // OID 1.3.6.1.4.1.57264.1.4 GithubWorkflowRepository: "5", // OID 1.3.6.1.4.1.57264.1.5 GithubWorkflowRef: "6", // 1.3.6.1.4.1.57264.1.6 BuildSignerURI: "9", // 1.3.6.1.4.1.57264.1.9 BuildSignerDigest: "10", // 1.3.6.1.4.1.57264.1.10 RunnerEnvironment: "11", // 1.3.6.1.4.1.57264.1.11 SourceRepositoryURI: "12", // 1.3.6.1.4.1.57264.1.12 SourceRepositoryDigest: "13", // 1.3.6.1.4.1.57264.1.13 SourceRepositoryRef: "14", // 1.3.6.1.4.1.57264.1.14 SourceRepositoryIdentifier: "15", // 1.3.6.1.4.1.57264.1.15 SourceRepositoryOwnerURI: "16", // 1.3.6.1.4.1.57264.1.16 SourceRepositoryOwnerIdentifier: "17", // 1.3.6.1.4.1.57264.1.17 BuildConfigURI: "18", // 1.3.6.1.4.1.57264.1.18 BuildConfigDigest: "19", // 1.3.6.1.4.1.57264.1.19 BuildTrigger: "20", // 1.3.6.1.4.1.57264.1.20 RunInvocationURI: "21", // 1.3.6.1.4.1.57264.1.21 SourceRepositoryVisibilityAtSigning: "22", // 1.3.6.1.4.1.57264.1.22 }, Expect: []pkix.Extension{ { Id: OIDIssuer, Value: []byte("issuer"), }, { Id: OIDGitHubWorkflowTrigger, Value: []byte("2"), }, { Id: OIDGitHubWorkflowSHA, Value: []byte("3"), }, { Id: OIDGitHubWorkflowName, Value: []byte("4"), }, { Id: OIDGitHubWorkflowRepository, Value: []byte("5"), }, { Id: OIDGitHubWorkflowRef, Value: []byte("6"), }, { Id: OIDIssuerV2, Value: marshalDERString(t, "issuer"), }, { Id: OIDBuildSignerURI, Value: marshalDERString(t, "9"), }, { Id: OIDBuildSignerDigest, Value: marshalDERString(t, "10"), }, { Id: OIDRunnerEnvironment, Value: marshalDERString(t, "11"), }, { Id: OIDSourceRepositoryURI, Value: marshalDERString(t, "12"), }, { Id: OIDSourceRepositoryDigest, Value: marshalDERString(t, "13"), }, { Id: OIDSourceRepositoryRef, Value: marshalDERString(t, "14"), }, { Id: OIDSourceRepositoryIdentifier, Value: marshalDERString(t, "15"), }, { Id: OIDSourceRepositoryOwnerURI, Value: marshalDERString(t, "16"), }, { Id: OIDSourceRepositoryOwnerIdentifier, Value: marshalDERString(t, "17"), }, { Id: OIDBuildConfigURI, Value: marshalDERString(t, "18"), }, { Id: OIDBuildConfigDigest, Value: marshalDERString(t, "19"), }, { Id: OIDBuildTrigger, Value: marshalDERString(t, "20"), }, { Id: OIDRunInvocationURI, Value: marshalDERString(t, "21"), }, { Id: OIDSourceRepositoryVisibilityAtSigning, Value: marshalDERString(t, "22"), }, }, WantErr: false, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { render, err := test.Extensions.Render() if err != nil { if !test.WantErr { t.Error("Failed to render with unexpected error", err) } else { return } } if diff := cmp.Diff(test.Expect, render); diff != "" { t.Errorf("Render: %s", diff) } parse, err := ParseExtensions(render) if err != nil { t.Fatalf("ParseExtensions: err = %v", err) } if diff := cmp.Diff(test.Extensions, parse); diff != "" { t.Errorf("ParseExtensions: %s", diff) } }) } } func marshalDERString(t *testing.T, val string) []byte { derString, err := asn1.MarshalWithParams(val, "utf8") if err != nil { t.Fatalf("error marshalling string %v", err) } return derString } func TestParseDERString(t *testing.T) { input := []byte{0x13, 0x0b, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64} expected := "Hello World" var actual string err := ParseDERString(input, &actual) if err != nil { t.Errorf("unexpected error: %v", err) } if actual != expected { t.Errorf("unexpected result: got %q, want %q", actual, expected) } } fulcio-1.6.5/pkg/challenges/000077500000000000000000000000001470150653400156775ustar00rootroot00000000000000fulcio-1.6.5/pkg/challenges/challenges.go000066400000000000000000000071431470150653400203400ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 challenges import ( "bytes" "context" "crypto" "crypto/x509" "errors" "fmt" "strings" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/buildkite" "github.com/sigstore/fulcio/pkg/identity/ciprovider" "github.com/sigstore/fulcio/pkg/identity/email" "github.com/sigstore/fulcio/pkg/identity/github" "github.com/sigstore/fulcio/pkg/identity/gitlabcom" "github.com/sigstore/fulcio/pkg/identity/kubernetes" "github.com/sigstore/fulcio/pkg/identity/spiffe" "github.com/sigstore/fulcio/pkg/identity/uri" "github.com/sigstore/fulcio/pkg/identity/username" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" ) // CheckSignature verifies a challenge, a signature over the subject or email // of an OIDC token func CheckSignature(pub crypto.PublicKey, proof []byte, subject string) error { verifier, err := signature.LoadVerifier(pub, crypto.SHA256) if err != nil { return err } return verifier.VerifySignature(bytes.NewReader(proof), strings.NewReader(subject)) } func PrincipalFromIDToken(ctx context.Context, tok *oidc.IDToken) (identity.Principal, error) { iss, ok := config.FromContext(ctx).GetIssuer(tok.Issuer) if !ok { return nil, fmt.Errorf("configuration can not be loaded for issuer %v", tok.Issuer) } var principal identity.Principal var err error switch iss.Type { case config.IssuerTypeBuildkiteJob: principal, err = buildkite.JobPrincipalFromIDToken(ctx, tok) case config.IssuerTypeGitLabPipeline: principal, err = gitlabcom.JobPrincipalFromIDToken(ctx, tok) case config.IssuerTypeEmail: principal, err = email.PrincipalFromIDToken(ctx, tok) case config.IssuerTypeSpiffe: principal, err = spiffe.PrincipalFromIDToken(ctx, tok) case config.IssuerTypeGithubWorkflow: principal, err = github.WorkflowPrincipalFromIDToken(ctx, tok) case config.IssuerTypeKubernetes: principal, err = kubernetes.PrincipalFromIDToken(ctx, tok) case config.IssuerTypeURI: principal, err = uri.PrincipalFromIDToken(ctx, tok) case config.IssuerTypeUsername: principal, err = username.PrincipalFromIDToken(ctx, tok) case config.IssuerTypeCIProvider: principal, err = ciprovider.WorkflowPrincipalFromIDToken(ctx, tok) default: return nil, fmt.Errorf("unsupported issuer: %s", iss.Type) } if err != nil { return nil, err } return principal, nil } // ParsePublicKey parses a PEM or DER encoded public key. Returns an error if // decoding fails or if no public key is found. func ParsePublicKey(encodedPubKey string) (crypto.PublicKey, error) { if len(encodedPubKey) == 0 { return nil, errors.New("public key not provided") } // try to unmarshal as PEM publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(encodedPubKey)) if err != nil { // try to unmarshal as DER publicKey, err = x509.ParsePKIXPublicKey([]byte(encodedPubKey)) if err != nil { return nil, errors.New("error parsing PEM or DER encoded public key") } } return publicKey, err } fulcio-1.6.5/pkg/challenges/challenges_test.go000066400000000000000000000066731470150653400214060ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 challenges import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/sha256" "testing" "github.com/sigstore/sigstore/pkg/cryptoutils" ) func failErr(t *testing.T, err error) { if err != nil { t.Fatal(err) } } func TestCheckSignatureECDSA(t *testing.T) { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) failErr(t, err) email := "test@gmail.com" if err := CheckSignature(&priv.PublicKey, []byte("foo"), email); err == nil { t.Fatal("check should have failed") } h := sha256.Sum256([]byte(email)) signature, err := priv.Sign(rand.Reader, h[:], crypto.SHA256) failErr(t, err) if err := CheckSignature(&priv.PublicKey, signature, email); err != nil { t.Fatal(err) } // Nil key should fail if err := CheckSignature(nil, signature, email); err == nil { t.Error("nil public key should raise error") } // Try a bad email but "good" signature if err := CheckSignature(&priv.PublicKey, signature, "bad@email.com"); err == nil { t.Fatal("check should have failed") } } func TestCheckSignatureRSA(t *testing.T) { priv, err := rsa.GenerateKey(rand.Reader, 2048) failErr(t, err) email := "test@gmail.com" if err := CheckSignature(&priv.PublicKey, []byte("foo"), email); err == nil { t.Fatal("check should have failed") } h := sha256.Sum256([]byte(email)) signature, err := priv.Sign(rand.Reader, h[:], crypto.SHA256) failErr(t, err) if err := CheckSignature(&priv.PublicKey, signature, email); err != nil { t.Fatal(err) } // Try a bad email but "good" signature if err := CheckSignature(&priv.PublicKey, signature, "bad@email.com"); err == nil { t.Fatal("check should have failed") } } func TestParsePublicKey(t *testing.T) { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) failErr(t, err) // succeeds with PEM-encoded key pemKey, err := cryptoutils.MarshalPublicKeyToPEM(priv.Public()) failErr(t, err) pubKey, err := ParsePublicKey(string(pemKey)) failErr(t, err) if err := cryptoutils.EqualKeys(pubKey, priv.Public()); err != nil { t.Fatalf("expected equal public keys") } // succeeds with DER-encoded key derKey, err := cryptoutils.MarshalPublicKeyToDER(priv.Public()) failErr(t, err) pubKey, err = ParsePublicKey(string(derKey)) failErr(t, err) if err := cryptoutils.EqualKeys(pubKey, priv.Public()); err != nil { t.Fatalf("expected equal public keys") } // fails with no public key _, err = ParsePublicKey("") if err == nil || err.Error() != "public key not provided" { t.Fatalf("expected error parsing no public key, got %v", err) } // fails with invalid public key (private key) pemPrivKey, err := cryptoutils.MarshalPrivateKeyToPEM(priv) failErr(t, err) _, err = ParsePublicKey(string(pemPrivKey)) if err == nil || err.Error() != "error parsing PEM or DER encoded public key" { t.Fatalf("expected error parsing invalid public key, got %v", err) } } fulcio-1.6.5/pkg/config/000077500000000000000000000000001470150653400150375ustar00rootroot00000000000000fulcio-1.6.5/pkg/config/config.go000066400000000000000000000474261470150653400166500ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 ( "context" "crypto/x509" "encoding/json" "errors" "fmt" "html/template" "net/http" "net/url" "os" "reflect" "regexp" "strings" "time" "github.com/coreos/go-oidc/v3/oidc" lru "github.com/hashicorp/golang-lru" "github.com/sigstore/fulcio/pkg/certificate" fulciogrpc "github.com/sigstore/fulcio/pkg/generated/protobuf" "github.com/sigstore/fulcio/pkg/log" "github.com/spiffe/go-spiffe/v2/spiffeid" "gopkg.in/yaml.v3" ) const defaultOIDCDiscoveryTimeout = 10 * time.Second // All hostnames for subject and issuer OIDC claims must have at least a // top-level and second-level domain const minimumHostnameLength = 2 type verifierWithConfig struct { *oidc.IDTokenVerifier *oidc.Config } type FulcioConfig struct { OIDCIssuers map[string]OIDCIssuer `json:"OIDCIssuers,omitempty" yaml:"oidc-issuers,omitempty"` // A meta issuer has a templated URL of the form: // https://oidc.eks.*.amazonaws.com/id/* // Where * can match a single hostname or URI path parts // (in particular, no '.' or '/' are permitted, among // other special characters) Some examples we want to match: // * https://oidc.eks.us-west-2.amazonaws.com/id/B02C93B6A2D30341AD01E1B6D48164CB // * https://container.googleapis.com/v1/projects/mattmoor-credit/locations/us-west1-b/clusters/tenant-cluster MetaIssuers map[string]OIDCIssuer `json:"MetaIssuers,omitempty" yaml:"meta-issuers,omitempty"` // It defines metadata to be used for the CIProvider identity provider principal. // The CI provider has a generic logic for ci providers, this metadata is used // to define the right behavior for each ci provider that is defined // on the configuration file CIIssuerMetadata map[string]IssuerMetadata `json:"CIIssuerMetadata,omitempty" yaml:"ci-issuer-metadata,omitempty"` // verifiers is a fixed mapping from our OIDCIssuers to their OIDC verifiers. verifiers map[string][]*verifierWithConfig // lru is an LRU cache of recently used verifiers for our meta issuers. lru *lru.TwoQueueCache } type IssuerMetadata struct { // Defaults contains key-value pairs that can be used for filling the templates from ExtensionTemplates // If a key cannot be found on the token claims, the template will use the defaults DefaultTemplateValues map[string]string `json:"DefaultTemplateValues,omitempty" yaml:"default-template-values,omitempty"` // ExtensionTemplates contains a mapping between certificate extension and token claim // Provide either strings following https://pkg.go.dev/text/template syntax, // e.g "{{ .url }}/{{ .repository }}" // or non-templated strings with token claim keys to be replaced, // e.g "job_workflow_sha" ExtensionTemplates certificate.Extensions `json:"ExtensionTemplates,omitempty" yaml:"extension-templates,omitempty"` // Template for the Subject Alternative Name extension // It's typically the same value as Build Signer URI SubjectAlternativeNameTemplate string `json:"SubjectAlternativeNameTemplate,omitempty" yaml:"subject-alternative-name-template,omitempty"` } type OIDCIssuer struct { // The expected issuer of an OIDC token IssuerURL string `json:"IssuerURL,omitempty" yaml:"issuer-url,omitempty"` // The expected client ID of the OIDC token ClientID string `json:"ClientID" yaml:"client-id,omitempty"` // Used to determine the subject of the certificate and if additional // certificate values are needed Type IssuerType `json:"Type" yaml:"type,omitempty"` // CIProvider is an optional configuration to map token claims to extensions for CI workflows CIProvider string `json:"CIProvider,omitempty" yaml:"ci-provider,omitempty"` // Optional, if the issuer is in a different claim in the OIDC token IssuerClaim string `json:"IssuerClaim,omitempty" yaml:"issuer-claim,omitempty"` // The domain that must be present in the subject for 'uri' issuer types // Also used to create an email for 'username' issuer types SubjectDomain string `json:"SubjectDomain,omitempty" yaml:"subject-domain,omitempty"` // SPIFFETrustDomain specifies the trust domain that 'spiffe' issuer types // issue ID tokens for. Tokens with a different trust domain will be // rejected. SPIFFETrustDomain string `json:"SPIFFETrustDomain,omitempty" yaml:"spiffe-trust-domain,omitempty"` // Optional, the challenge claim expected for the issuer // Set if using a custom issuer ChallengeClaim string `json:"ChallengeClaim,omitempty" yaml:"challenge-claim,omitempty"` // Optional, the description for the issuer Description string `json:"Description,omitempty" yaml:"description,omitempty"` // Optional, the contact for the issuer team // Usually it is a email Contact string `json:"Contact,omitempty" yaml:"contact,omitempty"` } func metaRegex(issuer string) (*regexp.Regexp, error) { // Quote all of the "meta" characters like `.` to avoid // those literal characters in the URL matching any character. // This will ALSO quote `*`, so we replace the quoted version. quoted := regexp.QuoteMeta(issuer) // Replace the quoted `*` with a regular expression that // will match alpha-numeric parts with common additional // "special" characters. replaced := strings.ReplaceAll(quoted, regexp.QuoteMeta("*"), "[-_a-zA-Z0-9]+") // Compile into a regular expression. return regexp.Compile(replaced) } // GetIssuer looks up the issuer configuration for an `issuerURL` // coming from an incoming OIDC token. If no matching configuration // is found, then it returns `false`. func (fc *FulcioConfig) GetIssuer(issuerURL string) (OIDCIssuer, bool) { iss, ok := fc.OIDCIssuers[issuerURL] if ok { return iss, ok } for meta, iss := range fc.MetaIssuers { re, err := metaRegex(meta) if err != nil { continue // Shouldn't happen, we check parsing the config } if re.MatchString(issuerURL) { // If it matches, then return a concrete OIDCIssuer // configuration for this issuer URL. return OIDCIssuer{ IssuerURL: issuerURL, ClientID: iss.ClientID, Type: iss.Type, IssuerClaim: iss.IssuerClaim, SubjectDomain: iss.SubjectDomain, CIProvider: iss.CIProvider, }, true } } return OIDCIssuer{}, false } // GetVerifier fetches a token verifier for the given `issuerURL` // coming from an incoming OIDC token. If no matching configuration // is found, then it returns `false`. func (fc *FulcioConfig) GetVerifier(issuerURL string, opts ...InsecureOIDCConfigOption) (*oidc.IDTokenVerifier, bool) { iss, ok := fc.GetIssuer(issuerURL) if !ok { return nil, false } cfg := &oidc.Config{ClientID: iss.ClientID} for _, o := range opts { o(cfg) } // Look up our fixed issuer verifiers v, ok := fc.verifiers[issuerURL] if ok { for _, c := range v { if reflect.DeepEqual(c.Config, cfg) { return c.IDTokenVerifier, true } } } // Look in the LRU cache for a verifier untyped, ok := fc.lru.Get(issuerURL) if ok { v := untyped.([]*verifierWithConfig) for _, c := range v { if reflect.DeepEqual(c.Config, cfg) { return c.IDTokenVerifier, true } } } // If this issuer hasn't been recently used, or we have special config options, then create a new verifier // and add it to the LRU cache. ctx, cancel := context.WithTimeout(context.Background(), defaultOIDCDiscoveryTimeout) defer cancel() provider, err := oidc.NewProvider(ctx, issuerURL) if err != nil { log.Logger.Warnf("Failed to create provider for issuer URL %q: %v", issuerURL, err) return nil, false } vwf := &verifierWithConfig{provider.Verifier(cfg), cfg} if untyped == nil { v = []*verifierWithConfig{vwf} } else { v = append(v, vwf) } fc.lru.Add(issuerURL, v) return vwf.IDTokenVerifier, true } type InsecureOIDCConfigOption func(opt *oidc.Config) func WithSkipExpiryCheck() InsecureOIDCConfigOption { return func(c *oidc.Config) { c.SkipExpiryCheck = true } } // ToIssuers returns a proto representation of the OIDC issuer configuration. func (fc *FulcioConfig) ToIssuers() []*fulciogrpc.OIDCIssuer { var issuers []*fulciogrpc.OIDCIssuer for _, cfgIss := range fc.OIDCIssuers { issuer := &fulciogrpc.OIDCIssuer{ Issuer: &fulciogrpc.OIDCIssuer_IssuerUrl{IssuerUrl: cfgIss.IssuerURL}, Audience: cfgIss.ClientID, SpiffeTrustDomain: cfgIss.SPIFFETrustDomain, ChallengeClaim: issuerToChallengeClaim(cfgIss.Type, cfgIss.ChallengeClaim), IssuerType: cfgIss.Type.String(), SubjectDomain: cfgIss.SubjectDomain, } issuers = append(issuers, issuer) } for metaIss, cfgIss := range fc.MetaIssuers { issuer := &fulciogrpc.OIDCIssuer{ Issuer: &fulciogrpc.OIDCIssuer_WildcardIssuerUrl{WildcardIssuerUrl: metaIss}, Audience: cfgIss.ClientID, SpiffeTrustDomain: cfgIss.SPIFFETrustDomain, ChallengeClaim: issuerToChallengeClaim(cfgIss.Type, cfgIss.ChallengeClaim), IssuerType: cfgIss.Type.String(), SubjectDomain: cfgIss.SubjectDomain, } issuers = append(issuers, issuer) } return issuers } func (fc *FulcioConfig) prepare() error { if _, ok := fc.GetIssuer("https://kubernetes.default.svc"); ok { // Add the Kubernetes cluster's CA to the system CA pool, and to // the default transport. rootCAs, _ := x509.SystemCertPool() if rootCAs == nil { rootCAs = x509.NewCertPool() } const k8sCA = "/var/run/fulcio/ca.crt" certs, err := os.ReadFile(k8sCA) if err != nil { return fmt.Errorf("read file: %w", err) } if ok := rootCAs.AppendCertsFromPEM(certs); !ok { return fmt.Errorf("unable to append certs") } t := originalTransport.(*http.Transport).Clone() t.TLSClientConfig.RootCAs = rootCAs http.DefaultTransport = t } else { // If we parse a config that doesn't include a cluster issuer // signed with the cluster'sCA, then restore the original transport // (in case we overwrote it) http.DefaultTransport = originalTransport } fc.verifiers = make(map[string][]*verifierWithConfig, len(fc.OIDCIssuers)) for _, iss := range fc.OIDCIssuers { ctx, cancel := context.WithTimeout(context.Background(), defaultOIDCDiscoveryTimeout) defer cancel() provider, err := oidc.NewProvider(ctx, iss.IssuerURL) if err != nil { log.Logger.Errorf("error creating provider for issuer URL %q: %v", iss.IssuerURL, err) } else { cfg := &oidc.Config{ClientID: iss.ClientID} fc.verifiers[iss.IssuerURL] = []*verifierWithConfig{{provider.Verifier(cfg), cfg}} } } cache, err := lru.New2Q(100 /* size */) if err != nil { return fmt.Errorf("lru: %w", err) } fc.lru = cache return nil } type IssuerType string func (it IssuerType) String() string { return string(it) } const ( IssuerTypeBuildkiteJob = "buildkite-job" IssuerTypeEmail = "email" IssuerTypeGithubWorkflow = "github-workflow" IssuerTypeCodefreshWorkflow = "codefresh-workflow" IssuerTypeGitLabPipeline = "gitlab-pipeline" IssuerTypeChainguard = "chainguard-identity" IssuerTypeKubernetes = "kubernetes" IssuerTypeSpiffe = "spiffe" IssuerTypeURI = "uri" IssuerTypeUsername = "username" IssuerTypeCIProvider = "ci-provider" ) func parseConfig(b []byte) (cfg *FulcioConfig, err error) { cfg = &FulcioConfig{} if err := json.Unmarshal(b, cfg); err != nil { if err = yaml.Unmarshal(b, cfg); err != nil { return nil, fmt.Errorf("unmarshal: %w", err) } } return cfg, nil } func validateConfig(conf *FulcioConfig) error { if conf == nil { return errors.New("nil config") } for _, issuer := range conf.OIDCIssuers { if issuer.IssuerClaim != "" && issuer.Type != IssuerTypeEmail { return errors.New("only email issuers can use issuer claim mapping") } if issuer.Type == IssuerTypeSpiffe { if issuer.SPIFFETrustDomain == "" { return errors.New("spiffe issuer must have SPIFFETrustDomain set") } // verify that trust domain is valid if _, err := spiffeid.TrustDomainFromString(issuer.SPIFFETrustDomain); err != nil { return errors.New("spiffe trust domain is invalid") } } if issuer.Type == IssuerTypeURI { if issuer.SubjectDomain == "" { return errors.New("uri issuer must have SubjectDomain set") } uDomain, err := url.Parse(issuer.SubjectDomain) if err != nil { return err } if uDomain.Scheme == "" { return errors.New("SubjectDomain for uri must contain scheme") } uIssuer, err := url.Parse(issuer.IssuerURL) if err != nil { return err } if uIssuer.Scheme == "" { return errors.New("issuer for uri must contain scheme") } // The domain in the configuration must match the domain (excluding the subdomain) of the issuer // In order to declare this configuration, a test must have been done to prove ownership // over both the issuer and domain configuration values. // Valid examples: // * SubjectDomain = https://example.com, IssuerURL = https://accounts.example.com // * SubjectDomain = https://accounts.example.com, IssuerURL = https://accounts.example.com // * SubjectDomain = https://users.example.com, IssuerURL = https://accounts.example.com if err := isURISubjectAllowed(uDomain, uIssuer); err != nil { return err } } if issuer.Type == IssuerTypeUsername { if issuer.SubjectDomain == "" { return errors.New("username issuer must have SubjectDomain set") } uDomain, err := url.Parse(issuer.SubjectDomain) if err != nil { return err } if uDomain.Scheme != "" { return errors.New("SubjectDomain for username should not contain scheme") } uIssuer, err := url.Parse(issuer.IssuerURL) if err != nil { return err } if uIssuer.Scheme == "" { return errors.New("issuer for username must contain scheme") } // The domain in the configuration must match the domain (excluding the subdomain) of the issuer // In order to declare this configuration, a test must have been done to prove ownership // over both the issuer and domain configuration values. // Valid examples: // * SubjectDomain = example.com, IssuerURL = https://accounts.example.com // * SubjectDomain = accounts.example.com, IssuerURL = https://accounts.example.com // * SubjectDomain = users.example.com, IssuerURL = https://accounts.example.com if err := validateAllowedDomain(issuer.SubjectDomain, uIssuer.Hostname()); err != nil { return err } } if issuerToChallengeClaim(issuer.Type, issuer.ChallengeClaim) == "" { return errors.New("issuer missing challenge claim") } } for _, metaIssuer := range conf.MetaIssuers { if metaIssuer.Type == IssuerTypeSpiffe { // This would establish a many to one relationship for OIDC issuers // to trust domains so we fail early and reject this configuration. return errors.New("SPIFFE meta issuers not supported") } if issuerToChallengeClaim(metaIssuer.Type, metaIssuer.ChallengeClaim) == "" { return errors.New("issuer missing challenge claim") } } return validateCIIssuerMetadata(conf) } var DefaultConfig = &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "https://oauth2.sigstore.dev/auth": { IssuerURL: "https://oauth2.sigstore.dev/auth", ClientID: "sigstore", IssuerClaim: "$.federated_claims.connector_id", Type: IssuerTypeEmail, }, "https://accounts.google.com": { IssuerURL: "https://accounts.google.com", ClientID: "sigstore", Type: IssuerTypeEmail, }, "https://token.actions.githubusercontent.com": { IssuerURL: "https://token.actions.githubusercontent.com", ClientID: "sigstore", Type: IssuerTypeGithubWorkflow, }, }, } var originalTransport = http.DefaultTransport type configKey struct{} func With(ctx context.Context, cfg *FulcioConfig) context.Context { ctx = context.WithValue(ctx, configKey{}, cfg) return ctx } func FromContext(ctx context.Context) *FulcioConfig { untyped := ctx.Value(configKey{}) if untyped == nil { return nil } return untyped.(*FulcioConfig) } // It checks that the templates defined are parseable // We should check it during the service bootstrap to avoid errors further func validateCIIssuerMetadata(fulcioConfig *FulcioConfig) error { checkParse := func(temp string) error { t := template.New("").Option("missingkey=error") _, err := t.Parse(temp) return err } for _, ciIssuerMetadata := range fulcioConfig.CIIssuerMetadata { v := reflect.ValueOf(ciIssuerMetadata.ExtensionTemplates) for i := 0; i < v.NumField(); i++ { s := v.Field(i).String() err := checkParse(s) if err != nil { return err } } err := checkParse(ciIssuerMetadata.SubjectAlternativeNameTemplate) if err != nil { return err } } return nil } // Load a config from disk, or use defaults func Load(configPath string) (*FulcioConfig, error) { if _, err := os.Stat(configPath); os.IsNotExist(err) { log.Logger.Infof("No config at %s, using defaults: %v", configPath, DefaultConfig) config := DefaultConfig if err := config.prepare(); err != nil { return nil, err } return config, nil } b, err := os.ReadFile(configPath) if err != nil { return nil, fmt.Errorf("read file: %w", err) } return Read(b) } // Read parses the bytes of a config func Read(b []byte) (*FulcioConfig, error) { config, err := parseConfig(b) if err != nil { return nil, fmt.Errorf("parse: %w", err) } err = validateConfig(config) if err != nil { return nil, fmt.Errorf("validate: %w", err) } if err := config.prepare(); err != nil { return nil, err } return config, nil } // isURISubjectAllowed compares the subject and issuer URIs, // returning an error if the scheme or the hostnames do not match func isURISubjectAllowed(subject, issuer *url.URL) error { if subject.Scheme != issuer.Scheme { return fmt.Errorf("subject (%s) and issuer (%s) URI schemes do not match", subject.Scheme, issuer.Scheme) } return validateAllowedDomain(subject.Hostname(), issuer.Hostname()) } // validateAllowedDomain compares two hostnames, returning an error if the // top-level and second-level domains do not match // TODO: This does not work for domains that end in co.jp or co.uk. We should consider // using eTLDs, or removing this validation when we can challenge domain ownership. func validateAllowedDomain(subjectHostname, issuerHostname string) error { // If the hostnames exactly match, return early if subjectHostname == issuerHostname { return nil } // Compare the top level and second level domains sHostname := strings.Split(subjectHostname, ".") iHostname := strings.Split(issuerHostname, ".") if len(sHostname) < minimumHostnameLength { return fmt.Errorf("URI hostname too short: %s", subjectHostname) } if len(iHostname) < minimumHostnameLength { return fmt.Errorf("URI hostname too short: %s", issuerHostname) } if sHostname[len(sHostname)-1] == iHostname[len(iHostname)-1] && sHostname[len(sHostname)-2] == iHostname[len(iHostname)-2] { return nil } return fmt.Errorf("hostname top-level and second-level domains do not match: %s, %s", subjectHostname, issuerHostname) } func issuerToChallengeClaim(issType IssuerType, challengeClaim string) string { if challengeClaim != "" { return challengeClaim } switch issType { case IssuerTypeBuildkiteJob: return "sub" case IssuerTypeGitLabPipeline: return "sub" case IssuerTypeEmail: return "email" case IssuerTypeGithubWorkflow: return "sub" case IssuerTypeCIProvider: return "sub" case IssuerTypeCodefreshWorkflow: return "sub" case IssuerTypeChainguard: return "sub" case IssuerTypeKubernetes: return "sub" case IssuerTypeSpiffe: return "sub" case IssuerTypeURI: return "sub" case IssuerTypeUsername: return "sub" default: return "" } } fulcio-1.6.5/pkg/config/config_network_test.go000066400000000000000000000142571470150653400214540ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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. // //go:build !hermetic package config import ( "context" "os" "path/filepath" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/sigstore/fulcio/pkg/certificate" ) func TestLoadYamlConfig(t *testing.T) { td := t.TempDir() cfgPath := filepath.Join(td, "config.yaml") if err := os.WriteFile(cfgPath, []byte(validYamlCfg), 0644); err != nil { t.Fatal(err) } cfg, err := Load(cfgPath) if err != nil { t.Fatal(err) } got, ok := cfg.GetIssuer("https://accounts.google.com") if !ok { t.Error("expected true, got false") } if got.ClientID != "foo" { t.Errorf("expected foo, got %s", got.ClientID) } if got.IssuerURL != "https://accounts.google.com" { t.Errorf("expected https://accounts.google.com, got %s", got.IssuerURL) } if got := len(cfg.OIDCIssuers); got != 1 { t.Errorf("expected 1 issuer, got %d", got) } got, ok = cfg.GetIssuer("https://oidc.eks.fantasy-land.amazonaws.com/id/CLUSTERIDENTIFIER") if !ok { t.Error("expected true, got false") } if got.ClientID != "bar" { t.Errorf("expected bar, got %s", got.ClientID) } if got.IssuerURL != "https://oidc.eks.fantasy-land.amazonaws.com/id/CLUSTERIDENTIFIER" { t.Errorf("expected https://oidc.eks.fantasy-land.amazonaws.com/id/CLUSTERIDENTIFIER, got %s", got.IssuerURL) } // Checking that the ci provider meta issuer has been set correctly got, ok = cfg.GetIssuer("https://oidc.foo.foobar.bar.com/id/CLUSTERIDENTIFIER") if !ok { t.Error("expected true, got false") } if got.Type != "ci-provider" { t.Errorf("expected ci-provider, got %s", got.Type) } if got.CIProvider != "github-workflow" { t.Errorf("expected github-workflow, got %s", got.CIProvider) } if _, ok := cfg.GetIssuer("not_an_issuer"); ok { t.Error("no error returned from an unconfigured issuer") } } func TestLoadJsonConfig(t *testing.T) { td := t.TempDir() cfgPath := filepath.Join(td, "config.json") if err := os.WriteFile(cfgPath, []byte(validJSONCfg), 0644); err != nil { t.Fatal(err) } cfg, err := Load(cfgPath) if err != nil { t.Fatal(err) } got, ok := cfg.GetIssuer("https://accounts.google.com") if !ok { t.Error("expected true, got false") } if got.ClientID != "foo" { t.Errorf("expected foo, got %s", got.ClientID) } if got.IssuerURL != "https://accounts.google.com" { t.Errorf("expected https://accounts.google.com, got %s", got.IssuerURL) } if got := len(cfg.OIDCIssuers); got != 1 { t.Errorf("expected 1 issuer, got %d", got) } got, ok = cfg.GetIssuer("https://oidc.eks.fantasy-land.amazonaws.com/id/CLUSTERIDENTIFIER") if !ok { t.Error("expected true, got false") } if got.ClientID != "bar" { t.Errorf("expected bar, got %s", got.ClientID) } if got.IssuerURL != "https://oidc.eks.fantasy-land.amazonaws.com/id/CLUSTERIDENTIFIER" { t.Errorf("expected https://oidc.eks.fantasy-land.amazonaws.com/id/CLUSTERIDENTIFIER, got %s", got.IssuerURL) } // Checking that the ci provider meta issuer has been set correctly got, ok = cfg.GetIssuer("https://oidc.foo.foobar.bar.com/id/CLUSTERIDENTIFIER") if !ok { t.Error("expected true, got false") } if got.Type != "ci-provider" { t.Errorf("expected ci-provider, got %s", got.Type) } if got.CIProvider != "github-workflow" { t.Errorf("expected github-workflow, got %s", got.CIProvider) } if _, ok := cfg.GetIssuer("not_an_issuer"); ok { t.Error("no error returned from an unconfigured issuer") } } func TestParseTemplate(t *testing.T) { validTemplate := "{{.foobar}}" invalidTemplate := "{{.foobar}" ciissuerMetadata := make(map[string]IssuerMetadata) ciissuerMetadata["github"] = IssuerMetadata{ ExtensionTemplates: certificate.Extensions{ BuildTrigger: invalidTemplate, }, } fulcioConfig := &FulcioConfig{ CIIssuerMetadata: ciissuerMetadata, } // BuildTrigger as a invalid template should raise an error err := validateCIIssuerMetadata(fulcioConfig) if err == nil { t.Error("invalid template should raise an error") } ciissuerMetadata["github"] = IssuerMetadata{ ExtensionTemplates: certificate.Extensions{ BuildTrigger: validTemplate, }, } fulcioConfig = &FulcioConfig{ CIIssuerMetadata: ciissuerMetadata, } // BuildTrigger as a valid template shouldn't raise an error err = validateCIIssuerMetadata(fulcioConfig) if err != nil { t.Error("valid template shouldn't raise an error, error: %w", err) } ciissuerMetadata["github"] = IssuerMetadata{ SubjectAlternativeNameTemplate: invalidTemplate, } fulcioConfig = &FulcioConfig{ CIIssuerMetadata: ciissuerMetadata, } // A SAN as a invalid template should raise an error err = validateCIIssuerMetadata(fulcioConfig) if err == nil { t.Error("invalid SAN should raise an error") } ciissuerMetadata["github"] = IssuerMetadata{ SubjectAlternativeNameTemplate: invalidTemplate, } fulcioConfig = &FulcioConfig{ CIIssuerMetadata: ciissuerMetadata, } // A SAN as a valid template should raise an error err = validateCIIssuerMetadata(fulcioConfig) if err == nil { t.Error("valid SAN shouldn't raise an error") } } func TestLoadDefaults(t *testing.T) { td := t.TempDir() // Don't put anything here! cfgPath := filepath.Join(td, "config.yaml") cfg, err := Load(cfgPath) if err != nil { t.Fatal(err) } if diff := cmp.Diff(DefaultConfig, cfg, cmpopts.IgnoreUnexported(FulcioConfig{})); diff != "" { t.Errorf("DefaultConfig(): -want +got: %s", diff) } ctx := context.Background() if got := FromContext(ctx); nil != got { t.Errorf("FromContext(): %#v, wanted nil", got) } ctx = With(ctx, cfg) if diff := cmp.Diff(cfg, FromContext(ctx), cmpopts.IgnoreUnexported(FulcioConfig{})); diff != "" { t.Errorf("FromContext(): -want +got: %s", diff) } } fulcio-1.6.5/pkg/config/config_test.go000066400000000000000000000463511470150653400177030ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 ( "context" "fmt" "net/url" "reflect" "testing" "github.com/coreos/go-oidc/v3/oidc" lru "github.com/hashicorp/golang-lru" "github.com/sigstore/fulcio/pkg/generated/protobuf" ) var validYamlCfg = ` oidc-issuers: https://accounts.google.com: issuer-url: https://accounts.google.com client-id: foo type: email challenge-claim: email meta-issuers: https://oidc.eks.*.amazonaws.com/id/*: client-id: bar type: kubernetes https://oidc.foo.*.bar.com/id/*: client-id: bar type: ci-provider ci-provider: github-workflow ` var validJSONCfg = ` { "OIDCIssuers": { "https://accounts.google.com": { "IssuerURL": "https://accounts.google.com", "ClientID": "foo", "Type": "email", "ChallengeClaim": "email" } }, "MetaIssuers": { "https://oidc.eks.*.amazonaws.com/id/*": { "ClientID": "bar", "Type": "kubernetes" }, "https://oidc.foo.*.bar.com/id/*": { "ClientID": "bar", "Type": "ci-provider", "CiProvider": "github-workflow" } } } ` func TestMetaURLs(t *testing.T) { tests := []struct { name string issuer string matches []string misses []string }{{ name: "AWS meta URL", issuer: "https://oidc.eks.*.amazonaws.com/id/*", matches: []string{ "https://oidc.eks.us-west-2.amazonaws.com/id/B02C93B6A2D30341AD01E1B6D48164CB", }, misses: []string{ // Extra dots "https://oidc.eks.us.west.2.amazonaws.com/id/B02C93B6A2D30341AD01E1B6D48164CB", // Extra slashes "https://oidc.eks.us-west/2.amazonaws.com/id/B02C93B6A2D3/0341AD01E1B6D48164CB", }, }, { name: "GKE meta URL", issuer: "https://container.googleapis.com/v1/projects/*/locations/*/clusters/*", matches: []string{ "https://container.googleapis.com/v1/projects/mattmoor-credit/locations/us-west1-b/clusters/tenant-cluster", }, misses: []string{ // Extra dots "https://container.googleapis.com/v1/projects/mattmoor-credit/locations/us.west1.b/clusters/tenant-cluster", }, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { re, err := metaRegex(test.issuer) if err != nil { t.Errorf("metaRegex() = %v", err) } for _, match := range test.matches { if !re.MatchString(match) { t.Errorf("MatchString(%q) = false, wanted true", match) } } for _, miss := range test.misses { if re.MatchString(miss) { t.Errorf("MatchString(%q) = true, wanted false", miss) } } }) } } func TestValidateConfig(t *testing.T) { tests := map[string]struct { Config *FulcioConfig WantError bool }{ "good spiffe config": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "issuer.example.com", ClientID: "foo", Type: IssuerTypeSpiffe, SPIFFETrustDomain: "example.com", }, }, }, WantError: false, }, "spiffe issuer requires a trust domain": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "issuer.example.com", ClientID: "foo", Type: IssuerTypeSpiffe, }, }, }, WantError: true, }, "spiffe issuer cannot be a meta issuer": { Config: &FulcioConfig{ MetaIssuers: map[string]OIDCIssuer{ "*.example.com": { ClientID: "foo", Type: IssuerTypeSpiffe, SPIFFETrustDomain: "example.com", }, }, }, WantError: true, }, "invalid spiffe trust domain": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "issuer.example.com", ClientID: "foo", Type: IssuerTypeSpiffe, SPIFFETrustDomain: "invalid#domain", }, }, }, WantError: true, }, "good uri config": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "https://issuer.example.com", ClientID: "foo", Type: IssuerTypeURI, SubjectDomain: "https://other.example.com", }, }, }, WantError: false, }, "uri issuer requires a subject domain": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "https://issuer.example.com", ClientID: "foo", Type: IssuerTypeURI, }, }, }, WantError: true, }, "uri subject domain should contain scheme": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "https://issuer.example.com", ClientID: "foo", Type: IssuerTypeURI, SubjectDomain: "other.example.com", }, }, }, WantError: true, }, "uri issuer url should contain scheme": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "issuer.example.com", ClientID: "foo", Type: IssuerTypeURI, SubjectDomain: "https://other.example.com", }, }, }, WantError: true, }, "uri issuer and subject domains must have same top-level hostname": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "https://issuer.example.com", ClientID: "foo", Type: IssuerTypeURI, SubjectDomain: "https://different.com", }, }, }, WantError: true, }, "uri issuer and subject domains must have same scheme": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "https://example.com", ClientID: "foo", Type: IssuerTypeURI, SubjectDomain: "http://example.com", }, }, }, WantError: true, }, "good username config": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "https://issuer.example.com", ClientID: "foo", Type: IssuerTypeUsername, SubjectDomain: "other.example.com", }, }, }, WantError: false, }, "username issuer requires a subject domain": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "https://issuer.example.com", ClientID: "foo", Type: IssuerTypeUsername, }, }, }, WantError: true, }, "username subject domain should not contain scheme": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "https://issuer.example.com", ClientID: "foo", Type: IssuerTypeUsername, SubjectDomain: "https://other.example.com", }, }, }, WantError: true, }, "username issuer url should contain scheme": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "issuer.example.com", ClientID: "foo", Type: IssuerTypeUsername, SubjectDomain: "other.example.com", }, }, }, WantError: true, }, "username issuer and subject domains must have same top-level hostname": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.example.com": { IssuerURL: "https://issuer.example.com", ClientID: "foo", Type: IssuerTypeUsername, SubjectDomain: "different.com", }, }, }, WantError: true, }, "non email issuer with issuer claim set is invalid": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "https://issuer.example.com": { IssuerURL: "htts://issuer.example.com", ClientID: "foo", Type: IssuerTypeSpiffe, SPIFFETrustDomain: "example.com", IssuerClaim: "$.foo.bar", }, }, }, WantError: true, }, "type without challenge claim is invalid": { Config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "https://issuer.example.com": { IssuerURL: "htts://issuer.example.com", ClientID: "sigstore", Type: "invalid", }, }, }, WantError: true, }, "nil config isn't valid": { Config: nil, WantError: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { err := validateConfig(test.Config) if err != nil && !test.WantError { t.Errorf("%s: %v", name, err) } if err == nil && test.WantError { t.Errorf("%s: expected error", name) } }) } } func Test_isURISubjectAllowed(t *testing.T) { tests := []struct { name string subject string // Parsed to url.URL issuer string // Parsed to url.URL want error }{{ name: "match", subject: "https://accounts.example.com", issuer: "https://accounts.example.com", want: nil, }, { name: "issuer subdomain", subject: "https://example.com", issuer: "https://accounts.example.com", want: nil, }, { name: "subject subdomain", subject: "https://profiles.example.com", issuer: "https://example.com", want: nil, }, { name: "subdomain mismatch", subject: "https://profiles.example.com", issuer: "https://accounts.example.com", want: nil, }, { name: "scheme mismatch", subject: "http://example.com", issuer: "https://example.com", want: fmt.Errorf("subject (http) and issuer (https) URI schemes do not match"), }, { name: "subject domain too short", subject: "https://example", issuer: "https://example.com", want: fmt.Errorf("URI hostname too short: example"), }, { name: "issuer domain too short", subject: "https://example.com", issuer: "https://issuer", want: fmt.Errorf("URI hostname too short: issuer"), }, { name: "domain mismatch", subject: "https://example.com", issuer: "https://otherexample.com", want: fmt.Errorf("hostname top-level and second-level domains do not match: example.com, otherexample.com"), }, { name: "top level domain mismatch", subject: "https://example.com", issuer: "https://example.org", want: fmt.Errorf("hostname top-level and second-level domains do not match: example.com, example.org"), }} for _, tt := range tests { subject, _ := url.Parse(tt.subject) issuer, _ := url.Parse(tt.issuer) t.Run(tt.name, func(t *testing.T) { got := isURISubjectAllowed(subject, issuer) if got == nil && tt.want != nil || got != nil && tt.want == nil { t.Errorf("isURISubjectAllowed() = %v, want %v", got, tt.want) } if got != nil && tt.want != nil && got.Error() != tt.want.Error() { t.Errorf("isURISubjectAllowed() = %v, want %v", got, tt.want) } }) } } func Test_validateAllowedDomain(t *testing.T) { tests := []struct { name string subject string // Parsed to url.URL issuer string // Parsed to url.URL want error }{{ name: "match", subject: "accounts.example.com", issuer: "accounts.example.com", want: nil, }, { name: "issuer subdomain", subject: "example.com", issuer: "accounts.example.com", want: nil, }, { name: "subject subdomain", subject: "profiles.example.com", issuer: "example.com", want: nil, }, { name: "subdomain mismatch", subject: "profiles.example.com", issuer: "accounts.example.com", want: nil, }, { name: "subject domain too short", subject: "example", issuer: "example.com", want: fmt.Errorf("URI hostname too short: example"), }, { name: "issuer domain too short", subject: "example.com", issuer: "issuer", want: fmt.Errorf("URI hostname too short: issuer"), }, { name: "domain mismatch", subject: "example.com", issuer: "otherexample.com", want: fmt.Errorf("hostname top-level and second-level domains do not match: example.com, otherexample.com"), }, { name: "domain mismatch, subdomain match", subject: "test.example.com", issuer: "test.otherexample.com", want: fmt.Errorf("hostname top-level and second-level domains do not match: test.example.com, test.otherexample.com"), }, { name: "top level domain mismatch", subject: "example.com", issuer: "example.org", want: fmt.Errorf("hostname top-level and second-level domains do not match: example.com, example.org"), }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := validateAllowedDomain(tt.subject, tt.issuer) if got == nil && tt.want != nil || got != nil && tt.want == nil { t.Errorf("validateAllowedDomain() = %v, want %v", got, tt.want) } if got != nil && tt.want != nil && got.Error() != tt.want.Error() { t.Errorf("validateAllowedDomain() = %v, want %v", got, tt.want) } }) } } func Test_issuerToChallengeClaim(t *testing.T) { if claim := issuerToChallengeClaim(IssuerTypeEmail, ""); claim != "email" { t.Fatalf("expected email subject claim for email issuer, got %s", claim) } if claim := issuerToChallengeClaim(IssuerTypeSpiffe, ""); claim != "sub" { t.Fatalf("expected sub subject claim for SPIFFE issuer, got %s", claim) } if claim := issuerToChallengeClaim(IssuerTypeUsername, ""); claim != "sub" { t.Fatalf("expected sub subject claim for username issuer, got %s", claim) } if claim := issuerToChallengeClaim(IssuerTypeURI, ""); claim != "sub" { t.Fatalf("expected sub subject claim for URI issuer, got %s", claim) } if claim := issuerToChallengeClaim(IssuerTypeBuildkiteJob, ""); claim != "sub" { t.Fatalf("expected sub subject claim for Buildkite issuer, got %s", claim) } if claim := issuerToChallengeClaim(IssuerTypeGithubWorkflow, ""); claim != "sub" { t.Fatalf("expected sub subject claim for GitHub issuer, got %s", claim) } if claim := issuerToChallengeClaim(IssuerTypeCIProvider, ""); claim != "sub" { t.Fatalf("expected sub subject claim for CI issuer, got %s", claim) } if claim := issuerToChallengeClaim(IssuerTypeGitLabPipeline, ""); claim != "sub" { t.Fatalf("expected sub subject claim for GitLab issuer, got %s", claim) } if claim := issuerToChallengeClaim(IssuerTypeCodefreshWorkflow, ""); claim != "sub" { t.Fatalf("expected sub subject claim for Codefresh issuer, got %s", claim) } if claim := issuerToChallengeClaim(IssuerTypeChainguard, ""); claim != "sub" { t.Fatalf("expected sub subject claim for Chainguard issuer, got %s", claim) } if claim := issuerToChallengeClaim(IssuerTypeKubernetes, ""); claim != "sub" { t.Fatalf("expected sub subject claim for K8S issuer, got %s", claim) } // unexpected issuer has empty claim and no claim was provided if claim := issuerToChallengeClaim("invalid", ""); claim != "" { t.Fatalf("expected no claim for invalid issuer, got %s", claim) } // custom issuer provides a claim if claim := issuerToChallengeClaim("custom", "email"); claim != "email" { t.Fatalf("expected email subject claim for custom issuer, got %s", claim) } } func TestToIssuers(t *testing.T) { tests := []struct { config *FulcioConfig want []*protobuf.OIDCIssuer }{ { config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "example.com": { IssuerURL: "example.com", ClientID: "sigstore", Type: IssuerTypeEmail, }, }, MetaIssuers: map[string]OIDCIssuer{ "wildcard.*.example.com": { ClientID: "sigstore", Type: IssuerTypeKubernetes, }, }, }, want: []*protobuf.OIDCIssuer{ { Audience: "sigstore", ChallengeClaim: "email", Issuer: &protobuf.OIDCIssuer_IssuerUrl{ IssuerUrl: "example.com", }, IssuerType: IssuerTypeEmail, }, { Audience: "sigstore", ChallengeClaim: "sub", Issuer: &protobuf.OIDCIssuer_WildcardIssuerUrl{ WildcardIssuerUrl: "wildcard.*.example.com", }, IssuerType: IssuerTypeKubernetes, }, }, }, { config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "username.example.com": { IssuerURL: "username.example.com", ClientID: "sigstore", Type: IssuerTypeUsername, SubjectDomain: "username.example.com", }, }, }, want: []*protobuf.OIDCIssuer{ { Audience: "sigstore", ChallengeClaim: "sub", Issuer: &protobuf.OIDCIssuer_IssuerUrl{ IssuerUrl: "username.example.com", }, IssuerType: IssuerTypeUsername, SubjectDomain: "username.example.com", }, }, }, { config: &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "uriissuer.example.com": { IssuerURL: "uriissuer.example.com", ClientID: "sigstore", Type: IssuerTypeURI, SubjectDomain: "uriissuer.example.com", }, }, }, want: []*protobuf.OIDCIssuer{ { Audience: "sigstore", ChallengeClaim: "sub", Issuer: &protobuf.OIDCIssuer_IssuerUrl{ IssuerUrl: "uriissuer.example.com", }, IssuerType: IssuerTypeURI, SubjectDomain: "uriissuer.example.com", }, }, }, } for _, test := range tests { issuers := test.config.ToIssuers() if !reflect.DeepEqual(issuers, test.want) { t.Fatalf("expected issuers %v, got %v", test.want, issuers) } } } func TestVerifierCache(t *testing.T) { cache, err := lru.New2Q(100 /* size */) if err != nil { t.Fatal(err) } fc := &FulcioConfig{ OIDCIssuers: map[string]OIDCIssuer{ "issuer.dev": { IssuerURL: "issuer.dev", ClientID: "sigstore", }, }, verifiers: map[string][]*verifierWithConfig{}, lru: cache, } // create a cache hit cfg := &oidc.Config{ClientID: "sigstore"} verifier := oidc.NewVerifier("issuer.dev", &mockKeySet{}, cfg) fc.verifiers = map[string][]*verifierWithConfig{ "issuer.dev": { { Config: cfg, IDTokenVerifier: verifier, }, }, } // make sure we get a hit v, ok := fc.GetVerifier("issuer.dev") if !ok { t.Fatal("unable to verifier") } if !reflect.DeepEqual(v, verifier) { t.Fatal("got unexpected verifier") } // get verifier with SkipExpiryCheck set, should fail on cache miss _, ok = fc.GetVerifier("issuer.dev", WithSkipExpiryCheck()) if ok { t.Fatal("expected cache miss") } // create a cache hit with SkipExpiryCheck set withExpiryCfg := &oidc.Config{ClientID: "sigstore", SkipExpiryCheck: true} expiryVerifier := oidc.NewVerifier("issuer.dev", &mockKeySet{}, cfg) fc.verifiers = map[string][]*verifierWithConfig{ "issuer.dev": { { Config: cfg, IDTokenVerifier: verifier, }, { Config: withExpiryCfg, IDTokenVerifier: expiryVerifier, }, }, } // make sure we get a hit and the correct verifier is returned v, ok = fc.GetVerifier("issuer.dev", WithSkipExpiryCheck()) if !ok { t.Fatal("unable to verifier") } if !reflect.DeepEqual(v, expiryVerifier) { t.Fatal("got unexpected verifier") } } type mockKeySet struct { } func (m *mockKeySet) VerifySignature(_ context.Context, _ string) (payload []byte, err error) { return nil, nil } fulcio-1.6.5/pkg/config/fulcio_config_test.go000066400000000000000000000061211470150653400212330ustar00rootroot00000000000000// Copyright 2024 The Sigstore 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. // //go:build !hermetic package config import ( "os" "path/filepath" "runtime" "strings" "testing" ) // The config/identity/config.yaml is a config file that is reflected directly // to the public good instance. // This test checks that the config.yaml is valid and can be properly used // on the public good instance. func TestLoadFulcioConfig(t *testing.T) { _, path, _, _ := runtime.Caller(0) basepath := filepath.Dir(path) b, err := os.ReadFile(basepath + "/../../config/identity/config.yaml") if err != nil { t.Errorf("read file: %v", err) } fulcioConfig, err := Read(b) if err != nil { t.Fatal(err) } for issuerURL := range fulcioConfig.OIDCIssuers { got, ok := fulcioConfig.GetIssuer(issuerURL) if !ok { t.Error("expected true, got false") } if got.ClientID != "sigstore" { t.Errorf("expected sigstore, got %s", got.ClientID) } if got.IssuerURL != issuerURL { t.Errorf("expected %s, got %s", issuerURL, got.IssuerURL) } if string(got.Type) == "" { t.Errorf("issuer Type should not be empty") } if got.Type == IssuerTypeCIProvider { if got.CIProvider == "" { t.Errorf("issuer that is CIProvider field shouldn't be empty when Type is ci-provider") } if _, ok := fulcioConfig.CIIssuerMetadata[got.CIProvider]; !ok { t.Error("issuer with type ci-provider should have the same CI provider name as key for CIIssuerMetadata") } } if _, ok := fulcioConfig.GetIssuer("not_an_issuer"); ok { t.Error("no error returned from an unconfigured issuer") } } for metaIssuerURLRegex := range fulcioConfig.MetaIssuers { metaIssuerURL := strings.ReplaceAll(metaIssuerURLRegex, "*", "foo") got, ok := fulcioConfig.GetIssuer(metaIssuerURL) if !ok { t.Errorf("expected true, got false, %s", metaIssuerURL) } if got.ClientID != "sigstore" { t.Errorf("expected sigstore, got %s", got.ClientID) } if got.IssuerURL != metaIssuerURL { t.Errorf("expected %s, got %s", metaIssuerURL, got.IssuerURL) } if string(got.Type) == "" { t.Errorf("issuer Type should not be empty") } if got.Type == IssuerTypeCIProvider { if got.CIProvider == "" { t.Errorf("issuer that is CIProvider field shouldn't be empty when Type is ci-provider") } if _, ok := fulcioConfig.CIIssuerMetadata[got.CIProvider]; !ok { t.Error("issuer with type ci-provider should have the same CI provider name as key for CIIssuerMetadata") } } if _, ok := fulcioConfig.GetIssuer("not_an_issuer"); ok { t.Error("no error returned from an unconfigured issuer") } } } fulcio-1.6.5/pkg/ctl/000077500000000000000000000000001470150653400143545ustar00rootroot00000000000000fulcio-1.6.5/pkg/ctl/utils.go000066400000000000000000000032131470150653400160420ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 ctl import ( "crypto/x509" "encoding/base64" "fmt" ct "github.com/google/certificate-transparency-go" "github.com/google/certificate-transparency-go/tls" ) // BuildCTChain constructs an ASN.1 encoded certificate chain for appending to the CT log. func BuildCTChain(cert *x509.Certificate, chain []*x509.Certificate) []ct.ASN1Cert { ctChain := []ct.ASN1Cert{} ctChain = append(ctChain, ct.ASN1Cert{Data: cert.Raw}) for _, c := range chain { ctChain = append(ctChain, ct.ASN1Cert{Data: c.Raw}) } return ctChain } // ToAddChainResponse converts an SCT struct to an AddChainResponse struct. func ToAddChainResponse(sct *ct.SignedCertificateTimestamp) (*ct.AddChainResponse, error) { sig, err := tls.Marshal(sct.Signature) if err != nil { return nil, fmt.Errorf("failed to marshal signature: %s", err) } addChainResp := &ct.AddChainResponse{ SCTVersion: sct.SCTVersion, Timestamp: sct.Timestamp, Extensions: base64.StdEncoding.EncodeToString(sct.Extensions), ID: sct.LogID.KeyID[:], Signature: sig, } return addChainResp, nil } fulcio-1.6.5/pkg/ctl/utils_test.go000066400000000000000000000044731470150653400171120ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 ctl import ( "crypto/x509" "crypto/x509/pkix" "encoding/base64" "reflect" "testing" ct "github.com/google/certificate-transparency-go" "github.com/google/certificate-transparency-go/tls" ) func TestBuildCTChain(t *testing.T) { certs := []*x509.Certificate{ {Subject: pkix.Name{CommonName: "leaf"}}, {Subject: pkix.Name{CommonName: "sub"}}, {Subject: pkix.Name{CommonName: "root"}}, } ctChain := BuildCTChain(certs[0], certs[1:3]) if len(ctChain) != len(certs) { t.Fatalf("CT chain length does not equal certificate chain length, got %v, expected %v", len(ctChain), len(certs)) } for i := 0; i < len(certs); i++ { if !reflect.DeepEqual(ctChain[i].Data, certs[i].Raw) { t.Fatal("CT certificate and certificate do not match") } } } func TestToAddChainResponse(t *testing.T) { sct := &ct.SignedCertificateTimestamp{ SCTVersion: ct.V1, LogID: ct.LogID{KeyID: [32]byte{1, 2, 3, 4}}, Timestamp: 12345, Extensions: ct.CTExtensions{1, 2, 3}, Signature: ct.DigitallySigned{Algorithm: tls.SignatureAndHashAlgorithm{Hash: tls.SHA1, Signature: tls.ECDSA}}, } resp, err := ToAddChainResponse(sct) if err != nil { t.Fatalf("unexpected error: %v", err) } if resp.SCTVersion != sct.SCTVersion { t.Fatal("SCT version does not match") } if !reflect.DeepEqual(resp.ID, sct.LogID.KeyID[:]) { t.Fatal("ID does not match") } if resp.Timestamp != sct.Timestamp { t.Fatal("timestamp does not match") } if resp.Extensions != base64.StdEncoding.EncodeToString(sct.Extensions) { t.Fatal("timestamp does not match") } sig, err := tls.Marshal(sct.Signature) if err != nil { t.Fatal("error marshalling signature") } if !reflect.DeepEqual(resp.Signature, sig) { t.Fatal("signature does not match") } } fulcio-1.6.5/pkg/generated/000077500000000000000000000000001470150653400155305ustar00rootroot00000000000000fulcio-1.6.5/pkg/generated/protobuf/000077500000000000000000000000001470150653400173705ustar00rootroot00000000000000fulcio-1.6.5/pkg/generated/protobuf/fulcio.pb.go000066400000000000000000001513671470150653400216150ustar00rootroot00000000000000// // Copyright 2022 The Sigstore 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. // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.28.2 // source: fulcio.proto package protobuf import ( _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type PublicKeyAlgorithm int32 const ( PublicKeyAlgorithm_PUBLIC_KEY_ALGORITHM_UNSPECIFIED PublicKeyAlgorithm = 0 PublicKeyAlgorithm_RSA_PSS PublicKeyAlgorithm = 1 PublicKeyAlgorithm_ECDSA PublicKeyAlgorithm = 2 PublicKeyAlgorithm_ED25519 PublicKeyAlgorithm = 3 ) // Enum value maps for PublicKeyAlgorithm. var ( PublicKeyAlgorithm_name = map[int32]string{ 0: "PUBLIC_KEY_ALGORITHM_UNSPECIFIED", 1: "RSA_PSS", 2: "ECDSA", 3: "ED25519", } PublicKeyAlgorithm_value = map[string]int32{ "PUBLIC_KEY_ALGORITHM_UNSPECIFIED": 0, "RSA_PSS": 1, "ECDSA": 2, "ED25519": 3, } ) func (x PublicKeyAlgorithm) Enum() *PublicKeyAlgorithm { p := new(PublicKeyAlgorithm) *p = x return p } func (x PublicKeyAlgorithm) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } func (PublicKeyAlgorithm) Descriptor() protoreflect.EnumDescriptor { return file_fulcio_proto_enumTypes[0].Descriptor() } func (PublicKeyAlgorithm) Type() protoreflect.EnumType { return &file_fulcio_proto_enumTypes[0] } func (x PublicKeyAlgorithm) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } // Deprecated: Use PublicKeyAlgorithm.Descriptor instead. func (PublicKeyAlgorithm) EnumDescriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{0} } type CreateSigningCertificateRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // Identity information about who possesses the private / public key pair presented Credentials *Credentials `protobuf:"bytes,1,opt,name=credentials,proto3" json:"credentials,omitempty"` // Types that are assignable to Key: // // *CreateSigningCertificateRequest_PublicKeyRequest // *CreateSigningCertificateRequest_CertificateSigningRequest Key isCreateSigningCertificateRequest_Key `protobuf_oneof:"key"` } func (x *CreateSigningCertificateRequest) Reset() { *x = CreateSigningCertificateRequest{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *CreateSigningCertificateRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*CreateSigningCertificateRequest) ProtoMessage() {} func (x *CreateSigningCertificateRequest) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use CreateSigningCertificateRequest.ProtoReflect.Descriptor instead. func (*CreateSigningCertificateRequest) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{0} } func (x *CreateSigningCertificateRequest) GetCredentials() *Credentials { if x != nil { return x.Credentials } return nil } func (m *CreateSigningCertificateRequest) GetKey() isCreateSigningCertificateRequest_Key { if m != nil { return m.Key } return nil } func (x *CreateSigningCertificateRequest) GetPublicKeyRequest() *PublicKeyRequest { if x, ok := x.GetKey().(*CreateSigningCertificateRequest_PublicKeyRequest); ok { return x.PublicKeyRequest } return nil } func (x *CreateSigningCertificateRequest) GetCertificateSigningRequest() []byte { if x, ok := x.GetKey().(*CreateSigningCertificateRequest_CertificateSigningRequest); ok { return x.CertificateSigningRequest } return nil } type isCreateSigningCertificateRequest_Key interface { isCreateSigningCertificateRequest_Key() } type CreateSigningCertificateRequest_PublicKeyRequest struct { // The public key to be stored in the requested certificate along with a signed // challenge as proof of possession of the private key. PublicKeyRequest *PublicKeyRequest `protobuf:"bytes,2,opt,name=public_key_request,json=publicKeyRequest,proto3,oneof"` } type CreateSigningCertificateRequest_CertificateSigningRequest struct { // PKCS#10 PEM-encoded certificate signing request // // Contains the public key to be stored in the requested certificate. All other CSR fields // are ignored. Since the CSR is self-signed, it also acts as a proof of possession of // the private key. // // In particular, the CSR's subject name is not verified, or tested for // compatibility with its specified X.509 name type (e.g. email address). CertificateSigningRequest []byte `protobuf:"bytes,3,opt,name=certificate_signing_request,json=certificateSigningRequest,proto3,oneof"` } func (*CreateSigningCertificateRequest_PublicKeyRequest) isCreateSigningCertificateRequest_Key() {} func (*CreateSigningCertificateRequest_CertificateSigningRequest) isCreateSigningCertificateRequest_Key() { } type Credentials struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // Types that are assignable to Credentials: // // *Credentials_OidcIdentityToken Credentials isCredentials_Credentials `protobuf_oneof:"credentials"` } func (x *Credentials) Reset() { *x = Credentials{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Credentials) String() string { return protoimpl.X.MessageStringOf(x) } func (*Credentials) ProtoMessage() {} func (x *Credentials) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Credentials.ProtoReflect.Descriptor instead. func (*Credentials) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{1} } func (m *Credentials) GetCredentials() isCredentials_Credentials { if m != nil { return m.Credentials } return nil } func (x *Credentials) GetOidcIdentityToken() string { if x, ok := x.GetCredentials().(*Credentials_OidcIdentityToken); ok { return x.OidcIdentityToken } return "" } type isCredentials_Credentials interface { isCredentials_Credentials() } type Credentials_OidcIdentityToken struct { // The OIDC token that identifies the caller OidcIdentityToken string `protobuf:"bytes,1,opt,name=oidc_identity_token,json=oidcIdentityToken,proto3,oneof"` } func (*Credentials_OidcIdentityToken) isCredentials_Credentials() {} type PublicKeyRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // The public key to be stored in the requested certificate PublicKey *PublicKey `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` // Proof that the client possesses the private key; must be verifiable by provided public key // // This is a currently a signature over the `sub` claim from the OIDC identity token ProofOfPossession []byte `protobuf:"bytes,2,opt,name=proof_of_possession,json=proofOfPossession,proto3" json:"proof_of_possession,omitempty"` } func (x *PublicKeyRequest) Reset() { *x = PublicKeyRequest{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *PublicKeyRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*PublicKeyRequest) ProtoMessage() {} func (x *PublicKeyRequest) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use PublicKeyRequest.ProtoReflect.Descriptor instead. func (*PublicKeyRequest) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{2} } func (x *PublicKeyRequest) GetPublicKey() *PublicKey { if x != nil { return x.PublicKey } return nil } func (x *PublicKeyRequest) GetProofOfPossession() []byte { if x != nil { return x.ProofOfPossession } return nil } type PublicKey struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // The cryptographic algorithm to use with the key material Algorithm PublicKeyAlgorithm `protobuf:"varint,1,opt,name=algorithm,proto3,enum=dev.sigstore.fulcio.v2.PublicKeyAlgorithm" json:"algorithm,omitempty"` // PKIX, ASN.1 DER or PEM-encoded public key. PEM is typically // of type PUBLIC KEY. Content string `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` } func (x *PublicKey) Reset() { *x = PublicKey{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *PublicKey) String() string { return protoimpl.X.MessageStringOf(x) } func (*PublicKey) ProtoMessage() {} func (x *PublicKey) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use PublicKey.ProtoReflect.Descriptor instead. func (*PublicKey) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{3} } func (x *PublicKey) GetAlgorithm() PublicKeyAlgorithm { if x != nil { return x.Algorithm } return PublicKeyAlgorithm_PUBLIC_KEY_ALGORITHM_UNSPECIFIED } func (x *PublicKey) GetContent() string { if x != nil { return x.Content } return "" } type SigningCertificate struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // Types that are assignable to Certificate: // // *SigningCertificate_SignedCertificateDetachedSct // *SigningCertificate_SignedCertificateEmbeddedSct Certificate isSigningCertificate_Certificate `protobuf_oneof:"certificate"` } func (x *SigningCertificate) Reset() { *x = SigningCertificate{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *SigningCertificate) String() string { return protoimpl.X.MessageStringOf(x) } func (*SigningCertificate) ProtoMessage() {} func (x *SigningCertificate) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use SigningCertificate.ProtoReflect.Descriptor instead. func (*SigningCertificate) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{4} } func (m *SigningCertificate) GetCertificate() isSigningCertificate_Certificate { if m != nil { return m.Certificate } return nil } func (x *SigningCertificate) GetSignedCertificateDetachedSct() *SigningCertificateDetachedSCT { if x, ok := x.GetCertificate().(*SigningCertificate_SignedCertificateDetachedSct); ok { return x.SignedCertificateDetachedSct } return nil } func (x *SigningCertificate) GetSignedCertificateEmbeddedSct() *SigningCertificateEmbeddedSCT { if x, ok := x.GetCertificate().(*SigningCertificate_SignedCertificateEmbeddedSct); ok { return x.SignedCertificateEmbeddedSct } return nil } type isSigningCertificate_Certificate interface { isSigningCertificate_Certificate() } type SigningCertificate_SignedCertificateDetachedSct struct { SignedCertificateDetachedSct *SigningCertificateDetachedSCT `protobuf:"bytes,1,opt,name=signed_certificate_detached_sct,json=signedCertificateDetachedSct,proto3,oneof"` } type SigningCertificate_SignedCertificateEmbeddedSct struct { SignedCertificateEmbeddedSct *SigningCertificateEmbeddedSCT `protobuf:"bytes,2,opt,name=signed_certificate_embedded_sct,json=signedCertificateEmbeddedSct,proto3,oneof"` } func (*SigningCertificate_SignedCertificateDetachedSct) isSigningCertificate_Certificate() {} func (*SigningCertificate_SignedCertificateEmbeddedSct) isSigningCertificate_Certificate() {} // (-- api-linter: core::0142::time-field-type=disabled // // aip.dev/not-precedent: SCT is defined in RFC6962 and we keep the name consistent for easier understanding. --) type SigningCertificateDetachedSCT struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // The certificate chain serialized with the leaf certificate first, followed // by all intermediate certificates (if present), finishing with the root certificate. // // All values are PEM-encoded certificates. Chain *CertificateChain `protobuf:"bytes,1,opt,name=chain,proto3" json:"chain,omitempty"` // The Signed Certificate Timestamp (SCT) is a promise for including the certificate in // a certificate transparency log. It can be "stapled" to verify the inclusion of // a certificate in the log in an offline fashion. // // The SCT format is an AddChainResponse struct, defined in // https://github.com/google/certificate-transparency-go SignedCertificateTimestamp []byte `protobuf:"bytes,2,opt,name=signed_certificate_timestamp,json=signedCertificateTimestamp,proto3" json:"signed_certificate_timestamp,omitempty"` } func (x *SigningCertificateDetachedSCT) Reset() { *x = SigningCertificateDetachedSCT{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *SigningCertificateDetachedSCT) String() string { return protoimpl.X.MessageStringOf(x) } func (*SigningCertificateDetachedSCT) ProtoMessage() {} func (x *SigningCertificateDetachedSCT) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use SigningCertificateDetachedSCT.ProtoReflect.Descriptor instead. func (*SigningCertificateDetachedSCT) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{5} } func (x *SigningCertificateDetachedSCT) GetChain() *CertificateChain { if x != nil { return x.Chain } return nil } func (x *SigningCertificateDetachedSCT) GetSignedCertificateTimestamp() []byte { if x != nil { return x.SignedCertificateTimestamp } return nil } type SigningCertificateEmbeddedSCT struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // The certificate chain serialized with the leaf certificate first, followed // by all intermediate certificates (if present), finishing with the root certificate. // // All values are PEM-encoded certificates. // // The leaf certificate contains an embedded Signed Certificate Timestamp (SCT) to // verify inclusion of the certificate in a log. The SCT format is a SignedCertificateTimestampList, // as defined in https://datatracker.ietf.org/doc/html/rfc6962#section-3.3 Chain *CertificateChain `protobuf:"bytes,1,opt,name=chain,proto3" json:"chain,omitempty"` } func (x *SigningCertificateEmbeddedSCT) Reset() { *x = SigningCertificateEmbeddedSCT{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *SigningCertificateEmbeddedSCT) String() string { return protoimpl.X.MessageStringOf(x) } func (*SigningCertificateEmbeddedSCT) ProtoMessage() {} func (x *SigningCertificateEmbeddedSCT) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use SigningCertificateEmbeddedSCT.ProtoReflect.Descriptor instead. func (*SigningCertificateEmbeddedSCT) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{6} } func (x *SigningCertificateEmbeddedSCT) GetChain() *CertificateChain { if x != nil { return x.Chain } return nil } // This is created for forward compatibility in case we want to add fields to the TrustBundle service in the future type GetTrustBundleRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields } func (x *GetTrustBundleRequest) Reset() { *x = GetTrustBundleRequest{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *GetTrustBundleRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*GetTrustBundleRequest) ProtoMessage() {} func (x *GetTrustBundleRequest) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use GetTrustBundleRequest.ProtoReflect.Descriptor instead. func (*GetTrustBundleRequest) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{7} } type TrustBundle struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // The set of PEM-encoded certificate chains for this Fulcio instance; each chain will start with any // intermediate certificates (if present), finishing with the root certificate. Chains []*CertificateChain `protobuf:"bytes,1,rep,name=chains,proto3" json:"chains,omitempty"` } func (x *TrustBundle) Reset() { *x = TrustBundle{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *TrustBundle) String() string { return protoimpl.X.MessageStringOf(x) } func (*TrustBundle) ProtoMessage() {} func (x *TrustBundle) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use TrustBundle.ProtoReflect.Descriptor instead. func (*TrustBundle) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{8} } func (x *TrustBundle) GetChains() []*CertificateChain { if x != nil { return x.Chains } return nil } type CertificateChain struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // The PEM-encoded certificate chain, ordered from leaf to intermediate to root as applicable. Certificates []string `protobuf:"bytes,1,rep,name=certificates,proto3" json:"certificates,omitempty"` } func (x *CertificateChain) Reset() { *x = CertificateChain{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *CertificateChain) String() string { return protoimpl.X.MessageStringOf(x) } func (*CertificateChain) ProtoMessage() {} func (x *CertificateChain) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use CertificateChain.ProtoReflect.Descriptor instead. func (*CertificateChain) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{9} } func (x *CertificateChain) GetCertificates() []string { if x != nil { return x.Certificates } return nil } // This is created for forward compatibility in case we want to add fields in the future. type GetConfigurationRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields } func (x *GetConfigurationRequest) Reset() { *x = GetConfigurationRequest{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *GetConfigurationRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*GetConfigurationRequest) ProtoMessage() {} func (x *GetConfigurationRequest) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use GetConfigurationRequest.ProtoReflect.Descriptor instead. func (*GetConfigurationRequest) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{10} } // The configuration for the Fulcio instance. type Configuration struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // The OIDC issuers supported by this Fulcio instance. Issuers []*OIDCIssuer `protobuf:"bytes,1,rep,name=issuers,proto3" json:"issuers,omitempty"` } func (x *Configuration) Reset() { *x = Configuration{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *Configuration) String() string { return protoimpl.X.MessageStringOf(x) } func (*Configuration) ProtoMessage() {} func (x *Configuration) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Configuration.ProtoReflect.Descriptor instead. func (*Configuration) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{11} } func (x *Configuration) GetIssuers() []*OIDCIssuer { if x != nil { return x.Issuers } return nil } // Metadata about an OIDC issuer. type OIDCIssuer struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // Types that are assignable to Issuer: // // *OIDCIssuer_IssuerUrl // *OIDCIssuer_WildcardIssuerUrl Issuer isOIDCIssuer_Issuer `protobuf_oneof:"issuer"` // The expected audience of the OIDC token for the issuer. Audience string `protobuf:"bytes,3,opt,name=audience,proto3" json:"audience,omitempty"` // The OIDC claim that must be signed for a proof of possession challenge. ChallengeClaim string `protobuf:"bytes,4,opt,name=challenge_claim,json=challengeClaim,proto3" json:"challenge_claim,omitempty"` // The expected SPIFFE trust domain. Only present when the OIDC issuer issues tokens for SPIFFE identities. SpiffeTrustDomain string `protobuf:"bytes,5,opt,name=spiffe_trust_domain,json=spiffeTrustDomain,proto3" json:"spiffe_trust_domain,omitempty"` // The type of the IDP (e.g. "email", "username", etc.). IssuerType string `protobuf:"bytes,6,opt,name=issuer_type,json=issuerType,proto3" json:"issuer_type,omitempty"` // The expected subject domain. Only present when the OIDC issuer issues tokens for URI or username identities. SubjectDomain string `protobuf:"bytes,7,opt,name=subject_domain,json=subjectDomain,proto3" json:"subject_domain,omitempty"` } func (x *OIDCIssuer) Reset() { *x = OIDCIssuer{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *OIDCIssuer) String() string { return protoimpl.X.MessageStringOf(x) } func (*OIDCIssuer) ProtoMessage() {} func (x *OIDCIssuer) ProtoReflect() protoreflect.Message { mi := &file_fulcio_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use OIDCIssuer.ProtoReflect.Descriptor instead. func (*OIDCIssuer) Descriptor() ([]byte, []int) { return file_fulcio_proto_rawDescGZIP(), []int{12} } func (m *OIDCIssuer) GetIssuer() isOIDCIssuer_Issuer { if m != nil { return m.Issuer } return nil } func (x *OIDCIssuer) GetIssuerUrl() string { if x, ok := x.GetIssuer().(*OIDCIssuer_IssuerUrl); ok { return x.IssuerUrl } return "" } func (x *OIDCIssuer) GetWildcardIssuerUrl() string { if x, ok := x.GetIssuer().(*OIDCIssuer_WildcardIssuerUrl); ok { return x.WildcardIssuerUrl } return "" } func (x *OIDCIssuer) GetAudience() string { if x != nil { return x.Audience } return "" } func (x *OIDCIssuer) GetChallengeClaim() string { if x != nil { return x.ChallengeClaim } return "" } func (x *OIDCIssuer) GetSpiffeTrustDomain() string { if x != nil { return x.SpiffeTrustDomain } return "" } func (x *OIDCIssuer) GetIssuerType() string { if x != nil { return x.IssuerType } return "" } func (x *OIDCIssuer) GetSubjectDomain() string { if x != nil { return x.SubjectDomain } return "" } type isOIDCIssuer_Issuer interface { isOIDCIssuer_Issuer() } type OIDCIssuer_IssuerUrl struct { // The URL of the OIDC issuer. IssuerUrl string `protobuf:"bytes,1,opt,name=issuer_url,json=issuerUrl,proto3,oneof"` } type OIDCIssuer_WildcardIssuerUrl struct { // The URL of wildcard OIDC issuer, e.g. "https://oidc.eks.*.amazonaws.com/id/*". // When comparing the issuer, the wildcards will be replaced by "[-_a-zA-Z0-9]+". WildcardIssuerUrl string `protobuf:"bytes,2,opt,name=wildcard_issuer_url,json=wildcardIssuerUrl,proto3,oneof"` } func (*OIDCIssuer_IssuerUrl) isOIDCIssuer_Issuer() {} func (*OIDCIssuer_WildcardIssuerUrl) isOIDCIssuer_Issuer() {} var File_fulcio_proto protoreflect.FileDescriptor var file_fulcio_proto_rawDesc = []byte{ 0x0a, 0x0c, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9d, 0x02, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x5e, 0x0a, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x48, 0x00, 0x52, 0x10, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x46, 0x0a, 0x1b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x48, 0x00, 0x52, 0x19, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x05, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x4e, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x11, 0x6f, 0x69, 0x64, 0x63, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x22, 0x90, 0x01, 0x0a, 0x10, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x46, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x6f, 0x73, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x11, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x4f, 0x66, 0x50, 0x6f, 0x73, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x75, 0x0a, 0x09, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x48, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x1e, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0xa3, 0x02, 0x0a, 0x12, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x7e, 0x0a, 0x1f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x73, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x53, 0x43, 0x54, 0x48, 0x00, 0x52, 0x1c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x53, 0x63, 0x74, 0x12, 0x7e, 0x0a, 0x1f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, 0x43, 0x54, 0x48, 0x00, 0x52, 0x1c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, 0x63, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0xa1, 0x01, 0x0a, 0x1d, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x53, 0x43, 0x54, 0x12, 0x3e, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x40, 0x0a, 0x1c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x5f, 0x0a, 0x1d, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, 0x43, 0x54, 0x12, 0x3e, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4f, 0x0a, 0x0b, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x40, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x22, 0x36, 0x0a, 0x10, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4d, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x07, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x49, 0x44, 0x43, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x52, 0x07, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x73, 0x22, 0xa6, 0x02, 0x0a, 0x0a, 0x4f, 0x49, 0x44, 0x43, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x30, 0x0a, 0x13, 0x77, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x5f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x11, 0x77, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x08, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x2a, 0x5f, 0x0a, 0x12, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x24, 0x0a, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x53, 0x41, 0x5f, 0x50, 0x53, 0x53, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x43, 0x44, 0x53, 0x41, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x44, 0x32, 0x35, 0x35, 0x31, 0x39, 0x10, 0x03, 0x32, 0xb6, 0x03, 0x0a, 0x02, 0x43, 0x41, 0x12, 0x9f, 0x01, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x37, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x12, 0x81, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x2d, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x8f, 0x03, 0x92, 0x41, 0xb1, 0x02, 0x12, 0xb9, 0x01, 0x0a, 0x06, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x22, 0x5c, 0x0a, 0x17, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x1a, 0x1d, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x64, 0x65, 0x76, 0x40, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2a, 0x4a, 0x0a, 0x12, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x32, 0x2e, 0x30, 0x12, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x32, 0x2e, 0x30, 0x2e, 0x30, 0x1a, 0x13, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x2a, 0x01, 0x01, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x72, 0x37, 0x0a, 0x11, 0x4d, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x0a, 0x16, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x42, 0x0b, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_fulcio_proto_rawDescOnce sync.Once file_fulcio_proto_rawDescData = file_fulcio_proto_rawDesc ) func file_fulcio_proto_rawDescGZIP() []byte { file_fulcio_proto_rawDescOnce.Do(func() { file_fulcio_proto_rawDescData = protoimpl.X.CompressGZIP(file_fulcio_proto_rawDescData) }) return file_fulcio_proto_rawDescData } var file_fulcio_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_fulcio_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_fulcio_proto_goTypes = []any{ (PublicKeyAlgorithm)(0), // 0: dev.sigstore.fulcio.v2.PublicKeyAlgorithm (*CreateSigningCertificateRequest)(nil), // 1: dev.sigstore.fulcio.v2.CreateSigningCertificateRequest (*Credentials)(nil), // 2: dev.sigstore.fulcio.v2.Credentials (*PublicKeyRequest)(nil), // 3: dev.sigstore.fulcio.v2.PublicKeyRequest (*PublicKey)(nil), // 4: dev.sigstore.fulcio.v2.PublicKey (*SigningCertificate)(nil), // 5: dev.sigstore.fulcio.v2.SigningCertificate (*SigningCertificateDetachedSCT)(nil), // 6: dev.sigstore.fulcio.v2.SigningCertificateDetachedSCT (*SigningCertificateEmbeddedSCT)(nil), // 7: dev.sigstore.fulcio.v2.SigningCertificateEmbeddedSCT (*GetTrustBundleRequest)(nil), // 8: dev.sigstore.fulcio.v2.GetTrustBundleRequest (*TrustBundle)(nil), // 9: dev.sigstore.fulcio.v2.TrustBundle (*CertificateChain)(nil), // 10: dev.sigstore.fulcio.v2.CertificateChain (*GetConfigurationRequest)(nil), // 11: dev.sigstore.fulcio.v2.GetConfigurationRequest (*Configuration)(nil), // 12: dev.sigstore.fulcio.v2.Configuration (*OIDCIssuer)(nil), // 13: dev.sigstore.fulcio.v2.OIDCIssuer } var file_fulcio_proto_depIdxs = []int32{ 2, // 0: dev.sigstore.fulcio.v2.CreateSigningCertificateRequest.credentials:type_name -> dev.sigstore.fulcio.v2.Credentials 3, // 1: dev.sigstore.fulcio.v2.CreateSigningCertificateRequest.public_key_request:type_name -> dev.sigstore.fulcio.v2.PublicKeyRequest 4, // 2: dev.sigstore.fulcio.v2.PublicKeyRequest.public_key:type_name -> dev.sigstore.fulcio.v2.PublicKey 0, // 3: dev.sigstore.fulcio.v2.PublicKey.algorithm:type_name -> dev.sigstore.fulcio.v2.PublicKeyAlgorithm 6, // 4: dev.sigstore.fulcio.v2.SigningCertificate.signed_certificate_detached_sct:type_name -> dev.sigstore.fulcio.v2.SigningCertificateDetachedSCT 7, // 5: dev.sigstore.fulcio.v2.SigningCertificate.signed_certificate_embedded_sct:type_name -> dev.sigstore.fulcio.v2.SigningCertificateEmbeddedSCT 10, // 6: dev.sigstore.fulcio.v2.SigningCertificateDetachedSCT.chain:type_name -> dev.sigstore.fulcio.v2.CertificateChain 10, // 7: dev.sigstore.fulcio.v2.SigningCertificateEmbeddedSCT.chain:type_name -> dev.sigstore.fulcio.v2.CertificateChain 10, // 8: dev.sigstore.fulcio.v2.TrustBundle.chains:type_name -> dev.sigstore.fulcio.v2.CertificateChain 13, // 9: dev.sigstore.fulcio.v2.Configuration.issuers:type_name -> dev.sigstore.fulcio.v2.OIDCIssuer 1, // 10: dev.sigstore.fulcio.v2.CA.CreateSigningCertificate:input_type -> dev.sigstore.fulcio.v2.CreateSigningCertificateRequest 8, // 11: dev.sigstore.fulcio.v2.CA.GetTrustBundle:input_type -> dev.sigstore.fulcio.v2.GetTrustBundleRequest 11, // 12: dev.sigstore.fulcio.v2.CA.GetConfiguration:input_type -> dev.sigstore.fulcio.v2.GetConfigurationRequest 5, // 13: dev.sigstore.fulcio.v2.CA.CreateSigningCertificate:output_type -> dev.sigstore.fulcio.v2.SigningCertificate 9, // 14: dev.sigstore.fulcio.v2.CA.GetTrustBundle:output_type -> dev.sigstore.fulcio.v2.TrustBundle 12, // 15: dev.sigstore.fulcio.v2.CA.GetConfiguration:output_type -> dev.sigstore.fulcio.v2.Configuration 13, // [13:16] is the sub-list for method output_type 10, // [10:13] is the sub-list for method input_type 10, // [10:10] is the sub-list for extension type_name 10, // [10:10] is the sub-list for extension extendee 0, // [0:10] is the sub-list for field type_name } func init() { file_fulcio_proto_init() } func file_fulcio_proto_init() { if File_fulcio_proto != nil { return } if !protoimpl.UnsafeEnabled { file_fulcio_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*CreateSigningCertificateRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Credentials); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*PublicKeyRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*PublicKey); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*SigningCertificate); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*SigningCertificateDetachedSCT); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*SigningCertificateEmbeddedSCT); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*GetTrustBundleRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*TrustBundle); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*CertificateChain); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*GetConfigurationRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*Configuration); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*OIDCIssuer); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } file_fulcio_proto_msgTypes[0].OneofWrappers = []any{ (*CreateSigningCertificateRequest_PublicKeyRequest)(nil), (*CreateSigningCertificateRequest_CertificateSigningRequest)(nil), } file_fulcio_proto_msgTypes[1].OneofWrappers = []any{ (*Credentials_OidcIdentityToken)(nil), } file_fulcio_proto_msgTypes[4].OneofWrappers = []any{ (*SigningCertificate_SignedCertificateDetachedSct)(nil), (*SigningCertificate_SignedCertificateEmbeddedSct)(nil), } file_fulcio_proto_msgTypes[12].OneofWrappers = []any{ (*OIDCIssuer_IssuerUrl)(nil), (*OIDCIssuer_WildcardIssuerUrl)(nil), } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_fulcio_proto_rawDesc, NumEnums: 1, NumMessages: 13, NumExtensions: 0, NumServices: 1, }, GoTypes: file_fulcio_proto_goTypes, DependencyIndexes: file_fulcio_proto_depIdxs, EnumInfos: file_fulcio_proto_enumTypes, MessageInfos: file_fulcio_proto_msgTypes, }.Build() File_fulcio_proto = out.File file_fulcio_proto_rawDesc = nil file_fulcio_proto_goTypes = nil file_fulcio_proto_depIdxs = nil } fulcio-1.6.5/pkg/generated/protobuf/fulcio.pb.gw.go000066400000000000000000000317231470150653400222220ustar00rootroot00000000000000// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. // source: fulcio.proto /* Package protobuf is a reverse proxy. It translates gRPC into RESTful JSON APIs. */ package protobuf import ( "context" "io" "net/http" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" ) // Suppress "imported and not used" errors var _ codes.Code var _ io.Reader var _ status.Status var _ = runtime.String var _ = utilities.NewDoubleArray var _ = metadata.Join func request_CA_CreateSigningCertificate_0(ctx context.Context, marshaler runtime.Marshaler, client CAClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq CreateSigningCertificateRequest var metadata runtime.ServerMetadata if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := client.CreateSigningCertificate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } func local_request_CA_CreateSigningCertificate_0(ctx context.Context, marshaler runtime.Marshaler, server CAServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq CreateSigningCertificateRequest var metadata runtime.ServerMetadata if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := server.CreateSigningCertificate(ctx, &protoReq) return msg, metadata, err } func request_CA_GetTrustBundle_0(ctx context.Context, marshaler runtime.Marshaler, client CAClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq GetTrustBundleRequest var metadata runtime.ServerMetadata msg, err := client.GetTrustBundle(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } func local_request_CA_GetTrustBundle_0(ctx context.Context, marshaler runtime.Marshaler, server CAServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq GetTrustBundleRequest var metadata runtime.ServerMetadata msg, err := server.GetTrustBundle(ctx, &protoReq) return msg, metadata, err } func request_CA_GetConfiguration_0(ctx context.Context, marshaler runtime.Marshaler, client CAClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq GetConfigurationRequest var metadata runtime.ServerMetadata msg, err := client.GetConfiguration(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } func local_request_CA_GetConfiguration_0(ctx context.Context, marshaler runtime.Marshaler, server CAServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq GetConfigurationRequest var metadata runtime.ServerMetadata msg, err := server.GetConfiguration(ctx, &protoReq) return msg, metadata, err } // RegisterCAHandlerServer registers the http handlers for service CA to "mux". // UnaryRPC :call CAServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterCAHandlerFromEndpoint instead. // GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call. func RegisterCAHandlerServer(ctx context.Context, mux *runtime.ServeMux, server CAServer) error { mux.Handle("POST", pattern_CA_CreateSigningCertificate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/dev.sigstore.fulcio.v2.CA/CreateSigningCertificate", runtime.WithHTTPPathPattern("/api/v2/signingCert")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } resp, md, err := local_request_CA_CreateSigningCertificate_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } forward_CA_CreateSigningCertificate_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) mux.Handle("GET", pattern_CA_GetTrustBundle_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/dev.sigstore.fulcio.v2.CA/GetTrustBundle", runtime.WithHTTPPathPattern("/api/v2/trustBundle")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } resp, md, err := local_request_CA_GetTrustBundle_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } forward_CA_GetTrustBundle_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) mux.Handle("GET", pattern_CA_GetConfiguration_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/dev.sigstore.fulcio.v2.CA/GetConfiguration", runtime.WithHTTPPathPattern("/api/v2/configuration")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } resp, md, err := local_request_CA_GetConfiguration_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } forward_CA_GetConfiguration_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) return nil } // RegisterCAHandlerFromEndpoint is same as RegisterCAHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterCAHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { conn, err := grpc.NewClient(endpoint, opts...) if err != nil { return err } defer func() { if err != nil { if cerr := conn.Close(); cerr != nil { grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } return } go func() { <-ctx.Done() if cerr := conn.Close(); cerr != nil { grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } }() }() return RegisterCAHandler(ctx, mux, conn) } // RegisterCAHandler registers the http handlers for service CA to "mux". // The handlers forward requests to the grpc endpoint over "conn". func RegisterCAHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { return RegisterCAHandlerClient(ctx, mux, NewCAClient(conn)) } // RegisterCAHandlerClient registers the http handlers for service CA // to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "CAClient". // Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "CAClient" // doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in // "CAClient" to call the correct interceptors. This client ignores the HTTP middlewares. func RegisterCAHandlerClient(ctx context.Context, mux *runtime.ServeMux, client CAClient) error { mux.Handle("POST", pattern_CA_CreateSigningCertificate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/dev.sigstore.fulcio.v2.CA/CreateSigningCertificate", runtime.WithHTTPPathPattern("/api/v2/signingCert")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } resp, md, err := request_CA_CreateSigningCertificate_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } forward_CA_CreateSigningCertificate_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) mux.Handle("GET", pattern_CA_GetTrustBundle_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/dev.sigstore.fulcio.v2.CA/GetTrustBundle", runtime.WithHTTPPathPattern("/api/v2/trustBundle")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } resp, md, err := request_CA_GetTrustBundle_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } forward_CA_GetTrustBundle_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) mux.Handle("GET", pattern_CA_GetConfiguration_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/dev.sigstore.fulcio.v2.CA/GetConfiguration", runtime.WithHTTPPathPattern("/api/v2/configuration")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } resp, md, err := request_CA_GetConfiguration_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } forward_CA_GetConfiguration_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) return nil } var ( pattern_CA_CreateSigningCertificate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v2", "signingCert"}, "")) pattern_CA_GetTrustBundle_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v2", "trustBundle"}, "")) pattern_CA_GetConfiguration_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v2", "configuration"}, "")) ) var ( forward_CA_CreateSigningCertificate_0 = runtime.ForwardResponseMessage forward_CA_GetTrustBundle_0 = runtime.ForwardResponseMessage forward_CA_GetConfiguration_0 = runtime.ForwardResponseMessage ) fulcio-1.6.5/pkg/generated/protobuf/fulcio_grpc.pb.go000066400000000000000000000212661470150653400226220ustar00rootroot00000000000000// // Copyright 2022 The Sigstore 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. // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 // - protoc v5.28.2 // source: fulcio.proto package protobuf import ( context "context" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" ) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. // Requires gRPC-Go v1.64.0 or later. const _ = grpc.SupportPackageIsVersion9 const ( CA_CreateSigningCertificate_FullMethodName = "/dev.sigstore.fulcio.v2.CA/CreateSigningCertificate" CA_GetTrustBundle_FullMethodName = "/dev.sigstore.fulcio.v2.CA/GetTrustBundle" CA_GetConfiguration_FullMethodName = "/dev.sigstore.fulcio.v2.CA/GetConfiguration" ) // CAClient is the client API for CA service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type CAClient interface { // * // Returns an X.509 certificate created by the Fulcio certificate authority for the given request parameters CreateSigningCertificate(ctx context.Context, in *CreateSigningCertificateRequest, opts ...grpc.CallOption) (*SigningCertificate, error) // * // Returns the bundle of certificates that can be used to validate code signing certificates issued by this Fulcio instance GetTrustBundle(ctx context.Context, in *GetTrustBundleRequest, opts ...grpc.CallOption) (*TrustBundle, error) // * // Returns the configuration of supported OIDC issuers, including the required challenge for each issuer. GetConfiguration(ctx context.Context, in *GetConfigurationRequest, opts ...grpc.CallOption) (*Configuration, error) } type cAClient struct { cc grpc.ClientConnInterface } func NewCAClient(cc grpc.ClientConnInterface) CAClient { return &cAClient{cc} } func (c *cAClient) CreateSigningCertificate(ctx context.Context, in *CreateSigningCertificateRequest, opts ...grpc.CallOption) (*SigningCertificate, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(SigningCertificate) err := c.cc.Invoke(ctx, CA_CreateSigningCertificate_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *cAClient) GetTrustBundle(ctx context.Context, in *GetTrustBundleRequest, opts ...grpc.CallOption) (*TrustBundle, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(TrustBundle) err := c.cc.Invoke(ctx, CA_GetTrustBundle_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } func (c *cAClient) GetConfiguration(ctx context.Context, in *GetConfigurationRequest, opts ...grpc.CallOption) (*Configuration, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Configuration) err := c.cc.Invoke(ctx, CA_GetConfiguration_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } // CAServer is the server API for CA service. // All implementations must embed UnimplementedCAServer // for forward compatibility. type CAServer interface { // * // Returns an X.509 certificate created by the Fulcio certificate authority for the given request parameters CreateSigningCertificate(context.Context, *CreateSigningCertificateRequest) (*SigningCertificate, error) // * // Returns the bundle of certificates that can be used to validate code signing certificates issued by this Fulcio instance GetTrustBundle(context.Context, *GetTrustBundleRequest) (*TrustBundle, error) // * // Returns the configuration of supported OIDC issuers, including the required challenge for each issuer. GetConfiguration(context.Context, *GetConfigurationRequest) (*Configuration, error) mustEmbedUnimplementedCAServer() } // UnimplementedCAServer must be embedded to have // forward compatible implementations. // // NOTE: this should be embedded by value instead of pointer to avoid a nil // pointer dereference when methods are called. type UnimplementedCAServer struct{} func (UnimplementedCAServer) CreateSigningCertificate(context.Context, *CreateSigningCertificateRequest) (*SigningCertificate, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateSigningCertificate not implemented") } func (UnimplementedCAServer) GetTrustBundle(context.Context, *GetTrustBundleRequest) (*TrustBundle, error) { return nil, status.Errorf(codes.Unimplemented, "method GetTrustBundle not implemented") } func (UnimplementedCAServer) GetConfiguration(context.Context, *GetConfigurationRequest) (*Configuration, error) { return nil, status.Errorf(codes.Unimplemented, "method GetConfiguration not implemented") } func (UnimplementedCAServer) mustEmbedUnimplementedCAServer() {} func (UnimplementedCAServer) testEmbeddedByValue() {} // UnsafeCAServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to CAServer will // result in compilation errors. type UnsafeCAServer interface { mustEmbedUnimplementedCAServer() } func RegisterCAServer(s grpc.ServiceRegistrar, srv CAServer) { // If the following call pancis, it indicates UnimplementedCAServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { t.testEmbeddedByValue() } s.RegisterService(&CA_ServiceDesc, srv) } func _CA_CreateSigningCertificate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(CreateSigningCertificateRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(CAServer).CreateSigningCertificate(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: CA_CreateSigningCertificate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(CAServer).CreateSigningCertificate(ctx, req.(*CreateSigningCertificateRequest)) } return interceptor(ctx, in, info, handler) } func _CA_GetTrustBundle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetTrustBundleRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(CAServer).GetTrustBundle(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: CA_GetTrustBundle_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(CAServer).GetTrustBundle(ctx, req.(*GetTrustBundleRequest)) } return interceptor(ctx, in, info, handler) } func _CA_GetConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetConfigurationRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(CAServer).GetConfiguration(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: CA_GetConfiguration_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(CAServer).GetConfiguration(ctx, req.(*GetConfigurationRequest)) } return interceptor(ctx, in, info, handler) } // CA_ServiceDesc is the grpc.ServiceDesc for CA service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var CA_ServiceDesc = grpc.ServiceDesc{ ServiceName: "dev.sigstore.fulcio.v2.CA", HandlerType: (*CAServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "CreateSigningCertificate", Handler: _CA_CreateSigningCertificate_Handler, }, { MethodName: "GetTrustBundle", Handler: _CA_GetTrustBundle_Handler, }, { MethodName: "GetConfiguration", Handler: _CA_GetConfiguration_Handler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "fulcio.proto", } fulcio-1.6.5/pkg/generated/protobuf/legacy/000077500000000000000000000000001470150653400206345ustar00rootroot00000000000000fulcio-1.6.5/pkg/generated/protobuf/legacy/fulcio_legacy.pb.go000066400000000000000000000400651470150653400243750ustar00rootroot00000000000000// // Copyright 2022 The Sigstore 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. // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 // protoc v5.28.2 // source: fulcio_legacy.proto package legacy import ( _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" _ "google.golang.org/genproto/googleapis/api/annotations" httpbody "google.golang.org/genproto/googleapis/api/httpbody" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" emptypb "google.golang.org/protobuf/types/known/emptypb" reflect "reflect" sync "sync" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type CreateSigningCertificateRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // The public key to be stored in the requested certificate // // Deprecated: Marked as deprecated in fulcio_legacy.proto. PublicKey *PublicKey `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` // Proof that the client possesses the private key // // Deprecated: Marked as deprecated in fulcio_legacy.proto. SignedEmailAddress []byte `protobuf:"bytes,2,opt,name=signedEmailAddress,proto3" json:"signedEmailAddress,omitempty"` // Optional: PKCS#10 PEM-encoded certificate signing request // Contains the public key to be stored in the requested // certificate. All other CSR fields are ignored. Since // the CSR is self-signed, it also acts as a proof of // possession of the private key. // // In particular, the CSR's subject name is not verified, or tested for // compatibility with its specified X.509 name type (e.g. email address). // // Deprecated: Marked as deprecated in fulcio_legacy.proto. CertificateSigningRequest []byte `protobuf:"bytes,3,opt,name=certificateSigningRequest,proto3" json:"certificateSigningRequest,omitempty"` } func (x *CreateSigningCertificateRequest) Reset() { *x = CreateSigningCertificateRequest{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_legacy_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *CreateSigningCertificateRequest) String() string { return protoimpl.X.MessageStringOf(x) } func (*CreateSigningCertificateRequest) ProtoMessage() {} func (x *CreateSigningCertificateRequest) ProtoReflect() protoreflect.Message { mi := &file_fulcio_legacy_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use CreateSigningCertificateRequest.ProtoReflect.Descriptor instead. func (*CreateSigningCertificateRequest) Descriptor() ([]byte, []int) { return file_fulcio_legacy_proto_rawDescGZIP(), []int{0} } // Deprecated: Marked as deprecated in fulcio_legacy.proto. func (x *CreateSigningCertificateRequest) GetPublicKey() *PublicKey { if x != nil { return x.PublicKey } return nil } // Deprecated: Marked as deprecated in fulcio_legacy.proto. func (x *CreateSigningCertificateRequest) GetSignedEmailAddress() []byte { if x != nil { return x.SignedEmailAddress } return nil } // Deprecated: Marked as deprecated in fulcio_legacy.proto. func (x *CreateSigningCertificateRequest) GetCertificateSigningRequest() []byte { if x != nil { return x.CertificateSigningRequest } return nil } type PublicKey struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // The cryptographic algorithm to use with the key material // // Deprecated: Marked as deprecated in fulcio_legacy.proto. Algorithm string `protobuf:"bytes,1,opt,name=algorithm,proto3" json:"algorithm,omitempty"` // PKIX, ASN.1 DER or PEM-encoded public key. PEM is typically // of type PUBLIC KEY. // // Deprecated: Marked as deprecated in fulcio_legacy.proto. Content []byte `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` } func (x *PublicKey) Reset() { *x = PublicKey{} if protoimpl.UnsafeEnabled { mi := &file_fulcio_legacy_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *PublicKey) String() string { return protoimpl.X.MessageStringOf(x) } func (*PublicKey) ProtoMessage() {} func (x *PublicKey) ProtoReflect() protoreflect.Message { mi := &file_fulcio_legacy_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use PublicKey.ProtoReflect.Descriptor instead. func (*PublicKey) Descriptor() ([]byte, []int) { return file_fulcio_legacy_proto_rawDescGZIP(), []int{1} } // Deprecated: Marked as deprecated in fulcio_legacy.proto. func (x *PublicKey) GetAlgorithm() string { if x != nil { return x.Algorithm } return "" } // Deprecated: Marked as deprecated in fulcio_legacy.proto. func (x *PublicKey) GetContent() []byte { if x != nil { return x.Content } return nil } var File_fulcio_legacy_proto protoreflect.FileDescriptor var file_fulcio_legacy_proto_rawDesc = []byte{ 0x0a, 0x13, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x5f, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1a, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xec, 0x01, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x06, 0xe2, 0x41, 0x01, 0x01, 0x18, 0x01, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0xe2, 0x41, 0x01, 0x01, 0x18, 0x01, 0x52, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x44, 0x0a, 0x19, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0xe2, 0x41, 0x01, 0x01, 0x18, 0x01, 0x52, 0x19, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4f, 0x0a, 0x09, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x20, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0xe2, 0x41, 0x01, 0x02, 0x18, 0x01, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x32, 0xf8, 0x01, 0x0a, 0x02, 0x43, 0x41, 0x12, 0x90, 0x01, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x88, 0x02, 0x01, 0x12, 0x5f, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, 0x88, 0x02, 0x01, 0x42, 0xa1, 0x03, 0x92, 0x41, 0xb8, 0x02, 0x12, 0xc0, 0x01, 0x0a, 0x0d, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x20, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x22, 0x5c, 0x0a, 0x17, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x1a, 0x1d, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x64, 0x65, 0x76, 0x40, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2a, 0x4a, 0x0a, 0x12, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x32, 0x2e, 0x30, 0x12, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x1a, 0x13, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x2a, 0x01, 0x01, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x72, 0x37, 0x0a, 0x11, 0x4d, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x0a, 0x1a, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x42, 0x0b, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_fulcio_legacy_proto_rawDescOnce sync.Once file_fulcio_legacy_proto_rawDescData = file_fulcio_legacy_proto_rawDesc ) func file_fulcio_legacy_proto_rawDescGZIP() []byte { file_fulcio_legacy_proto_rawDescOnce.Do(func() { file_fulcio_legacy_proto_rawDescData = protoimpl.X.CompressGZIP(file_fulcio_legacy_proto_rawDescData) }) return file_fulcio_legacy_proto_rawDescData } var file_fulcio_legacy_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_fulcio_legacy_proto_goTypes = []any{ (*CreateSigningCertificateRequest)(nil), // 0: dev.sigstore.fulcio.v1beta.CreateSigningCertificateRequest (*PublicKey)(nil), // 1: dev.sigstore.fulcio.v1beta.PublicKey (*emptypb.Empty)(nil), // 2: google.protobuf.Empty (*httpbody.HttpBody)(nil), // 3: google.api.HttpBody } var file_fulcio_legacy_proto_depIdxs = []int32{ 1, // 0: dev.sigstore.fulcio.v1beta.CreateSigningCertificateRequest.publicKey:type_name -> dev.sigstore.fulcio.v1beta.PublicKey 0, // 1: dev.sigstore.fulcio.v1beta.CA.CreateSigningCertificate:input_type -> dev.sigstore.fulcio.v1beta.CreateSigningCertificateRequest 2, // 2: dev.sigstore.fulcio.v1beta.CA.GetRootCertificate:input_type -> google.protobuf.Empty 3, // 3: dev.sigstore.fulcio.v1beta.CA.CreateSigningCertificate:output_type -> google.api.HttpBody 3, // 4: dev.sigstore.fulcio.v1beta.CA.GetRootCertificate:output_type -> google.api.HttpBody 3, // [3:5] is the sub-list for method output_type 1, // [1:3] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name } func init() { file_fulcio_legacy_proto_init() } func file_fulcio_legacy_proto_init() { if File_fulcio_legacy_proto != nil { return } if !protoimpl.UnsafeEnabled { file_fulcio_legacy_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*CreateSigningCertificateRequest); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } file_fulcio_legacy_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*PublicKey); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_fulcio_legacy_proto_rawDesc, NumEnums: 0, NumMessages: 2, NumExtensions: 0, NumServices: 1, }, GoTypes: file_fulcio_legacy_proto_goTypes, DependencyIndexes: file_fulcio_legacy_proto_depIdxs, MessageInfos: file_fulcio_legacy_proto_msgTypes, }.Build() File_fulcio_legacy_proto = out.File file_fulcio_legacy_proto_rawDesc = nil file_fulcio_legacy_proto_goTypes = nil file_fulcio_legacy_proto_depIdxs = nil } fulcio-1.6.5/pkg/generated/protobuf/legacy/fulcio_legacy.pb.gw.go000066400000000000000000000235471470150653400250170ustar00rootroot00000000000000// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. // source: fulcio_legacy.proto /* Package legacy is a reverse proxy. It translates gRPC into RESTful JSON APIs. */ package legacy import ( "context" "io" "net/http" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" ) // Suppress "imported and not used" errors var _ codes.Code var _ io.Reader var _ status.Status var _ = runtime.String var _ = utilities.NewDoubleArray var _ = metadata.Join func request_CA_CreateSigningCertificate_0(ctx context.Context, marshaler runtime.Marshaler, client CAClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq CreateSigningCertificateRequest var metadata runtime.ServerMetadata if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := client.CreateSigningCertificate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } func local_request_CA_CreateSigningCertificate_0(ctx context.Context, marshaler runtime.Marshaler, server CAServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq CreateSigningCertificateRequest var metadata runtime.ServerMetadata if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } msg, err := server.CreateSigningCertificate(ctx, &protoReq) return msg, metadata, err } func request_CA_GetRootCertificate_0(ctx context.Context, marshaler runtime.Marshaler, client CAClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq emptypb.Empty var metadata runtime.ServerMetadata msg, err := client.GetRootCertificate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } func local_request_CA_GetRootCertificate_0(ctx context.Context, marshaler runtime.Marshaler, server CAServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq emptypb.Empty var metadata runtime.ServerMetadata msg, err := server.GetRootCertificate(ctx, &protoReq) return msg, metadata, err } // RegisterCAHandlerServer registers the http handlers for service CA to "mux". // UnaryRPC :call CAServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterCAHandlerFromEndpoint instead. // GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call. func RegisterCAHandlerServer(ctx context.Context, mux *runtime.ServeMux, server CAServer) error { mux.Handle("POST", pattern_CA_CreateSigningCertificate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/dev.sigstore.fulcio.v1beta.CA/CreateSigningCertificate", runtime.WithHTTPPathPattern("/api/v1/signingCert")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } resp, md, err := local_request_CA_CreateSigningCertificate_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } forward_CA_CreateSigningCertificate_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) mux.Handle("GET", pattern_CA_GetRootCertificate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/dev.sigstore.fulcio.v1beta.CA/GetRootCertificate", runtime.WithHTTPPathPattern("/api/v1/rootCert")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } resp, md, err := local_request_CA_GetRootCertificate_0(annotatedContext, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } forward_CA_GetRootCertificate_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) return nil } // RegisterCAHandlerFromEndpoint is same as RegisterCAHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterCAHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { conn, err := grpc.NewClient(endpoint, opts...) if err != nil { return err } defer func() { if err != nil { if cerr := conn.Close(); cerr != nil { grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } return } go func() { <-ctx.Done() if cerr := conn.Close(); cerr != nil { grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } }() }() return RegisterCAHandler(ctx, mux, conn) } // RegisterCAHandler registers the http handlers for service CA to "mux". // The handlers forward requests to the grpc endpoint over "conn". func RegisterCAHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { return RegisterCAHandlerClient(ctx, mux, NewCAClient(conn)) } // RegisterCAHandlerClient registers the http handlers for service CA // to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "CAClient". // Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "CAClient" // doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in // "CAClient" to call the correct interceptors. This client ignores the HTTP middlewares. func RegisterCAHandlerClient(ctx context.Context, mux *runtime.ServeMux, client CAClient) error { mux.Handle("POST", pattern_CA_CreateSigningCertificate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/dev.sigstore.fulcio.v1beta.CA/CreateSigningCertificate", runtime.WithHTTPPathPattern("/api/v1/signingCert")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } resp, md, err := request_CA_CreateSigningCertificate_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } forward_CA_CreateSigningCertificate_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) mux.Handle("GET", pattern_CA_GetRootCertificate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) var err error var annotatedContext context.Context annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/dev.sigstore.fulcio.v1beta.CA/GetRootCertificate", runtime.WithHTTPPathPattern("/api/v1/rootCert")) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } resp, md, err := request_CA_GetRootCertificate_0(annotatedContext, inboundMarshaler, client, req, pathParams) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) if err != nil { runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) return } forward_CA_GetRootCertificate_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) return nil } var ( pattern_CA_CreateSigningCertificate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "signingCert"}, "")) pattern_CA_GetRootCertificate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "rootCert"}, "")) ) var ( forward_CA_CreateSigningCertificate_0 = runtime.ForwardResponseMessage forward_CA_GetRootCertificate_0 = runtime.ForwardResponseMessage ) fulcio-1.6.5/pkg/generated/protobuf/legacy/fulcio_legacy_grpc.pb.go000066400000000000000000000170041470150653400254050ustar00rootroot00000000000000// // Copyright 2022 The Sigstore 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. // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.5.1 // - protoc v5.28.2 // source: fulcio_legacy.proto package legacy import ( context "context" httpbody "google.golang.org/genproto/googleapis/api/httpbody" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" emptypb "google.golang.org/protobuf/types/known/emptypb" ) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. // Requires gRPC-Go v1.64.0 or later. const _ = grpc.SupportPackageIsVersion9 const ( CA_CreateSigningCertificate_FullMethodName = "/dev.sigstore.fulcio.v1beta.CA/CreateSigningCertificate" CA_GetRootCertificate_FullMethodName = "/dev.sigstore.fulcio.v1beta.CA/GetRootCertificate" ) // CAClient is the client API for CA service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // // This implements the pre-GA HTTP-based Fulcio API. // This interface is deprecated and will only receive backports of security-related features - clients should prefer the GA GRPC interface! type CAClient interface { // Deprecated: Do not use. // // Returns an X509 certificate created by the Fulcio certificate authority for the given request parameters CreateSigningCertificate(ctx context.Context, in *CreateSigningCertificateRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error) // Deprecated: Do not use. // // Returns the public key that can be used to validate the signed tree head GetRootCertificate(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*httpbody.HttpBody, error) } type cAClient struct { cc grpc.ClientConnInterface } func NewCAClient(cc grpc.ClientConnInterface) CAClient { return &cAClient{cc} } // Deprecated: Do not use. func (c *cAClient) CreateSigningCertificate(ctx context.Context, in *CreateSigningCertificateRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(httpbody.HttpBody) err := c.cc.Invoke(ctx, CA_CreateSigningCertificate_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } // Deprecated: Do not use. func (c *cAClient) GetRootCertificate(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*httpbody.HttpBody, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(httpbody.HttpBody) err := c.cc.Invoke(ctx, CA_GetRootCertificate_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } // CAServer is the server API for CA service. // All implementations must embed UnimplementedCAServer // for forward compatibility. // // This implements the pre-GA HTTP-based Fulcio API. // This interface is deprecated and will only receive backports of security-related features - clients should prefer the GA GRPC interface! type CAServer interface { // Deprecated: Do not use. // // Returns an X509 certificate created by the Fulcio certificate authority for the given request parameters CreateSigningCertificate(context.Context, *CreateSigningCertificateRequest) (*httpbody.HttpBody, error) // Deprecated: Do not use. // // Returns the public key that can be used to validate the signed tree head GetRootCertificate(context.Context, *emptypb.Empty) (*httpbody.HttpBody, error) mustEmbedUnimplementedCAServer() } // UnimplementedCAServer must be embedded to have // forward compatible implementations. // // NOTE: this should be embedded by value instead of pointer to avoid a nil // pointer dereference when methods are called. type UnimplementedCAServer struct{} func (UnimplementedCAServer) CreateSigningCertificate(context.Context, *CreateSigningCertificateRequest) (*httpbody.HttpBody, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateSigningCertificate not implemented") } func (UnimplementedCAServer) GetRootCertificate(context.Context, *emptypb.Empty) (*httpbody.HttpBody, error) { return nil, status.Errorf(codes.Unimplemented, "method GetRootCertificate not implemented") } func (UnimplementedCAServer) mustEmbedUnimplementedCAServer() {} func (UnimplementedCAServer) testEmbeddedByValue() {} // UnsafeCAServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to CAServer will // result in compilation errors. type UnsafeCAServer interface { mustEmbedUnimplementedCAServer() } func RegisterCAServer(s grpc.ServiceRegistrar, srv CAServer) { // If the following call pancis, it indicates UnimplementedCAServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { t.testEmbeddedByValue() } s.RegisterService(&CA_ServiceDesc, srv) } func _CA_CreateSigningCertificate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(CreateSigningCertificateRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(CAServer).CreateSigningCertificate(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: CA_CreateSigningCertificate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(CAServer).CreateSigningCertificate(ctx, req.(*CreateSigningCertificateRequest)) } return interceptor(ctx, in, info, handler) } func _CA_GetRootCertificate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(emptypb.Empty) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(CAServer).GetRootCertificate(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: CA_GetRootCertificate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(CAServer).GetRootCertificate(ctx, req.(*emptypb.Empty)) } return interceptor(ctx, in, info, handler) } // CA_ServiceDesc is the grpc.ServiceDesc for CA service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var CA_ServiceDesc = grpc.ServiceDesc{ ServiceName: "dev.sigstore.fulcio.v1beta.CA", HandlerType: (*CAServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "CreateSigningCertificate", Handler: _CA_CreateSigningCertificate_Handler, }, { MethodName: "GetRootCertificate", Handler: _CA_GetRootCertificate_Handler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "fulcio_legacy.proto", } fulcio-1.6.5/pkg/identity/000077500000000000000000000000001470150653400154235ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/authorize.go000066400000000000000000000022711470150653400177660ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 identity import ( "context" "fmt" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" ) // We do this to bypass needing actual OIDC tokens for unit testing. var Authorize = actualAuthorize func actualAuthorize(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { issuer, err := extractIssuerURL(token) if err != nil { return nil, err } verifier, ok := config.FromContext(ctx).GetVerifier(issuer, opts...) if !ok { return nil, fmt.Errorf("unsupported issuer: %s", issuer) } return verifier.Verify(ctx, token) } fulcio-1.6.5/pkg/identity/base/000077500000000000000000000000001470150653400163355ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/base/issuer.go000066400000000000000000000043621470150653400202030ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 base import ( "context" "fmt" "regexp" "strings" "github.com/google/go-cmp/cmp/cmpopts" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) var ( // For testing CmpOptions = cmpopts.IgnoreUnexported(baseIssuer{}) ) type baseIssuer struct { issuerURL string } func Issuer(issuerURL string) identity.Issuer { return &baseIssuer{issuerURL: issuerURL} } // This is unimplemented for the base issuer, and should be implemented unique to each issuer func (e *baseIssuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { //nolint: revive return nil, fmt.Errorf("unimplemented") } // Match is the same across issuers, so it doesn't need to be implemented anywhere else func (e *baseIssuer) Match(_ context.Context, url string) bool { if url == e.issuerURL { return true } // If this is a MetaIssuer the issuer URL could be a regex // Check if the regex is valid against the provided url re, err := metaRegex(e.issuerURL) if err != nil { return false } return re.MatchString(url) } func metaRegex(issuer string) (*regexp.Regexp, error) { // Quote all of the "meta" characters like `.` to avoid // those literal characters in the URL matching any character. // This will ALSO quote `*`, so we replace the quoted version. quoted := regexp.QuoteMeta(issuer) // Replace the quoted `*` with a regular expression that // will match alpha-numeric parts with common additional // "special" characters. replaced := strings.ReplaceAll(quoted, regexp.QuoteMeta("*"), "[-_a-zA-Z0-9]+") // Compile into a regular expression. return regexp.Compile(replaced) } fulcio-1.6.5/pkg/identity/base/issuer_test.go000066400000000000000000000062561470150653400212460ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 base import ( "context" "testing" ) func TestMetaURLs(t *testing.T) { tests := []struct { name string issuer string matches []string misses []string }{{ name: "AWS meta URL", issuer: "https://oidc.eks.*.amazonaws.com/id/*", matches: []string{ "https://oidc.eks.us-west-2.amazonaws.com/id/B02C93B6A2D30341AD01E1B6D48164CB", }, misses: []string{ // Extra dots "https://oidc.eks.us.west.2.amazonaws.com/id/B02C93B6A2D30341AD01E1B6D48164CB", // Extra slashes "https://oidc.eks.us-west/2.amazonaws.com/id/B02C93B6A2D3/0341AD01E1B6D48164CB", }, }, { name: "GKE meta URL", issuer: "https://container.googleapis.com/v1/projects/*/locations/*/clusters/*", matches: []string{ "https://container.googleapis.com/v1/projects/mattmoor-credit/locations/us-west1-b/clusters/tenant-cluster", }, misses: []string{ // Extra dots "https://container.googleapis.com/v1/projects/mattmoor-credit/locations/us.west1.b/clusters/tenant-cluster", }, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { re, err := metaRegex(test.issuer) if err != nil { t.Errorf("metaRegex() = %v", err) } for _, match := range test.matches { if !re.MatchString(match) { t.Errorf("MatchString(%q) = false, wanted true", match) } } for _, miss := range test.misses { if re.MatchString(miss) { t.Errorf("MatchString(%q) = true, wanted false", miss) } } }) } } func TestMatch(t *testing.T) { tests := []struct { description string issuerURL string url string expected bool }{ { description: "standard url", issuerURL: "example.com", url: "example.com", expected: true, }, { description: "url doesn't match", issuerURL: "example.com", url: "something-else.com", }, { description: "valid regex", issuerURL: "wildcard.*.example.com", url: "wildcard.hello.example.com", expected: true, }, { description: "invalid regex", issuerURL: "wildcard.*.example.com", url: "wildcard.helloexample.com", }, } for _, test := range tests { t.Run(test.description, func(t *testing.T) { base := Issuer(test.issuerURL) matched := base.Match(context.Background(), test.url) if matched != test.expected { t.Fatalf("expected %v got %v", test.expected, matched) } }) } } func TestAuthenticate(t *testing.T) { issuer := Issuer("example.com") if _, err := issuer.Authenticate(context.Background(), "token"); err == nil { t.Fatal("expected error on authenticate, BaseIssuer shouldn't implement Authenticate") } } fulcio-1.6.5/pkg/identity/buildkite/000077500000000000000000000000001470150653400173775ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/buildkite/issuer.go000066400000000000000000000022741470150653400212450ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 buildkite import ( "context" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/base" ) type buildkiteIssuer struct { identity.Issuer } func Issuer(issuerURL string) identity.Issuer { return &buildkiteIssuer{base.Issuer(issuerURL)} } func (e *buildkiteIssuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { idtoken, err := identity.Authorize(ctx, token, opts...) if err != nil { return nil, err } return JobPrincipalFromIDToken(ctx, idtoken) } fulcio-1.6.5/pkg/identity/buildkite/issuer_test.go000066400000000000000000000045131470150653400223020ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 buildkite import ( "context" "encoding/json" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) func TestIssuer(t *testing.T) { ctx := context.Background() url := "test-issuer-url" issuer := Issuer(url) // test the Match function t.Run("match", func(t *testing.T) { if matches := issuer.Match(ctx, url); !matches { t.Fatal("expected url to match but it doesn't") } if matches := issuer.Match(ctx, "some-other-url"); matches { t.Fatal("expected match to fail but it didn't") } }) t.Run("authenticate", func(t *testing.T) { token := &oidc.IDToken{ Issuer: "https://iss.example.com", Subject: "organization:acme-inc:pipeline:bash-example:ref:refs/heads/main:commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:step:build", } claims, err := json.Marshal(map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://agent.buildkite.com", "organization_slug": "acme-inc", "pipeline_slug": "bash-example", "sub": "organization:acme-inc:pipeline:bash-example:ref:refs/heads/main:commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:step:build", }) if err != nil { t.Fatal(err) } withClaims(token, claims) identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { return token, nil } principal, err := issuer.Authenticate(ctx, "token") if err != nil { t.Fatal(err) } if principal.Name(ctx) != "organization:acme-inc:pipeline:bash-example:ref:refs/heads/main:commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:step:build" { t.Fatalf("got unexpected name %s", principal.Name(ctx)) } }) } fulcio-1.6.5/pkg/identity/buildkite/principal.go000066400000000000000000000047341470150653400217170ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 buildkite import ( "context" "crypto/x509" "errors" "fmt" "net/url" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/identity" ) type jobPrincipal struct { // Subject matches the 'sub' claim from the OIDC ID token this is what is // signed as proof of possession for Buildkite job identities subject string // OIDC Issuer URL. Matches 'iss' claim from ID token. The real issuer URL is // https://agent.buildkite.com/.well-known/openid-configuration issuer string // The URL of the pipeline, the container of many builds. This will be // set as a human-friendly SubjectAlternativeName URI in the certificate. url string } func JobPrincipalFromIDToken(_ context.Context, token *oidc.IDToken) (identity.Principal, error) { var claims struct { OrganizationSlug string `json:"organization_slug"` PipelineSlug string `json:"pipeline_slug"` } if err := token.Claims(&claims); err != nil { return nil, err } if claims.OrganizationSlug == "" { return nil, errors.New("missing organization_slug claim in ID token") } if claims.PipelineSlug == "" { return nil, errors.New("missing pipeline_slug claim in ID token") } return &jobPrincipal{ subject: token.Subject, issuer: token.Issuer, url: fmt.Sprintf("https://buildkite.com/%s/%s", claims.OrganizationSlug, claims.PipelineSlug), }, nil } func (p jobPrincipal) Name(_ context.Context) string { return p.subject } func (p jobPrincipal) Embed(_ context.Context, cert *x509.Certificate) error { // Set SubjectAlternativeName to the pipeline URL on the certificate parsed, err := url.Parse(p.url) if err != nil { return err } cert.URIs = []*url.URL{parsed} // Embed additional information into custom extensions cert.ExtraExtensions, err = certificate.Extensions{ Issuer: p.issuer, }.Render() if err != nil { return err } return nil } fulcio-1.6.5/pkg/identity/buildkite/principal_test.go000066400000000000000000000156451470150653400227610ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 buildkite import ( "bytes" "context" "crypto/x509" "encoding/asn1" "encoding/json" "errors" "fmt" "reflect" "strings" "testing" "unsafe" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/identity" ) func TestJobPrincipalFromIDToken(t *testing.T) { tests := map[string]struct { Claims map[string]interface{} ExpectPrincipal jobPrincipal WantErr bool ErrContains string }{ `Valid token authenticates with correct claims`: { Claims: map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://agent.buildkite.com", "organization_slug": "acme-inc", "pipeline_slug": "bash-example", "sub": "organization:acme-inc:pipeline:bash-example:ref:refs/heads/main:commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:step:build", }, ExpectPrincipal: jobPrincipal{ issuer: "https://agent.buildkite.com", subject: "organization:acme-inc:pipeline:bash-example:ref:refs/heads/main:commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:step:build", url: "https://buildkite.com/acme-inc/bash-example", }, WantErr: false, }, `Token missing organization_slug claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://agent.buildkite.com", "pipeline_slug": "bash-example", "sub": "organization:acme-inc:pipeline:bash-example:ref:refs/heads/main:commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:step:build", }, WantErr: true, ErrContains: "organization_slug", }, `Token missing pipeline_slug claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://agent.buildkite.com", "organization_slug": "acme-inc", "sub": "organization:acme-inc:pipeline:bash-example:ref:refs/heads/main:commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:step:build", }, WantErr: true, ErrContains: "pipeline_slug", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) untyped, err := JobPrincipalFromIDToken(context.TODO(), token) if err != nil { if !test.WantErr { t.Fatal("didn't expect error", err) } if !strings.Contains(err.Error(), test.ErrContains) { t.Fatalf("expected error %s to contain %s", err, test.ErrContains) } return } if err == nil && test.WantErr { t.Fatal("expected error but got none") } principal, ok := untyped.(*jobPrincipal) if !ok { t.Errorf("Got wrong principal type %v", untyped) } if *principal != test.ExpectPrincipal { t.Errorf("got %v principal and expected %v", *principal, test.ExpectPrincipal) } }) } } // reflect hack because "claims" field is unexported by oidc IDToken // https://github.com/coreos/go-oidc/pull/329 func withClaims(token *oidc.IDToken, data []byte) { val := reflect.Indirect(reflect.ValueOf(token)) member := val.FieldByName("claims") pointer := unsafe.Pointer(member.UnsafeAddr()) realPointer := (*[]byte)(pointer) *realPointer = data } func TestName(t *testing.T) { tests := map[string]struct { Claims map[string]interface{} ExpectName string }{ `Valid token authenticates with correct claims`: { Claims: map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://agent.buildkite.com", "organization_slug": "acme-inc", "pipeline_slug": "bash-example", "sub": "organization:acme-inc:pipeline:bash-example:ref:refs/heads/main:commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:step:build", }, ExpectName: "organization:acme-inc:pipeline:bash-example:ref:refs/heads/main:commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:step:build", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) principal, err := JobPrincipalFromIDToken(context.TODO(), token) if err != nil { t.Fatal(err) } gotName := principal.Name(context.TODO()) if gotName != test.ExpectName { t.Error("name should match sub claim") } }) } } func TestEmbed(t *testing.T) { tests := map[string]struct { Principal identity.Principal WantErr bool WantFacts map[string]func(x509.Certificate) error }{ `Buildkite job challenge should have issue, subject and url embedded`: { Principal: &jobPrincipal{ issuer: "https://agent.buildkite.com", subject: "doesntmatter", url: `https://buildkite.com/foo/bar`, }, WantErr: false, WantFacts: map[string]func(x509.Certificate) error{ `Certifificate should have correct issuer`: factIssuerIs(`https://agent.buildkite.com`), }, }, `Buildkite job principal with bad URL fails`: { Principal: &jobPrincipal{ subject: "doesntmatter", url: "\nbadurl", }, WantErr: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { var cert x509.Certificate err := test.Principal.Embed(context.TODO(), &cert) if err != nil { if !test.WantErr { t.Error(err) } return } else if test.WantErr { t.Error("expected error") } for factName, fact := range test.WantFacts { t.Run(factName, func(t *testing.T) { if err := fact(cert); err != nil { t.Error(err) } }) } }) } } func factIssuerIs(issuer string) func(x509.Certificate) error { return factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, issuer) } func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { if !bytes.Equal(ext.Value, []byte(value)) { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, ext.Value) } return nil } } return errors.New("extension not set") } } fulcio-1.6.5/pkg/identity/chainguard/000077500000000000000000000000001470150653400175305ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/chainguard/issuer.go000066400000000000000000000023271470150653400213750ustar00rootroot00000000000000// Copyright 2024 The Sigstore 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 chainguard import ( "context" "fmt" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/base" ) type issuer struct { identity.Issuer } func Issuer(issuerURL string) identity.Issuer { return &issuer{base.Issuer(issuerURL)} } func (e *issuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { idtoken, err := identity.Authorize(ctx, token, opts...) if err != nil { return nil, fmt.Errorf("authorizing chainguard issuer: %w", err) } return PrincipalFromIDToken(ctx, idtoken) } fulcio-1.6.5/pkg/identity/chainguard/issuer_test.go000066400000000000000000000052721470150653400224360ustar00rootroot00000000000000// Copyright 2024 The Sigstore 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 chainguard import ( "context" "encoding/json" "fmt" "reflect" "testing" "unsafe" "chainguard.dev/sdk/uidp" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) func TestIssuer(t *testing.T) { ctx := context.Background() url := "test-issuer-url" issuer := Issuer(url) // test the Match function t.Run("match", func(t *testing.T) { if matches := issuer.Match(ctx, url); !matches { t.Fatal("expected url to match but it doesn't") } if matches := issuer.Match(ctx, "some-other-url"); matches { t.Fatal("expected match to fail but it didn't") } }) t.Run("authenticate", func(t *testing.T) { group := uidp.NewUIDP("") id := group.NewChild() token := &oidc.IDToken{ Issuer: "https://iss.example.com", Subject: id.String(), } claims, err := json.Marshal(map[string]interface{}{ "iss": "https://iss.example.com", "sub": id.String(), // Actor claims track the identity that was used to assume the // Chainguard identity. In this case, it is the Catalog Syncer // service principal. "act": map[string]string{ "iss": "https://iss.example.com/", "sub": fmt.Sprintf("catalog-syncer:%s", group.String()), "aud": "chainguard", }, "internal": map[string]interface{}{ "service-principal": "CATALOG_SYNCER", }, }) if err != nil { t.Fatal(err) } withClaims(token, claims) identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { return token, nil } principal, err := issuer.Authenticate(ctx, "token") if err != nil { t.Fatal(err) } if principal.Name(ctx) != id.String() { t.Fatalf("got unexpected name %s", principal.Name(ctx)) } }) } // reflect hack because "claims" field is unexported by oidc IDToken // https://github.com/coreos/go-oidc/pull/329 func withClaims(token *oidc.IDToken, data []byte) { val := reflect.Indirect(reflect.ValueOf(token)) member := val.FieldByName("claims") pointer := unsafe.Pointer(member.UnsafeAddr()) realPointer := (*[]byte)(pointer) *realPointer = data } fulcio-1.6.5/pkg/identity/chainguard/principal.go000066400000000000000000000047061470150653400220470ustar00rootroot00000000000000// Copyright 2024 The Sigstore 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 chainguard import ( "context" "crypto/x509" "net/url" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/sigstore/pkg/oauthflow" ) type workflowPrincipal struct { issuer string subject string name string actor map[string]string servicePrincipal string } var _ identity.Principal = (*workflowPrincipal)(nil) func (w workflowPrincipal) Name(_ context.Context) string { return w.name } func PrincipalFromIDToken(_ context.Context, token *oidc.IDToken) (identity.Principal, error) { var claims struct { Actor map[string]string `json:"act"` Internal struct { ServicePrincipal string `json:"service-principal,omitempty"` } `json:"internal"` } if err := token.Claims(&claims); err != nil { return nil, err } // This is the exact function that cosign uses to extract the "subject" // (misnomer) from the token in order to establish "proof of possession". // We MUST use this to implement Name() or tokens that embed an email claim // will fail to sign because of this divergent logic. name, err := oauthflow.SubjectFromToken(token) if err != nil { return nil, err } return &workflowPrincipal{ issuer: token.Issuer, subject: token.Subject, name: name, actor: claims.Actor, servicePrincipal: claims.Internal.ServicePrincipal, }, nil } func (w workflowPrincipal) Embed(_ context.Context, cert *x509.Certificate) error { baseURL, err := url.Parse(w.issuer) if err != nil { return err } // Set SAN to the / cert.URIs = []*url.URL{baseURL.JoinPath(w.subject)} cert.ExtraExtensions, err = certificate.Extensions{ Issuer: w.issuer, // TODO(mattmoor): Embed more of the Chainguard token structure via OIDs. }.Render() if err != nil { return err } return nil } fulcio-1.6.5/pkg/identity/chainguard/principal_test.go000066400000000000000000000165211470150653400231040ustar00rootroot00000000000000// Copyright 2024 The Sigstore 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 chainguard import ( "context" "crypto/x509" "encoding/asn1" "encoding/json" "errors" "fmt" "net/url" "reflect" "strings" "testing" "chainguard.dev/sdk/uidp" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/identity" ) func TestJobPrincipalFromIDToken(t *testing.T) { group := uidp.NewUIDP("") id := group.NewChild() tests := map[string]struct { Claims map[string]interface{} ExpectPrincipal workflowPrincipal WantErr bool ErrContains string }{ `Service principal token`: { Claims: map[string]interface{}{ "iss": "https://issuer.enforce.dev", "sub": id.String(), // Actor claims track the identity that was used to assume the // Chainguard identity. In this case, it is the Catalog Syncer // service principal. "act": map[string]string{ "iss": "https://iss.example.com/", "sub": fmt.Sprintf("catalog-syncer:%s", group.String()), "aud": "chainguard", }, "internal": map[string]interface{}{ "service-principal": "CATALOG_SYNCER", }, }, ExpectPrincipal: workflowPrincipal{ issuer: "https://issuer.enforce.dev", subject: id.String(), name: id.String(), actor: map[string]string{ "iss": "https://iss.example.com/", "sub": fmt.Sprintf("catalog-syncer:%s", group.String()), "aud": "chainguard", }, servicePrincipal: "CATALOG_SYNCER", }, WantErr: false, }, `Human SSO token`: { Claims: map[string]interface{}{ "iss": "https://issuer.enforce.dev", "sub": group.String(), // Actor claims track the identity that was used to assume the // Chainguard identity. In this case, it is the Catalog Syncer // service principal. "act": map[string]string{ "iss": "https://auth.chainguard.dev/", "sub": "google-oauth2|1234567890", "aud": "fdsaldfkjhasldf", }, }, ExpectPrincipal: workflowPrincipal{ issuer: "https://issuer.enforce.dev", subject: group.String(), name: group.String(), actor: map[string]string{ "iss": "https://auth.chainguard.dev/", "sub": "google-oauth2|1234567890", "aud": "fdsaldfkjhasldf", }, }, WantErr: false, }, `Human SSO token (with email)`: { Claims: map[string]interface{}{ "iss": "https://issuer.enforce.dev", "sub": group.String(), "email": "jane@doe.dev", "email_verified": true, // Actor claims track the identity that was used to assume the // Chainguard identity. In this case, it is the Catalog Syncer // service principal. "act": map[string]string{ "iss": "https://auth.chainguard.dev/", "sub": "google-oauth2|1234567890", "aud": "fdsaldfkjhasldf", }, }, ExpectPrincipal: workflowPrincipal{ issuer: "https://issuer.enforce.dev", subject: group.String(), name: "jane@doe.dev", actor: map[string]string{ "iss": "https://auth.chainguard.dev/", "sub": "google-oauth2|1234567890", "aud": "fdsaldfkjhasldf", }, }, WantErr: false, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) untyped, err := PrincipalFromIDToken(context.TODO(), token) if err != nil { if !test.WantErr { t.Fatal("didn't expect error", err) } if !strings.Contains(err.Error(), test.ErrContains) { t.Fatalf("expected error %s to contain %s", err, test.ErrContains) } return } if err == nil && test.WantErr { t.Fatal("expected error but got none") } principal, ok := untyped.(*workflowPrincipal) if !ok { t.Errorf("Got wrong principal type %v", untyped) } if !reflect.DeepEqual(*principal, test.ExpectPrincipal) { t.Errorf("got %v principal and expected %v", *principal, test.ExpectPrincipal) } }) } } func TestEmbed(t *testing.T) { group := uidp.NewUIDP("") id := group.NewChild() tests := map[string]struct { Principal identity.Principal WantErr bool WantFacts map[string]func(x509.Certificate) error }{ `Chainguard Service Principal`: { Principal: &workflowPrincipal{ issuer: "https://issuer.enforce.dev", subject: id.String(), actor: map[string]string{ "iss": "https://iss.example.com/", "sub": fmt.Sprintf("catalog-syncer:%s", group.String()), "aud": "chainguard", }, servicePrincipal: "CATALOG_SYNCER", }, WantErr: false, WantFacts: map[string]func(x509.Certificate) error{ `Certificate SAN has correct value`: factSanURIIs(fmt.Sprintf("https://issuer.enforce.dev/%s", id.String())), `Certificate has correct issuer (v2) extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 8}, "https://issuer.enforce.dev"), }, }, `Chainguard Human SSO`: { Principal: &workflowPrincipal{ issuer: "https://issuer.enforce.dev", subject: group.String(), actor: map[string]string{ "iss": "https://auth.chainguard.dev/", "sub": "google-oauth2|1234567890", "aud": "fdsaldfkjhasldf", }, }, WantErr: false, WantFacts: map[string]func(x509.Certificate) error{ `Certificate SAN has correct value`: factSanURIIs(fmt.Sprintf("https://issuer.enforce.dev/%s", group.String())), `Certificate has correct issuer (v2) extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 8}, "https://issuer.enforce.dev"), }, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { var cert x509.Certificate err := test.Principal.Embed(context.TODO(), &cert) if err != nil { if !test.WantErr { t.Error(err) } return } else if test.WantErr { t.Error("expected error") } for factName, fact := range test.WantFacts { t.Run(factName, func(t *testing.T) { if err := fact(cert); err != nil { t.Error(err) } }) } }) } } func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { var strVal string _, _ = asn1.Unmarshal(ext.Value, &strVal) if value != strVal { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, strVal) } return nil } } return errors.New("extension not set") } } func factSanURIIs(value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { url, err := url.Parse(value) if err != nil { return err } if cert.URIs[0].String() != url.String() { return fmt.Errorf("expected SAN o be %s, but got %s", value, cert.URIs[0].String()) } return nil } } fulcio-1.6.5/pkg/identity/ciprovider/000077500000000000000000000000001470150653400175715ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/ciprovider/issuer.go000066400000000000000000000023051470150653400214320ustar00rootroot00000000000000// Copyright 2024 The Sigstore 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 ciprovider import ( "context" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/base" ) type ciProviderIssuer struct { identity.Issuer } func Issuer(issuerURL string) identity.Issuer { return &ciProviderIssuer{base.Issuer(issuerURL)} } func (e *ciProviderIssuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { idtoken, err := identity.Authorize(ctx, token, opts...) if err != nil { return nil, err } return WorkflowPrincipalFromIDToken(ctx, idtoken) } fulcio-1.6.5/pkg/identity/ciprovider/issuer_test.go000066400000000000000000000067101470150653400224750ustar00rootroot00000000000000// Copyright 2024 The Sigstore 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 ciprovider import ( "context" "encoding/json" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) func TestIssuer(t *testing.T) { ctx := context.Background() url := "test-issuer-url" issuer := Issuer(url) // test the Match function t.Run("match", func(t *testing.T) { if matches := issuer.Match(ctx, url); !matches { t.Fatal("expected url to match but it doesn't") } if matches := issuer.Match(ctx, "some-other-url"); matches { t.Fatal("expected match to fail but it didn't") } }) t.Run("authenticate", func(t *testing.T) { token := &oidc.IDToken{ Issuer: "https://iss.example.com", Subject: "repo:sigstore/fulcio:ref:refs/heads/main", } claims, err := json.Marshal(map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }) if err != nil { t.Fatal(err) } withClaims(token, claims) ctx := context.TODO() OIDCIssuers := map[string]config.OIDCIssuer{ token.Issuer: { IssuerURL: token.Issuer, Type: config.IssuerTypeCIProvider, CIProvider: "github-workflow", ClientID: "sigstore", }, } template := "{{.foobar}}" ciissuerMetadata := make(map[string]config.IssuerMetadata) ciissuerMetadata["github-workflow"] = config.IssuerMetadata{ ExtensionTemplates: certificate.Extensions{ BuildTrigger: template, }, } cfg := &config.FulcioConfig{ OIDCIssuers: OIDCIssuers, CIIssuerMetadata: ciissuerMetadata, } ctx = config.With(ctx, cfg) identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { return token, nil } principal, err := issuer.Authenticate(ctx, "token") if err != nil { t.Fatal(err) } if principal.Name(ctx) != "repo:sigstore/fulcio:ref:refs/heads/main" { t.Fatalf("got unexpected name %s", principal.Name(ctx)) } }) } fulcio-1.6.5/pkg/identity/ciprovider/principal.go000066400000000000000000000131331470150653400221020ustar00rootroot00000000000000// Copyright 2024 The Sigstore 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 ciprovider import ( "bytes" "context" "crypto/x509" "encoding/json" "fmt" "html/template" "net/url" "reflect" "strings" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) func mapValuesToString(claims map[string]interface{}) map[string]string { newMap := make(map[string]string) for k, v := range claims { newMap[k] = fmt.Sprintf("%s", v) } return newMap } func getTokenClaims(token *oidc.IDToken) (map[string]string, error) { var tokenClaims map[string]interface{} if err := token.Claims(&tokenClaims); err != nil { return nil, err } return mapValuesToString(tokenClaims), nil } // It makes string interpolation for a given string by using the // templates syntax https://pkg.go.dev/text/template // logMetadata added as a parameter for having a richer log func applyTemplateOrReplace( extValueTemplate string, tokenClaims map[string]string, issuerMetadata map[string]string, logMetadata map[string]string) (string, error) { // Here we merge the data from was claimed by the id token with the // default data provided by the yaml file. // The order here matter because we want to override the claimed data // with the default data. // The claimed data will have priority over the default data. mergedData := make(map[string]string) for k, v := range issuerMetadata { mergedData[k] = v } for k, v := range tokenClaims { mergedData[k] = v } if strings.Contains(extValueTemplate, "{{") { var doc bytes.Buffer // This option forces to having the claim that is required // for the template t := template.New("").Option("missingkey=error") // It shouldn't raise error since we already checked all // templates in validateCIIssuerMetadata functions in config.go p, err := t.Parse(extValueTemplate) if err != nil { return "", err } err = p.Execute(&doc, mergedData) if err != nil { return "", err } return doc.String(), nil } claimValue, ok := mergedData[extValueTemplate] if !ok { var jsonMetadata bytes.Buffer inrec, _ := json.Marshal(logMetadata) _ = json.Indent(&jsonMetadata, inrec, "", "\t") return "", fmt.Errorf("value <%s> not present in either claims or defaults. %s", extValueTemplate, jsonMetadata.String()) } return claimValue, nil } type ciPrincipal struct { Token *oidc.IDToken ClaimsMetadata config.IssuerMetadata } func WorkflowPrincipalFromIDToken(ctx context.Context, token *oidc.IDToken) (identity.Principal, error) { cfg := config.FromContext(ctx) issuerCfg, ok := cfg.GetIssuer(token.Issuer) if !ok { return nil, fmt.Errorf("configuration can not be loaded for issuer %v", token.Issuer) } metadata, ok := cfg.CIIssuerMetadata[issuerCfg.CIProvider] if !ok { return nil, fmt.Errorf( "metadata not found for ci provider %s, issuer: %s", issuerCfg.CIProvider, token.Issuer) } return ciPrincipal{ token, metadata, }, nil } func (principal ciPrincipal) Name(_ context.Context) string { return principal.Token.Subject } func (principal ciPrincipal) Embed(_ context.Context, cert *x509.Certificate) error { claimsTemplates := principal.ClaimsMetadata.ExtensionTemplates defaults := principal.ClaimsMetadata.DefaultTemplateValues claims, err := getTokenClaims(principal.Token) if err != nil { return err } if strings.TrimSpace(principal.ClaimsMetadata.SubjectAlternativeNameTemplate) == "" { return fmt.Errorf("SubjectAlternativeNameTemplate should not be empty. Issuer: %s", principal.Token.Issuer) } subjectAlternativeName, err := applyTemplateOrReplace( principal.ClaimsMetadata.SubjectAlternativeNameTemplate, claims, defaults, map[string]string{ "Issuer": principal.Token.Issuer, "ExtensionName": "SubjectAlternativeName", }) if err != nil { return err } sanURL, err := url.Parse(subjectAlternativeName) if err != nil { return err } uris := []*url.URL{sanURL} cert.URIs = uris // We should use value.Elem() here as we need a // addressable reference of the templates for applying the SetString(). v := reflect.ValueOf(&claimsTemplates).Elem() // Type of the reflect value is needed as it is necessary // for getting the field name. vType := v.Type() for i := 0; i < v.NumField(); i++ { s := v.Field(i).String() // value of each field, e.g the template string // We check the field name to avoid to apply the template for the Issuer // Issuer field should always come from the token issuer if strings.TrimSpace(s) == "" || vType.Field(i).Name == "Issuer" { continue } extValue, err := applyTemplateOrReplace(s, claims, defaults, map[string]string{ "Issuer": principal.Token.Issuer, "ExtensionName": vType.Field(i).Name, }) if err != nil { return err } v.Field(i).SetString(extValue) } // Guarantees to set the extension issuer as the token issuer // regardless of whether this field has been set before claimsTemplates.Issuer = principal.Token.Issuer // Embed additional information into custom extensions cert.ExtraExtensions, err = claimsTemplates.Render() if err != nil { return err } return nil } fulcio-1.6.5/pkg/identity/ciprovider/principal_test.go000066400000000000000000000445311470150653400231470ustar00rootroot00000000000000// Copyright 2024 The Sigstore 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 ciprovider import ( "bytes" "context" "crypto/x509" "encoding/asn1" "encoding/json" "errors" "fmt" "reflect" "testing" "unsafe" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/config" ) func TestWorkflowPrincipalFromIDToken(t *testing.T) { tests := map[string]struct { ExpectedPrincipal ciPrincipal }{ `Github workflow challenge should have all Github workflow extensions and issuer set`: { ExpectedPrincipal: ciPrincipal{ ClaimsMetadata: config.IssuerMetadata{ ExtensionTemplates: certificate.Extensions{ Issuer: "issuer", GithubWorkflowTrigger: "event_name", GithubWorkflowSHA: "sha", GithubWorkflowName: "workflow", GithubWorkflowRepository: "repository", GithubWorkflowRef: "ref", BuildSignerURI: "{{ .url }}/{{ .job_workflow_ref }}", BuildSignerDigest: "job_workflow_sha", RunnerEnvironment: "runner_environment", SourceRepositoryURI: "{{ .url }}/{{ .repository }}", SourceRepositoryDigest: "sha", SourceRepositoryRef: "ref", SourceRepositoryIdentifier: "repository_id", SourceRepositoryOwnerURI: "{{ .url }}/{{ .repository_owner }}", SourceRepositoryOwnerIdentifier: "repository_owner_id", BuildConfigURI: "{{ .url }}/{{ .workflow_ref }}", BuildConfigDigest: "workflow_sha", BuildTrigger: "event_name", RunInvocationURI: "{{ .url }}/{{ .repository }}/actions/runs/{{ .run_id }}/attempts/{{ .run_attempt }}", SourceRepositoryVisibilityAtSigning: "repository_visibility", }, DefaultTemplateValues: map[string]string{ "url": "https://github.com", }, SubjectAlternativeNameTemplate: "{{.url}}/{{.job_workflow_ref}}", }, }, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { claims, err := json.Marshal(map[string]interface{}{ "issuer": "https://token.actions.githubusercontent.com", "event_name": "trigger", "sha": "sha", "workflow": "workflowname", "repository": "repository", "ref": "ref", "job_workflow_sha": "jobWorkflowSha", "job_workflow_ref": "jobWorkflowRef", "runner_environment": "runnerEnv", "repository_id": "repoID", "repository_owner": "repoOwner", "repository_owner_id": "repoOwnerID", "workflow_ref": "workflowRef", "workflow_sha": "workflowSHA", "run_id": "runID", "run_attempt": "runAttempt", "repository_visibility": "public", }) if err != nil { t.Fatal(err) } token := &oidc.IDToken{} withClaims(token, claims) test.ExpectedPrincipal.Token = token ctx := context.TODO() OIDCIssuers := map[string]config.OIDCIssuer{ token.Issuer: { IssuerURL: token.Issuer, Type: config.IssuerTypeCIProvider, CIProvider: "github-workflow", ClientID: "sigstore", }, } meta := make(map[string]config.IssuerMetadata) meta["github-workflow"] = test.ExpectedPrincipal.ClaimsMetadata cfg := &config.FulcioConfig{ OIDCIssuers: OIDCIssuers, CIIssuerMetadata: meta, } ctx = config.With(ctx, cfg) principal, err := WorkflowPrincipalFromIDToken(ctx, token) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(principal, test.ExpectedPrincipal) { t.Error("Principals should be equals") } }) } } // reflect hack because "claims" field is unexported by oidc IDToken // https://github.com/coreos/go-oidc/pull/329 func withClaims(token *oidc.IDToken, data []byte) { val := reflect.Indirect(reflect.ValueOf(token)) member := val.FieldByName("claims") pointer := unsafe.Pointer(member.UnsafeAddr()) realPointer := (*[]byte)(pointer) *realPointer = data } func TestName(t *testing.T) { tests := map[string]struct { Claims map[string]interface{} ExpectName string }{ `Valid token authenticates with correct claims`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": "0", "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, ExpectName: "repo:sigstore/fulcio:ref:refs/heads/main", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) ctx := context.TODO() template := "{{.foobar}}" ciissuerMetadata := make(map[string]config.IssuerMetadata) ciissuerMetadata["github-workflow"] = config.IssuerMetadata{ ExtensionTemplates: certificate.Extensions{ BuildTrigger: template, }, } OIDCIssuers := map[string]config.OIDCIssuer{ token.Issuer: { IssuerURL: token.Issuer, Type: config.IssuerTypeCIProvider, CIProvider: "github-workflow", ClientID: "sigstore", }, } cfg := &config.FulcioConfig{ OIDCIssuers: OIDCIssuers, CIIssuerMetadata: ciissuerMetadata, } ctx = config.With(ctx, cfg) principal, err := WorkflowPrincipalFromIDToken(ctx, token) if err != nil { t.Fatal(err) } gotName := principal.Name(context.TODO()) if gotName != test.ExpectName { t.Error("name should match sub claim") } }) } } func TestApplyTemplateOrReplace(t *testing.T) { tokenClaims := map[string]string{ "aud": "sigstore", "event_name": "push", "exp": "0", "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", "ref_type": "branch", "ref_gitlab": "main", "ref_type_tag": "tag", "ref_tag": "1.0.0", "claim_foo": "bar", } issuerMetadata := map[string]string{ "url": "https://github.com", "claim_foo": "default", "default_foo": "default_bar", "empty_value": "", } tests := map[string]struct { Template string ExpectedResult string ExpectErr bool }{ `Valid template`: { Template: "{{ .url }}/{{ .repository }}/actions/runs/{{ .run_id }}/attempts/{{ .run_attempt }}", ExpectedResult: "https://github.com/sigstore/fulcio/actions/runs/42/attempts/1", ExpectErr: false, }, `Empty template`: { Template: "{{}}", ExpectedResult: "", ExpectErr: true, }, `Missing key for template`: { Template: "{{ .foo }}", ExpectedResult: "", ExpectErr: true, }, `Empty string`: { Template: "", ExpectedResult: "", ExpectErr: true, }, `Replaceable string`: { Template: "job_workflow_ref", ExpectedResult: "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", ExpectErr: false, }, `Missing string`: { Template: "bar", ExpectedResult: "", ExpectErr: true, }, `If else template`: { Template: `refs/{{if eq .ref_type "branch"}}heads/{{ else }}tags/{{end}}{{ .ref_gitlab }}`, ExpectedResult: "refs/heads/main", ExpectErr: false, }, `If else template using else condition`: { Template: `refs/{{if eq .ref_type_tag "branch"}}heads/{{ else }}tags/{{end}}{{ .ref_tag }}`, ExpectedResult: "refs/tags/1.0.0", ExpectErr: false, }, `Raise error for empty key in comparison`: { Template: `{{if eq . ""}}foo{{else}}bar{{end}}`, ExpectedResult: "", ExpectErr: true, }, `Should use default when claim doesn't exist`: { Template: "default_foo", ExpectedResult: "default_bar", ExpectErr: false, }, `Should prior claims over defaults when they has the same name`: { Template: "claim_foo", ExpectedResult: "bar", ExpectErr: false, }, `Should return empty string for empty default`: { Template: "{{ .empty_value }}/123", ExpectedResult: "/123", ExpectErr: false, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { res, err := applyTemplateOrReplace(test.Template, tokenClaims, issuerMetadata, map[string]string{ "Issuer": "https://token.actions.githubusercontent.com", }) if res != test.ExpectedResult { t.Errorf("expected result don't matches: Expected %s, received: %s, error: %v", test.ExpectedResult, res, err) } if (err != nil) != test.ExpectErr { t.Errorf("should raise an error don't matches: Expected %v, received: %v, error: %v", test.ExpectErr, err != nil, err) } }) } } func TestEmbed(t *testing.T) { tests := map[string]struct { WantFacts map[string]func(x509.Certificate) error Principal ciPrincipal }{ `Github workflow challenge should have all Github workflow extensions and issuer set`: { WantFacts: map[string]func(x509.Certificate) error{ `Certifificate should have correct issuer`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, "https://token.actions.githubusercontent.com"), `Certificate has correct trigger extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 2}, "trigger"), `Certificate has correct SHA extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 3}, "sha"), `Certificate has correct workflow extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 4}, "workflowname"), `Certificate has correct repository extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 5}, "repository"), `Certificate has correct ref extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 6}, "ref"), `Certificate has correct issuer (v2) extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 8}, "https://token.actions.githubusercontent.com"), `Certificate has correct builder signer URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 9}, "https://github.com/jobWorkflowRef"), `Certificate has correct builder signer digest extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 10}, "jobWorkflowSha"), `Certificate has correct runner environment extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 11}, "runnerEnv"), `Certificate has correct source repo URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 12}, "https://github.com/repository"), `Certificate has correct source repo digest extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 13}, "sha"), `Certificate has correct source repo ref extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 14}, "ref"), `Certificate has correct source repo ID extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 15}, "repoID"), `Certificate has correct source repo owner URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 16}, "https://github.com/repoOwner"), `Certificate has correct source repo owner ID extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 17}, "repoOwnerID"), `Certificate has correct build config URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 18}, "https://github.com/workflowRef"), `Certificate has correct build config digest extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 19}, "workflowSHA"), `Certificate has correct build trigger extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 20}, "trigger"), `Certificate has correct run invocation ID extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 21}, "https://github.com/repository/actions/runs/runID/attempts/runAttempt"), `Certificate has correct source repository visibility extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 22}, "public"), }, Principal: ciPrincipal{ ClaimsMetadata: config.IssuerMetadata{ ExtensionTemplates: certificate.Extensions{ GithubWorkflowTrigger: "event_name", GithubWorkflowSHA: "sha", GithubWorkflowName: "workflow", GithubWorkflowRepository: "repository", GithubWorkflowRef: "ref", BuildSignerURI: "{{ .url }}/{{ .job_workflow_ref }}", BuildSignerDigest: "job_workflow_sha", RunnerEnvironment: "runner_environment", SourceRepositoryURI: "{{ .url }}/{{ .repository }}", SourceRepositoryDigest: "sha", SourceRepositoryRef: "ref", SourceRepositoryIdentifier: "repository_id", SourceRepositoryOwnerURI: "{{ .url }}/{{ .repository_owner }}", SourceRepositoryOwnerIdentifier: "repository_owner_id", BuildConfigURI: "{{ .url }}/{{ .workflow_ref }}", BuildConfigDigest: "workflow_sha", BuildTrigger: "event_name", RunInvocationURI: "{{ .url }}/{{ .repository }}/actions/runs/{{ .run_id }}/attempts/{{ .run_attempt }}", SourceRepositoryVisibilityAtSigning: "repository_visibility", }, DefaultTemplateValues: map[string]string{ "url": "https://github.com", }, SubjectAlternativeNameTemplate: "{{.url}}/{{.job_workflow_ref}}", }, }, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { var cert x509.Certificate claims, err := json.Marshal(map[string]interface{}{ "event_name": "trigger", "sha": "sha", "workflow": "workflowname", "repository": "repository", "ref": "ref", "job_workflow_sha": "jobWorkflowSha", "job_workflow_ref": "jobWorkflowRef", "runner_environment": "runnerEnv", "repository_id": "repoID", "repository_owner": "repoOwner", "repository_owner_id": "repoOwnerID", "workflow_ref": "workflowRef", "workflow_sha": "workflowSHA", "run_id": "runID", "run_attempt": "runAttempt", "repository_visibility": "public", }) if err != nil { t.Fatal(err) } token := &oidc.IDToken{} token.Issuer = "https://token.actions.githubusercontent.com" withClaims(token, claims) test.Principal.Token = token err = test.Principal.Embed(context.TODO(), &cert) if err != nil { t.Error(err) } for factName, fact := range test.WantFacts { t.Run(factName, func(t *testing.T) { if err := fact(cert); err != nil { t.Error(err) } }) } }) } } func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { var strVal string _, _ = asn1.Unmarshal(ext.Value, &strVal) if value != strVal { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, strVal) } return nil } } return errors.New("extension not set") } } func factDeprecatedExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { if !bytes.Equal(ext.Value, []byte(value)) { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, ext.Value) } return nil } } return errors.New("extension not set") } } fulcio-1.6.5/pkg/identity/codefresh/000077500000000000000000000000001470150653400173655ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/codefresh/issuer.go000066400000000000000000000023701470150653400212300ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 codefresh import ( "context" "fmt" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/base" ) type codefreshIssuer struct { identity.Issuer } func Issuer(issuerURL string) identity.Issuer { return &codefreshIssuer{base.Issuer(issuerURL)} } func (e *codefreshIssuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { idtoken, err := identity.Authorize(ctx, token, opts...) if err != nil { return nil, fmt.Errorf("authorizing codefresh issuer: %w", err) } return WorkflowPrincipalFromIDToken(ctx, idtoken) } fulcio-1.6.5/pkg/identity/codefresh/issuer_test.go000066400000000000000000000063341470150653400222730ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 codefresh import ( "context" "encoding/json" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) func TestIssuer(t *testing.T) { ctx := context.Background() url := "test-issuer-url" issuer := Issuer(url) // test the Match function t.Run("match", func(t *testing.T) { if matches := issuer.Match(ctx, url); !matches { t.Fatal("expected url to match but it doesn't") } if matches := issuer.Match(ctx, "some-other-url"); matches { t.Fatal("expected match to fail but it didn't") } }) t.Run("authenticate", func(t *testing.T) { token := &oidc.IDToken{ Issuer: "https://iss.example.com", Subject: "account:628a80b693a15c0f9c13ab75:pipeline:65e6d5551e47e5bc243ca93f:scm_repo_url:https://github.com/test-codefresh/fulcio:scm_user_name:test-codefresh:scm_ref:feat/codefresh-issuer:scm_pull_request_target_branch:main", } claims, err := json.Marshal(map[string]interface{}{ "sub": "account:628a80b693a15c0f9c13ab75:pipeline:65e6d5551e47e5bc243ca93f:scm_repo_url:https://github.com/test-codefresh/fulcio:scm_user_name:test-codefresh:scm_ref:feat/codefresh-issuer:scm_pull_request_target_branch:main", "account_id": "628a80b693a15c0f9c13ab75", "account_name": "test-codefresh", "pipeline_id": "65e6d5551e47e5bc243ca93f", "pipeline_name": "oidc-test/oidc-test-2", "workflow_id": "65e6ebe0bfbfa1782876165e", "scm_user_name": "test-codefresh", "scm_repo_url": "https://github.com/test-codefresh/fulcio", "scm_ref": "feat/codefresh-issuer", "scm_pull_request_target_branch": "main", "runner_environment": "hybrid", "aud": "sigstore", "exp": 1709633177, "iat": 1709632877, "iss": "https://oidc.codefresh.io", }) if err != nil { t.Fatal(err) } withClaims(token, claims) identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { return token, nil } principal, err := issuer.Authenticate(ctx, "token") if err != nil { t.Fatal(err) } if principal.Name(ctx) != "account:628a80b693a15c0f9c13ab75:pipeline:65e6d5551e47e5bc243ca93f:scm_repo_url:https://github.com/test-codefresh/fulcio:scm_user_name:test-codefresh:scm_ref:feat/codefresh-issuer:scm_pull_request_target_branch:main" { t.Fatalf("got unexpected name %s", principal.Name(ctx)) } }) } fulcio-1.6.5/pkg/identity/codefresh/principal.go000066400000000000000000000141361470150653400217020ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 codefresh import ( "context" "crypto/x509" "errors" "fmt" "net/url" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/identity" ) const ( DefaultPlatformURL string = "https://g.codefresh.io" ) type workflowPrincipal struct { // Subject matches the 'sub' claim from the OIDC ID token this is what is signed as proof of possession for Codefresh workflow identities subject string // OIDC Issuer URL. Matches 'iss' claim from ID token. The real issuer URL is // https://oidc.codefresh.io/.well-known/openid-configuration issuer string // Codefresh account id accountID string // Codefresh account name accountName string // Codefresh Pipeline id pipelineID string // Codefresh pipline name (project/pipeline) pipelineName string // The ID of the specific workflow authorized in the claim. For example, 64f447c02199f903000gh20. workflowID string // Applies to manual trigger types, and is the username of the user manually triggered the pipeline initiator string // Applies to Git push, PR, and manual Git trigger types. The SCM name of the user who initiated the Git action. scmUsername string // Applies to Git push, PR, and manual Git trigger types. The SCM URL specifying the Git repository’s location. For example, https://github.com/codefresh-user/oidc-test scmRepoURL string // Applies to Git push, PR, and manual Git trigger types. The SCM name of the branch or tag within the Git repository for which the workflow should execute. For example, main or v1.0.0. scmRef string // Applies to Git PR trigger types. The SCM target branch the pull request should merge into. For example, production scmPullRequestTargetBranch string // Whether the build took place in cloud or self-hosted infrastructure runnerEnvironment string // Codefresh platform url platformURL string } func (w workflowPrincipal) Name(_ context.Context) string { return w.subject } func WorkflowPrincipalFromIDToken(_ context.Context, token *oidc.IDToken) (identity.Principal, error) { var claims struct { AccountID string `json:"account_id"` AccountName string `json:"account_name"` PipelineID string `json:"pipeline_id"` PipelineName string `json:"pipeline_name"` WorkflowID string `json:"workflow_id"` Initiator string `json:"initiator"` SCMRepoURL string `json:"scm_repo_url"` SCMUsername string `json:"scm_user_name"` SCMRef string `json:"scm_ref"` SCMPullRequestRef string `json:"scm_pull_request_target_branch"` RunnerEnvironment string `json:"runner_environment"` PlatformURL string `json:"platform_url"` } if err := token.Claims(&claims); err != nil { return nil, err } if claims.AccountID == "" { return nil, errors.New("missing account_id in token") } if claims.PipelineID == "" { return nil, errors.New("missing pipeline_id in token") } if claims.WorkflowID == "" { return nil, errors.New("missing workflow_id in token") } // Set default platform url in case it is missing in the token if claims.PlatformURL == "" { claims.PlatformURL = DefaultPlatformURL } return &workflowPrincipal{ subject: token.Subject, issuer: token.Issuer, accountID: claims.AccountID, accountName: claims.AccountName, pipelineID: claims.PipelineID, pipelineName: claims.PipelineName, workflowID: claims.WorkflowID, initiator: claims.Initiator, scmUsername: claims.SCMUsername, scmRepoURL: claims.SCMRepoURL, scmRef: claims.SCMRef, scmPullRequestTargetBranch: claims.SCMPullRequestRef, runnerEnvironment: claims.RunnerEnvironment, platformURL: claims.PlatformURL, }, nil } func (w workflowPrincipal) Embed(_ context.Context, cert *x509.Certificate) error { baseURL, err := url.Parse(w.platformURL) if err != nil { return err } // Set SAN to the //:/ - for example https://g.codefresh.io/codefresh-account/oidc-test/get-token:628a80b693a15c0f9c13ab75/65e5a53e52853dc51a5b0cc1 // In Codefresh account names and pipeline names may be changed where as IDs do not. // This pattern will give users the possibility to verify the signature using various forms of `cosign verify --certificate-identity-regexp` i.e https://g.codefresh.io/codefresh-account/oidc-test/get-token:* or https://g.codefresh.io/*:628a80b693a15c0f9c13ab75/65e5a53e52853dc51a5b0cc1 cert.URIs = []*url.URL{baseURL.JoinPath(w.accountName, fmt.Sprintf("%s:%s/%s", w.pipelineName, w.accountID, w.pipelineID))} cert.ExtraExtensions, err = certificate.Extensions{ Issuer: w.issuer, // URL of the build in Codefresh. // The workflow url is used for build signer in Codefresh because for public builds unauthenticated users only have access to the workflow, not the pipeline definition. // Also, the workflow contains the definition of the pipeline that was used at the time of the build, making it ideal to be used as the signer url. BuildSignerURI: baseURL.JoinPath("build", w.workflowID).String(), RunnerEnvironment: w.runnerEnvironment, SourceRepositoryURI: w.scmRepoURL, SourceRepositoryRef: w.scmRef, BuildConfigURI: baseURL.JoinPath("api", "pipelines", w.pipelineID).String(), RunInvocationURI: baseURL.JoinPath("build", w.workflowID).String(), }.Render() if err != nil { return err } return nil } fulcio-1.6.5/pkg/identity/codefresh/principal_test.go000066400000000000000000000322511470150653400227370ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 codefresh import ( "context" "crypto/x509" "encoding/asn1" "encoding/json" "errors" "fmt" "net/url" "reflect" "strings" "testing" "unsafe" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/identity" ) func TestJobPrincipalFromIDToken(t *testing.T) { tests := map[string]struct { Claims map[string]interface{} ExpectPrincipal workflowPrincipal WantErr bool ErrContains string }{ `Valid token - Manual trigger authenticates with correct claims`: { Claims: map[string]interface{}{ "sub": "account:628a80b693a15c0f9c13ab75:pipeline:65e5a53e52853dc51a5b0cc1:initiator:codefresh-user", "account_id": "628a80b693a15c0f9c13ab75", "account_name": "codefresh-account", "pipeline_id": "65e5a53e52853dc51a5b0cc1", "pipeline_name": "oidc-test/get-token", "workflow_id": "65e5c23d706f166c4e8985ed", "initiator": "codefresh-user", "runner_environment": "hybrid", "aud": "sigstore", "exp": 1709556619, "iat": 1709556319, "iss": "https://oidc.codefresh.io", "platform_url": "https://pre-prod.codefresh.io", }, ExpectPrincipal: workflowPrincipal{ issuer: "https://oidc.codefresh.io", subject: "account:628a80b693a15c0f9c13ab75:pipeline:65e5a53e52853dc51a5b0cc1:initiator:codefresh-user", accountID: "628a80b693a15c0f9c13ab75", accountName: "codefresh-account", pipelineID: "65e5a53e52853dc51a5b0cc1", pipelineName: "oidc-test/get-token", workflowID: "65e5c23d706f166c4e8985ed", initiator: "codefresh-user", platformURL: "https://pre-prod.codefresh.io", runnerEnvironment: "hybrid", }, WantErr: false, }, `Valid token - Git push trigger authenticates with correct claims`: { Claims: map[string]interface{}{ "sub": "account:628a80b693a15c0f9c13ab75:pipeline:65e5a53e52853dc51a5b0cc1:initiator:codefresh-user:scm_repo_url:https://github.com/codefresh-user/fulcio:scm_user_name:git-user-name:scm_ref:main", "account_id": "628a80b693a15c0f9c13ab75", "account_name": "codefresh-account", "pipeline_id": "65e5a53e52853dc51a5b0cc1", "pipeline_name": "oidc-test/get-token", "workflow_id": "65e6bcf7c2af1f228fa97f80", "initiator": "codefresh-user", "scm_user_name": "git-user-name", "scm_repo_url": "https://github.com/codefresh-io/fulcio-oidc", "scm_ref": "main", "runner_environment": "hybrid", "aud": "sigstore", "exp": 1709620814, "iat": 1709620514, "iss": "https://oidc.codefresh.io", }, ExpectPrincipal: workflowPrincipal{ issuer: "https://oidc.codefresh.io", subject: "account:628a80b693a15c0f9c13ab75:pipeline:65e5a53e52853dc51a5b0cc1:initiator:codefresh-user:scm_repo_url:https://github.com/codefresh-user/fulcio:scm_user_name:git-user-name:scm_ref:main", accountID: "628a80b693a15c0f9c13ab75", accountName: "codefresh-account", pipelineID: "65e5a53e52853dc51a5b0cc1", pipelineName: "oidc-test/get-token", workflowID: "65e6bcf7c2af1f228fa97f80", initiator: "codefresh-user", scmUsername: "git-user-name", scmRepoURL: "https://github.com/codefresh-io/fulcio-oidc", scmRef: "main", platformURL: "https://g.codefresh.io", runnerEnvironment: "hybrid", }, WantErr: false, }, `Valid token - Git pull request trigger authenticates with correct claims`: { Claims: map[string]interface{}{ "sub": "account:628a80b693a15c0f9c13ab75:pipeline:65e6d5551e47e5bc243ca93f:scm_repo_url:https://github.com/test-codefresh/fulcio:scm_user_name:test-codefresh:scm_ref:feat/codefresh-issuer:scm_pull_request_target_branch:main", "account_id": "628a80b693a15c0f9c13ab75", "account_name": "test-codefresh", "pipeline_id": "65e6d5551e47e5bc243ca93f", "pipeline_name": "oidc-test/oidc-test-2", "workflow_id": "65e6ebe0bfbfa1782876165e", "scm_user_name": "test-codefresh", "scm_repo_url": "https://github.com/test-codefresh/fulcio", "scm_ref": "feat/codefresh-issuer", "scm_pull_request_target_branch": "main", "runner_environment": "hybrid", "aud": "sigstore", "exp": 1709633177, "iat": 1709632877, "iss": "https://oidc.codefresh.io", }, ExpectPrincipal: workflowPrincipal{ issuer: "https://oidc.codefresh.io", subject: "account:628a80b693a15c0f9c13ab75:pipeline:65e6d5551e47e5bc243ca93f:scm_repo_url:https://github.com/test-codefresh/fulcio:scm_user_name:test-codefresh:scm_ref:feat/codefresh-issuer:scm_pull_request_target_branch:main", accountID: "628a80b693a15c0f9c13ab75", accountName: "test-codefresh", pipelineID: "65e6d5551e47e5bc243ca93f", pipelineName: "oidc-test/oidc-test-2", workflowID: "65e6ebe0bfbfa1782876165e", scmUsername: "test-codefresh", scmRepoURL: "https://github.com/test-codefresh/fulcio", scmRef: "feat/codefresh-issuer", scmPullRequestTargetBranch: "main", platformURL: "https://g.codefresh.io", runnerEnvironment: "hybrid", }, WantErr: false, }, `Token missing workflow_id claim should be rejected`: { Claims: map[string]interface{}{ "sub": "account:628a80b693a15c0f9c13ab75:pipeline:65e5a53e52853dc51a5b0cc1:initiator:codefresh-user", "account_id": "628a80b693a15c0f9c13ab75", "account_name": "codefresh-oidc", "pipeline_id": "65e5a53e52853dc51a5b0cc1", "pipeline_name": "oidc-test/get-token", "initiator": "codefresh-user", "aud": "sigstore", "exp": 1709556619, "iat": 1709556319, "iss": "https://oidc.codefresh.io", }, WantErr: true, ErrContains: "workflow_id", }, `Token missing account_id claim should be rejected`: { Claims: map[string]interface{}{ "sub": "account:628a80b693a15c0f9c13ab75:pipeline:65e5a53e52853dc51a5b0cc1:initiator:codefresh-user", "account_name": "codefresh-oidc", "pipeline_id": "65e5a53e52853dc51a5b0cc1", "pipeline_name": "oidc-test/get-token", "initiator": "codefresh-user", "aud": "sigstore", "exp": 1709556619, "iat": 1709556319, "iss": "https://oidc.codefresh.io", }, WantErr: true, ErrContains: "account_id", }, `Token missing pipeline_id claim should be rejected`: { Claims: map[string]interface{}{ "sub": "account:628a80b693a15c0f9c13ab75:pipeline:65e5a53e52853dc51a5b0cc1:initiator:codefresh-user", "account_name": "codefresh-oidc", "account_id": "628a80b693a15c0f9c13ab75", "pipeline_name": "oidc-test/get-token", "workflow_id": "65e6bcf7c2af1f228fa97f80", "initiator": "codefresh-user", "aud": "sigstore", "exp": 1709556619, "iat": 1709556319, "iss": "https://oidc.codefresh.io", }, WantErr: true, ErrContains: "pipeline_id", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) untyped, err := WorkflowPrincipalFromIDToken(context.TODO(), token) if err != nil { if !test.WantErr { t.Fatal("didn't expect error", err) } if !strings.Contains(err.Error(), test.ErrContains) { t.Fatalf("expected error %s to contain %s", err, test.ErrContains) } return } if err == nil && test.WantErr { t.Fatal("expected error but got none") } principal, ok := untyped.(*workflowPrincipal) if !ok { t.Errorf("Got wrong principal type %v", untyped) } if *principal != test.ExpectPrincipal { t.Errorf("got %v principal and expected %v", *principal, test.ExpectPrincipal) } }) } } // reflect hack because "claims" field is unexported by oidc IDToken // https://github.com/coreos/go-oidc/pull/329 func withClaims(token *oidc.IDToken, data []byte) { val := reflect.Indirect(reflect.ValueOf(token)) member := val.FieldByName("claims") pointer := unsafe.Pointer(member.UnsafeAddr()) realPointer := (*[]byte)(pointer) *realPointer = data } func TestEmbed(t *testing.T) { tests := map[string]struct { Principal identity.Principal WantErr bool WantFacts map[string]func(x509.Certificate) error }{ `Github workflow challenge should have all Github workflow extensions and issuer set`: { Principal: &workflowPrincipal{ issuer: "https://oidc.codefresh.io", subject: "account:628a80b693a15c0f9c13ab75:pipeline:65e5a53e52853dc51a5b0cc1:initiator:codefresh-user:scm_repo_url:https://github.com/codefresh-user/fulcio:scm_user_name:git-user-name:scm_ref:main", accountID: "628a80b693a15c0f9c13ab75", accountName: "codefresh-account", pipelineID: "65e5a53e52853dc51a5b0cc1", pipelineName: "oidc-test/get-token", workflowID: "65e6bcf7c2af1f228fa97f80", initiator: "codefresh-user", scmUsername: "git-user-name", scmRepoURL: "https://github.com/codefresh-io/fulcio-oidc", scmRef: "main", platformURL: "https://g.codefresh.io", runnerEnvironment: "hybrid", }, WantErr: false, WantFacts: map[string]func(x509.Certificate) error{ `Certificate SAN has correct value`: factSanURIIs("https://g.codefresh.io/codefresh-account/oidc-test/get-token:628a80b693a15c0f9c13ab75/65e5a53e52853dc51a5b0cc1"), `Certificate has correct issuer (v2) extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 8}, "https://oidc.codefresh.io"), `Certificate has correct builder signer URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 9}, "https://g.codefresh.io/build/65e6bcf7c2af1f228fa97f80"), `Certificate has correct runner environment extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 11}, "hybrid"), `Certificate has correct source repo URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 12}, "https://github.com/codefresh-io/fulcio-oidc"), `Certificate has correct source repo ref extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 14}, "main"), `Certificate has correct build config URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 18}, "https://g.codefresh.io/api/pipelines/65e5a53e52853dc51a5b0cc1"), `Certificate has correct run invocation URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 21}, "https://g.codefresh.io/build/65e6bcf7c2af1f228fa97f80"), }, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { var cert x509.Certificate err := test.Principal.Embed(context.TODO(), &cert) if err != nil { if !test.WantErr { t.Error(err) } return } else if test.WantErr { t.Error("expected error") } for factName, fact := range test.WantFacts { t.Run(factName, func(t *testing.T) { if err := fact(cert); err != nil { t.Error(err) } }) } }) } } func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { var strVal string _, _ = asn1.Unmarshal(ext.Value, &strVal) if value != strVal { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, strVal) } return nil } } return errors.New("extension not set") } } func factSanURIIs(value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { url, err := url.Parse(value) if err != nil { return err } if cert.URIs[0].String() != url.String() { return fmt.Errorf("expected SAN o be %s, but got %s", value, cert.URIs[0].String()) } return nil } } fulcio-1.6.5/pkg/identity/email/000077500000000000000000000000001470150653400165125ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/email/issuer.go000066400000000000000000000022511470150653400203530ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 email import ( "context" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/base" ) type emailIssuer struct { identity.Issuer } func Issuer(issuerURL string) identity.Issuer { return &emailIssuer{base.Issuer(issuerURL)} } func (e *emailIssuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { idtoken, err := identity.Authorize(ctx, token, opts...) if err != nil { return nil, err } return PrincipalFromIDToken(ctx, idtoken) } fulcio-1.6.5/pkg/identity/email/issuer_test.go000066400000000000000000000043401470150653400214130ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 email import ( "context" "encoding/json" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) func TestIssuer(t *testing.T) { ctx := context.Background() url := "test-issuer-url" issuer := Issuer(url) // test the Match function t.Run("match", func(t *testing.T) { if matches := issuer.Match(ctx, url); !matches { t.Fatal("expected url to match but it doesn't") } if matches := issuer.Match(ctx, "some-other-url"); matches { t.Fatal("expected match to fail but it didn't") } }) t.Run("authenticate", func(t *testing.T) { token := &oidc.IDToken{ Issuer: "https://iss.example.com", Subject: "subject", } claims, err := json.Marshal(map[string]interface{}{ "aud": "sigstore", "iss": "https://iss.example.com", "sub": "doesntmatter", "email": "alice@example.com", "email_verified": true, }) if err != nil { t.Fatal(err) } withClaims(token, claims) ctx := config.With(context.Background(), &config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://iss.example.com": { IssuerURL: "https://iss.example.com", Type: config.IssuerTypeEmail, ClientID: "sigstore", }, }, }) identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { return token, nil } principal, err := issuer.Authenticate(ctx, "token") if err != nil { t.Fatal(err) } if principal.Name(ctx) != "alice@example.com" { t.Fatalf("got unexpected name %s", principal.Name(ctx)) } }) } fulcio-1.6.5/pkg/identity/email/principal.go000066400000000000000000000037671470150653400210370ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 email import ( "context" "crypto/x509" "errors" "fmt" "github.com/asaskevich/govalidator" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/oauthflow" ) type principal struct { address string issuer string } func PrincipalFromIDToken(ctx context.Context, token *oidc.IDToken) (identity.Principal, error) { emailAddress, emailVerified, err := oauthflow.EmailFromIDToken(token) if err != nil { return nil, err } if !emailVerified { return nil, errors.New("email_verified claim was false") } if !govalidator.IsEmail(emailAddress) { return nil, fmt.Errorf("email address is not valid") } cfg, ok := config.FromContext(ctx).GetIssuer(token.Issuer) if !ok { return nil, errors.New("invalid configuration for OIDC ID Token issuer") } issuer, err := oauthflow.IssuerFromIDToken(token, cfg.IssuerClaim) if err != nil { return nil, err } return principal{ issuer: issuer, address: emailAddress, }, nil } func (p principal) Name(_ context.Context) string { return p.address } func (p principal) Embed(_ context.Context, cert *x509.Certificate) error { cert.EmailAddresses = []string{p.address} var err error cert.ExtraExtensions, err = certificate.Extensions{ Issuer: p.issuer, }.Render() if err != nil { return err } return nil } fulcio-1.6.5/pkg/identity/email/principal_test.go000066400000000000000000000242341470150653400220660ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 email import ( "bytes" "context" "crypto/x509" "encoding/asn1" "encoding/json" "errors" "fmt" "reflect" "testing" "unsafe" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" ) func TestPrincipalFromIDToken(t *testing.T) { tests := map[string]struct { Claims map[string]interface{} Config config.FulcioConfig ExpectedPrincipal principal WantErr bool }{ `Well formed token has no errors`: { Claims: map[string]interface{}{ "aud": "sigstore", "iss": "https://iss.example.com", "sub": "doesntmatter", "email": "alice@example.com", "email_verified": true, }, Config: config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://iss.example.com": { IssuerURL: "https://iss.example.com", Type: config.IssuerTypeEmail, ClientID: "sigstore", }, }, }, ExpectedPrincipal: principal{ issuer: "https://iss.example.com", address: "alice@example.com", }, WantErr: false, }, `Custom issuer claim`: { Claims: map[string]interface{}{ "aud": "sigstore", "iss": "https://dex.other.com", "sub": "doesntmatter", "email": "alice@example.com", "email_verified": true, "federated": map[string]string{ "issuer": "https://example.com", }, }, Config: config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://dex.other.com": { IssuerURL: "https://dex.other.com", IssuerClaim: "$.federated.issuer", Type: config.IssuerTypeEmail, ClientID: "sigstore", }, }, }, ExpectedPrincipal: principal{ issuer: "https://example.com", address: "alice@example.com", }, WantErr: false, }, `String email verified value`: { Claims: map[string]interface{}{ "aud": "sigstore", "iss": "https://dex.other.com", "sub": "doesntmatter", "email": "alice@example.com", "email_verified": "true", "federated": map[string]string{ "issuer": "https://example.com", }, }, Config: config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://dex.other.com": { IssuerURL: "https://dex.other.com", IssuerClaim: "$.federated.issuer", Type: config.IssuerTypeEmail, ClientID: "sigstore", }, }, }, ExpectedPrincipal: principal{ issuer: "https://example.com", address: "alice@example.com", }, WantErr: false, }, `Custom issuer claim missing`: { Claims: map[string]interface{}{ "aud": "sigstore", "iss": "https://dex.other.com", "sub": "doesntmatter", "email": "alice@example.com", "email_verified": true, }, Config: config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://dex.other.com": { IssuerURL: "https://dex.other.com", IssuerClaim: "$.federated.issuer", Type: config.IssuerTypeEmail, ClientID: "sigstore", }, }, }, WantErr: true, }, `Email not verified should error`: { Claims: map[string]interface{}{ "aud": "sigstore", "iss": "https://iss.example.com", "sub": "doesntmatter", "email": "alice@example.com", "email_verified": false, }, Config: config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://iss.example.com": { IssuerURL: "https://iss.example.com", Type: config.IssuerTypeEmail, ClientID: "sigstore", }, }, }, WantErr: true, }, `Missing email claim should error`: { Claims: map[string]interface{}{ "aud": "sigstore", "iss": "https://iss.example.com", "sub": "doesntmatter", "email_verified": true, }, Config: config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://iss.example.com": { IssuerURL: "https://iss.example.com", Type: config.IssuerTypeEmail, ClientID: "sigstore", }, }, }, WantErr: true, }, `Invalid email address should error`: { Claims: map[string]interface{}{ "aud": "sigstore", "iss": "https://iss.example.com", "sub": "doesntmatter", "email": "foo.com", "email_verified": true, }, Config: config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://iss.example.com": { IssuerURL: "https://iss.example.com", Type: config.IssuerTypeEmail, ClientID: "sigstore", }, }, }, WantErr: true, }, `No issuer configured for token`: { Claims: map[string]interface{}{ "aud": "sigstore", "iss": "https://nope.example.com", "sub": "doesntmatter", "email": "alice@example.com", "email_verified": true, }, Config: config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://iss.example.com": { IssuerURL: "https://iss.example.com", Type: config.IssuerTypeEmail, ClientID: "sigstore", }, }, }, WantErr: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) ctx := config.With(context.Background(), &test.Config) untyped, err := PrincipalFromIDToken(ctx, token) if err != nil { if !test.WantErr { t.Fatal("didn't expect error", err) } return } if err == nil && test.WantErr { t.Fatal("expected error but got none") } gotPrincipal, ok := untyped.(principal) if !ok { t.Errorf("Got wrong principal type %v", untyped) } if gotPrincipal != test.ExpectedPrincipal { t.Errorf("got %v principal and expected %v", gotPrincipal, test.ExpectedPrincipal) } }) } } // reflect hack because "claims" field is unexported by oidc IDToken // https://github.com/coreos/go-oidc/pull/329 func withClaims(token *oidc.IDToken, data []byte) { val := reflect.Indirect(reflect.ValueOf(token)) member := val.FieldByName("claims") pointer := unsafe.Pointer(member.UnsafeAddr()) realPointer := (*[]byte)(pointer) *realPointer = data } func TestName(t *testing.T) { tests := map[string]struct { Claims map[string]interface{} Config config.FulcioConfig ExpectedName string }{ `name should match email address`: { Claims: map[string]interface{}{ "aud": "sigstore", "iss": "https://iss.example.com", "sub": "doesntmatter", "email": "alice@example.com", "email_verified": true, }, Config: config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://iss.example.com": { IssuerURL: "https://iss.example.com", Type: config.IssuerTypeEmail, ClientID: "sigstore", }, }, }, ExpectedName: "alice@example.com", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) ctx := config.With(context.Background(), &test.Config) got, err := PrincipalFromIDToken(ctx, token) if err != nil { t.Fatal("didn't expect error", err) } if test.ExpectedName != got.Name(ctx) { t.Errorf("got %s name but expected %s", got.Name(ctx), test.ExpectedName) } }) } } func TestEmbed(t *testing.T) { tests := map[string]struct { Principal principal WantErr bool WantFacts map[string]func(x509.Certificate) error }{ `should set issuer extension and email subject`: { Principal: principal{ issuer: `https://iss.example.com`, address: `alice@example.com`, }, WantErr: false, WantFacts: map[string]func(x509.Certificate) error{ `Certificate should have alice@example.com email subject`: func(cert x509.Certificate) error { if len(cert.EmailAddresses) != 1 { return errors.New("no email SAN set for email challenge") } if cert.EmailAddresses[0] != `alice@example.com` { return errors.New("bad email. expected alice@example.com") } return nil }, `Certificate should have issuer extension set`: factIssuerIs("https://iss.example.com"), }, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { var cert x509.Certificate err := test.Principal.Embed(context.TODO(), &cert) if err != nil { if !test.WantErr { t.Error(err) } return } else if test.WantErr { t.Error("expected error") } for factName, fact := range test.WantFacts { t.Run(factName, func(t *testing.T) { if err := fact(cert); err != nil { t.Error(err) } }) } }) } } func factIssuerIs(issuer string) func(x509.Certificate) error { return factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, issuer) } func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { if !bytes.Equal(ext.Value, []byte(value)) { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, ext.Value) } return nil } } return errors.New("extension not set") } } fulcio-1.6.5/pkg/identity/github/000077500000000000000000000000001470150653400167055ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/github/issuer.go000066400000000000000000000023511470150653400205470ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 github import ( "context" "fmt" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/base" ) type githubIssuer struct { identity.Issuer } func Issuer(issuerURL string) identity.Issuer { return &githubIssuer{base.Issuer(issuerURL)} } func (e *githubIssuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { idtoken, err := identity.Authorize(ctx, token, opts...) if err != nil { return nil, fmt.Errorf("authorizing github issuer: %w", err) } return WorkflowPrincipalFromIDToken(ctx, idtoken) } fulcio-1.6.5/pkg/identity/github/issuer_test.go000066400000000000000000000054471470150653400216170ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 github import ( "context" "encoding/json" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) func TestIssuer(t *testing.T) { ctx := context.Background() url := "test-issuer-url" issuer := Issuer(url) // test the Match function t.Run("match", func(t *testing.T) { if matches := issuer.Match(ctx, url); !matches { t.Fatal("expected url to match but it doesn't") } if matches := issuer.Match(ctx, "some-other-url"); matches { t.Fatal("expected match to fail but it didn't") } }) t.Run("authenticate", func(t *testing.T) { token := &oidc.IDToken{ Issuer: "https://iss.example.com", Subject: "repo:sigstore/fulcio:ref:refs/heads/main", } claims, err := json.Marshal(map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }) if err != nil { t.Fatal(err) } withClaims(token, claims) identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { return token, nil } principal, err := issuer.Authenticate(ctx, "token") if err != nil { t.Fatal(err) } if principal.Name(ctx) != "repo:sigstore/fulcio:ref:refs/heads/main" { t.Fatalf("got unexpected name %s", principal.Name(ctx)) } }) } fulcio-1.6.5/pkg/identity/github/principal.go000066400000000000000000000164531470150653400212260ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 github import ( "context" "crypto/x509" "errors" "net/url" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/identity" ) type workflowPrincipal struct { // Subject matches the 'sub' claim from the OIDC ID token this is what is // signed as proof of possession for Github workflow identities subject string // OIDC Issuer URL. Matches 'iss' claim from ID token. The real issuer URL is // https://token.actions.githubusercontent.com/.well-known/openid-configution issuer string // URL of issuer url string // Commit SHA being built sha string // Event that triggered this workflow run. E.g "push", "tag" eventName string // Name of repository being built repository string // Deprecated // Name of workflow that is running (mutable) workflow string // Git ref being built ref string // Specific build instructions (i.e. reusable workflow) jobWorkflowRef string // Commit SHA to specific build instructions jobWorkflowSha string // Whether the build took place in cloud or self-hosted infrastructure runnerEnvironment string // ID to the source repo repositoryID string // Owner of the source repo (mutable) repositoryOwner string // ID of the source repo repositoryOwnerID string // Visibility of the source repo repositoryVisibility string // Ref of top-level workflow that is running workflowRef string // Commit SHA of top-level workflow that is running workflowSha string // ID of workflow run runID string // Attempt number of workflow run runAttempt string } func WorkflowPrincipalFromIDToken(_ context.Context, token *oidc.IDToken) (identity.Principal, error) { var claims struct { JobWorkflowRef string `json:"job_workflow_ref"` Sha string `json:"sha"` EventName string `json:"event_name"` Repository string `json:"repository"` Workflow string `json:"workflow"` Ref string `json:"ref"` JobWorkflowSha string `json:"job_workflow_sha"` RunnerEnvironment string `json:"runner_environment"` RepositoryID string `json:"repository_id"` RepositoryOwner string `json:"repository_owner"` RepositoryOwnerID string `json:"repository_owner_id"` RepositoryVisibility string `json:"repository_visibility"` WorkflowRef string `json:"workflow_ref"` WorkflowSha string `json:"workflow_sha"` RunID string `json:"run_id"` RunAttempt string `json:"run_attempt"` } if err := token.Claims(&claims); err != nil { return nil, err } if claims.JobWorkflowRef == "" { return nil, errors.New("missing job_workflow_ref claim in ID token") } if claims.Sha == "" { return nil, errors.New("missing sha claim in ID token") } if claims.EventName == "" { return nil, errors.New("missing event_name claim in ID token") } if claims.Repository == "" { return nil, errors.New("missing repository claim in ID token") } if claims.Workflow == "" { return nil, errors.New("missing workflow claim in ID token") } if claims.Ref == "" { return nil, errors.New("missing ref claim in ID token") } if claims.JobWorkflowSha == "" { return nil, errors.New("missing job_workflow_sha claim in ID token") } if claims.RunnerEnvironment == "" { return nil, errors.New("missing runner_environment claim in ID token") } if claims.RepositoryID == "" { return nil, errors.New("missing repository_id claim in ID token") } if claims.RepositoryOwner == "" { return nil, errors.New("missing repository_owner claim in ID token") } if claims.RepositoryOwnerID == "" { return nil, errors.New("missing repository_owner_id claim in ID token") } if claims.RepositoryVisibility == "" { return nil, errors.New("missing repository_visibility claim in ID token") } if claims.WorkflowRef == "" { return nil, errors.New("missing workflow_ref claim in ID token") } if claims.WorkflowSha == "" { return nil, errors.New("missing workflow_sha claim in ID token") } if claims.RunID == "" { return nil, errors.New("missing run_id claim in ID token") } if claims.RunAttempt == "" { return nil, errors.New("missing run_attempt claim in ID token") } return &workflowPrincipal{ subject: token.Subject, issuer: token.Issuer, url: `https://github.com/`, sha: claims.Sha, eventName: claims.EventName, repository: claims.Repository, workflow: claims.Workflow, ref: claims.Ref, jobWorkflowRef: claims.JobWorkflowRef, jobWorkflowSha: claims.JobWorkflowSha, runnerEnvironment: claims.RunnerEnvironment, repositoryID: claims.RepositoryID, repositoryOwner: claims.RepositoryOwner, repositoryOwnerID: claims.RepositoryOwnerID, repositoryVisibility: claims.RepositoryVisibility, workflowRef: claims.WorkflowRef, workflowSha: claims.WorkflowSha, runID: claims.RunID, runAttempt: claims.RunAttempt, }, nil } func (w workflowPrincipal) Name(_ context.Context) string { return w.subject } func (w workflowPrincipal) Embed(_ context.Context, cert *x509.Certificate) error { baseURL, err := url.Parse(w.url) if err != nil { return err } // Set workflow ref URL to SubjectAlternativeName on certificate cert.URIs = []*url.URL{baseURL.JoinPath(w.jobWorkflowRef)} // Embed additional information into custom extensions cert.ExtraExtensions, err = certificate.Extensions{ Issuer: w.issuer, // BEGIN: Deprecated GithubWorkflowTrigger: w.eventName, GithubWorkflowSHA: w.sha, GithubWorkflowName: w.workflow, GithubWorkflowRepository: w.repository, GithubWorkflowRef: w.ref, // END: Deprecated BuildSignerURI: baseURL.JoinPath(w.jobWorkflowRef).String(), BuildSignerDigest: w.jobWorkflowSha, RunnerEnvironment: w.runnerEnvironment, SourceRepositoryURI: baseURL.JoinPath(w.repository).String(), SourceRepositoryDigest: w.sha, SourceRepositoryRef: w.ref, SourceRepositoryIdentifier: w.repositoryID, SourceRepositoryOwnerURI: baseURL.JoinPath(w.repositoryOwner).String(), SourceRepositoryOwnerIdentifier: w.repositoryOwnerID, BuildConfigURI: baseURL.JoinPath(w.workflowRef).String(), BuildConfigDigest: w.workflowSha, BuildTrigger: w.eventName, RunInvocationURI: baseURL.JoinPath(w.repository, "actions/runs", w.runID, "attempts", w.runAttempt).String(), SourceRepositoryVisibilityAtSigning: w.repositoryVisibility, }.Render() if err != nil { return err } return nil } fulcio-1.6.5/pkg/identity/github/principal_test.go000066400000000000000000000733521470150653400222660ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 github import ( "bytes" "context" "crypto/x509" "encoding/asn1" "encoding/json" "errors" "fmt" "reflect" "strings" "testing" "unsafe" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/identity" ) func TestWorkflowPrincipalFromIDToken(t *testing.T) { tests := map[string]struct { Claims map[string]interface{} ExpectPrincipal workflowPrincipal WantErr bool ErrContains string }{ `Valid token authenticates with correct claims`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, ExpectPrincipal: workflowPrincipal{ issuer: "https://token.actions.githubusercontent.com", subject: "repo:sigstore/fulcio:ref:refs/heads/main", url: "https://github.com/", jobWorkflowRef: "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", sha: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", eventName: "push", repository: "sigstore/fulcio", workflow: "foo", ref: "refs/heads/main", jobWorkflowSha: "example-sha", runnerEnvironment: "cloud-hosted", repositoryID: "12345", repositoryOwner: "username", repositoryOwnerID: "345", repositoryVisibility: "public", workflowRef: "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", workflowSha: "example-sha-other", runID: "42", runAttempt: "1", }, WantErr: false, }, `Token missing job_workflow_ref claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "job_workflow_ref", }, `Token missing sha should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "sha", }, `Token missing event_name claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "event_name", }, `Token missing repository claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "repository", }, `Token missing workflow claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "workflow", }, `Token missing ref claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "ref", }, `Token missing job_workflow_sha claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "job_workflow_sha", }, `Token missing runner_environment claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "runner_environment", }, `Token missing repository_id claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "repository_id", }, `Token missing repository_owner claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "repository_owner", }, `Token missing repository_owner_id claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "repository_owner_id", }, `Token missing workflow_ref claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "workflow_ref", }, `Token missing workflow_sha claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", }, WantErr: true, ErrContains: "workflow_sha", }, `Token missing run_id claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "run_id", }, `Token missing run_attempt claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "run_attempt", }, `Token missing repository_visibility claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, WantErr: true, ErrContains: "repository_visibility", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) untyped, err := WorkflowPrincipalFromIDToken(context.TODO(), token) if err != nil { if !test.WantErr { t.Fatal("didn't expect error", err) } if !strings.Contains(err.Error(), test.ErrContains) { t.Fatalf("expected error %s to contain %s", err, test.ErrContains) } return } if err == nil && test.WantErr { t.Fatal("expected error but got none") } principal, ok := untyped.(*workflowPrincipal) if !ok { t.Errorf("Got wrong principal type %v", untyped) } if *principal != test.ExpectPrincipal { t.Errorf("got %v principal and expected %v", *principal, test.ExpectPrincipal) } }) } } // reflect hack because "claims" field is unexported by oidc IDToken // https://github.com/coreos/go-oidc/pull/329 func withClaims(token *oidc.IDToken, data []byte) { val := reflect.Indirect(reflect.ValueOf(token)) member := val.FieldByName("claims") pointer := unsafe.Pointer(member.UnsafeAddr()) realPointer := (*[]byte)(pointer) *realPointer = data } func TestName(t *testing.T) { tests := map[string]struct { Claims map[string]interface{} ExpectName string }{ `Valid token authenticates with correct claims`: { Claims: map[string]interface{}{ "aud": "sigstore", "event_name": "push", "exp": 0, "iss": "https://token.actions.githubusercontent.com", "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", "job_workflow_sha": "example-sha", "ref": "refs/heads/main", "repository": "sigstore/fulcio", "repository_id": "12345", "repository_owner": "username", "repository_owner_id": "345", "repository_visibility": "public", "run_attempt": "1", "run_id": "42", "runner_environment": "cloud-hosted", "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "sub": "repo:sigstore/fulcio:ref:refs/heads/main", "workflow": "foo", "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", "workflow_sha": "example-sha-other", }, ExpectName: "repo:sigstore/fulcio:ref:refs/heads/main", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) principal, err := WorkflowPrincipalFromIDToken(context.TODO(), token) if err != nil { t.Fatal(err) } gotName := principal.Name(context.TODO()) if gotName != test.ExpectName { t.Error("name should match sub claim") } }) } } func TestEmbed(t *testing.T) { tests := map[string]struct { Principal identity.Principal WantErr bool WantFacts map[string]func(x509.Certificate) error }{ `Github workflow challenge should have all Github workflow extensions and issuer set`: { Principal: &workflowPrincipal{ issuer: "https://token.actions.githubusercontent.com", subject: "doesntmatter", url: `https://github.com/`, sha: "sha", eventName: "trigger", workflow: "workflowname", repository: "repository", ref: "ref", jobWorkflowRef: "jobWorkflowRef", jobWorkflowSha: "jobWorkflowSha", runnerEnvironment: "runnerEnv", repositoryID: "repoID", repositoryOwner: "repoOwner", repositoryOwnerID: "repoOwnerID", repositoryVisibility: "public", workflowRef: "workflowRef", workflowSha: "workflowSHA", runID: "runID", runAttempt: "runAttempt", }, WantErr: false, WantFacts: map[string]func(x509.Certificate) error{ `Certifificate should have correct issuer`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, "https://token.actions.githubusercontent.com"), `Certificate has correct trigger extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 2}, "trigger"), `Certificate has correct SHA extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 3}, "sha"), `Certificate has correct workflow extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 4}, "workflowname"), `Certificate has correct repository extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 5}, "repository"), `Certificate has correct ref extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 6}, "ref"), `Certificate has correct issuer (v2) extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 8}, "https://token.actions.githubusercontent.com"), `Certificate has correct builder signer URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 9}, "https://github.com/jobWorkflowRef"), `Certificate has correct builder signer digest extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 10}, "jobWorkflowSha"), `Certificate has correct runner environment extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 11}, "runnerEnv"), `Certificate has correct source repo URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 12}, "https://github.com/repository"), `Certificate has correct source repo digest extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 13}, "sha"), `Certificate has correct source repo ref extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 14}, "ref"), `Certificate has correct source repo ID extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 15}, "repoID"), `Certificate has correct source repo owner URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 16}, "https://github.com/repoOwner"), `Certificate has correct source repo owner ID extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 17}, "repoOwnerID"), `Certificate has correct build config URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 18}, "https://github.com/workflowRef"), `Certificate has correct build config digest extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 19}, "workflowSHA"), `Certificate has correct build trigger extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 20}, "trigger"), `Certificate has correct run invocation ID extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 21}, "https://github.com/repository/actions/runs/runID/attempts/runAttempt"), `Certificate has correct source repository visibility extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 22}, "public"), }, }, `Github workflow value with bad URL fails`: { Principal: &workflowPrincipal{ subject: "doesntmatter", url: "\nbadurl", sha: "sha", eventName: "trigger", workflow: "workflowname", repository: "repository", ref: "ref", }, WantErr: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { var cert x509.Certificate err := test.Principal.Embed(context.TODO(), &cert) if err != nil { if !test.WantErr { t.Error(err) } return } else if test.WantErr { t.Error("expected error") } for factName, fact := range test.WantFacts { t.Run(factName, func(t *testing.T) { if err := fact(cert); err != nil { t.Error(err) } }) } }) } } func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { var strVal string _, _ = asn1.Unmarshal(ext.Value, &strVal) if value != strVal { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, strVal) } return nil } } return errors.New("extension not set") } } func factDeprecatedExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { if !bytes.Equal(ext.Value, []byte(value)) { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, ext.Value) } return nil } } return errors.New("extension not set") } } fulcio-1.6.5/pkg/identity/gitlabcom/000077500000000000000000000000001470150653400173645ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/gitlabcom/issuer.go000066400000000000000000000022631470150653400212300ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 gitlabcom import ( "context" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/base" ) type gitlabIssuer struct { identity.Issuer } func Issuer(issuerURL string) identity.Issuer { return &gitlabIssuer{base.Issuer(issuerURL)} } func (e *gitlabIssuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { idtoken, err := identity.Authorize(ctx, token, opts...) if err != nil { return nil, err } return JobPrincipalFromIDToken(ctx, idtoken) } fulcio-1.6.5/pkg/identity/gitlabcom/issuer_test.go000066400000000000000000000056411470150653400222720ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 gitlabcom import ( "context" "encoding/json" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) func TestIssuer(t *testing.T) { ctx := context.Background() url := "test-issuer-url" issuer := Issuer(url) // test the Match function t.Run("match", func(t *testing.T) { if matches := issuer.Match(ctx, url); !matches { t.Fatal("expected url to match but it doesn't") } if matches := issuer.Match(ctx, "some-other-url"); matches { t.Fatal("expected match to fail but it didn't") } }) t.Run("authenticate", func(t *testing.T) { token := &oidc.IDToken{ Issuer: "https://iss.example.com", Subject: "repo:sigstore/fulcio:ref:refs/heads/main", } claims, err := json.Marshal(map[string]interface{}{ "namespace_id": "1730270", "namespace_path": "cpanato", "project_id": "42831435", "project_path": "cpanato/testing-cosign", "user_id": "1430381", "user_login": "cpanato", "user_email": "cpanato@example.com", "pipeline_id": "757451528", "pipeline_source": "push", "ci_config_ref_uri": "gitlab.com/cpanto/testing-cosign//.gitlab-ci.yml@refs/head/main", "job_id": "3659681386", "sha": "714a629c0b401fdce83e847fc9589983fc6f46bc", "runner_id": 1, "runner_environment": "gitlab-hosted", "ref": "main", "ref_type": "branch", "ref_protected": "true", "project_visibility": "public", "jti": "914910cc-09f6-4217-8091-a1d3231a37db", "iss": "https://gitlab.com", "iat": 1674658264, "nbf": 1674658259, "exp": 1674661864, "sub": "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", "aud": "sigstore", }) if err != nil { t.Fatal(err) } withClaims(token, claims) identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { return token, nil } principal, err := issuer.Authenticate(ctx, "token") if err != nil { t.Fatal(err) } if principal.Name(ctx) != "repo:sigstore/fulcio:ref:refs/heads/main" { t.Fatalf("got unexpected name %s", principal.Name(ctx)) } }) } fulcio-1.6.5/pkg/identity/gitlabcom/principal.go000066400000000000000000000157011470150653400217000ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 gitlabcom import ( "context" "crypto/x509" "errors" "fmt" "net/url" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/identity" ) type jobPrincipal struct { // Subject matches the 'sub' claim from the OIDC ID token this is what is // signed as proof of possession for Buildkite job identities subject string // OIDC Issuer URL. Matches 'iss' claim from ID token. The real issuer URL is // https://agent.buildkite.com/.well-known/openid-configuration issuer string // The URL of the GitLab instance. https://gitlab.com url string // Event that triggered this workflow run. E.g "push", "tag" etc eventName string // Pipeline ID pipelineID string // Ref of top-level pipeline definition. E.g. gitlab.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main ciConfigRefURI string // Commit sha of top-level pipeline definition, and is // only populated when `ciConfigRefURI` is local to the GitLab instance ciConfigSha string // Repository building built repository string // ID to the source repo repositoryID string // Owner of the source repo (mutable) repositoryOwner string // ID of the source repo repositoryOwnerID string // job ID jobID string // Git ref being built ref string // Commit SHA being built sha string // ID of the runner runnerID int64 // The type of runner used by the job. May be one of gitlab-hosted or self-hosted. runnerEnvironment string // Visibility of the source project projectVisibility string } func JobPrincipalFromIDToken(_ context.Context, token *oidc.IDToken) (identity.Principal, error) { var claims struct { ProjectPath string `json:"project_path"` ProjectID string `json:"project_id"` PipelineSource string `json:"pipeline_source"` PipelineID string `json:"pipeline_id"` CiConfigRefURI string `json:"ci_config_ref_uri"` CiConfigSha string `json:"ci_config_sha"` NamespacePath string `json:"namespace_path"` NamespaceID string `json:"namespace_id"` JobID string `json:"job_id"` Ref string `json:"ref"` RefType string `json:"ref_type"` Sha string `json:"sha"` RunnerEnvironment string `json:"runner_environment"` RunnerID int64 `json:"runner_id"` ProjectVisibility string `json:"project_visibility"` } if err := token.Claims(&claims); err != nil { return nil, err } if claims.ProjectPath == "" { return nil, errors.New("missing project_path claim in ID token") } if claims.PipelineSource == "" { return nil, errors.New("missing pipeline_source claim in ID token") } if claims.PipelineID == "" { return nil, errors.New("missing pipeline_id claim in ID token") } if claims.CiConfigRefURI == "" { return nil, errors.New("missing ci_config_ref_uri claim in ID token") } if claims.JobID == "" { return nil, errors.New("missing job_id claim in ID token") } if claims.Ref == "" { return nil, errors.New("missing ref claim in ID token") } if claims.RefType == "" { return nil, errors.New("missing ref_type claim in ID token") } if claims.NamespacePath == "" { return nil, errors.New("missing namespace_path claim in ID token") } if claims.NamespaceID == "" { return nil, errors.New("missing namespace_id claim in ID token") } if claims.ProjectID == "" { return nil, errors.New("missing project_id claim in ID token") } if claims.Sha == "" { return nil, errors.New("missing sha claim in ID token") } if claims.RunnerEnvironment == "" { return nil, errors.New("missing runner_environment claim in ID token") } if claims.RunnerID == 0 { return nil, errors.New("missing runner_id claim in ID token") } var ref string switch claims.RefType { case "branch": ref = "refs/heads/" + claims.Ref case "tag": ref = "refs/tags/" + claims.Ref default: return nil, fmt.Errorf("unexpected ref_type: %s", claims.RefType) } return &jobPrincipal{ subject: token.Subject, issuer: token.Issuer, url: `https://gitlab.com/`, eventName: claims.PipelineSource, pipelineID: claims.PipelineID, ciConfigRefURI: claims.CiConfigRefURI, ciConfigSha: claims.CiConfigSha, repository: claims.ProjectPath, ref: ref, repositoryID: claims.ProjectID, repositoryOwner: claims.NamespacePath, repositoryOwnerID: claims.NamespaceID, jobID: claims.JobID, sha: claims.Sha, runnerID: claims.RunnerID, runnerEnvironment: claims.RunnerEnvironment, projectVisibility: claims.ProjectVisibility, }, nil } func (p jobPrincipal) Name(_ context.Context) string { return p.subject } func (p jobPrincipal) Embed(_ context.Context, cert *x509.Certificate) error { baseURL, err := url.Parse(p.url) if err != nil { return err } // ci_config_ref_uri claim is a URI that does not include protocol scheme so we need to normalize it ciConfigRefURL, err := url.Parse(p.ciConfigRefURI) if err != nil { return err } // default to https ciConfigRefURL.Scheme = "https" // or use scheme from issuer if from the same host if baseURL.Host == ciConfigRefURL.Host { ciConfigRefURL.Scheme = baseURL.Scheme } // Set workflow ref URL to SubjectAlternativeName on certificate cert.URIs = []*url.URL{ciConfigRefURL} // Embed additional information into custom extensions cert.ExtraExtensions, err = certificate.Extensions{ Issuer: p.issuer, BuildConfigURI: ciConfigRefURL.String(), BuildConfigDigest: p.ciConfigSha, BuildSignerURI: ciConfigRefURL.String(), BuildSignerDigest: p.ciConfigSha, RunnerEnvironment: p.runnerEnvironment, SourceRepositoryURI: baseURL.JoinPath(p.repository).String(), SourceRepositoryDigest: p.sha, SourceRepositoryRef: p.ref, SourceRepositoryIdentifier: p.repositoryID, SourceRepositoryOwnerURI: baseURL.JoinPath(p.repositoryOwner).String(), SourceRepositoryOwnerIdentifier: p.repositoryOwnerID, BuildTrigger: p.eventName, RunInvocationURI: baseURL.JoinPath(p.repository, "/-/jobs/", p.jobID).String(), SourceRepositoryVisibilityAtSigning: p.projectVisibility, }.Render() if err != nil { return err } return nil } fulcio-1.6.5/pkg/identity/gitlabcom/principal_test.go000066400000000000000000000402671470150653400227440ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 gitlabcom import ( "context" "crypto/x509" "encoding/asn1" "encoding/json" "errors" "fmt" "reflect" "strings" "testing" "unsafe" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/identity" ) func TestJobPrincipalFromIDToken(t *testing.T) { tests := map[string]struct { Claims map[string]interface{} ExpectPrincipal jobPrincipal WantErr bool ErrContains string }{ `Valid token authenticates with correct claims`: { Claims: map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://gitlab.com", "sub": "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", "project_id": "42831435", "project_path": "cpanato/testing-cosign", "namespace_path": "cpanato", "namespace_id": "1730270", "pipeline_id": "757451528", "pipeline_source": "push", "ci_config_ref_uri": "gitlab.com/cpanto/testing-cosign//.gitlab-ci.yml@refs/head/main", "ci_config_sha": "714a629c0b401fdce83e847fc9589983fc6f46bc", "job_id": "3659681386", "ref": "main", "ref_type": "branch", "sha": "714a629c0b401fdce83e847fc9589983fc6f46bc", "runner_id": 1, "runner_environment": "gitlab-hosted", "project_visibility": "public", }, ExpectPrincipal: jobPrincipal{ issuer: "https://gitlab.com", subject: "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", url: "https://gitlab.com/", eventName: "push", pipelineID: "757451528", ciConfigRefURI: "gitlab.com/cpanto/testing-cosign//.gitlab-ci.yml@refs/head/main", ciConfigSha: "714a629c0b401fdce83e847fc9589983fc6f46bc", repository: "cpanato/testing-cosign", repositoryID: "42831435", repositoryOwner: "cpanato", repositoryOwnerID: "1730270", jobID: "3659681386", ref: "refs/heads/main", runnerID: 1, runnerEnvironment: "gitlab-hosted", sha: "714a629c0b401fdce83e847fc9589983fc6f46bc", projectVisibility: "public", }, WantErr: false, }, `Token missing pipeline_source claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://gitlab.com", "sub": "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", "ci_config_ref_uri": "gitlab.com/cpanto/testing-cosign//.gitlab-ci.yml@refs/head/main", "ci_config_sha": "714a629c0b401fdce83e847fc9589983fc6f46bc", "project_id": "42831435", "project_path": "cpanato/testing-cosign", "namespace_path": "cpanato", "namespace_id": "1730270", "pipeline_id": "757451528", "job_id": "3659681386", "ref": "main", "ref_type": "branch", "project_visibility": "public", }, WantErr: true, ErrContains: "pipeline_source", }, `Token missing project_path claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://gitlab.com", "sub": "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", "ci_config_ref_uri": "gitlab.com/cpanto/testing-cosign//.gitlab-ci.yml@refs/head/main", "ci_config_sha": "714a629c0b401fdce83e847fc9589983fc6f46bc", "project_id": "42831435", "pipeline_id": "757451528", "namespace_id": "1730270", "pipeline_source": "push", "namespace_path": "cpanato", "job_id": "3659681386", "ref": "main", "ref_type": "branch", "project_visibility": "public", }, WantErr: true, ErrContains: "project_path", }, `Token missing ci_config_ref_uri claim should be rejected`: { Claims: map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://gitlab.com", "sub": "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", "project_id": "42831435", "project_path": "cpanato/testing-cosign", "pipeline_id": "757451528", "namespace_id": "1730270", "pipeline_source": "push", "namespace_path": "cpanato", "job_id": "3659681386", "ref": "main", "ref_type": "branch", "project_visibility": "public", }, WantErr: true, ErrContains: "ci_config_ref_uri", }, `Token missing ci_config_sha claim is ok`: { Claims: map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://gitlab.com", "sub": "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", "project_id": "42831435", "project_path": "cpanato/testing-cosign", "namespace_path": "cpanato", "namespace_id": "1730270", "pipeline_id": "757451528", "pipeline_source": "push", "ci_config_ref_uri": "example.com/ci/config.yml", "job_id": "3659681386", "ref": "main", "ref_type": "branch", "sha": "714a629c0b401fdce83e847fc9589983fc6f46bc", "runner_id": 1, "runner_environment": "gitlab-hosted", "project_visibility": "public", }, ExpectPrincipal: jobPrincipal{ issuer: "https://gitlab.com", subject: "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", url: "https://gitlab.com/", eventName: "push", pipelineID: "757451528", ciConfigRefURI: "example.com/ci/config.yml", repository: "cpanato/testing-cosign", repositoryID: "42831435", repositoryOwner: "cpanato", repositoryOwnerID: "1730270", jobID: "3659681386", ref: "refs/heads/main", runnerID: 1, runnerEnvironment: "gitlab-hosted", sha: "714a629c0b401fdce83e847fc9589983fc6f46bc", projectVisibility: "public", }, WantErr: false, }, `Token missing project_visibility is ok`: { Claims: map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://gitlab.com", "sub": "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", "project_id": "42831435", "project_path": "cpanato/testing-cosign", "namespace_path": "cpanato", "namespace_id": "1730270", "pipeline_id": "757451528", "pipeline_source": "push", "ci_config_ref_uri": "gitlab.com/cpanto/testing-cosign//.gitlab-ci.yml@refs/head/main", "ci_config_sha": "714a629c0b401fdce83e847fc9589983fc6f46bc", "job_id": "3659681386", "ref": "main", "ref_type": "branch", "sha": "714a629c0b401fdce83e847fc9589983fc6f46bc", "runner_id": 1, "runner_environment": "gitlab-hosted", }, ExpectPrincipal: jobPrincipal{ issuer: "https://gitlab.com", subject: "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", url: "https://gitlab.com/", eventName: "push", pipelineID: "757451528", ciConfigRefURI: "gitlab.com/cpanto/testing-cosign//.gitlab-ci.yml@refs/head/main", ciConfigSha: "714a629c0b401fdce83e847fc9589983fc6f46bc", repository: "cpanato/testing-cosign", repositoryID: "42831435", repositoryOwner: "cpanato", repositoryOwnerID: "1730270", jobID: "3659681386", ref: "refs/heads/main", runnerID: 1, runnerEnvironment: "gitlab-hosted", sha: "714a629c0b401fdce83e847fc9589983fc6f46bc", }, WantErr: false, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) untyped, err := JobPrincipalFromIDToken(context.TODO(), token) if err != nil { if !test.WantErr { t.Fatal("didn't expect error", err) } if !strings.Contains(err.Error(), test.ErrContains) { t.Fatalf("expected error %s to contain %s", err, test.ErrContains) } return } if err == nil && test.WantErr { t.Fatal("expected error but got none") } principal, ok := untyped.(*jobPrincipal) if !ok { t.Errorf("Got wrong principal type %v", untyped) } if *principal != test.ExpectPrincipal { t.Errorf("got %v principal and expected %v", *principal, test.ExpectPrincipal) } }) } } // reflect hack because "claims" field is unexported by oidc IDToken // https://github.com/coreos/go-oidc/pull/329 func withClaims(token *oidc.IDToken, data []byte) { val := reflect.Indirect(reflect.ValueOf(token)) member := val.FieldByName("claims") pointer := unsafe.Pointer(member.UnsafeAddr()) realPointer := (*[]byte)(pointer) *realPointer = data } func TestName(t *testing.T) { tests := map[string]struct { Claims map[string]interface{} ExpectName string }{ `Valid token authenticates with correct claims`: { Claims: map[string]interface{}{ "aud": "sigstore", "exp": 0, "iss": "https://gitlab.com", "sub": "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", "project_id": "42831435", "project_path": "cpanato/testing-cosign", "pipeline_id": "757451528", "ci_config_ref_uri": "gitlab.com/cpanto/testing-cosign//.gitlab-ci.yml@refs/head/main", "pipeline_source": "push", "namespace_path": "cpanato", "namespace_id": "1730270", "job_id": "3659681386", "ref": "main", "ref_type": "branch", "sha": "714a629c0b401fdce83e847fc9589983fc6f46bc", "runner_id": 1, "runner_environment": "gitlab-hosted", "project_visibility": "public", }, ExpectName: "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) principal, err := JobPrincipalFromIDToken(context.TODO(), token) if err != nil { t.Fatal(err) } gotName := principal.Name(context.TODO()) if gotName != test.ExpectName { t.Error("name should match sub claim") } }) } } func TestEmbed(t *testing.T) { tests := map[string]struct { Principal identity.Principal WantErr bool WantFacts map[string]func(x509.Certificate) error }{ `GitLab job challenge should have issue, subject and url embedded`: { Principal: &jobPrincipal{ issuer: "https://gitlab.com", subject: "project_path:cpanato/testing-cosign:ref_type:branch:ref:main", url: "https://gitlab.com/", eventName: "push", pipelineID: "757451528", ciConfigRefURI: "gitlab.com/cpanto/testing-cosign//.gitlab-ci.yml@refs/head/main", ciConfigSha: "714a629c0b401fdce83e847fc9589983fc6f46bc", repository: "cpanato/testing-cosign", repositoryID: "42831435", repositoryOwner: "cpanato", repositoryOwnerID: "1730270", jobID: "3659681386", ref: "ref", runnerID: 1, runnerEnvironment: "gitlab-hosted", sha: "sha", projectVisibility: "public", }, WantErr: false, WantFacts: map[string]func(x509.Certificate) error{ `Certificate has correct issuer (v2) extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 8}, "https://gitlab.com"), `Certificate has correct builder signer URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 9}, "https://gitlab.com/cpanto/testing-cosign//.gitlab-ci.yml@refs/head/main"), `Certificate has correct builder signer digest extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 10}, "714a629c0b401fdce83e847fc9589983fc6f46bc"), `Certificate has correct runner environment extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 11}, "gitlab-hosted"), `Certificate has correct source repo URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 12}, "https://gitlab.com/cpanato/testing-cosign"), `Certificate has correct source repo digest extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 13}, "sha"), `Certificate has correct source repo ref extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 14}, "ref"), `Certificate has correct source repo ID extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 15}, "42831435"), `Certificate has correct source repo owner URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 16}, "https://gitlab.com/cpanato"), `Certificate has correct source repo owner ID extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 17}, "1730270"), `Certificate has correct build config URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 18}, "https://gitlab.com/cpanto/testing-cosign//.gitlab-ci.yml@refs/head/main"), `Certificate has correct build config digest extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 19}, "714a629c0b401fdce83e847fc9589983fc6f46bc"), `Certificate has correct build trigger extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 20}, "push"), `Certificate has correct run invocation ID extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 21}, "https://gitlab.com/cpanato/testing-cosign/-/jobs/3659681386"), `Certificate has correct source repository visibility extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 22}, "public"), }, }, `GitLab job principal with bad URL fails`: { Principal: &jobPrincipal{ subject: "doesntmatter", url: "\nbadurl", }, WantErr: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { var cert x509.Certificate err := test.Principal.Embed(context.TODO(), &cert) if err != nil { if !test.WantErr { t.Error(err) } return } else if test.WantErr { t.Error("expected error") } for factName, fact := range test.WantFacts { t.Run(factName, func(t *testing.T) { if err := fact(cert); err != nil { t.Error(err) } }) } }) } } func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { var strVal string _, _ = asn1.Unmarshal(ext.Value, &strVal) if value != strVal { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, strVal) } return nil } } return errors.New("extension not set") } } fulcio-1.6.5/pkg/identity/issuer.go000066400000000000000000000021151470150653400172630ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 identity import ( "context" "github.com/sigstore/fulcio/pkg/config" ) type Issuer interface { // Match checks if this issuer can authenticate tokens from a given issuer URL Match(ctx context.Context, url string) bool // Authenticate ID token and return Principal on success. The ID token's signature // is verified in the call -- invalid signature must result in an error. Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (Principal, error) } fulcio-1.6.5/pkg/identity/issuerpool.go000066400000000000000000000033201470150653400201540ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 identity import ( "context" "encoding/base64" "encoding/json" "fmt" "strings" "github.com/sigstore/fulcio/pkg/config" ) type IssuerPool []Issuer func (p IssuerPool) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (Principal, error) { url, err := extractIssuerURL(token) if err != nil { return nil, err } for _, issuer := range p { if issuer.Match(ctx, url) { return issuer.Authenticate(ctx, token, opts...) } } return nil, fmt.Errorf("failed to match issuer URL %s from token with any configured providers", url) } func extractIssuerURL(token string) (string, error) { parts := strings.Split(token, ".") if len(parts) != 3 { return "", fmt.Errorf("oidc: malformed jwt, expected 3 parts got %d", len(parts)) } raw, err := base64.RawURLEncoding.DecodeString(parts[1]) if err != nil { return "", fmt.Errorf("oidc: malformed jwt payload: %w", err) } var payload struct { Issuer string `json:"iss"` } if err := json.Unmarshal(raw, &payload); err != nil { return "", fmt.Errorf("oidc: failed to unmarshal claims: %w", err) } return payload.Issuer, nil } fulcio-1.6.5/pkg/identity/issuerpool_test.go000066400000000000000000000145051470150653400212220ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 identity import ( "context" "crypto/x509" "errors" "testing" "github.com/sigstore/fulcio/pkg/config" ) type testPrincipal struct { name string } func (p testPrincipal) Name(_ context.Context) string { return p.name } func (p testPrincipal) Embed(_ context.Context, _ *x509.Certificate) error { return nil } type testIssuer struct { match func(context.Context, string) bool auth func(context.Context, string) (Principal, error) } func (i testIssuer) Match(ctx context.Context, url string) bool { return i.match(ctx, url) } func (i testIssuer) Authenticate(ctx context.Context, token string, _ ...config.InsecureOIDCConfigOption) (Principal, error) { return i.auth(ctx, token) } func TestIssuerPool(t *testing.T) { var ( // Example principals alice = testPrincipal{`alice`} bob = testPrincipal{`bob`} // Example issuers bobIfExampleCom = testIssuer{ match: func(_ context.Context, url string) bool { return url == `example.com` }, auth: func(context.Context, string) (Principal, error) { return bob, nil }, } aliceIfOtherCom = testIssuer{ match: func(_ context.Context, url string) bool { return url == `other.com` }, auth: func(context.Context, string) (Principal, error) { return alice, nil }, } matchThenRejectAll = testIssuer{ match: func(context.Context, string) bool { return true }, auth: func(context.Context, string) (Principal, error) { return nil, errors.New(`boooooo`) }, } // Example tokens // iss == example.com exampleToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJleGFtcGxlLmNvbSJ9.eBJFurm45FSlxt9c7r339xkQC7yqn2O9SlBldCFAQhk` // iss == other.com otherToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJvdGhlci5jb20ifQ.GtTvBmBvm0kPIfBctKDD1GDavmtlQXBQIDjGg6k2kOA` // iss == bad.com badToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJiYWQuY29tIn0.aW-Zyc3JTnqI0uqc1VzNY9_5BhmhXmUksGaFEiiZCHU` // bad format token badFormatToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.??.aW-Zyc3JTnqI0uqc1VzNY9_5BhmhXmUksGaFEiiZCHU` ) tests := map[string]struct { Pool IssuerPool Token string ExpectedPrincipal Principal WantErr bool }{ `example.com only pool should allow example.com tokens`: { Pool: IssuerPool{bobIfExampleCom}, Token: exampleToken, ExpectedPrincipal: bob, WantErr: false, }, `example.com only pool should not allow other.com tokens`: { Pool: IssuerPool{bobIfExampleCom}, Token: otherToken, WantErr: true, }, `example.com and other.com pool should match other.com token to alice`: { Pool: IssuerPool{bobIfExampleCom, aliceIfOtherCom}, Token: otherToken, ExpectedPrincipal: alice, WantErr: false, }, `example.com and other.com pool should match example.com token to bob`: { Pool: IssuerPool{bobIfExampleCom, aliceIfOtherCom}, Token: exampleToken, ExpectedPrincipal: bob, WantErr: false, }, `example.com and other.com pool should reject bad.com token`: { Pool: IssuerPool{bobIfExampleCom, aliceIfOtherCom}, Token: badToken, WantErr: true, }, `example.com and other.com pool should reject badly formatted token`: { Pool: IssuerPool{bobIfExampleCom, aliceIfOtherCom}, Token: badFormatToken, WantErr: true, }, `empty pool should never authenticate`: { Pool: IssuerPool{}, Token: exampleToken, WantErr: true, }, `match then reject all pool should never authenticate`: { Pool: IssuerPool{matchThenRejectAll}, Token: exampleToken, WantErr: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { ctx := context.Background() principal, err := test.Pool.Authenticate(ctx, test.Token) if err != nil { if !test.WantErr { t.Error("Didn't expect error", err) } } else { if principal != test.ExpectedPrincipal { t.Errorf("Got principal %s, but wanted %s", principal.Name(ctx), test.ExpectedPrincipal.Name(ctx)) } } }) } } func TestExtractIssuerURL(t *testing.T) { tests := map[string]struct { Token string ExpectedURL string WantErr bool }{ `issuer example.com`: { // Valid token (HS256 with `derp` secret) and iss = example.com Token: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJleGFtcGxlLmNvbSJ9.LGkuVtRymNgdZFn4v_jRJCJVwdt1wZDw588tbXC8VTU`, ExpectedURL: `example.com`, WantErr: false, }, `no issuer claim`: { // Valid JWT but no `iss` claim. Claims are {"foo": "bar"}. Token: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.kOu-Qu-GoCH3G70LKrm_W9DJj2MpF4C5QweznLgGZgc`, WantErr: true, }, `Not enough token parts`: { // Has 2 parts instead of 3 Token: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ`, WantErr: true, }, `Too many token parts`: { // Has 4 parts instead of 3 Token: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.eyJmb28iOiJiYXIifQ.eyJmb28iOiJiYXIifQ`, WantErr: true, }, `Bad claims base64 encoding`: { // ??? are illegal base64 url safe characters Token: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.???.kOu-Qu-GoCH3G70LKrm_W9DJj2MpF4C5QweznLgGZgc`, WantErr: true, }, `Bad claims JSON format`: { // fXs decodes to `}{` which is note valid JSON Token: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.fXs.kOu-Qu-GoCH3G70LKrm_W9DJj2MpF4C5QweznLgGZgc`, WantErr: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { gotURL, err := extractIssuerURL(test.Token) if err != nil { if !test.WantErr { t.Error(err) } } else { if gotURL != test.ExpectedURL { t.Errorf("Wanted %s and got %s for issuer url", test.ExpectedURL, gotURL) } } }) } } fulcio-1.6.5/pkg/identity/kubernetes/000077500000000000000000000000001470150653400175725ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/kubernetes/issuer.go000066400000000000000000000022751470150653400214410ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 kubernetes import ( "context" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/base" ) type kubernetesIssuer struct { identity.Issuer } func Issuer(issuerURL string) identity.Issuer { return &kubernetesIssuer{base.Issuer(issuerURL)} } func (e *kubernetesIssuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { idtoken, err := identity.Authorize(ctx, token, opts...) if err != nil { return nil, err } return PrincipalFromIDToken(ctx, idtoken) } fulcio-1.6.5/pkg/identity/kubernetes/issuer_test.go000066400000000000000000000042571470150653400225020ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 kubernetes import ( "context" "encoding/json" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) func TestIssuer(t *testing.T) { ctx := context.Background() url := "test-issuer-url" issuer := Issuer(url) // test the Match function t.Run("match", func(t *testing.T) { if matches := issuer.Match(ctx, url); !matches { t.Fatal("expected url to match but it doesn't") } if matches := issuer.Match(ctx, "some-other-url"); matches { t.Fatal("expected match to fail but it didn't") } }) t.Run("authenticate", func(t *testing.T) { token := &oidc.IDToken{ Issuer: "https://iss.example.com", Subject: "subject", } claims, err := json.Marshal(map[string]interface{}{ "aud": []string{"sigstore"}, "iss": "https://iss.example.com", "kubernetes.io": map[string]interface{}{ "namespace": "foo", "pod": map[string]string{ "name": "bar", "uid": "2ff0bae1-6b8a-445b-ae03-1f8d2a08d031", }, "serviceaccount": map[string]string{ "name": "baz", "uid": "5cb6264f-e283-4365-9a1f-d5a15090527e", }, }, "sub": "system:serviceaccount:foo:baz", }) if err != nil { t.Fatal(err) } withClaims(token, claims) identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { return token, nil } principal, err := issuer.Authenticate(ctx, "token") if err != nil { t.Fatal(err) } if principal.Name(ctx) != "subject" { t.Fatalf("got unexpected name %s", principal.Name(ctx)) } }) } fulcio-1.6.5/pkg/identity/kubernetes/principal.go000066400000000000000000000052021470150653400221010ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 kubernetes import ( "context" "crypto/x509" "net/url" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/identity" ) type principal struct { // Subject ('sub') from ID token subject string // Issuer ('iss') from ID token issuer string // URI to be set in certificate. URI is of the form // https://kubernetes.io/namespaces//serviceaccounts/. uri string } func PrincipalFromIDToken(_ context.Context, token *oidc.IDToken) (identity.Principal, error) { k8sURI, err := kubernetesToken(token) if err != nil { return nil, err } return principal{ subject: token.Subject, issuer: token.Issuer, uri: k8sURI, }, nil } func (p principal) Name(context.Context) string { return p.subject } func (p principal) Embed(_ context.Context, cert *x509.Certificate) error { parsed, err := url.Parse(p.uri) if err != nil { return err } cert.URIs = []*url.URL{parsed} cert.ExtraExtensions, err = certificate.Extensions{ Issuer: p.issuer, }.Render() if err != nil { return err } return nil } func kubernetesToken(token *oidc.IDToken) (string, error) { // Extract custom claims var claims struct { // "kubernetes.io": { // "namespace": "default", // "pod": { // "name": "oidc-test", // "uid": "49ad3572-b3dd-43a6-8d77-5858d3660275" // }, // "serviceaccount": { // "name": "default", // "uid": "f5720c1d-e152-4356-a897-11b07aff165d" // } // } Kubernetes struct { Namespace string `json:"namespace"` Pod struct { Name string `json:"name"` UID string `json:"uid"` } `json:"pod"` ServiceAccount struct { Name string `json:"name"` UID string `json:"uid"` } `json:"serviceaccount"` } `json:"kubernetes.io"` } if err := token.Claims(&claims); err != nil { return "", err } // We use this in URIs, so it has to be a URI. return "https://kubernetes.io/namespaces/" + claims.Kubernetes.Namespace + "/serviceaccounts/" + claims.Kubernetes.ServiceAccount.Name, nil } fulcio-1.6.5/pkg/identity/kubernetes/principal_test.go000066400000000000000000000142511470150653400231440ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 kubernetes import ( "bytes" "context" "crypto/x509" "encoding/asn1" "encoding/json" "errors" "fmt" "net/url" "reflect" "testing" "unsafe" "github.com/coreos/go-oidc/v3/oidc" "github.com/google/go-cmp/cmp" ) func TestPrincipalFromIDToken(t *testing.T) { tests := map[string]struct { Claims map[string]interface{} ExpectedPrincipal principal WantErr bool }{ `Valid token authenticates with correct claims`: { Claims: map[string]interface{}{ "aud": []string{"sigstore"}, "iss": "https://iss.example.com", "kubernetes.io": map[string]interface{}{ "namespace": "foo", "pod": map[string]string{ "name": "bar", "uid": "2ff0bae1-6b8a-445b-ae03-1f8d2a08d031", }, "serviceaccount": map[string]string{ "name": "baz", "uid": "5cb6264f-e283-4365-9a1f-d5a15090527e", }, }, "sub": "system:serviceaccount:foo:baz", }, ExpectedPrincipal: principal{ issuer: "https://iss.example.com", subject: "system:serviceaccount:foo:baz", uri: "https://kubernetes.io/namespaces/foo/serviceaccounts/baz", }, WantErr: false, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) untyped, err := PrincipalFromIDToken(context.TODO(), token) if err != nil { if !test.WantErr { t.Fatal("didn't expect error", err) } return } if err == nil && test.WantErr { t.Fatal("expected error but got none") } gotPrincipal, ok := untyped.(principal) if !ok { t.Errorf("Got wrong principal type %v", untyped) } if gotPrincipal != test.ExpectedPrincipal { t.Errorf("got %v principal and expected %v", gotPrincipal, test.ExpectedPrincipal) } }) } } // reflect hack because "claims" field is unexported by oidc IDToken // https://github.com/coreos/go-oidc/pull/329 func withClaims(token *oidc.IDToken, data []byte) { val := reflect.Indirect(reflect.ValueOf(token)) member := val.FieldByName("claims") pointer := unsafe.Pointer(member.UnsafeAddr()) realPointer := (*[]byte)(pointer) *realPointer = data } func TestName(t *testing.T) { tests := map[string]struct { Claims map[string]interface{} ExpectedName string }{ `Valid token authenticates with correct claims`: { Claims: map[string]interface{}{ "aud": []string{"sigstore"}, "iss": "https://iss.example.com", "kubernetes.io": map[string]interface{}{ "namespace": "foo", "pod": map[string]string{ "name": "bar", "uid": "2ff0bae1-6b8a-445b-ae03-1f8d2a08d031", }, "serviceaccount": map[string]string{ "name": "baz", "uid": "5cb6264f-e283-4365-9a1f-d5a15090527e", }, }, "sub": "system:serviceaccount:foo:baz", }, ExpectedName: "system:serviceaccount:foo:baz", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { token := &oidc.IDToken{ Issuer: test.Claims["iss"].(string), Subject: test.Claims["sub"].(string), } claims, err := json.Marshal(test.Claims) if err != nil { t.Fatal(err) } withClaims(token, claims) got, err := PrincipalFromIDToken(context.TODO(), token) if err != nil { t.Fatal("didn't expect error", err) } if got.Name(context.TODO()) != test.ExpectedName { t.Errorf("got name %v and expected %v", got.Name(context.TODO()), test.ExpectedName) } }) } } func TestEmbed(t *testing.T) { tests := map[string]struct { Principal principal WantErr bool WantFacts map[string]func(x509.Certificate) error }{ `Good Kubernetes value`: { Principal: principal{ issuer: `https://k8s.example.com`, uri: "https://kubernetes.io/namespaces/foo/serviceaccounts/bar", }, WantErr: false, WantFacts: map[string]func(x509.Certificate) error{ `Issuer is k8s.example.com`: factIssuerIs(`https://k8s.example.com`), `SAN is https://k8s.example.com`: func(cert x509.Certificate) error { WantURI, err := url.Parse("https://kubernetes.io/namespaces/foo/serviceaccounts/bar") if err != nil { return err } if len(cert.URIs) != 1 { return errors.New("no URI SAN set") } if diff := cmp.Diff(cert.URIs[0], WantURI); diff != "" { return errors.New(diff) } return nil }, }, }, `Kubernetes value with bad URL fails`: { Principal: principal{ issuer: `example.com`, uri: "\nbadurl", }, WantErr: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { var cert x509.Certificate err := test.Principal.Embed(context.TODO(), &cert) if err != nil { if !test.WantErr { t.Error(err) } return } else if test.WantErr { t.Error("expected error") } for factName, fact := range test.WantFacts { t.Run(factName, func(t *testing.T) { if err := fact(cert); err != nil { t.Error(err) } }) } }) } } func factIssuerIs(issuer string) func(x509.Certificate) error { return factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, issuer) } func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { if !bytes.Equal(ext.Value, []byte(value)) { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, ext.Value) } return nil } } return errors.New("extension not set") } } fulcio-1.6.5/pkg/identity/principal.go000066400000000000000000000017621470150653400177410ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 identity import ( "context" "crypto/x509" ) type Principal interface { // Name is the email or subject of OIDC ID token. This value must match the // value signed in the proof of private key possession challenge. Name(ctx context.Context) string // Embed all SubjectAltName and custom x509 extension information into // certificate. Embed(ctx context.Context, cert *x509.Certificate) error } fulcio-1.6.5/pkg/identity/spiffe/000077500000000000000000000000001470150653400166775ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/spiffe/issuer.go000066400000000000000000000022551470150653400205440ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 spiffe import ( "context" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/base" ) type spiffeIssuer struct { identity.Issuer } func Issuer(issuerURL string) identity.Issuer { return &spiffeIssuer{base.Issuer(issuerURL)} } func (e *spiffeIssuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { idtoken, err := identity.Authorize(ctx, token, opts...) if err != nil { return nil, err } return PrincipalFromIDToken(ctx, idtoken) } fulcio-1.6.5/pkg/identity/spiffe/issuer_test.go000066400000000000000000000037771470150653400216150ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 spiffe import ( "context" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) func TestIssuer(t *testing.T) { ctx := context.Background() url := "test-issuer-url" issuer := Issuer(url) // test the Match function t.Run("match", func(t *testing.T) { if matches := issuer.Match(ctx, url); !matches { t.Fatal("expected url to match but it doesn't") } if matches := issuer.Match(ctx, "some-other-url"); matches { t.Fatal("expected match to fail but it didn't") } }) t.Run("authenticate", func(t *testing.T) { token := &oidc.IDToken{ Issuer: "https://issuer.example.com", Subject: "spiffe://example.com/foo/bar", } cfg := &config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://issuer.example.com": { IssuerURL: "https://issuer.example.com", ClientID: "sigstore", Type: "spiffe", SPIFFETrustDomain: "example.com", }, }, } ctx := config.With(context.Background(), cfg) identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { return token, nil } principal, err := issuer.Authenticate(ctx, "token") if err != nil { t.Fatal(err) } if principal.Name(ctx) != "spiffe://example.com/foo/bar" { t.Fatalf("got unexpected name %s", principal.Name(ctx)) } }) } fulcio-1.6.5/pkg/identity/spiffe/principal.go000066400000000000000000000044541470150653400212160ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 spiffe import ( "context" "crypto/x509" "errors" "fmt" "net/url" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/spiffe/go-spiffe/v2/spiffeid" ) type principal struct { // spiffe ID id string // OIDC issuer url issuer string } func PrincipalFromIDToken(ctx context.Context, token *oidc.IDToken) (identity.Principal, error) { cfg, ok := config.FromContext(ctx).GetIssuer(token.Issuer) if !ok { return nil, errors.New("invalid configuration for OIDC ID Token issuer") } if err := validSpiffeID(token.Subject, cfg.SPIFFETrustDomain); err != nil { return nil, err } return principal{ id: token.Subject, issuer: token.Issuer, }, nil } func validSpiffeID(id, trustDomain string) error { parsedTrustDomain, err := spiffeid.TrustDomainFromString(trustDomain) if err != nil { return fmt.Errorf("unable to parse trust domain from configuration %s: %w", trustDomain, err) } parsedID, err := spiffeid.FromString(id) if err != nil { return fmt.Errorf("invalid spiffe ID provided: %s", id) } if parsedID.TrustDomain().Compare(parsedTrustDomain) != 0 { return fmt.Errorf("spiffe ID trust domain %s doesn't match configured trust domain %s", parsedID.TrustDomain(), trustDomain) } return nil } func (p principal) Name(_ context.Context) string { return p.id } func (p principal) Embed(_ context.Context, cert *x509.Certificate) error { parsed, err := url.Parse(p.id) if err != nil { return err } cert.URIs = []*url.URL{parsed} cert.ExtraExtensions, err = certificate.Extensions{ Issuer: p.issuer, }.Render() if err != nil { return err } return nil } fulcio-1.6.5/pkg/identity/spiffe/principal_test.go000066400000000000000000000152001470150653400222440ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 spiffe import ( "bytes" "context" "crypto/x509" "encoding/asn1" "errors" "fmt" "net/url" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/google/go-cmp/cmp" "github.com/sigstore/fulcio/pkg/config" ) func TestPrincipalFromIDToken(t *testing.T) { tests := map[string]struct { Token *oidc.IDToken Principal principal WantErr bool }{ `Valid token authenticates with correct claims`: { Token: &oidc.IDToken{Issuer: "https://issuer.example.com", Subject: "spiffe://example.com/foo/bar"}, Principal: principal{ issuer: "https://issuer.example.com", id: "spiffe://example.com/foo/bar", }, WantErr: false, }, `Issuer URL mismatch should error`: { Token: &oidc.IDToken{Issuer: "https://foo.example.com", Subject: "spiffe://example.com/foo/bar"}, WantErr: true, }, `Incorrect trust domain should error`: { Token: &oidc.IDToken{Issuer: "https://issuer.example.com", Subject: "spiffe://foo.example.com/foo/bar"}, WantErr: true, }, `Invalid ID should error`: { Token: &oidc.IDToken{Issuer: "https://issuer.example.com", Subject: "not-a-spiffe-id"}, WantErr: true, }, } cfg := &config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://issuer.example.com": { IssuerURL: "https://issuer.example.com", ClientID: "sigstore", Type: "spiffe", SPIFFETrustDomain: "example.com", }, }, } ctx := config.With(context.Background(), cfg) for name, test := range tests { t.Run(name, func(t *testing.T) { untyped, err := PrincipalFromIDToken(ctx, test.Token) if err != nil { if !test.WantErr { t.Fatal("didn't expect error", err) } return } if err == nil && test.WantErr { t.Fatal("expected error but got none") } p, ok := untyped.(principal) if !ok { t.Errorf("Got wrong principal type %v", untyped) } if p != test.Principal { t.Errorf("got %v principal and expected %v", p, test.Principal) } }) } } func TestName(t *testing.T) { tests := map[string]struct { Token *oidc.IDToken ExpectedName string }{ `Valid token authenticates with correct claims`: { Token: &oidc.IDToken{Issuer: "https://issuer.example.com", Subject: "spiffe://example.com/foo/bar"}, ExpectedName: "spiffe://example.com/foo/bar", }, } cfg := &config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://issuer.example.com": { IssuerURL: "https://issuer.example.com", ClientID: "sigstore", Type: "spiffe", SPIFFETrustDomain: "example.com", }, }, } ctx := config.With(context.Background(), cfg) for name, test := range tests { t.Run(name, func(t *testing.T) { untyped, err := PrincipalFromIDToken(ctx, test.Token) if err != nil { t.Fatal(err) } if gotName := untyped.Name(ctx); gotName != test.ExpectedName { t.Errorf("got %s and expected %s", gotName, test.ExpectedName) } }) } } func TestEmbed(t *testing.T) { tests := map[string]struct { Principal principal WantErr bool WantFacts map[string]func(x509.Certificate) error }{ `Good spiffe challenge`: { Principal: principal{ issuer: `example.com`, id: `spiffe://example.com/foo/bar`, }, WantErr: false, WantFacts: map[string]func(x509.Certificate) error{ `Issuer is example.com`: factIssuerIs(`example.com`), `SAN is spiffe://example.com/foo/bar`: func(cert x509.Certificate) error { WantURI, err := url.Parse("spiffe://example.com/foo/bar") if err != nil { return err } if len(cert.URIs) != 1 { return errors.New("no URI SAN set") } if diff := cmp.Diff(cert.URIs[0], WantURI); diff != "" { return errors.New(diff) } return nil }, }, }, `Spiffe value with bad URL fails`: { Principal: principal{ issuer: `example.com`, id: "\nbadurl", }, WantErr: true, }, `Empty issuer url should fail to render extensions`: { Principal: principal{ issuer: "", id: "spiffe://example.com/foo/bar", }, WantErr: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { var cert x509.Certificate err := test.Principal.Embed(context.TODO(), &cert) if err != nil { if !test.WantErr { t.Error(err) } return } else if test.WantErr { t.Error("expected error") } for factName, fact := range test.WantFacts { t.Run(factName, func(t *testing.T) { if err := fact(cert); err != nil { t.Error(err) } }) } }) } } func factIssuerIs(issuer string) func(x509.Certificate) error { return factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, issuer) } func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { if !bytes.Equal(ext.Value, []byte(value)) { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, ext.Value) } return nil } } return errors.New("extension not set") } } func TestValidSpiffeID(t *testing.T) { tests := map[string]struct { ID string TrustDomain string WantErr bool }{ `Valid ID with matching trust domain results in no error`: { ID: `spiffe://foo.com/bar`, TrustDomain: `foo.com`, WantErr: false, }, `Invalid trust domain errors`: { ID: `spiffe://foo.com/bar`, TrustDomain: `not#a#trust#domain`, WantErr: true, }, `Trust domain mismatch should error`: { ID: `spiffe://foo.com/bar`, TrustDomain: `bar.com`, WantErr: true, }, `Invalid spiffe id should error`: { ID: `not#a#spiffe#id`, TrustDomain: `bar.com`, WantErr: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { err := validSpiffeID(test.ID, test.TrustDomain) if err != nil { if !test.WantErr { t.Error("unepected error", err) } return } if err == nil && test.WantErr { t.Error("expected err") } }) } } fulcio-1.6.5/pkg/identity/uri/000077500000000000000000000000001470150653400162225ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/uri/issuer.go000066400000000000000000000022411470150653400200620ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 uri import ( "context" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/base" ) type uriIssuer struct { identity.Issuer } func Issuer(issuerURL string) identity.Issuer { return &uriIssuer{base.Issuer(issuerURL)} } func (e *uriIssuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { idtoken, err := identity.Authorize(ctx, token, opts...) if err != nil { return nil, err } return PrincipalFromIDToken(ctx, idtoken) } fulcio-1.6.5/pkg/identity/uri/issuer_test.go000066400000000000000000000040041470150653400211200ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 uri import ( "context" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) func TestIssuer(t *testing.T) { ctx := context.Background() url := "test-issuer-url" issuer := Issuer(url) // test the Match function t.Run("match", func(t *testing.T) { if matches := issuer.Match(ctx, url); !matches { t.Fatal("expected url to match but it doesn't") } if matches := issuer.Match(ctx, "some-other-url"); matches { t.Fatal("expected match to fail but it didn't") } }) t.Run("authenticate", func(t *testing.T) { token := &oidc.IDToken{ Issuer: "https://accounts.example.com", Subject: "https://example.com/users/1", } cfg := &config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://accounts.example.com": { IssuerURL: "https://accounts.example.com", ClientID: "sigstore", SubjectDomain: "https://example.com", Type: config.IssuerTypeURI, }, }, } ctx := config.With(context.Background(), cfg) identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { return token, nil } principal, err := issuer.Authenticate(ctx, "token") if err != nil { t.Fatal(err) } if principal.Name(ctx) != "https://example.com/users/1" { t.Fatalf("got unexpected name %s", principal.Name(ctx)) } }) } fulcio-1.6.5/pkg/identity/uri/principal.go000066400000000000000000000045411470150653400205360ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 uri import ( "context" "crypto/x509" "errors" "fmt" "net/url" "github.com/asaskevich/govalidator" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) type principal struct { issuer string uri string } func PrincipalFromIDToken(ctx context.Context, token *oidc.IDToken) (identity.Principal, error) { uriWithSubject := token.Subject cfg, ok := config.FromContext(ctx).GetIssuer(token.Issuer) if !ok { return nil, errors.New("invalid configuration for OIDC ID Token issuer") } if govalidator.IsEmail(uriWithSubject) { return nil, fmt.Errorf("uri subject should not be an email address") } // The subject hostname must exactly match the subject domain from the configuration uSubject, err := url.Parse(uriWithSubject) if err != nil { return nil, err } uDomain, err := url.Parse(cfg.SubjectDomain) if err != nil { return nil, err } if uSubject.Scheme != uDomain.Scheme { return nil, fmt.Errorf("subject URI scheme (%s) must match expected domain URI scheme (%s)", uSubject.Scheme, uDomain.Scheme) } if uSubject.Hostname() != uDomain.Hostname() { return nil, fmt.Errorf("subject hostname (%s) must match expected domain (%s)", uSubject.Hostname(), uDomain.Hostname()) } return principal{ issuer: token.Issuer, uri: uriWithSubject, }, nil } func (p principal) Name(_ context.Context) string { return p.uri } func (p principal) Embed(_ context.Context, cert *x509.Certificate) error { subjectURI, err := url.Parse(p.uri) if err != nil { return err } cert.URIs = []*url.URL{subjectURI} cert.ExtraExtensions, err = certificate.Extensions{ Issuer: p.issuer, }.Render() if err != nil { return err } return nil } fulcio-1.6.5/pkg/identity/uri/principal_test.go000066400000000000000000000140571470150653400216000ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 uri import ( "bytes" "context" "crypto/x509" "encoding/asn1" "errors" "fmt" "net/url" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/google/go-cmp/cmp" "github.com/sigstore/fulcio/pkg/config" ) func TestPrincipalFromIDToken(t *testing.T) { tests := map[string]struct { Token *oidc.IDToken Principal principal WantErr bool }{ `Valid token authenticates with correct claims`: { Token: &oidc.IDToken{Issuer: "https://accounts.example.com", Subject: "https://example.com/users/1"}, Principal: principal{ issuer: "https://accounts.example.com", uri: "https://example.com/users/1", }, WantErr: false, }, `Issuer URL mismatch should error`: { Token: &oidc.IDToken{Issuer: "https://notaccounts.example.com", Subject: "https://example.com/users/1"}, WantErr: true, }, `Subject as an email address should error`: { Token: &oidc.IDToken{Issuer: "https://accounts.example.com", Subject: "user@example.com"}, WantErr: true, }, `Incorrect subject domain hostname should error`: { Token: &oidc.IDToken{Issuer: "https://accounts.example.com", Subject: "https://notexample.com/users/1"}, WantErr: true, }, `Incorrect subject domain scheme should error`: { Token: &oidc.IDToken{Issuer: "https://accounts.example.com", Subject: "http://example.com/users/1"}, WantErr: true, }, `Invalid uri should error`: { Token: &oidc.IDToken{Issuer: "https://accounts.example.com", Subject: "not\n#a#uri"}, WantErr: true, }, } cfg := &config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://accounts.example.com": { IssuerURL: "https://accounts.example.com", ClientID: "sigstore", SubjectDomain: "https://example.com", Type: config.IssuerTypeURI, }, }, } ctx := config.With(context.Background(), cfg) for name, test := range tests { t.Run(name, func(t *testing.T) { untyped, err := PrincipalFromIDToken(ctx, test.Token) if err != nil { if !test.WantErr { t.Fatal("didn't expect error", err) } return } if err == nil && test.WantErr { t.Fatal("expected error but got none") } p, ok := untyped.(principal) if !ok { t.Errorf("Got wrong principal type %v", untyped) } if p != test.Principal { t.Errorf("got %v principal and expected %v", p, test.Principal) } }) } } func TestName(t *testing.T) { tests := map[string]struct { Token *oidc.IDToken ExpectedName string }{ `Valid token authenticates with correct claims`: { Token: &oidc.IDToken{Issuer: "https://accounts.example.com", Subject: "https://example.com/users/1"}, ExpectedName: "https://example.com/users/1", }, } cfg := &config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://accounts.example.com": { IssuerURL: "https://accounts.example.com", ClientID: "sigstore", SubjectDomain: "https://example.com", Type: config.IssuerTypeURI, }, }, } ctx := config.With(context.Background(), cfg) for name, test := range tests { t.Run(name, func(t *testing.T) { p, err := PrincipalFromIDToken(ctx, test.Token) if err != nil { t.Fatal("didn't expect error", err) } if p.Name(ctx) != test.ExpectedName { t.Errorf("got %v principal name and expected %v", p.Name(ctx), test.ExpectedName) } }) } } func TestEmbed(t *testing.T) { tests := map[string]struct { Principal principal WantErr bool WantFacts map[string]func(x509.Certificate) error }{ `Valid uri challenge`: { Principal: principal{ issuer: `https://accounts.example.com`, uri: `https://example.com/users/1`, }, WantErr: false, WantFacts: map[string]func(x509.Certificate) error{ `Issuer is example.com`: factIssuerIs(`https://accounts.example.com`), `SAN is https://example.com/users/1`: func(cert x509.Certificate) error { WantURI, err := url.Parse("https://example.com/users/1") if err != nil { return err } if len(cert.URIs) != 1 { return errors.New("no URI SAN set") } if diff := cmp.Diff(cert.URIs[0], WantURI); diff != "" { return errors.New(diff) } return nil }, }, }, `invalid uri fails`: { Principal: principal{ issuer: `example.com`, uri: "\nbadurl", }, WantErr: true, }, `Empty issuer url should fail to render extensions`: { Principal: principal{ issuer: "", uri: "https://example.com/foo/bar", }, WantErr: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { var cert x509.Certificate err := test.Principal.Embed(context.TODO(), &cert) if err != nil { if !test.WantErr { t.Error(err) } return } else if test.WantErr { t.Error("expected error") } for factName, fact := range test.WantFacts { t.Run(factName, func(t *testing.T) { if err := fact(cert); err != nil { t.Error(err) } }) } }) } } func factIssuerIs(issuer string) func(x509.Certificate) error { return factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, issuer) } func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { if !bytes.Equal(ext.Value, []byte(value)) { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, ext.Value) } return nil } } return errors.New("extension not set") } } fulcio-1.6.5/pkg/identity/username/000077500000000000000000000000001470150653400172425ustar00rootroot00000000000000fulcio-1.6.5/pkg/identity/username/issuer.go000066400000000000000000000022651470150653400211100ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 username import ( "context" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/base" ) type usernameIssuer struct { identity.Issuer } func Issuer(issuerURL string) identity.Issuer { return &usernameIssuer{base.Issuer(issuerURL)} } func (e *usernameIssuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { idtoken, err := identity.Authorize(ctx, token, opts...) if err != nil { return nil, err } return PrincipalFromIDToken(ctx, idtoken) } fulcio-1.6.5/pkg/identity/username/issuer_test.go000066400000000000000000000037321470150653400221470ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 username import ( "context" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" ) func TestIssuer(t *testing.T) { ctx := context.Background() url := "test-issuer-url" issuer := Issuer(url) // test the Match function t.Run("match", func(t *testing.T) { if matches := issuer.Match(ctx, url); !matches { t.Fatal("expected url to match but it doesn't") } if matches := issuer.Match(ctx, "some-other-url"); matches { t.Fatal("expected match to fail but it didn't") } }) t.Run("authenticate", func(t *testing.T) { token := &oidc.IDToken{ Issuer: "https://accounts.example.com", Subject: "alice", } cfg := &config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://accounts.example.com": { IssuerURL: "https://accounts.example.com", ClientID: "sigstore", SubjectDomain: "example.com", Type: config.IssuerTypeUsername, }, }, } ctx := config.With(context.Background(), cfg) identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { return token, nil } principal, err := issuer.Authenticate(ctx, "token") if err != nil { t.Fatal(err) } if principal.Name(ctx) != "alice" { t.Fatalf("got unexpected name %s", principal.Name(ctx)) } }) } fulcio-1.6.5/pkg/identity/username/principal.go000066400000000000000000000042401470150653400215520ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 username import ( "context" "crypto/x509" "crypto/x509/pkix" "errors" "fmt" "strings" "github.com/asaskevich/govalidator" "github.com/coreos/go-oidc/v3/oidc" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/sigstore/pkg/cryptoutils" ) type principal struct { issuer string username string unIdentity string } func PrincipalFromIDToken(ctx context.Context, token *oidc.IDToken) (identity.Principal, error) { username := token.Subject if strings.Contains(username, "!") { return nil, errors.New("username cannot contain ! character") } if govalidator.IsEmail(username) { return nil, fmt.Errorf("uri subject should not be an email address") } cfg, ok := config.FromContext(ctx).GetIssuer(token.Issuer) if !ok { return nil, errors.New("invalid configuration for OIDC ID Token issuer") } unIdentity := fmt.Sprintf("%s!%s", username, cfg.SubjectDomain) return principal{ issuer: token.Issuer, username: username, unIdentity: unIdentity, }, nil } func (p principal) Name(context.Context) string { return p.username } func (p principal) Embed(_ context.Context, cert *x509.Certificate) error { var exts []pkix.Extension ext, err := cryptoutils.MarshalOtherNameSAN(p.unIdentity, true /*critical*/) if err != nil { return err } exts = append(exts, *ext) issuerExt, err := certificate.Extensions{ Issuer: p.issuer, }.Render() if err != nil { return err } exts = append(exts, issuerExt...) cert.ExtraExtensions = exts return nil } fulcio-1.6.5/pkg/identity/username/principal_test.go000066400000000000000000000131741470150653400226170ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 username import ( "bytes" "context" "crypto/x509" "encoding/asn1" "errors" "fmt" "testing" "github.com/coreos/go-oidc/v3/oidc" "github.com/google/go-cmp/cmp" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/sigstore/pkg/cryptoutils" ) func TestPrincipalFromIDToken(t *testing.T) { tests := map[string]struct { Token *oidc.IDToken Principal principal WantErr bool }{ `Valid token authenticates with correct claims`: { Token: &oidc.IDToken{Issuer: "https://accounts.example.com", Subject: "alice"}, Principal: principal{ issuer: "https://accounts.example.com", username: "alice", unIdentity: "alice!example.com", }, WantErr: false, }, `username with ! character should error`: { Token: &oidc.IDToken{Issuer: "https://accounts.example.com", Subject: "alice!"}, WantErr: true, }, `username as an email address should error`: { Token: &oidc.IDToken{Issuer: "https://accounts.example.com", Subject: "alice@example.com"}, WantErr: true, }, `invalid issuer should error`: { Token: &oidc.IDToken{Issuer: "https://notaccounts.example.com", Subject: "alice"}, WantErr: true, }, } cfg := &config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://accounts.example.com": { IssuerURL: "https://accounts.example.com", ClientID: "sigstore", SubjectDomain: "example.com", Type: config.IssuerTypeUsername, }, }, } ctx := config.With(context.Background(), cfg) for name, test := range tests { t.Run(name, func(t *testing.T) { untyped, err := PrincipalFromIDToken(ctx, test.Token) if err != nil { if !test.WantErr { t.Fatal("didn't expect error", err) } return } if err == nil && test.WantErr { t.Fatal("expected error but got none") } p, ok := untyped.(principal) if !ok { t.Errorf("Got wrong principal type %v", untyped) } if p != test.Principal { t.Errorf("got %v principal and expected %v", p, test.Principal) } }) } } func TestName(t *testing.T) { tests := map[string]struct { Token *oidc.IDToken ExpectedName string }{ `Valid token authenticates with correct claims`: { Token: &oidc.IDToken{Issuer: "https://accounts.example.com", Subject: "alice"}, ExpectedName: "alice", }, } cfg := &config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://accounts.example.com": { IssuerURL: "https://accounts.example.com", ClientID: "sigstore", SubjectDomain: "example.com", Type: config.IssuerTypeUsername, }, }, } ctx := config.With(context.Background(), cfg) for name, test := range tests { t.Run(name, func(t *testing.T) { p, err := PrincipalFromIDToken(ctx, test.Token) if err != nil { t.Fatal("didn't expect error", err) } if p.Name(ctx) != test.ExpectedName { t.Errorf("got %v principal name and expected %v", p.Name(ctx), test.ExpectedName) } }) } } func TestEmbed(t *testing.T) { tests := map[string]struct { Principal principal WantErr bool WantFacts map[string]func(x509.Certificate) error }{ `Valid uri challenge`: { Principal: principal{ issuer: `https://accounts.example.com`, username: "alice", unIdentity: "alice!example.com", }, WantErr: false, WantFacts: map[string]func(x509.Certificate) error{ `Issuer is example.com`: factIssuerIs(`https://accounts.example.com`), `SAN is alice!example.com`: func(cert x509.Certificate) error { otherName, err := cryptoutils.UnmarshalOtherNameSAN(cert.ExtraExtensions) if err != nil { return err } if len(cert.EmailAddresses) != 0 { return errors.New("unexpected email address SAN") } if diff := cmp.Diff(otherName, "alice!example.com"); diff != "" { return errors.New(diff) } return nil }, }, }, `Empty issuer url should fail to render extensions`: { Principal: principal{ issuer: "", unIdentity: "alice!example.com", username: "alice", }, WantErr: true, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { var cert x509.Certificate err := test.Principal.Embed(context.TODO(), &cert) if err != nil { if !test.WantErr { t.Error(err) } return } else if test.WantErr { t.Error("expected error") } for factName, fact := range test.WantFacts { t.Run(factName, func(t *testing.T) { if err := fact(cert); err != nil { t.Error(err) } }) } }) } } func factIssuerIs(issuer string) func(x509.Certificate) error { return factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, issuer) } func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { return func(cert x509.Certificate) error { for _, ext := range cert.ExtraExtensions { if ext.Id.Equal(oid) { if !bytes.Equal(ext.Value, []byte(value)) { return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, ext.Value) } return nil } } return errors.New("extension not set") } } fulcio-1.6.5/pkg/log/000077500000000000000000000000001470150653400143535ustar00rootroot00000000000000fulcio-1.6.5/pkg/log/log.go000066400000000000000000000060461470150653400154710ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 log import ( "context" "log" "github.com/goadesign/goa/grpc/middleware" grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap" "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap" "go.uber.org/zap" "go.uber.org/zap/zapcore" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" ) // Logger set the default logger to development mode var Logger *zap.SugaredLogger func init() { ConfigureLogger("dev") } func ConfigureLogger(logType string) { var cfg zap.Config if logType == "prod" { cfg = zap.NewProductionConfig() cfg.EncoderConfig.LevelKey = "severity" cfg.EncoderConfig.MessageKey = "message" } else { cfg = zap.NewDevelopmentConfig() cfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder cfg.OutputPaths = []string{"stdout"} } logger, err := cfg.Build() if err != nil { log.Fatalln("createLogger", err) } Logger = logger.Sugar() } var CliLogger = createCliLogger() func createCliLogger() *zap.SugaredLogger { cfg := zap.NewDevelopmentConfig() cfg.EncoderConfig.TimeKey = "" cfg.EncoderConfig.LevelKey = "" cfg.DisableCaller = true logger, err := cfg.Build() if err != nil { log.Fatalln("createLogger", err) } return logger.Sugar() } type requestIDMetadataKeyType string const ( requestIDMetadataKey requestIDMetadataKeyType = middleware.RequestIDMetadataKey ) func ContextLogger(ctx context.Context) *zap.SugaredLogger { proposedLogger := Logger if ctx != nil { if md, ok := metadata.FromIncomingContext(ctx); ok { val := md.Get(string(requestIDMetadataKey)) if len(val) == 1 { proposedLogger = proposedLogger.With(zap.String("requestID", val[0])) } } } return proposedLogger } func SetupGRPCLogging() (*zap.Logger, []grpc_zap.Option) { var options []grpc_zap.Option options = append(options, grpc_zap.WithDecider(func(_ string, _ error) bool { // TODO: implement filters to eliminate health check log statements return true })) options = append(options, grpc_zap.WithMessageProducer( func(ctx context.Context, msg string, _ zapcore.Level, code codes.Code, err error, duration zapcore.Field) { var requestID zap.Field if md, ok := metadata.FromIncomingContext(ctx); ok { val := md.Get(string(requestIDMetadataKey)) if len(val) == 1 { requestID = zap.String("requestID", val[0]) } } ctxzap.Extract(ctx).Debug(msg, zap.Error(err), zap.String("grpc.code", code.String()), requestID, duration) })) return Logger.Desugar(), options } fulcio-1.6.5/pkg/oauthflow/000077500000000000000000000000001470150653400156025ustar00rootroot00000000000000fulcio-1.6.5/pkg/oauthflow/oidc.go000066400000000000000000000033671470150653400170600ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 oauthflow import ( "errors" "fmt" "github.com/PaesslerAG/jsonpath" "github.com/coreos/go-oidc/v3/oidc" ) type stringAsBool bool func (sb *stringAsBool) UnmarshalJSON(b []byte) error { switch string(b) { case "true", `"true"`, "True", `"True"`: *sb = true case "false", `"false"`, "False", `"False"`: *sb = false default: return errors.New("invalid value for boolean") } return nil } func EmailFromIDToken(token *oidc.IDToken) (string, bool, error) { // Extract custom claims var claims struct { Email string `json:"email"` Verified stringAsBool `json:"email_verified"` } if err := token.Claims(&claims); err != nil { return "", false, err } if claims.Email == "" { return "", false, errors.New("token missing email claim") } return claims.Email, bool(claims.Verified), nil } func IssuerFromIDToken(token *oidc.IDToken, claimJSONPath string) (string, error) { if claimJSONPath == "" { return token.Issuer, nil } v := interface{}(nil) if err := token.Claims(&v); err != nil { return "", err } result, err := jsonpath.Get(claimJSONPath, v) if err != nil { return "", err } return fmt.Sprintf("%v", result), nil } fulcio-1.6.5/pkg/oauthflow/oidc_test.go000066400000000000000000000077741470150653400201250ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 oauthflow import ( "errors" "reflect" "strings" "testing" "unsafe" "github.com/coreos/go-oidc/v3/oidc" "github.com/magiconair/properties/assert" ) // reflect hack because "claims" field is unexported by oidc IDToken // https://github.com/coreos/go-oidc/pull/329 func updateIDToken(idToken *oidc.IDToken, fieldName string, data []byte) { val := reflect.Indirect(reflect.ValueOf(idToken)) member := val.FieldByName(fieldName) pointer := unsafe.Pointer(member.UnsafeAddr()) realPointer := (*[]byte)(pointer) *realPointer = data } func TestEmailFromIDToken(t *testing.T) { tests := []struct { name string inputClaims []byte expectedEmail string expectedVerified bool expectedErr error }{{ name: "token with nil claims", inputClaims: nil, expectedEmail: "", expectedVerified: false, expectedErr: errors.New("oidc: claims not set"), }, { name: "token with empty/no claims", inputClaims: []byte(`{}`), expectedEmail: "", expectedVerified: false, expectedErr: errors.New("token missing email claim"), }, { name: "token with non-verified claims set", inputClaims: []byte(`{"email":"John.Doe@email.com"}`), expectedEmail: "John.Doe@email.com", expectedVerified: false, expectedErr: nil, }, { name: "token missing email claim", inputClaims: []byte(`{"email_verified": true}`), expectedErr: errors.New("token missing email claim"), }, { name: "token with claims set", inputClaims: []byte(`{"email":"John.Doe@email.com", "email_verified":true}`), expectedEmail: "John.Doe@email.com", expectedVerified: true, expectedErr: nil, }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { idToken := &oidc.IDToken{} updateIDToken(idToken, "claims", tt.inputClaims) actualEmail, actualVerified, actualErr := EmailFromIDToken(idToken) assert.Equal(t, actualEmail, tt.expectedEmail) assert.Equal(t, actualVerified, tt.expectedVerified) if actualErr != nil { assert.Equal(t, actualErr.Error(), tt.expectedErr.Error()) } else { assert.Equal(t, actualErr, tt.expectedErr) } }) } } func TestIssuerFromIDToken(t *testing.T) { expectedIss := "issuer" idToken := &oidc.IDToken{Issuer: expectedIss} // Test with no claims path iss, err := IssuerFromIDToken(idToken, "") if err != nil { t.Fatalf("unexpected error generating issuer: %v", err) } if iss != expectedIss { t.Fatalf("unexpected issuer, expected %s, got %s", expectedIss, iss) } // append additional claims otherExpectedIss := "otherIssuer" updateIDToken(idToken, "claims", []byte(`{"other_issuer":"otherIssuer"}`)) iss, err = IssuerFromIDToken(idToken, "$.other_issuer") if err != nil { t.Fatalf("unexpected error generating issuer: %v", err) } if iss != otherExpectedIss { t.Fatalf("unexpected issuer, expected %s, got %s", otherExpectedIss, iss) } // failure with invalid claim path _, err = IssuerFromIDToken(idToken, "$.invalid") if err == nil || !strings.Contains(err.Error(), "unknown key invalid") { t.Fatalf("expected error fetching invalid key, got %v", err) } // failure with invalid claims updateIDToken(idToken, "claims", []byte(`{`)) _, err = IssuerFromIDToken(idToken, "$.other_issuer") if err == nil || !strings.Contains(err.Error(), "unexpected end of JSON input") { t.Fatalf("expected error with malformed ID token, got %v", err) } } fulcio-1.6.5/pkg/server/000077500000000000000000000000001470150653400151005ustar00rootroot00000000000000fulcio-1.6.5/pkg/server/error.go000066400000000000000000000041401470150653400165570ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 server import ( "context" "github.com/sigstore/fulcio/pkg/log" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) const ( invalidSignature = "The signature supplied in the request could not be verified" invalidPublicKey = "The public key supplied in the request could not be parsed" invalidCSR = "The certificate signing request could not be parsed" failedToEnterCertInCTL = "Error entering certificate in CTL" failedToMarshalSCT = "Error marshaling signed certificate timestamp" failedToMarshalCert = "Error marshaling code signing certificate" insecurePublicKey = "The public key supplied in the request is insecure" //nolint invalidCredentials = "There was an error processing the credentials for this request" // nolint invalidIdentityToken = "There was an error processing the identity token" genericCAError = "error communicating with CA backend" retrieveTrustBundleCAError = "error retrieving trust bundle from CA backend" marshalingCertificateChainBundleCAError = "error marshaling the certificate chain of the bundle" loadingFulcioConfigurationError = "error loading fulcio configuration" ) func handleFulcioGRPCError(ctx context.Context, code codes.Code, err error, message string, fields ...interface{}) error { log.ContextLogger(ctx).Errorw(err.Error(), append([]interface{}{"code", code, "clientMessage", message, "error", err}, fields...)...) return status.Error(code, message) } fulcio-1.6.5/pkg/server/grpc_server.go000066400000000000000000000233231470150653400177530ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 server import ( "context" "crypto" "encoding/json" "errors" "fmt" ctclient "github.com/google/certificate-transparency-go/client" health "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" certauth "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/challenges" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/ctl" fulciogrpc "github.com/sigstore/fulcio/pkg/generated/protobuf" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/log" "github.com/sigstore/sigstore/pkg/cryptoutils" ) type GRPCCAServer interface { fulciogrpc.CAServer health.HealthServer } func NewGRPCCAServer(ct *ctclient.LogClient, ca certauth.CertificateAuthority, ip identity.IssuerPool) GRPCCAServer { return &grpcaCAServer{ ct: ct, ca: ca, IssuerPool: ip, } } const ( MetadataOIDCTokenKey = "oidcidentitytoken" ) type grpcaCAServer struct { fulciogrpc.UnimplementedCAServer ct *ctclient.LogClient ca certauth.CertificateAuthority identity.IssuerPool } func (g *grpcaCAServer) CreateSigningCertificate(ctx context.Context, request *fulciogrpc.CreateSigningCertificateRequest) (*fulciogrpc.SigningCertificate, error) { logger := log.ContextLogger(ctx) // OIDC token either is passed in gRPC field or was extracted from HTTP headers token := "" if request.Credentials != nil { token = request.Credentials.GetOidcIdentityToken() } if token == "" { if md, ok := metadata.FromIncomingContext(ctx); ok { vals := md.Get(MetadataOIDCTokenKey) if len(vals) == 1 { token = vals[0] } } } // Authenticate OIDC ID token by checking signature principal, err := g.IssuerPool.Authenticate(ctx, token) if err != nil { return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, invalidIdentityToken) } var publicKey crypto.PublicKey // Verify caller is in possession of their private key and extract // public key from request. if len(request.GetCertificateSigningRequest()) > 0 { // Option 1: Verify CSR csr, err := cryptoutils.ParseCSR(request.GetCertificateSigningRequest()) if err != nil { return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, invalidCSR) } // Parse public key and check for weak key parameters publicKey = csr.PublicKey if err := cryptoutils.ValidatePubKey(publicKey); err != nil { return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, insecurePublicKey) } if err := csr.CheckSignature(); err != nil { return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, invalidSignature) } } else { // Option 2: Check the signature for proof of possession of a private key var ( pubKeyContent string proofOfPossession []byte err error ) if request.GetPublicKeyRequest() != nil { if request.GetPublicKeyRequest().PublicKey != nil { pubKeyContent = request.GetPublicKeyRequest().PublicKey.Content } proofOfPossession = request.GetPublicKeyRequest().ProofOfPossession } // Parse public key and check for weak parameters publicKey, err = challenges.ParsePublicKey(pubKeyContent) if err != nil { return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, invalidPublicKey) } if err := cryptoutils.ValidatePubKey(publicKey); err != nil { return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, insecurePublicKey) } // Check proof of possession signature if err := challenges.CheckSignature(publicKey, proofOfPossession, principal.Name(ctx)); err != nil { return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, invalidSignature) } } var csc *certauth.CodeSigningCertificate var sctBytes []byte result := &fulciogrpc.SigningCertificate{} // For CAs that do not support embedded SCTs or if the CT log is not configured if sctCa, ok := g.ca.(certauth.EmbeddedSCTCA); !ok || g.ct == nil { // currently configured CA doesn't support pre-certificate flow required to embed SCT in final certificate csc, err = g.ca.CreateCertificate(ctx, principal, publicKey) if err != nil { // if the error was due to invalid input in the request, return HTTP 400 if _, ok := err.(certauth.ValidationError); ok { return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, err.Error()) } err = fmt.Errorf("Error creating certificate: %w", err) // otherwise return a 500 error to reflect that it is a transient server issue that the client can't resolve return nil, handleFulcioGRPCError(ctx, codes.Internal, err, genericCAError) } // Submit to CTL if g.ct != nil { sct, err := g.ct.AddChain(ctx, ctl.BuildCTChain(csc.FinalCertificate, csc.FinalChain)) if err != nil { return nil, handleFulcioGRPCError(ctx, codes.Internal, err, failedToEnterCertInCTL) } // convert to AddChainResponse because Cosign expects this struct. addChainResp, err := ctl.ToAddChainResponse(sct) if err != nil { return nil, handleFulcioGRPCError(ctx, codes.Internal, err, failedToMarshalSCT) } sctBytes, err = json.Marshal(addChainResp) if err != nil { return nil, handleFulcioGRPCError(ctx, codes.Internal, err, failedToMarshalSCT) } } else { logger.Info("Skipping CT log upload.") } finalPEM, err := csc.CertPEM() if err != nil { return nil, handleFulcioGRPCError(ctx, codes.Internal, err, failedToMarshalCert) } finalChainPEM, err := csc.ChainPEM() if err != nil { return nil, handleFulcioGRPCError(ctx, codes.Internal, err, failedToMarshalCert) } result.Certificate = &fulciogrpc.SigningCertificate_SignedCertificateDetachedSct{ SignedCertificateDetachedSct: &fulciogrpc.SigningCertificateDetachedSCT{ Chain: &fulciogrpc.CertificateChain{ Certificates: append([]string{finalPEM}, finalChainPEM...), }, }, } if len(sctBytes) > 0 { result.GetSignedCertificateDetachedSct().SignedCertificateTimestamp = sctBytes } } else { precert, err := sctCa.CreatePrecertificate(ctx, principal, publicKey) if err != nil { // if the error was due to invalid input in the request, return HTTP 400 if _, ok := err.(certauth.ValidationError); ok { return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, err.Error()) } err = fmt.Errorf("Error creating a pre-certificate and chain: %w", err) // otherwise return a 500 error to reflect that it is a transient server issue that the client can't resolve return nil, handleFulcioGRPCError(ctx, codes.Internal, err, genericCAError) } // submit precertificate and chain to CT log sct, err := g.ct.AddPreChain(ctx, ctl.BuildCTChain(precert.PreCert, precert.CertChain)) if err != nil { return nil, handleFulcioGRPCError(ctx, codes.Internal, err, failedToEnterCertInCTL) } csc, err = sctCa.IssueFinalCertificate(ctx, precert, sct) if err != nil { err = fmt.Errorf("Error issuing final certificate using the pre-certificate with CA backend: %w", err) return nil, handleFulcioGRPCError(ctx, codes.Internal, err, genericCAError) } finalPEM, err := csc.CertPEM() if err != nil { return nil, handleFulcioGRPCError(ctx, codes.Internal, err, failedToMarshalCert) } finalChainPEM, err := csc.ChainPEM() if err != nil { return nil, handleFulcioGRPCError(ctx, codes.Internal, err, failedToMarshalCert) } result.Certificate = &fulciogrpc.SigningCertificate_SignedCertificateEmbeddedSct{ SignedCertificateEmbeddedSct: &fulciogrpc.SigningCertificateEmbeddedSCT{ Chain: &fulciogrpc.CertificateChain{ Certificates: append([]string{finalPEM}, finalChainPEM...), }, }, } } metricNewEntries.Inc() return result, nil } func (g *grpcaCAServer) GetTrustBundle(ctx context.Context, _ *fulciogrpc.GetTrustBundleRequest) (*fulciogrpc.TrustBundle, error) { trustBundle, err := g.ca.TrustBundle(ctx) if err != nil { return nil, handleFulcioGRPCError(ctx, codes.Internal, err, retrieveTrustBundleCAError) } resp := &fulciogrpc.TrustBundle{ Chains: []*fulciogrpc.CertificateChain{}, } for _, chain := range trustBundle { certChain := &fulciogrpc.CertificateChain{} for _, cert := range chain { certPEM, err := cryptoutils.MarshalCertificateToPEM(cert) if err != nil { return nil, handleFulcioGRPCError(ctx, codes.Internal, err, marshalingCertificateChainBundleCAError) } certChain.Certificates = append(certChain.Certificates, string(certPEM)) } resp.Chains = append(resp.Chains, certChain) } return resp, nil } func (g *grpcaCAServer) GetConfiguration(ctx context.Context, _ *fulciogrpc.GetConfigurationRequest) (*fulciogrpc.Configuration, error) { cfg := config.FromContext(ctx) if cfg == nil { err := errors.New("configuration not loaded") return nil, handleFulcioGRPCError(ctx, codes.Internal, err, loadingFulcioConfigurationError) } return &fulciogrpc.Configuration{ Issuers: cfg.ToIssuers(), }, nil } func (g *grpcaCAServer) Check(_ context.Context, _ *health.HealthCheckRequest) (*health.HealthCheckResponse, error) { return &health.HealthCheckResponse{Status: health.HealthCheckResponse_SERVING}, nil } func (g *grpcaCAServer) Watch(_ *health.HealthCheckRequest, _ health.Health_WatchServer) error { return status.Error(codes.Unimplemented, "unimplemented") } fulcio-1.6.5/pkg/server/grpc_server_test.go000066400000000000000000002244641470150653400210230ustar00rootroot00000000000000// // Copyright 2021 The Sigstore 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 server import ( "context" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/json" "encoding/pem" "errors" "fmt" "net" "net/http" "net/http/httptest" "net/url" "reflect" "strings" "testing" "time" "chainguard.dev/sdk/uidp" "github.com/go-jose/go-jose/v4" "github.com/go-jose/go-jose/v4/jwt" ctclient "github.com/google/certificate-transparency-go/client" "github.com/google/certificate-transparency-go/jsonclient" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" "google.golang.org/grpc/test/bufconn" "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/ca/ephemeralca" "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/generated/protobuf" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/sigstore/pkg/cryptoutils" "google.golang.org/grpc/resolver" ) const ( expectedNoRootMessage = "rpc error: code = Internal desc = error communicating with CA backend" expectedTrustBundleMessage = "rpc error: code = Internal desc = error retrieving trust bundle from CA backend" bufSize = 1024 * 1024 ) func init() { resolver.SetDefaultScheme("passthrough") } var lis *bufconn.Listener func passFulcioConfigThruContext(cfg *config.FulcioConfig) grpc.UnaryServerInterceptor { return func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { // For each request, infuse context with our snapshot of the FulcioConfig. // TODO(mattmoor): Consider periodically (every minute?) refreshing the ConfigMap // from disk, so that we don't need to cycle pods to pick up config updates. // Alternately we could take advantage of Knative's configmap watcher. ctx = config.With(ctx, cfg) ctx, cancel := context.WithCancel(ctx) defer cancel() // Calls the inner handler return handler(ctx, req) } } func setupGRPCForTest(t *testing.T, cfg *config.FulcioConfig, ctl *ctclient.LogClient, ca ca.CertificateAuthority) (*grpc.Server, *grpc.ClientConn) { t.Helper() lis = bufconn.Listen(bufSize) s := grpc.NewServer(grpc.UnaryInterceptor(passFulcioConfigThruContext(cfg))) ip := NewIssuerPool(cfg) protobuf.RegisterCAServer(s, NewGRPCCAServer(ctl, ca, ip)) go func() { if err := s.Serve(lis); err != nil && !errors.Is(err, grpc.ErrServerStopped) { t.Errorf("Server exited with error: %v", err) } }() // Create a dial option using a custom dialer dialOptions := []grpc.DialOption{ grpc.WithContextDialer(bufDialer), grpc.WithTransportCredentials(insecure.NewCredentials()), } // Use grpc.NewClient to create the client connection conn, err := grpc.NewClient("passthrough", dialOptions...) if err != nil { t.Fatal("could not create grpc connection", err) } return s, conn } func bufDialer(ctx context.Context, _ string) (net.Conn, error) { return lis.DialContext(ctx) } func TestMissingGetTrustBundleFails(t *testing.T) { ctx := context.Background() cfg := &config.FulcioConfig{} server, conn := setupGRPCForTest(t, cfg, nil, &FailingCertificateAuthority{}) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) // Check that we get the CA root back as well. _, err := client.GetTrustBundle(ctx, &protobuf.GetTrustBundleRequest{}) if err == nil { t.Fatal("GetTrustBundle did not fail", err) } if err.Error() != expectedTrustBundleMessage { t.Errorf("got an unexpected error: %q wanted: %q", err, expectedTrustBundleMessage) } if status.Code(err) != codes.Internal { t.Fatalf("expected invalid argument, got %v", status.Code(err)) } } func TestGetTrustBundleSuccess(t *testing.T) { cfg := &config.FulcioConfig{} ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) root, err := client.GetTrustBundle(ctx, &protobuf.GetTrustBundleRequest{}) if err != nil { t.Fatal("GetTrustBundle failed", err) } if len(root.Chains) == 0 { t.Fatal("got back empty chain") } if len(root.Chains) != 1 { t.Fatal("got back more than one chain") } if len(root.Chains[0].Certificates) != 1 { t.Fatalf("expected 1 cert, found %d", len(root.Chains[0].Certificates)) } block, rest := pem.Decode([]byte(root.Chains[0].Certificates[0])) if block == nil { t.Fatal("did not find PEM data") } if len(rest) != 0 { t.Fatal("got more than bargained for, should only have one cert") } if block.Type != "CERTIFICATE" { t.Fatalf("unexpected root type, expected CERTIFICATE, got %s", block.Type) } rootCert, err := x509.ParseCertificate(block.Bytes) if err != nil { t.Fatalf("failed to parse the received root cert: %v", err) } certs, _ := eca.GetSignerWithChain() if !rootCert.Equal(certs[0]) { t.Errorf("root CA does not match, wanted %+v got %+v", certs[0], rootCert) } } // Tests GetConfiguration API func TestGetConfiguration(t *testing.T) { _, emailIssuer := newOIDCIssuer(t) _, spiffeIssuer := newOIDCIssuer(t) _, uriIssuer := newOIDCIssuer(t) _, usernameIssuer := newOIDCIssuer(t) _, k8sIssuer := newOIDCIssuer(t) _, buildkiteIssuer := newOIDCIssuer(t) _, gitHubIssuer := newOIDCIssuer(t) _, gitLabIssuer := newOIDCIssuer(t) _, codefreshIssuer := newOIDCIssuer(t) _, chainguardIssuer := newOIDCIssuer(t) _, ciProviderIssuer := newOIDCIssuer(t) issuerDomain, err := url.Parse(usernameIssuer) if err != nil { t.Fatal("issuer URL could not be parsed", err) } cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "spiffe", "SPIFFETrustDomain": "example.com" }, %q: { "IssuerURL": %q, "ClientID": "sigstore", "SubjectDomain": %q, "Type": "uri" }, %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "email" }, %q: { "IssuerURL": %q, "ClientID": "sigstore", "SubjectDomain": %q, "Type": "username" }, %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "buildkite-job" }, %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "github-workflow" }, %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "gitlab-pipeline" }, %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "codefresh-workflow" }, %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "chainguard-identity" }, %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "ci-provider" } }, "MetaIssuers": { %q: { "ClientID": "sigstore", "Type": "kubernetes" } } }`, spiffeIssuer, spiffeIssuer, uriIssuer, uriIssuer, uriIssuer, emailIssuer, emailIssuer, usernameIssuer, usernameIssuer, issuerDomain.Hostname(), buildkiteIssuer, buildkiteIssuer, gitHubIssuer, gitHubIssuer, gitLabIssuer, gitLabIssuer, codefreshIssuer, codefreshIssuer, chainguardIssuer, chainguardIssuer, ciProviderIssuer, ciProviderIssuer, k8sIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) config, err := client.GetConfiguration(ctx, &protobuf.GetConfigurationRequest{}) if err != nil { t.Fatal("GetConfiguration failed", err) } if got, want := len(config.Issuers), 11; got != want { t.Fatalf("expected %d issuers, got %d", want, got) } expectedIssuers := map[string]bool{ emailIssuer: true, spiffeIssuer: true, uriIssuer: true, usernameIssuer: true, k8sIssuer: true, gitHubIssuer: true, buildkiteIssuer: true, gitLabIssuer: true, codefreshIssuer: true, chainguardIssuer: true, ciProviderIssuer: true, } for _, iss := range config.Issuers { var issURL string switch { case expectedIssuers[iss.GetIssuerUrl()]: delete(expectedIssuers, iss.GetIssuerUrl()) issURL = iss.GetIssuerUrl() case expectedIssuers[iss.GetWildcardIssuerUrl()]: delete(expectedIssuers, iss.GetWildcardIssuerUrl()) issURL = iss.GetWildcardIssuerUrl() default: t.Fatal("issuer missing from expected issuers") } if iss.Audience != "sigstore" { t.Fatalf("expected audience to be sigstore, got %v", iss.Audience) } if issURL == emailIssuer { if iss.ChallengeClaim != "email" { t.Fatalf("expected email claim for email PoP challenge, got %v", iss.ChallengeClaim) } } else { if iss.ChallengeClaim != "sub" { t.Fatalf("expected sub claim for non-email PoP challenge, got %v", iss.ChallengeClaim) } } if issURL == spiffeIssuer { if iss.SpiffeTrustDomain != "example.com" { t.Fatalf("expected SPIFFE trust domain example.com, got %v", iss.SpiffeTrustDomain) } } else { if iss.SpiffeTrustDomain != "" { t.Fatalf("expected no SPIFFE trust domain, got %v", iss.SpiffeTrustDomain) } } } if len(expectedIssuers) != 0 { t.Fatal("not all issuers were found in configuration") } } // Tests GetConfigurationFromYaml API func TestGetConfigurationFromYaml(t *testing.T) { _, emailIssuer := newOIDCIssuer(t) _, spiffeIssuer := newOIDCIssuer(t) _, uriIssuer := newOIDCIssuer(t) _, usernameIssuer := newOIDCIssuer(t) _, k8sIssuer := newOIDCIssuer(t) _, buildkiteIssuer := newOIDCIssuer(t) _, gitHubIssuer := newOIDCIssuer(t) _, gitLabIssuer := newOIDCIssuer(t) _, codefreshIssuer := newOIDCIssuer(t) issuerDomain, err := url.Parse(usernameIssuer) if err != nil { t.Fatal("issuer URL could not be parsed", err) } yamlBytes := []byte(fmt.Sprintf(` oidc-issuers: %v: issuer-url: %q client-id: sigstore type: spiffe spiffe-trust-domain: example.com %v: issuer-url: %q client-id: sigstore type: uri subject-domain: %q %v: issuer-url: %q client-id: sigstore type: email %v: issuer-url: %q client-id: sigstore type: username subject-domain: %q %v: issuer-url: %q client-id: sigstore type: buildkite-job %v: issuer-url: %q client-id: sigstore type: github-workflow %v: issuer-url: %q client-id: sigstore type: gitlab-pipeline %v: issuer-url: %q client-id: sigstore type: codefresh-workflow meta-issuers: %v: client-id: sigstore type: kubernetes`, spiffeIssuer, spiffeIssuer, uriIssuer, uriIssuer, uriIssuer, emailIssuer, emailIssuer, usernameIssuer, usernameIssuer, issuerDomain.Hostname(), buildkiteIssuer, buildkiteIssuer, gitHubIssuer, gitHubIssuer, gitLabIssuer, gitLabIssuer, codefreshIssuer, codefreshIssuer, k8sIssuer)) cfg, err := config.Read(yamlBytes) if err != nil { t.Fatalf("config.Read() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) config, err := client.GetConfiguration(ctx, &protobuf.GetConfigurationRequest{}) if err != nil { t.Fatal("GetConfiguration failed", err) } if len(config.Issuers) != 9 { t.Fatalf("expected 9 issuers, got %v", len(config.Issuers)) } expectedIssuers := map[string]bool{ emailIssuer: true, spiffeIssuer: true, uriIssuer: true, usernameIssuer: true, k8sIssuer: true, gitHubIssuer: true, buildkiteIssuer: true, gitLabIssuer: true, codefreshIssuer: true, } for _, iss := range config.Issuers { var issURL string switch { case expectedIssuers[iss.GetIssuerUrl()]: delete(expectedIssuers, iss.GetIssuerUrl()) issURL = iss.GetIssuerUrl() case expectedIssuers[iss.GetWildcardIssuerUrl()]: delete(expectedIssuers, iss.GetWildcardIssuerUrl()) issURL = iss.GetWildcardIssuerUrl() default: t.Fatal("issuer missing from expected issuers") } if iss.Audience != "sigstore" { t.Fatalf("expected audience to be sigstore, got %v", iss.Audience) } if issURL == emailIssuer { if iss.ChallengeClaim != "email" { t.Fatalf("expected email claim for email PoP challenge, got %v", iss.ChallengeClaim) } } else { if iss.ChallengeClaim != "sub" { t.Fatalf("expected sub claim for non-email PoP challenge, got %v", iss.ChallengeClaim) } } if issURL == spiffeIssuer { if iss.SpiffeTrustDomain != "example.com" { t.Fatalf("expected SPIFFE trust domain example.com, got %v", iss.SpiffeTrustDomain) } } else { if iss.SpiffeTrustDomain != "" { t.Fatalf("expected no SPIFFE trust domain, got %v", iss.SpiffeTrustDomain) } } } if len(expectedIssuers) != 0 { t.Fatal("not all issuers were found in configuration") } } // oidcTestContainer holds values needed for each API test invocation type oidcTestContainer struct { Signer jose.Signer Issuer string Subject string ExpectedSubject string } // customClaims holds additional JWT claims for email-based OIDC tokens type customClaims struct { Email string `json:"email"` EmailVerified bool `json:"email_verified"` OtherIssuer string `json:"other_issuer"` } // Tests API for email subject types func TestAPIWithEmail(t *testing.T) { emailSigner, emailIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "email" } } }`, emailIssuer, emailIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } emailSubject := "foo@example.com" tests := []oidcTestContainer{ { Signer: emailSigner, Issuer: emailIssuer, Subject: emailSubject, ExpectedSubject: emailSubject, }, } for _, c := range tests { // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(c.Signer).Claims(jwt.Claims{ Issuer: c.Issuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: c.Subject, Audience: jwt.Audience{"sigstore"}, }).Claims(customClaims{Email: c.Subject, EmailVerified: true}).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) pubBytes, proof := generateKeyAndProof(c.Subject, t) // Hit the API to have it sign our certificate. resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: pubBytes, }, ProofOfPossession: proof, }, }, }) if err != nil { t.Fatalf("SigningCert() = %v", err) } leafCert := verifyResponse(resp, eca, c.Issuer, t) // Expect email subject if len(leafCert.EmailAddresses) != 1 { t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) } if leafCert.EmailAddresses[0] != c.ExpectedSubject { t.Fatalf("subjects do not match: Expected %v, got %v", c.ExpectedSubject, leafCert.EmailAddresses[0]) } } } // Tests API for username subject types func TestAPIWithUsername(t *testing.T) { usernameSigner, usernameIssuer := newOIDCIssuer(t) issuerDomain, err := url.Parse(usernameIssuer) if err != nil { t.Fatal("issuer URL could not be parsed", err) } // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "SubjectDomain": %q, "Type": "username" } } }`, usernameIssuer, usernameIssuer, issuerDomain.Hostname()))) if err != nil { t.Fatalf("config.Read() = %v", err) } usernameSubject := "foo" expectedUsernamedSubject := fmt.Sprintf("%s!%s", usernameSubject, issuerDomain.Hostname()) tests := []oidcTestContainer{ { Signer: usernameSigner, Issuer: usernameIssuer, Subject: usernameSubject, ExpectedSubject: expectedUsernamedSubject, }, } for _, c := range tests { // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(c.Signer).Claims(jwt.Claims{ Issuer: c.Issuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: c.Subject, Audience: jwt.Audience{"sigstore"}, }).Claims(customClaims{Email: c.Subject, EmailVerified: true}).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) pubBytes, proof := generateKeyAndProof(c.Subject, t) // Hit the API to have it sign our certificate. resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: pubBytes, }, ProofOfPossession: proof, }, }, }) if err != nil { t.Fatalf("SigningCert() = %v", err) } leafCert := verifyResponse(resp, eca, c.Issuer, t) // Expect no email subject if len(leafCert.EmailAddresses) != 0 { t.Fatalf("unexpected length of leaf certificate URIs, expected 0, got %d", len(leafCert.URIs)) } otherName, err := cryptoutils.UnmarshalOtherNameSAN(leafCert.Extensions) if err != nil { t.Fatalf("error unmarshalling SANs: %v", err) } if otherName != c.ExpectedSubject { t.Fatalf("subjects do not match: Expected %v, got %v", c.ExpectedSubject, otherName) } } } // Tests API for SPIFFE and URI subject types func TestAPIWithUriSubject(t *testing.T) { spiffeSigner, spiffeIssuer := newOIDCIssuer(t) uriSigner, uriIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "spiffe", "SPIFFETrustDomain": "foo.com" }, %q: { "IssuerURL": %q, "ClientID": "sigstore", "SubjectDomain": %q, "Type": "uri" } } }`, spiffeIssuer, spiffeIssuer, uriIssuer, uriIssuer, uriIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } spiffeSubject := "spiffe://foo.com/bar" uriSubject := uriIssuer + "/users/1" tests := []oidcTestContainer{ { Signer: spiffeSigner, Issuer: spiffeIssuer, Subject: spiffeSubject, }, { Signer: uriSigner, Issuer: uriIssuer, Subject: uriSubject, }, } for _, c := range tests { // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(c.Signer).Claims(jwt.Claims{ Issuer: c.Issuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: c.Subject, Audience: jwt.Audience{"sigstore"}, }).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) pubBytes, proof := generateKeyAndProof(c.Subject, t) // Hit the API to have it sign our certificate. resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: pubBytes, }, ProofOfPossession: proof, }, }, }) if err != nil { t.Fatalf("SigningCert() = %v", err) } leafCert := verifyResponse(resp, eca, c.Issuer, t) // Expect URI values if len(leafCert.URIs) != 1 { t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) } uSubject, err := url.Parse(c.Subject) if err != nil { t.Fatalf("Failed to parse subject URI") } if *leafCert.URIs[0] != *uSubject { t.Fatalf("subjects do not match: Expected %v, got %v", uSubject, leafCert.URIs[0]) } } } // k8sClaims holds the additional Kubernetes claims for the JWT type k8sClaims struct { Kubernetes struct { Namespace string `json:"namespace"` ServiceAccount struct { Name string `json:"name"` } } `json:"kubernetes.io"` } // Tests API for Kubernetes URI subject types func TestAPIWithKubernetes(t *testing.T) { k8sSigner, k8sIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "MetaIssuers": { %q: { "ClientID": "sigstore", "Type": "kubernetes" } } }`, k8sIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } namespace := "namespace" saName := "sa" k8sSubject := fmt.Sprintf("https://kubernetes.io/namespaces/%s/serviceaccounts/%s", namespace, saName) // Create an OIDC token using this issuer's signer. claims := k8sClaims{} claims.Kubernetes.Namespace = namespace claims.Kubernetes.ServiceAccount.Name = saName tok, err := jwt.Signed(k8sSigner).Claims(jwt.Claims{ Issuer: k8sIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: k8sSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(&claims).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) pubBytes, proof := generateKeyAndProof(k8sSubject, t) // Hit the API to have it sign our certificate. resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: pubBytes, }, ProofOfPossession: proof, }, }, }) if err != nil { t.Fatalf("SigningCert() = %v", err) } leafCert := verifyResponse(resp, eca, k8sIssuer, t) // Expect URI values if len(leafCert.URIs) != 1 { t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) } uSubject, err := url.Parse(k8sSubject) if err != nil { t.Fatalf("failed to parse subject URI") } if *leafCert.URIs[0] != *uSubject { t.Fatalf("subjects do not match: Expected %v, got %v", uSubject, leafCert.URIs[0]) } } // buildkiteClaims holds the additional JWT claims for Buildkite OIDC tokens type buildkiteClaims struct { OrganizationSlug string `json:"organization_slug"` PipelineSlug string `json:"pipeline_slug"` } // Tests API for Buildkite subject types func TestAPIWithBuildkite(t *testing.T) { buildkiteSigner, buildkiteIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "buildkite-job" } } }`, buildkiteIssuer, buildkiteIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } claims := buildkiteClaims{ OrganizationSlug: "acme-inc", PipelineSlug: "bash-example", } buildkiteSubject := fmt.Sprintf("organization:%s:pipeline:%s:ref:refs/heads/main:commit:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:step:build", claims.OrganizationSlug, claims.PipelineSlug) // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(buildkiteSigner).Claims(jwt.Claims{ Issuer: buildkiteIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: buildkiteSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(&claims).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) pubBytes, proof := generateKeyAndProof(buildkiteSubject, t) // Hit the API to have it sign our certificate. resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: pubBytes, }, ProofOfPossession: proof, }, }, }) if err != nil { t.Fatalf("SigningCert() = %v", err) } leafCert := verifyResponse(resp, eca, buildkiteIssuer, t) // Expect URI values if len(leafCert.URIs) != 1 { t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) } buildkiteURL := fmt.Sprintf("https://buildkite.com/%s/%s", claims.OrganizationSlug, claims.PipelineSlug) buildkiteURI, err := url.Parse(buildkiteURL) if err != nil { t.Fatalf("failed to parse subject URI") } if *leafCert.URIs[0] != *buildkiteURI { t.Fatalf("URIs do not match: Expected %v, got %v", buildkiteURI, leafCert.URIs[0]) } } // githubClaims holds the additional JWT claims for GitHub OIDC tokens type githubClaims struct { JobWorkflowRef string `json:"job_workflow_ref"` Sha string `json:"sha"` EventName string `json:"event_name"` Repository string `json:"repository"` Workflow string `json:"workflow"` Ref string `json:"ref"` JobWorkflowSha string `json:"job_workflow_sha"` RunnerEnvironment string `json:"runner_environment"` RepositoryID string `json:"repository_id"` RepositoryOwner string `json:"repository_owner"` RepositoryOwnerID string `json:"repository_owner_id"` RepositoryVisibility string `json:"repository_visibility"` WorkflowRef string `json:"workflow_ref"` WorkflowSha string `json:"workflow_sha"` RunID string `json:"run_id"` RunAttempt string `json:"run_attempt"` } // Tests API for GitHub subject types func TestAPIWithGitHub(t *testing.T) { githubSigner, githubIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "github-workflow" } } }`, githubIssuer, githubIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } claims := githubClaims{ JobWorkflowRef: "job/workflow/ref", Sha: "sha", EventName: "trigger", Repository: "sigstore/fulcio", Workflow: "workflow", Ref: "refs/heads/main", JobWorkflowSha: "example-sha", RunnerEnvironment: "cloud-hosted", RepositoryID: "12345", RepositoryOwner: "username", RepositoryOwnerID: "345", RepositoryVisibility: "public", WorkflowRef: "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", WorkflowSha: "example-sha-other", RunID: "42", RunAttempt: "1", } githubSubject := fmt.Sprintf("repo:%s:ref:%s", claims.Repository, claims.Ref) // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(githubSigner).Claims(jwt.Claims{ Issuer: githubIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: githubSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(&claims).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) pubBytes, proof := generateKeyAndProof(githubSubject, t) // Hit the API to have it sign our certificate. resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: pubBytes, }, ProofOfPossession: proof, }, }, }) if err != nil { t.Fatalf("SigningCert() = %v", err) } leafCert := verifyResponse(resp, eca, githubIssuer, t) // Expect URI values if len(leafCert.URIs) != 1 { t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) } githubURL := fmt.Sprintf("https://github.com/%s", claims.JobWorkflowRef) githubURI, err := url.Parse(githubURL) if err != nil { t.Fatalf("failed to parse expected url") } if *leafCert.URIs[0] != *githubURI { t.Fatalf("URIs do not match: Expected %v, got %v", githubURI, leafCert.URIs[0]) } // Verify custom OID values deprecatedExpectedExts := map[int]string{ 2: claims.EventName, 3: claims.Sha, 4: claims.Workflow, 5: claims.Repository, 6: claims.Ref, } for o, value := range deprecatedExpectedExts { ext, found := findCustomExtension(leafCert, asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, o}) if !found { t.Fatalf("expected extension in custom OID 1.3.6.1.4.1.57264.1.%d", o) } if string(ext.Value) != value { t.Fatalf("unexpected extension value, expected %s, got %s", value, ext.Value) } } url := "https://github.com/" expectedExts := map[int]string{ 9: url + claims.JobWorkflowRef, 10: claims.JobWorkflowSha, 11: claims.RunnerEnvironment, 12: url + claims.Repository, 13: claims.Sha, 14: claims.Ref, 15: claims.RepositoryID, 16: url + claims.RepositoryOwner, 17: claims.RepositoryOwnerID, 18: url + claims.WorkflowRef, 19: claims.WorkflowSha, 20: claims.EventName, 21: url + claims.Repository + "/actions/runs/" + claims.RunID + "/attempts/" + claims.RunAttempt, 22: claims.RepositoryVisibility, } for o, value := range expectedExts { ext, found := findCustomExtension(leafCert, asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, o}) if !found { t.Fatalf("expected extension in custom OID 1.3.6.1.4.1.57264.1.%d", o) } var extValue string rest, err := asn1.Unmarshal(ext.Value, &extValue) if err != nil { t.Fatalf("error unmarshalling extension: :%v", err) } if len(rest) != 0 { t.Fatal("error unmarshalling extension, rest is not 0") } if string(extValue) != value { t.Fatalf("unexpected extension value, expected %s, got %s", value, extValue) } } } // Tests API for CiProvider subject types func TestAPIWithCiProvider(t *testing.T) { ciProviderSigner, ciProviderIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "ci-provider", "CIProvider": "github-workflow" } } }`, ciProviderIssuer, ciProviderIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } claims := githubClaims{ JobWorkflowRef: "job/workflow/ref", Sha: "sha", EventName: "trigger", Repository: "sigstore/fulcio", Workflow: "workflow", Ref: "refs/heads/main", JobWorkflowSha: "example-sha", RunnerEnvironment: "cloud-hosted", RepositoryID: "12345", RepositoryOwner: "username", RepositoryOwnerID: "345", RepositoryVisibility: "public", WorkflowRef: "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", WorkflowSha: "example-sha-other", RunID: "42", RunAttempt: "1", } githubSubject := fmt.Sprintf("repo:%s:ref:%s", claims.Repository, claims.Ref) // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(ciProviderSigner).Claims(jwt.Claims{ Issuer: ciProviderIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: githubSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(&claims).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() cfg.CIIssuerMetadata = make(map[string]config.IssuerMetadata) cfg.CIIssuerMetadata["github-workflow"] = config.IssuerMetadata{ ExtensionTemplates: certificate.Extensions{ Issuer: "issuer", GithubWorkflowTrigger: "event_name", GithubWorkflowSHA: "sha", GithubWorkflowName: "workflow", GithubWorkflowRepository: "repository", GithubWorkflowRef: "ref", BuildSignerURI: "{{ .url }}/{{ .job_workflow_ref }}", BuildSignerDigest: "job_workflow_sha", RunnerEnvironment: "runner_environment", SourceRepositoryURI: "{{ .url }}/{{ .repository }}", SourceRepositoryDigest: "sha", SourceRepositoryRef: "ref", SourceRepositoryIdentifier: "repository_id", SourceRepositoryOwnerURI: "{{ .url }}/{{ .repository_owner }}", SourceRepositoryOwnerIdentifier: "repository_owner_id", BuildConfigURI: "{{ .url }}/{{ .workflow_ref }}", BuildConfigDigest: "workflow_sha", BuildTrigger: "event_name", RunInvocationURI: "{{ .url }}/{{ .repository }}/actions/runs/{{ .run_id }}/attempts/{{ .run_attempt }}", SourceRepositoryVisibilityAtSigning: "repository_visibility", }, DefaultTemplateValues: map[string]string{ "url": "https://github.com", }, SubjectAlternativeNameTemplate: "{{.url}}/{{.job_workflow_ref}}", } server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) pubBytes, proof := generateKeyAndProof(githubSubject, t) // Hit the API to have it sign our certificate. resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: pubBytes, }, ProofOfPossession: proof, }, }, }) if err != nil { t.Fatalf("SigningCert() = %v", err) } leafCert := verifyResponse(resp, eca, ciProviderIssuer, t) // Expect URI values if len(leafCert.URIs) != 1 { t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) } githubURL := fmt.Sprintf("https://github.com/%s", claims.JobWorkflowRef) githubURI, err := url.Parse(githubURL) if err != nil { t.Fatalf("failed to parse expected url") } if *leafCert.URIs[0] != *githubURI { t.Fatalf("URIs do not match: Expected %v, got %v", githubURI, leafCert.URIs[0]) } // Verify custom OID values deprecatedExpectedExts := map[int]string{ 2: claims.EventName, 3: claims.Sha, 4: claims.Workflow, 5: claims.Repository, 6: claims.Ref, } for o, value := range deprecatedExpectedExts { ext, found := findCustomExtension(leafCert, asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, o}) if !found { t.Fatalf("expected extension in custom OID 1.3.6.1.4.1.57264.1.%d", o) } if string(ext.Value) != value { t.Fatalf("unexpected extension value, expected %s, got %s", value, ext.Value) } } url := "https://github.com/" expectedExts := map[int]string{ 9: url + claims.JobWorkflowRef, 10: claims.JobWorkflowSha, 11: claims.RunnerEnvironment, 12: url + claims.Repository, 13: claims.Sha, 14: claims.Ref, 15: claims.RepositoryID, 16: url + claims.RepositoryOwner, 17: claims.RepositoryOwnerID, 18: url + claims.WorkflowRef, 19: claims.WorkflowSha, 20: claims.EventName, 21: url + claims.Repository + "/actions/runs/" + claims.RunID + "/attempts/" + claims.RunAttempt, 22: claims.RepositoryVisibility, } for o, value := range expectedExts { ext, found := findCustomExtension(leafCert, asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, o}) if !found { t.Fatalf("expected extension in custom OID 1.3.6.1.4.1.57264.1.%d", o) } var extValue string rest, err := asn1.Unmarshal(ext.Value, &extValue) if err != nil { t.Fatalf("error unmarshalling extension: :%v", err) } if len(rest) != 0 { t.Fatal("error unmarshalling extension, rest is not 0") } if string(extValue) != value { t.Fatalf("unexpected extension value, expected %s, got %s", value, extValue) } } } // gitlabClaims holds the additional JWT claims for GitLab OIDC tokens type gitlabClaims struct { ProjectPath string `json:"project_path"` ProjectID string `json:"project_id"` PipelineSource string `json:"pipeline_source"` PipelineID string `json:"pipeline_id"` CiConfigRefURI string `json:"ci_config_ref_uri"` CiConfigSha string `json:"ci_config_sha"` NamespacePath string `json:"namespace_path"` NamespaceID string `json:"namespace_id"` JobID string `json:"job_id"` Ref string `json:"ref"` RefType string `json:"ref_type"` Sha string `json:"sha"` RunnerEnvironment string `json:"runner_environment"` RunnerID int64 `json:"runner_id"` ProjectVisibility string `json:"project_visibility"` } // Tests API for GitLab subject types func TestAPIWithGitLab(t *testing.T) { gitLabSigner, gitLabIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "gitlab-pipeline" } } }`, gitLabIssuer, gitLabIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } claims := gitlabClaims{ ProjectPath: "cpanato/testing-cosign", ProjectID: "42831435", PipelineSource: "push", PipelineID: "757451528", CiConfigRefURI: "gitlab.com/cpanato/testing-cosign//.gitlab-ci.yml@refs/heads/main", CiConfigSha: "714a629c0b401fdce83e847fc9589983fc6f46bc", NamespacePath: "cpanato", NamespaceID: "1730270", JobID: "3659681386", Ref: "main", RefType: "branch", Sha: "714a629c0b401fdce83e847fc9589983fc6f46bc", RunnerID: 1, RunnerEnvironment: "gitlab-hosted", ProjectVisibility: "public", } gitLabSubject := fmt.Sprintf("project_path:%s:ref_type:%s:ref:%s", claims.ProjectPath, claims.RefType, claims.Ref) // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(gitLabSigner).Claims(jwt.Claims{ Issuer: gitLabIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: gitLabSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(&claims).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) pubBytes, proof := generateKeyAndProof(gitLabSubject, t) // Hit the API to have it sign our certificate. resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: pubBytes, }, ProofOfPossession: proof, }, }, }) if err != nil { t.Fatalf("SigningCert() = %v", err) } leafCert := verifyResponse(resp, eca, gitLabIssuer, t) // Expect URI values if len(leafCert.URIs) != 1 { t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) } baseURL := "https://gitlab.com/" gitLabURL := baseURL + fmt.Sprintf("%s//.gitlab-ci.yml@refs/heads/%s", claims.ProjectPath, claims.Ref) gitLabURI, err := url.Parse(gitLabURL) if err != nil { t.Fatalf("failed to parse expected url") } if *leafCert.URIs[0] != *gitLabURI { t.Fatalf("URIs do not match: Expected %v, got %v", gitLabURI, leafCert.URIs[0]) } expectedExts := map[int]string{ 9: gitLabURL, 10: claims.CiConfigSha, 11: claims.RunnerEnvironment, 12: baseURL + claims.ProjectPath, 13: claims.Sha, 14: fmt.Sprintf("refs/heads/%s", claims.Ref), 15: claims.ProjectID, 16: baseURL + claims.NamespacePath, 17: claims.NamespaceID, 18: gitLabURL, 19: claims.CiConfigSha, 20: claims.PipelineSource, 21: baseURL + claims.ProjectPath + "/-/jobs/" + claims.JobID, 22: claims.ProjectVisibility, } for o, value := range expectedExts { ext, found := findCustomExtension(leafCert, asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, o}) if !found { t.Fatalf("expected extension in custom OID 1.3.6.1.4.1.57264.1.%d", o) } var extValue string rest, err := asn1.Unmarshal(ext.Value, &extValue) if err != nil { t.Fatalf("error unmarshalling extension: :%v", err) } if len(rest) != 0 { t.Fatal("error unmarshalling extension, rest is not 0") } if string(extValue) != value { t.Fatalf("unexpected extension value, expected %s, got %s", value, extValue) } } } // codefreshClaims holds the additional JWT claims for Codefresh OIDC tokens type codefreshClaims struct { AccountID string `json:"account_id"` AccountName string `json:"account_name"` PipelineID string `json:"pipeline_id"` PipelineName string `json:"pipeline_name"` WorkflowID string `json:"workflow_id"` Initiator string `json:"initiator"` SCMRepoURL string `json:"scm_repo_url"` SCMUsername string `json:"scm_user_name"` SCMRef string `json:"scm_ref"` SCMPullRequestRef string `json:"scm_pull_request_target_branch"` RunnerEnvironment string `json:"runner_environment"` PlatformURL string `json:"platform_url"` } // Tests API for Codefresh subject types func TestAPIWithCodefresh(t *testing.T) { codefreshSigner, codefreshIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "codefresh-workflow" } } }`, codefreshIssuer, codefreshIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } claims := codefreshClaims{ AccountID: "628a80b693a15c0f9c13ab75", AccountName: "test-codefresh", PipelineID: "65e6d5551e47e5bc243ca93f", PipelineName: "oidc-test/oidc-test-2", WorkflowID: "65e6ebe0bfbfa1782876165e", SCMUsername: "test-codefresh", SCMRepoURL: "https://github.com/test-codefresh/fulcio", SCMRef: "feat/codefresh-issuer", SCMPullRequestRef: "main", RunnerEnvironment: "hybrid", PlatformURL: "https://g.codefresh.io", } codefreshSubject := "account:628a80b693a15c0f9c13ab75:pipeline:65e6d5551e47e5bc243ca93f:scm_repo_url:https://github.com/test-codefresh/fulcio:scm_user_name:test-codefresh:scm_ref:feat/codefresh-issuer:scm_pull_request_target_branch:main" // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(codefreshSigner).Claims(jwt.Claims{ Issuer: codefreshIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: codefreshSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(&claims).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) pubBytes, proof := generateKeyAndProof(codefreshSubject, t) // Hit the API to have it sign our certificate. resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: pubBytes, }, ProofOfPossession: proof, }, }, }) if err != nil { t.Fatalf("SigningCert() = %v", err) } leafCert := verifyResponse(resp, eca, codefreshIssuer, t) // Expect URI values if len(leafCert.URIs) != 1 { t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) } codefreshURL := fmt.Sprintf("%s/%s/%s:%s/%s", claims.PlatformURL, claims.AccountName, claims.PipelineName, claims.AccountID, claims.PipelineID) codefreshURI, err := url.Parse(codefreshURL) if err != nil { t.Fatalf("failed to parse expected url") } if *leafCert.URIs[0] != *codefreshURI { t.Fatalf("URIs do not match: Expected %v, got %v", codefreshURI, leafCert.URIs[0]) } expectedExts := map[int]string{ 9: claims.PlatformURL + "/build/" + claims.WorkflowID, 11: claims.RunnerEnvironment, 12: claims.SCMRepoURL, 14: claims.SCMRef, 18: claims.PlatformURL + "/api/pipelines/" + claims.PipelineID, 21: claims.PlatformURL + "/build/" + claims.WorkflowID, } for o, value := range expectedExts { ext, found := findCustomExtension(leafCert, asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, o}) if !found { t.Fatalf("expected extension in custom OID 1.3.6.1.4.1.57264.1.%d", o) } var extValue string rest, err := asn1.Unmarshal(ext.Value, &extValue) if err != nil { t.Fatalf("error unmarshalling extension: :%v", err) } if len(rest) != 0 { t.Fatal("error unmarshalling extension, rest is not 0") } if string(extValue) != value { t.Fatalf("unexpected extension value, expected %s, got %s", value, extValue) } } } // chainguardClaims holds the additional JWT claims for Chainguard OIDC tokens type chainguardClaims struct { Actor map[string]string `json:"act"` Internal struct { ServicePrincipal string `json:"service-principal,omitempty"` } `json:"internal"` } // Tests API for Chainguard subject types func TestAPIWithChainguard(t *testing.T) { chainguardSigner, chainguardIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "chainguard-identity" } } }`, chainguardIssuer, chainguardIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } group := uidp.NewUIDP("") chainguardSubject := group.NewChild() claims := chainguardClaims{ Actor: map[string]string{ "iss": chainguardIssuer, "sub": fmt.Sprintf("catalog-syncer:%s", group.String()), "aud": "chainguard", }, Internal: struct { ServicePrincipal string `json:"service-principal,omitempty"` }{ ServicePrincipal: "CATALOG_SYNCER", }, } // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(chainguardSigner).Claims(jwt.Claims{ Issuer: chainguardIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: chainguardSubject.String(), Audience: jwt.Audience{"sigstore"}, }).Claims(&claims).Serialize() if err != nil { t.Fatalf("CompactSerialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) pubBytes, proof := generateKeyAndProof(chainguardSubject.String(), t) // Hit the API to have it sign our certificate. resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: pubBytes, }, ProofOfPossession: proof, }, }, }) if err != nil { t.Fatalf("SigningCert() = %v", err) } leafCert := verifyResponse(resp, eca, chainguardIssuer, t) // Expect URI values if len(leafCert.URIs) != 1 { t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) } chainguardURL := fmt.Sprintf("%s/%s", chainguardIssuer, chainguardSubject) chainguardURI, err := url.Parse(chainguardURL) if err != nil { t.Fatalf("failed to parse expected url") } if *leafCert.URIs[0] != *chainguardURI { t.Fatalf("URIs do not match: Expected %v, got %v", chainguardURI, leafCert.URIs[0]) } expectedExts := map[int]string{ 8: chainguardIssuer, // TODO(mattmoor): Embed more of the Chainguard token structure via OIDs. } for o, value := range expectedExts { ext, found := findCustomExtension(leafCert, asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, o}) if !found { t.Fatalf("expected extension in custom OID 1.3.6.1.4.1.57264.1.%d", o) } var extValue string rest, err := asn1.Unmarshal(ext.Value, &extValue) if err != nil { t.Fatalf("error unmarshalling extension: :%v", err) } if len(rest) != 0 { t.Fatal("error unmarshalling extension, rest is not 0") } if string(extValue) != value { t.Fatalf("unexpected extension value, expected %s, got %s", value, extValue) } } } // Tests API with issuer claim in different field in the OIDC token func TestAPIWithIssuerClaimConfig(t *testing.T) { emailSigner, emailIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "email", "IssuerClaim": "$.other_issuer" } } }`, emailIssuer, emailIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } emailSubject := "foo@example.com" otherIssuerVal := "other.issuer.com" // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(emailSigner).Claims(jwt.Claims{ Issuer: emailIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(customClaims{Email: emailSubject, EmailVerified: true, OtherIssuer: otherIssuerVal}).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) pubBytes, proof := generateKeyAndProof(emailSubject, t) // Hit the API to have it sign our certificate. resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: pubBytes, }, ProofOfPossession: proof, }, }, }) if err != nil { t.Fatalf("SigningCert() = %v", err) } // The issuer should be otherIssuerVal, not emailIssuer leafCert := verifyResponse(resp, eca, otherIssuerVal, t) // Expect email subject if len(leafCert.EmailAddresses) != 1 { t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) } if leafCert.EmailAddresses[0] != emailSubject { t.Fatalf("subjects do not match: Expected %v, got %v", emailSubject, leafCert.EmailAddresses[0]) } } // Tests API with challenge sent as CSR func TestAPIWithCSRChallenge(t *testing.T) { emailSigner, emailIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports this issuer. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "email" } } }`, emailIssuer, emailIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } emailSubject := "foo@example.com" // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(emailSigner).Claims(jwt.Claims{ Issuer: emailIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("error generating private key: %v", err) } csrTmpl := &x509.CertificateRequest{Subject: pkix.Name{CommonName: "test"}} derCSR, err := x509.CreateCertificateRequest(rand.Reader, csrTmpl, priv) if err != nil { t.Fatalf("error creating CSR: %v", err) } pemCSR := pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: derCSR, }) // Hit the API to have it sign our certificate. resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_CertificateSigningRequest{ CertificateSigningRequest: pemCSR, }, }) if err != nil { t.Fatalf("SigningCert() = %v", err) } leafCert := verifyResponse(resp, eca, emailIssuer, t) // Expect email subject if len(leafCert.EmailAddresses) != 1 { t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) } if leafCert.EmailAddresses[0] != emailSubject { t.Fatalf("subjects do not match: Expected %v, got %v", emailSubject, leafCert.EmailAddresses[0]) } } // Tests API with insecure pub key func TestAPIWithInsecurePublicKey(t *testing.T) { emailSigner, emailIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "email" } } }`, emailIssuer, emailIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } emailSubject := "foo@example.com" // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(emailSigner).Claims(jwt.Claims{ Issuer: emailIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) priv, err := rsa.GenerateKey(rand.Reader, 1024) if err != nil { t.Fatalf("GenerateKey() = %v", err) } pubBytes, err := x509.MarshalPKIXPublicKey(&priv.PublicKey) if err != nil { t.Fatalf("x509.MarshalPKIXPublicKey() = %v", err) } // Hit the API to have it sign our certificate. _, err = client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: string(cryptoutils.PEMEncode(cryptoutils.PublicKeyPEMType, pubBytes)), }, ProofOfPossession: []byte{}, }, }, }) if err == nil || !strings.Contains(err.Error(), "The public key supplied in the request is insecure") { t.Fatalf("expected insecure public key error, got %v", err) } if status.Code(err) != codes.InvalidArgument { t.Fatalf("expected invalid argument, got %v", status.Code(err)) } } // Tests API with no public key func TestAPIWithoutPublicKey(t *testing.T) { emailSigner, emailIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "email" } } }`, emailIssuer, emailIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } emailSubject := "foo@example.com" // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(emailSigner).Claims(jwt.Claims{ Issuer: emailIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) // Test with no key proto specified _, err = client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, }) if err == nil || !strings.Contains(err.Error(), "The public key supplied in the request could not be parsed") { t.Fatalf("expected parsing public key error, got %v", err) } if status.Code(err) != codes.InvalidArgument { t.Fatalf("expected invalid argument, got %v", status.Code(err)) } // Test with no public key specified _, err = client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{}, }, }) if err == nil || !strings.Contains(err.Error(), "The public key supplied in the request could not be parsed") { t.Fatalf("expected parsing public key error, got %v", err) } if status.Code(err) != codes.InvalidArgument { t.Fatalf("expected invalid argument, got %v", status.Code(err)) } } // Tests API with invalid challenge as proof of possession of private key func TestAPIWithInvalidChallenge(t *testing.T) { emailSigner, emailIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports these issuers. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "email" } } }`, emailIssuer, emailIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } emailSubject := "foo@example.com" // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(emailSigner).Claims(jwt.Claims{ Issuer: emailIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) pubBytes, _ := generateKeyAndProof(emailSubject, t) _, invalidProof := generateKeyAndProof(emailSubject, t) _, err = client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &protobuf.PublicKeyRequest{ PublicKey: &protobuf.PublicKey{ Content: pubBytes, }, ProofOfPossession: invalidProof, }, }, }) if err == nil || !strings.Contains(err.Error(), "The signature supplied in the request could not be verified") { t.Fatalf("expected invalid signature error, got %v", err) } if status.Code(err) != codes.InvalidArgument { t.Fatalf("expected invalid argument, got %v", status.Code(err)) } } // Tests API with an invalid CSR. func TestAPIWithInvalidCSR(t *testing.T) { emailSigner, emailIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports this issuer. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "email" } } }`, emailIssuer, emailIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } emailSubject := "foo@example.com" // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(emailSigner).Claims(jwt.Claims{ Issuer: emailIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) _, err = client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_CertificateSigningRequest{ CertificateSigningRequest: []byte("invalid"), }, }) if err == nil || !strings.Contains(err.Error(), "The certificate signing request could not be parsed") { t.Fatalf("expected invalid signature error, got %v", err) } if status.Code(err) != codes.InvalidArgument { t.Fatalf("expected invalid argument, got %v", status.Code(err)) } } // Tests API with unsigned CSR, which will fail signature verification. func TestAPIWithInvalidCSRSignature(t *testing.T) { emailSigner, emailIssuer := newOIDCIssuer(t) // Create a FulcioConfig that supports this issuer. cfg, err := config.Read([]byte(fmt.Sprintf(`{ "OIDCIssuers": { %q: { "IssuerURL": %q, "ClientID": "sigstore", "Type": "email" } } }`, emailIssuer, emailIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) } emailSubject := "foo@example.com" // Create an OIDC token using this issuer's signer. tok, err := jwt.Signed(emailSigner).Claims(jwt.Claims{ Issuer: emailIssuer, IssuedAt: jwt.NewNumericDate(time.Now()), Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).Serialize() if err != nil { t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) ctx := context.Background() server, conn := setupGRPCForTest(t, cfg, ctClient, eca) defer func() { server.Stop() conn.Close() }() client := protobuf.NewCAClient(conn) priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("error generating private key: %v", err) } csrTmpl := &x509.CertificateRequest{Subject: pkix.Name{CommonName: "test"}} derCSR, err := x509.CreateCertificateRequest(rand.Reader, csrTmpl, priv) if err != nil { t.Fatalf("error creating CSR: %v", err) } // Corrupt signature derCSR[len(derCSR)-1] = derCSR[len(derCSR)-1] + 1 pemCSR := pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: derCSR, }) // Hit the API to have it sign our certificate. _, err = client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ Credentials: &protobuf.Credentials{ Credentials: &protobuf.Credentials_OidcIdentityToken{ OidcIdentityToken: tok, }, }, Key: &protobuf.CreateSigningCertificateRequest_CertificateSigningRequest{ CertificateSigningRequest: pemCSR, }, }) if err == nil || !strings.Contains(err.Error(), "The signature supplied in the request could not be verified") { t.Fatalf("expected invalid signature error, got %v", err) } if status.Code(err) != codes.InvalidArgument { t.Fatalf("expected invalid argument, got %v", status.Code(err)) } } // Stand up a very simple OIDC endpoint. func newOIDCIssuer(t *testing.T) (jose.Signer, string) { t.Helper() pk, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatalf("cannot generate RSA key %v", err) } jwk := jose.JSONWebKey{ Algorithm: string(jose.RS256), Key: pk, } signer, err := jose.NewSigner(jose.SigningKey{ Algorithm: jose.RS256, Key: jwk.Key, }, nil) if err != nil { t.Fatalf("jose.NewSigner() = %v", err) } // Populated below, but we need to capture it first. var testIssuer *string oidcMux := http.NewServeMux() oidcMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, _ *http.Request) { t.Log("Handling request for openid-configuration.") if err := json.NewEncoder(w).Encode(struct { Issuer string `json:"issuer"` JWKSURI string `json:"jwks_uri"` }{ Issuer: *testIssuer, JWKSURI: *testIssuer + "/keys", }); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }) oidcMux.HandleFunc("/keys", func(w http.ResponseWriter, _ *http.Request) { t.Log("Handling request for jwks.") if err := json.NewEncoder(w).Encode(jose.JSONWebKeySet{ Keys: []jose.JSONWebKey{ jwk.Public(), }, }); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }) oidcServer := httptest.NewServer(oidcMux) t.Cleanup(oidcServer.Close) // Setup the testIssuer, so everything uses the right URL. testIssuer = &oidcServer.URL return signer, *testIssuer } func fakeCTLogServer(_ *testing.T) *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() addJSONResp := `{ "sct_version":0, "id":"KHYaGJAn++880NYaAY12sFBXKcenQRvMvfYE9F1CYVM=", "timestamp":1337, "extensions":"", "signature":"BAMARjBEAiAIc21J5ZbdKZHw5wLxCP+MhBEsV5+nfvGyakOIv6FOvAIgWYMZb6Pw///uiNM7QTg2Of1OqmK1GbeGuEl9VJN8v8c=" }` fmt.Fprint(w, string(addJSONResp)) })) } // createCA initializes an ephemeral CA server and CT log server func createCA(_ *config.FulcioConfig, t *testing.T) (*ctclient.LogClient, *ephemeralca.EphemeralCA) { // Stand up an ephemeral CA we can use for signing certificate requests. eca, err := ephemeralca.NewEphemeralCA() if err != nil { t.Fatalf("ephemeralca.NewEphemeralCA() = %v", err) } ctlogServer := fakeCTLogServer(t) if ctlogServer == nil { t.Fatalf("failed to create the fake ctlog server") } // Create a test HTTP server to host our API. ctClient, err := ctclient.New(ctlogServer.URL, &http.Client{Timeout: 30 * time.Second}, jsonclient.Options{}) if err != nil { t.Fatalf("error creating CT client: %v", err) } return ctClient, eca } // generateKeyAndProof creates a public key to be certified and creates a // signature for the OIDC token subject func generateKeyAndProof(subject string, t *testing.T) (string, []byte) { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("GenerateKey() = %v", err) } pubBytes, err := x509.MarshalPKIXPublicKey(&priv.PublicKey) if err != nil { t.Fatalf("x509.MarshalPKIXPublicKey() = %v", err) } hash := sha256.Sum256([]byte(subject)) proof, err := ecdsa.SignASN1(rand.Reader, priv, hash[:]) if err != nil { t.Fatalf("SignASN1() = %v", err) } return string(cryptoutils.PEMEncode(cryptoutils.PublicKeyPEMType, pubBytes)), proof } // findCustomExtension searches a certificate's non-critical extensions by OID func findCustomExtension(cert *x509.Certificate, oid asn1.ObjectIdentifier) (pkix.Extension, bool) { for _, ext := range cert.Extensions { if reflect.DeepEqual(ext.Id, oid) { return ext, true } } return pkix.Extension{}, false } // verifyResponse validates common response expectations for each response field func verifyResponse(resp *protobuf.SigningCertificate, eca *ephemeralca.EphemeralCA, issuer string, t *testing.T) *x509.Certificate { // Expect SCT if resp.GetSignedCertificateDetachedSct() != nil && string(resp.GetSignedCertificateDetachedSct().SignedCertificateTimestamp) == "" { t.Fatal("unexpected empty SCT in response") } var chain *protobuf.CertificateChain if resp.GetSignedCertificateDetachedSct() != nil { chain = resp.GetSignedCertificateDetachedSct().Chain } else { chain = resp.GetSignedCertificateEmbeddedSct().Chain } // Expect root certficate in resp.ChainPEM if len(chain.Certificates) == 0 { t.Fatal("unexpected empty chain in response") } // Expect root cert matches the server's configured root block, rest := pem.Decode([]byte(chain.Certificates[1])) if block == nil { t.Fatal("missing PEM data") } // Note: This may change in the future if we use intermediate certificates. if len(rest) != 0 { t.Fatal("expected only one certificate in PEM block chain") } if block.Type != "CERTIFICATE" { t.Fatalf("unexpected root type, expected CERTIFICATE, got %s", block.Type) } rootCert, err := x509.ParseCertificate(block.Bytes) if err != nil { t.Fatalf("failed to parse the received root cert: %v", err) } certs, _ := eca.GetSignerWithChain() if !rootCert.Equal(certs[0]) { t.Errorf("root CA does not match, wanted %+v got %+v", certs[0], rootCert) } // Expect leaf certificate values // TODO: if there are intermediates added, this logic needs to change block, rest = pem.Decode([]byte(chain.Certificates[0])) if len(rest) != 0 { t.Fatal("expected only one leaf certificate in PEM block") } leafCert, err := x509.ParseCertificate(block.Bytes) if err != nil { t.Fatalf("failed to parse the received leaf cert: %v", err) } if leafCert.SerialNumber == nil { t.Fatalf("expected certificate serial number") } if leafCert.NotAfter.Sub(leafCert.NotBefore) != time.Duration(10*time.Minute) { t.Fatalf("expected 10 minute lifetime, got %v", leafCert.NotAfter.Sub(leafCert.NotBefore)) } if len(leafCert.SubjectKeyId) != 20 { t.Fatalf("expected certificate subject key ID to be of length 20 bytes, got %d", len(leafCert.SubjectKeyId)) } if leafCert.KeyUsage != x509.KeyUsageDigitalSignature { t.Fatalf("unexpected key usage, expected %v, got %v", x509.KeyUsageDigitalSignature, leafCert.KeyUsage) } if len(leafCert.ExtKeyUsage) != 1 { t.Fatalf("unexpected length of extended key usage, expected 1, got %d", len(leafCert.ExtKeyUsage)) } if leafCert.ExtKeyUsage[0] != x509.ExtKeyUsageCodeSigning { t.Fatalf("unexpected key usage, expected %v, got %v", x509.ExtKeyUsageCodeSigning, leafCert.ExtKeyUsage[0]) } // Check issuer in custom OIDs issuerExt, found := findCustomExtension(leafCert, asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}) if !found { t.Fatal("expected issuer in custom OID 1.3.6.1.4.1.57264.1.1") } if string(issuerExt.Value) != issuer { t.Fatalf("unexpected issuer for 1.1, expected %s, got %s", issuer, string(issuerExt.Value)) } issuerExt, found = findCustomExtension(leafCert, asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 8}) if !found { t.Fatal("expected issuer in custom OID 1.3.6.1.4.1.57264.1.8") } // verify ASN.1 encoding is correct var raw asn1.RawValue rest, err = asn1.Unmarshal(issuerExt.Value, &raw) if err != nil { t.Fatalf("unexpected error unmarshalling issuer to RawValue: %v", err) } if len(rest) != 0 { t.Fatalf("unexpected trailing bytes in issuer") } // Universal class if raw.Class != 0 { t.Fatalf("expected ASN.1 issuer class to be 0, got %d", raw.Class) } // UTF8String if raw.Tag != 12 { t.Fatalf("expected ASN.1 issuer tag to be 12, got %d", raw.Tag) } // verify issuer unmarshals properly var issuerVal string rest, err = asn1.Unmarshal(issuerExt.Value, &issuerVal) if err != nil { t.Fatalf("unexpected error unmarshalling issuer: %v", err) } if len(rest) != 0 { t.Fatalf("unexpected trailing bytes in issuer") } if string(issuerVal) != issuer { t.Fatalf("unexpected issuer 1.3.6.1.4.1.57264.1.8, expected %s, got %s", issuer, string(issuerExt.Value)) } return leafCert } // Fake CA service that always fails. type FailingCertificateAuthority struct { } func (fca *FailingCertificateAuthority) CreateCertificate(context.Context, identity.Principal, crypto.PublicKey) (*ca.CodeSigningCertificate, error) { return nil, errors.New("CreateCertificate always fails for testing") } func (fca *FailingCertificateAuthority) TrustBundle(_ context.Context) ([][]*x509.Certificate, error) { return nil, errors.New("TrustBundle always fails for testing") } func (fca *FailingCertificateAuthority) Close() error { return nil } fulcio-1.6.5/pkg/server/issuer_pool.go000066400000000000000000000050021470150653400177670ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 server import ( "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/buildkite" "github.com/sigstore/fulcio/pkg/identity/chainguard" "github.com/sigstore/fulcio/pkg/identity/ciprovider" "github.com/sigstore/fulcio/pkg/identity/codefresh" "github.com/sigstore/fulcio/pkg/identity/email" "github.com/sigstore/fulcio/pkg/identity/github" "github.com/sigstore/fulcio/pkg/identity/gitlabcom" "github.com/sigstore/fulcio/pkg/identity/kubernetes" "github.com/sigstore/fulcio/pkg/identity/spiffe" "github.com/sigstore/fulcio/pkg/identity/uri" "github.com/sigstore/fulcio/pkg/identity/username" ) func NewIssuerPool(cfg *config.FulcioConfig) identity.IssuerPool { var ip identity.IssuerPool for _, i := range cfg.OIDCIssuers { iss := getIssuer("", i) if iss != nil { ip = append(ip, iss) } } for meta, i := range cfg.MetaIssuers { iss := getIssuer(meta, i) if iss != nil { ip = append(ip, iss) } } return ip } func getIssuer(meta string, i config.OIDCIssuer) identity.Issuer { issuerURL := i.IssuerURL if meta != "" { issuerURL = meta } switch i.Type { case config.IssuerTypeEmail: return email.Issuer(issuerURL) case config.IssuerTypeGithubWorkflow: return github.Issuer(issuerURL) case config.IssuerTypeCIProvider: return ciprovider.Issuer(issuerURL) case config.IssuerTypeGitLabPipeline: return gitlabcom.Issuer(issuerURL) case config.IssuerTypeBuildkiteJob: return buildkite.Issuer(issuerURL) case config.IssuerTypeCodefreshWorkflow: return codefresh.Issuer(issuerURL) case config.IssuerTypeChainguard: return chainguard.Issuer(issuerURL) case config.IssuerTypeKubernetes: return kubernetes.Issuer(issuerURL) case config.IssuerTypeSpiffe: return spiffe.Issuer(issuerURL) case config.IssuerTypeURI: return uri.Issuer(issuerURL) case config.IssuerTypeUsername: return username.Issuer(issuerURL) } return nil } fulcio-1.6.5/pkg/server/issuer_pool_test.go000066400000000000000000000072061470150653400210360ustar00rootroot00000000000000// Copyright 2023 The Sigstore 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 server import ( "testing" "github.com/google/go-cmp/cmp" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/base" "github.com/sigstore/fulcio/pkg/identity/email" "github.com/sigstore/fulcio/pkg/identity/github" "github.com/sigstore/fulcio/pkg/identity/kubernetes" "github.com/sigstore/fulcio/pkg/identity/spiffe" "github.com/sigstore/fulcio/pkg/identity/uri" "github.com/sigstore/fulcio/pkg/identity/username" ) func TestIssuerPool(t *testing.T) { // Test the issuer pool with the OIDCIssuers cfg := &config.FulcioConfig{ OIDCIssuers: map[string]config.OIDCIssuer{ "https://oauth2.sigstore.dev/auth": { IssuerURL: "https://oauth2.sigstore.dev/auth", ClientID: "sigstore", IssuerClaim: "$.federated_claims.connector_id", Type: config.IssuerTypeEmail, }, "https://custom.issuer.type": { IssuerURL: "https://custom.issuer.type", Type: "custom", }, }, } // Build the expected issuer pool expected := identity.IssuerPool{ email.Issuer("https://oauth2.sigstore.dev/auth"), } ignoreOpts := []cmp.Option{base.CmpOptions} got := NewIssuerPool(cfg) if d := cmp.Diff(expected, got, ignoreOpts...); d != "" { t.Fatal(d) } // Test the issuer pool with a MetaIssuer cfg = &config.FulcioConfig{ MetaIssuers: map[string]config.OIDCIssuer{ "https://oidc.eks.*.amazonaws.com/id/*": { ClientID: "bar", Type: "kubernetes", }, }, } expected = identity.IssuerPool{ kubernetes.Issuer("https://oidc.eks.*.amazonaws.com/id/*"), } got = NewIssuerPool(cfg) if d := cmp.Diff(expected, got, ignoreOpts...); d != "" { t.Fatal(d) } } func TestGetIssuer(t *testing.T) { tests := []struct { description string issuer config.OIDCIssuer expected identity.Issuer }{ { description: "email", issuer: config.OIDCIssuer{ IssuerURL: "email.com", Type: "email", }, expected: email.Issuer("email.com"), }, { description: "github", issuer: config.OIDCIssuer{ IssuerURL: "github.com", Type: "github-workflow", }, expected: github.Issuer("github.com"), }, { description: "spiffe", issuer: config.OIDCIssuer{ IssuerURL: "spiffe.com", Type: "spiffe", }, expected: spiffe.Issuer("spiffe.com"), }, { description: "kubernetes", issuer: config.OIDCIssuer{ IssuerURL: "kubernetes.com", Type: "kubernetes", }, expected: kubernetes.Issuer("kubernetes.com"), }, { description: "uri", issuer: config.OIDCIssuer{ IssuerURL: "uri.com", Type: "uri", }, expected: uri.Issuer("uri.com"), }, { description: "username", issuer: config.OIDCIssuer{ IssuerURL: "username.com", Type: "username", }, expected: username.Issuer("username.com"), }, } ignoreOpts := []cmp.Option{base.CmpOptions} for _, test := range tests { t.Run(test.description, func(t *testing.T) { got := getIssuer("", test.issuer) if d := cmp.Diff(got, test.expected, ignoreOpts...); d != "" { t.Fatal(d) } }) } } fulcio-1.6.5/pkg/server/legacy_server.go000066400000000000000000000124021470150653400202600ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 server import ( "context" "encoding/base64" "errors" "strings" fulciogrpc "github.com/sigstore/fulcio/pkg/generated/protobuf" "github.com/sigstore/fulcio/pkg/generated/protobuf/legacy" "google.golang.org/genproto/googleapis/api/httpbody" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" emptypb "google.golang.org/protobuf/types/known/emptypb" ) const ( PEMCertificateChain = "application/pem-certificate-chain" SCTMetadataKey = "x-sct" HTTPResponseCodeMetadataKey = "x-http-code" ) type legacyGRPCCAServer struct { legacy.UnimplementedCAServer v2Server fulciogrpc.CAServer } func NewLegacyGRPCCAServer(v2Server fulciogrpc.CAServer) legacy.CAServer { return &legacyGRPCCAServer{ v2Server: v2Server, } } func (l *legacyGRPCCAServer) CreateSigningCertificate(ctx context.Context, request *legacy.CreateSigningCertificateRequest) (*httpbody.HttpBody, error) { // OIDC token either is passed in gRPC field or was extracted from HTTP headers token := "" if md, ok := metadata.FromIncomingContext(ctx); ok { vals := md.Get(MetadataOIDCTokenKey) if len(vals) == 1 { token = vals[0] } } creds := fulciogrpc.Credentials{ Credentials: &fulciogrpc.Credentials_OidcIdentityToken{ OidcIdentityToken: token, }, } var v2Request fulciogrpc.CreateSigningCertificateRequest if len(request.CertificateSigningRequest) > 0 { key := fulciogrpc.CreateSigningCertificateRequest_CertificateSigningRequest{ CertificateSigningRequest: request.CertificateSigningRequest, //lint:ignore SA1019 this is valid because we're converting from v1beta to v1 API } v2Request = fulciogrpc.CreateSigningCertificateRequest{ Credentials: &creds, Key: &key, } } else { // the CSR and the public key have not been set if request.PublicKey == nil { return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, errors.New("public key not provided"), invalidPublicKey) } // create new CA request mapping fields from legacy to actual algorithmEnum, ok := fulciogrpc.PublicKeyAlgorithm_value[strings.ToUpper(request.PublicKey.Algorithm)] //lint:ignore SA1019 this is valid because we're converting from v1beta to v1 API if !ok { algorithmEnum = int32(fulciogrpc.PublicKeyAlgorithm_PUBLIC_KEY_ALGORITHM_UNSPECIFIED) } key := fulciogrpc.CreateSigningCertificateRequest_PublicKeyRequest{ PublicKeyRequest: &fulciogrpc.PublicKeyRequest{ PublicKey: &fulciogrpc.PublicKey{ Algorithm: fulciogrpc.PublicKeyAlgorithm(algorithmEnum), Content: string(request.PublicKey.Content), //lint:ignore SA1019 this is valid because we're converting from v1beta to v1 API }, ProofOfPossession: request.SignedEmailAddress, //lint:ignore SA1019 this is valid because we're converting from v1beta to v1 API, }, } v2Request = fulciogrpc.CreateSigningCertificateRequest{ Credentials: &creds, Key: &key, } } v2Response, err := l.v2Server.CreateSigningCertificate(ctx, &v2Request) if err != nil { return nil, err } // we need to return a HTTP 201 Created response code to be backward compliant if err = grpc.SetHeader(ctx, metadata.Pairs(HTTPResponseCodeMetadataKey, "201")); err != nil { return nil, err } detachedResponse := v2Response.GetSignedCertificateDetachedSct() if detachedResponse != nil && len(detachedResponse.SignedCertificateTimestamp) > 0 { // the SCT for the certificate needs to be returned in a HTTP response header sctString := base64.StdEncoding.EncodeToString(detachedResponse.SignedCertificateTimestamp) if sctString != "" { if err := grpc.SetHeader(ctx, metadata.Pairs(SCTMetadataKey, sctString)); err != nil { return nil, err } } } var chain *fulciogrpc.CertificateChain if detachedResponse != nil { chain = detachedResponse.Chain } else { chain = v2Response.GetSignedCertificateEmbeddedSct().Chain } var concatCerts strings.Builder for _, cert := range chain.Certificates { concatCerts.WriteString(cert) concatCerts.WriteRune('\n') } return &httpbody.HttpBody{ ContentType: PEMCertificateChain, Data: []byte(string(strings.TrimSpace(concatCerts.String()))), }, nil } func (l *legacyGRPCCAServer) GetRootCertificate(ctx context.Context, _ *emptypb.Empty) (*httpbody.HttpBody, error) { v2Response, err := l.v2Server.GetTrustBundle(ctx, &fulciogrpc.GetTrustBundleRequest{}) if err != nil { return nil, err } var concatCerts strings.Builder for _, chain := range v2Response.Chains { for _, cert := range chain.Certificates { concatCerts.WriteString(cert) concatCerts.WriteRune('\n') } } return &httpbody.HttpBody{ ContentType: PEMCertificateChain, Data: []byte(strings.TrimSpace(concatCerts.String())), }, nil } fulcio-1.6.5/pkg/server/max_bytes.go000066400000000000000000000016601470150653400174250ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 server import "net/http" // WithMaxBytes sets the max request size on a handler to n bytes. func WithMaxBytes(next http.Handler, n int64) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { limitedReader := http.MaxBytesReader(w, r.Body, n) r.Body = limitedReader next.ServeHTTP(w, r) }) } fulcio-1.6.5/pkg/server/max_bytes_test.go000066400000000000000000000034551470150653400204700ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 server import ( "io" "net/http" "net/http/httptest" "strings" "testing" ) func TestWithMaxBytes(t *testing.T) { var maxBodySize int64 = 10 handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, err := io.ReadAll(r.Body) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } }) ts := httptest.NewServer(WithMaxBytes(handler, maxBodySize)) tests := map[string]struct { Body string ExpectedStatus int }{ "Less than max": { Body: strings.Repeat("a", int(maxBodySize-1)), ExpectedStatus: http.StatusOK, }, "At max": { Body: strings.Repeat("b", int(maxBodySize)), ExpectedStatus: http.StatusOK, }, "Over max": { Body: strings.Repeat("c", int(maxBodySize+1)), ExpectedStatus: http.StatusBadRequest, }, } for testcase, data := range tests { t.Run(testcase, func(t *testing.T) { resp, err := http.Post(ts.URL, "text/plain", strings.NewReader(data.Body)) if err != nil { t.Fatal("Failed to send request to test server", err) } if resp.StatusCode != data.ExpectedStatus { t.Error("Expected status code", data.ExpectedStatus, "but got", resp.StatusCode) } }) } } fulcio-1.6.5/pkg/server/metrics.go000066400000000000000000000034031470150653400170750ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 server import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "sigs.k8s.io/release-utils/version" ) var ( metricNewEntries = promauto.NewCounter(prometheus.CounterOpts{ Name: "fulcio_new_certs", Help: "The total number of certificates generated", }) MetricLatency = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "fulcio_api_latency", Help: "API Latency on calls", }, []string{"code", "method"}) RequestsCount = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "http_requests_total", Help: "Count all HTTP requests", }, []string{"code", "method"}) _ = promauto.NewGaugeFunc( prometheus.GaugeOpts{ Namespace: "fulcio", Name: "build_info", Help: "A metric with a constant '1' value labeled by version, revision, branch, and goversion from which fulcio was built.", ConstLabels: prometheus.Labels{ "version": version.GetVersionInfo().GitVersion, "revision": version.GetVersionInfo().GitCommit, "build_date": version.GetVersionInfo().BuildDate, "goversion": version.GetVersionInfo().GoVersion, }, }, func() float64 { return 1 }, ) ) fulcio-1.6.5/pkg/server/version.go000066400000000000000000000051011470150653400171110ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 server import ( "encoding/json" "fmt" "runtime" "strings" "text/tabwriter" ) // Base version information. // // This is the fallback data used when version information from git is not // provided via go ldflags (e.g. via Makefile). var ( // Output of "git describe". The prerequisite is that the branch should be // tagged using the correct versioning strategy. gitVersion = "unknown" // SHA1 from git, output of $(git rev-parse HEAD) gitCommit = "unknown" // State of git tree, either "clean" or "dirty" gitTreeState = "unknown" // Build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ') buildDate = "unknown" ) type Info struct { GitVersion string GitCommit string GitTreeState string BuildDate string GoVersion string Compiler string Platform string } func VersionInfo() Info { // These variables typically come from -ldflags settings and in // their absence fallback to the global defaults set above. return Info{ GitVersion: gitVersion, GitCommit: gitCommit, GitTreeState: gitTreeState, BuildDate: buildDate, GoVersion: runtime.Version(), Compiler: runtime.Compiler, Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), } } // String returns the string representation of the version info func (i *Info) String() string { b := strings.Builder{} w := tabwriter.NewWriter(&b, 0, 0, 2, ' ', 0) fmt.Fprintf(w, "GitVersion:\t%s\n", i.GitVersion) fmt.Fprintf(w, "GitCommit:\t%s\n", i.GitCommit) fmt.Fprintf(w, "GitTreeState:\t%s\n", i.GitTreeState) fmt.Fprintf(w, "BuildDate:\t%s\n", i.BuildDate) fmt.Fprintf(w, "GoVersion:\t%s\n", i.GoVersion) fmt.Fprintf(w, "Compiler:\t%s\n", i.Compiler) fmt.Fprintf(w, "Platform:\t%s\n", i.Platform) w.Flush() // #nosec return b.String() } // JSONString returns the JSON representation of the version info func (i *Info) JSONString() (string, error) { b, err := json.MarshalIndent(i, "", " ") if err != nil { return "", err } return string(b), nil } fulcio-1.6.5/pkg/test/000077500000000000000000000000001470150653400145515ustar00rootroot00000000000000fulcio-1.6.5/pkg/test/cert_utils.go000066400000000000000000000146661470150653400172720ustar00rootroot00000000000000// Copyright 2022 The Sigstore 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 test import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "math/big" "time" ) /* To use: rootCert, rootKey, _ := GenerateRootCA() subCert, subKey, _ := GenerateSubordinateCa(rootCert, rootKey) leafCert, _, _ := GenerateLeafCert("subject", "oidc-issuer", subCert, subKey) roots := x509.NewCertPool() subs := x509.NewCertPool() roots.AddCert(rootCert) subs.AddCert(subCert) opts := x509.VerifyOptions{ Roots: roots, Intermediates: subs, KeyUsages: []x509.ExtKeyUsage{ x509.ExtKeyUsageCodeSigning, }, } _, err := leafCert.Verify(opts) */ func createCertificate(template *x509.Certificate, parent *x509.Certificate, pub interface{}, priv crypto.Signer) (*x509.Certificate, error) { certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, pub, priv) if err != nil { return nil, err } cert, err := x509.ParseCertificate(certBytes) if err != nil { return nil, err } return cert, nil } func GenerateRootCA() (*x509.Certificate, *ecdsa.PrivateKey, error) { rootTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "sigstore", Organization: []string{"sigstore.dev"}, }, NotBefore: time.Now().Add(-5 * time.Minute), NotAfter: time.Now().Add(5 * time.Hour), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, BasicConstraintsValid: true, IsCA: true, } priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, nil, err } cert, err := createCertificate(rootTemplate, rootTemplate, &priv.PublicKey, priv) if err != nil { return nil, nil, err } return cert, priv, nil } func GenerateRootCAFromSigner(signer crypto.Signer) (*x509.Certificate, error) { rootTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "sigstore", Organization: []string{"sigstore.dev"}, }, NotBefore: time.Now().Add(-5 * time.Minute), NotAfter: time.Now().Add(5 * time.Hour), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, BasicConstraintsValid: true, IsCA: true, } cert, err := createCertificate(rootTemplate, rootTemplate, signer.Public(), signer) if err != nil { return nil, err } return cert, nil } func GenerateSubordinateCA(rootTemplate *x509.Certificate, rootPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { subTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "sigstore-sub", Organization: []string{"sigstore.dev"}, }, NotBefore: time.Now().Add(-2 * time.Minute), NotAfter: time.Now().Add(2 * time.Hour), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, BasicConstraintsValid: true, IsCA: true, } priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, nil, err } cert, err := createCertificate(subTemplate, rootTemplate, &priv.PublicKey, rootPriv) if err != nil { return nil, nil, err } return cert, priv, nil } func GenerateWeakSubordinateCA(rootTemplate *x509.Certificate, rootPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { subTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "sigstore-sub", Organization: []string{"sigstore.dev"}, }, NotBefore: time.Now().Add(-2 * time.Minute), NotAfter: time.Now().Add(2 * time.Hour), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, BasicConstraintsValid: true, IsCA: true, } priv, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) if err != nil { return nil, nil, err } cert, err := createCertificate(subTemplate, rootTemplate, &priv.PublicKey, rootPriv) if err != nil { return nil, nil, err } return cert, priv, nil } func GenerateSubordinateCAWithoutEKU(rootTemplate *x509.Certificate, rootPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { subTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "sigstore-sub", Organization: []string{"sigstore.dev"}, }, NotBefore: time.Now().Add(-2 * time.Minute), NotAfter: time.Now().Add(2 * time.Hour), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, BasicConstraintsValid: true, IsCA: true, } priv, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) if err != nil { return nil, nil, err } cert, err := createCertificate(subTemplate, rootTemplate, &priv.PublicKey, rootPriv) if err != nil { return nil, nil, err } return cert, priv, nil } func GenerateLeafCert(subject string, oidcIssuer string, parentTemplate *x509.Certificate, parentPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { certTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), EmailAddresses: []string{subject}, NotBefore: time.Now().Add(-1 * time.Minute), NotAfter: time.Now().Add(time.Hour), KeyUsage: x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, IsCA: false, ExtraExtensions: []pkix.Extension{{ // OID for OIDC Issuer extension Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, Critical: false, Value: []byte(oidcIssuer), }}, } priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, nil, err } cert, err := createCertificate(certTemplate, parentTemplate, &priv.PublicKey, parentPriv) if err != nil { return nil, nil, err } return cert, priv, nil } fulcio-1.6.5/release/000077500000000000000000000000001470150653400144315ustar00rootroot00000000000000fulcio-1.6.5/release/README.md000066400000000000000000000052201470150653400157070ustar00rootroot00000000000000# Release This directory contain the files and scripts to run a Fulcio release. # Cutting a Fulcio Release 1. Release notes: Create a PR to update and review release notes in CHANGELOG.md. Check merged pull requests since the last release and make sure enhancements, bug fixes, and authors are reflected in the notes. You can get a list of pull requests since the last release by substituting in the date of the last release and running: ``` git log --pretty="* %s" --after="YYYY-MM-DD" ``` and a list of authors by running: ``` git log --pretty="* %an" --after="YYYY-MM-DD" | sort -u ``` 2. Open a Pull Request to update CHANGELOG.md 3. Tag the repository **WARNING**: Tags should not be updated to a new ref or deleted/recreated after creation. Go provides a [checksum database](https://sum.golang.org/) that persists an immutable mapping between version and ref, and updating the tag will break clients that have already downloaded the release. ```shell $ export RELEASE_TAG= $ git tag -s ${RELEASE_TAG} -m "${RELEASE_TAG}" $ git push upstream ${RELEASE_TAG} ``` Note that `upstream` should be the upstream `sigstore/fulcio` repository. You may have to change this if you've configured remotes. 4. Then go to the `Actions` tab and click on the [Cut Release workflow](https://github.com/sigstore/fulcio/actions/workflows/cut-release.yml). Note you need to be in [this list](https://github.com/sigstore/sigstore/blob/main/.github/workflows/reusable-release.yml#L45) to trigger this workflow. Click to run a workflow and insert the following parameters ("Cosign" is correct, this just refers to the artifact signing key): - `Release tag`: the tag that use pushed for the release - `Key ring for cosign key`: the value is `release-cosign` - `Key name for cosign key`: the value is `cosign` That will trigger a CloudBuild job and will run the release using `goreleaser`, which will publish images to `gcr.io` and `ghcr.io`, and the binaries will be available in the GitHub release. If you have permissions to access the project, you can follow the CloudBuild job in the `projectsigstore`(https://console.cloud.google.com/cloud-build/builds?project=projectsigstore) GCP Project. As the last step of the CloudBuild job, `goreleaser` will create a `draft release` in GitHub. 5. Navigate to the `Draft Release` in the Github repository. Click the `Publish Release` button to make the Release available. You might want/need to add any extra notes/breaking changes notices, upgrade paths. 6. Post on the `#general` and `#fulcio` Slack channels. 7. If it's a significant release, send an announcement email to sigstore-dev@googlegroups.com mailing list. fulcio-1.6.5/release/cloudbuild.yaml000066400000000000000000000073711470150653400174530ustar00rootroot00000000000000# # Copyright 2021 The Sigstore 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. --- timeout: 3600s steps: - name: gcr.io/cloud-builders/git dir: "go/src/sigstore" args: - "clone" - "https://github.com/${_TOOL_ORG}/${_TOOL_REPO}" - name: gcr.io/cloud-builders/git entrypoint: "bash" dir: "go/src/sigstore/fulcio" args: - '-c' - | git fetch echo "Checking out ${_GIT_TAG}" git checkout ${_GIT_TAG} - name: 'ghcr.io/sigstore/cosign/cosign:v2.4.1-dev@sha256:a1bb112f1758703aa1d222bf30b9655d04cf196c0b7feaf3479d1222c2283590' dir: "go/src/sigstore/fulcio" env: - TUF_ROOT=/tmp args: - 'verify' - 'ghcr.io/gythialy/golang-cross:v1.23.2-0@sha256:8feb33a131baabdef112d924a4379ff6b0a4f00a4854f97b0dc73742198638bd' - '--certificate-oidc-issuer' - "https://token.actions.githubusercontent.com" - '--certificate-identity' - "https://github.com/gythialy/golang-cross/.github/workflows/release-golang-cross.yml@refs/tags/v1.23.2-0" - name: ghcr.io/gythialy/golang-cross:v1.23.2-0@sha256:8feb33a131baabdef112d924a4379ff6b0a4f00a4854f97b0dc73742198638bd entrypoint: /bin/sh dir: "go/src/sigstore/fulcio" env: - "GOPATH=/workspace/go" - "GOBIN=/workspace/bin" - PROJECT_ID=${PROJECT_ID} - KEY_LOCATION=${_KEY_LOCATION} - KEY_RING=${_KEY_RING} - KEY_NAME=${_KEY_NAME} - KEY_VERSION=${_KEY_VERSION} - GIT_TAG=${_GIT_TAG} - GOOGLE_SERVICE_ACCOUNT_NAME=keyless@${PROJECT_ID}.iam.gserviceaccount.com - KO_PREFIX=gcr.io/${PROJECT_ID} - TUF_ROOT=/tmp secretEnv: - GITHUB_TOKEN args: - '-c' - | gcloud auth configure-docker \ && make release - name: ghcr.io/gythialy/golang-cross:v1.23.2-0@sha256:8feb33a131baabdef112d924a4379ff6b0a4f00a4854f97b0dc73742198638bd entrypoint: 'bash' dir: "go/src/sigstore/fulcio" env: - "GOPATH=/workspace/go" - "GOBIN=/workspace/bin" - PROJECT_ID=${PROJECT_ID} - KEY_LOCATION=${_KEY_LOCATION} - KEY_RING=${_KEY_RING} - KEY_NAME=${_KEY_NAME} - KEY_VERSION=${_KEY_VERSION} - GIT_TAG=${_GIT_TAG} - KO_PREFIX=gcr.io/${PROJECT_ID} - GOOGLE_SERVICE_ACCOUNT_NAME=keyless@${PROJECT_ID}.iam.gserviceaccount.com - GITHUB_USER=${_GITHUB_USER} - TUF_ROOT=/tmp secretEnv: - GITHUB_TOKEN args: - '-c' - | echo $$GITHUB_TOKEN | docker login ghcr.io -u $$GITHUB_USER --password-stdin \ && make copy-signed-release-to-ghcr availableSecrets: secretManager: - versionName: projects/${PROJECT_NUMBER}/secrets/GITHUB_TOKEN/versions/latest env: GITHUB_TOKEN artifacts: objects: location: 'gs://${_STORAGE_LOCATION}/${_GIT_TAG}' paths: - "go/src/sigstore/fulcio/dist/fulcio*" - "go/src/sigstore/fulcio/release/release-cosign.pub" - "go/src/sigstore/fulcio/fulcio*.yaml" options: machineType: E2_HIGHCPU_8 tags: - fulcio-release - ${_GIT_TAG} - ${_TOOL_ORG} - ${_TOOL_REPO} substitutions: _GIT_TAG: 'v0.0.0' _TOOL_ORG: 'honk' _TOOL_REPO: 'honk-repo' _STORAGE_LOCATION: 'honk' _KEY_RING: 'honk-ring' _KEY_NAME: 'honk-crypto' _KEY_VERSION: '1' _KEY_LOCATION: 'global' _GITHUB_USER: 'placeholder' fulcio-1.6.5/release/release-cosign.pub000066400000000000000000000002621470150653400200410ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhyQCx0E9wQWSFI9ULGwy3BuRklnt IqozONbbdbqz11hlRJy9c7SG+hdcFl9jE9uE/dwtuwU2MqU9T/cN0YkWww== -----END PUBLIC KEY----- fulcio-1.6.5/release/release.mk000066400000000000000000000067311470150653400164110ustar00rootroot00000000000000################## # release section ################## # used when releasing together with GCP CloudBuild .PHONY: release release: LDFLAGS="$(LDFLAGS)" goreleaser release # used when need to validate the goreleaser .PHONY: snapshot snapshot: LDFLAGS="$(LDFLAGS)" goreleaser release --skip=sign,publish --snapshot --clean ################## # images section ################## ALL_ARCH = amd64 arm arm64 ppc64le s390x .PHONY: ko-release ko-release: # amd64 LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ ko resolve --base-import-paths \ --platform=linux/amd64 --tags $(GIT_VERSION)-amd64 --tags $(GIT_HASH)-amd64 \ --filename config/ > $(FULCIO_YAML) # arm64 LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ CC=aarch64-linux-gnu-gcc \ ko publish --base-import-paths \ --platform=linux/arm64 --tags $(GIT_VERSION)-arm64 --tags $(GIT_HASH)-arm64 \ github.com/sigstore/fulcio # arm LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ CC=arm-linux-gnueabihf-gcc \ ko publish --base-import-paths \ --platform=linux/arm --tags $(GIT_VERSION)-arm --tags $(GIT_HASH)-arm \ github.com/sigstore/fulcio # ppc64le LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ CC=powerpc64le-linux-gnu-gcc \ ko publish --base-import-paths \ --platform=linux/ppc64le --tags $(GIT_VERSION)-ppc64le --tags $(GIT_HASH)-ppc64le \ github.com/sigstore/fulcio # s390x LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ CC=s390x-linux-gnu-gcc \ ko publish --base-import-paths \ --platform=linux/s390x --tags $(GIT_VERSION)-s390x --tags $(GIT_HASH)-s390x \ github.com/sigstore/fulcio .PHONY: push-manifest push-manifest: docker manifest create --amend $(KO_PREFIX)/fulcio:$(GIT_VERSION) $(shell echo $(ALL_ARCH) | sed -e "s~[^ ]*~$(KO_PREFIX)/fulcio:$(GIT_VERSION)\-&~g") @for arch in $(ALL_ARCH); do docker manifest annotate --arch $${arch} ${KO_PREFIX}/fulcio:${GIT_VERSION} ${KO_PREFIX}/fulcio:${GIT_VERSION}-$${arch}; done docker manifest push --purge ${KO_PREFIX}/fulcio:${GIT_VERSION} docker manifest create --amend $(KO_PREFIX)/fulcio:$(GIT_HASH) $(shell echo $(ALL_ARCH) | sed -e "s~[^ ]*~$(KO_PREFIX)/fulcio:$(GIT_HASH)\-&~g") @for arch in $(ALL_ARCH); do docker manifest annotate --arch $${arch} ${KO_PREFIX}/fulcio:${GIT_HASH} ${KO_PREFIX}/fulcio:${GIT_HASH}-$${arch}; done docker manifest push --purge ${KO_PREFIX}/fulcio:${GIT_HASH} .PHONY: update-yaml update-yaml: sed -i -e 's/$(subst /,\/,$(KO_PREFIX))\/fulcio@.*/$(subst /,\/,$(KO_PREFIX))\/fulcio:$(GIT_VERSION)/g' $(FULCIO_YAML) .PHONY: release-images release-images: ko-release push-manifest update-yaml ########################### # sign with GCP KMS section ########################### .PHONY: sign-container-release sign-container-release: release-images cosign sign --yes --key "gcpkms://projects/${PROJECT_ID}/locations/${KEY_LOCATION}/keyRings/${KEY_RING}/cryptoKeys/${KEY_NAME}/versions/${KEY_VERSION}" -a GIT_HASH=$(GIT_HASH) -a GIT_VERSION=$(GIT_VERSION) ${KO_PREFIX}/fulcio:$(GIT_VERSION) ###################### # sign keyless section ###################### .PHONY: sign-keyless-release sign-keyless-release: cosign sign --yes -a GIT_HASH=$(GIT_HASH) -a GIT_VERSION=$(GIT_VERSION) ${KO_PREFIX}/fulcio:$(GIT_VERSION) #################### # copy image to GHCR #################### .PHONY: copy-signed-release-to-ghcr copy-signed-release-to-ghcr: cosign copy ${KO_PREFIX}/fulcio:$(GIT_VERSION) ${GHCR_PREFIX}/fulcio:$(GIT_VERSION) fulcio-1.6.5/test/000077500000000000000000000000001470150653400137705ustar00rootroot00000000000000fulcio-1.6.5/test/prometheus/000077500000000000000000000000001470150653400161635ustar00rootroot00000000000000fulcio-1.6.5/test/prometheus/main.go000066400000000000000000000063741470150653400174500ustar00rootroot00000000000000// Copyright 2021 The Sigstore 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 main import ( "flag" "fmt" "log" "net/http" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" ) const ( latencyMetric = "fulcio_api_latency" certMetric = "fulcio_new_certs" ) func parseMF(url string) (map[string]*dto.MetricFamily, error) { resp, err := http.Get(url) // nolint if err != nil { return nil, err } defer resp.Body.Close() var parser expfmt.TextParser return parser.TextToMetricFamilies(resp.Body) } func main() { f := flag.String("url", "http://fulcio-server.fulcio-system.svc:2112/metrics", "set url to fetch metrics from") flag.Parse() mf, err := parseMF(*f) if err != nil { log.Fatalf("Failed to fetch/parse metrics: %v", err) } // Just grab the api_latency metric, make sure it's a histogram // and just make sure there is at least one 200, and no errors there. latency, ok := mf[latencyMetric] if !ok || latency == nil { log.Fatal("Did not get fulcio_api_latency metric") } if err := checkLatency(latency); err != nil { log.Fatalf("fulcio_api_latency metric failed: %s", err) } // Then make sure the cert counter went up. certCount, ok := mf[certMetric] if !ok || certCount == nil { log.Fatal("Did not get fulcio_new_certs metric") } if err := checkCertCount(certCount); err != nil { log.Fatalf("fulcio_new_certs metric failed: %s", err) } } // Make sure latency is a Histogram, and it has a POST with a 201. func checkLatency(latency *dto.MetricFamily) error { if *latency.Type != *dto.MetricType_HISTOGRAM.Enum() { return fmt.Errorf("Wrong type, wanted %+v, got: %+v", dto.MetricType_HISTOGRAM.Enum(), latency.Type) } for _, metric := range latency.Metric { var code string var method string for _, value := range metric.Label { if *value.Name == "code" { code = *value.Value } if *value.Name == "method" { method = *value.Value } } if code == "201" && method == "post" { if *metric.Histogram.SampleCount != 1 { return fmt.Errorf("Unexpected samplecount, wanted 1, got %d", *metric.Histogram.SampleCount) } return nil } } return fmt.Errorf("Got multiple entries, or none for metric, wanted one, got: %+v", latency.Metric) } func checkCertCount(certCount *dto.MetricFamily) error { if *certCount.Type != *dto.MetricType_COUNTER.Enum() { return fmt.Errorf("Wrong type, wanted %+v, got: %+v", dto.MetricType_COUNTER.Enum(), certCount.Type) } if len(certCount.Metric) != 1 { return fmt.Errorf("Got multiple entries, or none for metric, wanted one, got: %+v", certCount.Metric) } if *certCount.Metric[0].Counter.Value < 1 { return fmt.Errorf("Got incorrect cert count, wanted one, got: %f", *certCount.Metric[0].Counter.Value) } return nil } fulcio-1.6.5/third_party/000077500000000000000000000000001470150653400153425ustar00rootroot00000000000000fulcio-1.6.5/third_party/googleapis/000077500000000000000000000000001470150653400174735ustar00rootroot00000000000000fulcio-1.6.5/third_party/googleapis/google/000077500000000000000000000000001470150653400207475ustar00rootroot00000000000000fulcio-1.6.5/third_party/googleapis/google/api/000077500000000000000000000000001470150653400215205ustar00rootroot00000000000000fulcio-1.6.5/third_party/googleapis/google/api/annotations.proto000066400000000000000000000020251470150653400251410ustar00rootroot00000000000000// Copyright 2015 Google LLC // // 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. syntax = "proto3"; package google.api; import "google/api/http.proto"; import "google/protobuf/descriptor.proto"; option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; option java_multiple_files = true; option java_outer_classname = "AnnotationsProto"; option java_package = "com.google.api"; option objc_class_prefix = "GAPI"; extend google.protobuf.MethodOptions { // See `HttpRule`. HttpRule http = 72295728; } fulcio-1.6.5/third_party/googleapis/google/api/field_behavior.proto000066400000000000000000000070241470150653400255520ustar00rootroot00000000000000// Copyright 2018 Google LLC // // 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. syntax = "proto3"; package google.api; import "google/protobuf/descriptor.proto"; option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; option java_multiple_files = true; option java_outer_classname = "FieldBehaviorProto"; option java_package = "com.google.api"; option objc_class_prefix = "GAPI"; extend google.protobuf.FieldOptions { // A designation of a specific field behavior (required, output only, etc.) // in protobuf messages. // // Examples: // // string name = 1 [(google.api.field_behavior) = REQUIRED]; // State state = 1 [(google.api.field_behavior) = OUTPUT_ONLY]; // google.protobuf.Duration ttl = 1 // [(google.api.field_behavior) = INPUT_ONLY]; // google.protobuf.Timestamp expire_time = 1 // [(google.api.field_behavior) = OUTPUT_ONLY, // (google.api.field_behavior) = IMMUTABLE]; repeated google.api.FieldBehavior field_behavior = 1052; } // An indicator of the behavior of a given field (for example, that a field // is required in requests, or given as output but ignored as input). // This **does not** change the behavior in protocol buffers itself; it only // denotes the behavior and may affect how API tooling handles the field. // // Note: This enum **may** receive new values in the future. enum FieldBehavior { // Conventional default for enums. Do not use this. FIELD_BEHAVIOR_UNSPECIFIED = 0; // Specifically denotes a field as optional. // While all fields in protocol buffers are optional, this may be specified // for emphasis if appropriate. OPTIONAL = 1; // Denotes a field as required. // This indicates that the field **must** be provided as part of the request, // and failure to do so will cause an error (usually `INVALID_ARGUMENT`). REQUIRED = 2; // Denotes a field as output only. // This indicates that the field is provided in responses, but including the // field in a request does nothing (the server *must* ignore it and // *must not* throw an error as a result of the field's presence). OUTPUT_ONLY = 3; // Denotes a field as input only. // This indicates that the field is provided in requests, and the // corresponding field is not included in output. INPUT_ONLY = 4; // Denotes a field as immutable. // This indicates that the field may be set once in a request to create a // resource, but may not be changed thereafter. IMMUTABLE = 5; // Denotes that a (repeated) field is an unordered list. // This indicates that the service may provide the elements of the list // in any arbitrary order, rather than the order the user originally // provided. Additionally, the list's order may or may not be stable. UNORDERED_LIST = 6; // Denotes that this field returns a non-empty default value if not set. // This indicates that if the user provides the empty value in a request, // a non-empty value will be returned. The user will not be aware of what // non-empty value to expect. NON_EMPTY_DEFAULT = 7; } fulcio-1.6.5/third_party/googleapis/google/api/http.proto000066400000000000000000000354441470150653400235760ustar00rootroot00000000000000// Copyright 2015 Google LLC // // 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. syntax = "proto3"; package google.api; option cc_enable_arenas = true; option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; option java_multiple_files = true; option java_outer_classname = "HttpProto"; option java_package = "com.google.api"; option objc_class_prefix = "GAPI"; // Defines the HTTP configuration for an API service. It contains a list of // [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method // to one or more HTTP REST API methods. message Http { // A list of HTTP configuration rules that apply to individual API methods. // // **NOTE:** All service configuration rules follow "last one wins" order. repeated HttpRule rules = 1; // When set to true, URL path parameters will be fully URI-decoded except in // cases of single segment matches in reserved expansion, where "%2F" will be // left encoded. // // The default behavior is to not decode RFC 6570 reserved characters in multi // segment matches. bool fully_decode_reserved_expansion = 2; } // # gRPC Transcoding // // gRPC Transcoding is a feature for mapping between a gRPC method and one or // more HTTP REST endpoints. It allows developers to build a single API service // that supports both gRPC APIs and REST APIs. Many systems, including [Google // APIs](https://github.com/googleapis/googleapis), // [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC // Gateway](https://github.com/grpc-ecosystem/grpc-gateway), // and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature // and use it for large scale production services. // // `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies // how different portions of the gRPC request message are mapped to the URL // path, URL query parameters, and HTTP request body. It also controls how the // gRPC response message is mapped to the HTTP response body. `HttpRule` is // typically specified as an `google.api.http` annotation on the gRPC method. // // Each mapping specifies a URL path template and an HTTP method. The path // template may refer to one or more fields in the gRPC request message, as long // as each field is a non-repeated field with a primitive (non-message) type. // The path template controls how fields of the request message are mapped to // the URL path. // // Example: // // service Messaging { // rpc GetMessage(GetMessageRequest) returns (Message) { // option (google.api.http) = { // get: "/v1/{name=messages/*}" // }; // } // } // message GetMessageRequest { // string name = 1; // Mapped to URL path. // } // message Message { // string text = 1; // The resource content. // } // // This enables an HTTP REST to gRPC mapping as below: // // HTTP | gRPC // -----|----- // `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` // // Any fields in the request message which are not bound by the path template // automatically become HTTP query parameters if there is no HTTP request body. // For example: // // service Messaging { // rpc GetMessage(GetMessageRequest) returns (Message) { // option (google.api.http) = { // get:"/v1/messages/{message_id}" // }; // } // } // message GetMessageRequest { // message SubMessage { // string subfield = 1; // } // string message_id = 1; // Mapped to URL path. // int64 revision = 2; // Mapped to URL query parameter `revision`. // SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. // } // // This enables a HTTP JSON to RPC mapping as below: // // HTTP | gRPC // -----|----- // `GET /v1/messages/123456?revision=2&sub.subfield=foo` | // `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: // "foo"))` // // Note that fields which are mapped to URL query parameters must have a // primitive type or a repeated primitive type or a non-repeated message type. // In the case of a repeated type, the parameter can be repeated in the URL // as `...?param=A¶m=B`. In the case of a message type, each field of the // message is mapped to a separate parameter, such as // `...?foo.a=A&foo.b=B&foo.c=C`. // // For HTTP methods that allow a request body, the `body` field // specifies the mapping. Consider a REST update method on the // message resource collection: // // service Messaging { // rpc UpdateMessage(UpdateMessageRequest) returns (Message) { // option (google.api.http) = { // patch: "/v1/messages/{message_id}" // body: "message" // }; // } // } // message UpdateMessageRequest { // string message_id = 1; // mapped to the URL // Message message = 2; // mapped to the body // } // // The following HTTP JSON to RPC mapping is enabled, where the // representation of the JSON in the request body is determined by // protos JSON encoding: // // HTTP | gRPC // -----|----- // `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: // "123456" message { text: "Hi!" })` // // The special name `*` can be used in the body mapping to define that // every field not bound by the path template should be mapped to the // request body. This enables the following alternative definition of // the update method: // // service Messaging { // rpc UpdateMessage(Message) returns (Message) { // option (google.api.http) = { // patch: "/v1/messages/{message_id}" // body: "*" // }; // } // } // message Message { // string message_id = 1; // string text = 2; // } // // // The following HTTP JSON to RPC mapping is enabled: // // HTTP | gRPC // -----|----- // `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: // "123456" text: "Hi!")` // // Note that when using `*` in the body mapping, it is not possible to // have HTTP parameters, as all fields not bound by the path end in // the body. This makes this option more rarely used in practice when // defining REST APIs. The common usage of `*` is in custom methods // which don't use the URL at all for transferring data. // // It is possible to define multiple HTTP methods for one RPC by using // the `additional_bindings` option. Example: // // service Messaging { // rpc GetMessage(GetMessageRequest) returns (Message) { // option (google.api.http) = { // get: "/v1/messages/{message_id}" // additional_bindings { // get: "/v1/users/{user_id}/messages/{message_id}" // } // }; // } // } // message GetMessageRequest { // string message_id = 1; // string user_id = 2; // } // // This enables the following two alternative HTTP JSON to RPC mappings: // // HTTP | gRPC // -----|----- // `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` // `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: // "123456")` // // ## Rules for HTTP mapping // // 1. Leaf request fields (recursive expansion nested messages in the request // message) are classified into three categories: // - Fields referred by the path template. They are passed via the URL path. // - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP // request body. // - All other fields are passed via the URL query parameters, and the // parameter name is the field path in the request message. A repeated // field can be represented as multiple query parameters under the same // name. // 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields // are passed via URL path and HTTP request body. // 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all // fields are passed via URL path and URL query parameters. // // ### Path template syntax // // Template = "/" Segments [ Verb ] ; // Segments = Segment { "/" Segment } ; // Segment = "*" | "**" | LITERAL | Variable ; // Variable = "{" FieldPath [ "=" Segments ] "}" ; // FieldPath = IDENT { "." IDENT } ; // Verb = ":" LITERAL ; // // The syntax `*` matches a single URL path segment. The syntax `**` matches // zero or more URL path segments, which must be the last part of the URL path // except the `Verb`. // // The syntax `Variable` matches part of the URL path as specified by its // template. A variable template must not contain other variables. If a variable // matches a single path segment, its template may be omitted, e.g. `{var}` // is equivalent to `{var=*}`. // // The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` // contains any reserved character, such characters should be percent-encoded // before the matching. // // If a variable contains exactly one path segment, such as `"{var}"` or // `"{var=*}"`, when such a variable is expanded into a URL path on the client // side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The // server side does the reverse decoding. Such variables show up in the // [Discovery // Document](https://developers.google.com/discovery/v1/reference/apis) as // `{var}`. // // If a variable contains multiple path segments, such as `"{var=foo/*}"` // or `"{var=**}"`, when such a variable is expanded into a URL path on the // client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. // The server side does the reverse decoding, except "%2F" and "%2f" are left // unchanged. Such variables show up in the // [Discovery // Document](https://developers.google.com/discovery/v1/reference/apis) as // `{+var}`. // // ## Using gRPC API Service Configuration // // gRPC API Service Configuration (service config) is a configuration language // for configuring a gRPC service to become a user-facing product. The // service config is simply the YAML representation of the `google.api.Service` // proto message. // // As an alternative to annotating your proto file, you can configure gRPC // transcoding in your service config YAML files. You do this by specifying a // `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same // effect as the proto annotation. This can be particularly useful if you // have a proto that is reused in multiple services. Note that any transcoding // specified in the service config will override any matching transcoding // configuration in the proto. // // Example: // // http: // rules: // # Selects a gRPC method and applies HttpRule to it. // - selector: example.v1.Messaging.GetMessage // get: /v1/messages/{message_id}/{sub.subfield} // // ## Special notes // // When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the // proto to JSON conversion must follow the [proto3 // specification](https://developers.google.com/protocol-buffers/docs/proto3#json). // // While the single segment variable follows the semantics of // [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String // Expansion, the multi segment variable **does not** follow RFC 6570 Section // 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion // does not expand special characters like `?` and `#`, which would lead // to invalid URLs. As the result, gRPC Transcoding uses a custom encoding // for multi segment variables. // // The path variables **must not** refer to any repeated or mapped field, // because client libraries are not capable of handling such variable expansion. // // The path variables **must not** capture the leading "/" character. The reason // is that the most common use case "{var}" does not capture the leading "/" // character. For consistency, all path variables must share the same behavior. // // Repeated message fields must not be mapped to URL query parameters, because // no client library can support such complicated mapping. // // If an API needs to use a JSON array for request or response body, it can map // the request or response body to a repeated field. However, some gRPC // Transcoding implementations may not support this feature. message HttpRule { // Selects a method to which this rule applies. // // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. string selector = 1; // Determines the URL pattern is matched by this rules. This pattern can be // used with any of the {get|put|post|delete|patch} methods. A custom method // can be defined using the 'custom' field. oneof pattern { // Maps to HTTP GET. Used for listing and getting information about // resources. string get = 2; // Maps to HTTP PUT. Used for replacing a resource. string put = 3; // Maps to HTTP POST. Used for creating a resource or performing an action. string post = 4; // Maps to HTTP DELETE. Used for deleting a resource. string delete = 5; // Maps to HTTP PATCH. Used for updating a resource. string patch = 6; // The custom pattern is used for specifying an HTTP method that is not // included in the `pattern` field, such as HEAD, or "*" to leave the // HTTP method unspecified for this rule. The wild-card rule is useful // for services that provide content to Web (HTML) clients. CustomHttpPattern custom = 8; } // The name of the request field whose value is mapped to the HTTP request // body, or `*` for mapping all request fields not captured by the path // pattern to the HTTP body, or omitted for not having any HTTP request body. // // NOTE: the referred field must be present at the top-level of the request // message type. string body = 7; // Optional. The name of the response field whose value is mapped to the HTTP // response body. When omitted, the entire response message will be used // as the HTTP response body. // // NOTE: The referred field must be present at the top-level of the response // message type. string response_body = 12; // Additional HTTP bindings for the selector. Nested bindings must // not contain an `additional_bindings` field themselves (that is, // the nesting may only be one level deep). repeated HttpRule additional_bindings = 11; } // A custom pattern is used for defining custom HTTP verb. message CustomHttpPattern { // The name of this custom HTTP verb. string kind = 1; // The path matched by this custom verb. string path = 2; } fulcio-1.6.5/third_party/googleapis/google/api/httpbody.proto000066400000000000000000000052051470150653400244440ustar00rootroot00000000000000// Copyright 2015 Google LLC // // 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. syntax = "proto3"; package google.api; import "google/protobuf/any.proto"; option cc_enable_arenas = true; option go_package = "google.golang.org/genproto/googleapis/api/httpbody;httpbody"; option java_multiple_files = true; option java_outer_classname = "HttpBodyProto"; option java_package = "com.google.api"; option objc_class_prefix = "GAPI"; // Message that represents an arbitrary HTTP body. It should only be used for // payload formats that can't be represented as JSON, such as raw binary or // an HTML page. // // // This message can be used both in streaming and non-streaming API methods in // the request as well as the response. // // It can be used as a top-level request field, which is convenient if one // wants to extract parameters from either the URL or HTTP template into the // request fields and also want access to the raw HTTP body. // // Example: // // message GetResourceRequest { // // A unique request id. // string request_id = 1; // // // The raw HTTP body is bound to this field. // google.api.HttpBody http_body = 2; // // } // // service ResourceService { // rpc GetResource(GetResourceRequest) // returns (google.api.HttpBody); // rpc UpdateResource(google.api.HttpBody) // returns (google.protobuf.Empty); // // } // // Example with streaming methods: // // service CaldavService { // rpc GetCalendar(stream google.api.HttpBody) // returns (stream google.api.HttpBody); // rpc UpdateCalendar(stream google.api.HttpBody) // returns (stream google.api.HttpBody); // // } // // Use of this type only changes how the request and response bodies are // handled, all other features will continue to work unchanged. message HttpBody { // The HTTP Content-Type header value specifying the content type of the body. string content_type = 1; // The HTTP request/response body as raw binary. bytes data = 2; // Application specific response metadata. Must be set in the first response // for streaming APIs. repeated google.protobuf.Any extensions = 3; } fulcio-1.6.5/third_party/googleapis/google/protobuf/000077500000000000000000000000001470150653400226075ustar00rootroot00000000000000fulcio-1.6.5/third_party/googleapis/google/protobuf/any.proto000066400000000000000000000136321470150653400244700ustar00rootroot00000000000000// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syntax = "proto3"; package google.protobuf; option go_package = "google.golang.org/protobuf/types/known/anypb"; option java_package = "com.google.protobuf"; option java_outer_classname = "AnyProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // `Any` contains an arbitrary serialized protocol buffer message along with a // URL that describes the type of the serialized message. // // Protobuf library provides support to pack/unpack Any values in the form // of utility functions or additional generated methods of the Any type. // // Example 1: Pack and unpack a message in C++. // // Foo foo = ...; // Any any; // any.PackFrom(foo); // ... // if (any.UnpackTo(&foo)) { // ... // } // // Example 2: Pack and unpack a message in Java. // // Foo foo = ...; // Any any = Any.pack(foo); // ... // if (any.is(Foo.class)) { // foo = any.unpack(Foo.class); // } // // or ... // if (any.isSameTypeAs(Foo.getDefaultInstance())) { // foo = any.unpack(Foo.getDefaultInstance()); // } // // Example 3: Pack and unpack a message in Python. // // foo = Foo(...) // any = Any() // any.Pack(foo) // ... // if any.Is(Foo.DESCRIPTOR): // any.Unpack(foo) // ... // // Example 4: Pack and unpack a message in Go // // foo := &pb.Foo{...} // any, err := anypb.New(foo) // if err != nil { // ... // } // ... // foo := &pb.Foo{} // if err := any.UnmarshalTo(foo); err != nil { // ... // } // // The pack methods provided by protobuf library will by default use // 'type.googleapis.com/full.type.name' as the type URL and the unpack // methods only use the fully qualified type name after the last '/' // in the type URL, for example "foo.bar.com/x/y.z" will yield type // name "y.z". // // JSON // // The JSON representation of an `Any` value uses the regular // representation of the deserialized, embedded message, with an // additional field `@type` which contains the type URL. Example: // // package google.profile; // message Person { // string first_name = 1; // string last_name = 2; // } // // { // "@type": "type.googleapis.com/google.profile.Person", // "firstName": , // "lastName": // } // // If the embedded message type is well-known and has a custom JSON // representation, that representation will be embedded adding a field // `value` which holds the custom JSON in addition to the `@type` // field. Example (for message [google.protobuf.Duration][]): // // { // "@type": "type.googleapis.com/google.protobuf.Duration", // "value": "1.212s" // } // message Any { // A URL/resource name that uniquely identifies the type of the serialized // protocol buffer message. This string must contain at least // one "/" character. The last segment of the URL's path must represent // the fully qualified name of the type (as in // `path/google.protobuf.Duration`). The name should be in a canonical form // (e.g., leading "." is not accepted). // // In practice, teams usually precompile into the binary all types that they // expect it to use in the context of Any. However, for URLs which use the // scheme `http`, `https`, or no scheme, one can optionally set up a type // server that maps type URLs to message definitions as follows: // // * If no scheme is provided, `https` is assumed. // * An HTTP GET on the URL must yield a [google.protobuf.Type][] // value in binary format, or produce an error. // * Applications are allowed to cache lookup results based on the // URL, or have them precompiled into a binary to avoid any // lookup. Therefore, binary compatibility needs to be preserved // on changes to types. (Use versioned type names to manage // breaking changes.) // // Note: this functionality is not currently available in the official // protobuf release, and it is not used for type URLs beginning with // type.googleapis.com. // // Schemes other than `http`, `https` (or the empty scheme) might be // used with implementation specific semantics. // string type_url = 1; // Must be a valid serialized protocol buffer of the above specified type. bytes value = 2; } fulcio-1.6.5/third_party/googleapis/google/protobuf/api.proto000066400000000000000000000170611470150653400244520ustar00rootroot00000000000000// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syntax = "proto3"; package google.protobuf; import "google/protobuf/source_context.proto"; import "google/protobuf/type.proto"; option java_package = "com.google.protobuf"; option java_outer_classname = "ApiProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/apipb"; // Api is a light-weight descriptor for an API Interface. // // Interfaces are also described as "protocol buffer services" in some contexts, // such as by the "service" keyword in a .proto file, but they are different // from API Services, which represent a concrete implementation of an interface // as opposed to simply a description of methods and bindings. They are also // sometimes simply referred to as "APIs" in other contexts, such as the name of // this message itself. See https://cloud.google.com/apis/design/glossary for // detailed terminology. message Api { // The fully qualified name of this interface, including package name // followed by the interface's simple name. string name = 1; // The methods of this interface, in unspecified order. repeated Method methods = 2; // Any metadata attached to the interface. repeated Option options = 3; // A version string for this interface. If specified, must have the form // `major-version.minor-version`, as in `1.10`. If the minor version is // omitted, it defaults to zero. If the entire version field is empty, the // major version is derived from the package name, as outlined below. If the // field is not empty, the version in the package name will be verified to be // consistent with what is provided here. // // The versioning schema uses [semantic // versioning](http://semver.org) where the major version number // indicates a breaking change and the minor version an additive, // non-breaking change. Both version numbers are signals to users // what to expect from different versions, and should be carefully // chosen based on the product plan. // // The major version is also reflected in the package name of the // interface, which must end in `v`, as in // `google.feature.v1`. For major versions 0 and 1, the suffix can // be omitted. Zero major versions must only be used for // experimental, non-GA interfaces. // string version = 4; // Source context for the protocol buffer service represented by this // message. SourceContext source_context = 5; // Included interfaces. See [Mixin][]. repeated Mixin mixins = 6; // The source syntax of the service. Syntax syntax = 7; } // Method represents a method of an API interface. message Method { // The simple name of this method. string name = 1; // A URL of the input message type. string request_type_url = 2; // If true, the request is streamed. bool request_streaming = 3; // The URL of the output message type. string response_type_url = 4; // If true, the response is streamed. bool response_streaming = 5; // Any metadata attached to the method. repeated Option options = 6; // The source syntax of this method. Syntax syntax = 7; } // Declares an API Interface to be included in this interface. The including // interface must redeclare all the methods from the included interface, but // documentation and options are inherited as follows: // // - If after comment and whitespace stripping, the documentation // string of the redeclared method is empty, it will be inherited // from the original method. // // - Each annotation belonging to the service config (http, // visibility) which is not set in the redeclared method will be // inherited. // // - If an http annotation is inherited, the path pattern will be // modified as follows. Any version prefix will be replaced by the // version of the including interface plus the [root][] path if // specified. // // Example of a simple mixin: // // package google.acl.v1; // service AccessControl { // // Get the underlying ACL object. // rpc GetAcl(GetAclRequest) returns (Acl) { // option (google.api.http).get = "/v1/{resource=**}:getAcl"; // } // } // // package google.storage.v2; // service Storage { // rpc GetAcl(GetAclRequest) returns (Acl); // // // Get a data record. // rpc GetData(GetDataRequest) returns (Data) { // option (google.api.http).get = "/v2/{resource=**}"; // } // } // // Example of a mixin configuration: // // apis: // - name: google.storage.v2.Storage // mixins: // - name: google.acl.v1.AccessControl // // The mixin construct implies that all methods in `AccessControl` are // also declared with same name and request/response types in // `Storage`. A documentation generator or annotation processor will // see the effective `Storage.GetAcl` method after inheriting // documentation and annotations as follows: // // service Storage { // // Get the underlying ACL object. // rpc GetAcl(GetAclRequest) returns (Acl) { // option (google.api.http).get = "/v2/{resource=**}:getAcl"; // } // ... // } // // Note how the version in the path pattern changed from `v1` to `v2`. // // If the `root` field in the mixin is specified, it should be a // relative path under which inherited HTTP paths are placed. Example: // // apis: // - name: google.storage.v2.Storage // mixins: // - name: google.acl.v1.AccessControl // root: acls // // This implies the following inherited HTTP annotation: // // service Storage { // // Get the underlying ACL object. // rpc GetAcl(GetAclRequest) returns (Acl) { // option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; // } // ... // } message Mixin { // The fully qualified name of the interface which is included. string name = 1; // If non-empty specifies a path under which inherited HTTP paths // are rooted. string root = 2; } fulcio-1.6.5/third_party/googleapis/google/protobuf/compiler/000077500000000000000000000000001470150653400244215ustar00rootroot00000000000000fulcio-1.6.5/third_party/googleapis/google/protobuf/compiler/plugin.proto000066400000000000000000000210111470150653400267770ustar00rootroot00000000000000// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: kenton@google.com (Kenton Varda) // // protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is // just a program that reads a CodeGeneratorRequest from stdin and writes a // CodeGeneratorResponse to stdout. // // Plugins written using C++ can use google/protobuf/compiler/plugin.h instead // of dealing with the raw protocol defined here. // // A plugin executable needs only to be placed somewhere in the path. The // plugin should be named "protoc-gen-$NAME", and will then be used when the // flag "--${NAME}_out" is passed to protoc. syntax = "proto2"; package google.protobuf.compiler; option java_package = "com.google.protobuf.compiler"; option java_outer_classname = "PluginProtos"; option csharp_namespace = "Google.Protobuf.Compiler"; option go_package = "google.golang.org/protobuf/types/pluginpb"; import "google/protobuf/descriptor.proto"; // The version number of protocol compiler. message Version { optional int32 major = 1; optional int32 minor = 2; optional int32 patch = 3; // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should // be empty for mainline stable releases. optional string suffix = 4; } // An encoded CodeGeneratorRequest is written to the plugin's stdin. message CodeGeneratorRequest { // The .proto files that were explicitly listed on the command-line. The // code generator should generate code only for these files. Each file's // descriptor will be included in proto_file, below. repeated string file_to_generate = 1; // The generator parameter passed on the command-line. optional string parameter = 2; // FileDescriptorProtos for all files in files_to_generate and everything // they import. The files will appear in topological order, so each file // appears before any file that imports it. // // protoc guarantees that all proto_files will be written after // the fields above, even though this is not technically guaranteed by the // protobuf wire format. This theoretically could allow a plugin to stream // in the FileDescriptorProtos and handle them one by one rather than read // the entire set into memory at once. However, as of this writing, this // is not similarly optimized on protoc's end -- it will store all fields in // memory at once before sending them to the plugin. // // Type names of fields and extensions in the FileDescriptorProto are always // fully qualified. repeated FileDescriptorProto proto_file = 15; // The version number of protocol compiler. optional Version compiler_version = 3; } // The plugin writes an encoded CodeGeneratorResponse to stdout. message CodeGeneratorResponse { // Error message. If non-empty, code generation failed. The plugin process // should exit with status code zero even if it reports an error in this way. // // This should be used to indicate errors in .proto files which prevent the // code generator from generating correct code. Errors which indicate a // problem in protoc itself -- such as the input CodeGeneratorRequest being // unparseable -- should be reported by writing a message to stderr and // exiting with a non-zero status code. optional string error = 1; // A bitmask of supported features that the code generator supports. // This is a bitwise "or" of values from the Feature enum. optional uint64 supported_features = 2; // Sync with code_generator.h. enum Feature { FEATURE_NONE = 0; FEATURE_PROTO3_OPTIONAL = 1; } // Represents a single generated file. message File { // The file name, relative to the output directory. The name must not // contain "." or ".." components and must be relative, not be absolute (so, // the file cannot lie outside the output directory). "/" must be used as // the path separator, not "\". // // If the name is omitted, the content will be appended to the previous // file. This allows the generator to break large files into small chunks, // and allows the generated text to be streamed back to protoc so that large // files need not reside completely in memory at one time. Note that as of // this writing protoc does not optimize for this -- it will read the entire // CodeGeneratorResponse before writing files to disk. optional string name = 1; // If non-empty, indicates that the named file should already exist, and the // content here is to be inserted into that file at a defined insertion // point. This feature allows a code generator to extend the output // produced by another code generator. The original generator may provide // insertion points by placing special annotations in the file that look // like: // @@protoc_insertion_point(NAME) // The annotation can have arbitrary text before and after it on the line, // which allows it to be placed in a comment. NAME should be replaced with // an identifier naming the point -- this is what other generators will use // as the insertion_point. Code inserted at this point will be placed // immediately above the line containing the insertion point (thus multiple // insertions to the same point will come out in the order they were added). // The double-@ is intended to make it unlikely that the generated code // could contain things that look like insertion points by accident. // // For example, the C++ code generator places the following line in the // .pb.h files that it generates: // // @@protoc_insertion_point(namespace_scope) // This line appears within the scope of the file's package namespace, but // outside of any particular class. Another plugin can then specify the // insertion_point "namespace_scope" to generate additional classes or // other declarations that should be placed in this scope. // // Note that if the line containing the insertion point begins with // whitespace, the same whitespace will be added to every line of the // inserted text. This is useful for languages like Python, where // indentation matters. In these languages, the insertion point comment // should be indented the same amount as any inserted code will need to be // in order to work correctly in that context. // // The code generator that generates the initial file and the one which // inserts into it must both run as part of a single invocation of protoc. // Code generators are executed in the order in which they appear on the // command line. // // If |insertion_point| is present, |name| must also be present. optional string insertion_point = 2; // The file contents. optional string content = 15; // Information describing the file content being inserted. If an insertion // point is used, this information will be appropriately offset and inserted // into the code generation metadata for the generated files. optional GeneratedCodeInfo generated_code_info = 16; } repeated File file = 15; } fulcio-1.6.5/third_party/googleapis/google/protobuf/descriptor.proto000066400000000000000000001203061470150653400260540ustar00rootroot00000000000000// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: kenton@google.com (Kenton Varda) // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. // // The messages in this file describe the definitions found in .proto files. // A valid .proto file can be translated directly to a FileDescriptorProto // without any other information (e.g. without reading its imports). syntax = "proto2"; package google.protobuf; option go_package = "google.golang.org/protobuf/types/descriptorpb"; option java_package = "com.google.protobuf"; option java_outer_classname = "DescriptorProtos"; option csharp_namespace = "Google.Protobuf.Reflection"; option objc_class_prefix = "GPB"; option cc_enable_arenas = true; // descriptor.proto must be optimized for speed because reflection-based // algorithms don't work during bootstrapping. option optimize_for = SPEED; // The protocol compiler can output a FileDescriptorSet containing the .proto // files it parses. message FileDescriptorSet { repeated FileDescriptorProto file = 1; } // Describes a complete .proto file. message FileDescriptorProto { optional string name = 1; // file name, relative to root of source tree optional string package = 2; // e.g. "foo", "foo.bar", etc. // Names of files imported by this file. repeated string dependency = 3; // Indexes of the public imported files in the dependency list above. repeated int32 public_dependency = 10; // Indexes of the weak imported files in the dependency list. // For Google-internal migration only. Do not use. repeated int32 weak_dependency = 11; // All top-level definitions in this file. repeated DescriptorProto message_type = 4; repeated EnumDescriptorProto enum_type = 5; repeated ServiceDescriptorProto service = 6; repeated FieldDescriptorProto extension = 7; optional FileOptions options = 8; // This field contains optional information about the original source code. // You may safely remove this entire field without harming runtime // functionality of the descriptors -- the information is needed only by // development tools. optional SourceCodeInfo source_code_info = 9; // The syntax of the proto file. // The supported values are "proto2", "proto3", and "editions". // // If `edition` is present, this value must be "editions". optional string syntax = 12; // The edition of the proto file, which is an opaque string. optional string edition = 13; } // Describes a message type. message DescriptorProto { optional string name = 1; repeated FieldDescriptorProto field = 2; repeated FieldDescriptorProto extension = 6; repeated DescriptorProto nested_type = 3; repeated EnumDescriptorProto enum_type = 4; message ExtensionRange { optional int32 start = 1; // Inclusive. optional int32 end = 2; // Exclusive. optional ExtensionRangeOptions options = 3; } repeated ExtensionRange extension_range = 5; repeated OneofDescriptorProto oneof_decl = 8; optional MessageOptions options = 7; // Range of reserved tag numbers. Reserved tag numbers may not be used by // fields or extension ranges in the same message. Reserved ranges may // not overlap. message ReservedRange { optional int32 start = 1; // Inclusive. optional int32 end = 2; // Exclusive. } repeated ReservedRange reserved_range = 9; // Reserved field names, which may not be used by fields in the same message. // A given name may only be reserved once. repeated string reserved_name = 10; } message ExtensionRangeOptions { // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; } // Describes a field within a message. message FieldDescriptorProto { enum Type { // 0 is reserved for errors. // Order is weird for historical reasons. TYPE_DOUBLE = 1; TYPE_FLOAT = 2; // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if // negative values are likely. TYPE_INT64 = 3; TYPE_UINT64 = 4; // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if // negative values are likely. TYPE_INT32 = 5; TYPE_FIXED64 = 6; TYPE_FIXED32 = 7; TYPE_BOOL = 8; TYPE_STRING = 9; // Tag-delimited aggregate. // Group type is deprecated and not supported in proto3. However, Proto3 // implementations should still be able to parse the group wire format and // treat group fields as unknown fields. TYPE_GROUP = 10; TYPE_MESSAGE = 11; // Length-delimited aggregate. // New in version 2. TYPE_BYTES = 12; TYPE_UINT32 = 13; TYPE_ENUM = 14; TYPE_SFIXED32 = 15; TYPE_SFIXED64 = 16; TYPE_SINT32 = 17; // Uses ZigZag encoding. TYPE_SINT64 = 18; // Uses ZigZag encoding. } enum Label { // 0 is reserved for errors LABEL_OPTIONAL = 1; LABEL_REQUIRED = 2; LABEL_REPEATED = 3; } optional string name = 1; optional int32 number = 3; optional Label label = 4; // If type_name is set, this need not be set. If both this and type_name // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. optional Type type = 5; // For message and enum types, this is the name of the type. If the name // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping // rules are used to find the type (i.e. first the nested types within this // message are searched, then within the parent, on up to the root // namespace). optional string type_name = 6; // For extensions, this is the name of the type being extended. It is // resolved in the same manner as type_name. optional string extendee = 2; // For numeric types, contains the original text representation of the value. // For booleans, "true" or "false". // For strings, contains the default text contents (not escaped in any way). // For bytes, contains the C escaped value. All bytes >= 128 are escaped. optional string default_value = 7; // If set, gives the index of a oneof in the containing type's oneof_decl // list. This field is a member of that oneof. optional int32 oneof_index = 9; // JSON name of this field. The value is set by protocol compiler. If the // user has set a "json_name" option on this field, that option's value // will be used. Otherwise, it's deduced from the field's name by converting // it to camelCase. optional string json_name = 10; optional FieldOptions options = 8; // If true, this is a proto3 "optional". When a proto3 field is optional, it // tracks presence regardless of field type. // // When proto3_optional is true, this field must be belong to a oneof to // signal to old proto3 clients that presence is tracked for this field. This // oneof is known as a "synthetic" oneof, and this field must be its sole // member (each proto3 optional field gets its own synthetic oneof). Synthetic // oneofs exist in the descriptor only, and do not generate any API. Synthetic // oneofs must be ordered after all "real" oneofs. // // For message fields, proto3_optional doesn't create any semantic change, // since non-repeated message fields always track presence. However it still // indicates the semantic detail of whether the user wrote "optional" or not. // This can be useful for round-tripping the .proto file. For consistency we // give message fields a synthetic oneof also, even though it is not required // to track presence. This is especially important because the parser can't // tell if a field is a message or an enum, so it must always create a // synthetic oneof. // // Proto2 optional fields do not set this flag, because they already indicate // optional with `LABEL_OPTIONAL`. optional bool proto3_optional = 17; } // Describes a oneof. message OneofDescriptorProto { optional string name = 1; optional OneofOptions options = 2; } // Describes an enum type. message EnumDescriptorProto { optional string name = 1; repeated EnumValueDescriptorProto value = 2; optional EnumOptions options = 3; // Range of reserved numeric values. Reserved values may not be used by // entries in the same enum. Reserved ranges may not overlap. // // Note that this is distinct from DescriptorProto.ReservedRange in that it // is inclusive such that it can appropriately represent the entire int32 // domain. message EnumReservedRange { optional int32 start = 1; // Inclusive. optional int32 end = 2; // Inclusive. } // Range of reserved numeric values. Reserved numeric values may not be used // by enum values in the same enum declaration. Reserved ranges may not // overlap. repeated EnumReservedRange reserved_range = 4; // Reserved enum value names, which may not be reused. A given name may only // be reserved once. repeated string reserved_name = 5; } // Describes a value within an enum. message EnumValueDescriptorProto { optional string name = 1; optional int32 number = 2; optional EnumValueOptions options = 3; } // Describes a service. message ServiceDescriptorProto { optional string name = 1; repeated MethodDescriptorProto method = 2; optional ServiceOptions options = 3; } // Describes a method of a service. message MethodDescriptorProto { optional string name = 1; // Input and output type names. These are resolved in the same way as // FieldDescriptorProto.type_name, but must refer to a message type. optional string input_type = 2; optional string output_type = 3; optional MethodOptions options = 4; // Identifies if client streams multiple client messages optional bool client_streaming = 5 [default = false]; // Identifies if server streams multiple server messages optional bool server_streaming = 6 [default = false]; } // =================================================================== // Options // Each of the definitions above may have "options" attached. These are // just annotations which may cause code to be generated slightly differently // or may contain hints for code that manipulates protocol messages. // // Clients may define custom options as extensions of the *Options messages. // These extensions may not yet be known at parsing time, so the parser cannot // store the values in them. Instead it stores them in a field in the *Options // message called uninterpreted_option. This field must have the same name // across all *Options messages. We then use this field to populate the // extensions when we build a descriptor, at which point all protos have been // parsed and so all extensions are known. // // Extension numbers for custom options may be chosen as follows: // * For options which will only be used within a single application or // organization, or for experimental options, use field numbers 50000 // through 99999. It is up to you to ensure that you do not use the // same number for multiple options. // * For options which will be published and used publicly by multiple // independent entities, e-mail protobuf-global-extension-registry@google.com // to reserve extension numbers. Simply provide your project name (e.g. // Objective-C plugin) and your project website (if available) -- there's no // need to explain how you intend to use them. Usually you only need one // extension number. You can declare multiple options with only one extension // number by putting them in a sub-message. See the Custom Options section of // the docs for examples: // https://developers.google.com/protocol-buffers/docs/proto#options // If this turns out to be popular, a web service will be set up // to automatically assign option numbers. message FileOptions { // Sets the Java package where classes generated from this .proto will be // placed. By default, the proto package is used, but this is often // inappropriate because proto packages do not normally start with backwards // domain names. optional string java_package = 1; // Controls the name of the wrapper Java class generated for the .proto file. // That class will always contain the .proto file's getDescriptor() method as // well as any top-level extensions defined in the .proto file. // If java_multiple_files is disabled, then all the other classes from the // .proto file will be nested inside the single wrapper outer class. optional string java_outer_classname = 8; // If enabled, then the Java code generator will generate a separate .java // file for each top-level message, enum, and service defined in the .proto // file. Thus, these types will *not* be nested inside the wrapper class // named by java_outer_classname. However, the wrapper class will still be // generated to contain the file's getDescriptor() method as well as any // top-level extensions defined in the file. optional bool java_multiple_files = 10 [default = false]; // This option does nothing. optional bool java_generate_equals_and_hash = 20 [deprecated=true]; // If set true, then the Java2 code generator will generate code that // throws an exception whenever an attempt is made to assign a non-UTF-8 // byte sequence to a string field. // Message reflection will do the same. // However, an extension field still accepts non-UTF-8 byte sequences. // This option has no effect on when used with the lite runtime. optional bool java_string_check_utf8 = 27 [default = false]; // Generated classes can be optimized for speed or code size. enum OptimizeMode { SPEED = 1; // Generate complete code for parsing, serialization, // etc. CODE_SIZE = 2; // Use ReflectionOps to implement these methods. LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. } optional OptimizeMode optimize_for = 9 [default = SPEED]; // Sets the Go package where structs generated from this .proto will be // placed. If omitted, the Go package will be derived from the following: // - The basename of the package import path, if provided. // - Otherwise, the package statement in the .proto file, if present. // - Otherwise, the basename of the .proto file, without extension. optional string go_package = 11; // Should generic services be generated in each language? "Generic" services // are not specific to any particular RPC system. They are generated by the // main code generators in each language (without additional plugins). // Generic services were the only kind of service generation supported by // early versions of google.protobuf. // // Generic services are now considered deprecated in favor of using plugins // that generate code specific to your particular RPC system. Therefore, // these default to false. Old code which depends on generic services should // explicitly set them to true. optional bool cc_generic_services = 16 [default = false]; optional bool java_generic_services = 17 [default = false]; optional bool py_generic_services = 18 [default = false]; optional bool php_generic_services = 42 [default = false]; // Is this file deprecated? // Depending on the target platform, this can emit Deprecated annotations // for everything in the file, or it will be completely ignored; in the very // least, this is a formalization for deprecating files. optional bool deprecated = 23 [default = false]; // Enables the use of arenas for the proto messages in this file. This applies // only to generated classes for C++. optional bool cc_enable_arenas = 31 [default = true]; // Sets the objective c class prefix which is prepended to all objective c // generated classes from this .proto. There is no default. optional string objc_class_prefix = 36; // Namespace for generated classes; defaults to the package. optional string csharp_namespace = 37; // By default Swift generators will take the proto package and CamelCase it // replacing '.' with underscore and use that to prefix the types/symbols // defined. When this options is provided, they will use this value instead // to prefix the types/symbols defined. optional string swift_prefix = 39; // Sets the php class prefix which is prepended to all php generated classes // from this .proto. Default is empty. optional string php_class_prefix = 40; // Use this option to change the namespace of php generated classes. Default // is empty. When this option is empty, the package name will be used for // determining the namespace. optional string php_namespace = 41; // Use this option to change the namespace of php generated metadata classes. // Default is empty. When this option is empty, the proto file name will be // used for determining the namespace. optional string php_metadata_namespace = 44; // Use this option to change the package of ruby generated classes. Default // is empty. When this option is not set, the package name will be used for // determining the ruby package. optional string ruby_package = 45; // The parser stores options it doesn't recognize here. // See the documentation for the "Options" section above. repeated UninterpretedOption uninterpreted_option = 999; // Clients can define custom options in extensions of this message. // See the documentation for the "Options" section above. extensions 1000 to max; reserved 38; } message MessageOptions { // Set true to use the old proto1 MessageSet wire format for extensions. // This is provided for backwards-compatibility with the MessageSet wire // format. You should not use this for any other reason: It's less // efficient, has fewer features, and is more complicated. // // The message must be defined exactly as follows: // message Foo { // option message_set_wire_format = true; // extensions 4 to max; // } // Note that the message cannot have any defined fields; MessageSets only // have extensions. // // All extensions of your type must be singular messages; e.g. they cannot // be int32s, enums, or repeated messages. // // Because this is an option, the above two restrictions are not enforced by // the protocol compiler. optional bool message_set_wire_format = 1 [default = false]; // Disables the generation of the standard "descriptor()" accessor, which can // conflict with a field of the same name. This is meant to make migration // from proto1 easier; new code should avoid fields named "descriptor". optional bool no_standard_descriptor_accessor = 2 [default = false]; // Is this message deprecated? // Depending on the target platform, this can emit Deprecated annotations // for the message, or it will be completely ignored; in the very least, // this is a formalization for deprecating messages. optional bool deprecated = 3 [default = false]; reserved 4, 5, 6; // NOTE: Do not set the option in .proto files. Always use the maps syntax // instead. The option should only be implicitly set by the proto compiler // parser. // // Whether the message is an automatically generated map entry type for the // maps field. // // For maps fields: // map map_field = 1; // The parsed descriptor looks like: // message MapFieldEntry { // option map_entry = true; // optional KeyType key = 1; // optional ValueType value = 2; // } // repeated MapFieldEntry map_field = 1; // // Implementations may choose not to generate the map_entry=true message, but // use a native map in the target language to hold the keys and values. // The reflection APIs in such implementations still need to work as // if the field is a repeated message field. optional bool map_entry = 7; reserved 8; // javalite_serializable reserved 9; // javanano_as_lite // Enable the legacy handling of JSON field name conflicts. This lowercases // and strips underscored from the fields before comparison in proto3 only. // The new behavior takes `json_name` into account and applies to proto2 as // well. // // This should only be used as a temporary measure against broken builds due // to the change in behavior for JSON field name conflicts. // // TODO(b/261750190) This is legacy behavior we plan to remove once downstream // teams have had time to migrate. optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true]; // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; } message FieldOptions { // The ctype option instructs the C++ code generator to use a different // representation of the field than it normally would. See the specific // options below. This option is not yet implemented in the open source // release -- sorry, we'll try to include it in a future version! optional CType ctype = 1 [default = STRING]; enum CType { // Default mode. STRING = 0; CORD = 1; STRING_PIECE = 2; } // The packed option can be enabled for repeated primitive fields to enable // a more efficient representation on the wire. Rather than repeatedly // writing the tag and type for each element, the entire array is encoded as // a single length-delimited blob. In proto3, only explicit setting it to // false will avoid using packed encoding. optional bool packed = 2; // The jstype option determines the JavaScript type used for values of the // field. The option is permitted only for 64 bit integral and fixed types // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING // is represented as JavaScript string, which avoids loss of precision that // can happen when a large value is converted to a floating point JavaScript. // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to // use the JavaScript "number" type. The behavior of the default option // JS_NORMAL is implementation dependent. // // This option is an enum to permit additional types to be added, e.g. // goog.math.Integer. optional JSType jstype = 6 [default = JS_NORMAL]; enum JSType { // Use the default type. JS_NORMAL = 0; // Use JavaScript strings. JS_STRING = 1; // Use JavaScript numbers. JS_NUMBER = 2; } // Should this field be parsed lazily? Lazy applies only to message-type // fields. It means that when the outer message is initially parsed, the // inner message's contents will not be parsed but instead stored in encoded // form. The inner message will actually be parsed when it is first accessed. // // This is only a hint. Implementations are free to choose whether to use // eager or lazy parsing regardless of the value of this option. However, // setting this option true suggests that the protocol author believes that // using lazy parsing on this field is worth the additional bookkeeping // overhead typically needed to implement it. // // This option does not affect the public interface of any generated code; // all method signatures remain the same. Furthermore, thread-safety of the // interface is not affected by this option; const methods remain safe to // call from multiple threads concurrently, while non-const methods continue // to require exclusive access. // // Note that implementations may choose not to check required fields within // a lazy sub-message. That is, calling IsInitialized() on the outer message // may return true even if the inner message has missing required fields. // This is necessary because otherwise the inner message would have to be // parsed in order to perform the check, defeating the purpose of lazy // parsing. An implementation which chooses not to check required fields // must be consistent about it. That is, for any particular sub-message, the // implementation must either *always* check its required fields, or *never* // check its required fields, regardless of whether or not the message has // been parsed. // // As of May 2022, lazy verifies the contents of the byte stream during // parsing. An invalid byte stream will cause the overall parsing to fail. optional bool lazy = 5 [default = false]; // unverified_lazy does no correctness checks on the byte stream. This should // only be used where lazy with verification is prohibitive for performance // reasons. optional bool unverified_lazy = 15 [default = false]; // Is this field deprecated? // Depending on the target platform, this can emit Deprecated annotations // for accessors, or it will be completely ignored; in the very least, this // is a formalization for deprecating fields. optional bool deprecated = 3 [default = false]; // For Google-internal migration only. Do not use. optional bool weak = 10 [default = false]; // Indicate that the field value should not be printed out when using debug // formats, e.g. when the field contains sensitive credentials. optional bool debug_redact = 16 [default = false]; // If set to RETENTION_SOURCE, the option will be omitted from the binary. // Note: as of January 2023, support for this is in progress and does not yet // have an effect (b/264593489). enum OptionRetention { RETENTION_UNKNOWN = 0; RETENTION_RUNTIME = 1; RETENTION_SOURCE = 2; } optional OptionRetention retention = 17; // This indicates the types of entities that the field may apply to when used // as an option. If it is unset, then the field may be freely used as an // option on any kind of entity. Note: as of January 2023, support for this is // in progress and does not yet have an effect (b/264593489). enum OptionTargetType { TARGET_TYPE_UNKNOWN = 0; TARGET_TYPE_FILE = 1; TARGET_TYPE_EXTENSION_RANGE = 2; TARGET_TYPE_MESSAGE = 3; TARGET_TYPE_FIELD = 4; TARGET_TYPE_ONEOF = 5; TARGET_TYPE_ENUM = 6; TARGET_TYPE_ENUM_ENTRY = 7; TARGET_TYPE_SERVICE = 8; TARGET_TYPE_METHOD = 9; } optional OptionTargetType target = 18; // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; reserved 4; // removed jtype } message OneofOptions { // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; } message EnumOptions { // Set this option to true to allow mapping different tag names to the same // value. optional bool allow_alias = 2; // Is this enum deprecated? // Depending on the target platform, this can emit Deprecated annotations // for the enum, or it will be completely ignored; in the very least, this // is a formalization for deprecating enums. optional bool deprecated = 3 [default = false]; reserved 5; // javanano_as_lite // Enable the legacy handling of JSON field name conflicts. This lowercases // and strips underscored from the fields before comparison in proto3 only. // The new behavior takes `json_name` into account and applies to proto2 as // well. // TODO(b/261750190) Remove this legacy behavior once downstream teams have // had time to migrate. optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true]; // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; } message EnumValueOptions { // Is this enum value deprecated? // Depending on the target platform, this can emit Deprecated annotations // for the enum value, or it will be completely ignored; in the very least, // this is a formalization for deprecating enum values. optional bool deprecated = 1 [default = false]; // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; } message ServiceOptions { // Note: Field numbers 1 through 32 are reserved for Google's internal RPC // framework. We apologize for hoarding these numbers to ourselves, but // we were already using them long before we decided to release Protocol // Buffers. // Is this service deprecated? // Depending on the target platform, this can emit Deprecated annotations // for the service, or it will be completely ignored; in the very least, // this is a formalization for deprecating services. optional bool deprecated = 33 [default = false]; // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; } message MethodOptions { // Note: Field numbers 1 through 32 are reserved for Google's internal RPC // framework. We apologize for hoarding these numbers to ourselves, but // we were already using them long before we decided to release Protocol // Buffers. // Is this method deprecated? // Depending on the target platform, this can emit Deprecated annotations // for the method, or it will be completely ignored; in the very least, // this is a formalization for deprecating methods. optional bool deprecated = 33 [default = false]; // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, // or neither? HTTP based RPC implementation may choose GET verb for safe // methods, and PUT verb for idempotent methods instead of the default POST. enum IdempotencyLevel { IDEMPOTENCY_UNKNOWN = 0; NO_SIDE_EFFECTS = 1; // implies idempotent IDEMPOTENT = 2; // idempotent, but may have side effects } optional IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN]; // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; } // A message representing a option the parser does not recognize. This only // appears in options protos created by the compiler::Parser class. // DescriptorPool resolves these when building Descriptor objects. Therefore, // options protos in descriptor objects (e.g. returned by Descriptor::options(), // or produced by Descriptor::CopyTo()) will never have UninterpretedOptions // in them. message UninterpretedOption { // The name of the uninterpreted option. Each string represents a segment in // a dot-separated name. is_extension is true iff a segment represents an // extension (denoted with parentheses in options specs in .proto files). // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents // "foo.(bar.baz).moo". message NamePart { required string name_part = 1; required bool is_extension = 2; } repeated NamePart name = 2; // The value of the uninterpreted option, in whatever type the tokenizer // identified it as during parsing. Exactly one of these should be set. optional string identifier_value = 3; optional uint64 positive_int_value = 4; optional int64 negative_int_value = 5; optional double double_value = 6; optional bytes string_value = 7; optional string aggregate_value = 8; } // =================================================================== // Optional source code info // Encapsulates information about the original source file from which a // FileDescriptorProto was generated. message SourceCodeInfo { // A Location identifies a piece of source code in a .proto file which // corresponds to a particular definition. This information is intended // to be useful to IDEs, code indexers, documentation generators, and similar // tools. // // For example, say we have a file like: // message Foo { // optional string foo = 1; // } // Let's look at just the field definition: // optional string foo = 1; // ^ ^^ ^^ ^ ^^^ // a bc de f ghi // We have the following locations: // span path represents // [a,i) [ 4, 0, 2, 0 ] The whole field definition. // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). // // Notes: // - A location may refer to a repeated field itself (i.e. not to any // particular index within it). This is used whenever a set of elements are // logically enclosed in a single code segment. For example, an entire // extend block (possibly containing multiple extension definitions) will // have an outer location whose path refers to the "extensions" repeated // field without an index. // - Multiple locations may have the same path. This happens when a single // logical declaration is spread out across multiple places. The most // obvious example is the "extend" block again -- there may be multiple // extend blocks in the same scope, each of which will have the same path. // - A location's span is not always a subset of its parent's span. For // example, the "extendee" of an extension declaration appears at the // beginning of the "extend" block and is shared by all extensions within // the block. // - Just because a location's span is a subset of some other location's span // does not mean that it is a descendant. For example, a "group" defines // both a type and a field in a single declaration. Thus, the locations // corresponding to the type and field and their components will overlap. // - Code which tries to interpret locations should probably be designed to // ignore those that it doesn't understand, as more types of locations could // be recorded in the future. repeated Location location = 1; message Location { // Identifies which part of the FileDescriptorProto was defined at this // location. // // Each element is a field number or an index. They form a path from // the root FileDescriptorProto to the place where the definition occurs. // For example, this path: // [ 4, 3, 2, 7, 1 ] // refers to: // file.message_type(3) // 4, 3 // .field(7) // 2, 7 // .name() // 1 // This is because FileDescriptorProto.message_type has field number 4: // repeated DescriptorProto message_type = 4; // and DescriptorProto.field has field number 2: // repeated FieldDescriptorProto field = 2; // and FieldDescriptorProto.name has field number 1: // optional string name = 1; // // Thus, the above path gives the location of a field name. If we removed // the last element: // [ 4, 3, 2, 7 ] // this path refers to the whole field declaration (from the beginning // of the label to the terminating semicolon). repeated int32 path = 1 [packed = true]; // Always has exactly three or four elements: start line, start column, // end line (optional, otherwise assumed same as start line), end column. // These are packed into a single field for efficiency. Note that line // and column numbers are zero-based -- typically you will want to add // 1 to each before displaying to a user. repeated int32 span = 2 [packed = true]; // If this SourceCodeInfo represents a complete declaration, these are any // comments appearing before and after the declaration which appear to be // attached to the declaration. // // A series of line comments appearing on consecutive lines, with no other // tokens appearing on those lines, will be treated as a single comment. // // leading_detached_comments will keep paragraphs of comments that appear // before (but not connected to) the current element. Each paragraph, // separated by empty lines, will be one comment element in the repeated // field. // // Only the comment content is provided; comment markers (e.g. //) are // stripped out. For block comments, leading whitespace and an asterisk // will be stripped from the beginning of each line other than the first. // Newlines are included in the output. // // Examples: // // optional int32 foo = 1; // Comment attached to foo. // // Comment attached to bar. // optional int32 bar = 2; // // optional string baz = 3; // // Comment attached to baz. // // Another line attached to baz. // // // Comment attached to moo. // // // // Another line attached to moo. // optional double moo = 4; // // // Detached comment for corge. This is not leading or trailing comments // // to moo or corge because there are blank lines separating it from // // both. // // // Detached comment for corge paragraph 2. // // optional string corge = 5; // /* Block comment attached // * to corge. Leading asterisks // * will be removed. */ // /* Block comment attached to // * grault. */ // optional int32 grault = 6; // // // ignored detached comments. optional string leading_comments = 3; optional string trailing_comments = 4; repeated string leading_detached_comments = 6; } } // Describes the relationship between generated code and its original source // file. A GeneratedCodeInfo message is associated with only one generated // source file, but may contain references to different source .proto files. message GeneratedCodeInfo { // An Annotation connects some span of text in generated code to an element // of its generating .proto file. repeated Annotation annotation = 1; message Annotation { // Identifies the element in the original source .proto file. This field // is formatted the same as SourceCodeInfo.Location.path. repeated int32 path = 1 [packed = true]; // Identifies the filesystem path to the original source .proto. optional string source_file = 2; // Identifies the starting offset in bytes in the generated code // that relates to the identified object. optional int32 begin = 3; // Identifies the ending offset in bytes in the generated code that // relates to the identified object. The end offset should be one past // the last relevant byte (so the length of the text = end - begin). optional int32 end = 4; // Represents the identified object's effect on the element in the original // .proto file. enum Semantic { // There is no effect or the effect is indescribable. NONE = 0; // The element is set or otherwise mutated. SET = 1; // An alias to the element is returned. ALIAS = 2; } optional Semantic semantic = 5; } } fulcio-1.6.5/third_party/googleapis/google/protobuf/duration.proto000066400000000000000000000114341470150653400255240ustar00rootroot00000000000000// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syntax = "proto3"; package google.protobuf; option cc_enable_arenas = true; option go_package = "google.golang.org/protobuf/types/known/durationpb"; option java_package = "com.google.protobuf"; option java_outer_classname = "DurationProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // A Duration represents a signed, fixed-length span of time represented // as a count of seconds and fractions of seconds at nanosecond // resolution. It is independent of any calendar and concepts like "day" // or "month". It is related to Timestamp in that the difference between // two Timestamp values is a Duration and it can be added or subtracted // from a Timestamp. Range is approximately +-10,000 years. // // # Examples // // Example 1: Compute Duration from two Timestamps in pseudo code. // // Timestamp start = ...; // Timestamp end = ...; // Duration duration = ...; // // duration.seconds = end.seconds - start.seconds; // duration.nanos = end.nanos - start.nanos; // // if (duration.seconds < 0 && duration.nanos > 0) { // duration.seconds += 1; // duration.nanos -= 1000000000; // } else if (duration.seconds > 0 && duration.nanos < 0) { // duration.seconds -= 1; // duration.nanos += 1000000000; // } // // Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. // // Timestamp start = ...; // Duration duration = ...; // Timestamp end = ...; // // end.seconds = start.seconds + duration.seconds; // end.nanos = start.nanos + duration.nanos; // // if (end.nanos < 0) { // end.seconds -= 1; // end.nanos += 1000000000; // } else if (end.nanos >= 1000000000) { // end.seconds += 1; // end.nanos -= 1000000000; // } // // Example 3: Compute Duration from datetime.timedelta in Python. // // td = datetime.timedelta(days=3, minutes=10) // duration = Duration() // duration.FromTimedelta(td) // // # JSON Mapping // // In JSON format, the Duration type is encoded as a string rather than an // object, where the string ends in the suffix "s" (indicating seconds) and // is preceded by the number of seconds, with nanoseconds expressed as // fractional seconds. For example, 3 seconds with 0 nanoseconds should be // encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should // be expressed in JSON format as "3.000000001s", and 3 seconds and 1 // microsecond should be expressed in JSON format as "3.000001s". // message Duration { // Signed seconds of the span of time. Must be from -315,576,000,000 // to +315,576,000,000 inclusive. Note: these bounds are computed from: // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years int64 seconds = 1; // Signed fractions of a second at nanosecond resolution of the span // of time. Durations less than one second are represented with a 0 // `seconds` field and a positive or negative `nanos` field. For durations // of one second or more, a non-zero value for the `nanos` field must be // of the same sign as the `seconds` field. Must be from -999,999,999 // to +999,999,999 inclusive. int32 nanos = 2; } fulcio-1.6.5/third_party/googleapis/google/protobuf/empty.proto000066400000000000000000000044731470150653400250420ustar00rootroot00000000000000// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syntax = "proto3"; package google.protobuf; option go_package = "google.golang.org/protobuf/types/known/emptypb"; option java_package = "com.google.protobuf"; option java_outer_classname = "EmptyProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; // A generic empty message that you can re-use to avoid defining duplicated // empty messages in your APIs. A typical example is to use it as the request // or the response type of an API method. For instance: // // service Foo { // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); // } // message Empty {} fulcio-1.6.5/third_party/googleapis/google/protobuf/field_mask.proto000066400000000000000000000177711470150653400260070ustar00rootroot00000000000000// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syntax = "proto3"; package google.protobuf; option java_package = "com.google.protobuf"; option java_outer_classname = "FieldMaskProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; option cc_enable_arenas = true; // `FieldMask` represents a set of symbolic field paths, for example: // // paths: "f.a" // paths: "f.b.d" // // Here `f` represents a field in some root message, `a` and `b` // fields in the message found in `f`, and `d` a field found in the // message in `f.b`. // // Field masks are used to specify a subset of fields that should be // returned by a get operation or modified by an update operation. // Field masks also have a custom JSON encoding (see below). // // # Field Masks in Projections // // When used in the context of a projection, a response message or // sub-message is filtered by the API to only contain those fields as // specified in the mask. For example, if the mask in the previous // example is applied to a response message as follows: // // f { // a : 22 // b { // d : 1 // x : 2 // } // y : 13 // } // z: 8 // // The result will not contain specific values for fields x,y and z // (their value will be set to the default, and omitted in proto text // output): // // // f { // a : 22 // b { // d : 1 // } // } // // A repeated field is not allowed except at the last position of a // paths string. // // If a FieldMask object is not present in a get operation, the // operation applies to all fields (as if a FieldMask of all fields // had been specified). // // Note that a field mask does not necessarily apply to the // top-level response message. In case of a REST get operation, the // field mask applies directly to the response, but in case of a REST // list operation, the mask instead applies to each individual message // in the returned resource list. In case of a REST custom method, // other definitions may be used. Where the mask applies will be // clearly documented together with its declaration in the API. In // any case, the effect on the returned resource/resources is required // behavior for APIs. // // # Field Masks in Update Operations // // A field mask in update operations specifies which fields of the // targeted resource are going to be updated. The API is required // to only change the values of the fields as specified in the mask // and leave the others untouched. If a resource is passed in to // describe the updated values, the API ignores the values of all // fields not covered by the mask. // // If a repeated field is specified for an update operation, new values will // be appended to the existing repeated field in the target resource. Note that // a repeated field is only allowed in the last position of a `paths` string. // // If a sub-message is specified in the last position of the field mask for an // update operation, then new value will be merged into the existing sub-message // in the target resource. // // For example, given the target message: // // f { // b { // d: 1 // x: 2 // } // c: [1] // } // // And an update message: // // f { // b { // d: 10 // } // c: [2] // } // // then if the field mask is: // // paths: ["f.b", "f.c"] // // then the result will be: // // f { // b { // d: 10 // x: 2 // } // c: [1, 2] // } // // An implementation may provide options to override this default behavior for // repeated and message fields. // // In order to reset a field's value to the default, the field must // be in the mask and set to the default value in the provided resource. // Hence, in order to reset all fields of a resource, provide a default // instance of the resource and set all fields in the mask, or do // not provide a mask as described below. // // If a field mask is not present on update, the operation applies to // all fields (as if a field mask of all fields has been specified). // Note that in the presence of schema evolution, this may mean that // fields the client does not know and has therefore not filled into // the request will be reset to their default. If this is unwanted // behavior, a specific service may require a client to always specify // a field mask, producing an error if not. // // As with get operations, the location of the resource which // describes the updated values in the request message depends on the // operation kind. In any case, the effect of the field mask is // required to be honored by the API. // // ## Considerations for HTTP REST // // The HTTP kind of an update operation which uses a field mask must // be set to PATCH instead of PUT in order to satisfy HTTP semantics // (PUT must only be used for full updates). // // # JSON Encoding of Field Masks // // In JSON, a field mask is encoded as a single string where paths are // separated by a comma. Fields name in each path are converted // to/from lower-camel naming conventions. // // As an example, consider the following message declarations: // // message Profile { // User user = 1; // Photo photo = 2; // } // message User { // string display_name = 1; // string address = 2; // } // // In proto a field mask for `Profile` may look as such: // // mask { // paths: "user.display_name" // paths: "photo" // } // // In JSON, the same mask is represented as below: // // { // mask: "user.displayName,photo" // } // // # Field Masks and Oneof Fields // // Field masks treat fields in oneofs just as regular fields. Consider the // following message: // // message SampleMessage { // oneof test_oneof { // string name = 4; // SubMessage sub_message = 9; // } // } // // The field mask can be: // // mask { // paths: "name" // } // // Or: // // mask { // paths: "sub_message" // } // // Note that oneof type names ("test_oneof" in this case) cannot be used in // paths. // // ## Field Mask Verification // // The implementation of any API method which has a FieldMask type field in the // request should verify the included field paths, and return an // `INVALID_ARGUMENT` error if any path is unmappable. message FieldMask { // The set of field mask paths. repeated string paths = 1; } fulcio-1.6.5/third_party/googleapis/google/protobuf/source_context.proto000066400000000000000000000044451470150653400267470ustar00rootroot00000000000000// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syntax = "proto3"; package google.protobuf; option java_package = "com.google.protobuf"; option java_outer_classname = "SourceContextProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; // `SourceContext` represents information about the source of a // protobuf element, like the file in which it is defined. message SourceContext { // The path-qualified name of the .proto file that contained the associated // protobuf element. For example: `"google/protobuf/source_context.proto"`. string file_name = 1; } fulcio-1.6.5/third_party/googleapis/google/protobuf/struct.proto000066400000000000000000000073031470150653400252230ustar00rootroot00000000000000// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syntax = "proto3"; package google.protobuf; option cc_enable_arenas = true; option go_package = "google.golang.org/protobuf/types/known/structpb"; option java_package = "com.google.protobuf"; option java_outer_classname = "StructProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // `Struct` represents a structured data value, consisting of fields // which map to dynamically typed values. In some languages, `Struct` // might be supported by a native representation. For example, in // scripting languages like JS a struct is represented as an // object. The details of that representation are described together // with the proto support for the language. // // The JSON representation for `Struct` is JSON object. message Struct { // Unordered map of dynamically typed values. map fields = 1; } // `Value` represents a dynamically typed value which can be either // null, a number, a string, a boolean, a recursive struct value, or a // list of values. A producer of value is expected to set one of these // variants. Absence of any variant indicates an error. // // The JSON representation for `Value` is JSON value. message Value { // The kind of value. oneof kind { // Represents a null value. NullValue null_value = 1; // Represents a double value. double number_value = 2; // Represents a string value. string string_value = 3; // Represents a boolean value. bool bool_value = 4; // Represents a structured value. Struct struct_value = 5; // Represents a repeated `Value`. ListValue list_value = 6; } } // `NullValue` is a singleton enumeration to represent the null value for the // `Value` type union. // // The JSON representation for `NullValue` is JSON `null`. enum NullValue { // Null value. NULL_VALUE = 0; } // `ListValue` is a wrapper around a repeated field of values. // // The JSON representation for `ListValue` is JSON array. message ListValue { // Repeated field of dynamically typed values. repeated Value values = 1; } fulcio-1.6.5/third_party/googleapis/google/protobuf/timestamp.proto000066400000000000000000000144621470150653400257060ustar00rootroot00000000000000// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syntax = "proto3"; package google.protobuf; option cc_enable_arenas = true; option go_package = "google.golang.org/protobuf/types/known/timestamppb"; option java_package = "com.google.protobuf"; option java_outer_classname = "TimestampProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // A Timestamp represents a point in time independent of any time zone or local // calendar, encoded as a count of seconds and fractions of seconds at // nanosecond resolution. The count is relative to an epoch at UTC midnight on // January 1, 1970, in the proleptic Gregorian calendar which extends the // Gregorian calendar backwards to year one. // // All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap // second table is needed for interpretation, using a [24-hour linear // smear](https://developers.google.com/time/smear). // // The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By // restricting to that range, we ensure that we can convert to and from [RFC // 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. // // # Examples // // Example 1: Compute Timestamp from POSIX `time()`. // // Timestamp timestamp; // timestamp.set_seconds(time(NULL)); // timestamp.set_nanos(0); // // Example 2: Compute Timestamp from POSIX `gettimeofday()`. // // struct timeval tv; // gettimeofday(&tv, NULL); // // Timestamp timestamp; // timestamp.set_seconds(tv.tv_sec); // timestamp.set_nanos(tv.tv_usec * 1000); // // Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. // // FILETIME ft; // GetSystemTimeAsFileTime(&ft); // UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; // // // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z // // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. // Timestamp timestamp; // timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); // timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); // // Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. // // long millis = System.currentTimeMillis(); // // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) // .setNanos((int) ((millis % 1000) * 1000000)).build(); // // Example 5: Compute Timestamp from Java `Instant.now()`. // // Instant now = Instant.now(); // // Timestamp timestamp = // Timestamp.newBuilder().setSeconds(now.getEpochSecond()) // .setNanos(now.getNano()).build(); // // Example 6: Compute Timestamp from current time in Python. // // timestamp = Timestamp() // timestamp.GetCurrentTime() // // # JSON Mapping // // In JSON format, the Timestamp type is encoded as a string in the // [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the // format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" // where {year} is always expressed using four digits while {month}, {day}, // {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional // seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), // are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone // is required. A proto3 JSON serializer should always use UTC (as indicated by // "Z") when printing the Timestamp type and a proto3 JSON parser should be // able to accept both UTC and other timezones (as indicated by an offset). // // For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past // 01:30 UTC on January 15, 2017. // // In JavaScript, one can convert a Date object to this format using the // standard // [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) // method. In Python, a standard `datetime.datetime` object can be converted // to this format using // [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with // the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use // the Joda Time's [`ISODateTimeFormat.dateTime()`]( // http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D // ) to obtain a formatter capable of generating timestamps in this format. // message Timestamp { // Represents seconds of UTC time since Unix epoch // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to // 9999-12-31T23:59:59Z inclusive. int64 seconds = 1; // Non-negative fractions of a second at nanosecond resolution. Negative // second values with fractions must still have non-negative nanos values // that count forward in time. Must be from 0 to 999,999,999 // inclusive. int32 nanos = 2; } fulcio-1.6.5/third_party/googleapis/google/protobuf/type.proto000066400000000000000000000137561470150653400246710ustar00rootroot00000000000000// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syntax = "proto3"; package google.protobuf; import "google/protobuf/any.proto"; import "google/protobuf/source_context.proto"; option cc_enable_arenas = true; option java_package = "com.google.protobuf"; option java_outer_classname = "TypeProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/typepb"; // A protocol buffer message type. message Type { // The fully qualified message name. string name = 1; // The list of fields. repeated Field fields = 2; // The list of types appearing in `oneof` definitions in this type. repeated string oneofs = 3; // The protocol buffer options. repeated Option options = 4; // The source context. SourceContext source_context = 5; // The source syntax. Syntax syntax = 6; } // A single field of a message type. message Field { // Basic field types. enum Kind { // Field type unknown. TYPE_UNKNOWN = 0; // Field type double. TYPE_DOUBLE = 1; // Field type float. TYPE_FLOAT = 2; // Field type int64. TYPE_INT64 = 3; // Field type uint64. TYPE_UINT64 = 4; // Field type int32. TYPE_INT32 = 5; // Field type fixed64. TYPE_FIXED64 = 6; // Field type fixed32. TYPE_FIXED32 = 7; // Field type bool. TYPE_BOOL = 8; // Field type string. TYPE_STRING = 9; // Field type group. Proto2 syntax only, and deprecated. TYPE_GROUP = 10; // Field type message. TYPE_MESSAGE = 11; // Field type bytes. TYPE_BYTES = 12; // Field type uint32. TYPE_UINT32 = 13; // Field type enum. TYPE_ENUM = 14; // Field type sfixed32. TYPE_SFIXED32 = 15; // Field type sfixed64. TYPE_SFIXED64 = 16; // Field type sint32. TYPE_SINT32 = 17; // Field type sint64. TYPE_SINT64 = 18; } // Whether a field is optional, required, or repeated. enum Cardinality { // For fields with unknown cardinality. CARDINALITY_UNKNOWN = 0; // For optional fields. CARDINALITY_OPTIONAL = 1; // For required fields. Proto2 syntax only. CARDINALITY_REQUIRED = 2; // For repeated fields. CARDINALITY_REPEATED = 3; } // The field type. Kind kind = 1; // The field cardinality. Cardinality cardinality = 2; // The field number. int32 number = 3; // The field name. string name = 4; // The field type URL, without the scheme, for message or enumeration // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. string type_url = 6; // The index of the field type in `Type.oneofs`, for message or enumeration // types. The first type has index 1; zero means the type is not in the list. int32 oneof_index = 7; // Whether to use alternative packed wire representation. bool packed = 8; // The protocol buffer options. repeated Option options = 9; // The field JSON name. string json_name = 10; // The string value of the default value of this field. Proto2 syntax only. string default_value = 11; } // Enum type definition. message Enum { // Enum type name. string name = 1; // Enum value definitions. repeated EnumValue enumvalue = 2; // Protocol buffer options. repeated Option options = 3; // The source context. SourceContext source_context = 4; // The source syntax. Syntax syntax = 5; } // Enum value definition. message EnumValue { // Enum value name. string name = 1; // Enum value number. int32 number = 2; // Protocol buffer options. repeated Option options = 3; } // A protocol buffer option, which can be attached to a message, field, // enumeration, etc. message Option { // The option's name. For protobuf built-in options (options defined in // descriptor.proto), this is the short name. For example, `"map_entry"`. // For custom options, it should be the fully-qualified name. For example, // `"google.api.http"`. string name = 1; // The option's value packed in an Any message. If the value is a primitive, // the corresponding wrapper type defined in google/protobuf/wrappers.proto // should be used. If the value is an enum, it should be stored as an int32 // value using the google.protobuf.Int32Value type. Any value = 2; } // The syntax in which a protocol buffer element is defined. enum Syntax { // Syntax `proto2`. SYNTAX_PROTO2 = 0; // Syntax `proto3`. SYNTAX_PROTO3 = 1; } fulcio-1.6.5/third_party/googleapis/google/protobuf/wrappers.proto000066400000000000000000000077141470150653400255500ustar00rootroot00000000000000// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Wrappers for primitive (non-message) types. These types are useful // for embedding primitives in the `google.protobuf.Any` type and for places // where we need to distinguish between the absence of a primitive // typed field and its default value. // // These wrappers have no meaningful use within repeated fields as they lack // the ability to detect presence on individual elements. // These wrappers have no meaningful use within a map or a oneof since // individual entries of a map or fields of a oneof can already detect presence. syntax = "proto3"; package google.protobuf; option cc_enable_arenas = true; option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; option java_package = "com.google.protobuf"; option java_outer_classname = "WrappersProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // Wrapper message for `double`. // // The JSON representation for `DoubleValue` is JSON number. message DoubleValue { // The double value. double value = 1; } // Wrapper message for `float`. // // The JSON representation for `FloatValue` is JSON number. message FloatValue { // The float value. float value = 1; } // Wrapper message for `int64`. // // The JSON representation for `Int64Value` is JSON string. message Int64Value { // The int64 value. int64 value = 1; } // Wrapper message for `uint64`. // // The JSON representation for `UInt64Value` is JSON string. message UInt64Value { // The uint64 value. uint64 value = 1; } // Wrapper message for `int32`. // // The JSON representation for `Int32Value` is JSON number. message Int32Value { // The int32 value. int32 value = 1; } // Wrapper message for `uint32`. // // The JSON representation for `UInt32Value` is JSON number. message UInt32Value { // The uint32 value. uint32 value = 1; } // Wrapper message for `bool`. // // The JSON representation for `BoolValue` is JSON `true` and `false`. message BoolValue { // The bool value. bool value = 1; } // Wrapper message for `string`. // // The JSON representation for `StringValue` is JSON string. message StringValue { // The string value. string value = 1; } // Wrapper message for `bytes`. // // The JSON representation for `BytesValue` is JSON string. message BytesValue { // The bytes value. bytes value = 1; } fulcio-1.6.5/third_party/googleapis/protoc-gen-openapiv2/000077500000000000000000000000001470150653400234515ustar00rootroot00000000000000fulcio-1.6.5/third_party/googleapis/protoc-gen-openapiv2/options/000077500000000000000000000000001470150653400251445ustar00rootroot00000000000000fulcio-1.6.5/third_party/googleapis/protoc-gen-openapiv2/options/annotations.proto000066400000000000000000000064241470150653400305740ustar00rootroot00000000000000// Copyright (c) 2015, Gengo, Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * Neither the name of Gengo, Inc. nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syntax = "proto3"; package grpc.gateway.protoc_gen_openapiv2.options; import "google/protobuf/descriptor.proto"; import "protoc-gen-openapiv2/options/openapiv2.proto"; option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"; extend google.protobuf.FileOptions { // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. Swagger openapiv2_swagger = 1042; } extend google.protobuf.MethodOptions { // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. Operation openapiv2_operation = 1042; } extend google.protobuf.MessageOptions { // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. Schema openapiv2_schema = 1042; } extend google.protobuf.ServiceOptions { // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. Tag openapiv2_tag = 1042; } extend google.protobuf.FieldOptions { // ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. // // All IDs are the same, as assigned. It is okay that they are the same, as they extend // different descriptor messages. JSONSchema openapiv2_field = 1042; } fulcio-1.6.5/third_party/googleapis/protoc-gen-openapiv2/options/openapiv2.proto000066400000000000000000000647131470150653400301470ustar00rootroot00000000000000// Copyright (c) 2015, Gengo, Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * Neither the name of Gengo, Inc. nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. syntax = "proto3"; package grpc.gateway.protoc_gen_openapiv2.options; import "google/protobuf/struct.proto"; option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"; // Scheme describes the schemes supported by the OpenAPI Swagger // and Operation objects. enum Scheme { UNKNOWN = 0; HTTP = 1; HTTPS = 2; WS = 3; WSS = 4; } // `Swagger` is a representation of OpenAPI v2 specification's Swagger object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#swaggerObject // // Example: // // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { // info: { // title: "Echo API"; // version: "1.0"; // description: ""; // contact: { // name: "gRPC-Gateway project"; // url: "https://github.com/grpc-ecosystem/grpc-gateway"; // email: "none@example.com"; // }; // license: { // name: "BSD 3-Clause License"; // url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; // }; // }; // schemes: HTTPS; // consumes: "application/json"; // produces: "application/json"; // }; // message Swagger { // Specifies the OpenAPI Specification version being used. It can be // used by the OpenAPI UI and other clients to interpret the API listing. The // value MUST be "2.0". string swagger = 1; // Provides metadata about the API. The metadata can be used by the // clients if needed. Info info = 2; // The host (name or ip) serving the API. This MUST be the host only and does // not include the scheme nor sub-paths. It MAY include a port. If the host is // not included, the host serving the documentation is to be used (including // the port). The host does not support path templating. string host = 3; // The base path on which the API is served, which is relative to the host. If // it is not included, the API is served directly under the host. The value // MUST start with a leading slash (/). The basePath does not support path // templating. // Note that using `base_path` does not change the endpoint paths that are // generated in the resulting OpenAPI file. If you wish to use `base_path` // with relatively generated OpenAPI paths, the `base_path` prefix must be // manually removed from your `google.api.http` paths and your code changed to // serve the API from the `base_path`. string base_path = 4; // The transfer protocol of the API. Values MUST be from the list: "http", // "https", "ws", "wss". If the schemes is not included, the default scheme to // be used is the one used to access the OpenAPI definition itself. repeated Scheme schemes = 5; // A list of MIME types the APIs can consume. This is global to all APIs but // can be overridden on specific API calls. Value MUST be as described under // Mime Types. repeated string consumes = 6; // A list of MIME types the APIs can produce. This is global to all APIs but // can be overridden on specific API calls. Value MUST be as described under // Mime Types. repeated string produces = 7; // field 8 is reserved for 'paths'. reserved 8; // field 9 is reserved for 'definitions', which at this time are already // exposed as and customizable as proto messages. reserved 9; // An object to hold responses that can be used across operations. This // property does not define global responses for all operations. map responses = 10; // Security scheme definitions that can be used across the specification. SecurityDefinitions security_definitions = 11; // A declaration of which security schemes are applied for the API as a whole. // The list of values describes alternative security schemes that can be used // (that is, there is a logical OR between the security requirements). // Individual operations can override this definition. repeated SecurityRequirement security = 12; // field 13 is reserved for 'tags', which are supposed to be exposed as and // customizable as proto services. TODO(ivucica): add processing of proto // service objects into OpenAPI v2 Tag objects. reserved 13; // Additional external documentation. ExternalDocumentation external_docs = 14; map extensions = 15; } // `Operation` is a representation of OpenAPI v2 specification's Operation object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#operationObject // // Example: // // service EchoService { // rpc Echo(SimpleMessage) returns (SimpleMessage) { // option (google.api.http) = { // get: "/v1/example/echo/{id}" // }; // // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { // summary: "Get a message."; // operation_id: "getMessage"; // tags: "echo"; // responses: { // key: "200" // value: { // description: "OK"; // } // } // }; // } // } message Operation { // A list of tags for API documentation control. Tags can be used for logical // grouping of operations by resources or any other qualifier. repeated string tags = 1; // A short summary of what the operation does. For maximum readability in the // swagger-ui, this field SHOULD be less than 120 characters. string summary = 2; // A verbose explanation of the operation behavior. GFM syntax can be used for // rich text representation. string description = 3; // Additional external documentation for this operation. ExternalDocumentation external_docs = 4; // Unique string used to identify the operation. The id MUST be unique among // all operations described in the API. Tools and libraries MAY use the // operationId to uniquely identify an operation, therefore, it is recommended // to follow common programming naming conventions. string operation_id = 5; // A list of MIME types the operation can consume. This overrides the consumes // definition at the OpenAPI Object. An empty value MAY be used to clear the // global definition. Value MUST be as described under Mime Types. repeated string consumes = 6; // A list of MIME types the operation can produce. This overrides the produces // definition at the OpenAPI Object. An empty value MAY be used to clear the // global definition. Value MUST be as described under Mime Types. repeated string produces = 7; // field 8 is reserved for 'parameters'. reserved 8; // The list of possible responses as they are returned from executing this // operation. map responses = 9; // The transfer protocol for the operation. Values MUST be from the list: // "http", "https", "ws", "wss". The value overrides the OpenAPI Object // schemes definition. repeated Scheme schemes = 10; // Declares this operation to be deprecated. Usage of the declared operation // should be refrained. Default value is false. bool deprecated = 11; // A declaration of which security schemes are applied for this operation. The // list of values describes alternative security schemes that can be used // (that is, there is a logical OR between the security requirements). This // definition overrides any declared top-level security. To remove a top-level // security declaration, an empty array can be used. repeated SecurityRequirement security = 12; map extensions = 13; } // `Header` is a representation of OpenAPI v2 specification's Header object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#headerObject // message Header { // `Description` is a short description of the header. string description = 1; // The type of the object. The value MUST be one of "string", "number", "integer", or "boolean". The "array" type is not supported. string type = 2; // `Format` The extending format for the previously mentioned type. string format = 3; // field 4 is reserved for 'items', but in OpenAPI-specific way. reserved 4; // field 5 is reserved `Collection Format` Determines the format of the array if type array is used. reserved 5; // `Default` Declares the value of the header that the server will use if none is provided. // See: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2. // Unlike JSON Schema this value MUST conform to the defined type for the header. string default = 6; // field 7 is reserved for 'maximum'. reserved 7; // field 8 is reserved for 'exclusiveMaximum'. reserved 8; // field 9 is reserved for 'minimum'. reserved 9; // field 10 is reserved for 'exclusiveMinimum'. reserved 10; // field 11 is reserved for 'maxLength'. reserved 11; // field 12 is reserved for 'minLength'. reserved 12; // 'Pattern' See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.3. string pattern = 13; // field 14 is reserved for 'maxItems'. reserved 14; // field 15 is reserved for 'minItems'. reserved 15; // field 16 is reserved for 'uniqueItems'. reserved 16; // field 17 is reserved for 'enum'. reserved 17; // field 18 is reserved for 'multipleOf'. reserved 18; } // `Response` is a representation of OpenAPI v2 specification's Response object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#responseObject // message Response { // `Description` is a short description of the response. // GFM syntax can be used for rich text representation. string description = 1; // `Schema` optionally defines the structure of the response. // If `Schema` is not provided, it means there is no content to the response. Schema schema = 2; // `Headers` A list of headers that are sent with the response. // `Header` name is expected to be a string in the canonical format of the MIME header key // See: https://golang.org/pkg/net/textproto/#CanonicalMIMEHeaderKey map headers = 3; // `Examples` gives per-mimetype response examples. // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#example-object map examples = 4; map extensions = 5; } // `Info` is a representation of OpenAPI v2 specification's Info object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#infoObject // // Example: // // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { // info: { // title: "Echo API"; // version: "1.0"; // description: ""; // contact: { // name: "gRPC-Gateway project"; // url: "https://github.com/grpc-ecosystem/grpc-gateway"; // email: "none@example.com"; // }; // license: { // name: "BSD 3-Clause License"; // url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; // }; // }; // ... // }; // message Info { // The title of the application. string title = 1; // A short description of the application. GFM syntax can be used for rich // text representation. string description = 2; // The Terms of Service for the API. string terms_of_service = 3; // The contact information for the exposed API. Contact contact = 4; // The license information for the exposed API. License license = 5; // Provides the version of the application API (not to be confused // with the specification version). string version = 6; map extensions = 7; } // `Contact` is a representation of OpenAPI v2 specification's Contact object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#contactObject // // Example: // // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { // info: { // ... // contact: { // name: "gRPC-Gateway project"; // url: "https://github.com/grpc-ecosystem/grpc-gateway"; // email: "none@example.com"; // }; // ... // }; // ... // }; // message Contact { // The identifying name of the contact person/organization. string name = 1; // The URL pointing to the contact information. MUST be in the format of a // URL. string url = 2; // The email address of the contact person/organization. MUST be in the format // of an email address. string email = 3; } // `License` is a representation of OpenAPI v2 specification's License object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#licenseObject // // Example: // // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { // info: { // ... // license: { // name: "BSD 3-Clause License"; // url: "https://github.com/grpc-ecosystem/grpc-gateway/blob/master/LICENSE.txt"; // }; // ... // }; // ... // }; // message License { // The license name used for the API. string name = 1; // A URL to the license used for the API. MUST be in the format of a URL. string url = 2; } // `ExternalDocumentation` is a representation of OpenAPI v2 specification's // ExternalDocumentation object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#externalDocumentationObject // // Example: // // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { // ... // external_docs: { // description: "More about gRPC-Gateway"; // url: "https://github.com/grpc-ecosystem/grpc-gateway"; // } // ... // }; // message ExternalDocumentation { // A short description of the target documentation. GFM syntax can be used for // rich text representation. string description = 1; // The URL for the target documentation. Value MUST be in the format // of a URL. string url = 2; } // `Schema` is a representation of OpenAPI v2 specification's Schema object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject // message Schema { JSONSchema json_schema = 1; // Adds support for polymorphism. The discriminator is the schema property // name that is used to differentiate between other schema that inherit this // schema. The property name used MUST be defined at this schema and it MUST // be in the required property list. When used, the value MUST be the name of // this schema or any schema that inherits it. string discriminator = 2; // Relevant only for Schema "properties" definitions. Declares the property as // "read only". This means that it MAY be sent as part of a response but MUST // NOT be sent as part of the request. Properties marked as readOnly being // true SHOULD NOT be in the required list of the defined schema. Default // value is false. bool read_only = 3; // field 4 is reserved for 'xml'. reserved 4; // Additional external documentation for this schema. ExternalDocumentation external_docs = 5; // A free-form property to include an example of an instance for this schema in JSON. // This is copied verbatim to the output. string example = 6; } // `JSONSchema` represents properties from JSON Schema taken, and as used, in // the OpenAPI v2 spec. // // This includes changes made by OpenAPI v2. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject // // See also: https://cswr.github.io/JsonSchema/spec/basic_types/, // https://github.com/json-schema-org/json-schema-spec/blob/master/schema.json // // Example: // // message SimpleMessage { // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { // json_schema: { // title: "SimpleMessage" // description: "A simple message." // required: ["id"] // } // }; // // // Id represents the message identifier. // string id = 1; [ // (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { // description: "The unique identifier of the simple message." // }]; // } // message JSONSchema { // field 1 is reserved for '$id', omitted from OpenAPI v2. reserved 1; // field 2 is reserved for '$schema', omitted from OpenAPI v2. reserved 2; // Ref is used to define an external reference to include in the message. // This could be a fully qualified proto message reference, and that type must // be imported into the protofile. If no message is identified, the Ref will // be used verbatim in the output. // For example: // `ref: ".google.protobuf.Timestamp"`. string ref = 3; // field 4 is reserved for '$comment', omitted from OpenAPI v2. reserved 4; // The title of the schema. string title = 5; // A short description of the schema. string description = 6; string default = 7; bool read_only = 8; // A free-form property to include a JSON example of this field. This is copied // verbatim to the output swagger.json. Quotes must be escaped. // This property is the same for 2.0 and 3.0.0 https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md#schemaObject https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#schemaObject string example = 9; double multiple_of = 10; // Maximum represents an inclusive upper limit for a numeric instance. The // value of MUST be a number, double maximum = 11; bool exclusive_maximum = 12; // minimum represents an inclusive lower limit for a numeric instance. The // value of MUST be a number, double minimum = 13; bool exclusive_minimum = 14; uint64 max_length = 15; uint64 min_length = 16; string pattern = 17; // field 18 is reserved for 'additionalItems', omitted from OpenAPI v2. reserved 18; // field 19 is reserved for 'items', but in OpenAPI-specific way. // TODO(ivucica): add 'items'? reserved 19; uint64 max_items = 20; uint64 min_items = 21; bool unique_items = 22; // field 23 is reserved for 'contains', omitted from OpenAPI v2. reserved 23; uint64 max_properties = 24; uint64 min_properties = 25; repeated string required = 26; // field 27 is reserved for 'additionalProperties', but in OpenAPI-specific // way. TODO(ivucica): add 'additionalProperties'? reserved 27; // field 28 is reserved for 'definitions', omitted from OpenAPI v2. reserved 28; // field 29 is reserved for 'properties', but in OpenAPI-specific way. // TODO(ivucica): add 'additionalProperties'? reserved 29; // following fields are reserved, as the properties have been omitted from // OpenAPI v2: // patternProperties, dependencies, propertyNames, const reserved 30 to 33; // Items in 'array' must be unique. repeated string array = 34; enum JSONSchemaSimpleTypes { UNKNOWN = 0; ARRAY = 1; BOOLEAN = 2; INTEGER = 3; NULL = 4; NUMBER = 5; OBJECT = 6; STRING = 7; } repeated JSONSchemaSimpleTypes type = 35; // `Format` string format = 36; // following fields are reserved, as the properties have been omitted from // OpenAPI v2: contentMediaType, contentEncoding, if, then, else reserved 37 to 41; // field 42 is reserved for 'allOf', but in OpenAPI-specific way. // TODO(ivucica): add 'allOf'? reserved 42; // following fields are reserved, as the properties have been omitted from // OpenAPI v2: // anyOf, oneOf, not reserved 43 to 45; // Items in `enum` must be unique https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1 repeated string enum = 46; // Additional field level properties used when generating the OpenAPI v2 file. FieldConfiguration field_configuration = 1001; // 'FieldConfiguration' provides additional field level properties used when generating the OpenAPI v2 file. // These properties are not defined by OpenAPIv2, but they are used to control the generation. message FieldConfiguration { // Alternative parameter name when used as path parameter. If set, this will // be used as the complete parameter name when this field is used as a path // parameter. Use this to avoid having auto generated path parameter names // for overlapping paths. string path_param_name = 47; } map extensions = 48; } // `Tag` is a representation of OpenAPI v2 specification's Tag object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#tagObject // message Tag { // field 1 is reserved for 'name'. In our generator, this is (to be) extracted // from the name of proto service, and thus not exposed to the user, as // changing tag object's name would break the link to the references to the // tag in individual operation specifications. // // TODO(ivucica): Add 'name' property. Use it to allow override of the name of // global Tag object, then use that name to reference the tag throughout the // OpenAPI file. reserved 1; // A short description for the tag. GFM syntax can be used for rich text // representation. string description = 2; // Additional external documentation for this tag. ExternalDocumentation external_docs = 3; } // `SecurityDefinitions` is a representation of OpenAPI v2 specification's // Security Definitions object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityDefinitionsObject // // A declaration of the security schemes available to be used in the // specification. This does not enforce the security schemes on the operations // and only serves to provide the relevant details for each scheme. message SecurityDefinitions { // A single security scheme definition, mapping a "name" to the scheme it // defines. map security = 1; } // `SecurityScheme` is a representation of OpenAPI v2 specification's // Security Scheme object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securitySchemeObject // // Allows the definition of a security scheme that can be used by the // operations. Supported schemes are basic authentication, an API key (either as // a header or as a query parameter) and OAuth2's common flows (implicit, // password, application and access code). message SecurityScheme { // The type of the security scheme. Valid values are "basic", // "apiKey" or "oauth2". enum Type { TYPE_INVALID = 0; TYPE_BASIC = 1; TYPE_API_KEY = 2; TYPE_OAUTH2 = 3; } // The location of the API key. Valid values are "query" or "header". enum In { IN_INVALID = 0; IN_QUERY = 1; IN_HEADER = 2; } // The flow used by the OAuth2 security scheme. Valid values are // "implicit", "password", "application" or "accessCode". enum Flow { FLOW_INVALID = 0; FLOW_IMPLICIT = 1; FLOW_PASSWORD = 2; FLOW_APPLICATION = 3; FLOW_ACCESS_CODE = 4; } // The type of the security scheme. Valid values are "basic", // "apiKey" or "oauth2". Type type = 1; // A short description for security scheme. string description = 2; // The name of the header or query parameter to be used. // Valid for apiKey. string name = 3; // The location of the API key. Valid values are "query" or // "header". // Valid for apiKey. In in = 4; // The flow used by the OAuth2 security scheme. Valid values are // "implicit", "password", "application" or "accessCode". // Valid for oauth2. Flow flow = 5; // The authorization URL to be used for this flow. This SHOULD be in // the form of a URL. // Valid for oauth2/implicit and oauth2/accessCode. string authorization_url = 6; // The token URL to be used for this flow. This SHOULD be in the // form of a URL. // Valid for oauth2/password, oauth2/application and oauth2/accessCode. string token_url = 7; // The available scopes for the OAuth2 security scheme. // Valid for oauth2. Scopes scopes = 8; map extensions = 9; } // `SecurityRequirement` is a representation of OpenAPI v2 specification's // Security Requirement object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#securityRequirementObject // // Lists the required security schemes to execute this operation. The object can // have multiple security schemes declared in it which are all required (that // is, there is a logical AND between the schemes). // // The name used for each property MUST correspond to a security scheme // declared in the Security Definitions. message SecurityRequirement { // If the security scheme is of type "oauth2", then the value is a list of // scope names required for the execution. For other security scheme types, // the array MUST be empty. message SecurityRequirementValue { repeated string scope = 1; } // Each name must correspond to a security scheme which is declared in // the Security Definitions. If the security scheme is of type "oauth2", // then the value is a list of scope names required for the execution. // For other security scheme types, the array MUST be empty. map security_requirement = 1; } // `Scopes` is a representation of OpenAPI v2 specification's Scopes object. // // See: https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/2.0.md#scopesObject // // Lists the available scopes for an OAuth2 security scheme. message Scopes { // Maps between a name of a scope to a short description of it (as the value // of the property). map scope = 1; } fulcio-1.6.5/tools/000077500000000000000000000000001470150653400141515ustar00rootroot00000000000000fulcio-1.6.5/tools/loadtest/000077500000000000000000000000001470150653400157705ustar00rootroot00000000000000fulcio-1.6.5/tools/loadtest/README.md000066400000000000000000000053501470150653400172520ustar00rootroot00000000000000# Fulcio Performance Test ## Overview [Learn more about Locust](http://docs.locust.io/en/stable/index.html). 1. Install Locust with `pip3 install -r requirements.txt` 1. Fetch an identity token for a service account with `gcloud auth print-identity-token --audiences sigstore --impersonate-service-account @.iam.gserviceaccount.com --include-email`. 1. Start `locust`, configuring number of users, spawn rate, host, maximum QPS per user, and identity token. ## Prerequisites You will need Python 3 to install the Python requirements. You will also need to set up a GCP project with a single service account. The service account will be used to generate an identity token for calls to Fulcio. ## Running Locust ### Installation Run `pip3 install -r requirements.txt`, which will install Locust and necessary libraries. Confirm a successful install with `locust -V`, which should print the version. You may need to include `~/.local/bin` in your PATH. ### Fetching identity token To fetch a certificate, you will need an OIDC token from one of the [OIDC issuers](https://github.com/sigstore/fulcio/blob/main/config/identity/config.yaml). One way is to fetch a token from Google. Note that you will need to install [`gcloud`](https://cloud.google.com/sdk/gcloud) and create a service account. A service account is necessary for the `--include-email` flag, which is needed to get an OIDC token with the correct format for Fulcio. Run the following command, and record the output: `gcloud auth print-identity-token --audiences sigstore --impersonate-service-account @.iam.gserviceaccount.com --include-email` Note that this token will be valid for approximately one hour. ### Configuring maximum QPS per user You can configure the test to set a maximum QPS per user. This will limit each Locust user to the specified QPS. Without this, Locust will generate an unbounded amount of traffic. You can choose to remove `wait_time` if you want this behavior, but be careful to not overwhelm a production instance. ### Running test From within the directory with `locustfile.py`, run the command `locust`. Open `localhost:8089` in a browser. Note you can also run `locust` from the command line, see the [documentation](http://docs.locust.io/en/stable/configuration.html#configuration). From the browser, set the following: * Number of users. Each will run at a maximum QPS based on maximum QPS set below. * Spawn rate, how often users are created per second * Host, e.g. `localhost:port`. Please do not run against production or staging. * Token - The identity token from `gcloud auth` * Max QPS per user Click 'Start Swarming', and monitor for errors. ## Results (12/14/21) https://github.com/sigstore/fulcio/issues/193#issuecomment-994247492 fulcio-1.6.5/tools/loadtest/locustfile.py000066400000000000000000000052551470150653400205220ustar00rootroot00000000000000# Copyright 2022 The Sigstore 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. import base64 from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat from locust import HttpUser, task, constant_throughput, events import jwt @events.init_command_line_parser.add_listener def _(parser): parser.add_argument("--token", type=str, env_var="LOCUST_OIDC_TOKEN", default="", help="OIDC token for authentication with Fulcio") parser.add_argument("--max-qps-per-user", type=float, env_var="LOCUST_MAX_QPS_PER_USER", default=1.0, help="Maximum QPS per user") class FulcioUser(HttpUser): # FulcioUser represents an instance of a user making requests. # Maximum number of requests per second per user. For example, to reach 25 QPS, # run Locust with 25 users with a constant throughput of 1. def wait_time(self): return constant_throughput(self.environment.parsed_options.max_qps_per_user)(self) @task def create_cert(self): # create_cert generates a keypair and makes a request to Fulcio to fetch a certificate. # Static ID token. This avoids hitting the OIDC provider with each request to fetch a new token. token = self.environment.parsed_options.token # Generate keypair for challenge. privkey = ec.generate_private_key(ec.SECP256R1) pubkey = privkey.public_key() pubbytes = pubkey.public_bytes(Encoding.DER, PublicFormat.SubjectPublicKeyInfo) content = base64.b64encode(pubbytes).decode("utf-8") # Fetch identity of token and sign. email = jwt.decode(token, options={"verify_signature":False})['email'] data = email.encode() signature = privkey.sign(data, ec.ECDSA(hashes.SHA256())) challenge = base64.b64encode(signature).decode("utf-8") json = {"publicKey": {"content": content,"algorithm":"ecdsa"},"signedEmailAddress":challenge} response = self.client.post("/api/v1/signingCert", json=json, headers={"Authorization": f"Bearer {token}", "Content-Type":"application/json"}) print("Response status code:", response.status_code) fulcio-1.6.5/tools/loadtest/requirements.txt000066400000000000000000000000321470150653400212470ustar00rootroot00000000000000cryptography locust pyjwt